3
0
Mirror von https://github.com/GeyserMC/Geyser.git synchronisiert 2024-11-20 15:00:11 +01: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
Dieser Commit ist enthalten in:
onebeastchris 2024-06-19 20:09:10 +02:00
Commit 507a79eb88
666 geänderte Dateien mit 29118 neuen und 30397 gelöschten Zeilen

47
.github/workflows/build-remote.yml vendored Normale Datei
Datei anzeigen

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

Datei anzeigen

@ -3,9 +3,13 @@ name: Build
on: on:
workflow_dispatch: workflow_dispatch:
push: push:
branches-ignore:
- 'gh-readonly-queue/**'
paths-ignore: paths-ignore:
- '.github/ISSUE_TEMPLATE/*.yml' - '.github/ISSUE_TEMPLATE/*.yml'
- '.github/actions/pullrequest.yml' - '.github/workflows/build-remote.yml'
- '.github/workflows/preview.yml'
- '.github/workflows/pull-request.yml'
- '.idea/copyright/*.xml' - '.idea/copyright/*.xml'
- '.gitignore' - '.gitignore'
- 'CONTRIBUTING.md' - 'CONTRIBUTING.md'
@ -18,112 +22,99 @@ jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout repository and submodules - name: Get Release Info
# See https://github.com/actions/checkout/commits id: release-info
uses: actions/checkout@72f2cec99f417b1a1c5e2e88945068983b7965f9 uses: GeyserMC/actions/previous-release@master
with: with:
submodules: recursive data: ${{ vars.RELEASEACTION_PREVRELEASE }}
- name: Validate Gradle Wrapper - name: Setup Gradle
# See https://github.com/gradle/wrapper-validation-action/commits uses: GeyserMC/actions/setup-gradle-composite@master
uses: gradle/wrapper-validation-action@56b90f209b02bf6d1deae490e9ef18b21a389cd4 with:
setup-java_java-version: 21
# See https://github.com/actions/setup-java/commits - name: Build Geyser
- uses: actions/setup-java@4075bfc1b51bf22876335ae1cd589602d60d8758 run: ./gradlew build
with: env:
java-version: 17 BUILD_NUMBER: ${{ steps.release-info.outputs.curentRelease }}
distribution: temurin
- name: Build - name: Archive Artifacts
# See https://github.com/gradle/gradle-build-action/commits uses: GeyserMC/actions/upload-multi-artifact@master
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
if: success() if: success()
with: with:
name: Geyser Fabric artifacts: |
path: bootstrap/fabric/build/libs/Geyser-Fabric.jar bootstrap/mod/fabric/build/libs/Geyser-Fabric.jar
if-no-files-found: error bootstrap/mod/neoforge/build/libs/Geyser-NeoForge.jar
- name: Archive artifacts (Geyser Standalone) bootstrap/standalone/build/libs/Geyser-Standalone.jar
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 bootstrap/spigot/build/libs/Geyser-Spigot.jar
if: success() bootstrap/bungeecord/build/libs/Geyser-BungeeCord.jar
with: bootstrap/velocity/build/libs/Geyser-Velocity.jar
name: Geyser Standalone bootstrap/viaproxy/build/libs/Geyser-ViaProxy.jar
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
- name: Publish to Maven Repository - name: Publish to Maven Repository
if: ${{ success() && github.repository == 'GeyserMC/Geyser' && github.ref_name == 'master' }} if: ${{ success() && github.repository == 'GeyserMC/Geyser' && github.ref_name == 'master' }}
uses: gradle/gradle-build-action@3bfe3a46584a206fb8361cdedd0647b0c4204232 run: ./gradlew publish
env: env:
BUILD_NUMBER: ${{ steps.release-info.outputs.curentRelease }}
ORG_GRADLE_PROJECT_geysermcUsername: ${{ vars.DEPLOY_USER }} ORG_GRADLE_PROJECT_geysermcUsername: ${{ vars.DEPLOY_USER }}
ORG_GRADLE_PROJECT_geysermcPassword: ${{ secrets.DEPLOY_PASS }} ORG_GRADLE_PROJECT_geysermcPassword: ${{ secrets.DEPLOY_PASS }}
- 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: 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 - name: Publish to Downloads API
if: ${{ success() && github.repository == 'GeyserMC/Geyser' && github.ref_name == 'master' }} if: ${{ success() && github.repository == 'GeyserMC/Geyser' && github.ref_name == 'master' }}
shell: bash uses: GeyserMC/actions/upload-release@master
env: with:
DOWNLOADS_USERNAME: ${{ vars.DOWNLOADS_USERNAME }} username: ${{ vars.DOWNLOADS_USERNAME }}
DOWNLOADS_PRIVATE_KEY: ${{ secrets.DOWNLOADS_PRIVATE_KEY }} privateKey: ${{ secrets.DOWNLOADS_PRIVATE_KEY }}
DOWNLOADS_SERVER_IP: ${{ secrets.DOWNLOADS_SERVER_IP }} host: ${{ secrets.DOWNLOADS_SERVER_IP }}
run: | files: |
# Save the private key to a file bootstrap/bungeecord/build/libs/Geyser-BungeeCord.jar
echo "$DOWNLOADS_PRIVATE_KEY" > id_ecdsa bootstrap/mod/fabric/build/libs/Geyser-Fabric.jar
chmod 600 id_ecdsa bootstrap/mod/neoforge/build/libs/Geyser-NeoForge.jar
# Set the project bootstrap/spigot/build/libs/Geyser-Spigot.jar
project=geyser bootstrap/standalone/build/libs/Geyser-Standalone.jar
# Get the version from gradle.properties bootstrap/velocity/build/libs/Geyser-Velocity.jar
version=$(cat gradle.properties | grep -o "version=[0-9\\.]*" | cut -d"=" -f2) bootstrap/viaproxy/build/libs/Geyser-ViaProxy.jar
# Create the build folder changelog: ${{ steps.metadata.outputs.body }}
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/
- name: Publish to Modrinth - name: Publish to Modrinth
uses: gradle/gradle-build-action@3bfe3a46584a206fb8361cdedd0647b0c4204232
if: ${{ success() && github.repository == 'GeyserMC/Geyser' && github.ref_name == 'master' }} if: ${{ success() && github.repository == 'GeyserMC/Geyser' && github.ref_name == 'master' }}
env: env:
BUILD_NUMBER: ${{ steps.release-info.outputs.curentRelease }}
MODRINTH_TOKEN: ${{ secrets.MODRINTH_TOKEN }} MODRINTH_TOKEN: ${{ secrets.MODRINTH_TOKEN }}
with: run: ./gradlew modrinth
arguments: fabric:modrinth
gradle-home-cache-cleanup: true
- name: Notify Discord - name: Notify Discord
if: ${{ (success() || failure()) && github.repository == 'GeyserMC/Geyser' }} if: ${{ (success() || failure()) && github.repository == 'GeyserMC/Geyser' }}
# See https://github.com/Tim203/actions-git-discord-webhook/commits uses: GeyserMC/actions/notify-discord@master
uses: Tim203/actions-git-discord-webhook@70f38ded3aca51635ec978ab4e1a58cd4cd0c2ff
with: with:
webhook_url: ${{ secrets.DISCORD_WEBHOOK }} discordWebhook: ${{ secrets.DISCORD_WEBHOOK }}
status: ${{ job.status }} status: ${{ job.status }}
body: ${{ steps.metadata.outputs.body }}
includeDownloads: ${{ github.ref_name == 'master' }}

33
.github/workflows/dispatch-preview.yml vendored Normale Datei
Datei anzeigen

@ -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 Normale Datei
Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

@ -1,6 +1,7 @@
<component name="CopyrightManager"> <component name="CopyrightManager">
<copyright> <copyright>
<option name="notice" value="Copyright (c) 2019-&amp;#36;today.year GeyserMC. http://geysermc.org&#10;&#10;Permission is hereby granted, free of charge, to any person obtaining a copy&#10;of this software and associated documentation files (the &quot;Software&quot;), to deal&#10;in the Software without restriction, including without limitation the rights&#10;to use, copy, modify, merge, publish, distribute, sublicense, and/or sell&#10;copies of the Software, and to permit persons to whom the Software is&#10;furnished to do so, subject to the following conditions:&#10;&#10;The above copyright notice and this permission notice shall be included in&#10;all copies or substantial portions of the Software.&#10;&#10;THE SOFTWARE IS PROVIDED &quot;AS IS&quot;, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR&#10;IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,&#10;FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE&#10;AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER&#10;LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,&#10;OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN&#10;THE SOFTWARE.&#10;&#10;@author GeyserMC&#10;@link https://github.com/GeyserMC/Geyser" /> <option name="allowReplaceRegexp" value="Copyright" />
<option name="notice" value="Copyright (c) &amp;#36;originalComment.match(&quot;Copyright \(c\) (\d+)&quot;, 1, &quot;-&quot;)&amp;#36;today.year GeyserMC. http://geysermc.org&#10;&#10;Permission is hereby granted, free of charge, to any person obtaining a copy&#10;of this software and associated documentation files (the &quot;Software&quot;), to deal&#10;in the Software without restriction, including without limitation the rights&#10;to use, copy, modify, merge, publish, distribute, sublicense, and/or sell&#10;copies of the Software, and to permit persons to whom the Software is&#10;furnished to do so, subject to the following conditions:&#10;&#10;The above copyright notice and this permission notice shall be included in&#10;all copies or substantial portions of the Software.&#10;&#10;THE SOFTWARE IS PROVIDED &quot;AS IS&quot;, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR&#10;IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,&#10;FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE&#10;AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER&#10;LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,&#10;OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN&#10;THE SOFTWARE.&#10;&#10;@author GeyserMC&#10;@link https://github.com/GeyserMC/Geyser" />
<option name="myName" value="Geyser" /> <option name="myName" value="Geyser" />
</copyright> </copyright>
</component> </component>

Datei anzeigen

@ -2,7 +2,7 @@
[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) [![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) [![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. 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! 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 ## Setting Up
Take a look [here](https://wiki.geysermc.org/geyser/setup/) for how to set up Geyser. Take a look [here](https://wiki.geysermc.org/geyser/setup/) for how to set up Geyser.
@ -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 ## What's Left to be Added/Fixed
- Near-perfect movement (to the point where anticheat on large servers is unlikely to ban you) - Near-perfect movement (to the point where anticheat on large servers is unlikely to ban you)
- Some Entity Flags - Some Entity Flags
- Structure block UI
## What can't be fixed ## What can't be fixed
There are a few things Geyser is unable to support due to various differences between Minecraft Bedrock and Java. For a list of these limitations, see the [Current Limitations](https://wiki.geysermc.org/geyser/current-limitations/) page. There are a few things Geyser is unable to support due to various differences between Minecraft Bedrock and Java. For a list of these limitations, see the [Current Limitations](https://wiki.geysermc.org/geyser/current-limitations/) page.

Datei anzeigen

@ -145,4 +145,36 @@ public interface CameraData {
* @return whether the camera is currently locked * @return whether the camera is currently locked
*/ */
boolean isCameraLocked(); boolean isCameraLocked();
/**
* Hides a {@link GuiElement} on the client's side.
*
* @param element the {@link GuiElement} to hide
*/
void hideElement(@NonNull GuiElement... element);
/**
* Resets a {@link GuiElement} on the client's side.
* This makes the client decide on its own - e.g. based on client settings -
* whether to show or hide the gui element.
* <p>
* If no elements are specified, this will reset all currently hidden elements
*
* @param element the {@link GuiElement} to reset
*/
void resetElement(@NonNull GuiElement @Nullable... element);
/**
* Determines whether a {@link GuiElement} is currently hidden.
*
* @param element the {@link GuiElement} to check
*/
boolean isHudElementHidden(@NonNull GuiElement element);
/**
* Returns the currently hidden {@link GuiElement}s.
*
* @return an unmodifiable view of all currently hidden {@link GuiElement}s
*/
@NonNull Set<GuiElement> hiddenElements();
} }

Datei anzeigen

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

Datei anzeigen

@ -61,16 +61,16 @@ public interface CustomBlockData {
boolean includedInCreativeInventory(); 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(); @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(); @Nullable String creativeGroup();

Datei anzeigen

@ -129,8 +129,11 @@ public interface CustomBlockComponents {
* Gets the unit cube component * Gets the unit cube component
* Equivalent to "minecraft:unit_cube" * Equivalent to "minecraft:unit_cube"
* *
* @deprecated Use {@link #geometry()} and compare with `minecraft:geometry.full_block` instead.
*
* @return The rotation. * @return The rotation.
*/ */
@Deprecated
boolean unitCube(); boolean unitCube();
/** /**
@ -181,6 +184,10 @@ public interface CustomBlockComponents {
Builder transformation(TransformationComponent transformation); Builder transformation(TransformationComponent transformation);
/**
* @deprecated Use {@link #geometry(GeometryComponent)} with `minecraft:geometry.full_block` instead.
*/
@Deprecated
Builder unitCube(boolean unitCube); Builder unitCube(boolean unitCube);
Builder placeAir(boolean placeAir); Builder placeAir(boolean placeAir);

Datei anzeigen

@ -32,18 +32,27 @@ import org.geysermc.geyser.api.connection.GeyserConnection;
import org.geysermc.geyser.api.event.connection.ConnectionEvent; import org.geysermc.geyser.api.event.connection.ConnectionEvent;
import org.geysermc.geyser.api.network.RemoteServer; 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. * This event is cancellable, and can be used to prevent the player from connecting to the remote server.
*/ */
public final class SessionLoginEvent extends ConnectionEvent implements Cancellable { public final class SessionLoginEvent extends ConnectionEvent implements Cancellable {
private RemoteServer remoteServer; private RemoteServer remoteServer;
private boolean cancelled; private boolean cancelled;
private String disconnectReason; 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); super(connection);
this.remoteServer = remoteServer; 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() { public @NonNull RemoteServer remoteServer() {
return this.remoteServer; return this.remoteServer;
@ -106,4 +115,36 @@ public final class SessionLoginEvent extends ConnectionEvent implements Cancella
public void remoteServer(@NonNull RemoteServer remoteServer) { public void remoteServer(@NonNull RemoteServer remoteServer) {
this.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;
}
} }

Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

@ -29,6 +29,7 @@ import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.Nullable;
import org.geysermc.geyser.api.GeyserApi; import org.geysermc.geyser.api.GeyserApi;
import java.util.OptionalInt;
import java.util.Set; import java.util.Set;
/** /**
@ -77,6 +78,20 @@ public interface CustomItemData {
*/ */
boolean displayHandheld(); 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. * 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 displayHandheld(boolean displayHandheld);
Builder creativeCategory(int creativeCategory);
Builder creativeGroup(@Nullable String creativeGroup);
Builder textureSize(int textureSize); Builder textureSize(int textureSize);
Builder renderOffsets(@Nullable CustomRenderOffsets renderOffsets); Builder renderOffsets(@Nullable CustomRenderOffsets renderOffsets);

Datei anzeigen

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org * Copyright (c) 2019-2024 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@ -30,7 +30,6 @@ import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.Nullable;
import org.geysermc.geyser.api.GeyserApi; import org.geysermc.geyser.api.GeyserApi;
import java.util.OptionalInt;
import java.util.Set; import java.util.Set;
/** /**
@ -65,6 +64,14 @@ public interface NonVanillaCustomItemData extends CustomItemData {
*/ */
int maxDamage(); 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. * Gets the tool type of the item.
* *
@ -107,20 +114,6 @@ public interface NonVanillaCustomItemData extends CustomItemData {
*/ */
@Nullable Set<String> repairMaterials(); @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 * 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. * normally allow the player to equip it. This is not meant for armor.
@ -168,6 +161,13 @@ public interface NonVanillaCustomItemData extends CustomItemData {
return displayHandheld(); return displayHandheld();
} }
/**
* Gets the block the item places.
*
* @return the block the item places
*/
String block();
static NonVanillaCustomItemData.Builder builder() { static NonVanillaCustomItemData.Builder builder() {
return GeyserApi.api().provider(NonVanillaCustomItemData.Builder.class); return GeyserApi.api().provider(NonVanillaCustomItemData.Builder.class);
} }
@ -184,6 +184,8 @@ public interface NonVanillaCustomItemData extends CustomItemData {
Builder maxDamage(int maxDamage); Builder maxDamage(int maxDamage);
Builder attackDamage(int attackDamage);
Builder toolType(@Nullable String toolType); Builder toolType(@Nullable String toolType);
Builder toolTier(@Nullable String toolTier); Builder toolTier(@Nullable String toolTier);
@ -196,10 +198,6 @@ public interface NonVanillaCustomItemData extends CustomItemData {
Builder repairMaterials(@Nullable Set<String> repairMaterials); Builder repairMaterials(@Nullable Set<String> repairMaterials);
Builder creativeCategory(int creativeCategory);
Builder creativeGroup(@Nullable String creativeGroup);
Builder hat(boolean isHat); Builder hat(boolean isHat);
Builder foil(boolean isFoil); Builder foil(boolean isFoil);
@ -210,6 +208,8 @@ public interface NonVanillaCustomItemData extends CustomItemData {
Builder chargeable(boolean isChargeable); Builder chargeable(boolean isChargeable);
Builder block(String block);
/** /**
* @deprecated Use {@link #displayHandheld(boolean)} instead. * @deprecated Use {@link #displayHandheld(boolean)} instead.
*/ */
@ -218,6 +218,12 @@ public interface NonVanillaCustomItemData extends CustomItemData {
return displayHandheld(isTool); return displayHandheld(isTool);
} }
@Override
Builder creativeCategory(int creativeCategory);
@Override
Builder creativeGroup(@Nullable String creativeGroup);
@Override @Override
Builder customItemOptions(@NonNull CustomItemOptions customItemOptions); Builder customItemOptions(@NonNull CustomItemOptions customItemOptions);

Datei anzeigen

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org * Copyright (c) 2024 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@ -23,12 +23,18 @@
* @link https://github.com/GeyserMC/Geyser * @link https://github.com/GeyserMC/Geyser
*/ */
package org.geysermc.geyser.api.skin;
/** /**
* Contains useful collections for use in Geyser. * Represents a cape.
* <p> *
* Of note are the fixed int maps. Designed for use with block states that are positive and sequential, they do not allow keys to be * @param textureUrl The URL of the cape texture
* added that are not greater by one versus the previous key. Because of this, speedy operations of {@link java.util.Map#get(java.lang.Object)} * @param capeId The ID of the cape
* and {@link java.util.Map#containsKey(java.lang.Object)} can be performed by simply checking the bounds of the map * @param capeData The raw cape image data in ARGB format
* size and its "start" integer. * @param failed If the cape failed to load, this is for things like fallback capes
*/ */
package org.geysermc.geyser.util.collection; public record Cape(String textureUrl, String capeId, byte[] capeData, boolean failed) {
public Cape(String textureUrl, String capeId, byte[] capeData) {
this(textureUrl, capeId, capeData, false);
}
}

Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

@ -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" : "") + "\"}}", "");
}
}

Datei anzeigen

@ -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 * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@ -31,11 +31,10 @@ import org.checkerframework.checker.nullness.qual.NonNull;
* Represents the creative menu categories or tabs. * Represents the creative menu categories or tabs.
*/ */
public enum CreativeCategory { public enum CreativeCategory {
COMMANDS("commands", 1), CONSTRUCTION("construction", 1),
CONSTRUCTION("construction", 2), NATURE("nature", 2),
EQUIPMENT("equipment", 3), EQUIPMENT("equipment", 3),
ITEMS("items", 4), ITEMS("items", 4),
NATURE("nature", 5),
NONE("none", 6); NONE("none", 6);
private final String internalName; private final String internalName;

Datei anzeigen

@ -34,10 +34,12 @@ public record PlatformType(String platformName) {
public static final PlatformType ANDROID = new PlatformType("Android"); public static final PlatformType ANDROID = new PlatformType("Android");
public static final PlatformType BUNGEECORD = new PlatformType("BungeeCord"); public static final PlatformType BUNGEECORD = new PlatformType("BungeeCord");
public static final PlatformType FABRIC = new PlatformType("Fabric"); public static final PlatformType FABRIC = new PlatformType("Fabric");
public static final PlatformType NEOFORGE = new PlatformType("NeoForge");
public static final PlatformType SPIGOT = new PlatformType("Spigot"); public static final PlatformType SPIGOT = new PlatformType("Spigot");
@Deprecated @Deprecated
public static final PlatformType SPONGE = new PlatformType("Sponge"); public static final PlatformType SPONGE = new PlatformType("Sponge");
public static final PlatformType STANDALONE = new PlatformType("Standalone"); public static final PlatformType STANDALONE = new PlatformType("Standalone");
public static final PlatformType VELOCITY = new PlatformType("Velocity"); public static final PlatformType VELOCITY = new PlatformType("Velocity");
public static final PlatformType VIAPROXY = new PlatformType("ViaProxy");
} }

Datei anzeigen

@ -1,7 +1,7 @@
dependencies { dependencies {
api(projects.core) api(projects.core)
implementation(libs.adventure.text.serializer.bungeecord) implementation(libs.adventure.text.serializer.bungeecord)
compileOnlyApi(libs.bungeecord.proxy)
} }
platformRelocate("net.md_5.bungee.jni") platformRelocate("net.md_5.bungee.jni")
@ -22,6 +22,7 @@ tasks.withType<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar> {
dependencies { dependencies {
exclude(dependency("com.google.*:.*")) exclude(dependency("com.google.*:.*"))
exclude(dependency("io.netty.incubator:.*"))
exclude(dependency("io.netty:netty-transport-native-epoll:.*")) exclude(dependency("io.netty:netty-transport-native-epoll:.*"))
exclude(dependency("io.netty:netty-transport-native-unix-common:.*")) exclude(dependency("io.netty:netty-transport-native-unix-common:.*"))
exclude(dependency("io.netty:netty-handler:.*")) 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:.*")) exclude(dependency("io.netty:netty-resolver-dns:.*"))
} }
} }
modrinth {
uploadFile.set(tasks.getByPath("shadowJar"))
loaders.add("bungeecord")
}

Datei anzeigen

@ -26,22 +26,19 @@
package org.geysermc.geyser.platform.bungeecord; package org.geysermc.geyser.platform.bungeecord;
import lombok.Getter; import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter; import lombok.Setter;
import org.geysermc.geyser.GeyserLogger; import org.geysermc.geyser.GeyserLogger;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
@RequiredArgsConstructor
public class GeyserBungeeLogger implements GeyserLogger { public class GeyserBungeeLogger implements GeyserLogger {
private final Logger logger; private final Logger logger;
@Getter @Setter @Getter @Setter
private boolean debug; private boolean debug;
public GeyserBungeeLogger(Logger logger, boolean debug) {
this.logger = logger;
this.debug = debug;
}
@Override @Override
public void severe(String message) { public void severe(String message) {
logger.severe(message); logger.severe(message);

Datei anzeigen

@ -58,14 +58,13 @@ import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap { public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap {
private GeyserCommandManager geyserCommandManager; private GeyserCommandManager geyserCommandManager;
private GeyserBungeeConfiguration geyserConfig; private GeyserBungeeConfiguration geyserConfig;
private GeyserBungeeInjector geyserInjector; private GeyserBungeeInjector geyserInjector;
private GeyserBungeeLogger geyserLogger; private final GeyserBungeeLogger geyserLogger = new GeyserBungeeLogger(getLogger());
private IGeyserPingPassthrough geyserBungeePingPassthrough; private IGeyserPingPassthrough geyserBungeePingPassthrough;
private GeyserImpl geyser; private GeyserImpl geyser;
@ -82,21 +81,21 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap {
// Copied from ViaVersion. // Copied from ViaVersion.
// https://github.com/ViaVersion/ViaVersion/blob/b8072aad86695cc8ec6f5e4103e43baf3abf6cc5/bungee/src/main/java/us/myles/ViaVersion/BungeePlugin.java#L43 // https://github.com/ViaVersion/ViaVersion/blob/b8072aad86695cc8ec6f5e4103e43baf3abf6cc5/bungee/src/main/java/us/myles/ViaVersion/BungeePlugin.java#L43
try { try {
ProtocolConstants.class.getField("MINECRAFT_1_20_3"); ProtocolConstants.class.getField("MINECRAFT_1_21");
} catch (NoSuchFieldException e) { } catch (NoSuchFieldException e) {
getLogger().warning(" / \\"); geyserLogger.error(" / \\");
getLogger().warning(" / \\"); geyserLogger.error(" / \\");
getLogger().warning(" / | \\"); geyserLogger.error(" / | \\");
getLogger().warning(" / | \\ " + GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_proxy", getProxy().getName())); geyserLogger.error(" / | \\ " + GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_proxy", getProxy().getName()));
getLogger().warning(" / \\ " + GeyserLocale.getLocaleStringLog("geyser.may_not_work_as_intended_all_caps")); geyserLogger.error(" / \\ " + GeyserLocale.getLocaleStringLog("geyser.may_not_work_as_intended_all_caps"));
getLogger().warning(" / o \\"); geyserLogger.error(" / o \\");
getLogger().warning("/_____________\\"); geyserLogger.error("/_____________\\");
} }
if (!this.loadConfig()) { if (!this.loadConfig()) {
return; return;
} }
this.geyserLogger = new GeyserBungeeLogger(getLogger(), geyserConfig.isDebugMode()); this.geyserLogger.setDebug(geyserConfig.isDebugMode());
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger); GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
this.geyser = GeyserImpl.load(PlatformType.BUNGEECORD, this); this.geyser = GeyserImpl.load(PlatformType.BUNGEECORD, this);
this.geyserInjector = new GeyserBungeeInjector(this); this.geyserInjector = new GeyserBungeeInjector(this);
@ -293,7 +292,7 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap {
"config.yml", (x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()), this); "config.yml", (x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()), this);
this.geyserConfig = FileUtils.loadConfig(configFile, GeyserBungeeConfiguration.class); this.geyserConfig = FileUtils.loadConfig(configFile, GeyserBungeeConfiguration.class);
} catch (IOException ex) { } catch (IOException ex) {
getLogger().log(Level.SEVERE, GeyserLocale.getLocaleStringLog("geyser.config.failed"), ex); geyserLogger.error(GeyserLocale.getLocaleStringLog("geyser.config.failed"), ex);
ex.printStackTrace(); ex.printStackTrace();
return false; return false;
} }

Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

@ -0,0 +1 @@
loom.platform=fabric

Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

@ -9,23 +9,22 @@
], ],
"contact": { "contact": {
"website": "${url}", "website": "${url}",
"repo": "https://github.com/GeyserMC/Geyser-Fabric" "repo": "https://github.com/GeyserMC/Geyser"
}, },
"license": "MIT", "license": "MIT",
"icon": "assets/geyser-fabric/icon.png", "icon": "assets/geyser/icon.png",
"environment": "*", "environment": "*",
"entrypoints": { "entrypoints": {
"main": [ "main": [
"org.geysermc.geyser.platform.fabric.GeyserFabricMod" "org.geysermc.geyser.platform.fabric.GeyserFabricBootstrap"
] ]
}, },
"mixins": [ "mixins": [
"geyser-fabric.mixins.json" "geyser.mixins.json"
], ],
"depends": { "depends": {
"fabricloader": ">=0.15.2", "fabricloader": ">=0.15.11",
"fabric": "*", "fabric": "*",
"minecraft": ">=1.20.4", "minecraft": ">=1.21"
"fabric-permissions-api-v0": "*"
} }
} }

Datei anzeigen

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

Datei anzeigen

@ -0,0 +1 @@
loom.platform=neoforge

Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

@ -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";
}
}

Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

@ -23,11 +23,8 @@
* @link https://github.com/GeyserMC/Geyser * @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 ModConstants {
public class FlowerItem extends BlockItem { public static final String MOD_ID = "geyser_neoforge";
public FlowerItem(String javaIdentifier, Builder builder) {
super(javaIdentifier, builder);
}
} }

Datei anzeigen

@ -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"

Datei anzeigen

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

Datei anzeigen

@ -23,22 +23,17 @@
* @link https://github.com/GeyserMC/Geyser * @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.arguments.StringArgumentType;
import com.mojang.brigadier.builder.LiteralArgumentBuilder; import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import lombok.Getter; import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter; 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.CommandSourceStack;
import net.minecraft.commands.Commands; import net.minecraft.commands.Commands;
import net.minecraft.server.MinecraftServer; 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.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.Nullable;
import org.geysermc.geyser.GeyserBootstrap; import org.geysermc.geyser.GeyserBootstrap;
@ -46,7 +41,6 @@ import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.GeyserLogger; import org.geysermc.geyser.GeyserLogger;
import org.geysermc.geyser.api.command.Command; import org.geysermc.geyser.api.command.Command;
import org.geysermc.geyser.api.extension.Extension; 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.GeyserCommand;
import org.geysermc.geyser.command.GeyserCommandManager; import org.geysermc.geyser.command.GeyserCommandManager;
import org.geysermc.geyser.configuration.GeyserConfiguration; 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.level.WorldManager;
import org.geysermc.geyser.ping.GeyserLegacyPingPassthrough; import org.geysermc.geyser.ping.GeyserLegacyPingPassthrough;
import org.geysermc.geyser.ping.IGeyserPingPassthrough; import org.geysermc.geyser.ping.IGeyserPingPassthrough;
import org.geysermc.geyser.platform.fabric.command.GeyserFabricCommandExecutor; import org.geysermc.geyser.platform.mod.command.GeyserModCommandExecutor;
import org.geysermc.geyser.platform.fabric.world.GeyserFabricWorldManager; 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.text.GeyserLocale;
import org.geysermc.geyser.util.FileUtils; import org.geysermc.geyser.util.FileUtils;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.net.SocketAddress;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.Map; import java.util.Map;
import java.util.Optional;
import java.util.UUID; import java.util.UUID;
public class GeyserFabricMod implements ModInitializer, GeyserBootstrap { @RequiredArgsConstructor
public abstract class GeyserModBootstrap implements GeyserBootstrap {
@Getter @Getter
private static GeyserFabricMod instance; private static GeyserModBootstrap instance;
private final GeyserModPlatform platform;
private GeyserImpl geyser; private GeyserImpl geyser;
private ModContainer mod;
private Path dataFolder; private Path dataFolder;
@Setter @Setter
private MinecraftServer server; private MinecraftServer server;
private GeyserCommandManager geyserCommandManager; private GeyserCommandManager geyserCommandManager;
private GeyserFabricConfiguration geyserConfig; private GeyserModConfiguration geyserConfig;
private GeyserFabricLogger geyserLogger; private GeyserModInjector geyserInjector;
private final GeyserModLogger geyserLogger = new GeyserModLogger();
private IGeyserPingPassthrough geyserPingPassthrough; private IGeyserPingPassthrough geyserPingPassthrough;
private WorldManager geyserWorldManager; private WorldManager geyserWorldManager;
@Override
public void onInitialize() {
instance = this;
mod = FabricLoader.getInstance().getModContainer("geyser-fabric").orElseThrow();
onGeyserInitialize();
}
@Override @Override
public void onGeyserInitialize() { public void onGeyserInitialize() {
if (FabricLoader.getInstance().getEnvironmentType() == EnvType.SERVER) { instance = this;
// Set as an event, so we can get the proper IP and port if needed dataFolder = this.platform.dataFolder(this.platform.configPath());
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");
GeyserLocale.init(this); GeyserLocale.init(this);
if (!loadConfig()) { if (!loadConfig()) {
return; return;
} }
this.geyserLogger = new GeyserFabricLogger(geyserConfig.isDebugMode()); this.geyserLogger.setDebug(geyserConfig.isDebugMode());
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger); 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() { public void onGeyserEnable() {
if (GeyserImpl.getInstance().isReloading()) { if (GeyserImpl.getInstance().isReloading()) {
if (!loadConfig()) { if (!loadConfig()) {
@ -123,35 +107,39 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap {
} }
this.geyserLogger.setDebug(geyserConfig.isDebugMode()); this.geyserLogger.setDebug(geyserConfig.isDebugMode());
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger); GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
} else {
this.geyserCommandManager = new GeyserCommandManager(geyser);
this.geyserCommandManager.init();
} }
GeyserImpl.start();
if (geyserConfig.isLegacyPingPassthrough()) { if (geyserConfig.isLegacyPingPassthrough()) {
this.geyserPingPassthrough = GeyserLegacyPingPassthrough.init(geyser); this.geyserPingPassthrough = GeyserLegacyPingPassthrough.init(geyser);
} else { } else {
this.geyserPingPassthrough = new ModPingPassthrough(server, geyserLogger); this.geyserPingPassthrough = new ModPingPassthrough(server, geyserLogger);
} }
GeyserImpl.start(); // No need to re-register commands, or try to re-inject
// No need to re-register commands, or re-recreate the world manager when reloading
if (GeyserImpl.getInstance().isReloading()) { if (GeyserImpl.getInstance().isReloading()) {
return; 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 // Start command building
// Set just "geyser" as the help command // Set just "geyser" as the help command
GeyserFabricCommandExecutor helpExecutor = new GeyserFabricCommandExecutor(geyser, GeyserModCommandExecutor helpExecutor = new GeyserModCommandExecutor(geyser,
(GeyserCommand) geyser.commandManager().getCommands().get("help")); (GeyserCommand) geyser.commandManager().getCommands().get("help"));
LiteralArgumentBuilder<CommandSourceStack> builder = Commands.literal("geyser").executes(helpExecutor); LiteralArgumentBuilder<CommandSourceStack> builder = Commands.literal("geyser").executes(helpExecutor);
// Register all subcommands as valid // Register all subcommands as valid
for (Map.Entry<String, Command> command : geyser.commandManager().getCommands().entrySet()) { 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()) builder.then(Commands.literal(command.getKey())
.executes(executor) .executes(executor)
// Could also test for Bedrock but depending on when this is called it may backfire // 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>" // Register help command for just "/<extensionId>"
GeyserFabricCommandExecutor extensionHelpExecutor = new GeyserFabricCommandExecutor(geyser, GeyserModCommandExecutor extensionHelpExecutor = new GeyserModCommandExecutor(geyser,
(GeyserCommand) extensionCommands.get("help")); (GeyserCommand) extensionCommands.get("help"));
LiteralArgumentBuilder<CommandSourceStack> extCmdBuilder = Commands.literal(extensionMapEntry.getKey().description().id()).executes(extensionHelpExecutor); LiteralArgumentBuilder<CommandSourceStack> extCmdBuilder = Commands.literal(extensionMapEntry.getKey().description().id()).executes(extensionHelpExecutor);
for (Map.Entry<String, Command> command : extensionCommands.entrySet()) { 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()) extCmdBuilder.then(Commands.literal(command.getKey())
.executes(executor) .executes(executor)
.requires(executor::testPermission) .requires(executor::testPermission)
@ -201,11 +189,14 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap {
geyser.shutdown(); geyser.shutdown();
geyser = null; geyser = null;
} }
if (geyserInjector != null) {
geyserInjector.shutdown();
this.server = null; this.server = null;
} }
}
@Override @Override
public GeyserConfiguration getGeyserConfig() { public GeyserModConfiguration getGeyserConfig() {
return geyserConfig; return geyserConfig;
} }
@ -236,7 +227,7 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap {
@Override @Override
public BootstrapDumpInfo getDumpInfo() { public BootstrapDumpInfo getDumpInfo() {
return new GeyserFabricDumpInfo(server); return this.platform.dumpInfo(this.server);
} }
@Override @Override
@ -252,37 +243,36 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap {
} }
@Override @Override
public int getServerPort() { public SocketAddress getSocketAddress() {
return ((GeyserServerPortGetter) server).geyser$getServerPort(); return this.geyserInjector.getServerSocketAddress();
} }
@Override @Override
public boolean testFloodgatePluginPresent() { public int getServerPort() {
Optional<ModContainer> floodgate = FabricLoader.getInstance().getModContainer("floodgate"); if (isServer()) {
if (floodgate.isPresent()) { return ((GeyserServerPortGetter) server).geyser$getServerPort();
geyserConfig.loadFloodgate(this, floodgate.orElse(null)); } else {
return true; // Set in the IntegratedServerMixin
return geyserConfig.getRemote().port();
} }
return false; }
public abstract boolean isServer();
@Override
public boolean testFloodgatePluginPresent() {
return this.platform.testFloodgatePluginPresent(this);
} }
@Nullable @Nullable
@Override @Override
public InputStream getResourceOrNull(String resource) { public InputStream getResourceOrNull(String resource) {
// We need to handle this differently, because Fabric shares the classloader across multiple mods return this.platform.resolveResource(resource);
Path path = this.mod.findPath(resource).orElse(null);
if (path == null) {
return null;
} }
try { public abstract boolean hasPermission(@NonNull Player source, @NonNull String permissionNode);
return path.getFileSystem()
.provider() public abstract boolean hasPermission(@NonNull CommandSourceStack source, @NonNull String permissionNode, int permissionLevel);
.newInputStream(path);
} catch (IOException e) {
return null;
}
}
@SuppressWarnings("BooleanMethodIsAlwaysInverted") @SuppressWarnings("BooleanMethodIsAlwaysInverted")
private boolean loadConfig() { private boolean loadConfig() {
@ -294,10 +284,10 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap {
File configFile = FileUtils.fileOrCopiedFromResource(dataFolder.resolve("config.yml").toFile(), "config.yml", File configFile = FileUtils.fileOrCopiedFromResource(dataFolder.resolve("config.yml").toFile(), "config.yml",
(x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()), this); (x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()), this);
this.geyserConfig = FileUtils.loadConfig(configFile, GeyserFabricConfiguration.class); this.geyserConfig = FileUtils.loadConfig(configFile, GeyserModConfiguration.class);
return true; return true;
} catch (IOException ex) { } catch (IOException ex) {
LogManager.getLogger("geyser-fabric").error(GeyserLocale.getLocaleStringLog("geyser.config.failed"), ex); geyserLogger.error(GeyserLocale.getLocaleStringLog("geyser.config.failed"), ex);
ex.printStackTrace(); ex.printStackTrace();
return false; return false;
} }

Datei anzeigen

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

Datei anzeigen

@ -23,23 +23,20 @@
* @link https://github.com/GeyserMC/Geyser * @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 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.FloodgateKeyLoader;
import org.geysermc.geyser.configuration.GeyserJacksonConfiguration; import org.geysermc.geyser.configuration.GeyserJacksonConfiguration;
import java.nio.file.Path; import java.nio.file.Path;
public class GeyserFabricConfiguration extends GeyserJacksonConfiguration { public class GeyserModConfiguration extends GeyserJacksonConfiguration {
@JsonIgnore @JsonIgnore
private Path floodgateKeyPath; private Path floodgateKeyPath;
public void loadFloodgate(GeyserFabricMod geyser, ModContainer floodgate) { public void loadFloodgate(GeyserModBootstrap geyser, Path floodgateDataFolder) {
Path geyserDataFolder = geyser.getConfigFolder(); Path geyserDataFolder = geyser.getConfigFolder();
Path floodgateDataFolder = floodgate != null ? FabricLoader.getInstance().getConfigDir().resolve("floodgate") : null;
floodgateKeyPath = FloodgateKeyLoader.getKeyPath(this, floodgateDataFolder, geyserDataFolder, geyser.getGeyserLogger()); floodgateKeyPath = FloodgateKeyLoader.getKeyPath(this, floodgateDataFolder, geyserDataFolder, geyser.getGeyserLogger());
} }

Datei anzeigen

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

Datei anzeigen

@ -23,7 +23,7 @@
* @link https://github.com/GeyserMC/Geyser * @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.Component;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; 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.GeyserLogger;
import org.geysermc.geyser.text.ChatColor; import org.geysermc.geyser.text.ChatColor;
public class GeyserFabricLogger implements GeyserLogger { public class GeyserModLogger implements GeyserLogger {
private final Logger logger = LogManager.getLogger("geyser-fabric"); private final Logger logger = LogManager.getLogger("geyser");
private boolean debug; private boolean debug;
public GeyserFabricLogger(boolean isDebug) {
debug = isDebug;
}
@Override @Override
public void severe(String message) { public void severe(String message) {
logger.fatal(message); logger.fatal(message);
@ -73,7 +69,7 @@ public class GeyserFabricLogger implements GeyserLogger {
@Override @Override
public void sendMessage(Component message) { 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); String flattened = LegacyComponentSerializer.legacySection().serialize(message);
// Add the reset at the end, or else format will persist... forever. // Add the reset at the end, or else format will persist... forever.
// https://cdn.discordapp.com/attachments/573909525132738590/1033904509170225242/unknown.png // https://cdn.discordapp.com/attachments/573909525132738590/1033904509170225242/unknown.png

Datei anzeigen

@ -23,21 +23,22 @@
* @link https://github.com/GeyserMC/Geyser * @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.commands.CommandSourceStack;
import net.minecraft.server.network.ServerGamePacketListenerImpl; import net.minecraft.world.entity.player.Player;
import org.geysermc.geyser.Constants; 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; import org.geysermc.geyser.util.VersionCheckUtils;
public final class GeyserFabricUpdateListener { public final class GeyserModUpdateListener {
public static void onPlayReady(ServerGamePacketListenerImpl handler) { public static void onPlayReady(Player player) {
if (Permissions.check(handler.player, Constants.UPDATE_PERMISSION, 2)) { CommandSourceStack stack = player.createCommandSourceStack();
VersionCheckUtils.checkForGeyserUpdate(() -> new FabricCommandSender(handler.player.createCommandSourceStack())); if (GeyserModBootstrap.getInstance().hasPermission(stack, Constants.UPDATE_PERMISSION, 2)) {
VersionCheckUtils.checkForGeyserUpdate(() -> new ModCommandSender(stack));
} }
} }
private GeyserFabricUpdateListener() { private GeyserModUpdateListener() {
} }
} }

Datei anzeigen

@ -23,7 +23,7 @@
* @link https://github.com/GeyserMC/Geyser * @link https://github.com/GeyserMC/Geyser
*/ */
package org.geysermc.geyser.platform.fabric; package org.geysermc.geyser.platform.mod;
import net.minecraft.server.MinecraftServer; import net.minecraft.server.MinecraftServer;

Datei anzeigen

@ -23,12 +23,13 @@
* @link https://github.com/GeyserMC/Geyser * @link https://github.com/GeyserMC/Geyser
*/ */
package org.geysermc.geyser.platform.fabric; package org.geysermc.geyser.platform.mod;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import net.minecraft.core.RegistryAccess;
import net.minecraft.network.Connection; import net.minecraft.network.Connection;
import net.minecraft.network.PacketSendListener; import net.minecraft.network.PacketSendListener;
import net.minecraft.network.protocol.Packet; 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.network.protocol.status.ServerboundStatusRequestPacket;
import net.minecraft.server.MinecraftServer; import net.minecraft.server.MinecraftServer;
import net.minecraft.server.network.ServerStatusPacketListenerImpl; 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.GeyserLogger;
import org.geysermc.geyser.ping.GeyserPingInfo; import org.geysermc.geyser.ping.GeyserPingInfo;
import org.geysermc.geyser.ping.IGeyserPingPassthrough; import org.geysermc.geyser.ping.IGeyserPingPassthrough;
import org.jetbrains.annotations.Nullable;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.util.Objects; import java.util.Objects;
@ -68,7 +70,7 @@ public class ModPingPassthrough implements IGeyserPingPassthrough {
StatusInterceptor connection = new StatusInterceptor(); StatusInterceptor connection = new StatusInterceptor();
ServerStatusPacketListener statusPacketListener = new ServerStatusPacketListenerImpl(status, connection); 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 // mods like MiniMOTD (that inject into the above method) have now processed the response
status = Objects.requireNonNull(connection.status, "status response"); status = Objects.requireNonNull(connection.status, "status response");
} catch (Exception e) { } 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())); String legacyDescription = LEGACY_SERIALIZER.serialize(GSON_SERIALIZER.deserializeOr(jsonDescription, Component.empty()));
return new GeyserPingInfo( return new GeyserPingInfo(
@ -100,7 +102,7 @@ public class ModPingPassthrough implements IGeyserPingPassthrough {
} }
@Override @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) { if (packet instanceof ClientboundStatusResponsePacket statusResponse) {
status = statusResponse.status(); status = statusResponse.status();
} }

Datei anzeigen

@ -23,31 +23,31 @@
* @link https://github.com/GeyserMC/Geyser * @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.Command;
import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.context.CommandContext;
import me.lucko.fabric.api.permissions.v0.Permissions;
import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.CommandSourceStack;
import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.command.GeyserCommand; import org.geysermc.geyser.command.GeyserCommand;
import org.geysermc.geyser.command.GeyserCommandExecutor; import org.geysermc.geyser.command.GeyserCommandExecutor;
import org.geysermc.geyser.platform.mod.GeyserModBootstrap;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.text.ChatColor; import org.geysermc.geyser.text.ChatColor;
import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.text.GeyserLocale;
import java.util.Collections; import java.util.Collections;
public class GeyserFabricCommandExecutor extends GeyserCommandExecutor implements Command<CommandSourceStack> { public class GeyserModCommandExecutor extends GeyserCommandExecutor implements Command<CommandSourceStack> {
private final GeyserCommand command; private final GeyserCommand command;
public GeyserFabricCommandExecutor(GeyserImpl connector, GeyserCommand command) { public GeyserModCommandExecutor(GeyserImpl geyser, GeyserCommand command) {
super(connector, Collections.singletonMap(command.name(), command)); super(geyser, Collections.singletonMap(command.name(), command));
this.command = command; this.command = command;
} }
public boolean testPermission(CommandSourceStack source) { 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 @Override
@ -57,7 +57,7 @@ public class GeyserFabricCommandExecutor extends GeyserCommandExecutor implement
public int runWithArgs(CommandContext<CommandSourceStack> context, String args) { public int runWithArgs(CommandContext<CommandSourceStack> context, String args) {
CommandSourceStack source = context.getSource(); CommandSourceStack source = context.getSource();
FabricCommandSender sender = new FabricCommandSender(source); ModCommandSender sender = new ModCommandSender(source);
GeyserSession session = getGeyserSession(sender); GeyserSession session = getGeyserSession(sender);
if (!testPermission(source)) { if (!testPermission(source)) {
sender.sendMessage(ChatColor.RED + GeyserLocale.getPlayerLocaleString("geyser.bootstrap.command.permission_fail", sender.locale())); sender.sendMessage(ChatColor.RED + GeyserLocale.getPlayerLocaleString("geyser.bootstrap.command.permission_fail", sender.locale()));

Datei anzeigen

@ -23,25 +23,26 @@
* @link https://github.com/GeyserMC/Geyser * @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.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.CommandSourceStack;
import net.minecraft.core.RegistryAccess;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerPlayer;
import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.NonNull;
import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.command.GeyserCommandSource; import org.geysermc.geyser.command.GeyserCommandSource;
import org.geysermc.geyser.platform.mod.GeyserModBootstrap;
import org.geysermc.geyser.text.ChatColor; import org.geysermc.geyser.text.ChatColor;
import java.util.Objects; import java.util.Objects;
public class FabricCommandSender implements GeyserCommandSource { public class ModCommandSender implements GeyserCommandSource {
private final CommandSourceStack source; private final CommandSourceStack source;
public FabricCommandSender(CommandSourceStack source) { public ModCommandSender(CommandSourceStack source) {
this.source = source; this.source = source;
} }
@ -63,7 +64,7 @@ public class FabricCommandSender implements GeyserCommandSource {
public void sendMessage(net.kyori.adventure.text.Component message) { public void sendMessage(net.kyori.adventure.text.Component message) {
if (source.getEntity() instanceof ServerPlayer player) { if (source.getEntity() instanceof ServerPlayer player) {
String decoded = GsonComponentSerializer.gson().serialize(message); 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; return;
} }
GeyserCommandSource.super.sendMessage(message); GeyserCommandSource.super.sendMessage(message);
@ -76,6 +77,6 @@ public class FabricCommandSender implements GeyserCommandSource {
@Override @Override
public boolean hasPermission(String permission) { public boolean hasPermission(String permission) {
return Permissions.check(source, permission, source.getServer().getOperatorUserPermissionLevel()); return GeyserModBootstrap.getInstance().hasPermission(source, permission, source.getServer().getOperatorUserPermissionLevel());
} }
} }

Datei anzeigen

@ -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 * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@ -23,18 +23,16 @@
* @link https://github.com/GeyserMC/Geyser * @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.Minecraft;
import net.minecraft.client.server.IntegratedServer; import net.minecraft.client.server.IntegratedServer;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.server.MinecraftServer; import net.minecraft.server.MinecraftServer;
import net.minecraft.world.level.GameType; import net.minecraft.world.level.GameType;
import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.platform.fabric.GeyserFabricMod; import org.geysermc.geyser.platform.mod.GeyserModBootstrap;
import org.geysermc.geyser.platform.fabric.GeyserServerPortGetter; import org.geysermc.geyser.platform.mod.GeyserServerPortGetter;
import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.text.GeyserLocale;
import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
@ -45,7 +43,6 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.Objects; import java.util.Objects;
@Environment(EnvType.CLIENT)
@Mixin(IntegratedServer.class) @Mixin(IntegratedServer.class)
public class IntegratedServerMixin implements GeyserServerPortGetter { public class IntegratedServerMixin implements GeyserServerPortGetter {
@Shadow @Shadow
@ -57,8 +54,10 @@ public class IntegratedServerMixin implements GeyserServerPortGetter {
private void onOpenToLan(GameType gameType, boolean cheatsAllowed, int port, CallbackInfoReturnable<Boolean> cir) { private void onOpenToLan(GameType gameType, boolean cheatsAllowed, int port, CallbackInfoReturnable<Boolean> cir) {
if (cir.getReturnValueZ()) { if (cir.getReturnValueZ()) {
// If the LAN is opened, starts Geyser. // If the LAN is opened, starts Geyser.
GeyserFabricMod.getInstance().setServer((MinecraftServer) (Object) this); GeyserModBootstrap instance = GeyserModBootstrap.getInstance();
GeyserFabricMod.getInstance().onGeyserEnable(); 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 // Ensure player locale has been loaded, in case it's different from Java system language
GeyserLocale.loadGeyserLocale(this.minecraft.options.languageCode); GeyserLocale.loadGeyserLocale(this.minecraft.options.languageCode);
// Give indication that Geyser is loaded // Give indication that Geyser is loaded

Datei anzeigen

@ -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 * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@ -23,7 +23,7 @@
* @link https://github.com/GeyserMC/Geyser * @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 com.mojang.datafixers.DataFixer;
import net.minecraft.server.MinecraftServer; 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.level.progress.ChunkProgressListenerFactory;
import net.minecraft.server.packs.repository.PackRepository; import net.minecraft.server.packs.repository.PackRepository;
import net.minecraft.world.level.storage.LevelStorageSource; 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 org.spongepowered.asm.mixin.Mixin;
import java.net.Proxy; import java.net.Proxy;
@Mixin(DedicatedServer.class) @Mixin(DedicatedServer.class)
public abstract class MinecraftDedicatedServerMixin extends MinecraftServer implements GeyserServerPortGetter { public abstract class DedicatedServerMixin extends MinecraftServer implements GeyserServerPortGetter {
public MinecraftDedicatedServerMixin(Thread thread, LevelStorageSource.LevelStorageAccess levelStorageAccess, PackRepository packRepository, WorldStem worldStem, Proxy proxy, DataFixer dataFixer, Services services, ChunkProgressListenerFactory chunkProgressListenerFactory) { 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); super(thread, levelStorageAccess, packRepository, worldStem, proxy, dataFixer, services, chunkProgressListenerFactory);
} }

Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

@ -4,25 +4,27 @@ dependencies {
isTransitive = false isTransitive = false
} }
implementation(libs.erosion.bukkit.nms) {
attributes {
attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 21)
}
}
implementation(variantOf(libs.adapters.spigot) { implementation(variantOf(libs.adapters.spigot) {
classifier("all") // otherwise the unshaded jar is used without the shaded NMS implementations classifier("all") // otherwise the unshaded jar is used without the shaded NMS implementations
}) })
implementation(variantOf(libs.adapters.paper) {
classifier("all") // otherwise the unshaded jar is used without the shaded NMS implementations
})
implementation(libs.commodore) implementation(libs.commodore)
implementation(libs.adventure.text.serializer.bungeecord) implementation(libs.adventure.text.serializer.bungeecord)
// Both folia-api and paper-mojangapi only provide Java 17 versions for 1.19 compileOnly(libs.folia.api)
compileOnly(libs.folia.api) { compileOnly(libs.paper.mojangapi)
attributes {
attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 17) compileOnlyApi(libs.viaversion)
}
}
compileOnly(libs.paper.mojangapi) {
attributes {
attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 17)
}
}
} }
platformRelocate("it.unimi.dsi.fastutil") platformRelocate("it.unimi.dsi.fastutil")
@ -41,6 +43,12 @@ application {
} }
tasks.withType<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar> { 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") archiveBaseName.set("Geyser-Spigot")
dependencies { 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 // We cannot shade Netty, or else native libraries will not load
// Needed because older Spigot builds do not provide the haproxy module // 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-classes-epoll:.*"))
exclude(dependency("io.netty:netty-transport-native-epoll:.*")) exclude(dependency("io.netty:netty-transport-native-epoll:.*"))
exclude(dependency("io.netty:netty-transport-native-unix-common:.*")) 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:.*")) exclude(dependency("com.mojang:.*"))
} }
} }
modrinth {
uploadFile.set(tasks.getByPath("shadowJar"))
loaders.addAll("spigot", "paper")
}

Datei anzeigen

@ -34,8 +34,8 @@ import java.util.logging.Logger;
public final class GeyserPaperLogger extends GeyserSpigotLogger { public final class GeyserPaperLogger extends GeyserSpigotLogger {
private final ComponentLogger componentLogger; private final ComponentLogger componentLogger;
public GeyserPaperLogger(Plugin plugin, Logger logger, boolean debug) { public GeyserPaperLogger(Plugin plugin, Logger logger) {
super(logger, debug); super(logger);
componentLogger = plugin.getComponentLogger(); componentLogger = plugin.getComponentLogger();
} }

Datei anzeigen

@ -25,7 +25,7 @@
package org.geysermc.geyser.platform.spigot; 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 com.viaversion.viaversion.bukkit.handlers.BukkitChannelInitializer;
import io.netty.bootstrap.ServerBootstrap; import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*; import io.netty.channel.*;
@ -119,8 +119,11 @@ public class GeyserSpigotInjector extends GeyserInjector {
protected void initChannel(@NonNull Channel ch) throws Exception { protected void initChannel(@NonNull Channel ch) throws Exception {
initChannel.invoke(childHandler, ch); initChannel.invoke(childHandler, ch);
int index = ch.pipeline().names().indexOf("encoder");
String baseName = index != -1 ? "encoder" : "outbound_config";
if (bootstrap.getGeyserConfig().isDisableCompression() && GeyserSpigotCompressionDisabler.ENABLED) { 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, bootstrap.getGeyserConfig().getRemote().port(), this.serverSocketAddress,
InetAddress.getLoopbackAddress().getHostAddress(), protocol, protocol.createHelper()); InetAddress.getLoopbackAddress().getHostAddress(), protocol, protocol.createHelper());
session.connect(); session.connect();
session.disconnect("");
} }
@Override @Override

Datei anzeigen

@ -25,15 +25,15 @@
package org.geysermc.geyser.platform.spigot; package org.geysermc.geyser.platform.spigot;
import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter; import lombok.Setter;
import org.geysermc.geyser.GeyserLogger; import org.geysermc.geyser.GeyserLogger;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
@AllArgsConstructor @RequiredArgsConstructor
public class GeyserSpigotLogger implements GeyserLogger { public class GeyserSpigotLogger implements GeyserLogger {
private final Logger logger; private final Logger logger;
@Getter @Setter @Getter @Setter

Datei anzeigen

@ -46,6 +46,7 @@ import org.checkerframework.checker.nullness.qual.NonNull;
import org.geysermc.geyser.Constants; import org.geysermc.geyser.Constants;
import org.geysermc.geyser.GeyserBootstrap; import org.geysermc.geyser.GeyserBootstrap;
import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.adapters.paper.PaperAdapters;
import org.geysermc.geyser.adapters.spigot.SpigotAdapters; import org.geysermc.geyser.adapters.spigot.SpigotAdapters;
import org.geysermc.geyser.api.command.Command; import org.geysermc.geyser.api.command.Command;
import org.geysermc.geyser.api.extension.Extension; import org.geysermc.geyser.api.extension.Extension;
@ -78,14 +79,14 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.UUID; import java.util.UUID;
import java.util.logging.Level;
public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
private GeyserSpigotCommandManager geyserCommandManager; private GeyserSpigotCommandManager geyserCommandManager;
private GeyserSpigotConfiguration geyserConfig; private GeyserSpigotConfiguration geyserConfig;
private GeyserSpigotInjector geyserInjector; private GeyserSpigotInjector geyserInjector;
private GeyserSpigotLogger geyserLogger; private final GeyserSpigotLogger geyserLogger = GeyserPaperLogger.supported() ?
new GeyserPaperLogger(this, getLogger()) : new GeyserSpigotLogger(getLogger());
private IGeyserPingPassthrough geyserSpigotPingPassthrough; private IGeyserPingPassthrough geyserSpigotPingPassthrough;
private GeyserSpigotWorldManager geyserWorldManager; private GeyserSpigotWorldManager geyserWorldManager;
@ -113,12 +114,12 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
// We depend on this as a fallback in certain scenarios // We depend on this as a fallback in certain scenarios
BlockData.class.getMethod("getAsString"); BlockData.class.getMethod("getAsString");
} catch (ClassNotFoundException | NoSuchMethodException e) { } catch (ClassNotFoundException | NoSuchMethodException e) {
getLogger().severe("*********************************************"); geyserLogger.error("*********************************************");
getLogger().severe(""); geyserLogger.error("");
getLogger().severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_server.header")); geyserLogger.error(GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_server.header"));
getLogger().severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_server.message", "1.13.2")); geyserLogger.error(GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_server.message", "1.13.2"));
getLogger().severe(""); geyserLogger.error("");
getLogger().severe("*********************************************"); geyserLogger.error("*********************************************");
Bukkit.getPluginManager().disablePlugin(this); Bukkit.getPluginManager().disablePlugin(this);
return; return;
} }
@ -127,12 +128,12 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
Class.forName("net.md_5.bungee.chat.ComponentSerializer"); Class.forName("net.md_5.bungee.chat.ComponentSerializer");
} catch (ClassNotFoundException e) { } catch (ClassNotFoundException e) {
if (!PaperAdventure.canSendMessageUsingComponent()) { // Prepare for Paper eventually removing Bungee chat if (!PaperAdventure.canSendMessageUsingComponent()) { // Prepare for Paper eventually removing Bungee chat
getLogger().severe("*********************************************"); geyserLogger.error("*********************************************");
getLogger().severe(""); geyserLogger.error("");
getLogger().severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_server_type.header", getServer().getName())); geyserLogger.error(GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_server_type.header", getServer().getName()));
getLogger().severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_server_type.message", "Paper")); geyserLogger.error(GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_server_type.message", "Paper"));
getLogger().severe(""); geyserLogger.error("");
getLogger().severe("*********************************************"); geyserLogger.error("*********************************************");
Bukkit.getPluginManager().disablePlugin(this); Bukkit.getPluginManager().disablePlugin(this);
return; return;
} }
@ -141,11 +142,11 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
try { try {
Class.forName("io.netty.util.internal.ObjectPool$ObjectCreator"); Class.forName("io.netty.util.internal.ObjectPool$ObjectCreator");
} catch (ClassNotFoundException e) { } catch (ClassNotFoundException e) {
getLogger().severe("*********************************************"); geyserLogger.error("*********************************************");
getLogger().severe(""); geyserLogger.error("");
getLogger().severe("This version of Spigot is using an outdated version of netty. Please use Paper instead!"); geyserLogger.error("This version of Spigot is using an outdated version of netty. Please use Paper instead!");
getLogger().severe(""); geyserLogger.error("");
getLogger().severe("*********************************************"); geyserLogger.error("*********************************************");
Bukkit.getPluginManager().disablePlugin(this); Bukkit.getPluginManager().disablePlugin(this);
return; return;
} }
@ -153,8 +154,7 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
if (!loadConfig()) { if (!loadConfig()) {
return; return;
} }
this.geyserLogger = GeyserPaperLogger.supported() ? new GeyserPaperLogger(this, getLogger(), geyserConfig.isDebugMode()) this.geyserLogger.setDebug(geyserConfig.isDebugMode());
: new GeyserSpigotLogger(getLogger(), geyserConfig.isDebugMode());
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger); GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
// Turn "(MC: 1.16.4)" into 1.16.4. // Turn "(MC: 1.16.4)" into 1.16.4.
@ -243,18 +243,30 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
this.geyserInjector.initializeLocalChannel(this); this.geyserInjector.initializeLocalChannel(this);
if (Boolean.parseBoolean(System.getProperty("Geyser.UseDirectAdapters", "true"))) { if (Boolean.parseBoolean(System.getProperty("Geyser.UseDirectAdapters", "true"))) {
try {
boolean isPaper = false;
try { try {
String name = Bukkit.getServer().getClass().getPackage().getName(); String name = Bukkit.getServer().getClass().getPackage().getName();
String nmsVersion = name.substring(name.lastIndexOf('.') + 1); String nmsVersion = name.substring(name.lastIndexOf('.') + 1);
SpigotAdapters.registerWorldAdapter(nmsVersion); 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()) { if (isViaVersion && isViaVersionNeeded()) {
this.geyserWorldManager = new GeyserSpigotLegacyNativeWorldManager(this); this.geyserWorldManager = new GeyserSpigotLegacyNativeWorldManager(this, isPaper);
} else { } else {
// No ViaVersion // No ViaVersion
this.geyserWorldManager = new GeyserSpigotNativeWorldManager(this); this.geyserWorldManager = new GeyserSpigotNativeWorldManager(this, isPaper);
} }
geyserLogger.debug("Using NMS adapter: " + this.geyserWorldManager.getClass() + ", " + nmsVersion); geyserLogger.debug("Using world manager of type: " + this.geyserWorldManager.getClass().getSimpleName());
} catch (Exception e) { } catch (Throwable e) {
if (geyserConfig.isDebugMode()) { if (geyserConfig.isDebugMode()) {
geyserLogger.debug("Error while attempting to find NMS adapter. Most likely, this can be safely ignored. :)"); geyserLogger.debug("Error while attempting to find NMS adapter. Most likely, this can be safely ignored. :)");
e.printStackTrace(); e.printStackTrace();
@ -433,7 +445,7 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
return false; return false;
} }
for (int i = protocolList.size() - 1; i >= 0; i--) { 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) { if (mappingData != null) {
return true; return true;
} }
@ -474,7 +486,7 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
(x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()), this); (x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()), this);
this.geyserConfig = FileUtils.loadConfig(configFile, GeyserSpigotConfiguration.class); this.geyserConfig = FileUtils.loadConfig(configFile, GeyserSpigotConfiguration.class);
} catch (IOException ex) { } catch (IOException ex) {
getLogger().log(Level.SEVERE, GeyserLocale.getLocaleStringLog("geyser.config.failed"), ex); geyserLogger.error(GeyserLocale.getLocaleStringLog("geyser.config.failed"), ex);
ex.printStackTrace(); ex.printStackTrace();
Bukkit.getPluginManager().disablePlugin(this); Bukkit.getPluginManager().disablePlugin(this);
return false; return false;

Datei anzeigen

@ -25,7 +25,7 @@
package org.geysermc.geyser.platform.spigot; 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 net.kyori.adventure.text.Component;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.Nullable;

Datei anzeigen

@ -25,10 +25,8 @@
package org.geysermc.geyser.platform.spigot.world; package org.geysermc.geyser.platform.spigot.world;
import com.github.steveice10.mc.protocol.data.game.level.block.value.PistonValueType; import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap;
import org.cloudburstmc.math.vector.Vector3i; import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
import it.unimi.dsi.fastutil.objects.Object2IntArrayMap;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.World; import org.bukkit.World;
@ -40,13 +38,17 @@ import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockPistonEvent; import org.bukkit.event.block.BlockPistonEvent;
import org.bukkit.event.block.BlockPistonExtendEvent; import org.bukkit.event.block.BlockPistonExtendEvent;
import org.bukkit.event.block.BlockPistonRetractEvent; import org.bukkit.event.block.BlockPistonRetractEvent;
import org.cloudburstmc.math.vector.Vector3i;
import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.level.block.BlockStateValues;
import org.geysermc.geyser.level.block.property.Properties;
import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.level.physics.Direction; import org.geysermc.geyser.level.physics.Direction;
import org.geysermc.geyser.platform.spigot.world.manager.GeyserSpigotWorldManager; import org.geysermc.geyser.platform.spigot.world.manager.GeyserSpigotWorldManager;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.session.cache.PistonCache; import org.geysermc.geyser.session.cache.PistonCache;
import org.geysermc.geyser.translator.level.block.entity.PistonBlockEntity; import org.geysermc.geyser.translator.level.block.entity.PistonBlockEntity;
import org.geysermc.mcprotocollib.protocol.data.game.level.block.value.PistonValueType;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -85,7 +87,7 @@ public class GeyserPistonListener implements Listener {
PistonValueType type = isExtend ? PistonValueType.PUSHING : PistonValueType.PULLING; PistonValueType type = isExtend ? PistonValueType.PUSHING : PistonValueType.PULLING;
boolean sticky = event.isSticky(); boolean sticky = event.isSticky();
Object2IntMap<Vector3i> attachedBlocks = new Object2IntArrayMap<>(); Object2ObjectMap<Vector3i, BlockState> attachedBlocks = new Object2ObjectArrayMap<>();
boolean blocksFilled = false; boolean blocksFilled = false;
for (Map.Entry<UUID, GeyserSession> entry : geyser.getSessionManager().getSessions().entrySet()) { for (Map.Entry<UUID, GeyserSession> entry : geyser.getSessionManager().getSessions().entrySet()) {
@ -108,10 +110,10 @@ public class GeyserPistonListener implements Listener {
List<Block> blocks = isExtend ? ((BlockPistonExtendEvent) event).getBlocks() : ((BlockPistonRetractEvent) event).getBlocks(); List<Block> blocks = isExtend ? ((BlockPistonExtendEvent) event).getBlocks() : ((BlockPistonRetractEvent) event).getBlocks();
for (Block block : blocks) { for (Block block : blocks) {
Location attachedLocation = block.getLocation(); Location attachedLocation = block.getLocation();
int blockId = worldManager.getBlockNetworkId(block); BlockState state = BlockState.of(worldManager.getBlockNetworkId(block));
// Ignore blocks that will be destroyed // Ignore blocks that will be destroyed
if (BlockStateValues.canPistonMoveBlock(blockId, isExtend)) { if (BlockStateValues.canPistonMoveBlock(state, isExtend)) {
attachedBlocks.put(getVector(attachedLocation), blockId); attachedBlocks.put(getVector(attachedLocation), state);
} }
} }
blocksFilled = true; blocksFilled = true;
@ -119,7 +121,7 @@ public class GeyserPistonListener implements Listener {
int pistonBlockId = worldManager.getBlockNetworkId(event.getBlock()); int pistonBlockId = worldManager.getBlockNetworkId(event.getBlock());
// event.getDirection() is unreliable // event.getDirection() is unreliable
Direction orientation = BlockStateValues.getPistonOrientation(pistonBlockId); Direction orientation = BlockState.of(pistonBlockId).getValue(Properties.FACING);
session.executeInEventLoop(() -> { session.executeInEventLoop(() -> {
PistonCache pistonCache = session.getPistonCache(); PistonCache pistonCache = session.getPistonCache();

Datei anzeigen

@ -33,7 +33,7 @@ import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.event.block.BlockPlaceEvent;
import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.level.block.type.Block;
import org.geysermc.geyser.platform.spigot.world.manager.GeyserSpigotWorldManager; import org.geysermc.geyser.platform.spigot.world.manager.GeyserSpigotWorldManager;
import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.BlockRegistries;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
@ -59,11 +59,11 @@ public class GeyserSpigotBlockPlaceListener implements Listener {
event.getBlockPlaced().getX(), event.getBlockPlaced().getY(), event.getBlockPlaced().getZ()))); event.getBlockPlaced().getX(), event.getBlockPlaced().getY(), event.getBlockPlaced().getZ())));
} else { } else {
String javaBlockId = event.getBlockPlaced().getBlockData().getAsString(); String javaBlockId = event.getBlockPlaced().getBlockData().getAsString();
placeBlockSoundPacket.setExtraData(session.getBlockMappings().getBedrockBlockId(BlockRegistries.JAVA_IDENTIFIER_TO_ID.get().getOrDefault(javaBlockId, BlockStateValues.JAVA_AIR_ID))); placeBlockSoundPacket.setExtraData(session.getBlockMappings().getBedrockBlockId(BlockRegistries.JAVA_IDENTIFIER_TO_ID.get().getOrDefault(javaBlockId, Block.JAVA_AIR_ID)));
} }
placeBlockSoundPacket.setIdentifier(":"); placeBlockSoundPacket.setIdentifier(":");
session.sendUpstreamPacket(placeBlockSoundPacket); session.sendUpstreamPacket(placeBlockSoundPacket);
session.setLastBlockPlacePosition(null); session.setLastBlockPlacePosition(null);
session.setLastBlockPlacedId(null); session.setLastBlockPlaced(null);
} }
} }

Datei anzeigen

@ -46,8 +46,8 @@ public class GeyserSpigotLegacyNativeWorldManager extends GeyserSpigotNativeWorl
private final Int2IntMap oldToNewBlockId; private final Int2IntMap oldToNewBlockId;
public GeyserSpigotLegacyNativeWorldManager(GeyserSpigotPlugin plugin) { public GeyserSpigotLegacyNativeWorldManager(GeyserSpigotPlugin plugin, boolean isPaper) {
super(plugin); super(plugin, isPaper);
IntList allBlockStates = adapter.getAllBlockStates(); IntList allBlockStates = adapter.getAllBlockStates();
oldToNewBlockId = new Int2IntOpenHashMap(allBlockStates.size()); oldToNewBlockId = new Int2IntOpenHashMap(allBlockStates.size());
ProtocolVersion serverVersion = plugin.getServerProtocolVersion(); ProtocolVersion serverVersion = plugin.getServerProtocolVersion();
@ -58,7 +58,7 @@ public class GeyserSpigotLegacyNativeWorldManager extends GeyserSpigotNativeWorl
int newBlockId = oldBlockId; int newBlockId = oldBlockId;
// protocolList should *not* be null; we checked for that before initializing this class // protocolList should *not* be null; we checked for that before initializing this class
for (int i = protocolList.size() - 1; i >= 0; i--) { 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) { if (mappingData != null) {
newBlockId = mappingData.getNewBlockStateId(newBlockId); newBlockId = mappingData.getNewBlockStateId(newBlockId);
} }

Datei anzeigen

@ -26,27 +26,34 @@
package org.geysermc.geyser.platform.spigot.world.manager; package org.geysermc.geyser.platform.spigot.world.manager;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
import org.checkerframework.checker.nullness.qual.Nullable; 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.SpigotAdapters;
import org.geysermc.geyser.adapters.spigot.SpigotWorldAdapter;
import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.level.block.BlockStateValues;
import org.geysermc.geyser.level.block.type.Block;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
public class GeyserSpigotNativeWorldManager extends GeyserSpigotWorldManager { public class GeyserSpigotNativeWorldManager extends GeyserSpigotWorldManager {
protected final SpigotWorldAdapter adapter; protected final WorldAdapter<World> adapter;
public GeyserSpigotNativeWorldManager(Plugin plugin) { public GeyserSpigotNativeWorldManager(Plugin plugin, boolean isPaper) {
super(plugin); super(plugin);
if (isPaper) {
adapter = PaperAdapters.getWorldAdapter();
} else {
adapter = SpigotAdapters.getWorldAdapter(); adapter = SpigotAdapters.getWorldAdapter();
} }
}
@Override @Override
public int getBlockAt(GeyserSession session, int x, int y, int z) { public int getBlockAt(GeyserSession session, int x, int y, int z) {
Player player = Bukkit.getPlayer(session.getPlayerEntity().getUsername()); Player player = Bukkit.getPlayer(session.getPlayerEntity().getUsername());
if (player == null) { if (player == null) {
return BlockStateValues.JAVA_AIR_ID; return Block.JAVA_AIR_ID;
} }
return adapter.getBlockAt(player.getWorld(), x, y, z); return adapter.getBlockAt(player.getWorld(), x, y, z);
} }

Datei anzeigen

@ -25,31 +25,24 @@
package org.geysermc.geyser.platform.spigot.world.manager; package org.geysermc.geyser.platform.spigot.world.manager;
import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityInfo;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.nbt.NbtMap;
import org.geysermc.erosion.bukkit.BukkitLecterns;
import org.geysermc.erosion.bukkit.BukkitUtils;
import org.geysermc.erosion.bukkit.PickBlockUtils; import org.geysermc.erosion.bukkit.PickBlockUtils;
import org.geysermc.erosion.bukkit.SchedulerUtils; import org.geysermc.erosion.bukkit.SchedulerUtils;
import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.level.GameRule; import org.geysermc.geyser.level.GameRule;
import org.geysermc.geyser.level.WorldManager; import org.geysermc.geyser.level.WorldManager;
import org.geysermc.geyser.level.block.BlockStateValues;
import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.BlockRegistries;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.BlockEntityUtils; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode;
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents;
import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
@ -58,23 +51,21 @@ import java.util.concurrent.CompletableFuture;
*/ */
public class GeyserSpigotWorldManager extends WorldManager { public class GeyserSpigotWorldManager extends WorldManager {
private final Plugin plugin; private final Plugin plugin;
private final BukkitLecterns lecterns;
public GeyserSpigotWorldManager(Plugin plugin) { public GeyserSpigotWorldManager(Plugin plugin) {
this.plugin = plugin; this.plugin = plugin;
this.lecterns = new BukkitLecterns(plugin);
} }
@Override @Override
public int getBlockAt(GeyserSession session, int x, int y, int z) { public int getBlockAt(GeyserSession session, int x, int y, int z) {
Player bukkitPlayer; Player bukkitPlayer;
if ((bukkitPlayer = Bukkit.getPlayer(session.getPlayerEntity().getUsername())) == null) { if ((bukkitPlayer = Bukkit.getPlayer(session.getPlayerEntity().getUsername())) == null) {
return BlockStateValues.JAVA_AIR_ID; return org.geysermc.geyser.level.block.type.Block.JAVA_AIR_ID;
} }
World world = bukkitPlayer.getWorld(); World world = bukkitPlayer.getWorld();
if (!world.isChunkLoaded(x >> 4, z >> 4)) { if (!world.isChunkLoaded(x >> 4, z >> 4)) {
// If the chunk isn't loaded, how could we even be here? // If the chunk isn't loaded, how could we even be here?
return BlockStateValues.JAVA_AIR_ID; return org.geysermc.geyser.level.block.type.Block.JAVA_AIR_ID;
} }
return getBlockNetworkId(world.getBlockAt(x, y, z)); return getBlockNetworkId(world.getBlockAt(x, y, z));
@ -85,9 +76,9 @@ public class GeyserSpigotWorldManager extends WorldManager {
// Terrible behavior, but this is basically what's always been happening behind the scenes anyway. // Terrible behavior, but this is basically what's always been happening behind the scenes anyway.
CompletableFuture<String> blockData = new CompletableFuture<>(); CompletableFuture<String> blockData = new CompletableFuture<>();
Bukkit.getRegionScheduler().execute(this.plugin, block.getLocation(), () -> blockData.complete(block.getBlockData().getAsString())); Bukkit.getRegionScheduler().execute(this.plugin, block.getLocation(), () -> blockData.complete(block.getBlockData().getAsString()));
return BlockRegistries.JAVA_IDENTIFIER_TO_ID.getOrDefault(blockData.join(), BlockStateValues.JAVA_AIR_ID); return BlockRegistries.JAVA_IDENTIFIER_TO_ID.getOrDefault(blockData.join(), org.geysermc.geyser.level.block.type.Block.JAVA_AIR_ID);
} }
return BlockRegistries.JAVA_IDENTIFIER_TO_ID.getOrDefault(block.getBlockData().getAsString(), BlockStateValues.JAVA_AIR_ID); return BlockRegistries.JAVA_IDENTIFIER_TO_ID.getOrDefault(block.getBlockData().getAsString(), org.geysermc.geyser.level.block.type.Block.JAVA_AIR_ID); // TODO could just make this a BlockState lookup?
} }
@Override @Override
@ -95,69 +86,6 @@ public class GeyserSpigotWorldManager extends WorldManager {
return true; return true;
} }
@Override
public void sendLecternData(GeyserSession session, int x, int y, int z) {
Player bukkitPlayer;
if ((bukkitPlayer = Bukkit.getPlayer(session.getPlayerEntity().getUsername())) == null) {
return;
}
Block block = bukkitPlayer.getWorld().getBlockAt(x, y, z);
// Run as a task to prevent async issues
SchedulerUtils.runTask(this.plugin, () -> sendLecternData(session, block, false), block);
}
public void sendLecternData(GeyserSession session, int x, int z, List<BlockEntityInfo> blockEntityInfos) {
Player bukkitPlayer;
if ((bukkitPlayer = Bukkit.getPlayer(session.getPlayerEntity().getUsername())) == null) {
return;
}
if (SchedulerUtils.FOLIA) {
Chunk chunk = getChunk(bukkitPlayer.getWorld(), x, z);
if (chunk == null) {
return;
}
Bukkit.getRegionScheduler().execute(this.plugin, bukkitPlayer.getWorld(), x, z, () ->
sendLecternData(session, chunk, blockEntityInfos));
} else {
Bukkit.getScheduler().runTask(this.plugin, () -> {
Chunk chunk = getChunk(bukkitPlayer.getWorld(), x, z);
if (chunk == null) {
return;
}
sendLecternData(session, chunk, blockEntityInfos);
});
}
}
private @Nullable Chunk getChunk(World world, int x, int z) {
if (!world.isChunkLoaded(x, z)) {
return null;
}
return world.getChunkAt(x, z);
}
private void sendLecternData(GeyserSession session, Chunk chunk, List<BlockEntityInfo> blockEntityInfos) {
//noinspection ForLoopReplaceableByForEach - avoid constructing Iterator
for (int i = 0; i < blockEntityInfos.size(); i++) {
BlockEntityInfo info = blockEntityInfos.get(i);
Block block = chunk.getBlock(info.getX(), info.getY(), info.getZ());
sendLecternData(session, block, true);
}
}
private void sendLecternData(GeyserSession session, Block block, boolean isChunkLoad) {
NbtMap blockEntityTag = this.lecterns.getLecternData(block, isChunkLoad);
if (blockEntityTag != null) {
BlockEntityUtils.updateBlockEntity(session, blockEntityTag, BukkitUtils.getVector(block.getLocation()));
}
}
@Override
public boolean shouldExpectLecternHandled(GeyserSession session) {
return true;
}
public boolean getGameRuleBool(GeyserSession session, GameRule gameRule) { public boolean getGameRuleBool(GeyserSession session, GameRule gameRule) {
org.bukkit.GameRule<?> bukkitGameRule = org.bukkit.GameRule.getByName(gameRule.getJavaID()); org.bukkit.GameRule<?> bukkitGameRule = org.bukkit.GameRule.getByName(gameRule.getJavaID());
if (bukkitGameRule == null) { if (bukkitGameRule == null) {
@ -205,18 +133,17 @@ public class GeyserSpigotWorldManager extends WorldManager {
} }
@Override @Override
public @NonNull CompletableFuture<@Nullable CompoundTag> getPickItemNbt(GeyserSession session, int x, int y, int z, boolean addNbtData) { public @NonNull CompletableFuture<@Nullable DataComponents> getPickItemComponents(GeyserSession session, int x, int y, int z, boolean addNbtData) {
CompletableFuture<@Nullable CompoundTag> future = new CompletableFuture<>();
Player bukkitPlayer; Player bukkitPlayer;
if ((bukkitPlayer = Bukkit.getPlayer(session.getPlayerEntity().getUuid())) == null) { if ((bukkitPlayer = Bukkit.getPlayer(session.getPlayerEntity().getUuid())) == null) {
future.complete(null); return CompletableFuture.completedFuture(null);
return future;
} }
CompletableFuture<Int2ObjectMap<byte[]>> future = new CompletableFuture<>();
Block block = bukkitPlayer.getWorld().getBlockAt(x, y, z); Block block = bukkitPlayer.getWorld().getBlockAt(x, y, z);
// Paper 1.19.3 complains about async access otherwise. // Paper 1.19.3 complains about async access otherwise.
// java.lang.IllegalStateException: Tile is null, asynchronous access? // java.lang.IllegalStateException: Tile is null, asynchronous access?
SchedulerUtils.runTask(this.plugin, () -> future.complete(PickBlockUtils.pickBlock(block)), block); SchedulerUtils.runTask(this.plugin, () -> future.complete(PickBlockUtils.pickBlock(block)), block);
return future; return future.thenApply(RAW_TRANSFORMER);
} }
/** /**

Datei anzeigen

@ -71,7 +71,7 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap {
private GeyserCommandManager geyserCommandManager; private GeyserCommandManager geyserCommandManager;
private GeyserStandaloneConfiguration geyserConfig; private GeyserStandaloneConfiguration geyserConfig;
private GeyserStandaloneLogger geyserLogger; private final GeyserStandaloneLogger geyserLogger = new GeyserStandaloneLogger();
private IGeyserPingPassthrough geyserPingPassthrough; private IGeyserPingPassthrough geyserPingPassthrough;
private GeyserStandaloneGUI gui; private GeyserStandaloneGUI gui;
@Getter @Getter
@ -181,8 +181,6 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap {
} }
} }
this.geyserLogger = new GeyserStandaloneLogger();
if (useGui && gui == null) { if (useGui && gui == null) {
gui = new GeyserStandaloneGUI(geyserLogger); gui = new GeyserStandaloneGUI(geyserLogger);
gui.redirectSystemStreams(); gui.redirectSystemStreams();

Datei anzeigen

@ -100,7 +100,7 @@ public class GeyserStandaloneGUI {
Container cp = frame.getContentPane(); Container cp = frame.getContentPane();
// Fetch and set the icon for the frame // 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) { if (image != null) {
ImageIcon icon = new ImageIcon(image); ImageIcon icon = new ImageIcon(image);
frame.setIconImage(icon.getImage()); frame.setIconImage(icon.getImage());

Datei anzeigen

@ -1,15 +1,19 @@
dependencies { dependencies {
annotationProcessor(libs.velocity.api) annotationProcessor(libs.velocity.api)
api(projects.core) api(projects.core)
compileOnlyApi(libs.velocity.api)
} }
platformRelocate("com.fasterxml.jackson") platformRelocate("com.fasterxml.jackson")
platformRelocate("it.unimi.dsi.fastutil") platformRelocate("it.unimi.dsi.fastutil")
platformRelocate("net.kyori.adventure.text.serializer.gson.legacyimpl") platformRelocate("net.kyori.adventure.text.serializer.gson.legacyimpl")
platformRelocate("org.yaml")
exclude("com.google.*:*") 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-epoll:*")
exclude("io.netty:netty-transport-native-unix-common:*") exclude("io.netty:netty-transport-native-unix-common:*")
exclude("io.netty:netty-transport-native-kqueue:*") 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-transport:.*"))
exclude(dependency("io.netty:netty-codec:.*")) exclude(dependency("io.netty:netty-codec:.*"))
exclude(dependency("io.netty:netty-codec-haproxy:.*")) exclude(dependency("io.netty:netty-codec-haproxy:.*"))
exclude(dependency("io.netty.incubator:.*"))
exclude(dependency("org.slf4j:.*")) exclude(dependency("org.slf4j:.*"))
exclude(dependency("org.ow2.asm:.*")) exclude(dependency("org.ow2.asm:.*"))
// Exclude all Kyori dependencies except the legacy NBT serializer // Exclude all Kyori dependencies except the legacy NBT serializer
@ -65,3 +70,8 @@ tasks.withType<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar> {
exclude(dependency("net.kyori:adventure-nbt:.*")) exclude(dependency("net.kyori:adventure-nbt:.*"))
} }
} }
modrinth {
uploadFile.set(tasks.getByPath("shadowJar"))
loaders.addAll("velocity")
}

Datei anzeigen

@ -25,13 +25,13 @@
package org.geysermc.geyser.platform.velocity; package org.geysermc.geyser.platform.velocity;
import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter; import lombok.Setter;
import org.geysermc.geyser.GeyserLogger; import org.geysermc.geyser.GeyserLogger;
import org.slf4j.Logger; import org.slf4j.Logger;
@AllArgsConstructor @RequiredArgsConstructor
public class GeyserVelocityLogger implements GeyserLogger { public class GeyserVelocityLogger implements GeyserLogger {
private final Logger logger; private final Logger logger;
@Getter @Setter @Getter @Setter

Datei anzeigen

@ -26,6 +26,7 @@
package org.geysermc.geyser.platform.velocity; package org.geysermc.geyser.platform.velocity;
import com.velocitypowered.api.event.proxy.ProxyPingEvent; import com.velocitypowered.api.event.proxy.ProxyPingEvent;
import com.velocitypowered.api.network.ProtocolState;
import com.velocitypowered.api.network.ProtocolVersion; import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.api.proxy.InboundConnection; import com.velocitypowered.api.proxy.InboundConnection;
import com.velocitypowered.api.proxy.ProxyServer; import com.velocitypowered.api.proxy.ProxyServer;
@ -88,6 +89,11 @@ public class GeyserVelocityPingPassthrough implements IGeyserPingPassthrough {
public ProtocolVersion getProtocolVersion() { public ProtocolVersion getProtocolVersion() {
return ProtocolVersion.MAXIMUM_VERSION; return ProtocolVersion.MAXIMUM_VERSION;
} }
@Override
public ProtocolState getProtocolState() {
return ProtocolState.STATUS;
}
} }
} }

Datei anzeigen

@ -64,44 +64,44 @@ import java.util.UUID;
@Plugin(id = "geyser", name = GeyserImpl.NAME + "-Velocity", version = GeyserImpl.VERSION, url = "https://geysermc.org", authors = "GeyserMC") @Plugin(id = "geyser", name = GeyserImpl.NAME + "-Velocity", version = GeyserImpl.VERSION, url = "https://geysermc.org", authors = "GeyserMC")
public class GeyserVelocityPlugin implements GeyserBootstrap { public class GeyserVelocityPlugin implements GeyserBootstrap {
@Inject
private Logger logger;
@Inject
private ProxyServer proxyServer;
@Inject
private CommandManager commandManager;
private final ProxyServer proxyServer;
private final CommandManager commandManager;
private final GeyserVelocityLogger geyserLogger;
private GeyserCommandManager geyserCommandManager; private GeyserCommandManager geyserCommandManager;
private GeyserVelocityConfiguration geyserConfig; private GeyserVelocityConfiguration geyserConfig;
private GeyserVelocityInjector geyserInjector; private GeyserVelocityInjector geyserInjector;
private GeyserVelocityLogger geyserLogger;
private IGeyserPingPassthrough geyserPingPassthrough; private IGeyserPingPassthrough geyserPingPassthrough;
private GeyserImpl geyser; private GeyserImpl geyser;
@Getter @Getter
private final Path configFolder = Paths.get("plugins/" + GeyserImpl.NAME + "-Velocity/"); private final Path configFolder = Paths.get("plugins/" + GeyserImpl.NAME + "-Velocity/");
@Inject
public GeyserVelocityPlugin(ProxyServer server, Logger logger, CommandManager manager) {
this.geyserLogger = new GeyserVelocityLogger(logger);
this.proxyServer = server;
this.commandManager = manager;
}
@Override @Override
public void onGeyserInitialize() { public void onGeyserInitialize() {
GeyserLocale.init(this); GeyserLocale.init(this);
if (!ProtocolVersion.isSupported(GameProtocol.getJavaProtocolVersion())) { if (!ProtocolVersion.isSupported(GameProtocol.getJavaProtocolVersion())) {
logger.error(" / \\"); geyserLogger.error(" / \\");
logger.error(" / \\"); geyserLogger.error(" / \\");
logger.error(" / | \\"); geyserLogger.error(" / | \\");
logger.error(" / | \\ " + GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_proxy", proxyServer.getVersion().getName())); geyserLogger.error(" / | \\ " + GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_proxy", proxyServer.getVersion().getName()));
logger.error(" / \\ " + GeyserLocale.getLocaleStringLog("geyser.may_not_work_as_intended_all_caps")); geyserLogger.error(" / \\ " + GeyserLocale.getLocaleStringLog("geyser.may_not_work_as_intended_all_caps"));
logger.error(" / o \\"); geyserLogger.error(" / o \\");
logger.error("/_____________\\"); geyserLogger.error("/_____________\\");
} }
if (!loadConfig()) { if (!loadConfig()) {
return; return;
} }
this.geyserLogger = new GeyserVelocityLogger(logger, geyserConfig.isDebugMode()); this.geyserLogger.setDebug(geyserConfig.isDebugMode());
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger); GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
this.geyser = GeyserImpl.load(PlatformType.VELOCITY, this); this.geyser = GeyserImpl.load(PlatformType.VELOCITY, this);
@ -249,7 +249,7 @@ public class GeyserVelocityPlugin implements GeyserBootstrap {
"config.yml", (x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()), this); "config.yml", (x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()), this);
this.geyserConfig = FileUtils.loadConfig(configFile, GeyserVelocityConfiguration.class); this.geyserConfig = FileUtils.loadConfig(configFile, GeyserVelocityConfiguration.class);
} catch (IOException ex) { } catch (IOException ex) {
logger.error(GeyserLocale.getLocaleStringLog("geyser.config.failed"), ex); geyserLogger.error(GeyserLocale.getLocaleStringLog("geyser.config.failed"), ex);
ex.printStackTrace(); ex.printStackTrace();
return false; return false;
} }

Datei anzeigen

@ -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:.*"))
}
}

Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

@ -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";
}
}

Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

@ -0,0 +1,5 @@
name: "${name}-ViaProxy"
version: "${version}"
author: "${author}"
main: "org.geysermc.geyser.platform.viaproxy.GeyserViaProxyPlugin"
min-version: "3.2.1"

Datei anzeigen

@ -4,14 +4,20 @@ plugins {
repositories { repositories {
gradlePluginPortal() 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 { dependencies {
implementation("net.kyori", "indra-common", "3.1.1") // this is OK as long as the same version catalog is used in the main build and build-logic
implementation("com.github.johnrengelman", "shadow", "7.1.3-SNAPSHOT") // see https://github.com/gradle/gradle/issues/15383#issuecomment-779893192
implementation(files(libs.javaClass.superclass.protectionDomain.codeSource.location))
// Within the gradle plugin classpath, there is a version conflict between loom and some other implementation(libs.indra)
// plugin for databind. This fixes it: minimum 2.13.2 is required by loom. implementation(libs.shadow)
implementation("com.fasterxml.jackson.core:jackson-databind:2.14.0") implementation(libs.architectury.plugin)
implementation(libs.architectury.loom)
implementation(libs.minotaur)
} }

Datei anzeigen

@ -0,0 +1,11 @@
@file:Suppress("UnstableApiUsage")
dependencyResolutionManagement {
versionCatalogs {
create("libs") {
from(files("../gradle/libs.versions.toml"))
}
}
}
rootProject.name = "build-logic"

Datei anzeigen

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

Datei anzeigen

@ -24,11 +24,17 @@
*/ */
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import org.gradle.api.DefaultTask
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.api.artifacts.MinimalExternalModuleDependency import org.gradle.api.artifacts.MinimalExternalModuleDependency
import org.gradle.api.artifacts.ProjectDependency import org.gradle.api.artifacts.ProjectDependency
import org.gradle.api.provider.Provider 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 org.gradle.kotlin.dsl.named
import java.io.File
import java.net.URL
fun Project.relocate(pattern: String) { fun Project.relocate(pattern: String) {
tasks.named<ShadowJar>("shadowJar") { tasks.named<ShadowJar>("shadowJar") {
@ -52,22 +58,63 @@ fun Project.platformRelocate(pattern: String, exclusion: String = "") {
val providedDependencies = mutableMapOf<String, MutableSet<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() } providedDependencies.getOrPut(project.name) { mutableSetOf() }
.add("${calcExclusion(pattern, 0b100, excludedOn)}:" + .add("${calcExclusion(pattern, 0b100, excludedOn)}:${calcExclusion(name, 0b10, excludedOn)}")
"${calcExclusion(name, 0b10, excludedOn)}:" +
calcExclusion(version, 0b1, excludedOn))
dependencies.add("compileOnlyApi", "$pattern:$name:$version")
} }
fun Project.provided(dependency: ProjectDependency) = fun Project.provided(dependency: ProjectDependency) =
provided(dependency.group!!, dependency.name, dependency.version!!) provided(dependency.group!!, dependency.name)
fun Project.provided(dependency: MinimalExternalModuleDependency) = 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>) = fun Project.provided(provider: Provider<MinimalExternalModuleDependency>) =
provided(provider.get()) 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 = private fun calcExclusion(section: String, bit: Int, excludedOn: Int): String =
if (excludedOn and bit > 0) section else "" if (excludedOn and bit > 0) section else ""

Datei anzeigen

@ -22,8 +22,8 @@ indra {
tasks { tasks {
processResources { processResources {
// Spigot, BungeeCord, Velocity, Fabric // Spigot, BungeeCord, Velocity, Fabric, ViaProxy, NeoForge
filesMatching(listOf("plugin.yml", "bungee.yml", "velocity-plugin.json", "fabric.mod.json")) { filesMatching(listOf("plugin.yml", "bungee.yml", "velocity-plugin.json", "fabric.mod.json", "viaproxy.yml", "META-INF/neoforge.mods.toml")) {
expand( expand(
"id" to "geyser", "id" to "geyser",
"name" to "Geyser", "name" to "Geyser",

Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

@ -7,3 +7,9 @@ indra {
publishSnapshotsTo("geysermc", "https://repo.opencollab.dev/maven-snapshots") publishSnapshotsTo("geysermc", "https://repo.opencollab.dev/maven-snapshots")
publishReleasesTo("geysermc", "https://repo.opencollab.dev/maven-releases") 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() }
}

Datei anzeigen

@ -7,7 +7,6 @@ plugins {
tasks { tasks {
named<Jar>("jar") { named<Jar>("jar") {
archiveClassifier.set("unshaded")
from(project.rootProject.file("LICENSE")) from(project.rootProject.file("LICENSE"))
} }
val shadowJar = named<ShadowJar>("shadowJar") { val shadowJar = named<ShadowJar>("shadowJar") {

Datei anzeigen

@ -1,9 +1,9 @@
plugins { plugins {
`java-library` `java-library`
// Ensure AP works in eclipse (no effect on other IDEs) // Ensure AP works in eclipse (no effect on other IDEs)
`eclipse` eclipse
id("geyser.build-logic") id("geyser.build-logic")
id("io.freefair.lombok") version "6.3.0" apply false alias(libs.plugins.lombok) apply false
} }
allprojects { allprojects {
@ -12,17 +12,25 @@ allprojects {
description = properties["description"] as String description = properties["description"] as String
} }
java { val basePlatforms = setOf(
toolchain {
languageVersion.set(JavaLanguageVersion.of(17))
}
}
val platforms = setOf(
projects.fabric,
projects.bungeecord, projects.bungeecord,
projects.spigot, projects.spigot,
projects.standalone, 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 projects.velocity
).map { it.dependencyProject } ).map { it.dependencyProject }
@ -34,7 +42,14 @@ subprojects {
} }
when (this) { 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") 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")
}
} }

Datei anzeigen

@ -1,12 +1,15 @@
import net.kyori.blossom.BlossomExtension import net.kyori.blossom.BlossomExtension
plugins { plugins {
id("net.kyori.blossom") alias(libs.plugins.blossom)
id("net.kyori.indra.git")
id("geyser.publish-conventions") id("geyser.publish-conventions")
} }
dependencies { dependencies {
constraints {
implementation(libs.raknet) // Ensure protocol does not override the RakNet version
}
api(projects.common) api(projects.common)
api(projects.api) api(projects.api)
@ -21,7 +24,6 @@ dependencies {
implementation(libs.websocket) implementation(libs.websocket)
api(libs.bundles.protocol) api(libs.bundles.protocol)
implementation(libs.blockstateupdater)
api(libs.mcauthlib) api(libs.mcauthlib)
api(libs.mcprotocollib) { api(libs.mcprotocollib) {
@ -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-x86_64" } }
implementation(libs.netty.transport.native.epoll) { artifact { classifier = "linux-aarch_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.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 // Adventure text serialization
api(libs.bundles.adventure) api(libs.bundles.adventure)
@ -63,11 +67,6 @@ dependencies {
api(libs.events) 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 { tasks.processResources {
// This is solely for backwards compatibility for other programs that used this file before the switch to gradle. // 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 // It used to be generated by the maven Git-Commit-Id-Plugin
@ -98,7 +97,7 @@ configure<BlossomExtension> {
} }
fun Project.buildNumber(): Int = 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 { inner class GitInfo {
val branch: String val branch: String
@ -131,5 +130,18 @@ inner class GitInfo {
} }
} }
// todo remove this when we're not using Jenkins anymore // Manual task to download the bedrock data files from the CloudburstMC/Data repository
fun jenkinsBuildNumber(): String? = System.getenv("BUILD_NUMBER") // 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"
}

Datei anzeigen

@ -29,7 +29,6 @@ import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.steveice10.packetlib.tcp.TcpSession;
import io.netty.channel.epoll.Epoll; import io.netty.channel.epoll.Epoll;
import io.netty.util.NettyRuntime; import io.netty.util.NettyRuntime;
import io.netty.util.concurrent.DefaultThreadFactory; import io.netty.util.concurrent.DefaultThreadFactory;
@ -56,11 +55,7 @@ import org.geysermc.geyser.api.GeyserApi;
import org.geysermc.geyser.api.command.CommandSource; import org.geysermc.geyser.api.command.CommandSource;
import org.geysermc.geyser.api.event.EventBus; import org.geysermc.geyser.api.event.EventBus;
import org.geysermc.geyser.api.event.EventRegistrar; import org.geysermc.geyser.api.event.EventRegistrar;
import org.geysermc.geyser.api.event.lifecycle.GeyserPostInitializeEvent; import org.geysermc.geyser.api.event.lifecycle.*;
import org.geysermc.geyser.api.event.lifecycle.GeyserPostReloadEvent;
import org.geysermc.geyser.api.event.lifecycle.GeyserPreInitializeEvent;
import org.geysermc.geyser.api.event.lifecycle.GeyserPreReloadEvent;
import org.geysermc.geyser.api.event.lifecycle.GeyserShutdownEvent;
import org.geysermc.geyser.api.network.AuthType; import org.geysermc.geyser.api.network.AuthType;
import org.geysermc.geyser.api.network.BedrockListener; import org.geysermc.geyser.api.network.BedrockListener;
import org.geysermc.geyser.api.network.RemoteServer; import org.geysermc.geyser.api.network.RemoteServer;
@ -84,19 +79,15 @@ import org.geysermc.geyser.scoreboard.ScoreboardUpdater;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.session.PendingMicrosoftAuthentication; import org.geysermc.geyser.session.PendingMicrosoftAuthentication;
import org.geysermc.geyser.session.SessionManager; import org.geysermc.geyser.session.SessionManager;
import org.geysermc.geyser.session.cache.RegistryCache;
import org.geysermc.geyser.skin.FloodgateSkinUploader; import org.geysermc.geyser.skin.FloodgateSkinUploader;
import org.geysermc.geyser.skin.ProvidedSkins; import org.geysermc.geyser.skin.ProvidedSkins;
import org.geysermc.geyser.skin.SkinProvider; import org.geysermc.geyser.skin.SkinProvider;
import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.text.GeyserLocale;
import org.geysermc.geyser.text.MinecraftLocale; import org.geysermc.geyser.text.MinecraftLocale;
import org.geysermc.geyser.translator.text.MessageTranslator; import org.geysermc.geyser.translator.text.MessageTranslator;
import org.geysermc.geyser.util.AssetUtils; import org.geysermc.geyser.util.*;
import org.geysermc.geyser.util.CooldownUtils; import org.geysermc.mcprotocollib.network.tcp.TcpSession;
import org.geysermc.geyser.util.DimensionUtils;
import org.geysermc.geyser.util.Metrics;
import org.geysermc.geyser.util.NewsHandler;
import org.geysermc.geyser.util.VersionCheckUtils;
import org.geysermc.geyser.util.WebUtils;
import java.io.File; import java.io.File;
import java.io.FileWriter; import java.io.FileWriter;
@ -107,14 +98,7 @@ import java.net.UnknownHostException;
import java.nio.file.Path; import java.nio.file.Path;
import java.security.Key; import java.security.Key;
import java.text.DecimalFormat; import java.text.DecimalFormat;
import java.util.ArrayList; import java.util.*;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
@ -187,6 +171,12 @@ public class GeyserImpl implements GeyserApi {
*/ */
private volatile boolean isReloading; private volatile boolean isReloading;
/**
* Determines if Geyser is currently enabled. This is used to determine if {@link #disable()} should be called during {@link #shutdown()}.
*/
@Setter
private boolean isEnabled;
private GeyserImpl(PlatformType platformType, GeyserBootstrap bootstrap) { private GeyserImpl(PlatformType platformType, GeyserBootstrap bootstrap) {
instance = this; instance = this;
@ -224,6 +214,8 @@ public class GeyserImpl implements GeyserApi {
Registries.init(); Registries.init();
BlockRegistries.init(); BlockRegistries.init();
RegistryCache.init();
/* Initialize translators */ /* Initialize translators */
EntityDefinitions.init(); EntityDefinitions.init();
MessageTranslator.init(); MessageTranslator.init();
@ -233,6 +225,7 @@ public class GeyserImpl implements GeyserApi {
if (ex != null) { if (ex != null) {
return; return;
} }
MinecraftLocale.ensureEN_US(); MinecraftLocale.ensureEN_US();
String locale = GeyserLocale.getDefaultLocale(); String locale = GeyserLocale.getDefaultLocale();
if (!"en_us".equals(locale)) { if (!"en_us".equals(locale)) {
@ -362,6 +355,7 @@ public class GeyserImpl implements GeyserApi {
logger.info("Broadcast port set from system property: " + parsedPort); logger.info("Broadcast port set from system property: " + parsedPort);
} }
if (platformType != PlatformType.VIAPROXY) {
boolean floodgatePresent = bootstrap.testFloodgatePluginPresent(); boolean floodgatePresent = bootstrap.testFloodgatePluginPresent();
if (config.getRemote().authType() == AuthType.FLOODGATE && !floodgatePresent) { if (config.getRemote().authType() == AuthType.FLOODGATE && !floodgatePresent) {
logger.severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.not_installed") + " " logger.severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.not_installed") + " "
@ -373,6 +367,7 @@ public class GeyserImpl implements GeyserApi {
config.getRemote().setAuthType(AuthType.FLOODGATE); config.getRemote().setAuthType(AuthType.FLOODGATE);
} }
} }
}
String remoteAddress = config.getRemote().address(); String remoteAddress = config.getRemote().address();
// Filters whether it is not an IP address or localhost, because otherwise it is not possible to find out an SRV entry. // Filters whether it is not an IP address or localhost, because otherwise it is not possible to find out an SRV entry.
@ -655,14 +650,18 @@ public class GeyserImpl implements GeyserApi {
this.erosionUnixListener.close(); this.erosionUnixListener.close();
} }
// todo check
//Registries.RESOURCE_PACKS.get().clear();
ResourcePackLoader.clear(); ResourcePackLoader.clear();
bootstrap.getGeyserLogger().info(GeyserLocale.getLocaleStringLog("geyser.core.shutdown.done")); this.setEnabled(false);
} }
public void shutdown() { public void shutdown() {
shuttingDown = true; shuttingDown = true;
if (isEnabled) {
this.disable(); this.disable();
}
this.commandManager().getCommands().clear(); this.commandManager().getCommands().clear();
// Disable extensions, fire the shutdown event // Disable extensions, fire the shutdown event
@ -774,6 +773,7 @@ public class GeyserImpl implements GeyserApi {
return 0; return 0;
} }
//noinspection DataFlowIssue
return Integer.parseInt(BUILD_NUMBER); return Integer.parseInt(BUILD_NUMBER);
} }
@ -795,6 +795,7 @@ public class GeyserImpl implements GeyserApi {
} else { } else {
instance.initialize(); instance.initialize();
} }
instance.setEnabled(true);
} }
public GeyserLogger getLogger() { public GeyserLogger getLogger() {

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