mirror of
https://github.com/GeyserMC/Geyser.git
synced 2024-08-14 23:57:35 +00:00
Merge remote-tracking branch 'origin/master' into feature/floodgate-merge
This commit is contained in:
commit
05eb054559
298 changed files with 35381 additions and 44504 deletions
37
.github/workflows/build.yml
vendored
37
.github/workflows/build.yml
vendored
|
@ -19,61 +19,59 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository and submodules
|
- name: Checkout repository and submodules
|
||||||
uses: actions/checkout@v3
|
# See https://github.com/actions/checkout/commits
|
||||||
|
uses: actions/checkout@72f2cec99f417b1a1c5e2e88945068983b7965f9
|
||||||
with:
|
with:
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
|
|
||||||
- name: Validate Gradle Wrapper
|
- name: Validate Gradle Wrapper
|
||||||
uses: gradle/wrapper-validation-action@v1
|
# See https://github.com/gradle/wrapper-validation-action/commits
|
||||||
|
uses: gradle/wrapper-validation-action@56b90f209b02bf6d1deae490e9ef18b21a389cd4
|
||||||
|
|
||||||
- uses: actions/setup-java@v3
|
# See https://github.com/actions/setup-java/commits
|
||||||
|
- uses: actions/setup-java@4075bfc1b51bf22876335ae1cd589602d60d8758
|
||||||
with:
|
with:
|
||||||
java-version: 17
|
java-version: 17
|
||||||
distribution: temurin
|
distribution: temurin
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
uses: gradle/gradle-build-action@v2
|
# See https://github.com/gradle/gradle-build-action/commits
|
||||||
|
uses: gradle/gradle-build-action@3bfe3a46584a206fb8361cdedd0647b0c4204232
|
||||||
with:
|
with:
|
||||||
arguments: build
|
arguments: build
|
||||||
gradle-home-cache-cleanup: true
|
gradle-home-cache-cleanup: true
|
||||||
|
|
||||||
- name: Archive artifacts (Geyser Fabric)
|
- name: Archive artifacts (Geyser Fabric)
|
||||||
uses: actions/upload-artifact@v3
|
# See https://github.com/actions/upload-artifact/commits
|
||||||
|
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32
|
||||||
if: success()
|
if: success()
|
||||||
with:
|
with:
|
||||||
name: Geyser Fabric
|
name: Geyser Fabric
|
||||||
path: bootstrap/fabric/build/libs/Geyser-Fabric.jar
|
path: bootstrap/fabric/build/libs/Geyser-Fabric.jar
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
- name: Archive artifacts (Geyser Standalone)
|
- name: Archive artifacts (Geyser Standalone)
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32
|
||||||
if: success()
|
if: success()
|
||||||
with:
|
with:
|
||||||
name: Geyser Standalone
|
name: Geyser Standalone
|
||||||
path: bootstrap/standalone/build/libs/Geyser-Standalone.jar
|
path: bootstrap/standalone/build/libs/Geyser-Standalone.jar
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
- name: Archive artifacts (Geyser Spigot)
|
- name: Archive artifacts (Geyser Spigot)
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32
|
||||||
if: success()
|
if: success()
|
||||||
with:
|
with:
|
||||||
name: Geyser Spigot
|
name: Geyser Spigot
|
||||||
path: bootstrap/spigot/build/libs/Geyser-Spigot.jar
|
path: bootstrap/spigot/build/libs/Geyser-Spigot.jar
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
- name: Archive artifacts (Geyser BungeeCord)
|
- name: Archive artifacts (Geyser BungeeCord)
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32
|
||||||
if: success()
|
if: success()
|
||||||
with:
|
with:
|
||||||
name: Geyser BungeeCord
|
name: Geyser BungeeCord
|
||||||
path: bootstrap/bungeecord/build/libs/Geyser-BungeeCord.jar
|
path: bootstrap/bungeecord/build/libs/Geyser-BungeeCord.jar
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
- name: Archive artifacts (Geyser Sponge)
|
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
if: success()
|
|
||||||
with:
|
|
||||||
name: Geyser Sponge
|
|
||||||
path: bootstrap/sponge/build/libs/Geyser-Sponge.jar
|
|
||||||
if-no-files-found: error
|
|
||||||
- name: Archive artifacts (Geyser Velocity)
|
- name: Archive artifacts (Geyser Velocity)
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32
|
||||||
if: success()
|
if: success()
|
||||||
with:
|
with:
|
||||||
name: Geyser Velocity
|
name: Geyser Velocity
|
||||||
|
@ -82,7 +80,7 @@ jobs:
|
||||||
|
|
||||||
- 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@v2
|
uses: gradle/gradle-build-action@3bfe3a46584a206fb8361cdedd0647b0c4204232
|
||||||
env:
|
env:
|
||||||
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 }}
|
||||||
|
@ -114,7 +112,7 @@ jobs:
|
||||||
rsync -P -e "ssh -o StrictHostKeyChecking=no -i id_ecdsa" metadata.json $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP:~/uploads/$project/$GITHUB_RUN_NUMBER/
|
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@v2
|
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:
|
||||||
MODRINTH_TOKEN: ${{ secrets.MODRINTH_TOKEN }}
|
MODRINTH_TOKEN: ${{ secrets.MODRINTH_TOKEN }}
|
||||||
|
@ -124,7 +122,8 @@ jobs:
|
||||||
|
|
||||||
- name: Notify Discord
|
- name: Notify Discord
|
||||||
if: ${{ (success() || failure()) && github.repository == 'GeyserMC/Geyser' }}
|
if: ${{ (success() || failure()) && github.repository == 'GeyserMC/Geyser' }}
|
||||||
uses: Tim203/actions-git-discord-webhook@main
|
# See https://github.com/Tim203/actions-git-discord-webhook/commits
|
||||||
|
uses: Tim203/actions-git-discord-webhook@70f38ded3aca51635ec978ab4e1a58cd4cd0c2ff
|
||||||
with:
|
with:
|
||||||
webhook_url: ${{ secrets.DISCORD_WEBHOOK }}
|
webhook_url: ${{ secrets.DISCORD_WEBHOOK }}
|
||||||
status: ${{ job.status }}
|
status: ${{ job.status }}
|
||||||
|
|
36
.github/workflows/pullrequest.yml
vendored
36
.github/workflows/pullrequest.yml
vendored
|
@ -17,13 +17,15 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Set up JDK 17
|
- name: Set up JDK 17
|
||||||
uses: actions/setup-java@v1
|
# See https://github.com/actions/setup-java/commits
|
||||||
|
uses: actions/setup-java@4075bfc1b51bf22876335ae1cd589602d60d8758
|
||||||
with:
|
with:
|
||||||
java-version: 17
|
java-version: 17
|
||||||
distribution: temurin
|
distribution: temurin
|
||||||
|
|
||||||
- name: Check if the author has forked the API repo
|
- name: Check if the author has forked the API repo
|
||||||
uses: Kas-tle/ForkFinder@v1.0.1
|
# See https://github.com/Kas-tle/find-forks-action/commits
|
||||||
|
uses: Kas-tle/find-forks-action@1b5447d1e3c7a8ed79583dd817cc5399686eed3a
|
||||||
id: find_forks
|
id: find_forks
|
||||||
with:
|
with:
|
||||||
owner: GeyserMC
|
owner: GeyserMC
|
||||||
|
@ -31,7 +33,7 @@ jobs:
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Use author's API repo if it exists
|
- name: Use author's API repo if it exists
|
||||||
if: steps.find_forks.outputs.target_branch_found == 'true'
|
if: ${{ steps.find_forks.outputs.target_branch_found == 'true' }}
|
||||||
env:
|
env:
|
||||||
API_FORK_URL: ${{ steps.find_forks.outputs.user_fork_url }}
|
API_FORK_URL: ${{ steps.find_forks.outputs.user_fork_url }}
|
||||||
API_FORK_BRANCH: ${{ github.event.pull_request.head.ref }}
|
API_FORK_BRANCH: ${{ github.event.pull_request.head.ref }}
|
||||||
|
@ -41,54 +43,54 @@ jobs:
|
||||||
./gradlew publishToMavenLocal
|
./gradlew publishToMavenLocal
|
||||||
|
|
||||||
- name: Checkout repository and submodules
|
- name: Checkout repository and submodules
|
||||||
uses: actions/checkout@v3
|
# See https://github.com/actions/checkout/commits
|
||||||
|
uses: actions/checkout@72f2cec99f417b1a1c5e2e88945068983b7965f9
|
||||||
with:
|
with:
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
path: geyser
|
path: geyser
|
||||||
|
|
||||||
|
- name: Validate Gradle Wrapper
|
||||||
|
# See https://github.com/gradle/wrapper-validation-action/commits
|
||||||
|
uses: gradle/wrapper-validation-action@56b90f209b02bf6d1deae490e9ef18b21a389cd4
|
||||||
|
|
||||||
- name: Build Geyser
|
- name: Build Geyser
|
||||||
uses: gradle/gradle-build-action@v2
|
# See https://github.com/gradle/gradle-build-action/commits
|
||||||
|
uses: gradle/gradle-build-action@3bfe3a46584a206fb8361cdedd0647b0c4204232
|
||||||
with:
|
with:
|
||||||
arguments: build
|
arguments: build
|
||||||
build-root-directory: geyser
|
build-root-directory: geyser
|
||||||
|
|
||||||
- name: Archive artifacts (Geyser Fabric)
|
- name: Archive artifacts (Geyser Fabric)
|
||||||
uses: actions/upload-artifact@v3
|
# See https://github.com/actions/upload-artifact/commits
|
||||||
|
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32
|
||||||
if: success()
|
if: success()
|
||||||
with:
|
with:
|
||||||
name: Geyser Fabric
|
name: Geyser Fabric
|
||||||
path: geyser/bootstrap/fabric/build/libs/Geyser-Fabric.jar
|
path: geyser/bootstrap/fabric/build/libs/Geyser-Fabric.jar
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
- name: Archive artifacts (Geyser Standalone)
|
- name: Archive artifacts (Geyser Standalone)
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32
|
||||||
if: success()
|
if: success()
|
||||||
with:
|
with:
|
||||||
name: Geyser Standalone
|
name: Geyser Standalone
|
||||||
path: geyser/bootstrap/standalone/build/libs/Geyser-Standalone.jar
|
path: geyser/bootstrap/standalone/build/libs/Geyser-Standalone.jar
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
- name: Archive artifacts (Geyser Spigot)
|
- name: Archive artifacts (Geyser Spigot)
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32
|
||||||
if: success()
|
if: success()
|
||||||
with:
|
with:
|
||||||
name: Geyser Spigot
|
name: Geyser Spigot
|
||||||
path: geyser/bootstrap/spigot/build/libs/Geyser-Spigot.jar
|
path: geyser/bootstrap/spigot/build/libs/Geyser-Spigot.jar
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
- name: Archive artifacts (Geyser BungeeCord)
|
- name: Archive artifacts (Geyser BungeeCord)
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32
|
||||||
if: success()
|
if: success()
|
||||||
with:
|
with:
|
||||||
name: Geyser BungeeCord
|
name: Geyser BungeeCord
|
||||||
path: geyser/bootstrap/bungeecord/build/libs/Geyser-BungeeCord.jar
|
path: geyser/bootstrap/bungeecord/build/libs/Geyser-BungeeCord.jar
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
- name: Archive artifacts (Geyser Sponge)
|
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
if: success()
|
|
||||||
with:
|
|
||||||
name: Geyser Sponge
|
|
||||||
path: geyser/bootstrap/sponge/build/libs/Geyser-Sponge.jar
|
|
||||||
if-no-files-found: error
|
|
||||||
- name: Archive artifacts (Geyser Velocity)
|
- name: Archive artifacts (Geyser Velocity)
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32
|
||||||
if: success()
|
if: success()
|
||||||
with:
|
with:
|
||||||
name: Geyser Velocity
|
name: Geyser Velocity
|
||||||
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -251,3 +251,4 @@ locales/
|
||||||
/saved-refresh-tokens.json
|
/saved-refresh-tokens.json
|
||||||
/custom_mappings/
|
/custom_mappings/
|
||||||
/languages/
|
/languages/
|
||||||
|
/custom-skulls.yml
|
2
LICENSE
2
LICENSE
|
@ -1,6 +1,6 @@
|
||||||
The MIT License
|
The MIT License
|
||||||
|
|
||||||
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
|
||||||
|
|
|
@ -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.19.40 - 1.19.81 and Minecraft Java 1.19.4.
|
### Currently supporting Minecraft Bedrock 1.20.0 - 1.20.30 and Minecraft Java 1.20/1.20.1.
|
||||||
|
|
||||||
## 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.
|
||||||
|
|
|
@ -35,7 +35,9 @@ import org.geysermc.geyser.api.event.EventRegistrar;
|
||||||
import org.geysermc.geyser.api.extension.ExtensionManager;
|
import org.geysermc.geyser.api.extension.ExtensionManager;
|
||||||
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;
|
||||||
|
import org.geysermc.geyser.api.util.PlatformType;
|
||||||
|
|
||||||
|
import java.nio.file.Path;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@ -107,6 +109,30 @@ public interface GeyserApi extends GeyserApiBase {
|
||||||
@NonNull
|
@NonNull
|
||||||
BedrockListener bedrockListener();
|
BedrockListener bedrockListener();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the {@link Path} to the Geyser config directory.
|
||||||
|
*
|
||||||
|
* @return the path to the Geyser config directory
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
Path configDirectory();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the {@link Path} to the Geyser packs directory.
|
||||||
|
*
|
||||||
|
* @return the path to the Geyser packs directory
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
Path packDirectory();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets {@link PlatformType} the extension is running on
|
||||||
|
*
|
||||||
|
* @return type of platform
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
PlatformType platformType();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the current {@link GeyserApiBase} instance.
|
* Gets the current {@link GeyserApiBase} instance.
|
||||||
*
|
*
|
||||||
|
|
|
@ -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,21 +23,13 @@
|
||||||
* @link https://github.com/GeyserMC/Geyser
|
* @link https://github.com/GeyserMC/Geyser
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
<<<<<<<< HEAD:core/src/main/java/org/geysermc/geyser/util/PlatformType.java
|
||||||
package org.geysermc.geyser.util;
|
package org.geysermc.geyser.util;
|
||||||
|
========
|
||||||
|
package org.geysermc.geyser.api.bedrock.camera;
|
||||||
|
>>>>>>>> origin/master:api/src/main/java/org/geysermc/geyser/api/bedrock/camera/CameraShake.java
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
public enum CameraShake {
|
||||||
import lombok.Getter;
|
POSITIONAL,
|
||||||
|
ROTATIONAL;
|
||||||
@Getter
|
|
||||||
@AllArgsConstructor
|
|
||||||
public enum PlatformType {
|
|
||||||
ANDROID("Android"),
|
|
||||||
BUNGEECORD("BungeeCord"),
|
|
||||||
FABRIC("Fabric"),
|
|
||||||
SPIGOT("Spigot"),
|
|
||||||
SPONGE("Sponge"),
|
|
||||||
STANDALONE("Standalone"),
|
|
||||||
VELOCITY("Velocity");
|
|
||||||
|
|
||||||
private final String platformName;
|
|
||||||
}
|
}
|
|
@ -0,0 +1,143 @@
|
||||||
|
/*
|
||||||
|
* 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.api.block.custom;
|
||||||
|
|
||||||
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
import org.geysermc.geyser.api.GeyserApi;
|
||||||
|
import org.geysermc.geyser.api.block.custom.component.CustomBlockComponents;
|
||||||
|
import org.geysermc.geyser.api.block.custom.property.CustomBlockProperty;
|
||||||
|
import org.geysermc.geyser.api.util.CreativeCategory;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is used to store data for a custom block.
|
||||||
|
*/
|
||||||
|
public interface CustomBlockData {
|
||||||
|
/**
|
||||||
|
* Gets the name of the custom block
|
||||||
|
*
|
||||||
|
* @return The name of the custom block.
|
||||||
|
*/
|
||||||
|
@NonNull String name();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the identifier of the custom block
|
||||||
|
*
|
||||||
|
* @return The identifier of the custom block.
|
||||||
|
*/
|
||||||
|
@NonNull String identifier();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets if the custom block is included in the creative inventory
|
||||||
|
*
|
||||||
|
* @return If the custom block is included in the creative inventory.
|
||||||
|
*/
|
||||||
|
boolean includedInCreativeInventory();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the item's creative category, or tab id.
|
||||||
|
*
|
||||||
|
* @return the item's creative category
|
||||||
|
*/
|
||||||
|
@Nullable CreativeCategory creativeCategory();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the item's creative group.
|
||||||
|
*
|
||||||
|
* @return the item's creative group
|
||||||
|
*/
|
||||||
|
@Nullable String creativeGroup();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the components of the custom block
|
||||||
|
*
|
||||||
|
* @return The components of the custom block.
|
||||||
|
*/
|
||||||
|
@Nullable CustomBlockComponents components();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the custom block's map of block property names to CustomBlockProperty
|
||||||
|
* objects
|
||||||
|
*
|
||||||
|
* @return The custom block's map of block property names to CustomBlockProperty objects.
|
||||||
|
*/
|
||||||
|
@NonNull Map<String, CustomBlockProperty<?>> properties();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the list of the custom block's permutations
|
||||||
|
*
|
||||||
|
* @return The permutations of the custom block.
|
||||||
|
*/
|
||||||
|
@NonNull List<CustomBlockPermutation> permutations();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the custom block's default block state
|
||||||
|
*
|
||||||
|
* @return The default block state of the custom block.
|
||||||
|
*/
|
||||||
|
@NonNull CustomBlockState defaultBlockState();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a builder for a custom block state
|
||||||
|
*
|
||||||
|
* @return The builder for a custom block state.
|
||||||
|
*/
|
||||||
|
CustomBlockState.@NonNull Builder blockStateBuilder();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a Builder for CustomBlockData
|
||||||
|
*
|
||||||
|
* @return A CustomBlockData Builder
|
||||||
|
*/
|
||||||
|
static CustomBlockData.Builder builder() {
|
||||||
|
return GeyserApi.api().provider(CustomBlockData.Builder.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Builder {
|
||||||
|
Builder name(@NonNull String name);
|
||||||
|
|
||||||
|
Builder includedInCreativeInventory(boolean includedInCreativeInventory);
|
||||||
|
|
||||||
|
Builder creativeCategory(@Nullable CreativeCategory creativeCategory);
|
||||||
|
|
||||||
|
Builder creativeGroup(@Nullable String creativeGroup);
|
||||||
|
|
||||||
|
Builder components(@NonNull CustomBlockComponents components);
|
||||||
|
|
||||||
|
Builder booleanProperty(@NonNull String propertyName);
|
||||||
|
|
||||||
|
Builder intProperty(@NonNull String propertyName, List<Integer> values);
|
||||||
|
|
||||||
|
Builder stringProperty(@NonNull String propertyName, List<String> values);
|
||||||
|
|
||||||
|
Builder permutations(@NonNull List<CustomBlockPermutation> permutations);
|
||||||
|
|
||||||
|
CustomBlockData build();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
/*
|
||||||
|
* 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.api.block.custom;
|
||||||
|
|
||||||
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
import org.geysermc.geyser.api.block.custom.component.CustomBlockComponents;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is used to store a custom block permutations, which contain custom
|
||||||
|
* block components mapped to a Molang query that should return true or false
|
||||||
|
*
|
||||||
|
* @param components The components of the block
|
||||||
|
* @param condition The Molang query that should return true or false
|
||||||
|
*/
|
||||||
|
public record CustomBlockPermutation(@NonNull CustomBlockComponents components, @NonNull String condition) {
|
||||||
|
}
|
|
@ -0,0 +1,75 @@
|
||||||
|
/*
|
||||||
|
* 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.api.block.custom;
|
||||||
|
|
||||||
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is used to store a custom block state, which contains CustomBlockData
|
||||||
|
* tied to defined properties and values
|
||||||
|
*/
|
||||||
|
public interface CustomBlockState {
|
||||||
|
/**
|
||||||
|
* Gets the custom block data associated with the state
|
||||||
|
*
|
||||||
|
* @return The custom block data for the state.
|
||||||
|
*/
|
||||||
|
@NonNull CustomBlockData block();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the name of the state
|
||||||
|
*
|
||||||
|
* @return The name of the state.
|
||||||
|
*/
|
||||||
|
@NonNull String name();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the given property for the state
|
||||||
|
*
|
||||||
|
* @param propertyName the property name
|
||||||
|
* @return the boolean, int, or string property.
|
||||||
|
*/
|
||||||
|
@NonNull <T> T property(@NonNull String propertyName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a map of the properties for the state
|
||||||
|
*
|
||||||
|
* @return The properties for the state.
|
||||||
|
*/
|
||||||
|
@NonNull Map<String, Object> properties();
|
||||||
|
|
||||||
|
interface Builder {
|
||||||
|
Builder booleanProperty(@NonNull String propertyName, boolean value);
|
||||||
|
|
||||||
|
Builder intProperty(@NonNull String propertyName, int value);
|
||||||
|
|
||||||
|
Builder stringProperty(@NonNull String propertyName, @NonNull String value);
|
||||||
|
|
||||||
|
CustomBlockState build();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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.api.block.custom;
|
||||||
|
|
||||||
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
import org.geysermc.geyser.api.GeyserApi;
|
||||||
|
import org.geysermc.geyser.api.block.custom.component.CustomBlockComponents;
|
||||||
|
import org.geysermc.geyser.api.util.CreativeCategory;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a completely custom block that is not based on an existing vanilla Minecraft block.
|
||||||
|
*/
|
||||||
|
public interface NonVanillaCustomBlockData extends CustomBlockData {
|
||||||
|
/**
|
||||||
|
* Gets the namespace of the custom block
|
||||||
|
*
|
||||||
|
* @return The namespace of the custom block.
|
||||||
|
*/
|
||||||
|
@NonNull String namespace();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a Builder for NonVanillaCustomBlockData
|
||||||
|
*
|
||||||
|
* @return A NonVanillaCustomBlockData Builder
|
||||||
|
*/
|
||||||
|
static NonVanillaCustomBlockData.Builder builder() {
|
||||||
|
return GeyserApi.api().provider(NonVanillaCustomBlockData.Builder.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Builder extends CustomBlockData.Builder {
|
||||||
|
|
||||||
|
Builder namespace(@NonNull String namespace);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
Builder name(@NonNull String name);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
Builder includedInCreativeInventory(boolean includedInCreativeInventory);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
Builder creativeCategory(@Nullable CreativeCategory creativeCategory);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
Builder creativeGroup(@Nullable String creativeGroup);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
Builder components(@NonNull CustomBlockComponents components);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
Builder booleanProperty(@NonNull String propertyName);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
Builder intProperty(@NonNull String propertyName, List<Integer> values);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
Builder stringProperty(@NonNull String propertyName, List<String> values);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
Builder permutations(@NonNull List<CustomBlockPermutation> permutations);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
NonVanillaCustomBlockData build();
|
||||||
|
}
|
||||||
|
}
|
|
@ -23,39 +23,47 @@
|
||||||
* @link https://github.com/GeyserMC/Geyser
|
* @link https://github.com/GeyserMC/Geyser
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.geysermc.geyser.platform.sponge.command;
|
package org.geysermc.geyser.api.block.custom.component;
|
||||||
|
|
||||||
import net.kyori.adventure.text.Component;
|
/**
|
||||||
import org.geysermc.geyser.GeyserImpl;
|
* This class is used to store a box component for the selection and
|
||||||
import org.geysermc.geyser.command.GeyserCommandManager;
|
* collision boxes of a custom block.
|
||||||
import org.geysermc.geyser.translator.text.MessageTranslator;
|
*
|
||||||
import org.spongepowered.api.Sponge;
|
* @param originX The origin X of the box
|
||||||
import org.spongepowered.api.command.CommandCause;
|
* @param originY The origin Y of the box
|
||||||
import org.spongepowered.api.command.manager.CommandMapping;
|
* @param originZ The origin Z of the box
|
||||||
|
* @param sizeX The size X of the box
|
||||||
|
* @param sizeY The size Y of the box
|
||||||
|
* @param sizeZ The size Z of the box
|
||||||
|
*/
|
||||||
|
public record BoxComponent(float originX, float originY, float originZ, float sizeX, float sizeY, float sizeZ) {
|
||||||
|
private static final BoxComponent FULL_BOX = new BoxComponent(-8, 0, -8, 16, 16, 16);
|
||||||
|
private static final BoxComponent EMPTY_BOX = new BoxComponent(0, 0, 0, 0, 0, 0);
|
||||||
|
|
||||||
import java.util.Optional;
|
/**
|
||||||
|
* Gets a full box component
|
||||||
public class GeyserSpongeCommandManager extends GeyserCommandManager {
|
*
|
||||||
|
* @return A full box component
|
||||||
public GeyserSpongeCommandManager(GeyserImpl geyser) {
|
*/
|
||||||
super(geyser);
|
public static BoxComponent fullBox() {
|
||||||
|
return FULL_BOX;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public String description(String command) {
|
* Gets an empty box component
|
||||||
if (!Sponge.isServerAvailable()) {
|
*
|
||||||
return "";
|
* @return An empty box component
|
||||||
|
*/
|
||||||
|
public static BoxComponent emptyBox() {
|
||||||
|
return EMPTY_BOX;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: The command manager may be replaced at any point during the game lifecycle
|
/**
|
||||||
return Sponge.server().commandManager().commandMapping(command)
|
* Gets if the box component is empty
|
||||||
.map(this::description)
|
*
|
||||||
.map(Optional::get)
|
* @return If the box component is empty.
|
||||||
.map(MessageTranslator::convertMessage)
|
*/
|
||||||
.orElse("");
|
public boolean isEmpty() {
|
||||||
}
|
return sizeX == 0 && sizeY == 0 && sizeZ == 0;
|
||||||
|
|
||||||
public Optional<Component> description(CommandMapping mapping) {
|
|
||||||
return mapping.registrar().shortDescription(CommandCause.create(), mapping);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,192 @@
|
||||||
|
/*
|
||||||
|
* 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.api.block.custom.component;
|
||||||
|
|
||||||
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
import org.geysermc.geyser.api.GeyserApi;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is used to store components for a custom block or custom block permutation.
|
||||||
|
*/
|
||||||
|
public interface CustomBlockComponents {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the selection box component
|
||||||
|
* Equivalent to "minecraft:selection_box"
|
||||||
|
*
|
||||||
|
* @return The selection box.
|
||||||
|
*/
|
||||||
|
@Nullable BoxComponent selectionBox();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the collision box component
|
||||||
|
* Equivalent to "minecraft:collision_box"
|
||||||
|
* @return The collision box.
|
||||||
|
*/
|
||||||
|
@Nullable BoxComponent collisionBox();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the display name component
|
||||||
|
* Equivalent to "minecraft:display_name"
|
||||||
|
*
|
||||||
|
* @return The display name.
|
||||||
|
*/
|
||||||
|
@Nullable String displayName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the geometry component
|
||||||
|
* Equivalent to "minecraft:geometry"
|
||||||
|
*
|
||||||
|
* @return The geometry.
|
||||||
|
*/
|
||||||
|
@Nullable GeometryComponent geometry();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the material instances component
|
||||||
|
* Equivalent to "minecraft:material_instances"
|
||||||
|
*
|
||||||
|
* @return The material instances.
|
||||||
|
*/
|
||||||
|
@NonNull Map<String, MaterialInstance> materialInstances();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the placement filter component
|
||||||
|
* Equivalent to "minecraft:placement_filter"
|
||||||
|
*
|
||||||
|
* @return The placement filter.
|
||||||
|
*/
|
||||||
|
@Nullable List<PlacementConditions> placementFilter();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the destructible by mining component
|
||||||
|
* Equivalent to "minecraft:destructible_by_mining"
|
||||||
|
*
|
||||||
|
* @return The destructible by mining value.
|
||||||
|
*/
|
||||||
|
@Nullable Float destructibleByMining();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the friction component
|
||||||
|
* Equivalent to "minecraft:friction"
|
||||||
|
*
|
||||||
|
* @return The friction value.
|
||||||
|
*/
|
||||||
|
@Nullable Float friction();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the light emission component
|
||||||
|
* Equivalent to "minecraft:light_emission"
|
||||||
|
*
|
||||||
|
* @return The light emission value.
|
||||||
|
*/
|
||||||
|
@Nullable Integer lightEmission();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the light dampening component
|
||||||
|
* Equivalent to "minecraft:light_dampening"
|
||||||
|
*
|
||||||
|
* @return The light dampening value.
|
||||||
|
*/
|
||||||
|
@Nullable Integer lightDampening();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the transformation component
|
||||||
|
* Equivalent to "minecraft:transformation"
|
||||||
|
*
|
||||||
|
* @return The transformation.
|
||||||
|
*/
|
||||||
|
@Nullable TransformationComponent transformation();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the unit cube component
|
||||||
|
* Equivalent to "minecraft:unit_cube"
|
||||||
|
*
|
||||||
|
* @return The rotation.
|
||||||
|
*/
|
||||||
|
boolean unitCube();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets if the block should place only air
|
||||||
|
* Equivalent to setting a dummy event to run on "minecraft:on_player_placing"
|
||||||
|
*
|
||||||
|
* @return If the block should place only air.
|
||||||
|
*/
|
||||||
|
boolean placeAir();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the set of tags
|
||||||
|
* Equivalent to "tag:some_tag"
|
||||||
|
*
|
||||||
|
* @return The set of tags.
|
||||||
|
*/
|
||||||
|
@NonNull Set<String> tags();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a Builder for CustomBlockComponents
|
||||||
|
*
|
||||||
|
* @return A CustomBlockComponents Builder
|
||||||
|
*/
|
||||||
|
static CustomBlockComponents.Builder builder() {
|
||||||
|
return GeyserApi.api().provider(CustomBlockComponents.Builder.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Builder {
|
||||||
|
Builder selectionBox(BoxComponent selectionBox);
|
||||||
|
|
||||||
|
Builder collisionBox(BoxComponent collisionBox);
|
||||||
|
|
||||||
|
Builder displayName(String displayName);
|
||||||
|
|
||||||
|
Builder geometry(GeometryComponent geometry);
|
||||||
|
|
||||||
|
Builder materialInstance(@NonNull String name, @NonNull MaterialInstance materialInstance);
|
||||||
|
|
||||||
|
Builder placementFilter(List<PlacementConditions> placementConditions);
|
||||||
|
|
||||||
|
Builder destructibleByMining(Float destructibleByMining);
|
||||||
|
|
||||||
|
Builder friction(Float friction);
|
||||||
|
|
||||||
|
Builder lightEmission(Integer lightEmission);
|
||||||
|
|
||||||
|
Builder lightDampening(Integer lightDampening);
|
||||||
|
|
||||||
|
Builder transformation(TransformationComponent transformation);
|
||||||
|
|
||||||
|
Builder unitCube(boolean unitCube);
|
||||||
|
|
||||||
|
Builder placeAir(boolean placeAir);
|
||||||
|
|
||||||
|
Builder tags(Set<String> tags);
|
||||||
|
|
||||||
|
CustomBlockComponents build();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,69 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2023 GeyserMC. http://geysermc.org
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* @author GeyserMC
|
||||||
|
* @link https://github.com/GeyserMC/Geyser
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.geysermc.geyser.api.block.custom.component;
|
||||||
|
|
||||||
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
import org.geysermc.geyser.api.GeyserApi;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is used to store data for a geometry component.
|
||||||
|
*/
|
||||||
|
public interface GeometryComponent {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the identifier of the geometry
|
||||||
|
*
|
||||||
|
* @return The identifier of the geometry.
|
||||||
|
*/
|
||||||
|
@NonNull String identifier();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the bone visibility of the geometry
|
||||||
|
*
|
||||||
|
* @return The bone visibility of the geometry.
|
||||||
|
*/
|
||||||
|
@Nullable Map<String, String> boneVisibility();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a builder for GeometryComponent
|
||||||
|
*
|
||||||
|
* @return a builder for GeometryComponent.
|
||||||
|
*/
|
||||||
|
static GeometryComponent.Builder builder() {
|
||||||
|
return GeyserApi.api().provider(GeometryComponent.Builder.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Builder {
|
||||||
|
Builder identifier(@NonNull String identifier);
|
||||||
|
|
||||||
|
Builder boneVisibility(@Nullable Map<String, String> boneVisibility);
|
||||||
|
|
||||||
|
GeometryComponent build();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,83 @@
|
||||||
|
/*
|
||||||
|
* 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.api.block.custom.component;
|
||||||
|
|
||||||
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
import org.geysermc.geyser.api.GeyserApi;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is used to store data for a material instance.
|
||||||
|
*/
|
||||||
|
public interface MaterialInstance {
|
||||||
|
/**
|
||||||
|
* Gets the texture of the block
|
||||||
|
*
|
||||||
|
* @return The texture of the block.
|
||||||
|
*/
|
||||||
|
@Nullable String texture();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the render method of the block
|
||||||
|
*
|
||||||
|
* @return The render method of the block.
|
||||||
|
*/
|
||||||
|
@Nullable String renderMethod();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets if the block should be dimmed on certain faces
|
||||||
|
*
|
||||||
|
* @return If the block should be dimmed on certain faces.
|
||||||
|
*/
|
||||||
|
boolean faceDimming();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets if the block should have ambient occlusion
|
||||||
|
*
|
||||||
|
* @return If the block should have ambient occlusion.
|
||||||
|
*/
|
||||||
|
boolean ambientOcclusion();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a builder for MaterialInstance.
|
||||||
|
*
|
||||||
|
* @return a builder for MaterialInstance
|
||||||
|
*/
|
||||||
|
static MaterialInstance.Builder builder() {
|
||||||
|
return GeyserApi.api().provider(MaterialInstance.Builder.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Builder {
|
||||||
|
Builder texture(@Nullable String texture);
|
||||||
|
|
||||||
|
Builder renderMethod(@Nullable String renderMethod);
|
||||||
|
|
||||||
|
Builder faceDimming(boolean faceDimming);
|
||||||
|
|
||||||
|
Builder ambientOcclusion(boolean ambientOcclusion);
|
||||||
|
|
||||||
|
MaterialInstance build();
|
||||||
|
}
|
||||||
|
}
|
|
@ -21,39 +21,33 @@
|
||||||
*
|
*
|
||||||
* @author GeyserMC
|
* @author GeyserMC
|
||||||
* @link https://github.com/GeyserMC/Geyser
|
* @link https://github.com/GeyserMC/Geyser
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.geysermc.geyser.platform.sponge.command;
|
package org.geysermc.geyser.api.block.custom.component;
|
||||||
|
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
|
||||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
import org.geysermc.geyser.command.GeyserCommandSource;
|
|
||||||
import org.spongepowered.api.command.CommandCause;
|
|
||||||
import org.spongepowered.api.entity.living.player.server.ServerPlayer;
|
|
||||||
|
|
||||||
@AllArgsConstructor
|
/**
|
||||||
public class SpongeCommandSource implements GeyserCommandSource {
|
* This class is used to store conditions for a placement filter for a custom block.
|
||||||
|
*
|
||||||
private final CommandCause handle;
|
* @param allowedFaces The faces that the block can be placed on
|
||||||
|
* @param blockFilters The block filters that control what blocks the block can be placed on
|
||||||
@Override
|
*/
|
||||||
public String name() {
|
public record PlacementConditions(@NonNull Set<Face> allowedFaces, @NonNull LinkedHashMap<String, BlockFilterType> blockFilters) {
|
||||||
return handle.friendlyIdentifier().orElse(handle.identifier());
|
public enum Face {
|
||||||
|
DOWN,
|
||||||
|
UP,
|
||||||
|
NORTH,
|
||||||
|
SOUTH,
|
||||||
|
WEST,
|
||||||
|
EAST;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public enum BlockFilterType {
|
||||||
public void sendMessage(@NonNull String message) {
|
BLOCK,
|
||||||
handle.audience().sendMessage(LegacyComponentSerializer.legacySection().deserialize(message));
|
TAG
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isConsole() {
|
|
||||||
return !(handle.cause().root() instanceof ServerPlayer);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean hasPermission(String permission) {
|
|
||||||
return handle.hasPermission(permission);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,67 @@
|
||||||
|
/*
|
||||||
|
* 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.api.block.custom.component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is used to store the transformation component of a block
|
||||||
|
*
|
||||||
|
* @param rx The rotation on the x axis
|
||||||
|
* @param ry The rotation on the y axis
|
||||||
|
* @param rz The rotation on the z axis
|
||||||
|
* @param sx The scale on the x axis
|
||||||
|
* @param sy The scale on the y axis
|
||||||
|
* @param sz The scale on the z axis
|
||||||
|
* @param tx The translation on the x axis
|
||||||
|
* @param ty The translation on the y axis
|
||||||
|
* @param tz The translation on the z axis
|
||||||
|
*/
|
||||||
|
public record TransformationComponent(int rx, int ry, int rz, float sx, float sy, float sz, float tx, float ty, float tz) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new TransformationComponent with the rotation values and assumes default scale and translation
|
||||||
|
*
|
||||||
|
* @param rx The rotation on the x axis
|
||||||
|
* @param ry The rotation on the y axis
|
||||||
|
* @param rz The rotation on the z axis
|
||||||
|
*/
|
||||||
|
public TransformationComponent(int rx, int ry, int rz) {
|
||||||
|
this(rx, ry, rz, 1, 1, 1, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new TransformationComponent with the rotation and scale values and assumes default translation
|
||||||
|
*
|
||||||
|
* @param rx The rotation on the x axis
|
||||||
|
* @param ry The rotation on the y axis
|
||||||
|
* @param rz The rotation on the z axis
|
||||||
|
* @param sx The scale on the x axis
|
||||||
|
* @param sy The scale on the y axis
|
||||||
|
* @param sz The scale on the z axis
|
||||||
|
*/
|
||||||
|
public TransformationComponent(int rx, int ry, int rz, float sx, float sy, float sz) {
|
||||||
|
this(rx, ry, rz, sx, sy, sz, 0, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
package org.geysermc.geyser.api.block.custom.nonvanilla;
|
||||||
|
|
||||||
|
import org.checkerframework.checker.index.qual.NonNegative;
|
||||||
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
|
||||||
|
public record JavaBlockItem(@NonNull String identifier, @NonNegative int javaId, @NonNegative int stackSize) {
|
||||||
|
}
|
|
@ -0,0 +1,111 @@
|
||||||
|
package org.geysermc.geyser.api.block.custom.nonvanilla;
|
||||||
|
|
||||||
|
import org.checkerframework.checker.index.qual.NonNegative;
|
||||||
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
import org.geysermc.geyser.api.GeyserApi;
|
||||||
|
|
||||||
|
public interface JavaBlockState {
|
||||||
|
/**
|
||||||
|
* Gets the identifier of the block state
|
||||||
|
*
|
||||||
|
* @return the identifier of the block state
|
||||||
|
*/
|
||||||
|
@NonNull String identifier();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the Java ID of the block state
|
||||||
|
*
|
||||||
|
* @return the Java ID of the block state
|
||||||
|
*/
|
||||||
|
@NonNegative int javaId();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the state group ID of the block state
|
||||||
|
*
|
||||||
|
* @return the state group ID of the block state
|
||||||
|
*/
|
||||||
|
@NonNegative int stateGroupId();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the block hardness of the block state
|
||||||
|
*
|
||||||
|
* @return the block hardness of the block state
|
||||||
|
*/
|
||||||
|
@NonNegative float blockHardness();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets whether the block state is waterlogged
|
||||||
|
*
|
||||||
|
* @return whether the block state is waterlogged
|
||||||
|
*/
|
||||||
|
@NonNull boolean waterlogged();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the collision of the block state
|
||||||
|
*
|
||||||
|
* @return the collision of the block state
|
||||||
|
*/
|
||||||
|
@NonNull JavaBoundingBox[] collision();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets whether the block state can be broken with hand
|
||||||
|
*
|
||||||
|
* @return whether the block state can be broken with hand
|
||||||
|
*/
|
||||||
|
@NonNull boolean canBreakWithHand();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the pick item of the block state
|
||||||
|
*
|
||||||
|
* @return the pick item of the block state
|
||||||
|
*/
|
||||||
|
@Nullable String pickItem();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the piston behavior of the block state
|
||||||
|
*
|
||||||
|
* @return the piston behavior of the block state
|
||||||
|
*/
|
||||||
|
@Nullable String pistonBehavior();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets whether the block state has block entity
|
||||||
|
*
|
||||||
|
* @return whether the block state has block entity
|
||||||
|
*/
|
||||||
|
@Nullable boolean hasBlockEntity();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link JavaBlockState.Builder} instance
|
||||||
|
*
|
||||||
|
* @return a new {@link JavaBlockState.Builder} instance
|
||||||
|
*/
|
||||||
|
static JavaBlockState.Builder builder() {
|
||||||
|
return GeyserApi.api().provider(JavaBlockState.Builder.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Builder {
|
||||||
|
Builder identifier(@NonNull String identifier);
|
||||||
|
|
||||||
|
Builder javaId(@NonNegative int javaId);
|
||||||
|
|
||||||
|
Builder stateGroupId(@NonNegative int stateGroupId);
|
||||||
|
|
||||||
|
Builder blockHardness(@NonNegative float blockHardness);
|
||||||
|
|
||||||
|
Builder waterlogged(@NonNull boolean waterlogged);
|
||||||
|
|
||||||
|
Builder collision(@NonNull JavaBoundingBox[] collision);
|
||||||
|
|
||||||
|
Builder canBreakWithHand(@NonNull boolean canBreakWithHand);
|
||||||
|
|
||||||
|
Builder pickItem(@Nullable String pickItem);
|
||||||
|
|
||||||
|
Builder pistonBehavior(@Nullable String pistonBehavior);
|
||||||
|
|
||||||
|
Builder hasBlockEntity(@Nullable boolean hasBlockEntity);
|
||||||
|
|
||||||
|
JavaBlockState build();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
package org.geysermc.geyser.api.block.custom.nonvanilla;
|
||||||
|
|
||||||
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
|
||||||
|
public record JavaBoundingBox(@NonNull double middleX, @NonNull double middleY, @NonNull double middleZ, @NonNull double sizeX, @NonNull double sizeY, @NonNull double sizeZ) {
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
/*
|
||||||
|
* 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.api.block.custom.property;
|
||||||
|
|
||||||
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is used to store a property of a custom block of a generic type.
|
||||||
|
*/
|
||||||
|
public interface CustomBlockProperty<T> {
|
||||||
|
/**
|
||||||
|
* Gets the name of the property
|
||||||
|
*
|
||||||
|
* @return The name of the property.
|
||||||
|
*/
|
||||||
|
@NonNull String name();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the values of the property
|
||||||
|
*
|
||||||
|
* @return The values of the property.
|
||||||
|
*/
|
||||||
|
@NonNull List<T> values();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the type of the property
|
||||||
|
*
|
||||||
|
* @return The type of the property.
|
||||||
|
*/
|
||||||
|
@NonNull PropertyType type();
|
||||||
|
}
|
|
@ -0,0 +1,79 @@
|
||||||
|
/*
|
||||||
|
* 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.api.block.custom.property;
|
||||||
|
|
||||||
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is used to define a custom block property's type.
|
||||||
|
*/
|
||||||
|
public class PropertyType {
|
||||||
|
private static final PropertyType BOOLEAN = new PropertyType(Boolean.class);
|
||||||
|
private static final PropertyType INTEGER = new PropertyType(Integer.class);
|
||||||
|
private static final PropertyType STRING = new PropertyType(String.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the property type for a boolean.
|
||||||
|
*
|
||||||
|
* @return The property type for a boolean.
|
||||||
|
*/
|
||||||
|
@NonNull public static PropertyType booleanProp() {
|
||||||
|
return BOOLEAN;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the property type for an integer.
|
||||||
|
*
|
||||||
|
* @return The property type for an integer.
|
||||||
|
*/
|
||||||
|
@NonNull public static PropertyType integerProp() {
|
||||||
|
return INTEGER;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the property type for a string.
|
||||||
|
*
|
||||||
|
* @return The property type for a string.
|
||||||
|
*/
|
||||||
|
@NonNull public static PropertyType stringProp() {
|
||||||
|
return STRING;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Class<?> typeClass;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the class of the property type
|
||||||
|
*
|
||||||
|
* @return The class of the property type.
|
||||||
|
*/
|
||||||
|
@NonNull public Class<?> typeClass() {
|
||||||
|
return typeClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
private PropertyType(Class<?> typeClass) {
|
||||||
|
this.typeClass = typeClass;
|
||||||
|
}
|
||||||
|
}
|
|
@ -29,10 +29,12 @@ import org.checkerframework.checker.index.qual.NonNegative;
|
||||||
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.api.connection.Connection;
|
import org.geysermc.api.connection.Connection;
|
||||||
|
import org.geysermc.geyser.api.bedrock.camera.CameraShake;
|
||||||
import org.geysermc.geyser.api.command.CommandSource;
|
import org.geysermc.geyser.api.command.CommandSource;
|
||||||
import org.geysermc.geyser.api.entity.type.GeyserEntity;
|
import org.geysermc.geyser.api.entity.type.GeyserEntity;
|
||||||
import org.geysermc.geyser.api.entity.type.player.GeyserPlayerEntity;
|
import org.geysermc.geyser.api.entity.type.player.GeyserPlayerEntity;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -47,9 +49,50 @@ public interface GeyserConnection extends Connection, CommandSource {
|
||||||
CompletableFuture<@Nullable GeyserEntity> entityByJavaId(@NonNegative int javaId);
|
CompletableFuture<@Nullable GeyserEntity> entityByJavaId(@NonNegative int javaId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Displays a player entity as emoting to this client.
|
||||||
*
|
*
|
||||||
* @param emoter the player entity emoting.
|
* @param emoter the player entity emoting.
|
||||||
* @param emoteId the emote ID to send to the client.
|
* @param emoteId the emote ID to send to this client.
|
||||||
*/
|
*/
|
||||||
void showEmote(@NonNull GeyserPlayerEntity emoter, @NonNull String emoteId);
|
void showEmote(@NonNull GeyserPlayerEntity emoter, @NonNull String emoteId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shakes the client's camera.<br><br>
|
||||||
|
* If the camera is already shaking with the same {@link CameraShake} type, then the additional intensity
|
||||||
|
* will be layered on top of the existing intensity, with their own distinct durations.<br>
|
||||||
|
* If the existing shake type is different and the new intensity/duration are not positive, the existing shake only
|
||||||
|
* switches to the new type. Otherwise, the existing shake is completely overridden.
|
||||||
|
*
|
||||||
|
* @param intensity the intensity of the shake. The client has a maximum total intensity of 4.
|
||||||
|
* @param duration the time in seconds that the shake will occur for
|
||||||
|
* @param type the type of shake
|
||||||
|
*/
|
||||||
|
void shakeCamera(float intensity, float duration, @NonNull CameraShake type);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stops all camera shake of any type.
|
||||||
|
*/
|
||||||
|
void stopCameraShake();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the given fog IDs to the fog cache, then sends all fog IDs in the cache to the client.
|
||||||
|
* <p>
|
||||||
|
* Fog IDs can be found <a href="https://wiki.bedrock.dev/documentation/fog-ids.html">here</a>
|
||||||
|
*
|
||||||
|
* @param fogNameSpaces the fog IDs to add. If empty, the existing cached IDs will still be sent.
|
||||||
|
*/
|
||||||
|
void sendFog(String... fogNameSpaces);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the given fog IDs from the fog cache, then sends all fog IDs in the cache to the client.
|
||||||
|
*
|
||||||
|
* @param fogNameSpaces the fog IDs to remove. If empty, all fog IDs will be removed.
|
||||||
|
*/
|
||||||
|
void removeFog(String... fogNameSpaces);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an immutable copy of all fog affects currently applied to this client.
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
Set<String> fogEffects();
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2023 GeyserMC. http://geysermc.org
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* @author GeyserMC
|
||||||
|
* @link https://github.com/GeyserMC/Geyser
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.geysermc.geyser.api.event.bedrock;
|
||||||
|
|
||||||
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
import org.geysermc.geyser.api.connection.GeyserConnection;
|
||||||
|
import org.geysermc.geyser.api.event.connection.ConnectionEvent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when Geyser session connected to a Java remote server and is in a play-ready state.
|
||||||
|
*/
|
||||||
|
public final class SessionJoinEvent extends ConnectionEvent {
|
||||||
|
public SessionJoinEvent(@NonNull GeyserConnection connection) {
|
||||||
|
super(connection);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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.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.pack.ResourcePack;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when Geyser initializes a session for a new Bedrock client and is in the process of sending resource packs.
|
||||||
|
*/
|
||||||
|
public abstract class SessionLoadResourcePacksEvent extends ConnectionEvent {
|
||||||
|
public SessionLoadResourcePacksEvent(@NonNull GeyserConnection connection) {
|
||||||
|
super(connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets an unmodifiable list of {@link ResourcePack}s that will be sent to the client.
|
||||||
|
*
|
||||||
|
* @return an unmodifiable list of resource packs that will be sent to the client.
|
||||||
|
*/
|
||||||
|
public abstract @NonNull List<ResourcePack> resourcePacks();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a {@link ResourcePack} to be sent to the client.
|
||||||
|
*
|
||||||
|
* @param resourcePack a resource pack that will be sent to the client.
|
||||||
|
* @return true if the resource pack was added successfully,
|
||||||
|
* or false if already present
|
||||||
|
*/
|
||||||
|
public abstract boolean register(@NonNull ResourcePack resourcePack);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unregisters a resource pack from being sent to the client.
|
||||||
|
*
|
||||||
|
* @param uuid the UUID of the resource pack
|
||||||
|
* @return true whether the resource pack was removed from the list of resource packs.
|
||||||
|
*/
|
||||||
|
public abstract boolean unregister(@NonNull UUID uuid);
|
||||||
|
}
|
|
@ -0,0 +1,109 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2023 GeyserMC. http://geysermc.org
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* @author GeyserMC
|
||||||
|
* @link https://github.com/GeyserMC/Geyser
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.geysermc.geyser.api.event.bedrock;
|
||||||
|
|
||||||
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
import org.geysermc.event.Cancellable;
|
||||||
|
import org.geysermc.geyser.api.connection.GeyserConnection;
|
||||||
|
import org.geysermc.geyser.api.event.connection.ConnectionEvent;
|
||||||
|
import org.geysermc.geyser.api.network.RemoteServer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when a session has logged in, and is about to connect to a remote java server.
|
||||||
|
* This event is cancellable, and can be used to prevent the player from connecting to the remote server.
|
||||||
|
*/
|
||||||
|
public final class SessionLoginEvent extends ConnectionEvent implements Cancellable {
|
||||||
|
private RemoteServer remoteServer;
|
||||||
|
private boolean cancelled;
|
||||||
|
private String disconnectReason;
|
||||||
|
|
||||||
|
public SessionLoginEvent(@NonNull GeyserConnection connection, @NonNull RemoteServer remoteServer) {
|
||||||
|
super(connection);
|
||||||
|
this.remoteServer = remoteServer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the event is cancelled.
|
||||||
|
*
|
||||||
|
* @return The cancel status of the event.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean isCancelled() {
|
||||||
|
return this.cancelled;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancels the login event, and disconnects the player.
|
||||||
|
* If cancelled, the player disconnects without connecting to the remote server.
|
||||||
|
* This method will use a default disconnect reason. To specify one, use {@link #setCancelled(boolean, String)}.
|
||||||
|
*
|
||||||
|
* @param cancelled If the login event should be cancelled.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void setCancelled(boolean cancelled) {
|
||||||
|
this.cancelled = cancelled;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancels the login event, and disconnects the player with the specified reason.
|
||||||
|
* If cancelled, the player disconnects without connecting to the remote server.
|
||||||
|
*
|
||||||
|
* @param cancelled If the login event should be cancelled.
|
||||||
|
* @param disconnectReason The reason for the cancellation.
|
||||||
|
*/
|
||||||
|
public void setCancelled(boolean cancelled, @NonNull String disconnectReason) {
|
||||||
|
this.cancelled = cancelled;
|
||||||
|
this.disconnectReason = disconnectReason;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the reason for the cancellation, or null if there is no reason given.
|
||||||
|
*
|
||||||
|
* @return The reason for the cancellation.
|
||||||
|
*/
|
||||||
|
public @Nullable String disconnectReason() {
|
||||||
|
return this.disconnectReason;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the {@link RemoteServer} the section will attempt to connect to.
|
||||||
|
*
|
||||||
|
* @return the {@link RemoteServer} the section will attempt to connect to.
|
||||||
|
*/
|
||||||
|
public @NonNull RemoteServer remoteServer() {
|
||||||
|
return this.remoteServer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the {@link RemoteServer} to connect the session to.
|
||||||
|
*
|
||||||
|
* @param remoteServer Sets the {@link RemoteServer} to connect to.
|
||||||
|
*/
|
||||||
|
public void remoteServer(@NonNull RemoteServer remoteServer) {
|
||||||
|
this.remoteServer = remoteServer;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,110 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2023 GeyserMC. http://geysermc.org
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* @author GeyserMC
|
||||||
|
* @link https://github.com/GeyserMC/Geyser
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.geysermc.geyser.api.event.connection;
|
||||||
|
|
||||||
|
import org.checkerframework.checker.index.qual.NonNegative;
|
||||||
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
import org.geysermc.event.Event;
|
||||||
|
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called whenever Geyser gets pinged
|
||||||
|
*
|
||||||
|
* This event allows you to modify/obtain the MOTD, maximum player count, and current number of players online,
|
||||||
|
* Geyser will reply to the client with what was given.
|
||||||
|
*/
|
||||||
|
public interface GeyserBedrockPingEvent extends Event {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the given string as the primary motd, the given string cannot be null.
|
||||||
|
*
|
||||||
|
* @param primary the string to set as the primary motd
|
||||||
|
*/
|
||||||
|
void primaryMotd(@NonNull String primary);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the given string as the secondary motd, the given string cannot be null.
|
||||||
|
* Note: the secondary motd is only used for the LAN game entry.
|
||||||
|
*
|
||||||
|
* @param secondary the string to set as the secondary motd
|
||||||
|
*/
|
||||||
|
void secondaryMotd(@NonNull String secondary);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets how many players are currently online, the given number cannot be below 0.
|
||||||
|
*
|
||||||
|
* @param count the number to set
|
||||||
|
*/
|
||||||
|
void playerCount(int count);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the maximum number of players that can join this server, the given number cannot be below 1.
|
||||||
|
*
|
||||||
|
* @param max the number to set
|
||||||
|
*/
|
||||||
|
void maxPlayerCount(int max);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the primary motd.
|
||||||
|
*
|
||||||
|
* @return the primary motd string
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
String primaryMotd();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the secondary motd.
|
||||||
|
*
|
||||||
|
* @return the secondary motd string
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
String secondaryMotd();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the current number of players.
|
||||||
|
*
|
||||||
|
* @return number of players online
|
||||||
|
*/
|
||||||
|
@NonNegative
|
||||||
|
int playerCount();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the maximum number of players that can join this server
|
||||||
|
*
|
||||||
|
* @return maximum number of players that can join
|
||||||
|
*/
|
||||||
|
int maxPlayerCount();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the {@link InetSocketAddress} of the client pinging us.
|
||||||
|
*
|
||||||
|
* @return a {@link InetSocketAddress}
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
InetSocketAddress address();
|
||||||
|
}
|
|
@ -0,0 +1,76 @@
|
||||||
|
/*
|
||||||
|
* 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.api.event.lifecycle;
|
||||||
|
|
||||||
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
import org.geysermc.geyser.api.block.custom.CustomBlockData;
|
||||||
|
import org.geysermc.geyser.api.block.custom.CustomBlockState;
|
||||||
|
import org.geysermc.geyser.api.block.custom.nonvanilla.JavaBlockItem;
|
||||||
|
import org.geysermc.geyser.api.block.custom.nonvanilla.JavaBlockState;
|
||||||
|
import org.geysermc.event.Event;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called on Geyser's startup when looking for custom blocks. Custom blocks must be registered through this event.
|
||||||
|
*
|
||||||
|
* This event will not be called if the "add-non-bedrock-items" setting is disabled in the Geyser config.
|
||||||
|
*/
|
||||||
|
public abstract class GeyserDefineCustomBlocksEvent implements Event {
|
||||||
|
/**
|
||||||
|
* Registers the given {@link CustomBlockData} as a custom block
|
||||||
|
*
|
||||||
|
* @param customBlockData the custom block to register
|
||||||
|
*/
|
||||||
|
public abstract void register(@NonNull CustomBlockData customBlockData);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers the given {@link CustomBlockState} as an override for the
|
||||||
|
* given java state identifier
|
||||||
|
* Java state identifiers are listed in
|
||||||
|
* https://raw.githubusercontent.com/GeyserMC/mappings/master/blocks.json
|
||||||
|
*
|
||||||
|
* @param javaIdentifier the java state identifier to override
|
||||||
|
* @param customBlockState the custom block state with which to override java state identifier
|
||||||
|
*/
|
||||||
|
public abstract void registerOverride(@NonNull String javaIdentifier, @NonNull CustomBlockState customBlockState);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers the given {@link CustomBlockData} as an override for the
|
||||||
|
* given java item identifier
|
||||||
|
*
|
||||||
|
* @param javaIdentifier the java item identifier to override
|
||||||
|
* @param customBlockData the custom block data with which to override java item identifier
|
||||||
|
*/
|
||||||
|
public abstract void registerItemOverride(@NonNull String javaIdentifier, @NonNull CustomBlockData customBlockData);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers the given {@link CustomBlockState} as an override for the
|
||||||
|
* given {@link JavaBlockState}
|
||||||
|
*
|
||||||
|
* @param javaBlockState the java block state for the non-vanilla block
|
||||||
|
* @param customBlockState the custom block state with which to override java state identifier
|
||||||
|
*/
|
||||||
|
public abstract void registerOverride(@NonNull JavaBlockState javaBlockState, @NonNull CustomBlockState customBlockState);
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
package org.geysermc.geyser.api.event.lifecycle;
|
||||||
|
|
||||||
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
import org.geysermc.event.Event;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called on Geyser's startup when looking for custom skulls. Custom skulls must be registered through this event.
|
||||||
|
*
|
||||||
|
* This event will not be called if the "add-non-bedrock-items" setting is disabled in the Geyser config.
|
||||||
|
*/
|
||||||
|
public abstract class GeyserDefineCustomSkullsEvent implements Event {
|
||||||
|
/**
|
||||||
|
* The type of texture provided
|
||||||
|
*/
|
||||||
|
public enum SkullTextureType {
|
||||||
|
USERNAME,
|
||||||
|
UUID,
|
||||||
|
PROFILE,
|
||||||
|
SKIN_HASH
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers the given username, UUID, base64 encoded profile, or skin hash as a custom skull blocks
|
||||||
|
* @param texture the username, UUID, base64 encoded profile, or skin hash
|
||||||
|
* @param type the type of texture provided
|
||||||
|
*/
|
||||||
|
public abstract void register(@NonNull String texture, @NonNull SkullTextureType type);
|
||||||
|
}
|
|
@ -136,4 +136,12 @@ public interface Extension extends EventRegistrar {
|
||||||
default GeyserApi geyserApi() {
|
default GeyserApi geyserApi() {
|
||||||
return GeyserApi.api();
|
return GeyserApi.api();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disable the extension.
|
||||||
|
*/
|
||||||
|
default void disable() {
|
||||||
|
this.setEnabled(false);
|
||||||
|
this.eventBus().unregisterAll();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -129,6 +129,34 @@ public interface NonVanillaCustomItemData extends CustomItemData {
|
||||||
*/
|
*/
|
||||||
boolean isHat();
|
boolean isHat();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets if the item is a foil. This is used to determine if the item should be rendered with an enchantment glint effect.
|
||||||
|
*
|
||||||
|
* @return if the item is a foil
|
||||||
|
*/
|
||||||
|
boolean isFoil();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets if the item is edible.
|
||||||
|
*
|
||||||
|
* @return if the item is edible
|
||||||
|
*/
|
||||||
|
boolean isEdible();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets if the food item can always be eaten.
|
||||||
|
*
|
||||||
|
* @return if the item is allowed to be eaten all the time
|
||||||
|
*/
|
||||||
|
boolean canAlwaysEat();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets if the item is chargable, like a bow.
|
||||||
|
*
|
||||||
|
* @return if the item should act like a chargable item
|
||||||
|
*/
|
||||||
|
boolean isChargeable();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated Use {@link #displayHandheld()} instead.
|
* @deprecated Use {@link #displayHandheld()} instead.
|
||||||
* Gets if the item is a tool. This is used to set the render type of the item, if the item is handheld.
|
* Gets if the item is a tool. This is used to set the render type of the item, if the item is handheld.
|
||||||
|
@ -174,6 +202,14 @@ public interface NonVanillaCustomItemData extends CustomItemData {
|
||||||
|
|
||||||
Builder hat(boolean isHat);
|
Builder hat(boolean isHat);
|
||||||
|
|
||||||
|
Builder foil(boolean isFoil);
|
||||||
|
|
||||||
|
Builder edible(boolean isEdible);
|
||||||
|
|
||||||
|
Builder canAlwaysEat(boolean canAlwaysEat);
|
||||||
|
|
||||||
|
Builder chargeable(boolean isChargeable);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated Use {@link #displayHandheld(boolean)} instead.
|
* @deprecated Use {@link #displayHandheld(boolean)} instead.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -67,4 +67,11 @@ public interface RemoteServer {
|
||||||
*/
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
AuthType authType();
|
AuthType authType();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets if we should attempt to resolve the SRV record for this server.
|
||||||
|
*
|
||||||
|
* @return if we should attempt to resolve the SRV record for this server
|
||||||
|
*/
|
||||||
|
boolean resolveSrv();
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,82 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2023 GeyserMC. http://geysermc.org
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* @author GeyserMC
|
||||||
|
* @link https://github.com/GeyserMC/Geyser
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.geysermc.geyser.api.pack;
|
||||||
|
|
||||||
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
import org.geysermc.geyser.api.GeyserApi;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.channels.SeekableByteChannel;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a pack codec that can be used
|
||||||
|
* to provide resource packs to clients.
|
||||||
|
*/
|
||||||
|
public abstract class PackCodec {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the sha256 hash of the resource pack.
|
||||||
|
*
|
||||||
|
* @return the hash of the resource pack
|
||||||
|
*/
|
||||||
|
public abstract byte @NonNull [] sha256();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the resource pack size.
|
||||||
|
*
|
||||||
|
* @return the resource pack file size
|
||||||
|
*/
|
||||||
|
public abstract long size();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serializes the given resource pack into a byte buffer.
|
||||||
|
*
|
||||||
|
* @param resourcePack the resource pack to serialize
|
||||||
|
* @return the serialized resource pack
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
public abstract SeekableByteChannel serialize(@NonNull ResourcePack resourcePack) throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new resource pack from this codec.
|
||||||
|
*
|
||||||
|
* @return the new resource pack
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
protected abstract ResourcePack create();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new pack provider from the given path.
|
||||||
|
*
|
||||||
|
* @param path the path to create the pack provider from
|
||||||
|
* @return the new pack provider
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
public static PackCodec path(@NonNull Path path) {
|
||||||
|
return GeyserApi.api().provider(PathPackCodec.class, path);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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,15 +23,23 @@
|
||||||
* @link https://github.com/GeyserMC/Geyser
|
* @link https://github.com/GeyserMC/Geyser
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.geysermc.geyser.platform.sponge;
|
package org.geysermc.geyser.api.pack;
|
||||||
|
|
||||||
import org.geysermc.geyser.configuration.GeyserJacksonConfiguration;
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
|
||||||
public final class GeyserSpongeConfiguration extends GeyserJacksonConfiguration {
|
/**
|
||||||
@Override
|
* Represents a pack codec that creates a resource
|
||||||
public Path getFloodgateKeyPath() {
|
* pack from a path on the filesystem.
|
||||||
return null; //floodgate isn't available for Sponge
|
*/
|
||||||
}
|
public abstract class PathPackCodec extends PackCodec {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the path of the resource pack.
|
||||||
|
*
|
||||||
|
* @return the path of the resource pack
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
public abstract Path path();
|
||||||
}
|
}
|
|
@ -0,0 +1,72 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2023 GeyserMC. http://geysermc.org
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* @author GeyserMC
|
||||||
|
* @link https://github.com/GeyserMC/Geyser
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.geysermc.geyser.api.pack;
|
||||||
|
|
||||||
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a resource pack sent to Bedrock clients
|
||||||
|
* <p>
|
||||||
|
* This representation of a resource pack only contains what
|
||||||
|
* Geyser requires to send it to the client.
|
||||||
|
*/
|
||||||
|
public interface ResourcePack {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link PackCodec codec} for this pack.
|
||||||
|
*
|
||||||
|
* @return the codec for this pack
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
PackCodec codec();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the resource pack manifest.
|
||||||
|
*
|
||||||
|
* @return the resource pack manifest
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
ResourcePackManifest manifest();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the content key of the resource pack. Lack of a content key is represented by an empty String.
|
||||||
|
*
|
||||||
|
* @return the content key of the resource pack
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
String contentKey();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a resource pack with the given {@link PackCodec}.
|
||||||
|
*
|
||||||
|
* @param codec the pack codec
|
||||||
|
* @return the resource pack
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
static ResourcePack create(@NonNull PackCodec codec) {
|
||||||
|
return codec.create();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,209 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2023 GeyserMC. http://geysermc.org
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* @author GeyserMC
|
||||||
|
* @link https://github.com/GeyserMC/Geyser
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.geysermc.geyser.api.pack;
|
||||||
|
|
||||||
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a resource pack manifest.
|
||||||
|
*/
|
||||||
|
public interface ResourcePackManifest {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the format version of the resource pack.
|
||||||
|
*
|
||||||
|
* @return the format version
|
||||||
|
*/
|
||||||
|
int formatVersion();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the header of the resource pack.
|
||||||
|
*
|
||||||
|
* @return the header
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
Header header();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the modules of the resource pack.
|
||||||
|
*
|
||||||
|
* @return the modules
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
Collection<? extends Module> modules();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the dependencies of the resource pack.
|
||||||
|
*
|
||||||
|
* @return the dependencies
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
Collection<? extends Dependency> dependencies();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the header of a resource pack.
|
||||||
|
*/
|
||||||
|
interface Header {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the UUID of the resource pack.
|
||||||
|
*
|
||||||
|
* @return the UUID
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
UUID uuid();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the version of the resource pack.
|
||||||
|
*
|
||||||
|
* @return the version
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
Version version();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the name of the resource pack.
|
||||||
|
*
|
||||||
|
* @return the name
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
String name();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the description of the resource pack.
|
||||||
|
*
|
||||||
|
* @return the description
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
String description();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the minimum supported Minecraft version of the resource pack.
|
||||||
|
*
|
||||||
|
* @return the minimum supported Minecraft version
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
Version minimumSupportedMinecraftVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a module of a resource pack.
|
||||||
|
*/
|
||||||
|
interface Module {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the UUID of the module.
|
||||||
|
*
|
||||||
|
* @return the UUID
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
UUID uuid();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the version of the module.
|
||||||
|
*
|
||||||
|
* @return the version
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
Version version();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the type of the module.
|
||||||
|
*
|
||||||
|
* @return the type
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
String type();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the description of the module.
|
||||||
|
*
|
||||||
|
* @return the description
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
String description();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a dependency of a resource pack.
|
||||||
|
*/
|
||||||
|
interface Dependency {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the UUID of the dependency.
|
||||||
|
*
|
||||||
|
* @return the uuid
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
UUID uuid();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the version of the dependency.
|
||||||
|
*
|
||||||
|
* @return the version
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
Version version();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a version of a resource pack.
|
||||||
|
*/
|
||||||
|
interface Version {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the major version.
|
||||||
|
*
|
||||||
|
* @return the major version
|
||||||
|
*/
|
||||||
|
int major();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the minor version.
|
||||||
|
*
|
||||||
|
* @return the minor version
|
||||||
|
*/
|
||||||
|
int minor();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the patch version.
|
||||||
|
*
|
||||||
|
* @return the patch version
|
||||||
|
*/
|
||||||
|
int patch();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the version formatted as a String.
|
||||||
|
*
|
||||||
|
* @return the version string
|
||||||
|
*/
|
||||||
|
@NonNull String toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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.api.util;
|
||||||
|
|
||||||
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the creative menu categories or tabs.
|
||||||
|
*/
|
||||||
|
public enum CreativeCategory {
|
||||||
|
COMMANDS("commands", 1),
|
||||||
|
CONSTRUCTION("construction", 2),
|
||||||
|
EQUIPMENT("equipment", 3),
|
||||||
|
ITEMS("items", 4),
|
||||||
|
NATURE("nature", 5),
|
||||||
|
NONE("none", 6);
|
||||||
|
|
||||||
|
private final String internalName;
|
||||||
|
private final int id;
|
||||||
|
|
||||||
|
CreativeCategory(String internalName, int id) {
|
||||||
|
this.internalName = internalName;
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the internal name of the category.
|
||||||
|
*
|
||||||
|
* @return the name of the category
|
||||||
|
*/
|
||||||
|
@NonNull public String internalName() {
|
||||||
|
return internalName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the internal ID of the category.
|
||||||
|
*
|
||||||
|
* @return the ID of the category
|
||||||
|
*/
|
||||||
|
public int id() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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.api.util;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the platform Geyser is running on.
|
||||||
|
*/
|
||||||
|
public record PlatformType(String platformName) {
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
public static final PlatformType ANDROID = new PlatformType("Android");
|
||||||
|
public static final PlatformType BUNGEECORD = new PlatformType("BungeeCord");
|
||||||
|
public static final PlatformType FABRIC = new PlatformType("Fabric");
|
||||||
|
public static final PlatformType SPIGOT = new PlatformType("Spigot");
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
public static final PlatformType SPONGE = new PlatformType("Sponge");
|
||||||
|
public static final PlatformType STANDALONE = new PlatformType("Standalone");
|
||||||
|
public static final PlatformType VELOCITY = new PlatformType("Velocity");
|
||||||
|
}
|
|
@ -10,6 +10,7 @@ platformRelocate("net.md_5.bungee.jni")
|
||||||
platformRelocate("com.fasterxml.jackson")
|
platformRelocate("com.fasterxml.jackson")
|
||||||
platformRelocate("io.netty.channel.kqueue") // This is not used because relocating breaks natives, but we must include it or else we get ClassDefNotFound
|
platformRelocate("io.netty.channel.kqueue") // This is not used because relocating breaks natives, but we must include it or else we get ClassDefNotFound
|
||||||
platformRelocate("net.kyori")
|
platformRelocate("net.kyori")
|
||||||
|
platformRelocate("org.yaml") // Broken as of 1.20
|
||||||
|
|
||||||
// These dependencies are already present on the platform
|
// These dependencies are already present on the platform
|
||||||
provided(libs.bungeecord.proxy)
|
provided(libs.bungeecord.proxy)
|
||||||
|
@ -23,7 +24,6 @@ tasks.withType<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar> {
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
exclude(dependency("com.google.*:.*"))
|
exclude(dependency("com.google.*:.*"))
|
||||||
exclude(dependency("org.yaml:.*"))
|
|
||||||
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:.*"))
|
||||||
|
|
|
@ -34,6 +34,7 @@ import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
import org.geysermc.floodgate.bungee.BungeePlatform;
|
import org.geysermc.floodgate.bungee.BungeePlatform;
|
||||||
import org.geysermc.floodgate.bungee.pluginmessage.BungeeSkinApplier;
|
import org.geysermc.floodgate.bungee.pluginmessage.BungeeSkinApplier;
|
||||||
import org.geysermc.floodgate.core.skin.SkinApplier;
|
import org.geysermc.floodgate.core.skin.SkinApplier;
|
||||||
|
import org.geysermc.geyser.api.util.PlatformType;
|
||||||
import org.geysermc.geyser.GeyserBootstrap;
|
import org.geysermc.geyser.GeyserBootstrap;
|
||||||
import org.geysermc.geyser.GeyserImpl;
|
import org.geysermc.geyser.GeyserImpl;
|
||||||
import org.geysermc.geyser.api.command.Command;
|
import org.geysermc.geyser.api.command.Command;
|
||||||
|
@ -49,7 +50,6 @@ import org.geysermc.geyser.ping.IGeyserPingPassthrough;
|
||||||
import org.geysermc.geyser.platform.bungeecord.command.GeyserBungeeCommandExecutor;
|
import org.geysermc.geyser.platform.bungeecord.command.GeyserBungeeCommandExecutor;
|
||||||
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 org.geysermc.geyser.util.PlatformType;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
@ -117,26 +117,6 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onEnable() {
|
public void onEnable() {
|
||||||
if (getProxy().getConfig().getListeners().size() == 1) {
|
|
||||||
ListenerInfo listener = getProxy().getConfig().getListeners().toArray(new ListenerInfo[0])[0];
|
|
||||||
|
|
||||||
InetSocketAddress javaAddr = listener.getHost();
|
|
||||||
|
|
||||||
// By default this should be localhost but may need to be changed in some circumstances
|
|
||||||
if (this.geyserConfig.getRemote().address().equalsIgnoreCase("auto")) {
|
|
||||||
this.geyserConfig.setAutoconfiguredRemote(true);
|
|
||||||
// Don't use localhost if not listening on all interfaces
|
|
||||||
if (!javaAddr.getHostString().equals("0.0.0.0") && !javaAddr.getHostString().equals("")) {
|
|
||||||
this.geyserConfig.getRemote().setAddress(javaAddr.getHostString());
|
|
||||||
}
|
|
||||||
this.geyserConfig.getRemote().setPort(javaAddr.getPort());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (geyserConfig.getBedrock().isCloneRemotePort()) {
|
|
||||||
geyserConfig.getBedrock().setPort(javaAddr.getPort());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Force-disable query if enabled, or else Geyser won't enable
|
// Force-disable query if enabled, or else Geyser won't enable
|
||||||
for (ListenerInfo info : getProxy().getConfig().getListeners()) {
|
for (ListenerInfo info : getProxy().getConfig().getListeners()) {
|
||||||
if (info.isQueryEnabled() && info.getQueryPort() == geyserConfig.getBedrock().port()) {
|
if (info.isQueryEnabled() && info.getQueryPort() == geyserConfig.getBedrock().port()) {
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import net.fabricmc.loom.task.RemapJarTask
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("fabric-loom") version "1.0-SNAPSHOT"
|
id("fabric-loom") version "1.0-SNAPSHOT"
|
||||||
id("com.modrinth.minotaur") version "2.+"
|
id("com.modrinth.minotaur") version "2.+"
|
||||||
|
@ -33,6 +35,10 @@ dependencies {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
loom {
|
||||||
|
mixin.defaultRefmapName.set("geyser-fabric-refmap.json")
|
||||||
|
}
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenLocal()
|
mavenLocal()
|
||||||
maven("https://repo.opencollab.dev/maven-releases/")
|
maven("https://repo.opencollab.dev/maven-releases/")
|
||||||
|
@ -89,8 +95,16 @@ tasks {
|
||||||
dependsOn(shadowJar)
|
dependsOn(shadowJar)
|
||||||
inputFile.set(shadowJar.get().archiveFile)
|
inputFile.set(shadowJar.get().archiveFile)
|
||||||
archiveBaseName.set("Geyser-Fabric")
|
archiveBaseName.set("Geyser-Fabric")
|
||||||
archiveClassifier.set("")
|
|
||||||
archiveVersion.set("")
|
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("")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,10 +117,11 @@ modrinth {
|
||||||
|
|
||||||
syncBodyFrom.set(rootProject.file("README.md").readText())
|
syncBodyFrom.set(rootProject.file("README.md").readText())
|
||||||
|
|
||||||
uploadFile.set(tasks.getByPath("remapJar"))
|
uploadFile.set(tasks.getByPath("remapModrinthJar"))
|
||||||
gameVersions.addAll("1.19", "1.19.1", "1.19.2", "1.19.3", "1.19.4")
|
gameVersions.addAll("1.20", "1.20.1")
|
||||||
|
|
||||||
loaders.add("fabric")
|
loaders.add("fabric")
|
||||||
|
failSilently.set(true)
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
required.project("fabric-api")
|
required.project("fabric-api")
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
|
|
||||||
package org.geysermc.geyser.platform.fabric;
|
package org.geysermc.geyser.platform.fabric;
|
||||||
|
|
||||||
|
import com.mojang.brigadier.arguments.StringArgumentType;
|
||||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||||
import net.fabricmc.api.EnvType;
|
import net.fabricmc.api.EnvType;
|
||||||
import net.fabricmc.api.ModInitializer;
|
import net.fabricmc.api.ModInitializer;
|
||||||
|
@ -40,6 +41,8 @@ import org.geysermc.geyser.GeyserBootstrap;
|
||||||
import org.geysermc.geyser.GeyserImpl;
|
import org.geysermc.geyser.GeyserImpl;
|
||||||
import org.geysermc.geyser.GeyserLogger;
|
import org.geysermc.geyser.GeyserLogger;
|
||||||
import org.geysermc.geyser.api.command.Command;
|
import org.geysermc.geyser.api.command.Command;
|
||||||
|
import org.geysermc.geyser.api.extension.Extension;
|
||||||
|
import org.geysermc.geyser.api.util.PlatformType;
|
||||||
import org.geysermc.geyser.command.GeyserCommand;
|
import org.geysermc.geyser.command.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;
|
||||||
|
@ -161,9 +164,37 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap {
|
||||||
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
|
||||||
.requires(executor::testPermission));
|
.requires(executor::testPermission)
|
||||||
|
// Allows parsing of arguments; e.g. for /geyser dump logs or the connectiontest command
|
||||||
|
.then(Commands.argument("args", StringArgumentType.greedyString())
|
||||||
|
.executes(context -> executor.runWithArgs(context, StringArgumentType.getString(context, "args")))
|
||||||
|
.requires(executor::testPermission)));
|
||||||
}
|
}
|
||||||
server.getCommands().getDispatcher().register(builder);
|
server.getCommands().getDispatcher().register(builder);
|
||||||
|
|
||||||
|
// Register extension commands
|
||||||
|
for (Map.Entry<Extension, Map<String, Command>> extensionMapEntry : geyser.commandManager().extensionCommands().entrySet()) {
|
||||||
|
Map<String, Command> extensionCommands = extensionMapEntry.getValue();
|
||||||
|
if (extensionCommands.isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register help command for just "/<extensionId>"
|
||||||
|
GeyserFabricCommandExecutor extensionHelpExecutor = new GeyserFabricCommandExecutor(geyser,
|
||||||
|
(GeyserCommand) extensionCommands.get("help"));
|
||||||
|
LiteralArgumentBuilder<CommandSourceStack> extCmdBuilder = Commands.literal(extensionMapEntry.getKey().description().id()).executes(extensionHelpExecutor);
|
||||||
|
|
||||||
|
for (Map.Entry<String, Command> command : extensionCommands.entrySet()) {
|
||||||
|
GeyserFabricCommandExecutor executor = new GeyserFabricCommandExecutor(geyser, (GeyserCommand) command.getValue());
|
||||||
|
extCmdBuilder.then(Commands.literal(command.getKey())
|
||||||
|
.executes(executor)
|
||||||
|
.requires(executor::testPermission)
|
||||||
|
.then(Commands.argument("args", StringArgumentType.greedyString())
|
||||||
|
.executes(context -> executor.runWithArgs(context, StringArgumentType.getString(context, "args")))
|
||||||
|
.requires(executor::testPermission)));
|
||||||
|
}
|
||||||
|
server.getCommands().getDispatcher().register(extCmdBuilder);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -220,7 +251,8 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap {
|
||||||
@NotNull
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
public String getServerBindAddress() {
|
public String getServerBindAddress() {
|
||||||
return this.server.getLocalIp();
|
String ip = this.server.getLocalIp();
|
||||||
|
return ip != null ? ip : ""; // See issue #3812
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -75,6 +75,6 @@ public class FabricCommandSender implements GeyserCommandSource {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasPermission(String permission) {
|
public boolean hasPermission(String permission) {
|
||||||
return Permissions.check(source, permission);
|
return Permissions.check(source, permission, source.getServer().getOperatorUserPermissionLevel());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,6 +53,10 @@ public class GeyserFabricCommandExecutor extends GeyserCommandExecutor implement
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int run(CommandContext context) {
|
public int run(CommandContext context) {
|
||||||
|
return runWithArgs(context, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
public int runWithArgs(CommandContext context, String args) {
|
||||||
CommandSourceStack source = (CommandSourceStack) context.getSource();
|
CommandSourceStack source = (CommandSourceStack) context.getSource();
|
||||||
FabricCommandSender sender = new FabricCommandSender(source);
|
FabricCommandSender sender = new FabricCommandSender(source);
|
||||||
GeyserSession session = getGeyserSession(sender);
|
GeyserSession session = getGeyserSession(sender);
|
||||||
|
@ -68,7 +72,8 @@ public class GeyserFabricCommandExecutor extends GeyserCommandExecutor implement
|
||||||
sender.sendMessage(ChatColor.RED + GeyserLocale.getPlayerLocaleString("geyser.bootstrap.command.bedrock_only", sender.locale()));
|
sender.sendMessage(ChatColor.RED + GeyserLocale.getPlayerLocaleString("geyser.bootstrap.command.bedrock_only", sender.locale()));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
command.execute(session, sender, new String[0]);
|
|
||||||
|
command.execute(session, sender, args.split(" "));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
|
|
||||||
package org.geysermc.geyser.platform.fabric.world;
|
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 com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityInfo;
|
||||||
import me.lucko.fabric.api.permissions.v0.Permissions;
|
import me.lucko.fabric.api.permissions.v0.Permissions;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
|
@ -72,7 +73,7 @@ public class GeyserFabricWorldManager extends GeyserWorldManager {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
LevelChunk chunk = player.getLevel().getChunk(x, z);
|
LevelChunk chunk = player.level().getChunk(x, z);
|
||||||
final int chunkBlockX = x << 4;
|
final int chunkBlockX = x << 4;
|
||||||
final int chunkBlockZ = z << 4;
|
final int chunkBlockZ = z << 4;
|
||||||
for (int i = 0; i < blockEntityInfos.size(); i++) {
|
for (int i = 0; i < blockEntityInfos.size(); i++) {
|
||||||
|
@ -92,7 +93,7 @@ public class GeyserFabricWorldManager extends GeyserWorldManager {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
BlockEntity blockEntity = player.level.getBlockEntity(new BlockPos(x, y, z));
|
BlockEntity blockEntity = player.level().getBlockEntity(new BlockPos(x, y, z));
|
||||||
sendLecternData(session, blockEntity, false);
|
sendLecternData(session, blockEntity, false);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -153,6 +154,11 @@ public class GeyserFabricWorldManager extends GeyserWorldManager {
|
||||||
return Permissions.check(player, permission);
|
return Permissions.check(player, permission);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GameMode getDefaultGameMode(GeyserSession session) {
|
||||||
|
return GameMode.byId(server.getDefaultGameType().getId());
|
||||||
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<com.github.steveice10.opennbt.tag.builtin.CompoundTag> getPickItemNbt(GeyserSession session, int x, int y, int z, boolean addNbtData) {
|
public CompletableFuture<com.github.steveice10.opennbt.tag.builtin.CompoundTag> getPickItemNbt(GeyserSession session, int x, int y, int z, boolean addNbtData) {
|
||||||
|
@ -166,7 +172,7 @@ public class GeyserFabricWorldManager extends GeyserWorldManager {
|
||||||
|
|
||||||
BlockPos pos = new BlockPos(x, y, z);
|
BlockPos pos = new BlockPos(x, y, z);
|
||||||
// Don't create a new block entity if invalid
|
// Don't create a new block entity if invalid
|
||||||
BlockEntity blockEntity = player.level.getChunkAt(pos).getBlockEntity(pos);
|
BlockEntity blockEntity = player.level().getChunkAt(pos).getBlockEntity(pos);
|
||||||
if (blockEntity instanceof BannerBlockEntity banner) {
|
if (blockEntity instanceof BannerBlockEntity banner) {
|
||||||
// Potentially exposes other NBT data? But we need to get the NBT data for the banner patterns *and*
|
// 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
|
// the banner might have a custom name, both of which a Java client knows and caches
|
||||||
|
|
|
@ -23,9 +23,9 @@
|
||||||
"geyser-fabric.mixins.json"
|
"geyser-fabric.mixins.json"
|
||||||
],
|
],
|
||||||
"depends": {
|
"depends": {
|
||||||
"fabricloader": ">=0.14.8",
|
"fabricloader": ">=0.14.21",
|
||||||
"fabric": "*",
|
"fabric": "*",
|
||||||
"minecraft": ">=1.19",
|
"minecraft": ">=1.20",
|
||||||
"fabric-permissions-api-v0": "*"
|
"fabric-permissions-api-v0": "*"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
"required": true,
|
"required": true,
|
||||||
"package": "org.geysermc.geyser.platform.fabric.mixin",
|
"package": "org.geysermc.geyser.platform.fabric.mixin",
|
||||||
"compatibilityLevel": "JAVA_16",
|
"compatibilityLevel": "JAVA_16",
|
||||||
|
"refmap": "geyser-fabric-refmap.json",
|
||||||
"client": [
|
"client": [
|
||||||
"client.IntegratedServerMixin"
|
"client.IntegratedServerMixin"
|
||||||
],
|
],
|
||||||
|
|
|
@ -4,7 +4,9 @@ dependencies {
|
||||||
isTransitive = false
|
isTransitive = false
|
||||||
}
|
}
|
||||||
|
|
||||||
implementation(libs.adapters.spigot)
|
implementation(variantOf(libs.adapters.spigot) {
|
||||||
|
classifier("all") // otherwise the unshaded jar is used without the shaded NMS implementations
|
||||||
|
})
|
||||||
|
|
||||||
implementation(libs.commodore)
|
implementation(libs.commodore)
|
||||||
|
|
||||||
|
@ -22,6 +24,7 @@ platformRelocate("com.fasterxml.jackson")
|
||||||
platformRelocate("net.kyori", "net.kyori.adventure.text.logger.slf4j.ComponentLogger")
|
platformRelocate("net.kyori", "net.kyori.adventure.text.logger.slf4j.ComponentLogger")
|
||||||
platformRelocate("org.objectweb.asm")
|
platformRelocate("org.objectweb.asm")
|
||||||
platformRelocate("me.lucko.commodore")
|
platformRelocate("me.lucko.commodore")
|
||||||
|
platformRelocate("org.yaml") // Broken as of 1.20
|
||||||
|
|
||||||
// These dependencies are already present on the platform
|
// These dependencies are already present on the platform
|
||||||
provided(libs.viaversion)
|
provided(libs.viaversion)
|
||||||
|
@ -36,7 +39,6 @@ tasks.withType<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar> {
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
exclude(dependency("com.google.*:.*"))
|
exclude(dependency("com.google.*:.*"))
|
||||||
exclude(dependency("org.yaml:.*"))
|
|
||||||
|
|
||||||
// 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
|
||||||
|
|
|
@ -43,6 +43,7 @@ import org.bukkit.permissions.PermissionDefault;
|
||||||
import org.bukkit.plugin.Plugin;
|
import org.bukkit.plugin.Plugin;
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
import org.geysermc.floodgate.core.skin.SkinApplier;
|
import org.geysermc.floodgate.core.skin.SkinApplier;
|
||||||
|
import org.geysermc.geyser.api.util.PlatformType;
|
||||||
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;
|
||||||
|
@ -68,7 +69,6 @@ import org.geysermc.geyser.platform.spigot.world.manager.GeyserSpigotNativeWorld
|
||||||
import org.geysermc.geyser.platform.spigot.world.manager.GeyserSpigotWorldManager;
|
import org.geysermc.geyser.platform.spigot.world.manager.GeyserSpigotWorldManager;
|
||||||
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 org.geysermc.geyser.util.PlatformType;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
@ -168,20 +168,6 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// By default this should be localhost but may need to be changed in some circumstances
|
|
||||||
if (this.geyserConfig.getRemote().address().equalsIgnoreCase("auto")) {
|
|
||||||
geyserConfig.setAutoconfiguredRemote(true);
|
|
||||||
// Don't use localhost if not listening on all interfaces
|
|
||||||
if (!Bukkit.getIp().equals("0.0.0.0") && !Bukkit.getIp().equals("")) {
|
|
||||||
geyserConfig.getRemote().setAddress(Bukkit.getIp());
|
|
||||||
}
|
|
||||||
geyserConfig.getRemote().setPort(Bukkit.getPort());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (geyserConfig.getBedrock().isCloneRemotePort()) {
|
|
||||||
geyserConfig.getBedrock().setPort(Bukkit.getPort());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Bukkit.getPluginManager().getPlugin("floodgate") != null) {
|
if (Bukkit.getPluginManager().getPlugin("floodgate") != null) {
|
||||||
geyserLogger.severe("WHY DO YOU HAVE FLOODGATE INSTALLED!!!!!!! REMOVE IT!!!!");
|
geyserLogger.severe("WHY DO YOU HAVE FLOODGATE INSTALLED!!!!!!! REMOVE IT!!!!");
|
||||||
}
|
}
|
||||||
|
@ -337,6 +323,12 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Avoid registering the same permission twice, e.g. for the extension help commands
|
||||||
|
if (Bukkit.getPluginManager().getPermission(command.permission()) != null) {
|
||||||
|
GeyserImpl.getInstance().getLogger().debug("Skipping permission " + command.permission() + " as it is already registered");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
Bukkit.getPluginManager().addPermission(new Permission(command.permission(),
|
Bukkit.getPluginManager().addPermission(new Permission(command.permission(),
|
||||||
GeyserLocale.getLocaleStringLog(command.description()),
|
GeyserLocale.getLocaleStringLog(command.description()),
|
||||||
command.isSuggestedOpOnly() ? PermissionDefault.OP : PermissionDefault.TRUE));
|
command.isSuggestedOpOnly() ? PermissionDefault.OP : PermissionDefault.TRUE));
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
|
|
||||||
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 com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityInfo;
|
import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityInfo;
|
||||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
|
@ -171,6 +172,11 @@ public class GeyserSpigotWorldManager extends WorldManager {
|
||||||
return gameRule.getDefaultIntValue();
|
return gameRule.getDefaultIntValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GameMode getDefaultGameMode(GeyserSession session) {
|
||||||
|
return GameMode.byId(Bukkit.getDefaultGameMode().ordinal());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasPermission(GeyserSession session, String permission) {
|
public boolean hasPermission(GeyserSession session, String permission) {
|
||||||
return Bukkit.getPlayer(session.getPlayerEntity().getUsername()).hasPermission(permission);
|
return Bukkit.getPlayer(session.getPlayerEntity().getUsername()).hasPermission(permission);
|
||||||
|
|
|
@ -1,38 +0,0 @@
|
||||||
dependencies {
|
|
||||||
api(projects.core)
|
|
||||||
}
|
|
||||||
|
|
||||||
platformRelocate("com.fasterxml.jackson")
|
|
||||||
platformRelocate("io.netty")
|
|
||||||
platformRelocate("it.unimi.dsi.fastutil")
|
|
||||||
platformRelocate("com.google.common")
|
|
||||||
platformRelocate("com.google.guava")
|
|
||||||
platformRelocate("net.kyori.adventure.text.serializer.gson.legacyimpl")
|
|
||||||
platformRelocate("net.kyori.adventure.nbt")
|
|
||||||
|
|
||||||
// These dependencies are already present on the platform
|
|
||||||
provided(libs.sponge.api)
|
|
||||||
|
|
||||||
application {
|
|
||||||
mainClass.set("org.geysermc.geyser.platform.sponge.GeyserSpongeMain")
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.withType<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar> {
|
|
||||||
archiveBaseName.set("Geyser-Sponge")
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
exclude(dependency("com.google.code.gson:.*"))
|
|
||||||
exclude(dependency("org.yaml:.*"))
|
|
||||||
exclude(dependency("org.slf4j:.*"))
|
|
||||||
exclude(dependency("org.ow2.asm:.*"))
|
|
||||||
|
|
||||||
// Exclude all Kyori dependencies except the legacy NBT serializer and NBT
|
|
||||||
exclude(dependency("net.kyori:adventure-api:.*"))
|
|
||||||
exclude(dependency("net.kyori:examination-api:.*"))
|
|
||||||
exclude(dependency("net.kyori:examination-string:.*"))
|
|
||||||
exclude(dependency("net.kyori:adventure-text-serializer-gson:.*"))
|
|
||||||
exclude(dependency("net.kyori:adventure-text-serializer-legacy:.*"))
|
|
||||||
exclude(dependency("net.kyori:adventure-text-serializer-plain:.*"))
|
|
||||||
exclude(dependency("net.kyori:adventure-key:.*"))
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,71 +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.sponge;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
import org.geysermc.geyser.dump.BootstrapDumpInfo;
|
|
||||||
import org.geysermc.geyser.text.AsteriskSerializer;
|
|
||||||
import org.spongepowered.api.Platform;
|
|
||||||
import org.spongepowered.api.Sponge;
|
|
||||||
import org.spongepowered.plugin.PluginContainer;
|
|
||||||
import org.spongepowered.plugin.metadata.PluginMetadata;
|
|
||||||
import org.spongepowered.plugin.metadata.model.PluginContributor;
|
|
||||||
|
|
||||||
import java.net.InetSocketAddress;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
public class GeyserSpongeDumpInfo extends BootstrapDumpInfo {
|
|
||||||
private final String platformName;
|
|
||||||
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;
|
|
||||||
|
|
||||||
GeyserSpongeDumpInfo() {
|
|
||||||
PluginContainer container = Sponge.platform().container(Platform.Component.IMPLEMENTATION);
|
|
||||||
PluginMetadata platformMeta = container.metadata();
|
|
||||||
this.platformName = platformMeta.name().orElse("unknown");
|
|
||||||
this.platformVersion = platformMeta.version().getQualifier();
|
|
||||||
this.onlineMode = Sponge.server().isOnlineModeEnabled();
|
|
||||||
Optional<InetSocketAddress> socketAddress = Sponge.server().boundAddress();
|
|
||||||
this.serverIP = socketAddress.map(InetSocketAddress::getHostString).orElse("unknown");
|
|
||||||
this.serverPort = socketAddress.map(InetSocketAddress::getPort).orElse(-1);
|
|
||||||
this.plugins = new ArrayList<>();
|
|
||||||
|
|
||||||
for (PluginContainer plugin : Sponge.pluginManager().plugins()) {
|
|
||||||
PluginMetadata meta = plugin.metadata();
|
|
||||||
List<String> contributors = meta.contributors().stream().map(PluginContributor::name).collect(Collectors.toList());
|
|
||||||
this.plugins.add(new PluginInfo(true, meta.name().orElse("unknown"), meta.version().toString(), meta.entrypoint(), contributors));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,106 +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.sponge;
|
|
||||||
|
|
||||||
import org.geysermc.geyser.network.GameProtocol;
|
|
||||||
import org.geysermc.geyser.ping.GeyserPingInfo;
|
|
||||||
import org.geysermc.geyser.ping.IGeyserPingPassthrough;
|
|
||||||
import org.geysermc.geyser.translator.text.MessageTranslator;
|
|
||||||
import org.spongepowered.api.MinecraftVersion;
|
|
||||||
import org.spongepowered.api.Sponge;
|
|
||||||
import org.spongepowered.api.event.Cause;
|
|
||||||
import org.spongepowered.api.event.EventContext;
|
|
||||||
import org.spongepowered.api.event.SpongeEventFactory;
|
|
||||||
import org.spongepowered.api.event.server.ClientPingServerEvent;
|
|
||||||
import org.spongepowered.api.network.status.StatusClient;
|
|
||||||
import org.spongepowered.api.profile.GameProfile;
|
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.net.InetSocketAddress;
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
public class GeyserSpongePingPassthrough implements IGeyserPingPassthrough {
|
|
||||||
|
|
||||||
private static final Cause CAUSE = Cause.of(EventContext.empty(), Sponge.server());
|
|
||||||
|
|
||||||
private static Method SpongeStatusResponse_create;
|
|
||||||
|
|
||||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
|
||||||
@Override
|
|
||||||
public GeyserPingInfo getPingInformation(InetSocketAddress inetSocketAddress) {
|
|
||||||
// come on Sponge, this is in commons, why not expose it :(
|
|
||||||
ClientPingServerEvent event;
|
|
||||||
try {
|
|
||||||
if (SpongeStatusResponse_create == null) {
|
|
||||||
Class SpongeStatusResponse = Class.forName("org.spongepowered.common.network.status.SpongeStatusResponse");
|
|
||||||
Class MinecraftServer = Class.forName("net.minecraft.server.MinecraftServer");
|
|
||||||
SpongeStatusResponse_create = SpongeStatusResponse.getDeclaredMethod("create", MinecraftServer);
|
|
||||||
}
|
|
||||||
|
|
||||||
Object response = SpongeStatusResponse_create.invoke(null, Sponge.server());
|
|
||||||
event = SpongeEventFactory.createClientPingServerEvent(CAUSE, new GeyserStatusClient(inetSocketAddress), (ClientPingServerEvent.Response) response);
|
|
||||||
} catch (ReflectiveOperationException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
Sponge.eventManager().post(event);
|
|
||||||
GeyserPingInfo geyserPingInfo = new GeyserPingInfo(
|
|
||||||
MessageTranslator.convertMessage(event.response().description()),
|
|
||||||
new GeyserPingInfo.Players(
|
|
||||||
event.response().players().orElseThrow(IllegalStateException::new).max(),
|
|
||||||
event.response().players().orElseThrow(IllegalStateException::new).online()
|
|
||||||
),
|
|
||||||
new GeyserPingInfo.Version(
|
|
||||||
event.response().version().name(),
|
|
||||||
GameProtocol.getJavaProtocolVersion()) // thanks for also not exposing this sponge
|
|
||||||
);
|
|
||||||
event.response().players().ifPresent(players -> players.profiles().stream()
|
|
||||||
.map(GameProfile::name)
|
|
||||||
.filter(Optional::isPresent)
|
|
||||||
.map(Optional::get)
|
|
||||||
.forEach(geyserPingInfo.getPlayerList()::add)
|
|
||||||
);
|
|
||||||
|
|
||||||
return geyserPingInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
private record GeyserStatusClient(InetSocketAddress remote) implements StatusClient {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public InetSocketAddress address() {
|
|
||||||
return this.remote;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MinecraftVersion version() {
|
|
||||||
return Sponge.platform().minecraftVersion();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Optional<InetSocketAddress> virtualHost() {
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,247 +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.sponge;
|
|
||||||
|
|
||||||
import com.google.inject.Inject;
|
|
||||||
import org.apache.logging.log4j.Logger;
|
|
||||||
import org.geysermc.geyser.GeyserBootstrap;
|
|
||||||
import org.geysermc.geyser.GeyserImpl;
|
|
||||||
import org.geysermc.geyser.api.command.Command;
|
|
||||||
import org.geysermc.geyser.api.extension.Extension;
|
|
||||||
import org.geysermc.geyser.command.GeyserCommandManager;
|
|
||||||
import org.geysermc.geyser.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.sponge.command.GeyserSpongeCommandExecutor;
|
|
||||||
import org.geysermc.geyser.platform.sponge.command.GeyserSpongeCommandManager;
|
|
||||||
import org.geysermc.geyser.text.GeyserLocale;
|
|
||||||
import org.geysermc.geyser.util.FileUtils;
|
|
||||||
import org.geysermc.geyser.util.PlatformType;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.spongepowered.api.Server;
|
|
||||||
import org.spongepowered.api.Sponge;
|
|
||||||
import org.spongepowered.api.config.ConfigDir;
|
|
||||||
import org.spongepowered.api.event.Listener;
|
|
||||||
import org.spongepowered.api.event.lifecycle.ConstructPluginEvent;
|
|
||||||
import org.spongepowered.api.event.lifecycle.RegisterCommandEvent;
|
|
||||||
import org.spongepowered.api.event.lifecycle.StartedEngineEvent;
|
|
||||||
import org.spongepowered.api.event.lifecycle.StoppingEngineEvent;
|
|
||||||
import org.spongepowered.plugin.PluginContainer;
|
|
||||||
import org.spongepowered.plugin.builtin.jvm.Plugin;
|
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.InetSocketAddress;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
@Plugin(value = "geyser")
|
|
||||||
public class GeyserSpongePlugin implements GeyserBootstrap {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* True if the plugin should be in a disabled state.
|
|
||||||
* This exists because you can't unregister or disable plugins in Sponge
|
|
||||||
*/
|
|
||||||
private boolean enabled = true;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
private PluginContainer pluginContainer;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
private Logger logger;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
@ConfigDir(sharedRoot = false)
|
|
||||||
private Path configPath;
|
|
||||||
|
|
||||||
// Available after construction lifecycle
|
|
||||||
private GeyserSpongeConfiguration geyserConfig;
|
|
||||||
private GeyserSpongeLogger geyserLogger;
|
|
||||||
private GeyserImpl geyser;
|
|
||||||
private GeyserSpongeCommandManager geyserCommandManager; // Commands are only registered after command registration lifecycle
|
|
||||||
|
|
||||||
// Available after StartedEngine lifecycle
|
|
||||||
private IGeyserPingPassthrough geyserSpongePingPassthrough;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Only to be used for reloading
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void onEnable() {
|
|
||||||
enabled = true;
|
|
||||||
onConstruction(null);
|
|
||||||
// new commands cannot be registered, and geyser's command manager does not need be reloaded
|
|
||||||
onStartedEngine(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDisable() {
|
|
||||||
enabled = false;
|
|
||||||
if (geyser != null) {
|
|
||||||
geyser.shutdown();
|
|
||||||
geyser = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Construct the configuration, logger, and command manager. command manager will only be filled with commands once
|
|
||||||
* the connector is started, but it allows us to register events in sponge.
|
|
||||||
*
|
|
||||||
* @param event Not used.
|
|
||||||
*/
|
|
||||||
@Listener
|
|
||||||
public void onConstruction(@Nullable ConstructPluginEvent event) {
|
|
||||||
GeyserLocale.init(this);
|
|
||||||
|
|
||||||
File configDir = configPath.toFile();
|
|
||||||
if (!configDir.exists()) {
|
|
||||||
configDir.mkdirs();
|
|
||||||
}
|
|
||||||
|
|
||||||
File configFile;
|
|
||||||
try {
|
|
||||||
configFile = FileUtils.fileOrCopiedFromResource(new File(configDir, "config.yml"), "config.yml",
|
|
||||||
(file) -> file.replaceAll("generateduuid", UUID.randomUUID().toString()), this);
|
|
||||||
|
|
||||||
this.geyserConfig = FileUtils.loadConfig(configFile, GeyserSpongeConfiguration.class);
|
|
||||||
} catch (IOException ex) {
|
|
||||||
logger.error(GeyserLocale.getLocaleStringLog("geyser.config.failed"));
|
|
||||||
ex.printStackTrace();
|
|
||||||
onDisable();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
|
|
||||||
this.geyserLogger = new GeyserSpongeLogger(logger, geyserConfig.isDebugMode());
|
|
||||||
|
|
||||||
this.geyser = GeyserImpl.load(PlatformType.SPONGE, this, null);
|
|
||||||
|
|
||||||
this.geyserCommandManager = new GeyserSpongeCommandManager(geyser);
|
|
||||||
this.geyserCommandManager.init();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Construct the {@link GeyserSpongeCommandManager} and register the commands
|
|
||||||
*
|
|
||||||
* @param event required to register the commands
|
|
||||||
*/
|
|
||||||
@Listener
|
|
||||||
public void onRegisterCommands(@Nonnull RegisterCommandEvent<org.spongepowered.api.command.Command.Raw> event) {
|
|
||||||
if (enabled) {
|
|
||||||
event.register(this.pluginContainer, new GeyserSpongeCommandExecutor(geyser, geyserCommandManager.getCommands()), "geyser");
|
|
||||||
|
|
||||||
for (Map.Entry<Extension, Map<String, Command>> entry : this.geyserCommandManager.extensionCommands().entrySet()) {
|
|
||||||
Map<String, Command> commands = entry.getValue();
|
|
||||||
if (commands.isEmpty()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
event.register(this.pluginContainer, new GeyserSpongeCommandExecutor(this.geyser, commands), entry.getKey().description().id());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Configure the config properly if remote address is auto. Start connector and ping passthrough, and register subcommands of /geyser
|
|
||||||
*
|
|
||||||
* @param event not required
|
|
||||||
*/
|
|
||||||
@Listener
|
|
||||||
public void onStartedEngine(@Nullable StartedEngineEvent<Server> event) {
|
|
||||||
if (!enabled) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
GeyserImpl.start();
|
|
||||||
|
|
||||||
if (geyserConfig.isLegacyPingPassthrough()) {
|
|
||||||
this.geyserSpongePingPassthrough = GeyserLegacyPingPassthrough.init(geyser);
|
|
||||||
} else {
|
|
||||||
this.geyserSpongePingPassthrough = new GeyserSpongePingPassthrough();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Listener
|
|
||||||
public void onEngineStopping(StoppingEngineEvent<Server> event) {
|
|
||||||
onDisable();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public GeyserSpongeConfiguration getGeyserConfig() {
|
|
||||||
return geyserConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public GeyserSpongeLogger getGeyserLogger() {
|
|
||||||
return geyserLogger;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public GeyserCommandManager getGeyserCommandManager() {
|
|
||||||
return geyserCommandManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public IGeyserPingPassthrough getGeyserPingPassthrough() {
|
|
||||||
return geyserSpongePingPassthrough;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Path getConfigFolder() {
|
|
||||||
return configPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public BootstrapDumpInfo getDumpInfo() {
|
|
||||||
return new GeyserSpongeDumpInfo();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getMinecraftServerVersion() {
|
|
||||||
return Sponge.platform().minecraftVersion().name();
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
@Override
|
|
||||||
public String getServerBindAddress() {
|
|
||||||
return Sponge.server().boundAddress().map(InetSocketAddress::getHostString).orElse("");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getServerPort() {
|
|
||||||
return Sponge.server().boundAddress().stream().mapToInt(InetSocketAddress::getPort).findFirst().orElse(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean testFloodgatePluginPresent() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,112 +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.sponge.command;
|
|
||||||
|
|
||||||
import net.kyori.adventure.text.Component;
|
|
||||||
import net.kyori.adventure.text.format.NamedTextColor;
|
|
||||||
import org.geysermc.geyser.GeyserImpl;
|
|
||||||
import org.geysermc.geyser.api.command.Command;
|
|
||||||
import org.geysermc.geyser.command.GeyserCommand;
|
|
||||||
import org.geysermc.geyser.command.GeyserCommandExecutor;
|
|
||||||
import org.geysermc.geyser.command.GeyserCommandSource;
|
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
|
||||||
import org.geysermc.geyser.text.GeyserLocale;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.spongepowered.api.command.CommandCause;
|
|
||||||
import org.spongepowered.api.command.CommandCompletion;
|
|
||||||
import org.spongepowered.api.command.CommandResult;
|
|
||||||
import org.spongepowered.api.command.parameter.ArgumentReader;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
public class GeyserSpongeCommandExecutor extends GeyserCommandExecutor implements org.spongepowered.api.command.Command.Raw {
|
|
||||||
|
|
||||||
public GeyserSpongeCommandExecutor(GeyserImpl geyser, Map<String, Command> commands) {
|
|
||||||
super(geyser, commands);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CommandResult process(CommandCause cause, ArgumentReader.Mutable arguments) {
|
|
||||||
GeyserCommandSource commandSource = new SpongeCommandSource(cause);
|
|
||||||
GeyserSession session = getGeyserSession(commandSource);
|
|
||||||
|
|
||||||
String[] args = arguments.input().split(" ");
|
|
||||||
// This split operation results in an array of length 1, containing a zero length string, if the input string is empty
|
|
||||||
if (args.length > 0 && !args[0].isEmpty()) {
|
|
||||||
GeyserCommand command = getCommand(args[0]);
|
|
||||||
if (command != null) {
|
|
||||||
if (!cause.hasPermission(command.permission())) {
|
|
||||||
cause.audience().sendMessage(Component.text(GeyserLocale.getLocaleStringLog("geyser.bootstrap.command.permission_fail")).color(NamedTextColor.RED));
|
|
||||||
return CommandResult.success();
|
|
||||||
}
|
|
||||||
if (command.isBedrockOnly() && session == null) {
|
|
||||||
cause.audience().sendMessage(Component.text(GeyserLocale.getLocaleStringLog("geyser.bootstrap.command.bedrock_only")).color(NamedTextColor.RED));
|
|
||||||
return CommandResult.success();
|
|
||||||
}
|
|
||||||
command.execute(session, commandSource, args.length > 1 ? Arrays.copyOfRange(args, 1, args.length) : new String[0]);
|
|
||||||
} else {
|
|
||||||
cause.audience().sendMessage(Component.text(GeyserLocale.getLocaleStringLog("geyser.bootstrap.command.not_found")).color(NamedTextColor.RED));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
getCommand("help").execute(session, commandSource, new String[0]);
|
|
||||||
}
|
|
||||||
return CommandResult.success();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<CommandCompletion> complete(CommandCause cause, ArgumentReader.Mutable arguments) {
|
|
||||||
if (arguments.input().split(" ").length == 1) {
|
|
||||||
return tabComplete(new SpongeCommandSource(cause)).stream().map(CommandCompletion::of).collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean canExecute(CommandCause cause) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Optional<Component> shortDescription(CommandCause cause) {
|
|
||||||
return Optional.of(Component.text("The main command for Geyser."));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Optional<Component> extendedDescription(CommandCause cause) {
|
|
||||||
return shortDescription(cause);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Optional<Component> help(@NotNull CommandCause cause) {
|
|
||||||
return Optional.of(Component.text("/geyser help"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Component usage(CommandCause cause) {
|
|
||||||
return Component.text("/geyser help");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,30 +0,0 @@
|
||||||
{
|
|
||||||
"loader": {
|
|
||||||
"name": "java_plain",
|
|
||||||
"version": "1.0"
|
|
||||||
},
|
|
||||||
"license": "MIT",
|
|
||||||
"plugins": [
|
|
||||||
{
|
|
||||||
"id": "${id}",
|
|
||||||
"name": "${name}-Sponge",
|
|
||||||
"version": "${version}",
|
|
||||||
"entrypoint": "org.geysermc.geyser.platform.sponge.GeyserSpongePlugin",
|
|
||||||
"description": "${description}",
|
|
||||||
"links": {
|
|
||||||
"homepage": "${url}"
|
|
||||||
},
|
|
||||||
"contributors": [
|
|
||||||
{
|
|
||||||
"name": "${author}"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"dependencies": [
|
|
||||||
{
|
|
||||||
"id": "spongeapi",
|
|
||||||
"version": "8.0.0"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
{
|
|
||||||
"pack": {
|
|
||||||
"description": "Geyser for Sponge",
|
|
||||||
"pack_format": 6
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -7,10 +7,8 @@ dependencies {
|
||||||
api(projects.core)
|
api(projects.core)
|
||||||
|
|
||||||
implementation(libs.terminalconsoleappender) {
|
implementation(libs.terminalconsoleappender) {
|
||||||
exclude("org.apache.logging.log4j", "log4j-core")
|
exclude("org.apache.logging.log4j")
|
||||||
exclude("org.jline", "jline-reader")
|
exclude("org.jline")
|
||||||
exclude("org.jline", "jline-terminal")
|
|
||||||
exclude("org.jline", "jline-terminal-jna")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
implementation(libs.bundles.jline)
|
implementation(libs.bundles.jline)
|
||||||
|
@ -22,6 +20,13 @@ application {
|
||||||
mainClass.set("org.geysermc.geyser.platform.standalone.GeyserStandaloneBootstrap")
|
mainClass.set("org.geysermc.geyser.platform.standalone.GeyserStandaloneBootstrap")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tasks.named<Jar>("jar") {
|
||||||
|
manifest {
|
||||||
|
// log4j provides multi-release java 9 code which resolves https://github.com/GeyserMC/Geyser/issues/3693
|
||||||
|
attributes("Multi-Release" to true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
tasks.withType<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar> {
|
tasks.withType<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar> {
|
||||||
archiveBaseName.set("Geyser-Standalone")
|
archiveBaseName.set("Geyser-Standalone")
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,7 @@ import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.core.Appender;
|
import org.apache.logging.log4j.core.Appender;
|
||||||
import org.apache.logging.log4j.core.Logger;
|
import org.apache.logging.log4j.core.Logger;
|
||||||
import org.apache.logging.log4j.core.appender.ConsoleAppender;
|
import org.apache.logging.log4j.core.appender.ConsoleAppender;
|
||||||
|
import org.geysermc.geyser.api.util.PlatformType;
|
||||||
import org.geysermc.geyser.GeyserBootstrap;
|
import org.geysermc.geyser.GeyserBootstrap;
|
||||||
import org.geysermc.geyser.GeyserImpl;
|
import org.geysermc.geyser.GeyserImpl;
|
||||||
import org.geysermc.geyser.command.GeyserCommandManager;
|
import org.geysermc.geyser.command.GeyserCommandManager;
|
||||||
|
@ -50,7 +51,6 @@ import org.geysermc.geyser.platform.standalone.gui.GeyserStandaloneGUI;
|
||||||
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 org.geysermc.geyser.util.LoopbackUtil;
|
import org.geysermc.geyser.util.LoopbackUtil;
|
||||||
import org.geysermc.geyser.util.PlatformType;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
@ -181,14 +181,14 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.geyserLogger = new GeyserStandaloneLogger();
|
||||||
|
|
||||||
if (useGui && gui == null) {
|
if (useGui && gui == null) {
|
||||||
gui = new GeyserStandaloneGUI();
|
gui = new GeyserStandaloneGUI(geyserLogger);
|
||||||
gui.redirectSystemStreams();
|
gui.redirectSystemStreams();
|
||||||
gui.startUpdateThread();
|
gui.startUpdateThread();
|
||||||
}
|
}
|
||||||
|
|
||||||
geyserLogger = new GeyserStandaloneLogger();
|
|
||||||
|
|
||||||
LoopbackUtil.checkAndApplyLoopback(geyserLogger);
|
LoopbackUtil.checkAndApplyLoopback(geyserLogger);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -224,7 +224,7 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap {
|
||||||
geyserCommandManager.init();
|
geyserCommandManager.init();
|
||||||
|
|
||||||
if (gui != null) {
|
if (gui != null) {
|
||||||
gui.setupInterface(geyserLogger, geyserCommandManager);
|
gui.enableCommands(geyser.getScheduledThread(), geyserCommandManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
geyserPingPassthrough = GeyserLegacyPingPassthrough.init(geyser);
|
geyserPingPassthrough = GeyserLegacyPingPassthrough.init(geyser);
|
||||||
|
|
|
@ -92,6 +92,7 @@ public class GeyserStandaloneLogger extends SimpleTerminalConsole implements Gey
|
||||||
Configurator.setLevel(log.getName(), debug ? Level.DEBUG : Level.INFO);
|
Configurator.setLevel(log.getName(), debug ? Level.DEBUG : Level.INFO);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean isDebug() {
|
public boolean isDebug() {
|
||||||
return log.isDebugEnabled();
|
return log.isDebugEnabled();
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,7 +86,7 @@ public class ColorPane extends JTextPane {
|
||||||
while (stillSearching) {
|
while (stillSearching) {
|
||||||
mIndex = addString.indexOf("m", aPos); // find the end of the escape sequence
|
mIndex = addString.indexOf("m", aPos); // find the end of the escape sequence
|
||||||
if (mIndex < 0) { // the buffer ends halfway through the ansi string!
|
if (mIndex < 0) { // the buffer ends halfway through the ansi string!
|
||||||
remaining = addString.substring(aPos, addString.length());
|
remaining = addString.substring(aPos);
|
||||||
stillSearching = false;
|
stillSearching = false;
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
|
@ -99,7 +99,7 @@ public class ColorPane extends JTextPane {
|
||||||
aIndex = addString.indexOf("\u001B", aPos);
|
aIndex = addString.indexOf("\u001B", aPos);
|
||||||
|
|
||||||
if (aIndex == -1) { // if that was the last sequence of the input, send remaining text
|
if (aIndex == -1) { // if that was the last sequence of the input, send remaining text
|
||||||
tmpString = addString.substring(aPos, addString.length());
|
tmpString = addString.substring(aPos);
|
||||||
append(colorCurrent, tmpString);
|
append(colorCurrent, tmpString);
|
||||||
stillSearching = false;
|
stillSearching = false;
|
||||||
continue; // jump out of loop early, as the whole string has been sent now
|
continue; // jump out of loop early, as the whole string has been sent now
|
||||||
|
|
|
@ -26,10 +26,8 @@
|
||||||
package org.geysermc.geyser.platform.standalone.gui;
|
package org.geysermc.geyser.platform.standalone.gui;
|
||||||
|
|
||||||
import org.geysermc.geyser.GeyserImpl;
|
import org.geysermc.geyser.GeyserImpl;
|
||||||
import org.geysermc.geyser.api.command.Command;
|
import org.geysermc.geyser.GeyserLogger;
|
||||||
import org.geysermc.geyser.command.GeyserCommand;
|
|
||||||
import org.geysermc.geyser.command.GeyserCommandManager;
|
import org.geysermc.geyser.command.GeyserCommandManager;
|
||||||
import org.geysermc.geyser.platform.standalone.GeyserStandaloneLogger;
|
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
import org.geysermc.geyser.text.GeyserLocale;
|
import org.geysermc.geyser.text.GeyserLocale;
|
||||||
|
|
||||||
|
@ -45,28 +43,37 @@ import java.io.PrintStream;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Vector;
|
import java.util.Vector;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
public class GeyserStandaloneGUI {
|
public class GeyserStandaloneGUI {
|
||||||
|
|
||||||
private static final DefaultTableModel playerTableModel = new DefaultTableModel();
|
|
||||||
private static final List<Integer> ramValues = new ArrayList<>();
|
|
||||||
|
|
||||||
private static final ColorPane consolePane = new ColorPane();
|
|
||||||
private static final GraphPanel ramGraph = new GraphPanel();
|
|
||||||
private static final JTable playerTable = new JTable(playerTableModel);
|
|
||||||
private static final int originalFontSize = consolePane.getFont().getSize();
|
|
||||||
|
|
||||||
private static final long MEGABYTE = 1024L * 1024L;
|
private static final long MEGABYTE = 1024L * 1024L;
|
||||||
|
|
||||||
private final JMenu commandsMenu;
|
private final GeyserLogger logger;
|
||||||
private final JMenu optionsMenu;
|
|
||||||
|
private final ColorPane consolePane = new ColorPane();
|
||||||
|
private final int originalFontSize = consolePane.getFont().getSize();
|
||||||
|
private final JTextField commandInput = new JTextField();
|
||||||
|
private final CommandListener commandListener = new CommandListener();
|
||||||
|
|
||||||
|
private final GraphPanel ramGraph = new GraphPanel();
|
||||||
|
private final List<Integer> ramValues = new ArrayList<>();
|
||||||
|
|
||||||
|
private final DefaultTableModel playerTableModel = new DefaultTableModel();
|
||||||
|
private final JTable playerTable = new JTable(playerTableModel);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create and show the Geyser-Standalone GUI
|
||||||
|
*
|
||||||
|
* @param logger the logger for determining debug mode, and executing commands from the console
|
||||||
|
*/
|
||||||
|
public GeyserStandaloneGUI(GeyserLogger logger) {
|
||||||
|
this.logger = logger;
|
||||||
|
|
||||||
public GeyserStandaloneGUI() {
|
|
||||||
// Create the frame and setup basic settings
|
// Create the frame and setup basic settings
|
||||||
JFrame frame = new JFrame(GeyserLocale.getLocaleStringLog("geyser.gui.title"));
|
JFrame frame = new JFrame(GeyserLocale.getLocaleStringLog("geyser.gui.title"));
|
||||||
frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
|
frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
|
||||||
|
@ -81,8 +88,7 @@ public class GeyserStandaloneGUI {
|
||||||
// Show a confirm dialog on close
|
// Show a confirm dialog on close
|
||||||
frame.addWindowListener(new WindowAdapter() {
|
frame.addWindowListener(new WindowAdapter() {
|
||||||
@Override
|
@Override
|
||||||
public void windowClosing(WindowEvent we)
|
public void windowClosing(WindowEvent we) {
|
||||||
{
|
|
||||||
String[] buttons = {GeyserLocale.getLocaleStringLog("geyser.gui.exit.confirm"), GeyserLocale.getLocaleStringLog("geyser.gui.exit.deny")};
|
String[] buttons = {GeyserLocale.getLocaleStringLog("geyser.gui.exit.confirm"), GeyserLocale.getLocaleStringLog("geyser.gui.exit.deny")};
|
||||||
int result = JOptionPane.showOptionDialog(frame, GeyserLocale.getLocaleStringLog("geyser.gui.exit.message"), frame.getTitle(), JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE, null, buttons, buttons[1]);
|
int result = JOptionPane.showOptionDialog(frame, GeyserLocale.getLocaleStringLog("geyser.gui.exit.message"), frame.getTitle(), JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE, null, buttons, buttons[1]);
|
||||||
if (result == JOptionPane.YES_OPTION) {
|
if (result == JOptionPane.YES_OPTION) {
|
||||||
|
@ -100,91 +106,41 @@ public class GeyserStandaloneGUI {
|
||||||
frame.setIconImage(icon.getImage());
|
frame.setIconImage(icon.getImage());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// File, View, Options, etc
|
||||||
|
setupMenuBar(frame);
|
||||||
|
|
||||||
// Setup the split pane and event listeners
|
// Setup the split pane and event listeners
|
||||||
JSplitPane splitPane = new JSplitPane();
|
JSplitPane splitPane = new JSplitPane();
|
||||||
splitPane.setDividerLocation(600);
|
splitPane.setDividerLocation(600);
|
||||||
splitPane.addPropertyChangeListener("dividerLocation", e -> splitPaneLimit((JSplitPane)e.getSource()));
|
splitPane.addPropertyChangeListener("dividerLocation", e -> splitPaneLimit((JSplitPane) e.getSource()));
|
||||||
splitPane.addComponentListener(new ComponentAdapter() {
|
splitPane.addComponentListener(new ComponentAdapter() {
|
||||||
public void componentResized(ComponentEvent e) {
|
public void componentResized(ComponentEvent e) {
|
||||||
splitPaneLimit((JSplitPane)e.getSource());
|
splitPaneLimit((JSplitPane) e.getSource());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
cp.add(splitPane, BorderLayout.CENTER);
|
cp.add(splitPane, BorderLayout.CENTER);
|
||||||
|
|
||||||
// Set the background and disable input for the text pane
|
// Holds console and command input components
|
||||||
|
JPanel leftPane = new JPanel(new BorderLayout());
|
||||||
|
splitPane.setLeftComponent(leftPane);
|
||||||
|
|
||||||
|
// Set the background and disable editing of the console
|
||||||
consolePane.setBackground(Color.BLACK);
|
consolePane.setBackground(Color.BLACK);
|
||||||
consolePane.setEditable(false);
|
consolePane.setEditable(false);
|
||||||
|
|
||||||
// Wrap the text pane in a scroll pane and add it to the form
|
// Wrap the text pane in a scroll pane and add it to the form
|
||||||
JScrollPane consoleScrollPane = new JScrollPane(consolePane);
|
JScrollPane consoleScrollPane = new JScrollPane(consolePane);
|
||||||
//cp.add(consoleScrollPane, BorderLayout.CENTER);
|
leftPane.add(consoleScrollPane, BorderLayout.CENTER);
|
||||||
splitPane.setLeftComponent(consoleScrollPane);
|
|
||||||
|
|
||||||
// Create a new menu bar for the top of the frame
|
// a bit taller than the default layout - width is ignored fortunately
|
||||||
JMenuBar menuBar = new JMenuBar();
|
commandInput.setPreferredSize(new Dimension(100, 25));
|
||||||
|
commandInput.setEnabled(false); // disabled until command handler is initialized
|
||||||
// Create 'File'
|
commandInput.addActionListener(commandListener);
|
||||||
JMenu fileMenu = new JMenu(GeyserLocale.getLocaleStringLog("geyser.gui.menu.file"));
|
leftPane.add(commandInput, BorderLayout.SOUTH);
|
||||||
fileMenu.setMnemonic(KeyEvent.VK_F);
|
|
||||||
menuBar.add(fileMenu);
|
|
||||||
|
|
||||||
// 'Open Geyser folder' button
|
|
||||||
JMenuItem openButton = new JMenuItem(GeyserLocale.getLocaleStringLog("geyser.gui.menu.file.open_folder"), KeyEvent.VK_O);
|
|
||||||
openButton.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, InputEvent.CTRL_MASK));
|
|
||||||
openButton.addActionListener(e -> {
|
|
||||||
try {
|
|
||||||
Desktop.getDesktop().open(new File("./"));
|
|
||||||
} catch (IOException ignored) { }
|
|
||||||
});
|
|
||||||
fileMenu.add(openButton);
|
|
||||||
|
|
||||||
fileMenu.addSeparator();
|
|
||||||
|
|
||||||
// 'Exit' button
|
|
||||||
JMenuItem exitButton = new JMenuItem(GeyserLocale.getLocaleStringLog("geyser.gui.menu.file.exit"), KeyEvent.VK_X);
|
|
||||||
exitButton.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F4, InputEvent.ALT_MASK));
|
|
||||||
exitButton.addActionListener(e -> System.exit(0));
|
|
||||||
fileMenu.add(exitButton);
|
|
||||||
|
|
||||||
// Create 'Commands'
|
|
||||||
commandsMenu = new JMenu(GeyserLocale.getLocaleStringLog("geyser.gui.menu.commands"));
|
|
||||||
commandsMenu.setMnemonic(KeyEvent.VK_C);
|
|
||||||
menuBar.add(commandsMenu);
|
|
||||||
|
|
||||||
// Create 'View'
|
|
||||||
JMenu viewMenu = new JMenu(GeyserLocale.getLocaleStringLog("geyser.gui.menu.view"));
|
|
||||||
viewMenu.setMnemonic(KeyEvent.VK_V);
|
|
||||||
menuBar.add(viewMenu);
|
|
||||||
|
|
||||||
// 'Zoom in' button
|
|
||||||
JMenuItem zoomInButton = new JMenuItem(GeyserLocale.getLocaleStringLog("geyser.gui.menu.view.zoom_in"));
|
|
||||||
zoomInButton.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_EQUALS, InputEvent.CTRL_DOWN_MASK));
|
|
||||||
zoomInButton.addActionListener(e -> consolePane.setFont(new Font(consolePane.getFont().getName(), consolePane.getFont().getStyle(), consolePane.getFont().getSize() + 1)));
|
|
||||||
viewMenu.add(zoomInButton);
|
|
||||||
|
|
||||||
// 'Zoom in' button
|
|
||||||
JMenuItem zoomOutButton = new JMenuItem(GeyserLocale.getLocaleStringLog("geyser.gui.menu.view.zoom_out"));
|
|
||||||
zoomOutButton.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_MINUS, InputEvent.CTRL_DOWN_MASK));
|
|
||||||
zoomOutButton.addActionListener(e -> consolePane.setFont(new Font(consolePane.getFont().getName(), consolePane.getFont().getStyle(), consolePane.getFont().getSize() - 1)));
|
|
||||||
viewMenu.add(zoomOutButton);
|
|
||||||
|
|
||||||
// 'Reset Zoom' button
|
|
||||||
JMenuItem resetZoomButton = new JMenuItem(GeyserLocale.getLocaleStringLog("geyser.gui.menu.view.reset_zoom"));
|
|
||||||
resetZoomButton.addActionListener(e -> consolePane.setFont(new Font(consolePane.getFont().getName(), consolePane.getFont().getStyle(), originalFontSize)));
|
|
||||||
viewMenu.add(resetZoomButton);
|
|
||||||
|
|
||||||
// create 'Options'
|
|
||||||
optionsMenu = new JMenu(GeyserLocale.getLocaleStringLog("geyser.gui.menu.options"));
|
|
||||||
viewMenu.setMnemonic(KeyEvent.VK_O);
|
|
||||||
menuBar.add(optionsMenu);
|
|
||||||
|
|
||||||
// Set the frames menu bar
|
|
||||||
frame.setJMenuBar(menuBar);
|
|
||||||
|
|
||||||
JPanel rightPane = new JPanel();
|
JPanel rightPane = new JPanel();
|
||||||
rightPane.setLayout(new CardLayout(5, 5));
|
rightPane.setLayout(new CardLayout(5, 5));
|
||||||
//cp.add(rightPane, BorderLayout.EAST);
|
|
||||||
splitPane.setRightComponent(rightPane);
|
splitPane.setRightComponent(rightPane);
|
||||||
|
|
||||||
JPanel rightContentPane = new JPanel();
|
JPanel rightContentPane = new JPanel();
|
||||||
|
@ -209,12 +165,75 @@ public class GeyserStandaloneGUI {
|
||||||
frame.setVisible(true);
|
frame.setVisible(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setupMenuBar(JFrame frame) {
|
||||||
|
// Create a new menu bar for the top of the frame
|
||||||
|
JMenuBar menuBar = new JMenuBar();
|
||||||
|
|
||||||
|
// Create 'File'
|
||||||
|
JMenu fileMenu = new JMenu(GeyserLocale.getLocaleStringLog("geyser.gui.menu.file"));
|
||||||
|
fileMenu.setMnemonic(KeyEvent.VK_F);
|
||||||
|
menuBar.add(fileMenu);
|
||||||
|
|
||||||
|
// 'Open Geyser folder' button
|
||||||
|
JMenuItem openButton = new JMenuItem(GeyserLocale.getLocaleStringLog("geyser.gui.menu.file.open_folder"), KeyEvent.VK_O);
|
||||||
|
openButton.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, InputEvent.CTRL_DOWN_MASK));
|
||||||
|
openButton.addActionListener(e -> {
|
||||||
|
try {
|
||||||
|
Desktop.getDesktop().open(new File("./"));
|
||||||
|
} catch (IOException ignored) { }
|
||||||
|
});
|
||||||
|
fileMenu.add(openButton);
|
||||||
|
|
||||||
|
fileMenu.addSeparator();
|
||||||
|
|
||||||
|
// 'Exit' button
|
||||||
|
JMenuItem exitButton = new JMenuItem(GeyserLocale.getLocaleStringLog("geyser.gui.menu.file.exit"), KeyEvent.VK_X);
|
||||||
|
exitButton.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F4, InputEvent.ALT_DOWN_MASK));
|
||||||
|
exitButton.addActionListener(e -> System.exit(0));
|
||||||
|
fileMenu.add(exitButton);
|
||||||
|
|
||||||
|
// Create 'View'
|
||||||
|
JMenu viewMenu = new JMenu(GeyserLocale.getLocaleStringLog("geyser.gui.menu.view"));
|
||||||
|
viewMenu.setMnemonic(KeyEvent.VK_V);
|
||||||
|
menuBar.add(viewMenu);
|
||||||
|
|
||||||
|
// 'Zoom in' button
|
||||||
|
JMenuItem zoomInButton = new JMenuItem(GeyserLocale.getLocaleStringLog("geyser.gui.menu.view.zoom_in"));
|
||||||
|
zoomInButton.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_EQUALS, InputEvent.CTRL_DOWN_MASK));
|
||||||
|
zoomInButton.addActionListener(e -> consolePane.setFont(new Font(consolePane.getFont().getName(), consolePane.getFont().getStyle(), consolePane.getFont().getSize() + 1)));
|
||||||
|
viewMenu.add(zoomInButton);
|
||||||
|
|
||||||
|
// 'Zoom in' button
|
||||||
|
JMenuItem zoomOutButton = new JMenuItem(GeyserLocale.getLocaleStringLog("geyser.gui.menu.view.zoom_out"));
|
||||||
|
zoomOutButton.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_MINUS, InputEvent.CTRL_DOWN_MASK));
|
||||||
|
zoomOutButton.addActionListener(e -> consolePane.setFont(new Font(consolePane.getFont().getName(), consolePane.getFont().getStyle(), consolePane.getFont().getSize() - 1)));
|
||||||
|
viewMenu.add(zoomOutButton);
|
||||||
|
|
||||||
|
// 'Reset Zoom' button
|
||||||
|
JMenuItem resetZoomButton = new JMenuItem(GeyserLocale.getLocaleStringLog("geyser.gui.menu.view.reset_zoom"));
|
||||||
|
resetZoomButton.addActionListener(e -> consolePane.setFont(new Font(consolePane.getFont().getName(), consolePane.getFont().getStyle(), originalFontSize)));
|
||||||
|
viewMenu.add(resetZoomButton);
|
||||||
|
|
||||||
|
// create 'Options'
|
||||||
|
JMenu optionsMenu = new JMenu(GeyserLocale.getLocaleStringLog("geyser.gui.menu.options"));
|
||||||
|
viewMenu.setMnemonic(KeyEvent.VK_O);
|
||||||
|
menuBar.add(optionsMenu);
|
||||||
|
|
||||||
|
JCheckBoxMenuItem debugMode = new JCheckBoxMenuItem(GeyserLocale.getLocaleStringLog("geyser.gui.menu.options.toggle_debug_mode"));
|
||||||
|
debugMode.setSelected(logger.isDebug());
|
||||||
|
debugMode.addActionListener(e -> logger.setDebug(debugMode.getState()));
|
||||||
|
optionsMenu.add(debugMode);
|
||||||
|
|
||||||
|
// Set the frames menu bar
|
||||||
|
frame.setJMenuBar(menuBar);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Queue up an update to the text pane so we don't block the main thread
|
* Queue up an update to the text pane so we don't block the main thread
|
||||||
*
|
*
|
||||||
* @param text The text to append
|
* @param text The text to append
|
||||||
*/
|
*/
|
||||||
private void updateTextPane(final String text) {
|
private void appendConsole(final String text) {
|
||||||
SwingUtilities.invokeLater(() -> {
|
SwingUtilities.invokeLater(() -> {
|
||||||
consolePane.appendANSI(text);
|
consolePane.appendANSI(text);
|
||||||
Document doc = consolePane.getDocument();
|
Document doc = consolePane.getDocument();
|
||||||
|
@ -230,12 +249,12 @@ public class GeyserStandaloneGUI {
|
||||||
OutputStream out = new OutputStream() {
|
OutputStream out = new OutputStream() {
|
||||||
@Override
|
@Override
|
||||||
public void write(final int b) {
|
public void write(final int b) {
|
||||||
updateTextPane(String.valueOf((char) b));
|
appendConsole(String.valueOf((char) b));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void write(byte[] b, int off, int len) {
|
public void write(byte[] b, int off, int len) {
|
||||||
updateTextPane(new String(b, off, len));
|
appendConsole(new String(b, off, len));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -251,50 +270,17 @@ public class GeyserStandaloneGUI {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add all the Geyser commands to the commands menu, and setup the debug mode toggle
|
* Enable the command input box.
|
||||||
*
|
*
|
||||||
* @param geyserStandaloneLogger The current logger
|
* @param executor the executor for running commands off the GUI thread
|
||||||
* @param geyserCommandManager The commands manager
|
* @param commandManager the command manager to delegate commands to
|
||||||
*/
|
*/
|
||||||
public void setupInterface(GeyserStandaloneLogger geyserStandaloneLogger, GeyserCommandManager geyserCommandManager) {
|
public void enableCommands(ScheduledExecutorService executor, GeyserCommandManager commandManager) {
|
||||||
commandsMenu.removeAll();
|
// we don't want to block the GUI thread with the command execution
|
||||||
optionsMenu.removeAll();
|
// todo: once cloud is used, an AsynchronousCommandExecutionCoordinator can be used to avoid this scheduler
|
||||||
|
commandListener.handler = cmd -> executor.schedule(() -> commandManager.runCommand(logger, cmd), 0, TimeUnit.SECONDS);
|
||||||
for (Map.Entry<String, Command> entry : geyserCommandManager.getCommands().entrySet()) {
|
commandInput.setEnabled(true);
|
||||||
// Remove the offhand command and any alias commands to prevent duplicates in the list
|
commandInput.requestFocusInWindow();
|
||||||
if (!entry.getValue().isExecutableOnConsole() || entry.getValue().aliases().contains(entry.getKey())) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
GeyserCommand command = (GeyserCommand) entry.getValue();
|
|
||||||
// Create the button that runs the command
|
|
||||||
boolean hasSubCommands = !entry.getValue().subCommands().isEmpty();
|
|
||||||
// Add an extra menu if there are more commands that can be run
|
|
||||||
JMenuItem commandButton = hasSubCommands ? new JMenu(entry.getValue().name()) : new JMenuItem(entry.getValue().name());
|
|
||||||
commandButton.getAccessibleContext().setAccessibleDescription(entry.getValue().description());
|
|
||||||
if (!hasSubCommands) {
|
|
||||||
commandButton.addActionListener(e -> command.execute(null, geyserStandaloneLogger, new String[]{ }));
|
|
||||||
} else {
|
|
||||||
// Add a submenu that's the same name as the menu can't be pressed
|
|
||||||
JMenuItem otherCommandButton = new JMenuItem(entry.getValue().name());
|
|
||||||
otherCommandButton.getAccessibleContext().setAccessibleDescription(entry.getValue().description());
|
|
||||||
otherCommandButton.addActionListener(e -> command.execute(null, geyserStandaloneLogger, new String[]{ }));
|
|
||||||
commandButton.add(otherCommandButton);
|
|
||||||
// Add a menu option for all possible subcommands
|
|
||||||
for (String subCommandName : entry.getValue().subCommands()) {
|
|
||||||
JMenuItem item = new JMenuItem(subCommandName);
|
|
||||||
item.addActionListener(e -> command.execute(null, geyserStandaloneLogger, new String[]{subCommandName}));
|
|
||||||
commandButton.add(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
commandsMenu.add(commandButton);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 'Debug Mode' toggle
|
|
||||||
JCheckBoxMenuItem debugMode = new JCheckBoxMenuItem(GeyserLocale.getLocaleStringLog("geyser.gui.menu.options.toggle_debug_mode"));
|
|
||||||
debugMode.setSelected(geyserStandaloneLogger.isDebug());
|
|
||||||
debugMode.addActionListener(e -> geyserStandaloneLogger.setDebug(!geyserStandaloneLogger.isDebug()));
|
|
||||||
optionsMenu.add(debugMode);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -322,14 +308,14 @@ public class GeyserStandaloneGUI {
|
||||||
// Update ram graph
|
// Update ram graph
|
||||||
final long freeMemory = Runtime.getRuntime().freeMemory();
|
final long freeMemory = Runtime.getRuntime().freeMemory();
|
||||||
final long totalMemory = Runtime.getRuntime().totalMemory();
|
final long totalMemory = Runtime.getRuntime().totalMemory();
|
||||||
final int freePercent = (int)(freeMemory * 100.0 / totalMemory + 0.5);
|
final int freePercent = (int) (freeMemory * 100.0 / totalMemory + 0.5);
|
||||||
ramValues.add(100 - freePercent);
|
ramValues.add(100 - freePercent);
|
||||||
|
|
||||||
ramGraph.setXLabel(GeyserLocale.getLocaleStringLog("geyser.gui.graph.usage", String.format("%,d", (totalMemory - freeMemory) / MEGABYTE), freePercent));
|
ramGraph.setXLabel(GeyserLocale.getLocaleStringLog("geyser.gui.graph.usage", String.format("%,d", (totalMemory - freeMemory) / MEGABYTE), freePercent));
|
||||||
|
|
||||||
// Trim the list
|
// Trim the list
|
||||||
int k = ramValues.size();
|
int k = ramValues.size();
|
||||||
if ( k > 10 )
|
if (k > 10)
|
||||||
ramValues.subList(0, k - 10).clear();
|
ramValues.subList(0, k - 10).clear();
|
||||||
|
|
||||||
// Update the graph
|
// Update the graph
|
||||||
|
@ -354,4 +340,17 @@ public class GeyserStandaloneGUI {
|
||||||
splitPane.setDividerLocation(frame.getWidth() - 200);
|
splitPane.setDividerLocation(frame.getWidth() - 200);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class CommandListener implements ActionListener {
|
||||||
|
|
||||||
|
private Consumer<String> handler;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
String command = commandInput.getText();
|
||||||
|
appendConsole(command + "\n"); // show what was run in the console
|
||||||
|
handler.accept(command); // run the command
|
||||||
|
commandInput.setText(""); // clear the input
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,10 +2,10 @@
|
||||||
<Configuration status="WARN">
|
<Configuration status="WARN">
|
||||||
<Appenders>
|
<Appenders>
|
||||||
<TerminalConsole name="TerminalConsole">
|
<TerminalConsole name="TerminalConsole">
|
||||||
<PatternLayout pattern="[%d{HH:mm:ss} %style{%highlight{%level}{FATAL=red dark, ERROR=red, WARN=yellow bright, INFO=cyan bright, DEBUG=green, TRACE=white}}] %minecraftFormatting{%msg}%n"/>
|
<PatternLayout pattern="[%d{HH:mm:ss} %style{%highlight{%level}{FATAL=red, ERROR=red, WARN=yellow bright, INFO=cyan bright, DEBUG=green, TRACE=white}}] %minecraftFormatting{%msg}%n"/>
|
||||||
</TerminalConsole>
|
</TerminalConsole>
|
||||||
<Console name="Console" target="SYSTEM_OUT" follow="true">
|
<Console name="Console" target="SYSTEM_OUT" follow="true">
|
||||||
<PatternLayout pattern="[%d{HH:mm:ss} %style{%highlight{%level}{FATAL=red dark, ERROR=red, WARN=yellow bright, INFO=cyan bright, DEBUG=green, TRACE=white}}] %minecraftFormatting{%msg}%n"/>
|
<PatternLayout pattern="[%d{HH:mm:ss} %style{%highlight{%level}{FATAL=red, ERROR=red, WARN=yellow bright, INFO=cyan bright, DEBUG=green, TRACE=white}}] %minecraftFormatting{%msg}%n"/>
|
||||||
</Console>
|
</Console>
|
||||||
<RollingRandomAccessFile name="File" fileName="logs/latest.log" filePattern="logs/%d{yyyy-MM-dd}-%i.log.gz">
|
<RollingRandomAccessFile name="File" fileName="logs/latest.log" filePattern="logs/%d{yyyy-MM-dd}-%i.log.gz">
|
||||||
<PatternLayout pattern="[%d{HH:mm:ss.SSS} %t/%level] %minecraftFormatting{%msg}{strip}%n"/>
|
<PatternLayout pattern="[%d{HH:mm:ss.SSS} %t/%level] %minecraftFormatting{%msg}{strip}%n"/>
|
||||||
|
|
|
@ -38,6 +38,7 @@ import com.velocitypowered.api.proxy.ProxyServer;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import net.kyori.adventure.util.Codec;
|
import net.kyori.adventure.util.Codec;
|
||||||
import org.geysermc.floodgate.core.FloodgatePlatform;
|
import org.geysermc.floodgate.core.FloodgatePlatform;
|
||||||
|
import org.geysermc.geyser.api.util.PlatformType;
|
||||||
import org.geysermc.geyser.GeyserBootstrap;
|
import org.geysermc.geyser.GeyserBootstrap;
|
||||||
import org.geysermc.geyser.GeyserImpl;
|
import org.geysermc.geyser.GeyserImpl;
|
||||||
import org.geysermc.geyser.api.command.Command;
|
import org.geysermc.geyser.api.command.Command;
|
||||||
|
@ -52,7 +53,6 @@ import org.geysermc.geyser.platform.velocity.command.GeyserVelocityCommandExecut
|
||||||
import org.geysermc.geyser.platform.velocity.floodgate.FloodgateVelocityPlatform;
|
import org.geysermc.geyser.platform.velocity.floodgate.FloodgateVelocityPlatform;
|
||||||
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 org.geysermc.geyser.util.PlatformType;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
|
|
@ -8,7 +8,7 @@ repositories {
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("net.kyori", "indra-common", "3.0.1")
|
implementation("net.kyori", "indra-common", "3.1.1")
|
||||||
implementation("com.github.johnrengelman", "shadow", "7.1.3-SNAPSHOT")
|
implementation("com.github.johnrengelman", "shadow", "7.1.3-SNAPSHOT")
|
||||||
|
|
||||||
// Within the gradle plugin classpath, there is a version conflict between loom and some other
|
// Within the gradle plugin classpath, there is a version conflict between loom and some other
|
||||||
|
|
|
@ -22,8 +22,8 @@ indra {
|
||||||
|
|
||||||
tasks {
|
tasks {
|
||||||
processResources {
|
processResources {
|
||||||
// Spigot, BungeeCord, Velocity, Sponge, Fabric
|
// Spigot, BungeeCord, Velocity, Fabric
|
||||||
filesMatching(listOf("plugin.yml", "bungee.yml", "velocity-plugin.json", "META-INF/sponge_plugins.json", "fabric.mod.json")) {
|
filesMatching(listOf("plugin.yml", "bungee.yml", "velocity-plugin.json", "fabric.mod.json")) {
|
||||||
expand(
|
expand(
|
||||||
"id" to "geyser",
|
"id" to "geyser",
|
||||||
"name" to "Geyser",
|
"name" to "Geyser",
|
||||||
|
|
|
@ -5,12 +5,14 @@ plugins {
|
||||||
}
|
}
|
||||||
|
|
||||||
allprojects {
|
allprojects {
|
||||||
group = "org.geysermc.geyser"
|
group = properties["group"] as String + "." + properties["id"] as String
|
||||||
version = "3.0.0-SNAPSHOT"
|
version = properties["version"] as String
|
||||||
description = "Allows for players from Minecraft: Bedrock Edition to join Minecraft: Java Edition servers."
|
description = properties["description"] as String
|
||||||
|
}
|
||||||
|
|
||||||
tasks.withType<JavaCompile> {
|
java {
|
||||||
options.encoding = "UTF-8"
|
toolchain {
|
||||||
|
languageVersion.set(JavaLanguageVersion.of(16))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,7 +20,6 @@ val platforms = setOf(
|
||||||
projects.fabric,
|
projects.fabric,
|
||||||
projects.bungeecord,
|
projects.bungeecord,
|
||||||
projects.spigot,
|
projects.spigot,
|
||||||
projects.sponge,
|
|
||||||
projects.standalone,
|
projects.standalone,
|
||||||
projects.velocity
|
projects.velocity
|
||||||
).map { it.dependencyProject }
|
).map { it.dependencyProject }
|
||||||
|
|
|
@ -6,3 +6,9 @@ dependencies {
|
||||||
api(libs.cumulus)
|
api(libs.cumulus)
|
||||||
api(libs.gson)
|
api(libs.gson)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
indra {
|
||||||
|
javaVersions {
|
||||||
|
target(8)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ 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) {
|
||||||
|
@ -31,7 +32,7 @@ dependencies {
|
||||||
}
|
}
|
||||||
|
|
||||||
implementation(libs.raknet) {
|
implementation(libs.raknet) {
|
||||||
exclude("io.netty", "*");
|
exclude("io.netty", "*")
|
||||||
}
|
}
|
||||||
|
|
||||||
implementation(libs.netty.resolver.dns)
|
implementation(libs.netty.resolver.dns)
|
||||||
|
@ -98,7 +99,7 @@ configure<BlossomExtension> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Project.buildNumber(): Int =
|
fun Project.buildNumber(): Int =
|
||||||
System.getenv("BUILD_NUMBER")?.let { Integer.parseInt(it) } ?: -1
|
(System.getenv("GITHUB_RUN_NUMBER") ?: jenkinsBuildNumber())?.let { Integer.parseInt(it) } ?: -1
|
||||||
|
|
||||||
inner class GitInfo {
|
inner class GitInfo {
|
||||||
val branch: String
|
val branch: String
|
||||||
|
@ -130,3 +131,6 @@ inner class GitInfo {
|
||||||
repository = git?.repository?.config?.getString("remote", "origin", "url") ?: ""
|
repository = git?.repository?.config?.getString("remote", "origin", "url") ?: ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// todo remove this when we're not using Jenkins anymore
|
||||||
|
fun jenkinsBuildNumber(): String? = System.getenv("BUILD_NUMBER")
|
||||||
|
|
|
@ -26,9 +26,9 @@
|
||||||
package org.geysermc.connector;
|
package org.geysermc.connector;
|
||||||
|
|
||||||
import org.geysermc.api.Geyser;
|
import org.geysermc.api.Geyser;
|
||||||
|
import org.geysermc.geyser.api.util.PlatformType;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.geyser.GeyserImpl;
|
import org.geysermc.geyser.GeyserImpl;
|
||||||
import org.geysermc.geyser.util.PlatformType;
|
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
|
|
@ -36,17 +36,20 @@ public final class Constants {
|
||||||
|
|
||||||
public static final String FLOODGATE_DOWNLOAD_LOCATION = "https://ci.opencollab.dev/job/GeyserMC/job/Floodgate/job/master/";
|
public static final String FLOODGATE_DOWNLOAD_LOCATION = "https://ci.opencollab.dev/job/GeyserMC/job/Floodgate/job/master/";
|
||||||
|
|
||||||
public static final String GEYSER_DOWNLOAD_LOCATION = "https://ci.geysermc.org";
|
public static final String GEYSER_DOWNLOAD_LOCATION = "https://geysermc.org/download";
|
||||||
public static final String UPDATE_PERMISSION = "geyser.update";
|
public static final String UPDATE_PERMISSION = "geyser.update";
|
||||||
|
|
||||||
static final String SAVED_REFRESH_TOKEN_FILE = "saved-refresh-tokens.json";
|
static final String SAVED_REFRESH_TOKEN_FILE = "saved-refresh-tokens.json";
|
||||||
|
|
||||||
|
public static final String GEYSER_CUSTOM_NAMESPACE = "geyser_custom";
|
||||||
|
|
||||||
|
public static final String MINECRAFT_SKIN_SERVER_URL = "https://textures.minecraft.net/texture/";
|
||||||
|
|
||||||
static {
|
static {
|
||||||
URI wsUri = null;
|
URI wsUri = null;
|
||||||
try {
|
try {
|
||||||
wsUri = new URI("wss://api.geysermc.org/ws");
|
wsUri = new URI("wss://api.geysermc.org/ws");
|
||||||
} catch (URISyntaxException e) {
|
} catch (URISyntaxException e) {
|
||||||
GeyserImpl.getInstance().getLogger().error("Unable to resolve api.geysermc.org! Check your internet connection.");
|
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
GLOBAL_API_WS_URI = wsUri;
|
GLOBAL_API_WS_URI = wsUri;
|
||||||
|
|
|
@ -43,6 +43,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||||
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.api.Geyser;
|
import org.geysermc.api.Geyser;
|
||||||
|
import org.geysermc.geyser.api.util.PlatformType;
|
||||||
import org.geysermc.cumulus.form.Form;
|
import org.geysermc.cumulus.form.Form;
|
||||||
import org.geysermc.cumulus.form.util.FormBuilder;
|
import org.geysermc.cumulus.form.util.FormBuilder;
|
||||||
import org.geysermc.erosion.packet.Packets;
|
import org.geysermc.erosion.packet.Packets;
|
||||||
|
@ -66,9 +67,9 @@ import org.geysermc.geyser.extension.GeyserExtensionManager;
|
||||||
import org.geysermc.geyser.hybrid.HybridProvider;
|
import org.geysermc.geyser.hybrid.HybridProvider;
|
||||||
import org.geysermc.geyser.level.WorldManager;
|
import org.geysermc.geyser.level.WorldManager;
|
||||||
import org.geysermc.geyser.network.netty.GeyserServer;
|
import org.geysermc.geyser.network.netty.GeyserServer;
|
||||||
import org.geysermc.geyser.pack.ResourcePack;
|
|
||||||
import org.geysermc.geyser.registry.BlockRegistries;
|
import org.geysermc.geyser.registry.BlockRegistries;
|
||||||
import org.geysermc.geyser.registry.Registries;
|
import org.geysermc.geyser.registry.Registries;
|
||||||
|
import org.geysermc.geyser.registry.loader.RegistryLoaders;
|
||||||
import org.geysermc.geyser.scoreboard.ScoreboardUpdater;
|
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;
|
||||||
|
@ -87,6 +88,7 @@ import java.io.IOException;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
|
import java.nio.file.Path;
|
||||||
import java.text.DecimalFormat;
|
import java.text.DecimalFormat;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
@ -221,25 +223,9 @@ public class GeyserImpl implements GeyserApi {
|
||||||
|
|
||||||
GeyserConfiguration config = bootstrap.getGeyserConfig();
|
GeyserConfiguration config = bootstrap.getGeyserConfig();
|
||||||
|
|
||||||
boolean isGui = false;
|
|
||||||
// This will check if we are in standalone and get the 'useGui' variable from there
|
|
||||||
if (platformType == PlatformType.STANDALONE) {
|
|
||||||
try {
|
|
||||||
Class<?> cls = Class.forName("org.geysermc.geyser.platform.standalone.GeyserStandaloneBootstrap");
|
|
||||||
isGui = (boolean) cls.getMethod("isUseGui").invoke(cls.cast(bootstrap));
|
|
||||||
} catch (Exception e) {
|
|
||||||
logger.debug("Failed detecting if standalone is using a GUI; if this is a GeyserConnect instance this can be safely ignored.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
double completeTime = (System.currentTimeMillis() - startupTime) / 1000D;
|
double completeTime = (System.currentTimeMillis() - startupTime) / 1000D;
|
||||||
String message = GeyserLocale.getLocaleStringLog("geyser.core.finish.done", new DecimalFormat("#.###").format(completeTime)) + " ";
|
String message = GeyserLocale.getLocaleStringLog("geyser.core.finish.done", new DecimalFormat("#.###").format(completeTime));
|
||||||
if (isGui) {
|
message += " " + GeyserLocale.getLocaleStringLog("geyser.core.finish.console");
|
||||||
message += GeyserLocale.getLocaleStringLog("geyser.core.finish.gui");
|
|
||||||
} else {
|
|
||||||
message += GeyserLocale.getLocaleStringLog("geyser.core.finish.console");
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.info(message);
|
logger.info(message);
|
||||||
|
|
||||||
if (platformType == PlatformType.STANDALONE) {
|
if (platformType == PlatformType.STANDALONE) {
|
||||||
|
@ -262,8 +248,8 @@ public class GeyserImpl implements GeyserApi {
|
||||||
|
|
||||||
SkinProvider.registerCacheImageTask(this);
|
SkinProvider.registerCacheImageTask(this);
|
||||||
|
|
||||||
ResourcePack.loadPacks();
|
Registries.RESOURCE_PACKS.load();
|
||||||
//TODO start
|
|
||||||
String geyserUdpPort = System.getProperty("geyserUdpPort", "");
|
String geyserUdpPort = System.getProperty("geyserUdpPort", "");
|
||||||
String pluginUdpPort = geyserUdpPort.isEmpty() ? System.getProperty("pluginUdpPort", "") : geyserUdpPort;
|
String pluginUdpPort = geyserUdpPort.isEmpty() ? System.getProperty("pluginUdpPort", "") : geyserUdpPort;
|
||||||
if ("-1".equals(pluginUdpPort)) {
|
if ("-1".equals(pluginUdpPort)) {
|
||||||
|
@ -413,7 +399,7 @@ public class GeyserImpl implements GeyserApi {
|
||||||
metrics.addCustomChart(new Metrics.SingleLineChart("players", sessionManager::size));
|
metrics.addCustomChart(new Metrics.SingleLineChart("players", sessionManager::size));
|
||||||
// Prevent unwanted words best we can
|
// Prevent unwanted words best we can
|
||||||
metrics.addCustomChart(new Metrics.SimplePie("authMode", () -> config.getRemote().authType().toString().toLowerCase(Locale.ROOT)));
|
metrics.addCustomChart(new Metrics.SimplePie("authMode", () -> config.getRemote().authType().toString().toLowerCase(Locale.ROOT)));
|
||||||
metrics.addCustomChart(new Metrics.SimplePie("platform", platformType::getPlatformName));
|
metrics.addCustomChart(new Metrics.SimplePie("platform", platformType::platformName));
|
||||||
metrics.addCustomChart(new Metrics.SimplePie("defaultLocale", GeyserLocale::getDefaultLocale));
|
metrics.addCustomChart(new Metrics.SimplePie("defaultLocale", GeyserLocale::getDefaultLocale));
|
||||||
metrics.addCustomChart(new Metrics.SimplePie("version", () -> GeyserImpl.VERSION));
|
metrics.addCustomChart(new Metrics.SimplePie("version", () -> GeyserImpl.VERSION));
|
||||||
metrics.addCustomChart(new Metrics.AdvancedPie("playerPlatform", () -> {
|
metrics.addCustomChart(new Metrics.AdvancedPie("playerPlatform", () -> {
|
||||||
|
@ -449,7 +435,7 @@ public class GeyserImpl implements GeyserApi {
|
||||||
if (minecraftVersion != null) {
|
if (minecraftVersion != null) {
|
||||||
Map<String, Map<String, Integer>> versionMap = new HashMap<>();
|
Map<String, Map<String, Integer>> versionMap = new HashMap<>();
|
||||||
Map<String, Integer> platformMap = new HashMap<>();
|
Map<String, Integer> platformMap = new HashMap<>();
|
||||||
platformMap.put(platformType.getPlatformName(), 1);
|
platformMap.put(platformType.platformName(), 1);
|
||||||
versionMap.put(minecraftVersion, platformMap);
|
versionMap.put(minecraftVersion, platformMap);
|
||||||
|
|
||||||
metrics.addCustomChart(new Metrics.DrilldownPie("minecraftServerVersion", () -> {
|
metrics.addCustomChart(new Metrics.DrilldownPie("minecraftServerVersion", () -> {
|
||||||
|
@ -543,6 +529,8 @@ public class GeyserImpl implements GeyserApi {
|
||||||
if (config.isNotifyOnNewBedrockUpdate()) {
|
if (config.isNotifyOnNewBedrockUpdate()) {
|
||||||
VersionCheckUtils.checkForGeyserUpdate(this::getLogger);
|
VersionCheckUtils.checkForGeyserUpdate(this::getLogger);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VersionCheckUtils.checkForOutdatedJava(logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -623,7 +611,7 @@ public class GeyserImpl implements GeyserApi {
|
||||||
this.erosionUnixListener.close();
|
this.erosionUnixListener.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
ResourcePack.PACKS.clear();
|
Registries.RESOURCE_PACKS.get().clear();
|
||||||
|
|
||||||
this.eventBus.fire(new GeyserShutdownEvent(this.extensionManager, this.eventBus));
|
this.eventBus.fire(new GeyserShutdownEvent(this.extensionManager, this.eventBus));
|
||||||
this.extensionManager.disableExtensions();
|
this.extensionManager.disableExtensions();
|
||||||
|
@ -682,6 +670,24 @@ public class GeyserImpl implements GeyserApi {
|
||||||
return getConfig().getBedrock();
|
return getConfig().getBedrock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NonNull
|
||||||
|
public Path configDirectory() {
|
||||||
|
return bootstrap.getConfigFolder();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NonNull
|
||||||
|
public Path packDirectory() {
|
||||||
|
return bootstrap.getConfigFolder().resolve("packs");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NonNull
|
||||||
|
public PlatformType platformType() {
|
||||||
|
return platformType;
|
||||||
|
}
|
||||||
|
|
||||||
public int buildNumber() {
|
public int buildNumber() {
|
||||||
if (!this.isProductionEnvironment()) {
|
if (!this.isProductionEnvironment()) {
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -29,22 +29,38 @@ import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
import org.geysermc.geyser.api.util.PlatformType;
|
||||||
import org.geysermc.geyser.GeyserImpl;
|
import org.geysermc.geyser.GeyserImpl;
|
||||||
import org.geysermc.geyser.api.command.Command;
|
import org.geysermc.geyser.api.command.Command;
|
||||||
import org.geysermc.geyser.api.command.CommandExecutor;
|
import org.geysermc.geyser.api.command.CommandExecutor;
|
||||||
import org.geysermc.geyser.api.command.CommandSource;
|
import org.geysermc.geyser.api.command.CommandSource;
|
||||||
import org.geysermc.geyser.api.event.lifecycle.GeyserDefineCommandsEvent;
|
import org.geysermc.geyser.api.event.lifecycle.GeyserDefineCommandsEvent;
|
||||||
import org.geysermc.geyser.api.extension.Extension;
|
import org.geysermc.geyser.api.extension.Extension;
|
||||||
import org.geysermc.geyser.command.defaults.*;
|
import org.geysermc.geyser.command.defaults.AdvancedTooltipsCommand;
|
||||||
|
import org.geysermc.geyser.command.defaults.AdvancementsCommand;
|
||||||
|
import org.geysermc.geyser.command.defaults.ConnectionTestCommand;
|
||||||
|
import org.geysermc.geyser.command.defaults.DumpCommand;
|
||||||
|
import org.geysermc.geyser.command.defaults.ExtensionsCommand;
|
||||||
|
import org.geysermc.geyser.command.defaults.HelpCommand;
|
||||||
|
import org.geysermc.geyser.command.defaults.ListCommand;
|
||||||
|
import org.geysermc.geyser.command.defaults.OffhandCommand;
|
||||||
|
import org.geysermc.geyser.command.defaults.ReloadCommand;
|
||||||
|
import org.geysermc.geyser.command.defaults.SettingsCommand;
|
||||||
|
import org.geysermc.geyser.command.defaults.StatisticsCommand;
|
||||||
|
import org.geysermc.geyser.command.defaults.StopCommand;
|
||||||
|
import org.geysermc.geyser.command.defaults.VersionCommand;
|
||||||
import org.geysermc.geyser.event.type.GeyserDefineCommandsEventImpl;
|
import org.geysermc.geyser.event.type.GeyserDefineCommandsEventImpl;
|
||||||
import org.geysermc.geyser.extension.command.GeyserExtensionCommand;
|
import org.geysermc.geyser.extension.command.GeyserExtensionCommand;
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
import org.geysermc.geyser.text.GeyserLocale;
|
import org.geysermc.geyser.text.GeyserLocale;
|
||||||
import org.geysermc.geyser.util.PlatformType;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class GeyserCommandManager {
|
public class GeyserCommandManager {
|
||||||
|
@ -91,7 +107,8 @@ public class GeyserCommandManager {
|
||||||
|
|
||||||
// Register help commands for all extensions with commands
|
// Register help commands for all extensions with commands
|
||||||
for (Map.Entry<Extension, Map<String, Command>> entry : this.extensionCommands.entrySet()) {
|
for (Map.Entry<Extension, Map<String, Command>> entry : this.extensionCommands.entrySet()) {
|
||||||
registerExtensionCommand(entry.getKey(), new HelpCommand(this.geyser, "help", "geyser.commands.exthelp.desc", "geyser.command.exthelp", entry.getKey().description().id(), entry.getValue()));
|
String id = entry.getKey().description().id();
|
||||||
|
registerExtensionCommand(entry.getKey(), new HelpCommand(this.geyser, "help", "geyser.commands.exthelp.desc", "geyser.command.exthelp." + id, id, entry.getValue()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,7 @@ package org.geysermc.geyser.command.defaults;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
import org.geysermc.geyser.GeyserImpl;
|
import org.geysermc.geyser.GeyserImpl;
|
||||||
|
import org.geysermc.geyser.api.util.PlatformType;
|
||||||
import org.geysermc.geyser.command.GeyserCommand;
|
import org.geysermc.geyser.command.GeyserCommand;
|
||||||
import org.geysermc.geyser.command.GeyserCommandSource;
|
import org.geysermc.geyser.command.GeyserCommandSource;
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
|
@ -36,11 +37,20 @@ import org.geysermc.geyser.util.PlatformType;
|
||||||
import org.geysermc.geyser.util.WebUtils;
|
import org.geysermc.geyser.util.WebUtils;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.Random;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
public class ConnectionTestCommand extends GeyserCommand {
|
public class ConnectionTestCommand extends GeyserCommand {
|
||||||
|
/*
|
||||||
|
* The MOTD is temporarily changed during the connection test.
|
||||||
|
* This allows us to check if we are pinging the correct Geyser instance
|
||||||
|
*/
|
||||||
|
public static String CONNECTION_TEST_MOTD = null;
|
||||||
|
|
||||||
private final GeyserImpl geyser;
|
private final GeyserImpl geyser;
|
||||||
|
|
||||||
|
private final Random random = new Random();
|
||||||
|
|
||||||
public ConnectionTestCommand(GeyserImpl geyser, String name, String description, String permission) {
|
public ConnectionTestCommand(GeyserImpl geyser, String name, String description, String permission) {
|
||||||
super(name, description, permission);
|
super(name, description, permission);
|
||||||
this.geyser = geyser;
|
this.geyser = geyser;
|
||||||
|
@ -55,23 +65,61 @@ public class ConnectionTestCommand extends GeyserCommand {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args.length == 0) {
|
if (args.length == 0) {
|
||||||
sender.sendMessage("Provide the Bedrock server IP you are trying to connect with. Example: `test.geysermc.org:19132`");
|
sender.sendMessage("Provide the server IP and port you are trying to test Bedrock connections for. Example: `test.geysermc.org:19132`");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Replace "<" and ">" symbols if they are present to avoid the common issue of people including them
|
||||||
|
String[] fullAddress = args[0].replace("<", "").replace(">", "").split(":", 2);
|
||||||
|
|
||||||
// Still allow people to not supply a port and fallback to 19132
|
// Still allow people to not supply a port and fallback to 19132
|
||||||
String[] fullAddress = args[0].split(":", 2);
|
|
||||||
int port;
|
int port;
|
||||||
if (fullAddress.length == 2) {
|
if (fullAddress.length == 2) {
|
||||||
|
try {
|
||||||
port = Integer.parseInt(fullAddress[1]);
|
port = Integer.parseInt(fullAddress[1]);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
// can occur if e.g. "/geyser connectiontest <ip>:<port> is ran
|
||||||
|
sender.sendMessage("Not a valid port! Specify a valid numeric port.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
port = 19132;
|
port = 19132;
|
||||||
}
|
}
|
||||||
|
String ip = fullAddress[0];
|
||||||
|
|
||||||
|
// Issue: people commonly checking placeholders
|
||||||
|
if (ip.equals("ip")) {
|
||||||
|
sender.sendMessage(ip + " is not a valid IP, and instead a placeholder. Please specify the IP to check.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Issue: checking 0.0.0.0 won't work
|
||||||
|
if (ip.equals("0.0.0.0")) {
|
||||||
|
sender.sendMessage("Please specify the IP that you would connect with. 0.0.0.0 in the config tells Geyser to the listen on the server's IPv4.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Issue: people testing local ip
|
||||||
|
if (ip.equals("localhost") || ip.startsWith("127.") || ip.startsWith("10.") || ip.startsWith("192.168.")) {
|
||||||
|
sender.sendMessage("This tool checks if connections from other networks are possible, so you cannot check a local IP.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Issue: do the ports not line up?
|
// Issue: do the ports not line up?
|
||||||
if (port != geyser.getConfig().getBedrock().port()) {
|
if (port != geyser.getConfig().getBedrock().port()) {
|
||||||
sender.sendMessage("The port you supplied (" + port + ") does not match the port supplied in Geyser's configuration ("
|
if (fullAddress.length == 2) {
|
||||||
+ geyser.getConfig().getBedrock().port() + "). You can change it under `bedrock` `port`.");
|
sender.sendMessage("The port you are testing with (" + port + ") is not the same as you set in your Geyser configuration ("
|
||||||
|
+ geyser.getConfig().getBedrock().port() + ")");
|
||||||
|
sender.sendMessage("Re-run the command with the port in the config, or change the `bedrock` `port` in the config.");
|
||||||
|
if (geyser.getConfig().getBedrock().isCloneRemotePort()) {
|
||||||
|
sender.sendMessage("You have `clone-remote-port` enabled. This option ignores the `bedrock` `port` in the config, and uses the Java server port instead.");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sender.sendMessage("You did not specify the port to check (add it with \":<port>\"), " +
|
||||||
|
"and the default port 19132 does not match the port in your Geyser configuration ("
|
||||||
|
+ geyser.getConfig().getBedrock().port() + ")!");
|
||||||
|
sender.sendMessage("Re-run the command with that port, or change the port in the config under `bedrock` `port`.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Issue: is the `bedrock` `address` in the config different?
|
// Issue: is the `bedrock` `address` in the config different?
|
||||||
|
@ -79,7 +127,7 @@ public class ConnectionTestCommand extends GeyserCommand {
|
||||||
sender.sendMessage("The address specified in `bedrock` `address` is not \"0.0.0.0\" - this may cause issues unless this is deliberate and intentional.");
|
sender.sendMessage("The address specified in `bedrock` `address` is not \"0.0.0.0\" - this may cause issues unless this is deliberate and intentional.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Issue: did someone turn on enable-proxy-protocol and they didn't mean it?
|
// Issue: did someone turn on enable-proxy-protocol, and they didn't mean it?
|
||||||
if (geyser.getConfig().getBedrock().isEnableProxyProtocol()) {
|
if (geyser.getConfig().getBedrock().isEnableProxyProtocol()) {
|
||||||
sender.sendMessage("You have the `enable-proxy-protocol` setting enabled. " +
|
sender.sendMessage("You have the `enable-proxy-protocol` setting enabled. " +
|
||||||
"Unless you're deliberately using additional software that REQUIRES this setting, you may not need it enabled.");
|
"Unless you're deliberately using additional software that REQUIRES this setting, you may not need it enabled.");
|
||||||
|
@ -88,7 +136,6 @@ public class ConnectionTestCommand extends GeyserCommand {
|
||||||
CompletableFuture.runAsync(() -> {
|
CompletableFuture.runAsync(() -> {
|
||||||
try {
|
try {
|
||||||
// Issue: SRV record?
|
// Issue: SRV record?
|
||||||
String ip = fullAddress[0];
|
|
||||||
String[] record = WebUtils.findSrvRecord(geyser, ip);
|
String[] record = WebUtils.findSrvRecord(geyser, ip);
|
||||||
if (record != null && !ip.equals(record[3]) && !record[2].equals(String.valueOf(port))) {
|
if (record != null && !ip.equals(record[3]) && !record[2].equals(String.valueOf(port))) {
|
||||||
sender.sendMessage("Bedrock Edition does not support SRV records. Try connecting to your server using the address " + record[3] + " and the port " + record[2]
|
sender.sendMessage("Bedrock Edition does not support SRV records. Try connecting to your server using the address " + record[3] + " and the port " + record[2]
|
||||||
|
@ -102,20 +149,50 @@ public class ConnectionTestCommand extends GeyserCommand {
|
||||||
"See here for steps on how to resolve: " + "https://wiki.geysermc.org/geyser/fixing-unable-to-connect-to-world/#using-geyser-on-the-same-computer");
|
"See here for steps on how to resolve: " + "https://wiki.geysermc.org/geyser/fixing-unable-to-connect-to-world/#using-geyser-on-the-same-computer");
|
||||||
}
|
}
|
||||||
|
|
||||||
// mcsrvstatus will likely be replaced in the future with our own service where we can also test
|
// Generate some random, unique bits that another server wouldn't provide
|
||||||
// around the OVH workaround without worrying about caching
|
byte[] randomBytes = new byte[2];
|
||||||
JsonNode output = WebUtils.getJson("https://api.mcsrvstat.us/bedrock/2/" + args[0]);
|
this.random.nextBytes(randomBytes);
|
||||||
|
StringBuilder randomStr = new StringBuilder();
|
||||||
|
for (byte b : randomBytes) {
|
||||||
|
randomStr.append(Integer.toHexString(b));
|
||||||
|
}
|
||||||
|
String connectionTestMotd = "Geyser Connection Test " + randomStr;
|
||||||
|
CONNECTION_TEST_MOTD = connectionTestMotd;
|
||||||
|
|
||||||
long cacheTime = output.get("debug").get("cachetime").asLong();
|
sender.sendMessage("Testing server connection now. Please wait...");
|
||||||
String when;
|
JsonNode output;
|
||||||
if (cacheTime == 0) {
|
try {
|
||||||
when = "now";
|
output = WebUtils.getJson("https://checker.geysermc.org/ping?hostname=" + ip + "&port=" + port);
|
||||||
} else {
|
} finally {
|
||||||
when = ((System.currentTimeMillis() / 1000L) - cacheTime) + " seconds ago";
|
CONNECTION_TEST_MOTD = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (output.get("online").asBoolean()) {
|
JsonNode cache = output.get("cache");
|
||||||
sender.sendMessage("Your server is likely online as of " + when + "!");
|
String when;
|
||||||
|
if (cache.get("fromCache").asBoolean()) {
|
||||||
|
when = cache.get("secondsSince").asInt() + " seconds ago";
|
||||||
|
} else {
|
||||||
|
when = "now";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (output.get("success").asBoolean()) {
|
||||||
|
JsonNode ping = output.get("ping");
|
||||||
|
JsonNode pong = ping.get("pong");
|
||||||
|
String remoteMotd = pong.get("motd").asText();
|
||||||
|
if (!connectionTestMotd.equals(remoteMotd)) {
|
||||||
|
sender.sendMessage("The MOTD did not match when we pinged the server (we got '" + remoteMotd + "'). " +
|
||||||
|
"Did you supply the correct IP and port of your server?");
|
||||||
|
sendLinks(sender);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ping.get("tcpFirst").asBoolean()) {
|
||||||
|
sender.sendMessage("Your server hardware likely has some sort of firewall preventing people from joining easily. See https://geysermc.link/ovh-firewall for more information.");
|
||||||
|
sendLinks(sender);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sender.sendMessage("Your server is likely online and working as of " + when + "!");
|
||||||
sendLinks(sender);
|
sendLinks(sender);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -123,16 +200,16 @@ public class ConnectionTestCommand extends GeyserCommand {
|
||||||
sender.sendMessage("Your server is likely unreachable from outside the network as of " + when + ".");
|
sender.sendMessage("Your server is likely unreachable from outside the network as of " + when + ".");
|
||||||
sendLinks(sender);
|
sendLinks(sender);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
sender.sendMessage("Error while trying to check your connection!");
|
sender.sendMessage("An error occurred while trying to check your connection! Check the console for more information.");
|
||||||
geyser.getLogger().error("Error while trying to check your connection!", e);
|
geyser.getLogger().error("Error while trying to check your connection!", e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendLinks(GeyserCommandSource sender) {
|
private void sendLinks(GeyserCommandSource sender) {
|
||||||
sender.sendMessage("If you still have issues, check to see if your hosting provider has a specific setup: " +
|
sender.sendMessage("If you still face issues, check the setup guide for instructions: " +
|
||||||
"https://wiki.geysermc.org/geyser/supported-hosting-providers/" + ", see this page: "
|
"https://wiki.geysermc.org/geyser/setup/");
|
||||||
+ "https://wiki.geysermc.org/geyser/fixing-unable-to-connect-to-world/" + ", or contact us on our Discord: " + "https://discord.gg/geysermc");
|
sender.sendMessage("If that does not work, see " + "https://wiki.geysermc.org/geyser/fixing-unable-to-connect-to-world/" + ", or contact us on Discord: " + "https://discord.gg/geysermc");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -30,6 +30,7 @@ import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
import org.geysermc.geyser.api.util.PlatformType;
|
||||||
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.GeyserCommandSource;
|
import org.geysermc.geyser.command.GeyserCommandSource;
|
||||||
|
@ -38,7 +39,6 @@ import org.geysermc.geyser.session.GeyserSession;
|
||||||
import org.geysermc.geyser.text.AsteriskSerializer;
|
import org.geysermc.geyser.text.AsteriskSerializer;
|
||||||
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 org.geysermc.geyser.util.PlatformType;
|
|
||||||
import org.geysermc.geyser.util.WebUtils;
|
import org.geysermc.geyser.util.WebUtils;
|
||||||
|
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
|
|
||||||
package org.geysermc.geyser.command.defaults;
|
package org.geysermc.geyser.command.defaults;
|
||||||
|
|
||||||
|
import org.geysermc.geyser.api.util.PlatformType;
|
||||||
import org.geysermc.geyser.GeyserImpl;
|
import org.geysermc.geyser.GeyserImpl;
|
||||||
import org.geysermc.geyser.api.command.Command;
|
import org.geysermc.geyser.api.command.Command;
|
||||||
import org.geysermc.geyser.command.GeyserCommand;
|
import org.geysermc.geyser.command.GeyserCommand;
|
||||||
|
@ -32,7 +33,6 @@ import org.geysermc.geyser.command.GeyserCommandSource;
|
||||||
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 org.geysermc.geyser.util.PlatformType;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -63,7 +63,8 @@ public class HelpCommand extends GeyserCommand {
|
||||||
public void execute(GeyserSession session, GeyserCommandSource sender, String[] args) {
|
public void execute(GeyserSession session, GeyserCommandSource sender, String[] args) {
|
||||||
int page = 1;
|
int page = 1;
|
||||||
int maxPage = 1;
|
int maxPage = 1;
|
||||||
String header = GeyserLocale.getPlayerLocaleString("geyser.commands.help.header", sender.locale(), page, maxPage);
|
String translationKey = this.baseCommand.equals("geyser") ? "geyser.commands.help.header" : "geyser.commands.extensions.header";
|
||||||
|
String header = GeyserLocale.getPlayerLocaleString(translationKey, sender.locale(), page, maxPage);
|
||||||
sender.sendMessage(header);
|
sender.sendMessage(header);
|
||||||
|
|
||||||
this.commands.entrySet().stream().sorted(Map.Entry.comparingByKey()).forEach(entry -> {
|
this.commands.entrySet().stream().sorted(Map.Entry.comparingByKey()).forEach(entry -> {
|
||||||
|
|
|
@ -25,12 +25,12 @@
|
||||||
|
|
||||||
package org.geysermc.geyser.command.defaults;
|
package org.geysermc.geyser.command.defaults;
|
||||||
|
|
||||||
|
import org.geysermc.geyser.api.util.PlatformType;
|
||||||
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.GeyserCommandSource;
|
import org.geysermc.geyser.command.GeyserCommandSource;
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
import org.geysermc.geyser.text.GeyserLocale;
|
import org.geysermc.geyser.text.GeyserLocale;
|
||||||
import org.geysermc.geyser.util.PlatformType;
|
|
||||||
|
|
||||||
public class ReloadCommand extends GeyserCommand {
|
public class ReloadCommand extends GeyserCommand {
|
||||||
|
|
||||||
|
|
|
@ -25,12 +25,12 @@
|
||||||
|
|
||||||
package org.geysermc.geyser.command.defaults;
|
package org.geysermc.geyser.command.defaults;
|
||||||
|
|
||||||
|
import org.geysermc.geyser.api.util.PlatformType;
|
||||||
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.GeyserCommandSource;
|
import org.geysermc.geyser.command.GeyserCommandSource;
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
import org.geysermc.geyser.text.GeyserLocale;
|
import org.geysermc.geyser.text.GeyserLocale;
|
||||||
import org.geysermc.geyser.util.PlatformType;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,8 @@
|
||||||
package org.geysermc.geyser.command.defaults;
|
package org.geysermc.geyser.command.defaults;
|
||||||
|
|
||||||
import org.cloudburstmc.protocol.bedrock.codec.BedrockCodec;
|
import org.cloudburstmc.protocol.bedrock.codec.BedrockCodec;
|
||||||
|
import org.geysermc.geyser.Constants;
|
||||||
|
import org.geysermc.geyser.api.util.PlatformType;
|
||||||
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.GeyserCommandSource;
|
import org.geysermc.geyser.command.GeyserCommandSource;
|
||||||
|
@ -33,7 +35,6 @@ import org.geysermc.geyser.network.GameProtocol;
|
||||||
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 org.geysermc.geyser.util.PlatformType;
|
|
||||||
import org.geysermc.geyser.util.WebUtils;
|
import org.geysermc.geyser.util.WebUtils;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -84,7 +85,7 @@ public class VersionCommand extends GeyserCommand {
|
||||||
sender.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.commands.version.no_updates", sender.locale()));
|
sender.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.commands.version.no_updates", sender.locale()));
|
||||||
} else {
|
} else {
|
||||||
sender.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.commands.version.outdated",
|
sender.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.commands.version.outdated",
|
||||||
sender.locale(), (latestBuildNum - buildNum), "https://ci.geysermc.org/"));
|
sender.locale(), (latestBuildNum - buildNum), Constants.GEYSER_DOWNLOAD_LOCATION));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new AssertionError("buildNumber missing");
|
throw new AssertionError("buildNumber missing");
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
/*
|
||||||
|
* 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.configuration;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
|
@SuppressWarnings("FieldMayBeFinal") // Jackson requires that the fields are not final
|
||||||
|
public class GeyserCustomSkullConfiguration {
|
||||||
|
@JsonProperty("player-usernames")
|
||||||
|
private List<String> playerUsernames;
|
||||||
|
|
||||||
|
@JsonProperty("player-uuids")
|
||||||
|
private List<String> playerUUIDs;
|
||||||
|
|
||||||
|
@JsonProperty("player-profiles")
|
||||||
|
private List<String> playerProfiles;
|
||||||
|
|
||||||
|
@JsonProperty("skin-hashes")
|
||||||
|
private List<String> skinHashes;
|
||||||
|
|
||||||
|
public List<String> getPlayerUsernames() {
|
||||||
|
return Objects.requireNonNullElse(playerUsernames, Collections.emptyList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getPlayerUUIDs() {
|
||||||
|
return Objects.requireNonNullElse(playerUUIDs, Collections.emptyList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getPlayerProfiles() {
|
||||||
|
return Objects.requireNonNullElse(playerProfiles, Collections.emptyList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getPlayerSkinHashes() {
|
||||||
|
return Objects.requireNonNullElse(skinHashes, Collections.emptyList());
|
||||||
|
}
|
||||||
|
}
|
|
@ -282,6 +282,11 @@ public abstract class GeyserJacksonConfiguration implements GeyserConfiguration
|
||||||
return authType;
|
return authType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean resolveSrv() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@JsonProperty("allow-password-authentication")
|
@JsonProperty("allow-password-authentication")
|
||||||
private boolean passwordAuthentication = true;
|
private boolean passwordAuthentication = true;
|
||||||
|
|
|
@ -27,9 +27,9 @@ package org.geysermc.geyser.dump;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
import org.geysermc.geyser.api.util.PlatformType;
|
||||||
import org.geysermc.geyser.GeyserImpl;
|
import org.geysermc.geyser.GeyserImpl;
|
||||||
import org.geysermc.geyser.text.AsteriskSerializer;
|
import org.geysermc.geyser.text.AsteriskSerializer;
|
||||||
import org.geysermc.geyser.util.PlatformType;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
|
|
@ -104,6 +104,7 @@ public final class EntityDefinitions {
|
||||||
public static final EntityDefinition<HorseEntity> HORSE;
|
public static final EntityDefinition<HorseEntity> HORSE;
|
||||||
public static final EntityDefinition<ZombieEntity> HUSK;
|
public static final EntityDefinition<ZombieEntity> HUSK;
|
||||||
public static final EntityDefinition<SpellcasterIllagerEntity> ILLUSIONER; // Not present on Bedrock
|
public static final EntityDefinition<SpellcasterIllagerEntity> ILLUSIONER; // Not present on Bedrock
|
||||||
|
public static final EntityDefinition<InteractionEntity> INTERACTION;
|
||||||
public static final EntityDefinition<IronGolemEntity> IRON_GOLEM;
|
public static final EntityDefinition<IronGolemEntity> IRON_GOLEM;
|
||||||
public static final EntityDefinition<ItemEntity> ITEM;
|
public static final EntityDefinition<ItemEntity> ITEM;
|
||||||
public static final EntityDefinition<ItemFrameEntity> ITEM_FRAME;
|
public static final EntityDefinition<ItemFrameEntity> ITEM_FRAME;
|
||||||
|
@ -133,6 +134,7 @@ public final class EntityDefinitions {
|
||||||
public static final EntityDefinition<AbstractFishEntity> SALMON;
|
public static final EntityDefinition<AbstractFishEntity> SALMON;
|
||||||
public static final EntityDefinition<SheepEntity> SHEEP;
|
public static final EntityDefinition<SheepEntity> SHEEP;
|
||||||
public static final EntityDefinition<ShulkerEntity> SHULKER;
|
public static final EntityDefinition<ShulkerEntity> SHULKER;
|
||||||
|
public static final EntityDefinition<SnifferEntity> SNIFFER;
|
||||||
public static final EntityDefinition<ThrowableEntity> SHULKER_BULLET;
|
public static final EntityDefinition<ThrowableEntity> SHULKER_BULLET;
|
||||||
public static final EntityDefinition<MonsterEntity> SILVERFISH;
|
public static final EntityDefinition<MonsterEntity> SILVERFISH;
|
||||||
public static final EntityDefinition<SkeletonEntity> SKELETON;
|
public static final EntityDefinition<SkeletonEntity> SKELETON;
|
||||||
|
@ -235,7 +237,7 @@ public final class EntityDefinitions {
|
||||||
.type(EntityType.EXPERIENCE_ORB)
|
.type(EntityType.EXPERIENCE_ORB)
|
||||||
.identifier("minecraft:xp_orb")
|
.identifier("minecraft:xp_orb")
|
||||||
.build();
|
.build();
|
||||||
EVOKER_FANGS = EntityDefinition.builder(EvokerFangsEntity::new) // No entity metadata to listen to as of 1.18.1
|
EVOKER_FANGS = EntityDefinition.inherited(EvokerFangsEntity::new, entityBase)
|
||||||
.type(EntityType.EVOKER_FANGS)
|
.type(EntityType.EVOKER_FANGS)
|
||||||
.height(0.8f).width(0.5f)
|
.height(0.8f).width(0.5f)
|
||||||
.identifier("minecraft:evocation_fang")
|
.identifier("minecraft:evocation_fang")
|
||||||
|
@ -318,6 +320,15 @@ public final class EntityDefinitions {
|
||||||
.addTranslator(MetadataType.CHAT, TextDisplayEntity::setText)
|
.addTranslator(MetadataType.CHAT, TextDisplayEntity::setText)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
INTERACTION = EntityDefinition.inherited(InteractionEntity::new, entityBase)
|
||||||
|
.type(EntityType.INTERACTION)
|
||||||
|
.heightAndWidth(1.0f) // default size until server specifies otherwise
|
||||||
|
.identifier("minecraft:armor_stand")
|
||||||
|
.addTranslator(MetadataType.FLOAT, InteractionEntity::setWidth)
|
||||||
|
.addTranslator(MetadataType.FLOAT, InteractionEntity::setHeight)
|
||||||
|
.addTranslator(MetadataType.BOOLEAN, InteractionEntity::setResponse)
|
||||||
|
.build();
|
||||||
|
|
||||||
EntityDefinition<FireballEntity> fireballBase = EntityDefinition.inherited(FireballEntity::new, entityBase)
|
EntityDefinition<FireballEntity> fireballBase = EntityDefinition.inherited(FireballEntity::new, entityBase)
|
||||||
.addTranslator(null) // Item
|
.addTranslator(null) // Item
|
||||||
.build();
|
.build();
|
||||||
|
@ -777,7 +788,7 @@ public final class EntityDefinitions {
|
||||||
.build();
|
.build();
|
||||||
FOX = EntityDefinition.inherited(FoxEntity::new, ageableEntityBase)
|
FOX = EntityDefinition.inherited(FoxEntity::new, ageableEntityBase)
|
||||||
.type(EntityType.FOX)
|
.type(EntityType.FOX)
|
||||||
.height(0.5f).width(1.25f)
|
.height(0.7f).width(0.6f)
|
||||||
.addTranslator(MetadataType.INT, FoxEntity::setFoxVariant)
|
.addTranslator(MetadataType.INT, FoxEntity::setFoxVariant)
|
||||||
.addTranslator(MetadataType.BYTE, FoxEntity::setFoxFlags)
|
.addTranslator(MetadataType.BYTE, FoxEntity::setFoxFlags)
|
||||||
.addTranslator(null) // Trusted player 1
|
.addTranslator(null) // Trusted player 1
|
||||||
|
@ -842,6 +853,12 @@ public final class EntityDefinitions {
|
||||||
.height(1.3f).width(0.9f)
|
.height(1.3f).width(0.9f)
|
||||||
.addTranslator(MetadataType.BYTE, SheepEntity::setSheepFlags)
|
.addTranslator(MetadataType.BYTE, SheepEntity::setSheepFlags)
|
||||||
.build();
|
.build();
|
||||||
|
SNIFFER = EntityDefinition.inherited(SnifferEntity::new, ageableEntityBase)
|
||||||
|
.type(EntityType.SNIFFER)
|
||||||
|
.height(1.75f).width(1.9f)
|
||||||
|
.addTranslator(MetadataType.SNIFFER_STATE, SnifferEntity::setSnifferState)
|
||||||
|
.addTranslator(null) // Integer, drop seed at tick
|
||||||
|
.build();
|
||||||
STRIDER = EntityDefinition.inherited(StriderEntity::new, ageableEntityBase)
|
STRIDER = EntityDefinition.inherited(StriderEntity::new, ageableEntityBase)
|
||||||
.type(EntityType.STRIDER)
|
.type(EntityType.STRIDER)
|
||||||
.height(1.7f).width(0.9f)
|
.height(1.7f).width(0.9f)
|
||||||
|
@ -884,7 +901,6 @@ public final class EntityDefinitions {
|
||||||
.build();
|
.build();
|
||||||
CAMEL = EntityDefinition.inherited(CamelEntity::new, abstractHorseEntityBase)
|
CAMEL = EntityDefinition.inherited(CamelEntity::new, abstractHorseEntityBase)
|
||||||
.type(EntityType.CAMEL)
|
.type(EntityType.CAMEL)
|
||||||
.identifier("minecraft:llama") // todo 1.20
|
|
||||||
.height(2.375f).width(1.7f)
|
.height(2.375f).width(1.7f)
|
||||||
.addTranslator(MetadataType.BOOLEAN, CamelEntity::setDashing)
|
.addTranslator(MetadataType.BOOLEAN, CamelEntity::setDashing)
|
||||||
.addTranslator(null) // Last pose change tick
|
.addTranslator(null) // Last pose change tick
|
||||||
|
|
|
@ -66,7 +66,7 @@ public class BoatEntity extends Entity {
|
||||||
private int variant;
|
private int variant;
|
||||||
|
|
||||||
// Looks too fast and too choppy with 0.1f, which is how I believe the Microsoftian client handles it
|
// Looks too fast and too choppy with 0.1f, which is how I believe the Microsoftian client handles it
|
||||||
private final float ROWING_SPEED = 0.05f;
|
private final float ROWING_SPEED = 0.1f;
|
||||||
|
|
||||||
public BoatEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
public BoatEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
||||||
// Initial rotation is incorrect
|
// Initial rotation is incorrect
|
||||||
|
@ -125,8 +125,8 @@ public class BoatEntity extends Entity {
|
||||||
public void setVariant(IntEntityMetadata entityMetadata) {
|
public void setVariant(IntEntityMetadata entityMetadata) {
|
||||||
variant = entityMetadata.getPrimitiveValue();
|
variant = entityMetadata.getPrimitiveValue();
|
||||||
dirtyMetadata.put(EntityDataTypes.VARIANT, switch (variant) {
|
dirtyMetadata.put(EntityDataTypes.VARIANT, switch (variant) {
|
||||||
case 6, 7 -> variant - 1; // Dark oak and mangrove
|
case 6, 7, 8 -> variant - 1; // dark_oak, mangrove, bamboo
|
||||||
case 5, 8 -> 0; // TODO temp until 1.20. Cherry and bamboo
|
case 5 -> 8; // cherry
|
||||||
default -> variant;
|
default -> variant;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,7 @@ import lombok.AccessLevel;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
|
import org.cloudburstmc.math.vector.Vector2f;
|
||||||
import org.cloudburstmc.math.vector.Vector3f;
|
import org.cloudburstmc.math.vector.Vector3f;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
|
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.entity.EntityEventType;
|
import org.cloudburstmc.protocol.bedrock.data.entity.EntityEventType;
|
||||||
|
@ -171,7 +172,9 @@ public class Entity implements GeyserEntity {
|
||||||
addEntityPacket.setUniqueEntityId(geyserId);
|
addEntityPacket.setUniqueEntityId(geyserId);
|
||||||
addEntityPacket.setPosition(position);
|
addEntityPacket.setPosition(position);
|
||||||
addEntityPacket.setMotion(motion);
|
addEntityPacket.setMotion(motion);
|
||||||
addEntityPacket.setRotation(getBedrockRotation().toVector2(false)); // TODO: Check this
|
addEntityPacket.setRotation(Vector2f.from(pitch, yaw));
|
||||||
|
addEntityPacket.setHeadRotation(headYaw);
|
||||||
|
addEntityPacket.setBodyRotation(yaw); // TODO: This should be bodyYaw
|
||||||
addEntityPacket.getMetadata().putFlags(flags);
|
addEntityPacket.getMetadata().putFlags(flags);
|
||||||
dirtyMetadata.apply(addEntityPacket.getMetadata());
|
dirtyMetadata.apply(addEntityPacket.getMetadata());
|
||||||
addAdditionalSpawnData(addEntityPacket);
|
addAdditionalSpawnData(addEntityPacket);
|
||||||
|
@ -490,9 +493,10 @@ public class Entity implements GeyserEntity {
|
||||||
* Update the mount offsets of each passenger on this vehicle
|
* Update the mount offsets of each passenger on this vehicle
|
||||||
*/
|
*/
|
||||||
protected void updatePassengerOffsets() {
|
protected void updatePassengerOffsets() {
|
||||||
for (Entity passenger : passengers) {
|
for (int i = 0; i < passengers.size(); i++) {
|
||||||
|
Entity passenger = passengers.get(i);
|
||||||
if (passenger != null) {
|
if (passenger != null) {
|
||||||
boolean rider = passengers.get(0) == this;
|
boolean rider = i == 0;
|
||||||
EntityUtils.updateMountOffset(passenger, this, rider, true, passengers.size() > 1);
|
EntityUtils.updateMountOffset(passenger, this, rider, true, passengers.size() > 1);
|
||||||
passenger.updateBedrockMetadata();
|
passenger.updateBedrockMetadata();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.entity.type;
|
||||||
|
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.FloatEntityMetadata;
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
|
||||||
|
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundSwingPacket;
|
||||||
|
import org.cloudburstmc.math.vector.Vector3f;
|
||||||
|
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
|
||||||
|
import org.cloudburstmc.protocol.bedrock.packet.AnimatePacket;
|
||||||
|
import org.geysermc.geyser.entity.EntityDefinition;
|
||||||
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
|
import org.geysermc.geyser.util.InteractionResult;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class InteractionEntity extends Entity {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* true - java client hears swing sound when attacking, and arm swings when right-clicking
|
||||||
|
* false - java client hears no swing sound when attacking, and arm does not swing when right-clicking
|
||||||
|
*/
|
||||||
|
private boolean response = false;
|
||||||
|
|
||||||
|
public InteractionEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
||||||
|
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void initializeMetadata() {
|
||||||
|
super.initializeMetadata();
|
||||||
|
|
||||||
|
// hide the armor stand but keep the hitbox active
|
||||||
|
setFlag(EntityFlag.INVISIBLE, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InteractionResult interact(Hand hand) {
|
||||||
|
// these InteractionResults do mirror the java client
|
||||||
|
// but the bedrock client won't arm swing itself because of our armor stand workaround
|
||||||
|
if (response) {
|
||||||
|
AnimatePacket animatePacket = new AnimatePacket();
|
||||||
|
animatePacket.setRuntimeEntityId(session.getPlayerEntity().getGeyserId());
|
||||||
|
animatePacket.setAction(AnimatePacket.Action.SWING_ARM);
|
||||||
|
session.sendUpstreamPacket(animatePacket);
|
||||||
|
|
||||||
|
session.sendDownstreamPacket(new ServerboundSwingPacket(hand));
|
||||||
|
return InteractionResult.SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
return InteractionResult.CONSUME;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWidth(FloatEntityMetadata width) {
|
||||||
|
setBoundingBoxWidth(width.getPrimitiveValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHeight(FloatEntityMetadata height) {
|
||||||
|
setBoundingBoxHeight(height.getPrimitiveValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setResponse(BooleanEntityMetadata response) {
|
||||||
|
this.response = response.getPrimitiveValue();
|
||||||
|
}
|
||||||
|
}
|
|
@ -35,7 +35,7 @@ import org.cloudburstmc.math.vector.Vector3f;
|
||||||
import org.cloudburstmc.math.vector.Vector3i;
|
import org.cloudburstmc.math.vector.Vector3i;
|
||||||
import org.cloudburstmc.nbt.NbtMap;
|
import org.cloudburstmc.nbt.NbtMap;
|
||||||
import org.cloudburstmc.nbt.NbtMapBuilder;
|
import org.cloudburstmc.nbt.NbtMapBuilder;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.defintions.BlockDefinition;
|
import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
|
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
|
||||||
import org.cloudburstmc.protocol.bedrock.packet.BlockEntityDataPacket;
|
import org.cloudburstmc.protocol.bedrock.packet.BlockEntityDataPacket;
|
||||||
import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket;
|
import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket;
|
||||||
|
@ -83,8 +83,7 @@ public class ItemFrameEntity extends Entity {
|
||||||
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
|
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
|
||||||
|
|
||||||
NbtMapBuilder blockBuilder = NbtMap.builder()
|
NbtMapBuilder blockBuilder = NbtMap.builder()
|
||||||
.putString("name", this.definition.entityType() == EntityType.GLOW_ITEM_FRAME ? "minecraft:glow_frame" : "minecraft:frame")
|
.putString("name", this.definition.entityType() == EntityType.GLOW_ITEM_FRAME ? "minecraft:glow_frame" : "minecraft:frame");
|
||||||
.putInt("version", session.getBlockMappings().getBlockStateVersion());
|
|
||||||
NbtMapBuilder statesBuilder = NbtMap.builder()
|
NbtMapBuilder statesBuilder = NbtMap.builder()
|
||||||
.putInt("facing_direction", direction.ordinal())
|
.putInt("facing_direction", direction.ordinal())
|
||||||
.putByte("item_frame_map_bit", (byte) 0)
|
.putByte("item_frame_map_bit", (byte) 0)
|
||||||
|
|
|
@ -41,7 +41,6 @@ import lombok.Setter;
|
||||||
import org.cloudburstmc.math.vector.Vector3f;
|
import org.cloudburstmc.math.vector.Vector3f;
|
||||||
import org.cloudburstmc.math.vector.Vector3i;
|
import org.cloudburstmc.math.vector.Vector3i;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.AttributeData;
|
import org.cloudburstmc.protocol.bedrock.data.AttributeData;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.defintions.ItemDefinition;
|
|
||||||
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
|
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
|
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerId;
|
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerId;
|
||||||
|
@ -211,10 +210,10 @@ public class LivingEntity extends Entity {
|
||||||
// If an entity has a banner on them, it will be in the helmet slot in Java but the chestplate spot in Bedrock
|
// If an entity has a banner on them, it will be in the helmet slot in Java but the chestplate spot in Bedrock
|
||||||
// But don't overwrite the chestplate if it isn't empty
|
// But don't overwrite the chestplate if it isn't empty
|
||||||
ItemMapping banner = session.getItemMappings().getStoredItems().banner();
|
ItemMapping banner = session.getItemMappings().getStoredItems().banner();
|
||||||
if (ItemDefinition.AIR.equals(chestplate.getDefinition()) && helmet.getDefinition().equals(banner)) {
|
if (ItemData.AIR.equals(chestplate) && helmet.getDefinition().equals(banner.getBedrockDefinition())) {
|
||||||
chestplate = this.helmet;
|
chestplate = this.helmet;
|
||||||
helmet = ItemData.AIR;
|
helmet = ItemData.AIR;
|
||||||
} else if (chestplate.getDefinition().equals(banner)) {
|
} else if (chestplate.getDefinition().equals(banner.getBedrockDefinition())) {
|
||||||
// Prevent chestplate banners from showing erroneously
|
// Prevent chestplate banners from showing erroneously
|
||||||
chestplate = ItemData.AIR;
|
chestplate = ItemData.AIR;
|
||||||
}
|
}
|
||||||
|
|
|
@ -249,7 +249,7 @@ public class ArmorStandEntity extends LivingEntity {
|
||||||
@Override
|
@Override
|
||||||
public InteractionResult interactAt(Hand hand) {
|
public InteractionResult interactAt(Hand hand) {
|
||||||
if (!isMarker && session.getPlayerInventory().getItemInHand(hand).asItem() != Items.NAME_TAG) {
|
if (!isMarker && session.getPlayerInventory().getItemInHand(hand).asItem() != Items.NAME_TAG) {
|
||||||
// Java Edition returns SUCCESS if in spectator mode, but this is overrided with an earlier check on the client
|
// Java Edition returns SUCCESS if in spectator mode, but this is overridden with an earlier check on the client
|
||||||
return InteractionResult.CONSUME;
|
return InteractionResult.CONSUME;
|
||||||
} else {
|
} else {
|
||||||
return InteractionResult.PASS;
|
return InteractionResult.PASS;
|
||||||
|
|
|
@ -0,0 +1,124 @@
|
||||||
|
/*
|
||||||
|
* 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.entity.type.living.animal;
|
||||||
|
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose;
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.SnifferState;
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ObjectEntityMetadata;
|
||||||
|
import org.cloudburstmc.math.vector.Vector3f;
|
||||||
|
import org.cloudburstmc.protocol.bedrock.data.LevelEvent;
|
||||||
|
import org.cloudburstmc.protocol.bedrock.data.SoundEvent;
|
||||||
|
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
|
||||||
|
import org.cloudburstmc.protocol.bedrock.packet.LevelEventPacket;
|
||||||
|
import org.cloudburstmc.protocol.bedrock.packet.LevelSoundEventPacket;
|
||||||
|
import org.geysermc.geyser.entity.EntityDefinition;
|
||||||
|
import org.geysermc.geyser.entity.EntityDefinitions;
|
||||||
|
import org.geysermc.geyser.entity.type.Tickable;
|
||||||
|
import org.geysermc.geyser.item.type.Item;
|
||||||
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class SnifferEntity extends AnimalEntity implements Tickable {
|
||||||
|
private static final float DIGGING_HEIGHT = EntityDefinitions.SNIFFER.height() - 0.4f;
|
||||||
|
private static final int DIG_END = 120;
|
||||||
|
private static final int DIG_START = DIG_END - 34;
|
||||||
|
|
||||||
|
private Pose pose = Pose.STANDING; // Needed to call setDimensions for DIGGING state
|
||||||
|
private int digTicks;
|
||||||
|
|
||||||
|
public SnifferEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
||||||
|
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPose(Pose pose) {
|
||||||
|
this.pose = pose;
|
||||||
|
super.setPose(pose);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void setDimensions(Pose pose) {
|
||||||
|
if (getFlag(EntityFlag.DIGGING)) {
|
||||||
|
setBoundingBoxHeight(DIGGING_HEIGHT);
|
||||||
|
setBoundingBoxWidth(definition.width());
|
||||||
|
} else {
|
||||||
|
super.setDimensions(pose);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canEat(Item item) {
|
||||||
|
return session.getTagCache().isSnifferFood(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSnifferState(ObjectEntityMetadata<SnifferState> entityMetadata) {
|
||||||
|
SnifferState snifferState = entityMetadata.getValue();
|
||||||
|
|
||||||
|
// SnifferState.SCENTING and SnifferState.IDLING not used in bedrock
|
||||||
|
// The bedrock client does the scenting animation and sound on its own
|
||||||
|
setFlag(EntityFlag.FEELING_HAPPY, snifferState == SnifferState.FEELING_HAPPY);
|
||||||
|
setFlag(EntityFlag.SCENTING, snifferState == SnifferState.SNIFFING); // SnifferState.SNIFFING -> EntityFlag.SCENTING
|
||||||
|
setFlag(EntityFlag.SEARCHING, snifferState == SnifferState.SEARCHING);
|
||||||
|
setFlag(EntityFlag.DIGGING, snifferState == SnifferState.DIGGING);
|
||||||
|
setFlag(EntityFlag.RISING, snifferState == SnifferState.RISING);
|
||||||
|
|
||||||
|
setDimensions(pose);
|
||||||
|
|
||||||
|
if (getFlag(EntityFlag.DIGGING)) {
|
||||||
|
digTicks = DIG_END;
|
||||||
|
} else {
|
||||||
|
// Handles situations where the DIGGING state is exited earlier than expected,
|
||||||
|
// such as hitting the sniffer or joining the game while it is digging
|
||||||
|
digTicks = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tick() {
|
||||||
|
// The java client renders digging particles on its own, but bedrock does not
|
||||||
|
if (digTicks > 0 && --digTicks < DIG_START && digTicks % 5 == 0) {
|
||||||
|
Vector3f rot = Vector3f.createDirectionDeg(0, -getYaw()).mul(2.25f);
|
||||||
|
Vector3f pos = getPosition().add(rot).up(0.2f).floor(); // Handle non-full blocks
|
||||||
|
int blockId = session.getBlockMappings().getBedrockBlockId(session.getGeyser().getWorldManager().getBlockAt(session, pos.toInt().down()));
|
||||||
|
|
||||||
|
LevelEventPacket levelEventPacket = new LevelEventPacket();
|
||||||
|
levelEventPacket.setType(LevelEvent.PARTICLE_DESTROY_BLOCK_NO_SOUND);
|
||||||
|
levelEventPacket.setPosition(pos);
|
||||||
|
levelEventPacket.setData(blockId);
|
||||||
|
session.sendUpstreamPacket(levelEventPacket);
|
||||||
|
|
||||||
|
if (digTicks % 10 == 0) {
|
||||||
|
LevelSoundEventPacket levelSoundEventPacket = new LevelSoundEventPacket();
|
||||||
|
levelSoundEventPacket.setSound(SoundEvent.HIT);
|
||||||
|
levelSoundEventPacket.setPosition(pos);
|
||||||
|
levelSoundEventPacket.setExtraData(blockId);
|
||||||
|
levelSoundEventPacket.setIdentifier(":");
|
||||||
|
session.sendUpstreamPacket(levelSoundEventPacket);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -27,8 +27,13 @@ package org.geysermc.geyser.entity.type.living.animal.horse;
|
||||||
|
|
||||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose;
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose;
|
||||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
|
||||||
import org.cloudburstmc.math.vector.Vector3f;
|
import org.cloudburstmc.math.vector.Vector3f;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
|
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
|
||||||
|
import org.cloudburstmc.protocol.bedrock.data.entity.EntityEventType;
|
||||||
|
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
|
||||||
|
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType;
|
||||||
|
import org.cloudburstmc.protocol.bedrock.packet.EntityEventPacket;
|
||||||
import org.geysermc.geyser.entity.EntityDefinition;
|
import org.geysermc.geyser.entity.EntityDefinition;
|
||||||
import org.geysermc.geyser.item.Items;
|
import org.geysermc.geyser.item.Items;
|
||||||
import org.geysermc.geyser.item.type.Item;
|
import org.geysermc.geyser.item.type.Item;
|
||||||
|
@ -38,16 +43,50 @@ import java.util.UUID;
|
||||||
|
|
||||||
public class CamelEntity extends AbstractHorseEntity {
|
public class CamelEntity extends AbstractHorseEntity {
|
||||||
|
|
||||||
private static final float SITTING_HEIGHT_DIFFERENCE = 1.43F;
|
public static final float SITTING_HEIGHT_DIFFERENCE = 1.43F;
|
||||||
|
|
||||||
public CamelEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
public CamelEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
|
||||||
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
|
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
|
||||||
|
|
||||||
|
dirtyMetadata.put(EntityDataTypes.CONTAINER_TYPE, (byte) ContainerType.HORSE.getId());
|
||||||
|
|
||||||
|
// Always tamed, but not indicated in horse flags
|
||||||
|
setFlag(EntityFlag.TAMED, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public void setHorseFlags(ByteEntityMetadata entityMetadata) {
|
||||||
protected void initializeMetadata() {
|
byte xd = entityMetadata.getPrimitiveValue();
|
||||||
super.initializeMetadata();
|
boolean saddled = (xd & 0x04) == 0x04;
|
||||||
this.dirtyMetadata.put(EntityDataTypes.VARIANT, 2); // Closest llama colour to camel
|
setFlag(EntityFlag.SADDLED, saddled);
|
||||||
|
setFlag(EntityFlag.EATING, (xd & 0x10) == 0x10);
|
||||||
|
setFlag(EntityFlag.STANDING, (xd & 0x20) == 0x20);
|
||||||
|
|
||||||
|
// HorseFlags
|
||||||
|
// Bred 0x10
|
||||||
|
// Eating 0x20
|
||||||
|
// Open mouth 0x80
|
||||||
|
int horseFlags = 0x0;
|
||||||
|
horseFlags = (xd & 0x40) == 0x40 ? horseFlags | 0x80 : horseFlags;
|
||||||
|
|
||||||
|
// Only set eating when we don't have mouth open so a player interaction doesn't trigger the eating animation
|
||||||
|
horseFlags = (xd & 0x10) == 0x10 && (xd & 0x40) != 0x40 ? horseFlags | 0x20 : horseFlags;
|
||||||
|
|
||||||
|
// Set the flags into the horse flags
|
||||||
|
dirtyMetadata.put(EntityDataTypes.HORSE_FLAGS, horseFlags);
|
||||||
|
|
||||||
|
// Send the eating particles
|
||||||
|
// We use the wheat metadata as static particles since Java
|
||||||
|
// doesn't send over what item was used to feed the horse
|
||||||
|
if ((xd & 0x40) == 0x40) {
|
||||||
|
EntityEventPacket entityEventPacket = new EntityEventPacket();
|
||||||
|
entityEventPacket.setRuntimeEntityId(geyserId);
|
||||||
|
entityEventPacket.setType(EntityEventType.EATING_ITEM);
|
||||||
|
entityEventPacket.setData(session.getItemMappings().getStoredItems().wheat().getBedrockDefinition().getRuntimeId() << 16);
|
||||||
|
session.sendUpstreamPacket(entityEventPacket);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shows the dash meter
|
||||||
|
setFlag(EntityFlag.CAN_DASH, saddled);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -55,10 +94,16 @@ public class CamelEntity extends AbstractHorseEntity {
|
||||||
return item == Items.CACTUS;
|
return item == Items.CACTUS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPose(Pose pose) {
|
||||||
|
setFlag(EntityFlag.SITTING, pose == Pose.SITTING);
|
||||||
|
super.setPose(pose);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void setDimensions(Pose pose) {
|
protected void setDimensions(Pose pose) {
|
||||||
if (pose == Pose.SITTING) {
|
if (pose == Pose.SITTING) {
|
||||||
setBoundingBoxWidth(definition.height() - SITTING_HEIGHT_DIFFERENCE);
|
setBoundingBoxHeight(definition.height() - SITTING_HEIGHT_DIFFERENCE);
|
||||||
setBoundingBoxWidth(definition.width());
|
setBoundingBoxWidth(definition.width());
|
||||||
} else {
|
} else {
|
||||||
super.setDimensions(pose);
|
super.setDimensions(pose);
|
||||||
|
|
|
@ -118,7 +118,7 @@ public class VillagerEntity extends AbstractMerchantEntity {
|
||||||
|
|
||||||
// The bed block
|
// The bed block
|
||||||
int blockId = session.getGeyser().getWorldManager().getBlockAt(session, bedPosition);
|
int blockId = session.getGeyser().getWorldManager().getBlockAt(session, bedPosition);
|
||||||
String fullIdentifier = BlockRegistries.JAVA_BLOCKS.getOrDefault(blockId, BlockMapping.AIR).getJavaIdentifier();
|
String fullIdentifier = BlockRegistries.JAVA_BLOCKS.getOrDefault(blockId, BlockMapping.DEFAULT).getJavaIdentifier();
|
||||||
|
|
||||||
// Set the correct position offset and rotation when sleeping
|
// Set the correct position offset and rotation when sleeping
|
||||||
int bedRotation = 0;
|
int bedRotation = 0;
|
||||||
|
|
|
@ -29,7 +29,7 @@ import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanE
|
||||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
|
||||||
import org.cloudburstmc.math.vector.Vector3f;
|
import org.cloudburstmc.math.vector.Vector3f;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.SoundEvent;
|
import org.cloudburstmc.protocol.bedrock.data.SoundEvent;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.defintions.BlockDefinition;
|
import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
|
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
|
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
|
||||||
import org.cloudburstmc.protocol.bedrock.packet.LevelSoundEvent2Packet;
|
import org.cloudburstmc.protocol.bedrock.packet.LevelSoundEvent2Packet;
|
||||||
|
|
|
@ -30,6 +30,7 @@ import com.github.steveice10.mc.protocol.data.game.entity.attribute.AttributeTyp
|
||||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.GlobalPos;
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.GlobalPos;
|
||||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose;
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose;
|
||||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode;
|
||||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import org.cloudburstmc.math.vector.Vector3f;
|
import org.cloudburstmc.math.vector.Vector3f;
|
||||||
|
@ -67,10 +68,6 @@ public class SessionPlayerEntity extends PlayerEntity {
|
||||||
*/
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
private boolean isRidingInFront;
|
private boolean isRidingInFront;
|
||||||
/**
|
|
||||||
* Used for villager inventory emulation.
|
|
||||||
*/
|
|
||||||
private int fakeTradeXp;
|
|
||||||
|
|
||||||
public SessionPlayerEntity(GeyserSession session) {
|
public SessionPlayerEntity(GeyserSession session) {
|
||||||
super(session, -1, 1, null, Vector3f.ZERO, Vector3f.ZERO, 0, 0, 0, null, null);
|
super(session, -1, 1, null, Vector3f.ZERO, Vector3f.ZERO, 0, 0, 0, null, null);
|
||||||
|
@ -113,10 +110,17 @@ public class SessionPlayerEntity extends PlayerEntity {
|
||||||
this.position = position;
|
this.position = position;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sending any updated flags (sprinting, onFire, etc.) to the client while in spectator is not needed
|
||||||
|
* Also "fixes" https://github.com/GeyserMC/Geyser/issues/3318
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void setFlags(ByteEntityMetadata entityMetadata) {
|
public void setFlags(ByteEntityMetadata entityMetadata) {
|
||||||
|
// TODO: proper fix, BDS somehow does it? https://paste.gg/p/anonymous/3adfb7612f1540be80fa03a2281f93dc (BDS 1.20.13)
|
||||||
|
if (!this.session.getGameMode().equals(GameMode.SPECTATOR)) {
|
||||||
super.setFlags(entityMetadata);
|
super.setFlags(entityMetadata);
|
||||||
session.setSwimmingInWater((entityMetadata.getPrimitiveValue() & 0x10) == 0x10 && getFlag(EntityFlag.SPRINTING));
|
session.setSwimmingInWater((entityMetadata.getPrimitiveValue() & 0x10) == 0x10 && getFlag(EntityFlag.SPRINTING));
|
||||||
|
}
|
||||||
refreshSpeed = true;
|
refreshSpeed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,11 +179,6 @@ public class SessionPlayerEntity extends PlayerEntity {
|
||||||
this.isRidingInFront = position != null && position.getX() > 0;
|
this.isRidingInFront = position != null && position.getX() > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addFakeTradeExperience(int tradeXp) {
|
|
||||||
fakeTradeXp += tradeXp;
|
|
||||||
dirtyMetadata.put(EntityDataTypes.TRADE_EXPERIENCE, fakeTradeXp);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AttributeData createHealthAttribute() {
|
public AttributeData createHealthAttribute() {
|
||||||
// Max health must be divisible by two in bedrock
|
// Max health must be divisible by two in bedrock
|
||||||
|
|
|
@ -0,0 +1,93 @@
|
||||||
|
/*
|
||||||
|
* 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.event.type;
|
||||||
|
|
||||||
|
import org.checkerframework.checker.index.qual.NonNegative;
|
||||||
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
import org.cloudburstmc.protocol.bedrock.BedrockPong;
|
||||||
|
import org.geysermc.geyser.api.event.connection.GeyserBedrockPingEvent;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public class GeyserBedrockPingEventImpl implements GeyserBedrockPingEvent {
|
||||||
|
private final InetSocketAddress address;
|
||||||
|
private final BedrockPong pong;
|
||||||
|
|
||||||
|
public GeyserBedrockPingEventImpl(BedrockPong pong, InetSocketAddress address) {
|
||||||
|
this.address = address;
|
||||||
|
this.pong = pong;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void primaryMotd(@Nonnull String primary) {
|
||||||
|
pong.motd(Objects.requireNonNull(primary, "Primary MOTD cannot be null"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void secondaryMotd(@Nonnull String secondary) {
|
||||||
|
pong.subMotd(Objects.requireNonNull(secondary, "Secondary MOTD cannot be null"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void playerCount(int count) {
|
||||||
|
if (count < 0) throw new IllegalArgumentException("Player count cannot be below 0");
|
||||||
|
pong.playerCount(count);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void maxPlayerCount(int max) {
|
||||||
|
if (max < 1) throw new IllegalArgumentException("Max player count cannot be below 1");
|
||||||
|
pong.maximumPlayerCount(max);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable String primaryMotd() {
|
||||||
|
return pong.motd();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable String secondaryMotd() {
|
||||||
|
return pong.subMotd();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NonNegative int playerCount() {
|
||||||
|
return pong.playerCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int maxPlayerCount() {
|
||||||
|
return pong.maximumPlayerCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull InetSocketAddress address() {
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,69 @@
|
||||||
|
/*
|
||||||
|
* 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.event.type;
|
||||||
|
|
||||||
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
import org.geysermc.geyser.api.event.bedrock.SessionLoadResourcePacksEvent;
|
||||||
|
import org.geysermc.geyser.api.pack.ResourcePack;
|
||||||
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class SessionLoadResourcePacksEventImpl extends SessionLoadResourcePacksEvent {
|
||||||
|
|
||||||
|
private final Map<String, ResourcePack> packs;
|
||||||
|
|
||||||
|
public SessionLoadResourcePacksEventImpl(GeyserSession session, Map<String, ResourcePack> packMap) {
|
||||||
|
super(session);
|
||||||
|
this.packs = packMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
public @NonNull Map<String, ResourcePack> getPacks() {
|
||||||
|
return packs;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NonNull List<ResourcePack> resourcePacks() {
|
||||||
|
return List.copyOf(packs.values());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean register(@NonNull ResourcePack resourcePack) {
|
||||||
|
String packID = resourcePack.manifest().header().uuid().toString();
|
||||||
|
if (packs.containsValue(resourcePack) || packs.containsKey(packID)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
packs.put(resourcePack.manifest().header().uuid().toString(), resourcePack);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean unregister(@NonNull UUID uuid) {
|
||||||
|
return packs.remove(uuid.toString()) != null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -27,6 +27,7 @@ package org.geysermc.geyser.extension.event;
|
||||||
|
|
||||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
import org.geysermc.event.Event;
|
import org.geysermc.event.Event;
|
||||||
|
import org.geysermc.event.FireResult;
|
||||||
import org.geysermc.event.PostOrder;
|
import org.geysermc.event.PostOrder;
|
||||||
import org.geysermc.event.subscribe.Subscriber;
|
import org.geysermc.event.subscribe.Subscriber;
|
||||||
import org.geysermc.geyser.api.event.EventBus;
|
import org.geysermc.geyser.api.event.EventBus;
|
||||||
|
@ -47,10 +48,15 @@ public record GeyserExtensionEventBus(EventBus<EventRegistrar> eventBus, Extensi
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean fire(@NonNull Event event) {
|
public FireResult fire(@NonNull Event event) {
|
||||||
return eventBus.fire(event);
|
return eventBus.fire(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FireResult fireSilently(@NonNull Event event) {
|
||||||
|
return eventBus.fireSilently(event);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NonNull <T extends Event> Set<? extends EventSubscriber<EventRegistrar, T>> subscribers(@NonNull Class<T> eventClass) {
|
public @NonNull <T extends Event> Set<? extends EventSubscriber<EventRegistrar, T>> subscribers(@NonNull Class<T> eventClass) {
|
||||||
return eventBus.subscribers(eventClass);
|
return eventBus.subscribers(eventClass);
|
||||||
|
|
|
@ -75,7 +75,7 @@ public class AnvilContainer extends Container {
|
||||||
|
|
||||||
String originalName = ItemUtils.getCustomName(getInput().getNbt());
|
String originalName = ItemUtils.getCustomName(getInput().getNbt());
|
||||||
|
|
||||||
String plainOriginalName = MessageTranslator.convertToPlainText(originalName, session.locale());
|
String plainOriginalName = MessageTranslator.convertToPlainTextLenient(originalName, session.locale());
|
||||||
String plainNewName = MessageTranslator.convertToPlainText(rename);
|
String plainNewName = MessageTranslator.convertToPlainText(rename);
|
||||||
if (!plainOriginalName.equals(plainNewName)) {
|
if (!plainOriginalName.equals(plainNewName)) {
|
||||||
// Strip out formatting since Java Edition does not allow it
|
// Strip out formatting since Java Edition does not allow it
|
||||||
|
|
|
@ -33,7 +33,7 @@ import org.cloudburstmc.math.vector.Vector3i;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.defintions.ItemDefinition;
|
import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition;
|
||||||
import org.geysermc.geyser.GeyserImpl;
|
import org.geysermc.geyser.GeyserImpl;
|
||||||
import org.geysermc.geyser.item.Items;
|
import org.geysermc.geyser.item.Items;
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
|
|
|
@ -30,6 +30,7 @@ import com.github.steveice10.mc.protocol.data.game.inventory.VillagerTrade;
|
||||||
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.inventory.ClientboundMerchantOffersPacket;
|
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.inventory.ClientboundMerchantOffersPacket;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
|
||||||
import org.geysermc.geyser.entity.type.Entity;
|
import org.geysermc.geyser.entity.type.Entity;
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
|
|
||||||
|
@ -40,6 +41,8 @@ public class MerchantContainer extends Container {
|
||||||
private VillagerTrade[] villagerTrades;
|
private VillagerTrade[] villagerTrades;
|
||||||
@Getter @Setter
|
@Getter @Setter
|
||||||
private ClientboundMerchantOffersPacket pendingOffersPacket;
|
private ClientboundMerchantOffersPacket pendingOffersPacket;
|
||||||
|
@Getter @Setter
|
||||||
|
private int tradeExperience;
|
||||||
|
|
||||||
public MerchantContainer(String title, int id, int size, ContainerType containerType, PlayerInventory playerInventory) {
|
public MerchantContainer(String title, int id, int size, ContainerType containerType, PlayerInventory playerInventory) {
|
||||||
super(title, id, size, containerType, playerInventory);
|
super(title, id, size, containerType, playerInventory);
|
||||||
|
@ -49,9 +52,10 @@ public class MerchantContainer extends Container {
|
||||||
if (villagerTrades != null && slot >= 0 && slot < villagerTrades.length) {
|
if (villagerTrades != null && slot >= 0 && slot < villagerTrades.length) {
|
||||||
VillagerTrade trade = villagerTrades[slot];
|
VillagerTrade trade = villagerTrades[slot];
|
||||||
setItem(2, GeyserItemStack.from(trade.getOutput()), session);
|
setItem(2, GeyserItemStack.from(trade.getOutput()), session);
|
||||||
// TODO this logic doesn't add up
|
|
||||||
session.getPlayerEntity().addFakeTradeExperience(trade.getXp());
|
tradeExperience += trade.getXp();
|
||||||
session.getPlayerEntity().updateBedrockMetadata();
|
villager.getDirtyMetadata().put(EntityDataTypes.TRADE_EXPERIENCE, tradeExperience);
|
||||||
|
villager.updateBedrockMetadata();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue