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 rp
# Conflicts: # core/src/main/java/org/geysermc/geyser/GeyserImpl.java # core/src/main/java/org/geysermc/geyser/util/WebUtils.java
This commit is contained in:
commit
507a79eb88
666 changed files with 29118 additions and 30397 deletions
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
|
163
.github/workflows/build.yml
vendored
163
.github/workflows/build.yml
vendored
|
@ -3,10 +3,14 @@ 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'
|
||||
|
@ -18,112 +22,99 @@ 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:
|
||||
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 }}
|
89
.github/workflows/pullrequest.yml
vendored
89
.github/workflows/pullrequest.yml
vendored
|
@ -1,89 +0,0 @@
|
|||
name: Build Pull Request
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
|
||||
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
|
|
@ -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>
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
|
||||
[![Discord](https://img.shields.io/discord/613163671870242838.svg?color=%237289da&label=discord)](https://discord.gg/geysermc)
|
||||
[![Crowdin](https://badges.crowdin.net/geyser/localized.svg)](https://translate.geysermc.org/)
|
||||
[![Crowdin](https://badges.crowdin.net/e/51361b7f8a01644a238d0fe8f3bddc62/localized.svg)](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,7 +14,7 @@ The ultimate goal of this project is to allow Minecraft: Bedrock Edition users t
|
|||
|
||||
Special thanks to the DragonProxy project for being a trailblazer in protocol translation and for all the team members who have joined us here!
|
||||
|
||||
### Currently supporting Minecraft Bedrock 1.20.40 - 1.20.61 and Minecraft Java 1.20.4
|
||||
### Currently supporting Minecraft Bedrock 1.20.80 - 1.21.0 and Minecraft Java 1.21
|
||||
|
||||
## Setting Up
|
||||
Take a look [here](https://wiki.geysermc.org/geyser/setup/) for how to set up Geyser.
|
||||
|
@ -32,7 +32,6 @@ 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.
|
||||
|
|
|
@ -145,4 +145,36 @@ public interface CameraData {
|
|||
* @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,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,6 +184,10 @@ 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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -29,6 +29,7 @@ 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;
|
||||
|
||||
/**
|
||||
|
@ -77,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.
|
||||
*
|
||||
|
@ -119,6 +134,10 @@ 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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -42,4 +42,4 @@ public abstract class PathPackCodec extends PackCodec {
|
|||
*/
|
||||
@NonNull
|
||||
public abstract Path path();
|
||||
}
|
||||
}
|
|
@ -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.
|
||||
* <p>
|
||||
* Of note are the fixed int maps. Designed for use with block states that are positive and sequential, they do not allow keys to be
|
||||
* 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.
|
||||
* Represents a cape.
|
||||
*
|
||||
* @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;
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
dependencies {
|
||||
api(projects.core)
|
||||
|
||||
implementation(libs.adventure.text.serializer.bungeecord)
|
||||
compileOnlyApi(libs.bungeecord.proxy)
|
||||
}
|
||||
|
||||
platformRelocate("net.md_5.bungee.jni")
|
||||
|
@ -22,6 +22,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 +34,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")
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -58,14 +58,13 @@ 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 GeyserBungeeConfiguration geyserConfig;
|
||||
private GeyserBungeeInjector geyserInjector;
|
||||
private GeyserBungeeLogger geyserLogger;
|
||||
private final GeyserBungeeLogger geyserLogger = new GeyserBungeeLogger(getLogger());
|
||||
private IGeyserPingPassthrough geyserBungeePingPassthrough;
|
||||
|
||||
private GeyserImpl geyser;
|
||||
|
@ -82,21 +81,21 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap {
|
|||
// 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_20_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 (!this.loadConfig()) {
|
||||
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);
|
||||
|
@ -293,7 +292,7 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap {
|
|||
"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);
|
||||
geyserLogger.error(GeyserLocale.getLocaleStringLog("geyser.config.failed"), ex);
|
||||
ex.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -1,124 +0,0 @@
|
|||
import net.fabricmc.loom.task.RemapJarTask
|
||||
|
||||
plugins {
|
||||
id("fabric-loom") version "1.0-SNAPSHOT"
|
||||
id("com.modrinth.minotaur") version "2.+"
|
||||
}
|
||||
|
||||
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.4")
|
||||
|
||||
loaders.add("fabric")
|
||||
failSilently.set(true)
|
||||
|
||||
dependencies {
|
||||
required.project("fabric-api")
|
||||
}
|
||||
}
|
|
@ -1,289 +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.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.cloudburstmc.math.vector.Vector3i;
|
||||
import org.cloudburstmc.nbt.NbtMap;
|
||||
import org.cloudburstmc.nbt.NbtMapBuilder;
|
||||
import org.cloudburstmc.nbt.NbtType;
|
||||
import org.geysermc.erosion.util.LecternUtils;
|
||||
import org.geysermc.geyser.level.GeyserWorldManager;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.util.BlockEntityUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
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;
|
||||
}
|
||||
|
||||
//noinspection resource - level() is just a getter
|
||||
LevelChunk chunk = player.level().getChunk(x, z);
|
||||
final int chunkBlockX = x << 4;
|
||||
final int chunkBlockZ = z << 4;
|
||||
//noinspection ForLoopReplaceableByForEach - avoid constructing iterator
|
||||
for (int i = 0; i < blockEntityInfos.size(); i++) {
|
||||
BlockEntityInfo blockEntityInfo = blockEntityInfos.get(i);
|
||||
BlockEntity blockEntity = chunk.getBlockEntity(new BlockPos(chunkBlockX + blockEntityInfo.getX(),
|
||||
blockEntityInfo.getY(), chunkBlockZ + blockEntityInfo.getZ()));
|
||||
sendLecternData(session, blockEntity, true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendLecternData(GeyserSession session, int x, int y, int z) {
|
||||
server.execute(() -> {
|
||||
ServerPlayer player = getPlayer(session);
|
||||
if (player == null) {
|
||||
return;
|
||||
}
|
||||
//noinspection resource - level() is just a getter
|
||||
BlockEntity blockEntity = player.level().getBlockEntity(new BlockPos(x, y, z));
|
||||
sendLecternData(session, blockEntity, false);
|
||||
});
|
||||
}
|
||||
|
||||
private void sendLecternData(GeyserSession session, BlockEntity blockEntity, boolean isChunkLoad) {
|
||||
if (!(blockEntity instanceof LecternBlockEntity lectern)) {
|
||||
return;
|
||||
}
|
||||
|
||||
int x = blockEntity.getBlockPos().getX();
|
||||
int y = blockEntity.getBlockPos().getY();
|
||||
int z = blockEntity.getBlockPos().getZ();
|
||||
|
||||
if (!lectern.hasBook()) {
|
||||
if (!isChunkLoad) {
|
||||
BlockEntityUtils.updateBlockEntity(session, LecternUtils.getBaseLecternTag(x, y, z, 0).build(), Vector3i.from(x, y, z));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
ItemStack book = lectern.getBook();
|
||||
int pageCount = 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
|
||||
//noinspection resource - level() is just a getter
|
||||
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(@NonNull 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 = Objects.requireNonNull(compoundTag.get(key));
|
||||
tag.accept(visitor);
|
||||
visitor.root.put(visitor.currentTag);
|
||||
}
|
||||
return visitor.root;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd(@NonNull 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
|
||||
}
|
||||
}
|
22
bootstrap/mod/build.gradle.kts
Normal file
22
bootstrap/mod/build.gradle.kts
Normal file
|
@ -0,0 +1,22 @@
|
|||
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)
|
||||
|
||||
// Only here to suppress "unknown enum constant EnvType.CLIENT" warnings. DO NOT USE!
|
||||
compileOnly(libs.fabric.loader)
|
||||
}
|
70
bootstrap/mod/fabric/build.gradle.kts
Normal file
70
bootstrap/mod/fabric/build.gradle.kts
Normal file
|
@ -0,0 +1,70 @@
|
|||
plugins {
|
||||
application
|
||||
}
|
||||
|
||||
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.mcauthlib) { isTransitive = false }
|
||||
shadow(libs.raknet) { isTransitive = false }
|
||||
|
||||
// Consequences of shading + relocating mcauthlib: shadow/relocate mcpl!
|
||||
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 }
|
||||
|
||||
// Permissions
|
||||
modImplementation(libs.fabric.permissions)
|
||||
include(libs.fabric.permissions)
|
||||
}
|
||||
|
||||
application {
|
||||
mainClass.set("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,89 @@
|
|||
/*
|
||||
* 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 me.lucko.fabric.api.permissions.v0.Permissions;
|
||||
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.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.geysermc.geyser.platform.mod.GeyserModBootstrap;
|
||||
import org.geysermc.geyser.platform.mod.GeyserModUpdateListener;
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isServer() {
|
||||
return FabricLoader.getInstance().getEnvironmentType().equals(EnvType.SERVER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(@NonNull Player source, @NonNull String permissionNode) {
|
||||
return Permissions.check(source, permissionNode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(@NonNull CommandSourceStack source, @NonNull String permissionNode, int permissionLevel) {
|
||||
return Permissions.check(source, permissionNode, permissionLevel);
|
||||
}
|
||||
}
|
|
@ -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.15.2",
|
||||
"fabricloader": ">=0.15.11",
|
||||
"fabric": "*",
|
||||
"minecraft": ">=1.20.4",
|
||||
"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 @@
|
|||
plugins {
|
||||
application
|
||||
}
|
||||
|
||||
// This is provided by "org.cloudburstmc.math.mutable" too, so yeet.
|
||||
// NeoForge's class loader is *really* annoying.
|
||||
provided("org.cloudburstmc.math", "api")
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
application {
|
||||
mainClass.set("org.geysermc.geyser.platform.forge.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,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.neoforge;
|
||||
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
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 org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.geysermc.geyser.platform.mod.GeyserModBootstrap;
|
||||
import org.geysermc.geyser.platform.mod.GeyserModUpdateListener;
|
||||
|
||||
@Mod(ModConstants.MOD_ID)
|
||||
public class GeyserNeoForgeBootstrap extends GeyserModBootstrap {
|
||||
|
||||
private final GeyserNeoForgePermissionHandler permissionHandler = new GeyserNeoForgePermissionHandler();
|
||||
|
||||
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(this.permissionHandler::onPermissionGather);
|
||||
|
||||
this.onGeyserInitialize();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(@NonNull Player source, @NonNull String permissionNode) {
|
||||
return this.permissionHandler.hasPermission(source, permissionNode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(@NonNull CommandSourceStack source, @NonNull String permissionNode, int permissionLevel) {
|
||||
return this.permissionHandler.hasPermission(source, permissionNode, permissionLevel);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* 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 org.geysermc.geyser.GeyserMain;
|
||||
|
||||
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,149 @@
|
|||
/*
|
||||
* 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.server.level.ServerPlayer;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.neoforged.neoforge.server.permission.PermissionAPI;
|
||||
import net.neoforged.neoforge.server.permission.events.PermissionGatherEvent;
|
||||
import net.neoforged.neoforge.server.permission.nodes.PermissionDynamicContextKey;
|
||||
import net.neoforged.neoforge.server.permission.nodes.PermissionNode;
|
||||
import net.neoforged.neoforge.server.permission.nodes.PermissionType;
|
||||
import net.neoforged.neoforge.server.permission.nodes.PermissionTypes;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.geysermc.geyser.Constants;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.api.command.Command;
|
||||
import org.geysermc.geyser.command.GeyserCommandManager;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class GeyserNeoForgePermissionHandler {
|
||||
|
||||
private static final Constructor<?> PERMISSION_NODE_CONSTRUCTOR;
|
||||
|
||||
static {
|
||||
try {
|
||||
@SuppressWarnings("rawtypes")
|
||||
Constructor<PermissionNode> constructor = PermissionNode.class.getDeclaredConstructor(
|
||||
String.class,
|
||||
PermissionType.class,
|
||||
PermissionNode.PermissionResolver.class,
|
||||
PermissionDynamicContextKey[].class
|
||||
);
|
||||
constructor.setAccessible(true);
|
||||
PERMISSION_NODE_CONSTRUCTOR = constructor;
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new RuntimeException("Unable to construct PermissionNode!", e);
|
||||
}
|
||||
}
|
||||
|
||||
private final Map<String, PermissionNode<Boolean>> permissionNodes = new HashMap<>();
|
||||
|
||||
public void onPermissionGather(PermissionGatherEvent.Nodes event) {
|
||||
this.registerNode(Constants.UPDATE_PERMISSION, event);
|
||||
|
||||
GeyserCommandManager commandManager = GeyserImpl.getInstance().commandManager();
|
||||
for (Map.Entry<String, Command> entry : commandManager.commands().entrySet()) {
|
||||
Command command = entry.getValue();
|
||||
|
||||
// Don't register aliases
|
||||
if (!command.name().equals(entry.getKey())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
this.registerNode(command.permission(), event);
|
||||
}
|
||||
|
||||
for (Map<String, Command> commands : commandManager.extensionCommands().values()) {
|
||||
for (Map.Entry<String, Command> entry : commands.entrySet()) {
|
||||
Command command = entry.getValue();
|
||||
|
||||
// Don't register aliases
|
||||
if (!command.name().equals(entry.getKey())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
this.registerNode(command.permission(), event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasPermission(@NonNull Player source, @NonNull String permissionNode) {
|
||||
PermissionNode<Boolean> node = this.permissionNodes.get(permissionNode);
|
||||
if (node == null) {
|
||||
GeyserImpl.getInstance().getLogger().warning("Unable to find permission node " + permissionNode);
|
||||
return false;
|
||||
}
|
||||
|
||||
return PermissionAPI.getPermission((ServerPlayer) source, node);
|
||||
}
|
||||
|
||||
public boolean hasPermission(@NonNull CommandSourceStack source, @NonNull String permissionNode, int permissionLevel) {
|
||||
if (!source.isPlayer()) {
|
||||
return true;
|
||||
}
|
||||
assert source.getPlayer() != null;
|
||||
boolean permission = this.hasPermission(source.getPlayer(), permissionNode);
|
||||
if (!permission) {
|
||||
return source.getPlayer().hasPermissions(permissionLevel);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void registerNode(String node, PermissionGatherEvent.Nodes event) {
|
||||
PermissionNode<Boolean> permissionNode = this.createNode(node);
|
||||
|
||||
// NeoForge likes to crash if you try and register a duplicate node
|
||||
if (!event.getNodes().contains(permissionNode)) {
|
||||
event.addNodes(permissionNode);
|
||||
this.permissionNodes.put(node, permissionNode);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private PermissionNode<Boolean> createNode(String node) {
|
||||
// The typical constructors in PermissionNode require a
|
||||
// mod id, which means our permission nodes end up becoming
|
||||
// geyser_neoforge.<node> instead of just <node>. We work around
|
||||
// this by using reflection to access the constructor that
|
||||
// doesn't require a mod id or ResourceLocation.
|
||||
try {
|
||||
return (PermissionNode<Boolean>) PERMISSION_NODE_CONSTRUCTOR.newInstance(
|
||||
node,
|
||||
PermissionTypes.BOOLEAN,
|
||||
(PermissionNode.PermissionResolver<Boolean>) (player, playerUUID, context) -> false,
|
||||
new PermissionDynamicContextKey[0]
|
||||
);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Unable to create permission node " + node, e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -23,11 +23,8 @@
|
|||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.geyser.item.type;
|
||||
package org.geysermc.geyser.platform.neoforge;
|
||||
|
||||
// If blocks are implemented, then this class is not needed.
|
||||
public class FlowerItem extends BlockItem {
|
||||
public FlowerItem(String javaIdentifier, Builder builder) {
|
||||
super(javaIdentifier, builder);
|
||||
}
|
||||
public class ModConstants {
|
||||
public static final String MOD_ID = "geyser_neoforge";
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
modLoader="javafml"
|
||||
loaderVersion="[1,)"
|
||||
license="MIT"
|
||||
[[mods]]
|
||||
modId="geyser_neoforge"
|
||||
version="${version}"
|
||||
displayName="Geyser"
|
||||
displayURL="https://geysermc.org/"
|
||||
logoFile= "../assets/geyser/icon.png"
|
||||
authors="GeyserMC"
|
||||
description="${description}"
|
||||
[[mixins]]
|
||||
config = "geyser.mixins.json"
|
||||
[[dependencies.geyser_neoforge]]
|
||||
modId="neoforge"
|
||||
type="required"
|
||||
versionRange="[21.0.0-beta,)"
|
||||
ordering="NONE"
|
||||
side="BOTH"
|
||||
[[dependencies.geyser_neoforge]]
|
||||
modId="minecraft"
|
||||
type="required"
|
||||
versionRange="[1.21,)"
|
||||
ordering="NONE"
|
||||
side="BOTH"
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* 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.mod;
|
||||
|
||||
import io.netty.channel.ChannelFuture;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Represents a getter to the server channels in the connection listener class.
|
||||
*/
|
||||
public interface GeyserChannelGetter {
|
||||
|
||||
/**
|
||||
* Returns the channels.
|
||||
*
|
||||
* @return The channels.
|
||||
*/
|
||||
List<ChannelFuture> geyser$getChannels();
|
||||
}
|
|
@ -23,22 +23,17 @@
|
|||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.geyser.platform.fabric;
|
||||
package org.geysermc.geyser.platform.mod;
|
||||
|
||||
import com.mojang.brigadier.arguments.StringArgumentType;
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Setter;
|
||||
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 net.minecraft.world.entity.player.Player;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.geysermc.geyser.GeyserBootstrap;
|
||||
|
@ -46,7 +41,6 @@ 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;
|
||||
|
@ -54,68 +48,58 @@ 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.platform.mod.command.GeyserModCommandExecutor;
|
||||
import org.geysermc.geyser.platform.mod.platform.GeyserModPlatform;
|
||||
import org.geysermc.geyser.platform.mod.world.GeyserModWorldManager;
|
||||
import org.geysermc.geyser.text.GeyserLocale;
|
||||
import org.geysermc.geyser.util.FileUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.SocketAddress;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
public class GeyserFabricMod implements ModInitializer, GeyserBootstrap {
|
||||
@RequiredArgsConstructor
|
||||
public abstract class GeyserModBootstrap implements GeyserBootstrap {
|
||||
|
||||
@Getter
|
||||
private static GeyserFabricMod instance;
|
||||
private static GeyserModBootstrap instance;
|
||||
|
||||
private final GeyserModPlatform platform;
|
||||
|
||||
private GeyserImpl geyser;
|
||||
private ModContainer mod;
|
||||
private Path dataFolder;
|
||||
|
||||
@Setter
|
||||
private MinecraftServer server;
|
||||
|
||||
private GeyserCommandManager geyserCommandManager;
|
||||
private GeyserFabricConfiguration geyserConfig;
|
||||
private GeyserFabricLogger geyserLogger;
|
||||
private GeyserModConfiguration geyserConfig;
|
||||
private GeyserModInjector geyserInjector;
|
||||
private final GeyserModLogger geyserLogger = new GeyserModLogger();
|
||||
private IGeyserPingPassthrough geyserPingPassthrough;
|
||||
private WorldManager geyserWorldManager;
|
||||
|
||||
@Override
|
||||
public void onInitialize() {
|
||||
instance = this;
|
||||
mod = FabricLoader.getInstance().getModContainer("geyser-fabric").orElseThrow();
|
||||
onGeyserInitialize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGeyserInitialize() {
|
||||
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((server) -> {
|
||||
this.server = server;
|
||||
onGeyserEnable();
|
||||
});
|
||||
}
|
||||
|
||||
// These are only registered once
|
||||
ServerLifecycleEvents.SERVER_STOPPING.register((server) -> onGeyserShutdown());
|
||||
ServerPlayConnectionEvents.JOIN.register((handler, $, $$) -> GeyserFabricUpdateListener.onPlayReady(handler));
|
||||
|
||||
dataFolder = FabricLoader.getInstance().getConfigDir().resolve("Geyser-Fabric");
|
||||
instance = this;
|
||||
dataFolder = this.platform.dataFolder(this.platform.configPath());
|
||||
GeyserLocale.init(this);
|
||||
if (!loadConfig()) {
|
||||
return;
|
||||
}
|
||||
this.geyserLogger = new GeyserFabricLogger(geyserConfig.isDebugMode());
|
||||
this.geyserLogger.setDebug(geyserConfig.isDebugMode());
|
||||
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
|
||||
this.geyser = GeyserImpl.load(PlatformType.FABRIC, this);
|
||||
this.geyser = GeyserImpl.load(this.platform.platformType(), this);
|
||||
|
||||
// Create command manager here, since the permission handler on neo needs it
|
||||
this.geyserCommandManager = new GeyserCommandManager(geyser);
|
||||
this.geyserCommandManager.init();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGeyserEnable() {
|
||||
if (GeyserImpl.getInstance().isReloading()) {
|
||||
if (!loadConfig()) {
|
||||
|
@ -123,35 +107,39 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap {
|
|||
}
|
||||
this.geyserLogger.setDebug(geyserConfig.isDebugMode());
|
||||
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
|
||||
} else {
|
||||
this.geyserCommandManager = new GeyserCommandManager(geyser);
|
||||
this.geyserCommandManager.init();
|
||||
}
|
||||
|
||||
GeyserImpl.start();
|
||||
|
||||
if (geyserConfig.isLegacyPingPassthrough()) {
|
||||
this.geyserPingPassthrough = GeyserLegacyPingPassthrough.init(geyser);
|
||||
} else {
|
||||
this.geyserPingPassthrough = new ModPingPassthrough(server, geyserLogger);
|
||||
}
|
||||
|
||||
GeyserImpl.start();
|
||||
|
||||
// No need to re-register commands, or re-recreate the world manager when reloading
|
||||
// No need to re-register commands, or try to re-inject
|
||||
if (GeyserImpl.getInstance().isReloading()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.geyserWorldManager = new GeyserFabricWorldManager(server);
|
||||
this.geyserWorldManager = new GeyserModWorldManager(server);
|
||||
|
||||
// We want to do this late in the server startup process to allow other mods
|
||||
// To do their job injecting, then connect into *that*
|
||||
this.geyserInjector = new GeyserModInjector(server, this.platform);
|
||||
if (isServer()) {
|
||||
this.geyserInjector.initializeLocalChannel(this);
|
||||
}
|
||||
|
||||
// Start command building
|
||||
// Set just "geyser" as the help command
|
||||
GeyserFabricCommandExecutor helpExecutor = new GeyserFabricCommandExecutor(geyser,
|
||||
GeyserModCommandExecutor helpExecutor = new GeyserModCommandExecutor(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());
|
||||
GeyserModCommandExecutor executor = new GeyserModCommandExecutor(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
|
||||
|
@ -171,12 +159,12 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap {
|
|||
}
|
||||
|
||||
// Register help command for just "/<extensionId>"
|
||||
GeyserFabricCommandExecutor extensionHelpExecutor = new GeyserFabricCommandExecutor(geyser,
|
||||
GeyserModCommandExecutor extensionHelpExecutor = new GeyserModCommandExecutor(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());
|
||||
GeyserModCommandExecutor executor = new GeyserModCommandExecutor(geyser, (GeyserCommand) command.getValue());
|
||||
extCmdBuilder.then(Commands.literal(command.getKey())
|
||||
.executes(executor)
|
||||
.requires(executor::testPermission)
|
||||
|
@ -201,11 +189,14 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap {
|
|||
geyser.shutdown();
|
||||
geyser = null;
|
||||
}
|
||||
this.server = null;
|
||||
if (geyserInjector != null) {
|
||||
geyserInjector.shutdown();
|
||||
this.server = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public GeyserConfiguration getGeyserConfig() {
|
||||
public GeyserModConfiguration getGeyserConfig() {
|
||||
return geyserConfig;
|
||||
}
|
||||
|
||||
|
@ -236,7 +227,7 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap {
|
|||
|
||||
@Override
|
||||
public BootstrapDumpInfo getDumpInfo() {
|
||||
return new GeyserFabricDumpInfo(server);
|
||||
return this.platform.dumpInfo(this.server);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -252,38 +243,37 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap {
|
|||
}
|
||||
|
||||
@Override
|
||||
public int getServerPort() {
|
||||
return ((GeyserServerPortGetter) server).geyser$getServerPort();
|
||||
public SocketAddress getSocketAddress() {
|
||||
return this.geyserInjector.getServerSocketAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean testFloodgatePluginPresent() {
|
||||
Optional<ModContainer> floodgate = FabricLoader.getInstance().getModContainer("floodgate");
|
||||
if (floodgate.isPresent()) {
|
||||
geyserConfig.loadFloodgate(this, floodgate.orElse(null));
|
||||
return true;
|
||||
public int getServerPort() {
|
||||
if (isServer()) {
|
||||
return ((GeyserServerPortGetter) server).geyser$getServerPort();
|
||||
} else {
|
||||
// Set in the IntegratedServerMixin
|
||||
return geyserConfig.getRemote().port();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public abstract boolean isServer();
|
||||
|
||||
@Override
|
||||
public boolean testFloodgatePluginPresent() {
|
||||
return this.platform.testFloodgatePluginPresent(this);
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
return this.platform.resolveResource(resource);
|
||||
}
|
||||
|
||||
public abstract boolean hasPermission(@NonNull Player source, @NonNull String permissionNode);
|
||||
|
||||
public abstract boolean hasPermission(@NonNull CommandSourceStack source, @NonNull String permissionNode, int permissionLevel);
|
||||
|
||||
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
|
||||
private boolean loadConfig() {
|
||||
try {
|
||||
|
@ -294,10 +284,10 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap {
|
|||
|
||||
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);
|
||||
this.geyserConfig = FileUtils.loadConfig(configFile, GeyserModConfiguration.class);
|
||||
return true;
|
||||
} catch (IOException ex) {
|
||||
LogManager.getLogger("geyser-fabric").error(GeyserLocale.getLocaleStringLog("geyser.config.failed"), ex);
|
||||
geyserLogger.error(GeyserLocale.getLocaleStringLog("geyser.config.failed"), ex);
|
||||
ex.printStackTrace();
|
||||
return false;
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.mod;
|
||||
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelOutboundHandlerAdapter;
|
||||
import io.netty.channel.ChannelPromise;
|
||||
import net.minecraft.network.protocol.login.ClientboundGameProfilePacket;
|
||||
import net.minecraft.network.protocol.login.ClientboundLoginCompressionPacket;
|
||||
|
||||
/**
|
||||
* Disables the compression packet (and the compression handlers from being added to the pipeline) for Geyser clients
|
||||
* that won't be receiving the data over the network.
|
||||
* <p>
|
||||
* As of 1.8 - 1.17.1, compression is enabled in the Netty pipeline by adding a listener after a packet is written.
|
||||
* If we simply "cancel" or don't forward the packet, then the listener is never called.
|
||||
*/
|
||||
public class GeyserModCompressionDisabler extends ChannelOutboundHandlerAdapter {
|
||||
|
||||
@Override
|
||||
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
|
||||
Class<?> msgClass = msg.getClass();
|
||||
// Don't let any compression packet get through
|
||||
if (!ClientboundLoginCompressionPacket.class.isAssignableFrom(msgClass)) {
|
||||
if (ClientboundGameProfilePacket.class.isAssignableFrom(msgClass)) {
|
||||
|
||||
// We're past the point that a compression packet can be sent, so we can safely yeet ourselves away
|
||||
ctx.channel().pipeline().remove(this);
|
||||
}
|
||||
super.write(ctx, msg, promise);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -23,23 +23,20 @@
|
|||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.geyser.platform.fabric;
|
||||
package org.geysermc.geyser.platform.mod;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
import net.fabricmc.loader.api.ModContainer;
|
||||
import org.geysermc.geyser.FloodgateKeyLoader;
|
||||
import org.geysermc.geyser.configuration.GeyserJacksonConfiguration;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class GeyserFabricConfiguration extends GeyserJacksonConfiguration {
|
||||
public class GeyserModConfiguration extends GeyserJacksonConfiguration {
|
||||
@JsonIgnore
|
||||
private Path floodgateKeyPath;
|
||||
|
||||
public void loadFloodgate(GeyserFabricMod geyser, ModContainer floodgate) {
|
||||
public void loadFloodgate(GeyserModBootstrap geyser, Path floodgateDataFolder) {
|
||||
Path geyserDataFolder = geyser.getConfigFolder();
|
||||
Path floodgateDataFolder = floodgate != null ? FabricLoader.getInstance().getConfigDir().resolve("floodgate") : null;
|
||||
|
||||
floodgateKeyPath = FloodgateKeyLoader.getKeyPath(this, floodgateDataFolder, geyserDataFolder, geyser.getGeyserLogger());
|
||||
}
|
|
@ -0,0 +1,159 @@
|
|||
/*
|
||||
* 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.mod;
|
||||
|
||||
import io.netty.bootstrap.ServerBootstrap;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.DefaultEventLoopGroup;
|
||||
import io.netty.channel.local.LocalAddress;
|
||||
import io.netty.util.concurrent.DefaultThreadFactory;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.network.ServerConnectionListener;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.geysermc.geyser.GeyserBootstrap;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.network.netty.GeyserInjector;
|
||||
import org.geysermc.geyser.network.netty.LocalServerChannelWrapper;
|
||||
import org.geysermc.geyser.platform.mod.platform.GeyserModPlatform;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
|
||||
public class GeyserModInjector extends GeyserInjector {
|
||||
|
||||
private final MinecraftServer server;
|
||||
private final GeyserModPlatform platform;
|
||||
private DefaultEventLoopGroup eventLoopGroup;
|
||||
|
||||
/**
|
||||
* Used to uninject ourselves on shutdown.
|
||||
*/
|
||||
private List<ChannelFuture> allServerChannels;
|
||||
|
||||
public GeyserModInjector(MinecraftServer server, GeyserModPlatform platform) {
|
||||
this.server = server;
|
||||
this.platform = platform;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initializeLocalChannel0(GeyserBootstrap bootstrap) throws Exception {
|
||||
ServerConnectionListener connection = this.server.getConnection();
|
||||
|
||||
// Find the channel that Minecraft uses to listen to connections
|
||||
ChannelFuture listeningChannel = null;
|
||||
this.allServerChannels = ((GeyserChannelGetter) connection).geyser$getChannels();
|
||||
for (ChannelFuture o : allServerChannels) {
|
||||
listeningChannel = o;
|
||||
break;
|
||||
}
|
||||
|
||||
if (listeningChannel == null) {
|
||||
throw new RuntimeException("Unable to find listening channel!");
|
||||
}
|
||||
|
||||
// Making this a function prevents childHandler from being treated as a non-final variable
|
||||
ChannelInitializer<Channel> childHandler = getChildHandler(bootstrap, listeningChannel);
|
||||
// This method is what initializes the connection in Java Edition, after Netty is all set.
|
||||
Method initChannel = childHandler.getClass().getDeclaredMethod("initChannel", Channel.class);
|
||||
initChannel.setAccessible(true);
|
||||
|
||||
// Separate variable so we can shut it down later
|
||||
eventLoopGroup = new DefaultEventLoopGroup(0, new DefaultThreadFactory("Geyser " + this.platform.platformType().platformName() + " connection thread", Thread.MAX_PRIORITY));
|
||||
ChannelFuture channelFuture = (new ServerBootstrap()
|
||||
.channel(LocalServerChannelWrapper.class)
|
||||
.childHandler(new ChannelInitializer<>() {
|
||||
@Override
|
||||
protected void initChannel(@NonNull Channel ch) throws Exception {
|
||||
initChannel.invoke(childHandler, ch);
|
||||
|
||||
int index = ch.pipeline().names().indexOf("encoder");
|
||||
String baseName = index != -1 ? "encoder" : "outbound_config";
|
||||
|
||||
if (bootstrap.getGeyserConfig().isDisableCompression()) {
|
||||
ch.pipeline().addAfter(baseName, "geyser-compression-disabler", new GeyserModCompressionDisabler());
|
||||
}
|
||||
}
|
||||
})
|
||||
// Set to MAX_PRIORITY as MultithreadEventLoopGroup#newDefaultThreadFactory which DefaultEventLoopGroup implements does by default
|
||||
.group(eventLoopGroup)
|
||||
.localAddress(LocalAddress.ANY))
|
||||
.bind()
|
||||
.syncUninterruptibly();
|
||||
// We don't need to add to the list, but plugins like ProtocolSupport and ProtocolLib that add to the main pipeline
|
||||
// will work when we add to the list.
|
||||
allServerChannels.add(channelFuture);
|
||||
this.localChannel = channelFuture;
|
||||
this.serverSocketAddress = channelFuture.channel().localAddress();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private ChannelInitializer<Channel> getChildHandler(GeyserBootstrap bootstrap, ChannelFuture listeningChannel) {
|
||||
List<String> names = listeningChannel.channel().pipeline().names();
|
||||
ChannelInitializer<Channel> childHandler = null;
|
||||
for (String name : names) {
|
||||
ChannelHandler handler = listeningChannel.channel().pipeline().get(name);
|
||||
try {
|
||||
Field childHandlerField = handler.getClass().getDeclaredField("childHandler");
|
||||
childHandlerField.setAccessible(true);
|
||||
childHandler = (ChannelInitializer<Channel>) childHandlerField.get(handler);
|
||||
break;
|
||||
} catch (Exception e) {
|
||||
if (bootstrap.getGeyserConfig().isDebugMode()) {
|
||||
bootstrap.getGeyserLogger().debug("The handler " + name + " isn't a ChannelInitializer. THIS ERROR IS SAFE TO IGNORE!");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (childHandler == null) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
return childHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() {
|
||||
if (this.allServerChannels != null) {
|
||||
this.allServerChannels.remove(this.localChannel);
|
||||
this.allServerChannels = null;
|
||||
}
|
||||
|
||||
if (eventLoopGroup != null) {
|
||||
try {
|
||||
eventLoopGroup.shutdownGracefully().sync();
|
||||
eventLoopGroup = null;
|
||||
} catch (Exception e) {
|
||||
GeyserImpl.getInstance().getLogger().error("Unable to shut down injector! " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
super.shutdown();
|
||||
}
|
||||
}
|
|
@ -23,7 +23,7 @@
|
|||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.geyser.platform.fabric;
|
||||
package org.geysermc.geyser.platform.mod;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||
|
@ -32,15 +32,11 @@ import org.apache.logging.log4j.Logger;
|
|||
import org.geysermc.geyser.GeyserLogger;
|
||||
import org.geysermc.geyser.text.ChatColor;
|
||||
|
||||
public class GeyserFabricLogger implements GeyserLogger {
|
||||
private final Logger logger = LogManager.getLogger("geyser-fabric");
|
||||
public class GeyserModLogger implements GeyserLogger {
|
||||
private final Logger logger = LogManager.getLogger("geyser");
|
||||
|
||||
private boolean debug;
|
||||
|
||||
public GeyserFabricLogger(boolean isDebug) {
|
||||
debug = isDebug;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void severe(String message) {
|
||||
logger.fatal(message);
|
||||
|
@ -73,7 +69,7 @@ public class GeyserFabricLogger implements GeyserLogger {
|
|||
|
||||
@Override
|
||||
public void sendMessage(Component message) {
|
||||
// As of Java Edition 1.19.2, Fabric's console doesn't natively support legacy format
|
||||
// As of Java Edition 1.19.2, Minecraft's console doesn't natively support legacy format
|
||||
String flattened = LegacyComponentSerializer.legacySection().serialize(message);
|
||||
// Add the reset at the end, or else format will persist... forever.
|
||||
// https://cdn.discordapp.com/attachments/573909525132738590/1033904509170225242/unknown.png
|
|
@ -23,21 +23,22 @@
|
|||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.geyser.platform.fabric;
|
||||
package org.geysermc.geyser.platform.mod;
|
||||
|
||||
import me.lucko.fabric.api.permissions.v0.Permissions;
|
||||
import net.minecraft.server.network.ServerGamePacketListenerImpl;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import org.geysermc.geyser.Constants;
|
||||
import org.geysermc.geyser.platform.fabric.command.FabricCommandSender;
|
||||
import org.geysermc.geyser.platform.mod.command.ModCommandSender;
|
||||
import org.geysermc.geyser.util.VersionCheckUtils;
|
||||
|
||||
public final class GeyserFabricUpdateListener {
|
||||
public static void onPlayReady(ServerGamePacketListenerImpl handler) {
|
||||
if (Permissions.check(handler.player, Constants.UPDATE_PERMISSION, 2)) {
|
||||
VersionCheckUtils.checkForGeyserUpdate(() -> new FabricCommandSender(handler.player.createCommandSourceStack()));
|
||||
public final class GeyserModUpdateListener {
|
||||
public static void onPlayReady(Player player) {
|
||||
CommandSourceStack stack = player.createCommandSourceStack();
|
||||
if (GeyserModBootstrap.getInstance().hasPermission(stack, Constants.UPDATE_PERMISSION, 2)) {
|
||||
VersionCheckUtils.checkForGeyserUpdate(() -> new ModCommandSender(stack));
|
||||
}
|
||||
}
|
||||
|
||||
private GeyserFabricUpdateListener() {
|
||||
private GeyserModUpdateListener() {
|
||||
}
|
||||
}
|
|
@ -23,7 +23,7 @@
|
|||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.geyser.platform.fabric;
|
||||
package org.geysermc.geyser.platform.mod;
|
||||
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
|
|
@ -23,12 +23,13 @@
|
|||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.geyser.platform.fabric;
|
||||
package org.geysermc.geyser.platform.mod;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||
import net.minecraft.core.RegistryAccess;
|
||||
import net.minecraft.network.Connection;
|
||||
import net.minecraft.network.PacketSendListener;
|
||||
import net.minecraft.network.protocol.Packet;
|
||||
|
@ -39,10 +40,11 @@ import net.minecraft.network.protocol.status.ServerStatusPacketListener;
|
|||
import net.minecraft.network.protocol.status.ServerboundStatusRequestPacket;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.network.ServerStatusPacketListenerImpl;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.geysermc.geyser.GeyserLogger;
|
||||
import org.geysermc.geyser.ping.GeyserPingInfo;
|
||||
import org.geysermc.geyser.ping.IGeyserPingPassthrough;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.Objects;
|
||||
|
@ -68,7 +70,7 @@ public class ModPingPassthrough implements IGeyserPingPassthrough {
|
|||
StatusInterceptor connection = new StatusInterceptor();
|
||||
ServerStatusPacketListener statusPacketListener = new ServerStatusPacketListenerImpl(status, connection);
|
||||
|
||||
statusPacketListener.handleStatusRequest(new ServerboundStatusRequestPacket());
|
||||
statusPacketListener.handleStatusRequest(ServerboundStatusRequestPacket.INSTANCE);
|
||||
// mods like MiniMOTD (that inject into the above method) have now processed the response
|
||||
status = Objects.requireNonNull(connection.status, "status response");
|
||||
} catch (Exception e) {
|
||||
|
@ -78,7 +80,7 @@ public class ModPingPassthrough implements IGeyserPingPassthrough {
|
|||
}
|
||||
}
|
||||
|
||||
String jsonDescription = net.minecraft.network.chat.Component.Serializer.toJson(status.description());
|
||||
String jsonDescription = net.minecraft.network.chat.Component.Serializer.toJson(status.description(), RegistryAccess.EMPTY);
|
||||
String legacyDescription = LEGACY_SERIALIZER.serialize(GSON_SERIALIZER.deserializeOr(jsonDescription, Component.empty()));
|
||||
|
||||
return new GeyserPingInfo(
|
||||
|
@ -100,7 +102,7 @@ public class ModPingPassthrough implements IGeyserPingPassthrough {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void send(Packet<?> packet, @Nullable PacketSendListener packetSendListener, boolean bl) {
|
||||
public void send(@NonNull Packet<?> packet, @Nullable PacketSendListener packetSendListener, boolean bl) {
|
||||
if (packet instanceof ClientboundStatusResponsePacket statusResponse) {
|
||||
status = statusResponse.status();
|
||||
}
|
|
@ -23,31 +23,31 @@
|
|||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.geyser.platform.fabric.command;
|
||||
package org.geysermc.geyser.platform.mod.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.mod.GeyserModBootstrap;
|
||||
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> {
|
||||
public class GeyserModCommandExecutor extends GeyserCommandExecutor implements Command<CommandSourceStack> {
|
||||
private final GeyserCommand command;
|
||||
|
||||
public GeyserFabricCommandExecutor(GeyserImpl connector, GeyserCommand command) {
|
||||
super(connector, Collections.singletonMap(command.name(), command));
|
||||
public GeyserModCommandExecutor(GeyserImpl geyser, GeyserCommand command) {
|
||||
super(geyser, Collections.singletonMap(command.name(), command));
|
||||
this.command = command;
|
||||
}
|
||||
|
||||
public boolean testPermission(CommandSourceStack source) {
|
||||
return Permissions.check(source, command.permission(), command.isSuggestedOpOnly() ? 2 : 0);
|
||||
return GeyserModBootstrap.getInstance().hasPermission(source, command.permission(), command.isSuggestedOpOnly() ? 2 : 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -57,7 +57,7 @@ public class GeyserFabricCommandExecutor extends GeyserCommandExecutor implement
|
|||
|
||||
public int runWithArgs(CommandContext<CommandSourceStack> context, String args) {
|
||||
CommandSourceStack source = context.getSource();
|
||||
FabricCommandSender sender = new FabricCommandSender(source);
|
||||
ModCommandSender sender = new ModCommandSender(source);
|
||||
GeyserSession session = getGeyserSession(sender);
|
||||
if (!testPermission(source)) {
|
||||
sender.sendMessage(ChatColor.RED + GeyserLocale.getPlayerLocaleString("geyser.bootstrap.command.permission_fail", sender.locale()));
|
|
@ -23,25 +23,26 @@
|
|||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.geyser.platform.fabric.command;
|
||||
package org.geysermc.geyser.platform.mod.command;
|
||||
|
||||
import me.lucko.fabric.api.permissions.v0.Permissions;
|
||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.core.RegistryAccess;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.command.GeyserCommandSource;
|
||||
import org.geysermc.geyser.platform.mod.GeyserModBootstrap;
|
||||
import org.geysermc.geyser.text.ChatColor;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class FabricCommandSender implements GeyserCommandSource {
|
||||
public class ModCommandSender implements GeyserCommandSource {
|
||||
|
||||
private final CommandSourceStack source;
|
||||
|
||||
public FabricCommandSender(CommandSourceStack source) {
|
||||
public ModCommandSender(CommandSourceStack source) {
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
|
@ -63,7 +64,7 @@ public class FabricCommandSender implements GeyserCommandSource {
|
|||
public void sendMessage(net.kyori.adventure.text.Component message) {
|
||||
if (source.getEntity() instanceof ServerPlayer player) {
|
||||
String decoded = GsonComponentSerializer.gson().serialize(message);
|
||||
player.displayClientMessage(Objects.requireNonNull(Component.Serializer.fromJson(decoded)), false);
|
||||
player.displayClientMessage(Objects.requireNonNull(Component.Serializer.fromJson(decoded, RegistryAccess.EMPTY)), false);
|
||||
return;
|
||||
}
|
||||
GeyserCommandSource.super.sendMessage(message);
|
||||
|
@ -76,6 +77,6 @@ public class FabricCommandSender implements GeyserCommandSource {
|
|||
|
||||
@Override
|
||||
public boolean hasPermission(String permission) {
|
||||
return Permissions.check(source, permission, source.getServer().getOperatorUserPermissionLevel());
|
||||
return GeyserModBootstrap.getInstance().hasPermission(source, permission, source.getServer().getOperatorUserPermissionLevel());
|
||||
}
|
||||
}
|
|
@ -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,18 +23,16 @@
|
|||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.geyser.platform.fabric.mixin.client;
|
||||
package org.geysermc.geyser.platform.mod.mixin.client;
|
||||
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.server.IntegratedServer;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.world.level.GameType;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.platform.fabric.GeyserFabricMod;
|
||||
import org.geysermc.geyser.platform.fabric.GeyserServerPortGetter;
|
||||
import org.geysermc.geyser.platform.mod.GeyserModBootstrap;
|
||||
import org.geysermc.geyser.platform.mod.GeyserServerPortGetter;
|
||||
import org.geysermc.geyser.text.GeyserLocale;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
|
@ -45,7 +43,6 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
|||
|
||||
import java.util.Objects;
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
@Mixin(IntegratedServer.class)
|
||||
public class IntegratedServerMixin implements GeyserServerPortGetter {
|
||||
@Shadow
|
||||
|
@ -57,8 +54,10 @@ public class IntegratedServerMixin implements GeyserServerPortGetter {
|
|||
private void onOpenToLan(GameType gameType, boolean cheatsAllowed, int port, CallbackInfoReturnable<Boolean> cir) {
|
||||
if (cir.getReturnValueZ()) {
|
||||
// If the LAN is opened, starts Geyser.
|
||||
GeyserFabricMod.getInstance().setServer((MinecraftServer) (Object) this);
|
||||
GeyserFabricMod.getInstance().onGeyserEnable();
|
||||
GeyserModBootstrap instance = GeyserModBootstrap.getInstance();
|
||||
instance.setServer((MinecraftServer) (Object) this);
|
||||
instance.getGeyserConfig().getRemote().setPort(port);
|
||||
instance.onGeyserEnable();
|
||||
// Ensure player locale has been loaded, in case it's different from Java system language
|
||||
GeyserLocale.loadGeyserLocale(this.minecraft.options.languageCode);
|
||||
// Give indication that Geyser is loaded
|
|
@ -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,7 +23,7 @@
|
|||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.geyser.platform.fabric.mixin.server;
|
||||
package org.geysermc.geyser.platform.mod.mixin.server;
|
||||
|
||||
import com.mojang.datafixers.DataFixer;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
|
@ -33,14 +33,14 @@ import net.minecraft.server.dedicated.DedicatedServer;
|
|||
import net.minecraft.server.level.progress.ChunkProgressListenerFactory;
|
||||
import net.minecraft.server.packs.repository.PackRepository;
|
||||
import net.minecraft.world.level.storage.LevelStorageSource;
|
||||
import org.geysermc.geyser.platform.fabric.GeyserServerPortGetter;
|
||||
import org.geysermc.geyser.platform.mod.GeyserServerPortGetter;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
|
||||
import java.net.Proxy;
|
||||
|
||||
@Mixin(DedicatedServer.class)
|
||||
public abstract class MinecraftDedicatedServerMixin extends MinecraftServer implements GeyserServerPortGetter {
|
||||
public MinecraftDedicatedServerMixin(Thread thread, LevelStorageSource.LevelStorageAccess levelStorageAccess, PackRepository packRepository, WorldStem worldStem, Proxy proxy, DataFixer dataFixer, Services services, ChunkProgressListenerFactory chunkProgressListenerFactory) {
|
||||
public abstract class DedicatedServerMixin extends MinecraftServer implements GeyserServerPortGetter {
|
||||
public DedicatedServerMixin(Thread thread, LevelStorageSource.LevelStorageAccess levelStorageAccess, PackRepository packRepository, WorldStem worldStem, Proxy proxy, DataFixer dataFixer, Services services, ChunkProgressListenerFactory chunkProgressListenerFactory) {
|
||||
super(thread, levelStorageAccess, packRepository, worldStem, proxy, dataFixer, services, chunkProgressListenerFactory);
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* 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.mod.mixin.server;
|
||||
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import net.minecraft.server.network.ServerConnectionListener;
|
||||
import org.geysermc.geyser.platform.mod.GeyserChannelGetter;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mixin(ServerConnectionListener.class)
|
||||
public abstract class ServerConnectionListenerMixin implements GeyserChannelGetter {
|
||||
|
||||
@Shadow @Final private List<ChannelFuture> channels;
|
||||
|
||||
@Override
|
||||
public List<ChannelFuture> geyser$getChannels() {
|
||||
return this.channels;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* 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.mod.platform;
|
||||
|
||||
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 java.io.InputStream;
|
||||
import java.nio.file.Path;
|
||||
|
||||
/**
|
||||
* An interface which holds common methods that have different
|
||||
* APIs on their respective mod platforms.
|
||||
*/
|
||||
public interface GeyserModPlatform {
|
||||
|
||||
/**
|
||||
* Gets the {@link PlatformType} of the mod platform.
|
||||
*
|
||||
* @return the platform type of the mod platform
|
||||
*/
|
||||
@NonNull
|
||||
PlatformType platformType();
|
||||
|
||||
/**
|
||||
* Gets the config path of the mod platform.
|
||||
*
|
||||
* @return the config path of the mod platform
|
||||
*/
|
||||
@NonNull
|
||||
String configPath();
|
||||
|
||||
/**
|
||||
* Gets the data folder of the mod platform.
|
||||
*
|
||||
* @return the data folder of the mod platform
|
||||
*/
|
||||
@NonNull
|
||||
Path dataFolder(@NonNull String modId);
|
||||
|
||||
/**
|
||||
* Gets the dump info of the mod platform.
|
||||
*
|
||||
* @param server the server to get the dump info from
|
||||
* @return the dump info of the mod platform
|
||||
*/
|
||||
@NonNull
|
||||
BootstrapDumpInfo dumpInfo(@NonNull MinecraftServer server);
|
||||
|
||||
/**
|
||||
* Tests if the Floodgate plugin is present on the mod platform.
|
||||
*
|
||||
* @return {@code true} if the Floodgate plugin is present on the mod platform, {@code false} otherwise
|
||||
*/
|
||||
boolean testFloodgatePluginPresent(@NonNull GeyserModBootstrap bootstrap);
|
||||
|
||||
/**
|
||||
* Resolves a resource from the mod jar.
|
||||
*
|
||||
* @param resource the name of the resource
|
||||
* @return the input stream of the resource
|
||||
*/
|
||||
@Nullable
|
||||
InputStream resolveResource(@NonNull String resource);
|
||||
}
|
|
@ -0,0 +1,183 @@
|
|||
/*
|
||||
* 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.mod.world;
|
||||
|
||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||
import net.minecraft.SharedConstants;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.RegistryAccess;
|
||||
import net.minecraft.core.component.DataComponents;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.entity.BannerBlockEntity;
|
||||
import net.minecraft.world.level.block.entity.BannerPatternLayers;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||
import net.minecraft.world.level.chunk.LevelChunkSection;
|
||||
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.geysermc.geyser.level.GeyserWorldManager;
|
||||
import org.geysermc.geyser.network.GameProtocol;
|
||||
import org.geysermc.geyser.platform.mod.GeyserModBootstrap;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.util.MinecraftKey;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.Holder;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.BannerPatternLayer;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class GeyserModWorldManager extends GeyserWorldManager {
|
||||
|
||||
private static final GsonComponentSerializer GSON_SERIALIZER = GsonComponentSerializer.gson();
|
||||
private final MinecraftServer server;
|
||||
|
||||
public GeyserModWorldManager(MinecraftServer server) {
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBlockAt(GeyserSession session, int x, int y, int z) {
|
||||
// If the protocol version of Geyser and the server are not the
|
||||
// same, fallback to the chunk cache. May be able to update this
|
||||
// in the future to use ViaVersion however, like Spigot does.
|
||||
if (SharedConstants.getCurrentVersion().getProtocolVersion() != GameProtocol.getJavaProtocolVersion()) {
|
||||
return super.getBlockAt(session, x, y, z);
|
||||
}
|
||||
|
||||
ServerPlayer player = this.getPlayer(session);
|
||||
if (player == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Level level = player.level();
|
||||
if (y < level.getMinBuildHeight()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ChunkAccess chunk = level.getChunkSource().getChunk(x >> 4, z >> 4, ChunkStatus.FULL, false);
|
||||
if (chunk == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int worldOffset = level.getMinBuildHeight() >> 4;
|
||||
int chunkOffset = (y >> 4) - worldOffset;
|
||||
if (chunkOffset < chunk.getSections().length) {
|
||||
LevelChunkSection section = chunk.getSections()[chunkOffset];
|
||||
if (section != null && !section.hasOnlyAir()) {
|
||||
return Block.getId(section.getBlockState(x & 15, y & 15, z & 15));
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasOwnChunkCache() {
|
||||
return SharedConstants.getCurrentVersion().getProtocolVersion() == GameProtocol.getJavaProtocolVersion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(GeyserSession session, String permission) {
|
||||
ServerPlayer player = getPlayer(session);
|
||||
return GeyserModBootstrap.getInstance().hasPermission(player, permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GameMode getDefaultGameMode(GeyserSession session) {
|
||||
return GameMode.byId(server.getDefaultGameType().getId());
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public CompletableFuture<org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents> getPickItemComponents(GeyserSession session, int x, int y, int z, boolean addNbtData) {
|
||||
CompletableFuture<org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents> 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
|
||||
//noinspection resource - level() is just a getter
|
||||
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();
|
||||
|
||||
org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents components =
|
||||
new org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents(new HashMap<>());
|
||||
|
||||
components.put(DataComponentType.DAMAGE, itemStack.getDamageValue());
|
||||
|
||||
Component customName = itemStack.getComponents().get(DataComponents.CUSTOM_NAME);
|
||||
if (customName != null) {
|
||||
components.put(DataComponentType.CUSTOM_NAME, toKyoriComponent(customName));
|
||||
}
|
||||
|
||||
BannerPatternLayers pattern = itemStack.get(DataComponents.BANNER_PATTERNS);
|
||||
if (pattern != null) {
|
||||
components.put(DataComponentType.BANNER_PATTERNS, toPatternList(pattern));
|
||||
}
|
||||
|
||||
future.complete(components);
|
||||
return;
|
||||
}
|
||||
future.complete(null);
|
||||
});
|
||||
return future;
|
||||
}
|
||||
|
||||
private ServerPlayer getPlayer(GeyserSession session) {
|
||||
return server.getPlayerList().getPlayer(session.getPlayerEntity().getUuid());
|
||||
}
|
||||
|
||||
private static net.kyori.adventure.text.Component toKyoriComponent(Component component) {
|
||||
String json = Component.Serializer.toJson(component, RegistryAccess.EMPTY);
|
||||
return GSON_SERIALIZER.deserializeOr(json, net.kyori.adventure.text.Component.empty());
|
||||
}
|
||||
|
||||
private static List<BannerPatternLayer> toPatternList(BannerPatternLayers patternLayers) {
|
||||
return patternLayers.layers().stream()
|
||||
.map(layer -> {
|
||||
BannerPatternLayer.BannerPattern pattern = new BannerPatternLayer.BannerPattern(
|
||||
MinecraftKey.key(layer.pattern().value().assetId().toString()), layer.pattern().value().translationKey()
|
||||
);
|
||||
return new BannerPatternLayer(Holder.ofCustom(pattern), layer.color().getId());
|
||||
})
|
||||
.toList();
|
||||
}
|
||||
}
|
18
bootstrap/mod/src/main/resources/geyser.mixins.json
Normal file
18
bootstrap/mod/src/main/resources/geyser.mixins.json
Normal file
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"required": true,
|
||||
"minVersion": "0.8",
|
||||
"package": "org.geysermc.geyser.platform.mod.mixin",
|
||||
"compatibilityLevel": "JAVA_17",
|
||||
"mixins": [
|
||||
"server.ServerConnectionListenerMixin"
|
||||
],
|
||||
"server": [
|
||||
"server.DedicatedServerMixin"
|
||||
],
|
||||
"client": [
|
||||
"client.IntegratedServerMixin"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
}
|
||||
}
|
|
@ -4,25 +4,27 @@ dependencies {
|
|||
isTransitive = false
|
||||
}
|
||||
|
||||
implementation(libs.erosion.bukkit.nms) {
|
||||
attributes {
|
||||
attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 21)
|
||||
}
|
||||
}
|
||||
|
||||
implementation(variantOf(libs.adapters.spigot) {
|
||||
classifier("all") // otherwise the unshaded jar is used without the shaded NMS implementations
|
||||
})
|
||||
implementation(variantOf(libs.adapters.paper) {
|
||||
classifier("all") // otherwise the unshaded jar is used without the shaded NMS implementations
|
||||
})
|
||||
|
||||
implementation(libs.commodore)
|
||||
|
||||
implementation(libs.adventure.text.serializer.bungeecord)
|
||||
|
||||
// Both folia-api and paper-mojangapi only provide Java 17 versions for 1.19
|
||||
compileOnly(libs.folia.api) {
|
||||
attributes {
|
||||
attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 17)
|
||||
}
|
||||
}
|
||||
compileOnly(libs.paper.mojangapi) {
|
||||
attributes {
|
||||
attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 17)
|
||||
}
|
||||
}
|
||||
|
||||
compileOnly(libs.folia.api)
|
||||
compileOnly(libs.paper.mojangapi)
|
||||
|
||||
compileOnlyApi(libs.viaversion)
|
||||
}
|
||||
|
||||
platformRelocate("it.unimi.dsi.fastutil")
|
||||
|
@ -41,6 +43,12 @@ application {
|
|||
}
|
||||
|
||||
tasks.withType<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar> {
|
||||
|
||||
// Prevents Paper 1.20.5+ from remapping Geyser
|
||||
manifest {
|
||||
attributes["paperweight-mappings-namespace"] = "mojang"
|
||||
}
|
||||
|
||||
archiveBaseName.set("Geyser-Spigot")
|
||||
|
||||
dependencies {
|
||||
|
@ -48,6 +56,7 @@ tasks.withType<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar> {
|
|||
|
||||
// We cannot shade Netty, or else native libraries will not load
|
||||
// Needed because older Spigot builds do not provide the haproxy module
|
||||
exclude(dependency("io.netty.incubator:.*"))
|
||||
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:.*"))
|
||||
|
@ -67,3 +76,8 @@ tasks.withType<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar> {
|
|||
exclude(dependency("com.mojang:.*"))
|
||||
}
|
||||
}
|
||||
|
||||
modrinth {
|
||||
uploadFile.set(tasks.getByPath("shadowJar"))
|
||||
loaders.addAll("spigot", "paper")
|
||||
}
|
||||
|
|
|
@ -34,8 +34,8 @@ import java.util.logging.Logger;
|
|||
public final class GeyserPaperLogger extends GeyserSpigotLogger {
|
||||
private final ComponentLogger componentLogger;
|
||||
|
||||
public GeyserPaperLogger(Plugin plugin, Logger logger, boolean debug) {
|
||||
super(logger, debug);
|
||||
public GeyserPaperLogger(Plugin plugin, Logger logger) {
|
||||
super(logger);
|
||||
componentLogger = plugin.getComponentLogger();
|
||||
}
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
|
||||
package org.geysermc.geyser.platform.spigot;
|
||||
|
||||
import com.github.steveice10.mc.protocol.MinecraftProtocol;
|
||||
import org.geysermc.mcprotocollib.protocol.MinecraftProtocol;
|
||||
import com.viaversion.viaversion.bukkit.handlers.BukkitChannelInitializer;
|
||||
import io.netty.bootstrap.ServerBootstrap;
|
||||
import io.netty.channel.*;
|
||||
|
@ -119,8 +119,11 @@ public class GeyserSpigotInjector extends GeyserInjector {
|
|||
protected void initChannel(@NonNull Channel ch) throws Exception {
|
||||
initChannel.invoke(childHandler, ch);
|
||||
|
||||
int index = ch.pipeline().names().indexOf("encoder");
|
||||
String baseName = index != -1 ? "encoder" : "outbound_config";
|
||||
|
||||
if (bootstrap.getGeyserConfig().isDisableCompression() && GeyserSpigotCompressionDisabler.ENABLED) {
|
||||
ch.pipeline().addAfter("encoder", "geyser-compression-disabler", new GeyserSpigotCompressionDisabler());
|
||||
ch.pipeline().addAfter(baseName, "geyser-compression-disabler", new GeyserSpigotCompressionDisabler());
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -177,6 +180,7 @@ public class GeyserSpigotInjector extends GeyserInjector {
|
|||
bootstrap.getGeyserConfig().getRemote().port(), this.serverSocketAddress,
|
||||
InetAddress.getLoopbackAddress().getHostAddress(), protocol, protocol.createHelper());
|
||||
session.connect();
|
||||
session.disconnect("");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -25,15 +25,15 @@
|
|||
|
||||
package org.geysermc.geyser.platform.spigot;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import org.geysermc.geyser.GeyserLogger;
|
||||
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
@AllArgsConstructor
|
||||
@RequiredArgsConstructor
|
||||
public class GeyserSpigotLogger implements GeyserLogger {
|
||||
private final Logger logger;
|
||||
@Getter @Setter
|
||||
|
|
|
@ -46,6 +46,7 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
|||
import org.geysermc.geyser.Constants;
|
||||
import org.geysermc.geyser.GeyserBootstrap;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.adapters.paper.PaperAdapters;
|
||||
import org.geysermc.geyser.adapters.spigot.SpigotAdapters;
|
||||
import org.geysermc.geyser.api.command.Command;
|
||||
import org.geysermc.geyser.api.extension.Extension;
|
||||
|
@ -78,14 +79,14 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
|
||||
|
||||
private GeyserSpigotCommandManager geyserCommandManager;
|
||||
private GeyserSpigotConfiguration geyserConfig;
|
||||
private GeyserSpigotInjector geyserInjector;
|
||||
private GeyserSpigotLogger geyserLogger;
|
||||
private final GeyserSpigotLogger geyserLogger = GeyserPaperLogger.supported() ?
|
||||
new GeyserPaperLogger(this, getLogger()) : new GeyserSpigotLogger(getLogger());
|
||||
private IGeyserPingPassthrough geyserSpigotPingPassthrough;
|
||||
private GeyserSpigotWorldManager geyserWorldManager;
|
||||
|
||||
|
@ -113,12 +114,12 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
|
|||
// We depend on this as a fallback in certain scenarios
|
||||
BlockData.class.getMethod("getAsString");
|
||||
} catch (ClassNotFoundException | NoSuchMethodException e) {
|
||||
getLogger().severe("*********************************************");
|
||||
getLogger().severe("");
|
||||
getLogger().severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_server.header"));
|
||||
getLogger().severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_server.message", "1.13.2"));
|
||||
getLogger().severe("");
|
||||
getLogger().severe("*********************************************");
|
||||
geyserLogger.error("*********************************************");
|
||||
geyserLogger.error("");
|
||||
geyserLogger.error(GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_server.header"));
|
||||
geyserLogger.error(GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_server.message", "1.13.2"));
|
||||
geyserLogger.error("");
|
||||
geyserLogger.error("*********************************************");
|
||||
Bukkit.getPluginManager().disablePlugin(this);
|
||||
return;
|
||||
}
|
||||
|
@ -127,12 +128,12 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
|
|||
Class.forName("net.md_5.bungee.chat.ComponentSerializer");
|
||||
} catch (ClassNotFoundException e) {
|
||||
if (!PaperAdventure.canSendMessageUsingComponent()) { // Prepare for Paper eventually removing Bungee chat
|
||||
getLogger().severe("*********************************************");
|
||||
getLogger().severe("");
|
||||
getLogger().severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_server_type.header", getServer().getName()));
|
||||
getLogger().severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_server_type.message", "Paper"));
|
||||
getLogger().severe("");
|
||||
getLogger().severe("*********************************************");
|
||||
geyserLogger.error("*********************************************");
|
||||
geyserLogger.error("");
|
||||
geyserLogger.error(GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_server_type.header", getServer().getName()));
|
||||
geyserLogger.error(GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_server_type.message", "Paper"));
|
||||
geyserLogger.error("");
|
||||
geyserLogger.error("*********************************************");
|
||||
Bukkit.getPluginManager().disablePlugin(this);
|
||||
return;
|
||||
}
|
||||
|
@ -141,11 +142,11 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
|
|||
try {
|
||||
Class.forName("io.netty.util.internal.ObjectPool$ObjectCreator");
|
||||
} catch (ClassNotFoundException e) {
|
||||
getLogger().severe("*********************************************");
|
||||
getLogger().severe("");
|
||||
getLogger().severe("This version of Spigot is using an outdated version of netty. Please use Paper instead!");
|
||||
getLogger().severe("");
|
||||
getLogger().severe("*********************************************");
|
||||
geyserLogger.error("*********************************************");
|
||||
geyserLogger.error("");
|
||||
geyserLogger.error("This version of Spigot is using an outdated version of netty. Please use Paper instead!");
|
||||
geyserLogger.error("");
|
||||
geyserLogger.error("*********************************************");
|
||||
Bukkit.getPluginManager().disablePlugin(this);
|
||||
return;
|
||||
}
|
||||
|
@ -153,8 +154,7 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
|
|||
if (!loadConfig()) {
|
||||
return;
|
||||
}
|
||||
this.geyserLogger = GeyserPaperLogger.supported() ? new GeyserPaperLogger(this, getLogger(), geyserConfig.isDebugMode())
|
||||
: new GeyserSpigotLogger(getLogger(), geyserConfig.isDebugMode());
|
||||
this.geyserLogger.setDebug(geyserConfig.isDebugMode());
|
||||
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
|
||||
|
||||
// Turn "(MC: 1.16.4)" into 1.16.4.
|
||||
|
@ -244,17 +244,29 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
|
|||
|
||||
if (Boolean.parseBoolean(System.getProperty("Geyser.UseDirectAdapters", "true"))) {
|
||||
try {
|
||||
String name = Bukkit.getServer().getClass().getPackage().getName();
|
||||
String nmsVersion = name.substring(name.lastIndexOf('.') + 1);
|
||||
SpigotAdapters.registerWorldAdapter(nmsVersion);
|
||||
boolean isPaper = false;
|
||||
try {
|
||||
String name = Bukkit.getServer().getClass().getPackage().getName();
|
||||
String nmsVersion = name.substring(name.lastIndexOf('.') + 1);
|
||||
SpigotAdapters.registerWorldAdapter(nmsVersion);
|
||||
geyserLogger.debug("Using spigot NMS adapter for nms version: " + nmsVersion);
|
||||
} catch (Exception e) { // Likely running on Paper 1.20.5+
|
||||
geyserLogger.debug("Unable to find spigot world manager: " + e.getMessage());
|
||||
//noinspection deprecation
|
||||
int protocolVersion = Bukkit.getUnsafe().getProtocolVersion();
|
||||
PaperAdapters.registerClosestWorldAdapter(protocolVersion);
|
||||
isPaper = true;
|
||||
geyserLogger.debug("Using paper world adapter for protocol version: " + protocolVersion);
|
||||
}
|
||||
|
||||
if (isViaVersion && isViaVersionNeeded()) {
|
||||
this.geyserWorldManager = new GeyserSpigotLegacyNativeWorldManager(this);
|
||||
this.geyserWorldManager = new GeyserSpigotLegacyNativeWorldManager(this, isPaper);
|
||||
} else {
|
||||
// No ViaVersion
|
||||
this.geyserWorldManager = new GeyserSpigotNativeWorldManager(this);
|
||||
this.geyserWorldManager = new GeyserSpigotNativeWorldManager(this, isPaper);
|
||||
}
|
||||
geyserLogger.debug("Using NMS adapter: " + this.geyserWorldManager.getClass() + ", " + nmsVersion);
|
||||
} catch (Exception e) {
|
||||
geyserLogger.debug("Using world manager of type: " + this.geyserWorldManager.getClass().getSimpleName());
|
||||
} catch (Throwable e) {
|
||||
if (geyserConfig.isDebugMode()) {
|
||||
geyserLogger.debug("Error while attempting to find NMS adapter. Most likely, this can be safely ignored. :)");
|
||||
e.printStackTrace();
|
||||
|
@ -433,7 +445,7 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
|
|||
return false;
|
||||
}
|
||||
for (int i = protocolList.size() - 1; i >= 0; i--) {
|
||||
MappingData mappingData = protocolList.get(i).getProtocol().getMappingData();
|
||||
MappingData mappingData = protocolList.get(i).protocol().getMappingData();
|
||||
if (mappingData != null) {
|
||||
return true;
|
||||
}
|
||||
|
@ -474,7 +486,7 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
|
|||
(x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()), this);
|
||||
this.geyserConfig = FileUtils.loadConfig(configFile, GeyserSpigotConfiguration.class);
|
||||
} catch (IOException ex) {
|
||||
getLogger().log(Level.SEVERE, GeyserLocale.getLocaleStringLog("geyser.config.failed"), ex);
|
||||
geyserLogger.error(GeyserLocale.getLocaleStringLog("geyser.config.failed"), ex);
|
||||
ex.printStackTrace();
|
||||
Bukkit.getPluginManager().disablePlugin(this);
|
||||
return false;
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
|
||||
package org.geysermc.geyser.platform.spigot;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.DefaultComponentSerializer;
|
||||
import org.geysermc.mcprotocollib.protocol.data.DefaultComponentSerializer;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
|
|
@ -25,10 +25,8 @@
|
|||
|
||||
package org.geysermc.geyser.platform.spigot.world;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.level.block.value.PistonValueType;
|
||||
import org.cloudburstmc.math.vector.Vector3i;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntArrayMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
|
@ -40,13 +38,17 @@ import org.bukkit.event.Listener;
|
|||
import org.bukkit.event.block.BlockPistonEvent;
|
||||
import org.bukkit.event.block.BlockPistonExtendEvent;
|
||||
import org.bukkit.event.block.BlockPistonRetractEvent;
|
||||
import org.cloudburstmc.math.vector.Vector3i;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.level.block.BlockStateValues;
|
||||
import org.geysermc.geyser.level.block.property.Properties;
|
||||
import org.geysermc.geyser.level.block.type.BlockState;
|
||||
import org.geysermc.geyser.level.physics.Direction;
|
||||
import org.geysermc.geyser.platform.spigot.world.manager.GeyserSpigotWorldManager;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.session.cache.PistonCache;
|
||||
import org.geysermc.geyser.translator.level.block.entity.PistonBlockEntity;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.level.block.value.PistonValueType;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -85,7 +87,7 @@ public class GeyserPistonListener implements Listener {
|
|||
PistonValueType type = isExtend ? PistonValueType.PUSHING : PistonValueType.PULLING;
|
||||
boolean sticky = event.isSticky();
|
||||
|
||||
Object2IntMap<Vector3i> attachedBlocks = new Object2IntArrayMap<>();
|
||||
Object2ObjectMap<Vector3i, BlockState> attachedBlocks = new Object2ObjectArrayMap<>();
|
||||
boolean blocksFilled = false;
|
||||
|
||||
for (Map.Entry<UUID, GeyserSession> entry : geyser.getSessionManager().getSessions().entrySet()) {
|
||||
|
@ -108,10 +110,10 @@ public class GeyserPistonListener implements Listener {
|
|||
List<Block> blocks = isExtend ? ((BlockPistonExtendEvent) event).getBlocks() : ((BlockPistonRetractEvent) event).getBlocks();
|
||||
for (Block block : blocks) {
|
||||
Location attachedLocation = block.getLocation();
|
||||
int blockId = worldManager.getBlockNetworkId(block);
|
||||
BlockState state = BlockState.of(worldManager.getBlockNetworkId(block));
|
||||
// Ignore blocks that will be destroyed
|
||||
if (BlockStateValues.canPistonMoveBlock(blockId, isExtend)) {
|
||||
attachedBlocks.put(getVector(attachedLocation), blockId);
|
||||
if (BlockStateValues.canPistonMoveBlock(state, isExtend)) {
|
||||
attachedBlocks.put(getVector(attachedLocation), state);
|
||||
}
|
||||
}
|
||||
blocksFilled = true;
|
||||
|
@ -119,7 +121,7 @@ public class GeyserPistonListener implements Listener {
|
|||
|
||||
int pistonBlockId = worldManager.getBlockNetworkId(event.getBlock());
|
||||
// event.getDirection() is unreliable
|
||||
Direction orientation = BlockStateValues.getPistonOrientation(pistonBlockId);
|
||||
Direction orientation = BlockState.of(pistonBlockId).getValue(Properties.FACING);
|
||||
|
||||
session.executeInEventLoop(() -> {
|
||||
PistonCache pistonCache = session.getPistonCache();
|
||||
|
|
|
@ -33,7 +33,7 @@ import org.bukkit.event.EventHandler;
|
|||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.block.BlockPlaceEvent;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.level.block.BlockStateValues;
|
||||
import org.geysermc.geyser.level.block.type.Block;
|
||||
import org.geysermc.geyser.platform.spigot.world.manager.GeyserSpigotWorldManager;
|
||||
import org.geysermc.geyser.registry.BlockRegistries;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
|
@ -59,11 +59,11 @@ public class GeyserSpigotBlockPlaceListener implements Listener {
|
|||
event.getBlockPlaced().getX(), event.getBlockPlaced().getY(), event.getBlockPlaced().getZ())));
|
||||
} else {
|
||||
String javaBlockId = event.getBlockPlaced().getBlockData().getAsString();
|
||||
placeBlockSoundPacket.setExtraData(session.getBlockMappings().getBedrockBlockId(BlockRegistries.JAVA_IDENTIFIER_TO_ID.get().getOrDefault(javaBlockId, BlockStateValues.JAVA_AIR_ID)));
|
||||
placeBlockSoundPacket.setExtraData(session.getBlockMappings().getBedrockBlockId(BlockRegistries.JAVA_IDENTIFIER_TO_ID.get().getOrDefault(javaBlockId, Block.JAVA_AIR_ID)));
|
||||
}
|
||||
placeBlockSoundPacket.setIdentifier(":");
|
||||
session.sendUpstreamPacket(placeBlockSoundPacket);
|
||||
session.setLastBlockPlacePosition(null);
|
||||
session.setLastBlockPlacedId(null);
|
||||
session.setLastBlockPlaced(null);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,8 +46,8 @@ public class GeyserSpigotLegacyNativeWorldManager extends GeyserSpigotNativeWorl
|
|||
|
||||
private final Int2IntMap oldToNewBlockId;
|
||||
|
||||
public GeyserSpigotLegacyNativeWorldManager(GeyserSpigotPlugin plugin) {
|
||||
super(plugin);
|
||||
public GeyserSpigotLegacyNativeWorldManager(GeyserSpigotPlugin plugin, boolean isPaper) {
|
||||
super(plugin, isPaper);
|
||||
IntList allBlockStates = adapter.getAllBlockStates();
|
||||
oldToNewBlockId = new Int2IntOpenHashMap(allBlockStates.size());
|
||||
ProtocolVersion serverVersion = plugin.getServerProtocolVersion();
|
||||
|
@ -58,7 +58,7 @@ public class GeyserSpigotLegacyNativeWorldManager extends GeyserSpigotNativeWorl
|
|||
int newBlockId = oldBlockId;
|
||||
// protocolList should *not* be null; we checked for that before initializing this class
|
||||
for (int i = protocolList.size() - 1; i >= 0; i--) {
|
||||
MappingData mappingData = protocolList.get(i).getProtocol().getMappingData();
|
||||
MappingData mappingData = protocolList.get(i).protocol().getMappingData();
|
||||
if (mappingData != null) {
|
||||
newBlockId = mappingData.getNewBlockStateId(newBlockId);
|
||||
}
|
||||
|
|
|
@ -26,27 +26,34 @@
|
|||
package org.geysermc.geyser.platform.spigot.world.manager;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.geysermc.geyser.adapters.WorldAdapter;
|
||||
import org.geysermc.geyser.adapters.paper.PaperAdapters;
|
||||
import org.geysermc.geyser.adapters.spigot.SpigotAdapters;
|
||||
import org.geysermc.geyser.adapters.spigot.SpigotWorldAdapter;
|
||||
import org.geysermc.geyser.level.block.BlockStateValues;
|
||||
import org.geysermc.geyser.level.block.type.Block;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
|
||||
public class GeyserSpigotNativeWorldManager extends GeyserSpigotWorldManager {
|
||||
protected final SpigotWorldAdapter adapter;
|
||||
protected final WorldAdapter<World> adapter;
|
||||
|
||||
public GeyserSpigotNativeWorldManager(Plugin plugin) {
|
||||
public GeyserSpigotNativeWorldManager(Plugin plugin, boolean isPaper) {
|
||||
super(plugin);
|
||||
adapter = SpigotAdapters.getWorldAdapter();
|
||||
if (isPaper) {
|
||||
adapter = PaperAdapters.getWorldAdapter();
|
||||
} else {
|
||||
adapter = SpigotAdapters.getWorldAdapter();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBlockAt(GeyserSession session, int x, int y, int z) {
|
||||
Player player = Bukkit.getPlayer(session.getPlayerEntity().getUsername());
|
||||
if (player == null) {
|
||||
return BlockStateValues.JAVA_AIR_ID;
|
||||
return Block.JAVA_AIR_ID;
|
||||
}
|
||||
return adapter.getBlockAt(player.getWorld(), x, y, z);
|
||||
}
|
||||
|
|
|
@ -25,31 +25,24 @@
|
|||
|
||||
package org.geysermc.geyser.platform.spigot.world.manager;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode;
|
||||
import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityInfo;
|
||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.cloudburstmc.nbt.NbtMap;
|
||||
import org.geysermc.erosion.bukkit.BukkitLecterns;
|
||||
import org.geysermc.erosion.bukkit.BukkitUtils;
|
||||
import org.geysermc.erosion.bukkit.PickBlockUtils;
|
||||
import org.geysermc.erosion.bukkit.SchedulerUtils;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.level.GameRule;
|
||||
import org.geysermc.geyser.level.WorldManager;
|
||||
import org.geysermc.geyser.level.block.BlockStateValues;
|
||||
import org.geysermc.geyser.registry.BlockRegistries;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.util.BlockEntityUtils;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
|
@ -58,23 +51,21 @@ import java.util.concurrent.CompletableFuture;
|
|||
*/
|
||||
public class GeyserSpigotWorldManager extends WorldManager {
|
||||
private final Plugin plugin;
|
||||
private final BukkitLecterns lecterns;
|
||||
|
||||
public GeyserSpigotWorldManager(Plugin plugin) {
|
||||
this.plugin = plugin;
|
||||
this.lecterns = new BukkitLecterns(plugin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBlockAt(GeyserSession session, int x, int y, int z) {
|
||||
Player bukkitPlayer;
|
||||
if ((bukkitPlayer = Bukkit.getPlayer(session.getPlayerEntity().getUsername())) == null) {
|
||||
return BlockStateValues.JAVA_AIR_ID;
|
||||
return org.geysermc.geyser.level.block.type.Block.JAVA_AIR_ID;
|
||||
}
|
||||
World world = bukkitPlayer.getWorld();
|
||||
if (!world.isChunkLoaded(x >> 4, z >> 4)) {
|
||||
// If the chunk isn't loaded, how could we even be here?
|
||||
return BlockStateValues.JAVA_AIR_ID;
|
||||
return org.geysermc.geyser.level.block.type.Block.JAVA_AIR_ID;
|
||||
}
|
||||
|
||||
return getBlockNetworkId(world.getBlockAt(x, y, z));
|
||||
|
@ -85,9 +76,9 @@ public class GeyserSpigotWorldManager extends WorldManager {
|
|||
// Terrible behavior, but this is basically what's always been happening behind the scenes anyway.
|
||||
CompletableFuture<String> blockData = new CompletableFuture<>();
|
||||
Bukkit.getRegionScheduler().execute(this.plugin, block.getLocation(), () -> blockData.complete(block.getBlockData().getAsString()));
|
||||
return BlockRegistries.JAVA_IDENTIFIER_TO_ID.getOrDefault(blockData.join(), BlockStateValues.JAVA_AIR_ID);
|
||||
return BlockRegistries.JAVA_IDENTIFIER_TO_ID.getOrDefault(blockData.join(), org.geysermc.geyser.level.block.type.Block.JAVA_AIR_ID);
|
||||
}
|
||||
return BlockRegistries.JAVA_IDENTIFIER_TO_ID.getOrDefault(block.getBlockData().getAsString(), BlockStateValues.JAVA_AIR_ID);
|
||||
return BlockRegistries.JAVA_IDENTIFIER_TO_ID.getOrDefault(block.getBlockData().getAsString(), org.geysermc.geyser.level.block.type.Block.JAVA_AIR_ID); // TODO could just make this a BlockState lookup?
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -95,69 +86,6 @@ public class GeyserSpigotWorldManager extends WorldManager {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendLecternData(GeyserSession session, int x, int y, int z) {
|
||||
Player bukkitPlayer;
|
||||
if ((bukkitPlayer = Bukkit.getPlayer(session.getPlayerEntity().getUsername())) == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Block block = bukkitPlayer.getWorld().getBlockAt(x, y, z);
|
||||
// Run as a task to prevent async issues
|
||||
SchedulerUtils.runTask(this.plugin, () -> sendLecternData(session, block, false), block);
|
||||
}
|
||||
|
||||
public void sendLecternData(GeyserSession session, int x, int z, List<BlockEntityInfo> blockEntityInfos) {
|
||||
Player bukkitPlayer;
|
||||
if ((bukkitPlayer = Bukkit.getPlayer(session.getPlayerEntity().getUsername())) == null) {
|
||||
return;
|
||||
}
|
||||
if (SchedulerUtils.FOLIA) {
|
||||
Chunk chunk = getChunk(bukkitPlayer.getWorld(), x, z);
|
||||
if (chunk == null) {
|
||||
return;
|
||||
}
|
||||
Bukkit.getRegionScheduler().execute(this.plugin, bukkitPlayer.getWorld(), x, z, () ->
|
||||
sendLecternData(session, chunk, blockEntityInfos));
|
||||
} else {
|
||||
Bukkit.getScheduler().runTask(this.plugin, () -> {
|
||||
Chunk chunk = getChunk(bukkitPlayer.getWorld(), x, z);
|
||||
if (chunk == null) {
|
||||
return;
|
||||
}
|
||||
sendLecternData(session, chunk, blockEntityInfos);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private @Nullable Chunk getChunk(World world, int x, int z) {
|
||||
if (!world.isChunkLoaded(x, z)) {
|
||||
return null;
|
||||
}
|
||||
return world.getChunkAt(x, z);
|
||||
}
|
||||
|
||||
private void sendLecternData(GeyserSession session, Chunk chunk, List<BlockEntityInfo> blockEntityInfos) {
|
||||
//noinspection ForLoopReplaceableByForEach - avoid constructing Iterator
|
||||
for (int i = 0; i < blockEntityInfos.size(); i++) {
|
||||
BlockEntityInfo info = blockEntityInfos.get(i);
|
||||
Block block = chunk.getBlock(info.getX(), info.getY(), info.getZ());
|
||||
sendLecternData(session, block, true);
|
||||
}
|
||||
}
|
||||
|
||||
private void sendLecternData(GeyserSession session, Block block, boolean isChunkLoad) {
|
||||
NbtMap blockEntityTag = this.lecterns.getLecternData(block, isChunkLoad);
|
||||
if (blockEntityTag != null) {
|
||||
BlockEntityUtils.updateBlockEntity(session, blockEntityTag, BukkitUtils.getVector(block.getLocation()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldExpectLecternHandled(GeyserSession session) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean getGameRuleBool(GeyserSession session, GameRule gameRule) {
|
||||
org.bukkit.GameRule<?> bukkitGameRule = org.bukkit.GameRule.getByName(gameRule.getJavaID());
|
||||
if (bukkitGameRule == null) {
|
||||
|
@ -205,18 +133,17 @@ public class GeyserSpigotWorldManager extends WorldManager {
|
|||
}
|
||||
|
||||
@Override
|
||||
public @NonNull CompletableFuture<@Nullable CompoundTag> getPickItemNbt(GeyserSession session, int x, int y, int z, boolean addNbtData) {
|
||||
CompletableFuture<@Nullable CompoundTag> future = new CompletableFuture<>();
|
||||
public @NonNull CompletableFuture<@Nullable DataComponents> getPickItemComponents(GeyserSession session, int x, int y, int z, boolean addNbtData) {
|
||||
Player bukkitPlayer;
|
||||
if ((bukkitPlayer = Bukkit.getPlayer(session.getPlayerEntity().getUuid())) == null) {
|
||||
future.complete(null);
|
||||
return future;
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
CompletableFuture<Int2ObjectMap<byte[]>> future = new CompletableFuture<>();
|
||||
Block block = bukkitPlayer.getWorld().getBlockAt(x, y, z);
|
||||
// Paper 1.19.3 complains about async access otherwise.
|
||||
// java.lang.IllegalStateException: Tile is null, asynchronous access?
|
||||
SchedulerUtils.runTask(this.plugin, () -> future.complete(PickBlockUtils.pickBlock(block)), block);
|
||||
return future;
|
||||
return future.thenApply(RAW_TRANSFORMER);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -71,7 +71,7 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap {
|
|||
|
||||
private GeyserCommandManager geyserCommandManager;
|
||||
private GeyserStandaloneConfiguration geyserConfig;
|
||||
private GeyserStandaloneLogger geyserLogger;
|
||||
private final GeyserStandaloneLogger geyserLogger = new GeyserStandaloneLogger();
|
||||
private IGeyserPingPassthrough geyserPingPassthrough;
|
||||
private GeyserStandaloneGUI gui;
|
||||
@Getter
|
||||
|
@ -181,8 +181,6 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap {
|
|||
}
|
||||
}
|
||||
|
||||
this.geyserLogger = new GeyserStandaloneLogger();
|
||||
|
||||
if (useGui && gui == null) {
|
||||
gui = new GeyserStandaloneGUI(geyserLogger);
|
||||
gui.redirectSystemStreams();
|
||||
|
|
|
@ -100,7 +100,7 @@ public class GeyserStandaloneGUI {
|
|||
Container cp = frame.getContentPane();
|
||||
|
||||
// Fetch and set the icon for the frame
|
||||
URL image = getClass().getClassLoader().getResource("icon.png");
|
||||
URL image = getClass().getClassLoader().getResource("assets/geyser/icon.png");
|
||||
if (image != null) {
|
||||
ImageIcon icon = new ImageIcon(image);
|
||||
frame.setIconImage(icon.getImage());
|
||||
|
|
|
@ -1,15 +1,19 @@
|
|||
dependencies {
|
||||
annotationProcessor(libs.velocity.api)
|
||||
api(projects.core)
|
||||
|
||||
compileOnlyApi(libs.velocity.api)
|
||||
}
|
||||
|
||||
platformRelocate("com.fasterxml.jackson")
|
||||
platformRelocate("it.unimi.dsi.fastutil")
|
||||
platformRelocate("net.kyori.adventure.text.serializer.gson.legacyimpl")
|
||||
platformRelocate("org.yaml")
|
||||
|
||||
exclude("com.google.*:*")
|
||||
|
||||
// Needed because Velocity provides every dependency except netty-resolver-dns
|
||||
// Needed because Velocity provides every dependency except netty-resolver-dns
|
||||
exclude("io.netty.incubator:.*")
|
||||
exclude("io.netty:netty-transport-native-epoll:*")
|
||||
exclude("io.netty:netty-transport-native-unix-common:*")
|
||||
exclude("io.netty:netty-transport-native-kqueue:*")
|
||||
|
@ -54,6 +58,7 @@ tasks.withType<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar> {
|
|||
exclude(dependency("io.netty:netty-transport:.*"))
|
||||
exclude(dependency("io.netty:netty-codec:.*"))
|
||||
exclude(dependency("io.netty:netty-codec-haproxy:.*"))
|
||||
exclude(dependency("io.netty.incubator:.*"))
|
||||
exclude(dependency("org.slf4j:.*"))
|
||||
exclude(dependency("org.ow2.asm:.*"))
|
||||
// Exclude all Kyori dependencies except the legacy NBT serializer
|
||||
|
@ -64,4 +69,9 @@ tasks.withType<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar> {
|
|||
exclude(dependency("net.kyori:adventure-text-serializer-legacy:.*"))
|
||||
exclude(dependency("net.kyori:adventure-nbt:.*"))
|
||||
}
|
||||
}
|
||||
|
||||
modrinth {
|
||||
uploadFile.set(tasks.getByPath("shadowJar"))
|
||||
loaders.addAll("velocity")
|
||||
}
|
|
@ -25,13 +25,13 @@
|
|||
|
||||
package org.geysermc.geyser.platform.velocity;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import org.geysermc.geyser.GeyserLogger;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
@AllArgsConstructor
|
||||
@RequiredArgsConstructor
|
||||
public class GeyserVelocityLogger implements GeyserLogger {
|
||||
private final Logger logger;
|
||||
@Getter @Setter
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
package org.geysermc.geyser.platform.velocity;
|
||||
|
||||
import com.velocitypowered.api.event.proxy.ProxyPingEvent;
|
||||
import com.velocitypowered.api.network.ProtocolState;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.api.proxy.InboundConnection;
|
||||
import com.velocitypowered.api.proxy.ProxyServer;
|
||||
|
@ -88,6 +89,11 @@ public class GeyserVelocityPingPassthrough implements IGeyserPingPassthrough {
|
|||
public ProtocolVersion getProtocolVersion() {
|
||||
return ProtocolVersion.MAXIMUM_VERSION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProtocolState getProtocolState() {
|
||||
return ProtocolState.STATUS;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -64,44 +64,44 @@ import java.util.UUID;
|
|||
|
||||
@Plugin(id = "geyser", name = GeyserImpl.NAME + "-Velocity", version = GeyserImpl.VERSION, url = "https://geysermc.org", authors = "GeyserMC")
|
||||
public class GeyserVelocityPlugin implements GeyserBootstrap {
|
||||
@Inject
|
||||
private Logger logger;
|
||||
|
||||
@Inject
|
||||
private ProxyServer proxyServer;
|
||||
|
||||
@Inject
|
||||
private CommandManager commandManager;
|
||||
|
||||
private final ProxyServer proxyServer;
|
||||
private final CommandManager commandManager;
|
||||
private final GeyserVelocityLogger geyserLogger;
|
||||
private GeyserCommandManager geyserCommandManager;
|
||||
private GeyserVelocityConfiguration geyserConfig;
|
||||
private GeyserVelocityInjector geyserInjector;
|
||||
private GeyserVelocityLogger geyserLogger;
|
||||
private IGeyserPingPassthrough geyserPingPassthrough;
|
||||
|
||||
private GeyserImpl geyser;
|
||||
|
||||
@Getter
|
||||
private final Path configFolder = Paths.get("plugins/" + GeyserImpl.NAME + "-Velocity/");
|
||||
|
||||
@Inject
|
||||
public GeyserVelocityPlugin(ProxyServer server, Logger logger, CommandManager manager) {
|
||||
this.geyserLogger = new GeyserVelocityLogger(logger);
|
||||
this.proxyServer = server;
|
||||
this.commandManager = manager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGeyserInitialize() {
|
||||
GeyserLocale.init(this);
|
||||
|
||||
if (!ProtocolVersion.isSupported(GameProtocol.getJavaProtocolVersion())) {
|
||||
logger.error(" / \\");
|
||||
logger.error(" / \\");
|
||||
logger.error(" / | \\");
|
||||
logger.error(" / | \\ " + GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_proxy", proxyServer.getVersion().getName()));
|
||||
logger.error(" / \\ " + GeyserLocale.getLocaleStringLog("geyser.may_not_work_as_intended_all_caps"));
|
||||
logger.error(" / o \\");
|
||||
logger.error("/_____________\\");
|
||||
geyserLogger.error(" / \\");
|
||||
geyserLogger.error(" / \\");
|
||||
geyserLogger.error(" / | \\");
|
||||
geyserLogger.error(" / | \\ " + GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_proxy", proxyServer.getVersion().getName()));
|
||||
geyserLogger.error(" / \\ " + GeyserLocale.getLocaleStringLog("geyser.may_not_work_as_intended_all_caps"));
|
||||
geyserLogger.error(" / o \\");
|
||||
geyserLogger.error("/_____________\\");
|
||||
}
|
||||
|
||||
if (!loadConfig()) {
|
||||
return;
|
||||
}
|
||||
this.geyserLogger = new GeyserVelocityLogger(logger, geyserConfig.isDebugMode());
|
||||
this.geyserLogger.setDebug(geyserConfig.isDebugMode());
|
||||
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
|
||||
|
||||
this.geyser = GeyserImpl.load(PlatformType.VELOCITY, this);
|
||||
|
@ -249,7 +249,7 @@ public class GeyserVelocityPlugin implements GeyserBootstrap {
|
|||
"config.yml", (x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()), this);
|
||||
this.geyserConfig = FileUtils.loadConfig(configFile, GeyserVelocityConfiguration.class);
|
||||
} catch (IOException ex) {
|
||||
logger.error(GeyserLocale.getLocaleStringLog("geyser.config.failed"), ex);
|
||||
geyserLogger.error(GeyserLocale.getLocaleStringLog("geyser.config.failed"), ex);
|
||||
ex.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
|
|
29
bootstrap/viaproxy/build.gradle.kts
Normal file
29
bootstrap/viaproxy/build.gradle.kts
Normal file
|
@ -0,0 +1,29 @@
|
|||
dependencies {
|
||||
api(projects.core)
|
||||
|
||||
compileOnlyApi(libs.viaproxy)
|
||||
}
|
||||
|
||||
platformRelocate("net.kyori")
|
||||
platformRelocate("org.yaml")
|
||||
platformRelocate("it.unimi.dsi.fastutil")
|
||||
platformRelocate("org.cloudburstmc.netty")
|
||||
|
||||
// These dependencies are already present on the platform
|
||||
provided(libs.viaproxy)
|
||||
|
||||
application {
|
||||
mainClass.set("org.geysermc.geyser.platform.viaproxy.GeyserViaProxyMain")
|
||||
}
|
||||
|
||||
tasks.withType<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar> {
|
||||
archiveBaseName.set("Geyser-ViaProxy")
|
||||
|
||||
dependencies {
|
||||
exclude(dependency("com.google.*:.*"))
|
||||
exclude(dependency("io.netty:.*"))
|
||||
exclude(dependency("io.netty.incubator:.*"))
|
||||
exclude(dependency("org.slf4j:.*"))
|
||||
exclude(dependency("org.ow2.asm:.*"))
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* 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.viaproxy;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import net.raphimc.vialegacy.api.LegacyProtocolVersion;
|
||||
import net.raphimc.viaproxy.ViaProxy;
|
||||
import net.raphimc.viaproxy.protocoltranslator.viaproxy.ViaProxyConfig;
|
||||
import org.geysermc.geyser.configuration.GeyserJacksonConfiguration;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@SuppressWarnings("FieldMayBeFinal") // Jackson requires that the fields are not final
|
||||
public class GeyserViaProxyConfiguration extends GeyserJacksonConfiguration {
|
||||
|
||||
private RemoteConfiguration remote = new RemoteConfiguration() {
|
||||
@Override
|
||||
public boolean isForwardHost() {
|
||||
return super.isForwardHost() || !ViaProxy.getConfig().getWildcardDomainHandling().equals(ViaProxyConfig.WildcardDomainHandling.NONE);
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public Path getFloodgateKeyPath() {
|
||||
return new File(GeyserViaProxyPlugin.ROOT_FOLDER, this.getFloodgateKeyFile()).toPath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPingPassthroughInterval() {
|
||||
int interval = super.getPingPassthroughInterval();
|
||||
if (interval < 15 && ViaProxy.getConfig().getTargetVersion() != null && ViaProxy.getConfig().getTargetVersion().olderThanOrEqualTo(LegacyProtocolVersion.r1_6_4)) {
|
||||
// <= 1.6.4 servers sometimes block incoming connections from an IP address if too many connections are made
|
||||
interval = 15;
|
||||
}
|
||||
return interval;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RemoteConfiguration getRemote() {
|
||||
return this.remote;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* 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.viaproxy;
|
||||
|
||||
import lombok.Getter;
|
||||
import net.raphimc.viaproxy.ViaProxy;
|
||||
import net.raphimc.viaproxy.plugins.ViaProxyPlugin;
|
||||
import org.geysermc.geyser.dump.BootstrapDumpInfo;
|
||||
import org.geysermc.geyser.text.AsteriskSerializer;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
public class GeyserViaProxyDumpInfo extends BootstrapDumpInfo {
|
||||
|
||||
private final String platformVersion;
|
||||
private final boolean onlineMode;
|
||||
|
||||
@AsteriskSerializer.Asterisk(isIp = true)
|
||||
private final String serverIP;
|
||||
private final int serverPort;
|
||||
private final List<PluginInfo> plugins;
|
||||
|
||||
public GeyserViaProxyDumpInfo() {
|
||||
this.platformVersion = ViaProxy.VERSION;
|
||||
this.onlineMode = ViaProxy.getConfig().isProxyOnlineMode();
|
||||
if (ViaProxy.getConfig().getBindAddress() instanceof InetSocketAddress inetSocketAddress) {
|
||||
this.serverIP = inetSocketAddress.getHostString();
|
||||
this.serverPort = inetSocketAddress.getPort();
|
||||
} else {
|
||||
this.serverIP = "unsupported";
|
||||
this.serverPort = 0;
|
||||
}
|
||||
this.plugins = new ArrayList<>();
|
||||
|
||||
for (ViaProxyPlugin plugin : ViaProxy.getPluginManager().getPlugins()) {
|
||||
this.plugins.add(new PluginInfo(true, plugin.getName(), plugin.getVersion(), "unknown", Collections.singletonList(plugin.getAuthor())));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* 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.viaproxy;
|
||||
|
||||
import net.raphimc.viaproxy.cli.ConsoleFormatter;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.geysermc.geyser.GeyserLogger;
|
||||
import org.geysermc.geyser.command.GeyserCommandSource;
|
||||
|
||||
public class GeyserViaProxyLogger implements GeyserLogger, GeyserCommandSource {
|
||||
|
||||
private final Logger logger;
|
||||
private boolean debug;
|
||||
|
||||
public GeyserViaProxyLogger(Logger logger) {
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void severe(String message) {
|
||||
this.logger.fatal(ConsoleFormatter.convert(message));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void severe(String message, Throwable error) {
|
||||
this.logger.fatal(ConsoleFormatter.convert(message), error);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(String message) {
|
||||
this.logger.error(ConsoleFormatter.convert(message));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(String message, Throwable error) {
|
||||
this.logger.error(ConsoleFormatter.convert(message), error);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warning(String message) {
|
||||
this.logger.warn(ConsoleFormatter.convert(message));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(String message) {
|
||||
this.logger.info(ConsoleFormatter.convert(message));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(String message) {
|
||||
if (this.debug) {
|
||||
this.logger.debug(ConsoleFormatter.convert(message));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDebug(boolean debug) {
|
||||
this.debug = debug;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDebug() {
|
||||
return this.debug;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* 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.viaproxy;
|
||||
|
||||
import org.geysermc.geyser.GeyserMain;
|
||||
|
||||
public class GeyserViaProxyMain extends GeyserMain {
|
||||
|
||||
public static void main(String[] args) {
|
||||
new GeyserViaProxyMain().displayMessage();
|
||||
}
|
||||
|
||||
public String getPluginType() {
|
||||
return "ViaProxy";
|
||||
}
|
||||
|
||||
public String getPluginFolder() {
|
||||
return "plugins";
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,226 @@
|
|||
/*
|
||||
* 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.viaproxy;
|
||||
|
||||
import net.lenni0451.lambdaevents.EventHandler;
|
||||
import net.raphimc.vialegacy.api.LegacyProtocolVersion;
|
||||
import net.raphimc.viaproxy.ViaProxy;
|
||||
import net.raphimc.viaproxy.plugins.PluginManager;
|
||||
import net.raphimc.viaproxy.plugins.ViaProxyPlugin;
|
||||
import net.raphimc.viaproxy.plugins.events.ConsoleCommandEvent;
|
||||
import net.raphimc.viaproxy.plugins.events.ProxyStartEvent;
|
||||
import net.raphimc.viaproxy.plugins.events.ProxyStopEvent;
|
||||
import net.raphimc.viaproxy.plugins.events.ShouldVerifyOnlineModeEvent;
|
||||
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.event.EventRegistrar;
|
||||
import org.geysermc.geyser.api.network.AuthType;
|
||||
import org.geysermc.geyser.api.util.PlatformType;
|
||||
import org.geysermc.geyser.command.GeyserCommandManager;
|
||||
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.viaproxy.listener.GeyserServerTransferListener;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.text.GeyserLocale;
|
||||
import org.geysermc.geyser.util.FileUtils;
|
||||
import org.geysermc.geyser.util.LoopbackUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.UUID;
|
||||
|
||||
public class GeyserViaProxyPlugin extends ViaProxyPlugin implements GeyserBootstrap, EventRegistrar {
|
||||
|
||||
public static final File ROOT_FOLDER = new File(PluginManager.PLUGINS_DIR, "Geyser");
|
||||
|
||||
private final GeyserViaProxyLogger logger = new GeyserViaProxyLogger(LogManager.getLogger("Geyser"));
|
||||
private GeyserViaProxyConfiguration config;
|
||||
private GeyserImpl geyser;
|
||||
private GeyserCommandManager commandManager;
|
||||
private IGeyserPingPassthrough pingPassthrough;
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
ROOT_FOLDER.mkdirs();
|
||||
|
||||
GeyserLocale.init(this);
|
||||
this.onGeyserInitialize();
|
||||
|
||||
ViaProxy.EVENT_MANAGER.register(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
this.onGeyserShutdown();
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
private void onConsoleCommand(final ConsoleCommandEvent event) {
|
||||
final String command = event.getCommand().startsWith("/") ? event.getCommand().substring(1) : event.getCommand();
|
||||
if (this.getGeyserCommandManager().runCommand(this.getGeyserLogger(), command + " " + String.join(" ", event.getArgs()))) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
private void onShouldVerifyOnlineModeEvent(final ShouldVerifyOnlineModeEvent event) {
|
||||
final UUID uuid = event.getProxyConnection().getGameProfile().getId();
|
||||
if (uuid == null) return;
|
||||
|
||||
final GeyserSession connection = GeyserImpl.getInstance().onlineConnections().stream().filter(s -> s.javaUuid().equals(uuid)).findAny().orElse(null);
|
||||
if (connection == null) return;
|
||||
|
||||
if (connection.javaUsername().equals(event.getProxyConnection().getGameProfile().getName())) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
private void onProxyStart(final ProxyStartEvent event) {
|
||||
this.onGeyserEnable();
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
private void onProxyStop(final ProxyStopEvent event) {
|
||||
this.onGeyserDisable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGeyserInitialize() {
|
||||
if (!this.loadConfig()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.geyser = GeyserImpl.load(PlatformType.VIAPROXY, this);
|
||||
this.geyser.eventBus().register(this, new GeyserServerTransferListener());
|
||||
LoopbackUtil.checkAndApplyLoopback(this.logger);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGeyserEnable() {
|
||||
if (GeyserImpl.getInstance().isReloading()) {
|
||||
if (!this.loadConfig()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this.commandManager = new GeyserCommandManager(this.geyser);
|
||||
this.commandManager.init();
|
||||
|
||||
GeyserImpl.start();
|
||||
|
||||
if (ViaProxy.getConfig().getTargetVersion() != null && ViaProxy.getConfig().getTargetVersion().newerThanOrEqualTo(LegacyProtocolVersion.b1_8tob1_8_1)) {
|
||||
// Only initialize the ping passthrough if the protocol version is above beta 1.7.3, as that's when the status protocol was added
|
||||
this.pingPassthrough = GeyserLegacyPingPassthrough.init(this.geyser);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGeyserDisable() {
|
||||
this.geyser.disable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGeyserShutdown() {
|
||||
this.geyser.shutdown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public GeyserConfiguration getGeyserConfig() {
|
||||
return this.config;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GeyserLogger getGeyserLogger() {
|
||||
return this.logger;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GeyserCommandManager getGeyserCommandManager() {
|
||||
return this.commandManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IGeyserPingPassthrough getGeyserPingPassthrough() {
|
||||
return this.pingPassthrough;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getConfigFolder() {
|
||||
return ROOT_FOLDER.toPath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BootstrapDumpInfo getDumpInfo() {
|
||||
return new GeyserViaProxyDumpInfo();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getServerBindAddress() {
|
||||
if (ViaProxy.getConfig().getBindAddress() instanceof InetSocketAddress socketAddress) {
|
||||
return socketAddress.getHostString();
|
||||
} else {
|
||||
throw new IllegalStateException("Unsupported bind address type: " + ViaProxy.getConfig().getBindAddress().getClass().getName());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getServerPort() {
|
||||
if (ViaProxy.getConfig().getBindAddress() instanceof InetSocketAddress socketAddress) {
|
||||
return socketAddress.getPort();
|
||||
} else {
|
||||
throw new IllegalStateException("Unsupported bind address type: " + ViaProxy.getConfig().getBindAddress().getClass().getName());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean testFloodgatePluginPresent() {
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean loadConfig() {
|
||||
try {
|
||||
final File configFile = FileUtils.fileOrCopiedFromResource(new File(ROOT_FOLDER, "config.yml"), "config.yml", s -> s.replaceAll("generateduuid", UUID.randomUUID().toString()), this);
|
||||
this.config = FileUtils.loadConfig(configFile, GeyserViaProxyConfiguration.class);
|
||||
} catch (IOException e) {
|
||||
this.logger.severe(GeyserLocale.getLocaleStringLog("geyser.config.failed"), e);
|
||||
return false;
|
||||
}
|
||||
this.config.getRemote().setAuthType(Files.isRegularFile(this.config.getFloodgateKeyPath()) ? AuthType.FLOODGATE : AuthType.OFFLINE);
|
||||
this.logger.setDebug(this.config.isDebugMode());
|
||||
GeyserConfiguration.checkGeyserConfiguration(this.config, this.logger);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright (c) 2024 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.geyser.platform.viaproxy.listener;
|
||||
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.net.HostAndPort;
|
||||
import org.geysermc.event.PostOrder;
|
||||
import org.geysermc.event.subscribe.Subscribe;
|
||||
import org.geysermc.geyser.api.event.bedrock.SessionLoginEvent;
|
||||
import org.geysermc.geyser.api.event.java.ServerTransferEvent;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class GeyserServerTransferListener {
|
||||
|
||||
private final Cache<String, Map<String, byte[]>> cookieStorages = CacheBuilder.newBuilder().expireAfterWrite(1, TimeUnit.MINUTES).build();
|
||||
|
||||
@Subscribe(postOrder = PostOrder.FIRST)
|
||||
private void onServerTransfer(final ServerTransferEvent event) {
|
||||
this.cookieStorages.put(event.connection().xuid(), event.cookies());
|
||||
final GeyserSession geyserSession = (GeyserSession) event.connection();
|
||||
final HostAndPort hostAndPort = HostAndPort.fromString(geyserSession.getClientData().getServerAddress()).withDefaultPort(19132);
|
||||
event.bedrockHost(hostAndPort.getHost());
|
||||
event.bedrockPort(hostAndPort.getPort());
|
||||
}
|
||||
|
||||
@Subscribe(postOrder = PostOrder.FIRST)
|
||||
private void onSessionLogin(final SessionLoginEvent event) {
|
||||
final Map<String, byte[]> cookies = this.cookieStorages.asMap().remove(event.connection().xuid());
|
||||
if (cookies != null) {
|
||||
event.cookies(cookies);
|
||||
event.transferring(true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
5
bootstrap/viaproxy/src/main/resources/viaproxy.yml
Normal file
5
bootstrap/viaproxy/src/main/resources/viaproxy.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
name: "${name}-ViaProxy"
|
||||
version: "${version}"
|
||||
author: "${author}"
|
||||
main: "org.geysermc.geyser.platform.viaproxy.GeyserViaProxyPlugin"
|
||||
min-version: "3.2.1"
|
|
@ -4,14 +4,20 @@ plugins {
|
|||
|
||||
repositories {
|
||||
gradlePluginPortal()
|
||||
maven("https://repo.opencollab.dev/maven-snapshots")
|
||||
|
||||
maven("https://repo.opencollab.dev/maven-snapshots/")
|
||||
maven("https://maven.fabricmc.net/")
|
||||
maven("https://maven.neoforged.net/releases")
|
||||
maven("https://maven.architectury.dev/")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("net.kyori", "indra-common", "3.1.1")
|
||||
implementation("com.github.johnrengelman", "shadow", "7.1.3-SNAPSHOT")
|
||||
|
||||
// Within the gradle plugin classpath, there is a version conflict between loom and some other
|
||||
// plugin for databind. This fixes it: minimum 2.13.2 is required by loom.
|
||||
implementation("com.fasterxml.jackson.core:jackson-databind:2.14.0")
|
||||
// this is OK as long as the same version catalog is used in the main build and build-logic
|
||||
// see https://github.com/gradle/gradle/issues/15383#issuecomment-779893192
|
||||
implementation(files(libs.javaClass.superclass.protectionDomain.codeSource.location))
|
||||
implementation(libs.indra)
|
||||
implementation(libs.shadow)
|
||||
implementation(libs.architectury.plugin)
|
||||
implementation(libs.architectury.loom)
|
||||
implementation(libs.minotaur)
|
||||
}
|
||||
|
|
11
build-logic/settings.gradle.kts
Normal file
11
build-logic/settings.gradle.kts
Normal file
|
@ -0,0 +1,11 @@
|
|||
@file:Suppress("UnstableApiUsage")
|
||||
|
||||
dependencyResolutionManagement {
|
||||
versionCatalogs {
|
||||
create("libs") {
|
||||
from(files("../gradle/libs.versions.toml"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rootProject.name = "build-logic"
|
6
build-logic/src/main/kotlin/LibsAccessor.kt
Normal file
6
build-logic/src/main/kotlin/LibsAccessor.kt
Normal file
|
@ -0,0 +1,6 @@
|
|||
import org.gradle.accessors.dm.LibrariesForLibs
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.kotlin.dsl.getByType
|
||||
|
||||
val Project.libs: LibrariesForLibs
|
||||
get() = rootProject.extensions.getByType()
|
|
@ -24,11 +24,17 @@
|
|||
*/
|
||||
|
||||
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.artifacts.MinimalExternalModuleDependency
|
||||
import org.gradle.api.artifacts.ProjectDependency
|
||||
import org.gradle.api.provider.Provider
|
||||
import org.gradle.api.tasks.Input
|
||||
import org.gradle.api.tasks.options.Option
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import org.gradle.kotlin.dsl.named
|
||||
import java.io.File
|
||||
import java.net.URL
|
||||
|
||||
fun Project.relocate(pattern: String) {
|
||||
tasks.named<ShadowJar>("shadowJar") {
|
||||
|
@ -52,22 +58,63 @@ fun Project.platformRelocate(pattern: String, exclusion: String = "") {
|
|||
|
||||
val providedDependencies = mutableMapOf<String, MutableSet<String>>()
|
||||
|
||||
fun Project.provided(pattern: String, name: String, version: String, excludedOn: Int = 0b110) {
|
||||
fun getProvidedDependenciesForProject(projectName: String): MutableSet<String> {
|
||||
return providedDependencies.getOrDefault(projectName, emptySet()).toMutableSet()
|
||||
}
|
||||
|
||||
fun Project.provided(pattern: String, name: String, excludedOn: Int = 0b110) {
|
||||
providedDependencies.getOrPut(project.name) { mutableSetOf() }
|
||||
.add("${calcExclusion(pattern, 0b100, excludedOn)}:" +
|
||||
"${calcExclusion(name, 0b10, excludedOn)}:" +
|
||||
calcExclusion(version, 0b1, excludedOn))
|
||||
dependencies.add("compileOnlyApi", "$pattern:$name:$version")
|
||||
.add("${calcExclusion(pattern, 0b100, excludedOn)}:${calcExclusion(name, 0b10, excludedOn)}")
|
||||
}
|
||||
|
||||
fun Project.provided(dependency: ProjectDependency) =
|
||||
provided(dependency.group!!, dependency.name, dependency.version!!)
|
||||
provided(dependency.group!!, dependency.name)
|
||||
|
||||
fun Project.provided(dependency: MinimalExternalModuleDependency) =
|
||||
provided(dependency.module.group, dependency.module.name, dependency.versionConstraint.requiredVersion)
|
||||
provided(dependency.module.group, dependency.module.name)
|
||||
|
||||
fun Project.provided(provider: Provider<MinimalExternalModuleDependency>) =
|
||||
provided(provider.get())
|
||||
|
||||
open class DownloadFilesTask : DefaultTask() {
|
||||
@Input
|
||||
var urls: List<String> = listOf()
|
||||
|
||||
@Input
|
||||
var destinationDir: String = ""
|
||||
|
||||
@Option(option="suffix", description="suffix")
|
||||
@Input
|
||||
var suffix: String = ""
|
||||
|
||||
@Input
|
||||
var suffixedFiles: List<String> = listOf()
|
||||
|
||||
@TaskAction
|
||||
fun downloadAndAddSuffix() {
|
||||
urls.forEach { fileUrl ->
|
||||
val fileName = fileUrl.substringAfterLast("/")
|
||||
val baseName = fileName.substringBeforeLast(".")
|
||||
val extension = fileName.substringAfterLast(".", "")
|
||||
val shouldSuffix = fileName in suffixedFiles
|
||||
val suffixedFileName = if (shouldSuffix && extension.isNotEmpty()) "$baseName.$suffix.$extension" else fileName
|
||||
val outputFile = File(destinationDir, suffixedFileName)
|
||||
|
||||
if (!outputFile.parentFile.exists()) {
|
||||
outputFile.parentFile.mkdirs()
|
||||
}
|
||||
|
||||
URL(fileUrl).openStream().use { input ->
|
||||
outputFile.outputStream().use { output ->
|
||||
input.copyTo(output)
|
||||
}
|
||||
}
|
||||
|
||||
println("Downloaded: $suffixedFileName")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun calcExclusion(section: String, bit: Int, excludedOn: Int): String =
|
||||
if (excludedOn and bit > 0) section else ""
|
||||
if (excludedOn and bit > 0) section else ""
|
||||
|
||||
|
|
|
@ -22,8 +22,8 @@ indra {
|
|||
|
||||
tasks {
|
||||
processResources {
|
||||
// Spigot, BungeeCord, Velocity, Fabric
|
||||
filesMatching(listOf("plugin.yml", "bungee.yml", "velocity-plugin.json", "fabric.mod.json")) {
|
||||
// Spigot, BungeeCord, Velocity, Fabric, ViaProxy, NeoForge
|
||||
filesMatching(listOf("plugin.yml", "bungee.yml", "velocity-plugin.json", "fabric.mod.json", "viaproxy.yml", "META-INF/neoforge.mods.toml")) {
|
||||
expand(
|
||||
"id" to "geyser",
|
||||
"name" to "Geyser",
|
||||
|
|
123
build-logic/src/main/kotlin/geyser.modded-conventions.gradle.kts
Normal file
123
build-logic/src/main/kotlin/geyser.modded-conventions.gradle.kts
Normal file
|
@ -0,0 +1,123 @@
|
|||
@file:Suppress("UnstableApiUsage")
|
||||
|
||||
import net.fabricmc.loom.task.RemapJarTask
|
||||
import org.gradle.kotlin.dsl.dependencies
|
||||
import org.gradle.kotlin.dsl.maven
|
||||
|
||||
plugins {
|
||||
id("geyser.publish-conventions")
|
||||
id("architectury-plugin")
|
||||
id("dev.architectury.loom")
|
||||
}
|
||||
|
||||
// These are provided by Minecraft/modded platforms already, no need to include them
|
||||
provided("com.google.code.gson", "gson")
|
||||
provided("com.google.guava", ".*")
|
||||
provided("org.slf4j", "slf4j-api")
|
||||
provided("com.nukkitx.fastutil", ".*")
|
||||
provided("org.cloudburstmc.fastutil.maps", ".*")
|
||||
provided("org.cloudburstmc.fastutil.sets", ".*")
|
||||
provided("org.cloudburstmc.fastutil.commons", ".*")
|
||||
provided("org.cloudburstmc.fastutil", ".*")
|
||||
provided("org.checkerframework", "checker-qual")
|
||||
provided("io.netty", "netty-transport-classes-epoll")
|
||||
provided("io.netty", "netty-transport-native-epoll")
|
||||
provided("io.netty", "netty-transport-native-unix-common")
|
||||
provided("io.netty", "netty-transport-classes-kqueue")
|
||||
provided("io.netty", "netty-transport-native-kqueue")
|
||||
provided("io.netty.incubator", "netty-incubator-transport-native-io_uring")
|
||||
provided("io.netty.incubator", "netty-incubator-transport-classes-io_uring")
|
||||
provided("io.netty", "netty-handler")
|
||||
provided("io.netty", "netty-common")
|
||||
provided("io.netty", "netty-buffer")
|
||||
provided("io.netty", "netty-resolver")
|
||||
provided("io.netty", "netty-transport")
|
||||
provided("io.netty", "netty-codec")
|
||||
provided("io.netty", "netty-resolver-dns")
|
||||
provided("io.netty", "netty-resolver-dns-native-macos")
|
||||
provided("org.ow2.asm", "asm")
|
||||
|
||||
architectury {
|
||||
minecraft = libs.minecraft.get().version as String
|
||||
}
|
||||
|
||||
loom {
|
||||
silentMojangMappingsLicense()
|
||||
}
|
||||
|
||||
indra {
|
||||
javaVersions {
|
||||
target(21)
|
||||
}
|
||||
}
|
||||
|
||||
configurations {
|
||||
create("includeTransitive").isTransitive = true
|
||||
}
|
||||
|
||||
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 mod jar
|
||||
archiveVersion.set(project.version.toString())
|
||||
archiveClassifier.set("shaded")
|
||||
}
|
||||
|
||||
remapJar {
|
||||
dependsOn(shadowJar)
|
||||
inputFile.set(shadowJar.get().archiveFile)
|
||||
archiveClassifier.set("")
|
||||
archiveVersion.set("")
|
||||
}
|
||||
|
||||
register("remapModrinthJar", RemapJarTask::class) {
|
||||
dependsOn(shadowJar)
|
||||
inputFile.set(shadowJar.get().archiveFile)
|
||||
archiveVersion.set(project.version.toString() + "+build." + System.getenv("BUILD_NUMBER"))
|
||||
archiveClassifier.set("")
|
||||
}
|
||||
}
|
||||
|
||||
afterEvaluate {
|
||||
val providedDependencies = getProvidedDependenciesForProject(project.name)
|
||||
|
||||
// These are shaded, no need to JiJ them
|
||||
configurations["shadow"].dependencies.forEach {shadowed ->
|
||||
//println("Not including shadowed dependency: ${shadowed.group}:${shadowed.name}")
|
||||
providedDependencies.add("${shadowed.group}:${shadowed.name}")
|
||||
}
|
||||
|
||||
// Now: Include all transitive dependencies that aren't excluded
|
||||
configurations["includeTransitive"].resolvedConfiguration.resolvedArtifacts.forEach { dep ->
|
||||
if (!providedDependencies.contains("${dep.moduleVersion.id.group}:${dep.moduleVersion.id.name}")
|
||||
and !providedDependencies.contains("${dep.moduleVersion.id.group}:.*")) {
|
||||
//println("Including dependency via JiJ: ${dep.id}")
|
||||
dependencies.add("include", dep.moduleVersion.id.toString())
|
||||
} else {
|
||||
//println("Not including ${dep.id} for ${project.name}!")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
minecraft(libs.minecraft)
|
||||
mappings(loom.officialMojangMappings())
|
||||
}
|
||||
|
||||
repositories {
|
||||
// mavenLocal()
|
||||
maven("https://repo.opencollab.dev/main")
|
||||
maven("https://jitpack.io")
|
||||
maven("https://oss.sonatype.org/content/repositories/snapshots/")
|
||||
maven("https://s01.oss.sonatype.org/content/repositories/snapshots/")
|
||||
maven("https://maven.neoforged.net/releases")
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
plugins {
|
||||
id("com.modrinth.minotaur")
|
||||
}
|
||||
|
||||
// Ensure that the readme is synched
|
||||
tasks.modrinth.get().dependsOn(tasks.modrinthSyncBody)
|
||||
|
||||
modrinth {
|
||||
token.set(System.getenv("MODRINTH_TOKEN") ?: "") // Even though this is the default value, apparently this prevents GitHub Actions caching the token?
|
||||
projectId.set("geyser")
|
||||
versionNumber.set(project.version as String + "-" + System.getenv("BUILD_NUMBER"))
|
||||
versionType.set("beta")
|
||||
changelog.set("A changelog can be found at https://github.com/GeyserMC/Geyser/commits")
|
||||
gameVersions.add(libs.minecraft.get().version as String)
|
||||
failSilently.set(true)
|
||||
|
||||
syncBodyFrom.set(rootProject.file("README.md").readText())
|
||||
}
|
|
@ -7,3 +7,9 @@ indra {
|
|||
publishSnapshotsTo("geysermc", "https://repo.opencollab.dev/maven-snapshots")
|
||||
publishReleasesTo("geysermc", "https://repo.opencollab.dev/maven-releases")
|
||||
}
|
||||
|
||||
publishing {
|
||||
// skip shadow jar from publishing. Workaround for https://github.com/johnrengelman/shadow/issues/651
|
||||
val javaComponent = project.components["java"] as AdhocComponentWithVariants
|
||||
javaComponent.withVariantsFromConfiguration(configurations["shadowRuntimeElements"]) { skip() }
|
||||
}
|
|
@ -7,7 +7,6 @@ plugins {
|
|||
|
||||
tasks {
|
||||
named<Jar>("jar") {
|
||||
archiveClassifier.set("unshaded")
|
||||
from(project.rootProject.file("LICENSE"))
|
||||
}
|
||||
val shadowJar = named<ShadowJar>("shadowJar") {
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
plugins {
|
||||
`java-library`
|
||||
// Ensure AP works in eclipse (no effect on other IDEs)
|
||||
`eclipse`
|
||||
eclipse
|
||||
id("geyser.build-logic")
|
||||
id("io.freefair.lombok") version "6.3.0" apply false
|
||||
alias(libs.plugins.lombok) apply false
|
||||
}
|
||||
|
||||
allprojects {
|
||||
|
@ -12,17 +12,25 @@ allprojects {
|
|||
description = properties["description"] as String
|
||||
}
|
||||
|
||||
java {
|
||||
toolchain {
|
||||
languageVersion.set(JavaLanguageVersion.of(17))
|
||||
}
|
||||
}
|
||||
|
||||
val platforms = setOf(
|
||||
projects.fabric,
|
||||
val basePlatforms = setOf(
|
||||
projects.bungeecord,
|
||||
projects.spigot,
|
||||
projects.standalone,
|
||||
projects.velocity,
|
||||
projects.viaproxy
|
||||
).map { it.dependencyProject }
|
||||
|
||||
val moddedPlatforms = setOf(
|
||||
projects.fabric,
|
||||
projects.neoforge,
|
||||
projects.mod
|
||||
).map { it.dependencyProject }
|
||||
|
||||
val modrinthPlatforms = setOf(
|
||||
projects.bungeecord,
|
||||
projects.fabric,
|
||||
projects.neoforge,
|
||||
projects.spigot,
|
||||
projects.velocity
|
||||
).map { it.dependencyProject }
|
||||
|
||||
|
@ -34,7 +42,14 @@ subprojects {
|
|||
}
|
||||
|
||||
when (this) {
|
||||
in platforms -> plugins.apply("geyser.platform-conventions")
|
||||
in basePlatforms -> plugins.apply("geyser.platform-conventions")
|
||||
in moddedPlatforms -> plugins.apply("geyser.modded-conventions")
|
||||
else -> plugins.apply("geyser.base-conventions")
|
||||
}
|
||||
}
|
||||
|
||||
// Not combined with platform-conventions as that also contains
|
||||
// platforms which we cant publish to modrinth
|
||||
if (modrinthPlatforms.contains(this)) {
|
||||
plugins.apply("geyser.modrinth-uploading-conventions")
|
||||
}
|
||||
}
|
|
@ -1,12 +1,15 @@
|
|||
import net.kyori.blossom.BlossomExtension
|
||||
|
||||
plugins {
|
||||
id("net.kyori.blossom")
|
||||
id("net.kyori.indra.git")
|
||||
alias(libs.plugins.blossom)
|
||||
id("geyser.publish-conventions")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
constraints {
|
||||
implementation(libs.raknet) // Ensure protocol does not override the RakNet version
|
||||
}
|
||||
|
||||
api(projects.common)
|
||||
api(projects.api)
|
||||
|
||||
|
@ -21,7 +24,6 @@ dependencies {
|
|||
implementation(libs.websocket)
|
||||
|
||||
api(libs.bundles.protocol)
|
||||
implementation(libs.blockstateupdater)
|
||||
|
||||
api(libs.mcauthlib)
|
||||
api(libs.mcprotocollib) {
|
||||
|
@ -44,6 +46,8 @@ dependencies {
|
|||
implementation(libs.netty.transport.native.epoll) { artifact { classifier = "linux-x86_64" } }
|
||||
implementation(libs.netty.transport.native.epoll) { artifact { classifier = "linux-aarch_64" } }
|
||||
implementation(libs.netty.transport.native.kqueue) { artifact { classifier = "osx-x86_64" } }
|
||||
implementation(libs.netty.transport.native.io.uring) { artifact { classifier = "linux-x86_64" } }
|
||||
implementation(libs.netty.transport.native.io.uring) { artifact { classifier = "linux-aarch_64" } }
|
||||
|
||||
// Adventure text serialization
|
||||
api(libs.bundles.adventure)
|
||||
|
@ -63,11 +67,6 @@ dependencies {
|
|||
api(libs.events)
|
||||
}
|
||||
|
||||
configurations.api {
|
||||
// This is still experimental - additionally, it could only really benefit standalone
|
||||
exclude(group = "io.netty.incubator", module = "netty-incubator-transport-native-io_uring")
|
||||
}
|
||||
|
||||
tasks.processResources {
|
||||
// This is solely for backwards compatibility for other programs that used this file before the switch to gradle.
|
||||
// It used to be generated by the maven Git-Commit-Id-Plugin
|
||||
|
@ -98,7 +97,7 @@ configure<BlossomExtension> {
|
|||
}
|
||||
|
||||
fun Project.buildNumber(): Int =
|
||||
(System.getenv("GITHUB_RUN_NUMBER") ?: jenkinsBuildNumber())?.let { Integer.parseInt(it) } ?: -1
|
||||
(System.getenv("BUILD_NUMBER"))?.let { Integer.parseInt(it) } ?: -1
|
||||
|
||||
inner class GitInfo {
|
||||
val branch: String
|
||||
|
@ -131,5 +130,18 @@ inner class GitInfo {
|
|||
}
|
||||
}
|
||||
|
||||
// todo remove this when we're not using Jenkins anymore
|
||||
fun jenkinsBuildNumber(): String? = System.getenv("BUILD_NUMBER")
|
||||
// Manual task to download the bedrock data files from the CloudburstMC/Data repository
|
||||
// Invoke with ./gradlew :core:downloadBedrockData --suffix=1_20_70
|
||||
// Set suffix to the current Bedrock version
|
||||
tasks.register<DownloadFilesTask>("downloadBedrockData") {
|
||||
urls = listOf(
|
||||
"https://raw.githubusercontent.com/CloudburstMC/Data/master/entity_identifiers.dat",
|
||||
"https://raw.githubusercontent.com/CloudburstMC/Data/master/biome_definitions.dat",
|
||||
"https://raw.githubusercontent.com/CloudburstMC/Data/master/block_palette.nbt",
|
||||
"https://raw.githubusercontent.com/CloudburstMC/Data/master/creative_items.json",
|
||||
"https://raw.githubusercontent.com/CloudburstMC/Data/master/runtime_item_states.json"
|
||||
)
|
||||
suffixedFiles = listOf("block_palette.nbt", "creative_items.json", "runtime_item_states.json")
|
||||
|
||||
destinationDir = "$projectDir/src/main/resources/bedrock"
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue