Mirror von
https://github.com/GeyserMC/Geyser.git
synchronisiert 2024-11-19 22:40:18 +01:00
Merge remote-tracking branch 'upstream/master' into feature/blocky
Dieser Commit ist enthalten in:
Commit
f2d4176054
9
.github/workflows/pullrequest.yml
vendored
9
.github/workflows/pullrequest.yml
vendored
@ -19,12 +19,19 @@ jobs:
|
|||||||
uses: snickerbockers/submodules-init@v4
|
uses: snickerbockers/submodules-init@v4
|
||||||
- name: Build with Gradle
|
- name: Build with Gradle
|
||||||
run: ./gradlew build
|
run: ./gradlew build
|
||||||
|
|
||||||
|
- name: Archive artifacts (Geyser Fabric)
|
||||||
|
uses: actions/upload-artifact@v2
|
||||||
|
if: success()
|
||||||
|
with:
|
||||||
|
name: Geyser Fabric
|
||||||
|
path: bootstrap/fabric/build/libs/Geyser-Fabric.jar
|
||||||
- name: Archive artifacts (Geyser Standalone)
|
- name: Archive artifacts (Geyser Standalone)
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v2
|
||||||
if: success()
|
if: success()
|
||||||
with:
|
with:
|
||||||
name: Geyser Standalone
|
name: Geyser Standalone
|
||||||
path: bootstrap/standalone/build/libs/Geyser.jar
|
path: bootstrap/standalone/build/libs/Geyser-Standalone.jar
|
||||||
- name: Archive artifacts (Geyser Spigot)
|
- name: Archive artifacts (Geyser Spigot)
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v2
|
||||||
if: success()
|
if: success()
|
||||||
|
36
.github/workflows/sonarcloud.yml
vendored
36
.github/workflows/sonarcloud.yml
vendored
@ -1,36 +0,0 @@
|
|||||||
name: SonarCloud
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- master
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
name: SonarCloud
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
with:
|
|
||||||
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
|
|
||||||
submodules: true
|
|
||||||
- name: Set up JDK 17
|
|
||||||
uses: actions/setup-java@v2
|
|
||||||
with:
|
|
||||||
distribution: 'temurin'
|
|
||||||
java-version: 17
|
|
||||||
- name: Cache SonarCloud packages
|
|
||||||
uses: actions/cache@v1
|
|
||||||
with:
|
|
||||||
path: ~/.sonar/cache
|
|
||||||
key: ${{ runner.os }}-sonar
|
|
||||||
restore-keys: ${{ runner.os }}-sonar
|
|
||||||
- name: Cache Maven packages
|
|
||||||
uses: actions/cache@v1
|
|
||||||
with:
|
|
||||||
path: ~/.m2
|
|
||||||
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
|
|
||||||
restore-keys: ${{ runner.os }}-m2
|
|
||||||
- name: Build and analyze
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any
|
|
||||||
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
|
||||||
run: mvn -B verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar -Dsonar.projectKey=GeyserMC_Geyser
|
|
6
Jenkinsfile
vendored
6
Jenkinsfile
vendored
@ -20,7 +20,7 @@ pipeline {
|
|||||||
}
|
}
|
||||||
post {
|
post {
|
||||||
success {
|
success {
|
||||||
archiveArtifacts artifacts: 'bootstrap/**/build/libs/*.jar', excludes: 'bootstrap/**/build/libs/*-sources.jar,bootstrap/**/build/libs/*-unshaded.jar', fingerprint: true
|
archiveArtifacts artifacts: 'bootstrap/**/build/libs/Geyser-*.jar', fingerprint: true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -29,7 +29,6 @@ pipeline {
|
|||||||
when {
|
when {
|
||||||
anyOf {
|
anyOf {
|
||||||
branch "master"
|
branch "master"
|
||||||
branch "feature/extensions"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,7 +49,7 @@ pipeline {
|
|||||||
rootDir: "",
|
rootDir: "",
|
||||||
useWrapper: true,
|
useWrapper: true,
|
||||||
buildFile: 'build.gradle.kts',
|
buildFile: 'build.gradle.kts',
|
||||||
tasks: 'build artifactoryPublish',
|
tasks: 'artifactoryPublish',
|
||||||
deployerId: "GRADLE_DEPLOYER",
|
deployerId: "GRADLE_DEPLOYER",
|
||||||
resolverId: "GRADLE_RESOLVER"
|
resolverId: "GRADLE_RESOLVER"
|
||||||
)
|
)
|
||||||
@ -102,7 +101,6 @@ pipeline {
|
|||||||
success {
|
success {
|
||||||
script {
|
script {
|
||||||
if (env.BRANCH_NAME == 'master') {
|
if (env.BRANCH_NAME == 'master') {
|
||||||
build propagate: false, wait: false, job: 'GeyserMC/Geyser-Fabric/java-1.18', parameters: [booleanParam(name: 'SKIP_DISCORD', value: true)]
|
|
||||||
build propagate: false, wait: false, job: 'GeyserMC/GeyserConnect/master', parameters: [booleanParam(name: 'SKIP_DISCORD', value: true)]
|
build propagate: false, wait: false, job: 'GeyserMC/GeyserConnect/master', parameters: [booleanParam(name: 'SKIP_DISCORD', value: true)]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,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.0 - 1.19.10 and Minecraft Java 1.19.0.
|
### Currently supporting Minecraft Bedrock 1.19.20 - 1.19.51 and Minecraft Java 1.19.3.
|
||||||
|
|
||||||
## 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.
|
||||||
@ -34,7 +34,6 @@ Take a look [here](https://wiki.geysermc.org/geyser/setup/) for how to set up Ge
|
|||||||
|
|
||||||
## What's Left to be Added/Fixed
|
## What's Left to be Added/Fixed
|
||||||
- Near-perfect movement (to the point where anticheat on large servers is unlikely to ban you)
|
- Near-perfect movement (to the point where anticheat on large servers is unlikely to ban you)
|
||||||
- Resource pack conversion/CustomModelData
|
|
||||||
- Some Entity Flags
|
- Some Entity Flags
|
||||||
- Structure block UI
|
- Structure block UI
|
||||||
|
|
||||||
@ -43,9 +42,8 @@ There are a few things Geyser is unable to support due to various differences be
|
|||||||
|
|
||||||
## Compiling
|
## Compiling
|
||||||
1. Clone the repo to your computer
|
1. Clone the repo to your computer
|
||||||
2. [Install Maven](https://maven.apache.org/install.html)
|
2. Navigate to the Geyser root directory and run `git submodule update --init --recursive`. This command downloads all the needed submodules for Geyser and is a crucial step in this process.
|
||||||
3. Navigate to the Geyser root directory and run `git submodule update --init --recursive`. This command downloads all the needed submodules for Geyser and is a crucial step in this process.
|
3. Run `gradlew build` and locate to `bootstrap/build` folder.
|
||||||
4. Run `mvn clean install` and locate to the `target` folder.
|
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
Any contributions are appreciated. Please feel free to reach out to us on [Discord](http://discord.geysermc.org/) if
|
Any contributions are appreciated. Please feel free to reach out to us on [Discord](http://discord.geysermc.org/) if
|
||||||
|
@ -1 +1,7 @@
|
|||||||
provided("net.kyori", "event-api", Versions.eventVersion)
|
dependencies {
|
||||||
|
api(libs.cumulus)
|
||||||
|
api(libs.events) {
|
||||||
|
exclude(group = "com.google.guava", module = "guava")
|
||||||
|
exclude(group = "org.lanternpowered", module = "lmbda")
|
||||||
|
}
|
||||||
|
}
|
@ -39,6 +39,7 @@ public class Geyser {
|
|||||||
*
|
*
|
||||||
* @return the base api
|
* @return the base api
|
||||||
*/
|
*/
|
||||||
|
@NonNull
|
||||||
public static GeyserApiBase api() {
|
public static GeyserApiBase api() {
|
||||||
if (api == null) {
|
if (api == null) {
|
||||||
throw new RuntimeException("Api has not been registered yet!");
|
throw new RuntimeException("Api has not been registered yet!");
|
||||||
@ -69,7 +70,7 @@ public class Geyser {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers the given api type. The api cannot be
|
* Registers the given api type. The api cannot be
|
||||||
* registered if {@link #registered()} is true as
|
* registered if {@link #isRegistered()} is true as
|
||||||
* an api has already been specified.
|
* an api has already been specified.
|
||||||
*
|
*
|
||||||
* @param api the api
|
* @param api the api
|
||||||
@ -88,7 +89,7 @@ public class Geyser {
|
|||||||
*
|
*
|
||||||
* @return if the api has been registered
|
* @return if the api has been registered
|
||||||
*/
|
*/
|
||||||
public static boolean registered() {
|
public static boolean isRegistered() {
|
||||||
return api != null;
|
return api != null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,9 +25,13 @@
|
|||||||
|
|
||||||
package org.geysermc.api;
|
package org.geysermc.api;
|
||||||
|
|
||||||
|
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.checkerframework.common.value.qual.IntRange;
|
||||||
import org.geysermc.api.connection.Connection;
|
import org.geysermc.api.connection.Connection;
|
||||||
|
import org.geysermc.cumulus.form.Form;
|
||||||
|
import org.geysermc.cumulus.form.util.FormBuilder;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@ -37,52 +41,88 @@ import java.util.UUID;
|
|||||||
*/
|
*/
|
||||||
public interface GeyserApiBase {
|
public interface GeyserApiBase {
|
||||||
/**
|
/**
|
||||||
* Gets the session from the given UUID, if applicable. The player must be logged in to the Java server
|
* Gets the connection from the given UUID, if applicable. The player must be logged in to the Java server
|
||||||
* for this to return a non-null value.
|
* for this to return a non-null value.
|
||||||
*
|
*
|
||||||
* @param uuid the UUID of the session
|
* @param uuid the UUID of the connection
|
||||||
* @return the session from the given UUID, if applicable
|
* @return the connection from the given UUID, if applicable
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
Connection connectionByUuid(@NonNull UUID uuid);
|
Connection connectionByUuid(@NonNull UUID uuid);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the session from the given
|
* Gets the connection from the given XUID, if applicable. This method only works for online connections.
|
||||||
* XUID, if applicable.
|
|
||||||
*
|
*
|
||||||
* @param xuid the XUID of the session
|
* @param xuid the XUID of the session
|
||||||
* @return the session from the given UUID, if applicable
|
* @return the connection from the given UUID, if applicable
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
Connection connectionByXuid(@NonNull String xuid);
|
Connection connectionByXuid(@NonNull String xuid);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the session from the given
|
* Method to determine if the given <b>online</b> player is a Bedrock player.
|
||||||
* name, if applicable.
|
|
||||||
*
|
*
|
||||||
* @param name the uuid of the session
|
* @param uuid the uuid of the online player
|
||||||
* @return the session from the given name, if applicable
|
* @return true if the given online player is a Bedrock player
|
||||||
*/
|
*/
|
||||||
@Nullable
|
boolean isBedrockPlayer(@NonNull UUID uuid);
|
||||||
Connection connectionByName(@NonNull String name);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets all the online sessions.
|
* Sends a form to the given connection and opens it.
|
||||||
*
|
*
|
||||||
* @return all the online sessions
|
* @param uuid the uuid of the connection to open it on
|
||||||
|
* @param form the form to send
|
||||||
|
* @return whether the form was successfully sent
|
||||||
|
*/
|
||||||
|
boolean sendForm(@NonNull UUID uuid, @NonNull Form form);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a form to the given connection and opens it.
|
||||||
|
*
|
||||||
|
* @param uuid the uuid of the connection to open it on
|
||||||
|
* @param formBuilder the formBuilder to send
|
||||||
|
* @return whether the form was successfully sent
|
||||||
|
*/
|
||||||
|
boolean sendForm(@NonNull UUID uuid, @NonNull FormBuilder<?, ?, ?> formBuilder);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transfer the given connection to a server. A Bedrock player can successfully transfer to the same server they are
|
||||||
|
* currently playing on.
|
||||||
|
*
|
||||||
|
* @param uuid the uuid of the connection
|
||||||
|
* @param address the address of the server
|
||||||
|
* @param port the port of the server
|
||||||
|
* @return true if the transfer was a success
|
||||||
|
*/
|
||||||
|
boolean transfer(@NonNull UUID uuid, @NonNull String address, @IntRange(from = 0, to = 65535) int port);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all the online connections.
|
||||||
*/
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
List<? extends Connection> onlineConnections();
|
List<? extends Connection> onlineConnections();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the major API version. Bumped whenever a significant breaking change or feature addition is added.
|
* Returns the amount of online connections.
|
||||||
|
*/
|
||||||
|
int onlineConnectionsCount();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the prefix used by Floodgate. Will be null when the auth-type isn't Floodgate.
|
||||||
|
*/
|
||||||
|
@MonotonicNonNull
|
||||||
|
String usernamePrefix();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the major API version. Bumped whenever a significant breaking change or feature addition is added.
|
||||||
*/
|
*/
|
||||||
default int majorApiVersion() {
|
default int majorApiVersion() {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the minor API version. May be bumped for new API additions.
|
* Returns the minor API version. May be bumped for new API additions.
|
||||||
*/
|
*/
|
||||||
default int minorApiVersion() {
|
default int minorApiVersion() {
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -25,43 +25,96 @@
|
|||||||
|
|
||||||
package org.geysermc.api.connection;
|
package org.geysermc.api.connection;
|
||||||
|
|
||||||
|
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
import org.checkerframework.common.value.qual.IntRange;
|
import org.checkerframework.common.value.qual.IntRange;
|
||||||
|
import org.geysermc.api.util.BedrockPlatform;
|
||||||
|
import org.geysermc.api.util.InputMode;
|
||||||
|
import org.geysermc.api.util.UiProfile;
|
||||||
|
import org.geysermc.cumulus.form.Form;
|
||||||
|
import org.geysermc.cumulus.form.util.FormBuilder;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a player connection.
|
* Represents a player connection.
|
||||||
*/
|
*/
|
||||||
@NonNull
|
|
||||||
public interface Connection {
|
public interface Connection {
|
||||||
/**
|
/**
|
||||||
* Gets the name of the connection.
|
* Returns the bedrock name of the connection.
|
||||||
*
|
|
||||||
* @return the name of the connection
|
|
||||||
*/
|
*/
|
||||||
String name();
|
@NonNull String bedrockUsername();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the {@link UUID} of the connection.
|
* Returns the java name of the connection.
|
||||||
*
|
|
||||||
* @return the UUID of the connection
|
|
||||||
*/
|
*/
|
||||||
UUID uuid();
|
@MonotonicNonNull
|
||||||
|
String javaUsername();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the XUID of the connection.
|
* Returns the UUID of the connection.
|
||||||
*
|
|
||||||
* @return the XUID of the connection
|
|
||||||
*/
|
*/
|
||||||
String xuid();
|
@MonotonicNonNull
|
||||||
|
UUID javaUuid();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the XUID of the connection.
|
||||||
|
*/
|
||||||
|
@NonNull String xuid();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the version of the Bedrock client.
|
||||||
|
*/
|
||||||
|
@NonNull String version();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the platform that the connection is playing on.
|
||||||
|
*/
|
||||||
|
@NonNull BedrockPlatform platform();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the language code of the connection.
|
||||||
|
*/
|
||||||
|
@NonNull String languageCode();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the User Interface Profile of the connection.
|
||||||
|
*/
|
||||||
|
@NonNull UiProfile uiProfile();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the Input Mode of the Bedrock client.
|
||||||
|
*/
|
||||||
|
@NonNull InputMode inputMode();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the connection is linked.
|
||||||
|
* This will always return false when the auth-type isn't Floodgate.
|
||||||
|
*/
|
||||||
|
boolean isLinked();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a form to the connection and opens it.
|
||||||
|
*
|
||||||
|
* @param form the form to send
|
||||||
|
* @return whether the form was successfully sent
|
||||||
|
*/
|
||||||
|
boolean sendForm(@NonNull Form form);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a form to the connection and opens it.
|
||||||
|
*
|
||||||
|
* @param formBuilder the formBuilder to send
|
||||||
|
* @return whether the form was successfully sent
|
||||||
|
*/
|
||||||
|
boolean sendForm(@NonNull FormBuilder<?, ?, ?> formBuilder);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transfer the connection to a server. A Bedrock player can successfully transfer to the same server they are
|
* Transfer the connection to a server. A Bedrock player can successfully transfer to the same server they are
|
||||||
* currently playing on.
|
* currently playing on.
|
||||||
*
|
*
|
||||||
* @param address The address of the server
|
* @param address the address of the server
|
||||||
* @param port The port of the server
|
* @param port the port of the server
|
||||||
* @return true if the transfer was a success
|
* @return true if the transfer was a success
|
||||||
*/
|
*/
|
||||||
boolean transfer(@NonNull String address, @IntRange(from = 0, to = 65535) int port);
|
boolean transfer(@NonNull String address, @IntRange(from = 0, to = 65535) int port);
|
||||||
|
@ -23,60 +23,51 @@
|
|||||||
* @link https://github.com/GeyserMC/Geyser
|
* @link https://github.com/GeyserMC/Geyser
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.geysermc.geyser.api.event;
|
package org.geysermc.api.util;
|
||||||
|
|
||||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
import org.geysermc.geyser.api.extension.Extension;
|
|
||||||
|
|
||||||
/**
|
public enum BedrockPlatform {
|
||||||
* Represents a subscribed listener to a {@link Event}. Wraps around
|
UNKNOWN("Unknown"),
|
||||||
* the event and is capable of unsubscribing from the event or give
|
GOOGLE("Android"),
|
||||||
* information about it.
|
IOS("iOS"),
|
||||||
*
|
OSX("macOS"),
|
||||||
* @param <T> the class of the event
|
AMAZON("Amazon"),
|
||||||
*/
|
GEARVR("Gear VR"),
|
||||||
public interface EventSubscription<T extends Event> {
|
HOLOLENS("Hololens"),
|
||||||
|
UWP("Windows"),
|
||||||
|
WIN32("Windows x86"),
|
||||||
|
DEDICATED("Dedicated"),
|
||||||
|
TVOS("Apple TV"),
|
||||||
|
PS4("PS4"),
|
||||||
|
NX("Switch"),
|
||||||
|
XBOX("Xbox One"),
|
||||||
|
WINDOWS_PHONE("Windows Phone");
|
||||||
|
|
||||||
|
private static final BedrockPlatform[] VALUES = values();
|
||||||
|
|
||||||
|
private final String displayName;
|
||||||
|
|
||||||
|
BedrockPlatform(String displayName) {
|
||||||
|
this.displayName = displayName;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the event class.
|
* Get the BedrockPlatform from the identifier.
|
||||||
*
|
*
|
||||||
* @return the event class
|
* @param id the BedrockPlatform identifier
|
||||||
|
* @return The BedrockPlatform or {@link #UNKNOWN} if the platform wasn't found
|
||||||
*/
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
Class<T> eventClass();
|
public static BedrockPlatform fromId(int id) {
|
||||||
|
return id < VALUES.length ? VALUES[id] : VALUES[0];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the {@link Extension} that owns this
|
* @return friendly display name of platform.
|
||||||
* event subscription.
|
|
||||||
*
|
|
||||||
* @return the extension that owns this subscription
|
|
||||||
*/
|
*/
|
||||||
@NonNull
|
@Override
|
||||||
Extension owner();
|
public String toString() {
|
||||||
|
return displayName;
|
||||||
/**
|
}
|
||||||
* Gets the post order of this event subscription.
|
|
||||||
*
|
|
||||||
* @return the post order of this event subscription
|
|
||||||
*/
|
|
||||||
Subscribe.PostOrder order();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets if this event subscription is active.
|
|
||||||
*
|
|
||||||
* @return if this event subscription is active
|
|
||||||
*/
|
|
||||||
boolean isActive();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unsubscribes from this event listener
|
|
||||||
*/
|
|
||||||
void unsubscribe();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Invokes the given event
|
|
||||||
*
|
|
||||||
* @param event the event
|
|
||||||
*/
|
|
||||||
void invoke(@NonNull T event) throws Throwable;
|
|
||||||
}
|
}
|
49
api/base/src/main/java/org/geysermc/api/util/InputMode.java
Normale Datei
49
api/base/src/main/java/org/geysermc/api/util/InputMode.java
Normale Datei
@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* 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.api.util;
|
||||||
|
|
||||||
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
|
||||||
|
public enum InputMode {
|
||||||
|
UNKNOWN,
|
||||||
|
KEYBOARD_MOUSE,
|
||||||
|
TOUCH,
|
||||||
|
CONTROLLER,
|
||||||
|
VR;
|
||||||
|
|
||||||
|
private static final InputMode[] VALUES = values();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the InputMode from the identifier.
|
||||||
|
*
|
||||||
|
* @param id the InputMode identifier
|
||||||
|
* @return The InputMode or {@link #UNKNOWN} if the mode wasn't found
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
public static InputMode fromId(int id) {
|
||||||
|
return VALUES.length > id ? VALUES[id] : VALUES[0];
|
||||||
|
}
|
||||||
|
}
|
@ -23,19 +23,23 @@
|
|||||||
* @link https://github.com/GeyserMC/Geyser
|
* @link https://github.com/GeyserMC/Geyser
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.geysermc.geyser.platform.standalone.command;
|
package org.geysermc.api.util;
|
||||||
|
|
||||||
import org.geysermc.geyser.GeyserImpl;
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
import org.geysermc.geyser.command.GeyserCommandManager;
|
|
||||||
|
|
||||||
public class GeyserStandaloneCommandManager extends GeyserCommandManager {
|
public enum UiProfile {
|
||||||
|
CLASSIC, POCKET;
|
||||||
|
|
||||||
public GeyserStandaloneCommandManager(GeyserImpl geyser) {
|
private static final UiProfile[] VALUES = values();
|
||||||
super(geyser);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public String description(String command) {
|
* Get the UiProfile from the identifier.
|
||||||
return ""; // this is not sent over the protocol, so we return none
|
*
|
||||||
|
* @param id the UiProfile identifier
|
||||||
|
* @return The UiProfile or {@link #CLASSIC} if the profile wasn't found
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
public static UiProfile fromId(int id) {
|
||||||
|
return VALUES.length > id ? VALUES[id] : VALUES[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -29,9 +29,9 @@ 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.api.GeyserApiBase;
|
import org.geysermc.api.GeyserApiBase;
|
||||||
import org.geysermc.geyser.api.command.CommandManager;
|
|
||||||
import org.geysermc.geyser.api.connection.GeyserConnection;
|
import org.geysermc.geyser.api.connection.GeyserConnection;
|
||||||
import org.geysermc.geyser.api.event.EventBus;
|
import org.geysermc.geyser.api.event.EventBus;
|
||||||
|
import org.geysermc.geyser.api.event.EventRegistrar;
|
||||||
import org.geysermc.geyser.api.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;
|
||||||
@ -55,12 +55,6 @@ public interface GeyserApi extends GeyserApiBase {
|
|||||||
@Override
|
@Override
|
||||||
@Nullable GeyserConnection connectionByXuid(@NonNull String xuid);
|
@Nullable GeyserConnection connectionByXuid(@NonNull String xuid);
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
@Nullable GeyserConnection connectionByName(@NonNull String name);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
@ -72,15 +66,9 @@ public interface GeyserApi extends GeyserApiBase {
|
|||||||
*
|
*
|
||||||
* @return the extension manager
|
* @return the extension manager
|
||||||
*/
|
*/
|
||||||
|
@NonNull
|
||||||
ExtensionManager extensionManager();
|
ExtensionManager extensionManager();
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the {@link CommandManager}.
|
|
||||||
*
|
|
||||||
* @return the command manager
|
|
||||||
*/
|
|
||||||
CommandManager commandManager();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides an implementation for the specified API type.
|
* Provides an implementation for the specified API type.
|
||||||
*
|
*
|
||||||
@ -98,7 +86,8 @@ public interface GeyserApi extends GeyserApiBase {
|
|||||||
*
|
*
|
||||||
* @return the event bus
|
* @return the event bus
|
||||||
*/
|
*/
|
||||||
EventBus eventBus();
|
@NonNull
|
||||||
|
EventBus<EventRegistrar> eventBus();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the default {@link RemoteServer} configured
|
* Gets the default {@link RemoteServer} configured
|
||||||
@ -106,6 +95,7 @@ public interface GeyserApi extends GeyserApiBase {
|
|||||||
*
|
*
|
||||||
* @return the default remote server used within Geyser
|
* @return the default remote server used within Geyser
|
||||||
*/
|
*/
|
||||||
|
@NonNull
|
||||||
RemoteServer defaultRemoteServer();
|
RemoteServer defaultRemoteServer();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -114,6 +104,7 @@ public interface GeyserApi extends GeyserApiBase {
|
|||||||
*
|
*
|
||||||
* @return the listener used for Bedrock client connectins
|
* @return the listener used for Bedrock client connectins
|
||||||
*/
|
*/
|
||||||
|
@NonNull
|
||||||
BedrockListener bedrockListener();
|
BedrockListener bedrockListener();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -121,6 +112,7 @@ public interface GeyserApi extends GeyserApiBase {
|
|||||||
*
|
*
|
||||||
* @return the current geyser api instance
|
* @return the current geyser api instance
|
||||||
*/
|
*/
|
||||||
|
@NonNull
|
||||||
static GeyserApi api() {
|
static GeyserApi api() {
|
||||||
return Geyser.api(GeyserApi.class);
|
return Geyser.api(GeyserApi.class);
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,8 @@ package org.geysermc.geyser.api.command;
|
|||||||
|
|
||||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
import org.geysermc.geyser.api.GeyserApi;
|
import org.geysermc.geyser.api.GeyserApi;
|
||||||
|
import org.geysermc.geyser.api.connection.GeyserConnection;
|
||||||
|
import org.geysermc.geyser.api.extension.Extension;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -104,19 +106,39 @@ public interface Command {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static <T extends CommandSource> Command.Builder<T> builder(Class<T> sourceType) {
|
/**
|
||||||
return GeyserApi.api().provider(Builder.class, sourceType);
|
* Creates a new {@link Command.Builder} used to construct commands.
|
||||||
|
*
|
||||||
|
* @param extension the extension
|
||||||
|
* @param <T> the source type
|
||||||
|
* @return a new command builder used to construct commands
|
||||||
|
*/
|
||||||
|
static <T extends CommandSource> Command.Builder<T> builder(@NonNull Extension extension) {
|
||||||
|
return GeyserApi.api().provider(Builder.class, extension);
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Builder<T extends CommandSource> {
|
interface Builder<T extends CommandSource> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines the source type to use for this command.
|
||||||
|
* <p>
|
||||||
|
* Command source types can be anything that extend
|
||||||
|
* {@link CommandSource}, such as {@link GeyserConnection}.
|
||||||
|
* This will guarantee that the source used in the executor
|
||||||
|
* is an instance of this source.
|
||||||
|
*
|
||||||
|
* @param sourceType the source type
|
||||||
|
* @return the builder
|
||||||
|
*/
|
||||||
|
Builder<T> source(@NonNull Class<? extends T> sourceType);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the command name.
|
* Sets the command name.
|
||||||
*
|
*
|
||||||
* @param name the command name
|
* @param name the command name
|
||||||
* @return the builder
|
* @return the builder
|
||||||
*/
|
*/
|
||||||
Builder<T> name(String name);
|
Builder<T> name(@NonNull String name);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the command description.
|
* Sets the command description.
|
||||||
@ -124,7 +146,7 @@ public interface Command {
|
|||||||
* @param description the command description
|
* @param description the command description
|
||||||
* @return the builder
|
* @return the builder
|
||||||
*/
|
*/
|
||||||
Builder<T> description(String description);
|
Builder<T> description(@NonNull String description);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the permission node.
|
* Sets the permission node.
|
||||||
@ -132,7 +154,7 @@ public interface Command {
|
|||||||
* @param permission the permission node
|
* @param permission the permission node
|
||||||
* @return the builder
|
* @return the builder
|
||||||
*/
|
*/
|
||||||
Builder<T> permission(String permission);
|
Builder<T> permission(@NonNull String permission);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the aliases.
|
* Sets the aliases.
|
||||||
@ -140,7 +162,7 @@ public interface Command {
|
|||||||
* @param aliases the aliases
|
* @param aliases the aliases
|
||||||
* @return the builder
|
* @return the builder
|
||||||
*/
|
*/
|
||||||
Builder<T> aliases(List<String> aliases);
|
Builder<T> aliases(@NonNull List<String> aliases);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets if this command is designed to be used only by server operators.
|
* Sets if this command is designed to be used only by server operators.
|
||||||
@ -164,7 +186,7 @@ public interface Command {
|
|||||||
* @param subCommands the subcommands
|
* @param subCommands the subcommands
|
||||||
* @return the builder
|
* @return the builder
|
||||||
*/
|
*/
|
||||||
Builder<T> subCommands(List<String> subCommands);
|
Builder<T> subCommands(@NonNull List<String> subCommands);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets if this command is bedrock only.
|
* Sets if this command is bedrock only.
|
||||||
@ -180,13 +202,14 @@ public interface Command {
|
|||||||
* @param executor the command executor
|
* @param executor the command executor
|
||||||
* @return the builder
|
* @return the builder
|
||||||
*/
|
*/
|
||||||
Builder<T> executor(CommandExecutor<T> executor);
|
Builder<T> executor(@NonNull CommandExecutor<T> executor);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds the command.
|
* Builds the command.
|
||||||
*
|
*
|
||||||
* @return the command
|
* @return the command
|
||||||
*/
|
*/
|
||||||
|
@NonNull
|
||||||
Command build();
|
Command build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,13 +25,14 @@
|
|||||||
|
|
||||||
package org.geysermc.geyser.api.command;
|
package org.geysermc.geyser.api.command;
|
||||||
|
|
||||||
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles executing a command.
|
* Handles executing a command.
|
||||||
*
|
*
|
||||||
* @param <T> the command source
|
* @param <T> the command source
|
||||||
*/
|
*/
|
||||||
public interface CommandExecutor<T extends CommandSource> {
|
public interface CommandExecutor<T extends CommandSource> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Executes the given {@link Command} with the given
|
* Executes the given {@link Command} with the given
|
||||||
* {@link CommandSource}.
|
* {@link CommandSource}.
|
||||||
@ -40,5 +41,5 @@ public interface CommandExecutor<T extends CommandSource> {
|
|||||||
* @param command the command
|
* @param command the command
|
||||||
* @param args the arguments
|
* @param args the arguments
|
||||||
*/
|
*/
|
||||||
void execute(T source, Command command, String[] args);
|
void execute(@NonNull T source, @NonNull Command command, @NonNull String[] args);
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,8 @@
|
|||||||
|
|
||||||
package org.geysermc.geyser.api.command;
|
package org.geysermc.geyser.api.command;
|
||||||
|
|
||||||
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents an instance capable of sending commands.
|
* Represents an instance capable of sending commands.
|
||||||
*/
|
*/
|
||||||
@ -42,7 +44,7 @@ public interface CommandSource {
|
|||||||
*
|
*
|
||||||
* @param message the message to send
|
* @param message the message to send
|
||||||
*/
|
*/
|
||||||
void sendMessage(String message);
|
void sendMessage(@NonNull String message);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends the given messages to the command source
|
* Sends the given messages to the command source
|
||||||
@ -58,7 +60,7 @@ public interface CommandSource {
|
|||||||
/**
|
/**
|
||||||
* If this source is the console.
|
* If this source is the console.
|
||||||
*
|
*
|
||||||
* @return true if this source is the console
|
* @return true if this source is the console
|
||||||
*/
|
*/
|
||||||
boolean isConsole();
|
boolean isConsole();
|
||||||
|
|
||||||
|
@ -26,71 +26,18 @@
|
|||||||
package org.geysermc.geyser.api.event;
|
package org.geysermc.geyser.api.event;
|
||||||
|
|
||||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
import org.geysermc.event.Event;
|
||||||
|
import org.geysermc.event.bus.OwnedEventBus;
|
||||||
import org.geysermc.geyser.api.extension.Extension;
|
import org.geysermc.geyser.api.extension.Extension;
|
||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.function.Consumer;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a bus capable of subscribing
|
* Represents a bus capable of subscribing
|
||||||
* or "listening" to events and firing them.
|
* or "listening" to events and firing them.
|
||||||
*/
|
*/
|
||||||
public interface EventBus {
|
public interface EventBus<R extends EventRegistrar> extends OwnedEventBus<R, Event, EventSubscriber<R, ? extends Event>> {
|
||||||
|
@Override
|
||||||
/**
|
|
||||||
* Subscribes to the given event see {@link EventSubscription}.
|
|
||||||
*
|
|
||||||
* The difference between this method and {@link ExtensionEventBus#subscribe(Class, Consumer)}
|
|
||||||
* is that this method takes in an extension parameter which allows for
|
|
||||||
* the event to be unsubscribed upon extension disable and reloads.
|
|
||||||
*
|
|
||||||
* @param extension the extension to subscribe the event to
|
|
||||||
* @param eventClass the class of the event
|
|
||||||
* @param consumer the consumer for handling the event
|
|
||||||
* @param <T> the event class
|
|
||||||
* @return the event subscription
|
|
||||||
*/
|
|
||||||
@NonNull
|
@NonNull
|
||||||
<T extends Event> EventSubscription<T> subscribe(@NonNull Extension extension, @NonNull Class<T> eventClass, @NonNull Consumer<? super T> consumer);
|
<T extends Event> Set<? extends EventSubscriber<R, T>> subscribers(@NonNull Class<T> eventClass);
|
||||||
|
|
||||||
/**
|
|
||||||
* Unsubscribes the given {@link EventSubscription}.
|
|
||||||
*
|
|
||||||
* @param subscription the event subscription
|
|
||||||
*/
|
|
||||||
<T extends Event> void unsubscribe(@NonNull EventSubscription<T> subscription);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Registers events for the given listener.
|
|
||||||
*
|
|
||||||
* @param extension the extension registering the event
|
|
||||||
* @param eventHolder the listener
|
|
||||||
*/
|
|
||||||
void register(@NonNull Extension extension, @NonNull Object eventHolder);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unregisters all events from a given {@link Extension}.
|
|
||||||
*
|
|
||||||
* @param extension the extension
|
|
||||||
*/
|
|
||||||
void unregisterAll(@NonNull Extension extension);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fires the given {@link Event} and returns the result.
|
|
||||||
*
|
|
||||||
* @param event the event to fire
|
|
||||||
*
|
|
||||||
* @return true if the event successfully fired
|
|
||||||
*/
|
|
||||||
boolean fire(@NonNull Event event);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the subscriptions for the given event class.
|
|
||||||
*
|
|
||||||
* @param eventClass the event class
|
|
||||||
* @param <T> the value
|
|
||||||
* @return the subscriptions for the event class
|
|
||||||
*/
|
|
||||||
@NonNull
|
|
||||||
<T extends Event> Set<EventSubscription<T>> subscriptions(@NonNull Class<T> eventClass);
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
import org.geysermc.geyser.api.GeyserApi;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents an owner for an event that allows it
|
||||||
|
* to be registered through an {@link EventBus}.
|
||||||
|
*/
|
||||||
|
public interface EventRegistrar {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an {@link EventRegistrar} instance.
|
||||||
|
*
|
||||||
|
* @param object the object to wrap around
|
||||||
|
* @return an event registrar instance
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
static EventRegistrar of(@NonNull Object object) {
|
||||||
|
return GeyserApi.api().provider(EventRegistrar.class, object);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
import org.geysermc.event.Event;
|
||||||
|
import org.geysermc.event.subscribe.OwnedSubscriber;
|
||||||
|
import org.geysermc.geyser.api.extension.Extension;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a subscribed listener to a {@link Event}. Wraps around
|
||||||
|
* the event and is capable of unsubscribing from the event or give
|
||||||
|
* information about it.
|
||||||
|
*
|
||||||
|
* @param <T> the class of the event
|
||||||
|
*/
|
||||||
|
public interface EventSubscriber<R extends EventRegistrar, T extends Event> extends OwnedSubscriber<R, T> {
|
||||||
|
}
|
@ -26,36 +26,16 @@
|
|||||||
package org.geysermc.geyser.api.event;
|
package org.geysermc.geyser.api.event;
|
||||||
|
|
||||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
import org.geysermc.event.Event;
|
||||||
|
import org.geysermc.geyser.api.extension.Extension;
|
||||||
|
|
||||||
import java.util.function.Consumer;
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An {@link EventBus} with additional methods that implicitly
|
* An {@link EventBus} with additional methods that implicitly
|
||||||
* set the extension instance.
|
* set the extension instance.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public interface ExtensionEventBus extends EventBus {
|
public interface ExtensionEventBus extends org.geysermc.event.bus.EventBus<Event, EventSubscriber<Extension, ? extends Event>> {
|
||||||
|
@Override
|
||||||
/**
|
@NonNull <T extends Event> Set<? extends EventSubscriber<EventRegistrar, T>> subscribers(@NonNull Class<T> eventClass);
|
||||||
* Subscribes to the given event see {@link EventSubscription}.
|
|
||||||
*
|
|
||||||
* @param eventClass the class of the event
|
|
||||||
* @param consumer the consumer for handling the event
|
|
||||||
* @param <T> the event class
|
|
||||||
* @return the event subscription
|
|
||||||
*/
|
|
||||||
@NonNull
|
|
||||||
<T extends Event> EventSubscription<T> subscribe(@NonNull Class<T> eventClass, @NonNull Consumer<? super T> consumer);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Registers events for the given listener.
|
|
||||||
*
|
|
||||||
* @param eventHolder the listener
|
|
||||||
*/
|
|
||||||
void register(@NonNull Object eventHolder);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unregisters all events for this extension.
|
|
||||||
*/
|
|
||||||
void unregisterAll();
|
|
||||||
}
|
}
|
||||||
|
@ -25,17 +25,8 @@
|
|||||||
|
|
||||||
package org.geysermc.geyser.api.event;
|
package org.geysermc.geyser.api.event;
|
||||||
|
|
||||||
/**
|
import org.geysermc.event.Event;
|
||||||
* Represents an event.
|
import org.geysermc.event.subscribe.Subscriber;
|
||||||
*/
|
|
||||||
public interface Event {
|
|
||||||
|
|
||||||
/**
|
public interface ExtensionEventSubscriber<T extends Event> extends Subscriber<T> {
|
||||||
* Gets if the event is async.
|
|
||||||
*
|
|
||||||
* @return if the event is async
|
|
||||||
*/
|
|
||||||
default boolean isAsync() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -1,103 +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.api.event;
|
|
||||||
|
|
||||||
import java.lang.annotation.ElementType;
|
|
||||||
import java.lang.annotation.Retention;
|
|
||||||
import java.lang.annotation.RetentionPolicy;
|
|
||||||
import java.lang.annotation.Target;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An annotation used to signify the given method is
|
|
||||||
* an {@link Event}. Only should be applied to methods
|
|
||||||
* where the class containing them is designated for
|
|
||||||
* events specifically.
|
|
||||||
*
|
|
||||||
* When using {@link EventBus#subscribe}, this annotation should
|
|
||||||
* not be applied whatsoever as it will have no use and potentially
|
|
||||||
* throw errors due to it being used wrongly.
|
|
||||||
*/
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
|
||||||
@Target(ElementType.METHOD)
|
|
||||||
public @interface Subscribe {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The {@link PostOrder} of the event
|
|
||||||
*
|
|
||||||
* @return the post order of the event
|
|
||||||
*/
|
|
||||||
Subscribe.PostOrder postOrder() default PostOrder.NORMAL;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents the post order of an event.
|
|
||||||
*/
|
|
||||||
enum PostOrder {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The lowest priority. Called first to
|
|
||||||
* allow for other events to customize
|
|
||||||
* the outcome
|
|
||||||
*/
|
|
||||||
FIRST(net.kyori.event.PostOrders.FIRST),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The second lowest priority.
|
|
||||||
*/
|
|
||||||
EARLY(net.kyori.event.PostOrders.EARLY),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Normal priority. Event is neither
|
|
||||||
* important nor unimportant
|
|
||||||
*/
|
|
||||||
NORMAL(net.kyori.event.PostOrders.NORMAL),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The second highest priority
|
|
||||||
*/
|
|
||||||
LATE(net.kyori.event.PostOrders.LATE),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The highest of importance! Event is called
|
|
||||||
* last and has the final say in the outcome
|
|
||||||
*/
|
|
||||||
LAST(net.kyori.event.PostOrders.LAST);
|
|
||||||
|
|
||||||
private final int postOrder;
|
|
||||||
|
|
||||||
PostOrder(int postOrder) {
|
|
||||||
this.postOrder = postOrder;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The numerical post order value.
|
|
||||||
*
|
|
||||||
* @return numerical post order value
|
|
||||||
*/
|
|
||||||
public int postOrder() {
|
|
||||||
return this.postOrder;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -26,8 +26,8 @@
|
|||||||
package org.geysermc.geyser.api.event.connection;
|
package org.geysermc.geyser.api.event.connection;
|
||||||
|
|
||||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
import org.geysermc.event.Event;
|
||||||
import org.geysermc.geyser.api.connection.GeyserConnection;
|
import org.geysermc.geyser.api.connection.GeyserConnection;
|
||||||
import org.geysermc.geyser.api.event.Event;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An event that contains a {@link GeyserConnection}.
|
* An event that contains a {@link GeyserConnection}.
|
||||||
|
@ -26,8 +26,8 @@
|
|||||||
package org.geysermc.geyser.api.event.downstream;
|
package org.geysermc.geyser.api.event.downstream;
|
||||||
|
|
||||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
import org.geysermc.event.Cancellable;
|
||||||
import org.geysermc.geyser.api.connection.GeyserConnection;
|
import org.geysermc.geyser.api.connection.GeyserConnection;
|
||||||
import org.geysermc.geyser.api.event.Cancellable;
|
|
||||||
import org.geysermc.geyser.api.event.connection.ConnectionEvent;
|
import org.geysermc.geyser.api.event.connection.ConnectionEvent;
|
||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
@ -23,36 +23,35 @@
|
|||||||
* @link https://github.com/GeyserMC/Geyser
|
* @link https://github.com/GeyserMC/Geyser
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.geysermc.geyser.api.command;
|
package org.geysermc.geyser.api.event.lifecycle;
|
||||||
|
|
||||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
import org.geysermc.event.Event;
|
||||||
|
import org.geysermc.geyser.api.command.Command;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages Bedrock commands within Geyser.
|
* Called when commands are defined within Geyser.
|
||||||
|
*
|
||||||
|
* This event allows you to register new commands using the {@link #register(Command)}
|
||||||
|
* method and retrieve the default commands defined.
|
||||||
*/
|
*/
|
||||||
public abstract class CommandManager {
|
public interface GeyserDefineCommandsEvent extends Event {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers the given {@link Command}.
|
* Registers the given {@link Command} into the Geyser
|
||||||
|
* command manager.
|
||||||
*
|
*
|
||||||
* @param command the command to register
|
* @param command the command to register
|
||||||
*/
|
*/
|
||||||
public abstract void register(@NonNull Command command);
|
void register(@NonNull Command command);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unregisters the given {@link Command}.
|
* Gets all the registered built-in {@link Command}s.
|
||||||
*
|
*
|
||||||
* @param command the command to unregister
|
* @return all the registered built-in commands
|
||||||
*/
|
|
||||||
public abstract void unregister(@NonNull Command command);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets all the registered {@link Command}s.
|
|
||||||
*
|
|
||||||
* @return all the registered commands
|
|
||||||
*/
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
public abstract Map<String, Command> commands();
|
Map<String, Command> commands();
|
||||||
}
|
}
|
@ -25,45 +25,36 @@
|
|||||||
|
|
||||||
package org.geysermc.geyser.api.event.lifecycle;
|
package org.geysermc.geyser.api.event.lifecycle;
|
||||||
|
|
||||||
import com.google.common.collect.Multimap;
|
|
||||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
import org.geysermc.geyser.api.event.Event;
|
import org.geysermc.event.Event;
|
||||||
import org.geysermc.geyser.api.item.custom.CustomItemData;
|
import org.geysermc.geyser.api.item.custom.CustomItemData;
|
||||||
import org.geysermc.geyser.api.item.custom.NonVanillaCustomItemData;
|
import org.geysermc.geyser.api.item.custom.NonVanillaCustomItemData;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called on Geyser's startup when looking for custom items. Custom items must be registered through this event.
|
* Called on Geyser's startup when looking for custom items. Custom items 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.
|
* This event will not be called if the "add non-Bedrock items" setting is disabled in the Geyser config.
|
||||||
*/
|
*/
|
||||||
public abstract class GeyserDefineCustomItemsEvent implements Event {
|
public interface GeyserDefineCustomItemsEvent extends Event {
|
||||||
private final Multimap<String, CustomItemData> customItems;
|
|
||||||
private final List<NonVanillaCustomItemData> nonVanillaCustomItems;
|
|
||||||
|
|
||||||
public GeyserDefineCustomItemsEvent(Multimap<String, CustomItemData> customItems, List<NonVanillaCustomItemData> nonVanillaCustomItems) {
|
|
||||||
this.customItems = customItems;
|
|
||||||
this.nonVanillaCustomItems = nonVanillaCustomItems;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a multimap of all the already registered custom items indexed by the item's extended java item's identifier.
|
* Gets a multimap of all the already registered custom items indexed by the item's extended java item's identifier.
|
||||||
*
|
*
|
||||||
* @return a multimap of all the already registered custom items
|
* @return a multimap of all the already registered custom items
|
||||||
*/
|
*/
|
||||||
public Map<String, Collection<CustomItemData>> getExistingCustomItems() {
|
@NonNull
|
||||||
return Collections.unmodifiableMap(this.customItems.asMap());
|
Map<String, Collection<CustomItemData>> getExistingCustomItems();
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the list of the already registered non-vanilla custom items.
|
* Gets the list of the already registered non-vanilla custom items.
|
||||||
*
|
*
|
||||||
* @return the list of the already registered non-vanilla custom items
|
* @return the list of the already registered non-vanilla custom items
|
||||||
*/
|
*/
|
||||||
public List<NonVanillaCustomItemData> getExistingNonVanillaCustomItems() {
|
@NonNull
|
||||||
return Collections.unmodifiableList(this.nonVanillaCustomItems);
|
List<NonVanillaCustomItemData> getExistingNonVanillaCustomItems();
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers a custom item with a base Java item. This is used to register items with custom textures and properties
|
* Registers a custom item with a base Java item. This is used to register items with custom textures and properties
|
||||||
@ -73,7 +64,7 @@ public abstract class GeyserDefineCustomItemsEvent implements Event {
|
|||||||
* @param customItemData the custom item data to register
|
* @param customItemData the custom item data to register
|
||||||
* @return if the item was registered
|
* @return if the item was registered
|
||||||
*/
|
*/
|
||||||
public abstract boolean register(@NonNull String identifier, @NonNull CustomItemData customItemData);
|
boolean register(@NonNull String identifier, @NonNull CustomItemData customItemData);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers a custom item with no base item. This is used for mods.
|
* Registers a custom item with no base item. This is used for mods.
|
||||||
@ -81,5 +72,5 @@ public abstract class GeyserDefineCustomItemsEvent implements Event {
|
|||||||
* @param customItemData the custom item data to register
|
* @param customItemData the custom item data to register
|
||||||
* @return if the item was registered
|
* @return if the item was registered
|
||||||
*/
|
*/
|
||||||
public abstract boolean register(@NonNull NonVanillaCustomItemData customItemData);
|
boolean register(@NonNull NonVanillaCustomItemData customItemData);
|
||||||
}
|
}
|
@ -26,7 +26,7 @@
|
|||||||
package org.geysermc.geyser.api.event.lifecycle;
|
package org.geysermc.geyser.api.event.lifecycle;
|
||||||
|
|
||||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
import org.geysermc.geyser.api.event.Event;
|
import org.geysermc.event.Event;
|
||||||
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -26,8 +26,9 @@
|
|||||||
package org.geysermc.geyser.api.event.lifecycle;
|
package org.geysermc.geyser.api.event.lifecycle;
|
||||||
|
|
||||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
import org.geysermc.geyser.api.event.Event;
|
import org.geysermc.event.Event;
|
||||||
import org.geysermc.geyser.api.event.EventBus;
|
import org.geysermc.geyser.api.event.EventBus;
|
||||||
|
import org.geysermc.geyser.api.event.EventRegistrar;
|
||||||
import org.geysermc.geyser.api.extension.ExtensionManager;
|
import org.geysermc.geyser.api.extension.ExtensionManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -36,5 +37,5 @@ import org.geysermc.geyser.api.extension.ExtensionManager;
|
|||||||
* @param extensionManager the extension manager
|
* @param extensionManager the extension manager
|
||||||
* @param eventBus the event bus
|
* @param eventBus the event bus
|
||||||
*/
|
*/
|
||||||
public record GeyserPostInitializeEvent(@NonNull ExtensionManager extensionManager, @NonNull EventBus eventBus) implements Event {
|
public record GeyserPostInitializeEvent(@NonNull ExtensionManager extensionManager, @NonNull EventBus<EventRegistrar> eventBus) implements Event {
|
||||||
}
|
}
|
||||||
|
@ -26,8 +26,9 @@
|
|||||||
package org.geysermc.geyser.api.event.lifecycle;
|
package org.geysermc.geyser.api.event.lifecycle;
|
||||||
|
|
||||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
import org.geysermc.geyser.api.event.Event;
|
import org.geysermc.event.Event;
|
||||||
import org.geysermc.geyser.api.event.EventBus;
|
import org.geysermc.geyser.api.event.EventBus;
|
||||||
|
import org.geysermc.geyser.api.event.EventRegistrar;
|
||||||
import org.geysermc.geyser.api.extension.ExtensionManager;
|
import org.geysermc.geyser.api.extension.ExtensionManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -36,5 +37,5 @@ import org.geysermc.geyser.api.extension.ExtensionManager;
|
|||||||
* @param extensionManager the extension manager
|
* @param extensionManager the extension manager
|
||||||
* @param eventBus the event bus
|
* @param eventBus the event bus
|
||||||
*/
|
*/
|
||||||
public record GeyserPreInitializeEvent(@NonNull ExtensionManager extensionManager, @NonNull EventBus eventBus) implements Event {
|
public record GeyserPreInitializeEvent(@NonNull ExtensionManager extensionManager, @NonNull EventBus<EventRegistrar> eventBus) implements Event {
|
||||||
}
|
}
|
||||||
|
@ -26,13 +26,13 @@
|
|||||||
package org.geysermc.geyser.api.event.lifecycle;
|
package org.geysermc.geyser.api.event.lifecycle;
|
||||||
|
|
||||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
import org.geysermc.geyser.api.command.CommandManager;
|
import org.geysermc.event.Event;
|
||||||
import org.geysermc.geyser.api.event.Event;
|
|
||||||
import org.geysermc.geyser.api.event.EventBus;
|
import org.geysermc.geyser.api.event.EventBus;
|
||||||
|
import org.geysermc.geyser.api.event.EventRegistrar;
|
||||||
import org.geysermc.geyser.api.extension.ExtensionManager;
|
import org.geysermc.geyser.api.extension.ExtensionManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when Geyser is shutting down.
|
* Called when Geyser is shutting down.
|
||||||
*/
|
*/
|
||||||
public record GeyserShutdownEvent(@NonNull ExtensionManager extensionManager, @NonNull CommandManager commandManager, @NonNull EventBus eventBus) implements Event {
|
public record GeyserShutdownEvent(@NonNull ExtensionManager extensionManager, @NonNull EventBus<EventRegistrar> eventBus) implements Event {
|
||||||
}
|
}
|
||||||
|
@ -25,16 +25,19 @@
|
|||||||
|
|
||||||
package org.geysermc.geyser.api.extension;
|
package org.geysermc.geyser.api.extension;
|
||||||
|
|
||||||
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
import org.geysermc.api.GeyserApiBase;
|
import org.geysermc.api.GeyserApiBase;
|
||||||
import org.geysermc.geyser.api.GeyserApi;
|
import org.geysermc.geyser.api.GeyserApi;
|
||||||
|
import org.geysermc.geyser.api.event.EventRegistrar;
|
||||||
import org.geysermc.geyser.api.event.ExtensionEventBus;
|
import org.geysermc.geyser.api.event.ExtensionEventBus;
|
||||||
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents an extension within Geyser.
|
* Represents an extension within Geyser.
|
||||||
*/
|
*/
|
||||||
public interface Extension {
|
public interface Extension extends EventRegistrar {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets if the extension is enabled
|
* Gets if the extension is enabled
|
||||||
@ -59,6 +62,7 @@ public interface Extension {
|
|||||||
*
|
*
|
||||||
* @return the extension's data folder
|
* @return the extension's data folder
|
||||||
*/
|
*/
|
||||||
|
@NonNull
|
||||||
default Path dataFolder() {
|
default Path dataFolder() {
|
||||||
return this.extensionLoader().dataFolder(this);
|
return this.extensionLoader().dataFolder(this);
|
||||||
}
|
}
|
||||||
@ -68,6 +72,7 @@ public interface Extension {
|
|||||||
*
|
*
|
||||||
* @return the extension event bus
|
* @return the extension event bus
|
||||||
*/
|
*/
|
||||||
|
@NonNull
|
||||||
default ExtensionEventBus eventBus() {
|
default ExtensionEventBus eventBus() {
|
||||||
return this.extensionLoader().eventBus(this);
|
return this.extensionLoader().eventBus(this);
|
||||||
}
|
}
|
||||||
@ -77,6 +82,7 @@ public interface Extension {
|
|||||||
*
|
*
|
||||||
* @return the extension manager
|
* @return the extension manager
|
||||||
*/
|
*/
|
||||||
|
@NonNull
|
||||||
default ExtensionManager extensionManager() {
|
default ExtensionManager extensionManager() {
|
||||||
return this.geyserApi().extensionManager();
|
return this.geyserApi().extensionManager();
|
||||||
}
|
}
|
||||||
@ -86,6 +92,7 @@ public interface Extension {
|
|||||||
*
|
*
|
||||||
* @return the extension's name
|
* @return the extension's name
|
||||||
*/
|
*/
|
||||||
|
@NonNull
|
||||||
default String name() {
|
default String name() {
|
||||||
return this.description().name();
|
return this.description().name();
|
||||||
}
|
}
|
||||||
@ -95,6 +102,7 @@ public interface Extension {
|
|||||||
*
|
*
|
||||||
* @return the extension's description
|
* @return the extension's description
|
||||||
*/
|
*/
|
||||||
|
@NonNull
|
||||||
default ExtensionDescription description() {
|
default ExtensionDescription description() {
|
||||||
return this.extensionLoader().description(this);
|
return this.extensionLoader().description(this);
|
||||||
}
|
}
|
||||||
@ -104,6 +112,7 @@ public interface Extension {
|
|||||||
*
|
*
|
||||||
* @return the extension's logger
|
* @return the extension's logger
|
||||||
*/
|
*/
|
||||||
|
@NonNull
|
||||||
default ExtensionLogger logger() {
|
default ExtensionLogger logger() {
|
||||||
return this.extensionLoader().logger(this);
|
return this.extensionLoader().logger(this);
|
||||||
}
|
}
|
||||||
@ -113,8 +122,9 @@ public interface Extension {
|
|||||||
*
|
*
|
||||||
* @return the extension loader
|
* @return the extension loader
|
||||||
*/
|
*/
|
||||||
|
@NonNull
|
||||||
default ExtensionLoader extensionLoader() {
|
default ExtensionLoader extensionLoader() {
|
||||||
return this.extensionManager().extensionLoader(this);
|
return Objects.requireNonNull(this.extensionManager().extensionLoader());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -122,6 +132,7 @@ public interface Extension {
|
|||||||
*
|
*
|
||||||
* @return the geyser api instance
|
* @return the geyser api instance
|
||||||
*/
|
*/
|
||||||
|
@NonNull
|
||||||
default GeyserApi geyserApi() {
|
default GeyserApi geyserApi() {
|
||||||
return GeyserApi.api();
|
return GeyserApi.api();
|
||||||
}
|
}
|
||||||
|
@ -30,12 +30,20 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is the Geyser extension description
|
* Represents the description of an {@link Extension}.
|
||||||
*/
|
*/
|
||||||
public interface ExtensionDescription {
|
public interface ExtensionDescription {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the extension's name
|
* Gets the extension's id.
|
||||||
|
*
|
||||||
|
* @return the extension's id
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
String id();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the extension's name.
|
||||||
*
|
*
|
||||||
* @return the extension's name
|
* @return the extension's name
|
||||||
*/
|
*/
|
||||||
@ -43,7 +51,7 @@ public interface ExtensionDescription {
|
|||||||
String name();
|
String name();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the extension's main class
|
* Gets the extension's main class.
|
||||||
*
|
*
|
||||||
* @return the extension's main class
|
* @return the extension's main class
|
||||||
*/
|
*/
|
||||||
@ -51,15 +59,37 @@ public interface ExtensionDescription {
|
|||||||
String main();
|
String main();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the extension's api version
|
* Gets the extension's major api version
|
||||||
|
*
|
||||||
|
* @return the extension's major api version
|
||||||
|
*/
|
||||||
|
int majorApiVersion();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the extension's minor api version
|
||||||
|
*
|
||||||
|
* @return the extension's minor api version
|
||||||
|
*/
|
||||||
|
int minorApiVersion();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the extension's patch api version
|
||||||
|
*
|
||||||
|
* @return the extension's patch api version
|
||||||
|
*/
|
||||||
|
int patchApiVersion();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the extension's api version.
|
||||||
*
|
*
|
||||||
* @return the extension's api version
|
* @return the extension's api version
|
||||||
*/
|
*/
|
||||||
@NonNull
|
default String apiVersion() {
|
||||||
String apiVersion();
|
return majorApiVersion() + "." + minorApiVersion() + "." + patchApiVersion();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the extension's description
|
* Gets the extension's description.
|
||||||
*
|
*
|
||||||
* @return the extension's description
|
* @return the extension's description
|
||||||
*/
|
*/
|
||||||
@ -67,7 +97,7 @@ public interface ExtensionDescription {
|
|||||||
String version();
|
String version();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the extension's authors
|
* Gets the extension's authors.
|
||||||
*
|
*
|
||||||
* @return the extension's authors
|
* @return the extension's authors
|
||||||
*/
|
*/
|
||||||
|
@ -34,7 +34,6 @@ import java.nio.file.Path;
|
|||||||
* The extension loader is responsible for loading, unloading, enabling and disabling extensions
|
* The extension loader is responsible for loading, unloading, enabling and disabling extensions
|
||||||
*/
|
*/
|
||||||
public abstract class ExtensionLoader {
|
public abstract class ExtensionLoader {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets if the given {@link Extension} is enabled.
|
* Gets if the given {@link Extension} is enabled.
|
||||||
*
|
*
|
||||||
@ -101,6 +100,6 @@ public abstract class ExtensionLoader {
|
|||||||
* @param extensionManager the extension manager
|
* @param extensionManager the extension manager
|
||||||
*/
|
*/
|
||||||
protected void register(@NonNull Extension extension, @NonNull ExtensionManager extensionManager) {
|
protected void register(@NonNull Extension extension, @NonNull ExtensionManager extensionManager) {
|
||||||
extensionManager.register(extension, this);
|
extensionManager.register(extension);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -29,7 +29,6 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
|||||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages Geyser {@link Extension}s
|
* Manages Geyser {@link Extension}s
|
||||||
@ -59,15 +58,6 @@ public abstract class ExtensionManager {
|
|||||||
*/
|
*/
|
||||||
public abstract void disable(@NonNull Extension extension);
|
public abstract void disable(@NonNull Extension extension);
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the {@link ExtensionLoader} responsible for loading
|
|
||||||
* the given {@link Extension}.
|
|
||||||
*
|
|
||||||
* @return the extension loader for loading the given extension
|
|
||||||
*/
|
|
||||||
@Nullable
|
|
||||||
public abstract ExtensionLoader extensionLoader(@NonNull Extension extension);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets all the {@link Extension}s currently loaded.
|
* Gets all the {@link Extension}s currently loaded.
|
||||||
*
|
*
|
||||||
@ -77,37 +67,19 @@ public abstract class ExtensionManager {
|
|||||||
public abstract Collection<Extension> extensions();
|
public abstract Collection<Extension> extensions();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the {@link ExtensionLoader} with the given identifier.
|
* Gets the {@link ExtensionLoader}.
|
||||||
*
|
*
|
||||||
* @param identifier the identifier
|
* @return the extension loader
|
||||||
* @return the extension loader at the given identifier
|
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
public abstract ExtensionLoader extensionLoader(@NonNull String identifier);
|
public abstract ExtensionLoader extensionLoader();
|
||||||
|
|
||||||
/**
|
|
||||||
* Registers an {@link ExtensionLoader} with the given identifier.
|
|
||||||
*
|
|
||||||
* @param identifier the identifier
|
|
||||||
* @param extensionLoader the extension loader
|
|
||||||
*/
|
|
||||||
public abstract void registerExtensionLoader(@NonNull String identifier, @NonNull ExtensionLoader extensionLoader);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets all the currently registered {@link ExtensionLoader}s.
|
|
||||||
*
|
|
||||||
* @return all the currently registered extension loaders
|
|
||||||
*/
|
|
||||||
@NonNull
|
|
||||||
public abstract Map<String, ExtensionLoader> extensionLoaders();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers an {@link Extension} with the given {@link ExtensionLoader}.
|
* Registers an {@link Extension} with the given {@link ExtensionLoader}.
|
||||||
*
|
*
|
||||||
* @param extension the extension
|
* @param extension the extension
|
||||||
* @param loader the loader
|
|
||||||
*/
|
*/
|
||||||
public abstract void register(@NonNull Extension extension, @NonNull ExtensionLoader loader);
|
public abstract void register(@NonNull Extension extension);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads all extensions from the given {@link ExtensionLoader}.
|
* Loads all extensions from the given {@link ExtensionLoader}.
|
||||||
|
@ -25,6 +25,8 @@
|
|||||||
|
|
||||||
package org.geysermc.geyser.api.network;
|
package org.geysermc.geyser.api.network;
|
||||||
|
|
||||||
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The listener that handles connections from Minecraft:
|
* The listener that handles connections from Minecraft:
|
||||||
* Bedrock Edition.
|
* Bedrock Edition.
|
||||||
@ -37,6 +39,7 @@ public interface BedrockListener {
|
|||||||
*
|
*
|
||||||
* @return the listening address
|
* @return the listening address
|
||||||
*/
|
*/
|
||||||
|
@NonNull
|
||||||
String address();
|
String address();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -25,6 +25,8 @@
|
|||||||
|
|
||||||
package org.geysermc.geyser.api.network;
|
package org.geysermc.geyser.api.network;
|
||||||
|
|
||||||
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents the Java server that Geyser is connecting to.
|
* Represents the Java server that Geyser is connecting to.
|
||||||
*/
|
*/
|
||||||
@ -63,5 +65,6 @@ public interface RemoteServer {
|
|||||||
*
|
*
|
||||||
* @return the auth type required by the remote server
|
* @return the auth type required by the remote server
|
||||||
*/
|
*/
|
||||||
|
@NonNull
|
||||||
AuthType authType();
|
AuthType authType();
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
val bungeeVersion = "a7c6ede";
|
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
api(projects.core)
|
api(projects.core)
|
||||||
|
|
||||||
|
implementation(libs.adventure.text.serializer.bungeecord)
|
||||||
}
|
}
|
||||||
|
|
||||||
platformRelocate("net.md_5.bungee.jni")
|
platformRelocate("net.md_5.bungee.jni")
|
||||||
@ -10,7 +10,7 @@ platformRelocate("io.netty.channel.kqueue") // This is not used because relocati
|
|||||||
platformRelocate("net.kyori")
|
platformRelocate("net.kyori")
|
||||||
|
|
||||||
// These dependencies are already present on the platform
|
// These dependencies are already present on the platform
|
||||||
provided("com.github.SpigotMC.BungeeCord", "bungeecord-proxy", bungeeVersion)
|
provided(libs.bungeecord.proxy)
|
||||||
|
|
||||||
application {
|
application {
|
||||||
mainClass.set("org.geysermc.geyser.platform.bungeecord.GeyserBungeeMain")
|
mainClass.set("org.geysermc.geyser.platform.bungeecord.GeyserBungeeMain")
|
||||||
|
@ -29,7 +29,6 @@ import lombok.Getter;
|
|||||||
import net.md_5.bungee.api.ProxyServer;
|
import net.md_5.bungee.api.ProxyServer;
|
||||||
import net.md_5.bungee.api.plugin.Plugin;
|
import net.md_5.bungee.api.plugin.Plugin;
|
||||||
import org.geysermc.geyser.dump.BootstrapDumpInfo;
|
import org.geysermc.geyser.dump.BootstrapDumpInfo;
|
||||||
import org.geysermc.geyser.text.AsteriskSerializer;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@ -52,17 +51,17 @@ public class GeyserBungeeDumpInfo extends BootstrapDumpInfo {
|
|||||||
this.plugins = new ArrayList<>();
|
this.plugins = new ArrayList<>();
|
||||||
|
|
||||||
for (net.md_5.bungee.api.config.ListenerInfo listener : proxy.getConfig().getListeners()) {
|
for (net.md_5.bungee.api.config.ListenerInfo listener : proxy.getConfig().getListeners()) {
|
||||||
String hostname;
|
this.listeners.add(new ListenerInfo(listener.getHost().getHostString(), listener.getHost().getPort()));
|
||||||
if (AsteriskSerializer.showSensitive || (listener.getHost().getHostString().equals("") || listener.getHost().getHostString().equals("0.0.0.0"))) {
|
|
||||||
hostname = listener.getHost().getHostString();
|
|
||||||
} else {
|
|
||||||
hostname = "***";
|
|
||||||
}
|
|
||||||
this.listeners.add(new ListenerInfo(hostname, listener.getHost().getPort()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Plugin plugin : proxy.getPluginManager().getPlugins()) {
|
for (Plugin plugin : proxy.getPluginManager().getPlugins()) {
|
||||||
this.plugins.add(new PluginInfo(true, plugin.getDescription().getName(), plugin.getDescription().getVersion(), plugin.getDescription().getMain(), Collections.singletonList(plugin.getDescription().getAuthor())));
|
this.plugins.add(new PluginInfo(
|
||||||
|
true,
|
||||||
|
plugin.getDescription().getName(),
|
||||||
|
plugin.getDescription().getVersion(),
|
||||||
|
plugin.getDescription().getMain(),
|
||||||
|
Collections.singletonList(plugin.getDescription().getAuthor()))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,12 +25,17 @@
|
|||||||
|
|
||||||
package org.geysermc.geyser.platform.bungeecord;
|
package org.geysermc.geyser.platform.bungeecord;
|
||||||
|
|
||||||
|
import io.netty.channel.Channel;
|
||||||
|
import net.md_5.bungee.BungeeCord;
|
||||||
import net.md_5.bungee.api.config.ListenerInfo;
|
import net.md_5.bungee.api.config.ListenerInfo;
|
||||||
import net.md_5.bungee.api.plugin.Plugin;
|
import net.md_5.bungee.api.plugin.Plugin;
|
||||||
|
import net.md_5.bungee.protocol.ProtocolConstants;
|
||||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
import org.geysermc.common.PlatformType;
|
import org.geysermc.common.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.extension.Extension;
|
||||||
import org.geysermc.geyser.api.network.AuthType;
|
import org.geysermc.geyser.api.network.AuthType;
|
||||||
import org.geysermc.geyser.command.GeyserCommandManager;
|
import org.geysermc.geyser.command.GeyserCommandManager;
|
||||||
import org.geysermc.geyser.configuration.GeyserConfiguration;
|
import org.geysermc.geyser.configuration.GeyserConfiguration;
|
||||||
@ -38,22 +43,25 @@ import org.geysermc.geyser.dump.BootstrapDumpInfo;
|
|||||||
import org.geysermc.geyser.ping.GeyserLegacyPingPassthrough;
|
import org.geysermc.geyser.ping.GeyserLegacyPingPassthrough;
|
||||||
import org.geysermc.geyser.ping.IGeyserPingPassthrough;
|
import org.geysermc.geyser.ping.IGeyserPingPassthrough;
|
||||||
import org.geysermc.geyser.platform.bungeecord.command.GeyserBungeeCommandExecutor;
|
import org.geysermc.geyser.platform.bungeecord.command.GeyserBungeeCommandExecutor;
|
||||||
import org.geysermc.geyser.platform.bungeecord.command.GeyserBungeeCommandManager;
|
|
||||||
import org.geysermc.geyser.text.GeyserLocale;
|
import org.geysermc.geyser.text.GeyserLocale;
|
||||||
import org.geysermc.geyser.util.FileUtils;
|
import org.geysermc.geyser.util.FileUtils;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.net.SocketAddress;
|
import java.net.SocketAddress;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
|
||||||
public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap {
|
public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap {
|
||||||
|
|
||||||
private GeyserBungeeCommandManager geyserCommandManager;
|
private GeyserCommandManager geyserCommandManager;
|
||||||
private GeyserBungeeConfiguration geyserConfig;
|
private GeyserBungeeConfiguration geyserConfig;
|
||||||
private GeyserBungeeInjector geyserInjector;
|
private GeyserBungeeInjector geyserInjector;
|
||||||
private GeyserBungeeLogger geyserLogger;
|
private GeyserBungeeLogger geyserLogger;
|
||||||
@ -62,9 +70,23 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap {
|
|||||||
private GeyserImpl geyser;
|
private GeyserImpl geyser;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onEnable() {
|
public void onLoad() {
|
||||||
GeyserLocale.init(this);
|
GeyserLocale.init(this);
|
||||||
|
|
||||||
|
// Copied from ViaVersion.
|
||||||
|
// https://github.com/ViaVersion/ViaVersion/blob/b8072aad86695cc8ec6f5e4103e43baf3abf6cc5/bungee/src/main/java/us/myles/ViaVersion/BungeePlugin.java#L43
|
||||||
|
try {
|
||||||
|
ProtocolConstants.class.getField("MINECRAFT_1_19_3");
|
||||||
|
} catch (NoSuchFieldException e) {
|
||||||
|
getLogger().warning(" / \\");
|
||||||
|
getLogger().warning(" / \\");
|
||||||
|
getLogger().warning(" / | \\");
|
||||||
|
getLogger().warning(" / | \\ " + GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_proxy", getProxy().getName()));
|
||||||
|
getLogger().warning(" / \\ " + GeyserLocale.getLocaleStringLog("geyser.may_not_work_as_intended_all_caps"));
|
||||||
|
getLogger().warning(" / o \\");
|
||||||
|
getLogger().warning("/_____________\\");
|
||||||
|
}
|
||||||
|
|
||||||
if (!getDataFolder().exists())
|
if (!getDataFolder().exists())
|
||||||
getDataFolder().mkdir();
|
getDataFolder().mkdir();
|
||||||
|
|
||||||
@ -80,6 +102,20 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.geyserLogger = new GeyserBungeeLogger(getLogger(), geyserConfig.isDebugMode());
|
||||||
|
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
|
||||||
|
|
||||||
|
this.geyser = GeyserImpl.load(PlatformType.BUNGEECORD, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEnable() {
|
||||||
|
// Remove this in like a year
|
||||||
|
if (getProxy().getPluginManager().getPlugin("floodgate-bungee") != null) {
|
||||||
|
geyserLogger.severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.outdated", "https://ci.opencollab.dev/job/GeyserMC/job/Floodgate/job/master/"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (getProxy().getConfig().getListeners().size() == 1) {
|
if (getProxy().getConfig().getListeners().size() == 1) {
|
||||||
ListenerInfo listener = getProxy().getConfig().getListeners().toArray(new ListenerInfo[0])[0];
|
ListenerInfo listener = getProxy().getConfig().getListeners().toArray(new ListenerInfo[0])[0];
|
||||||
|
|
||||||
@ -100,13 +136,22 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.geyserLogger = new GeyserBungeeLogger(getLogger(), geyserConfig.isDebugMode());
|
// Force-disable query if enabled, or else Geyser won't enable
|
||||||
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
|
for (ListenerInfo info : getProxy().getConfig().getListeners()) {
|
||||||
|
if (info.isQueryEnabled() && info.getQueryPort() == geyserConfig.getBedrock().port()) {
|
||||||
// Remove this in like a year
|
try {
|
||||||
if (getProxy().getPluginManager().getPlugin("floodgate-bungee") != null) {
|
Field queryField = ListenerInfo.class.getDeclaredField("queryEnabled");
|
||||||
geyserLogger.severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.outdated", "https://ci.opencollab.dev/job/GeyserMC/job/Floodgate/job/master/"));
|
queryField.setAccessible(true);
|
||||||
return;
|
queryField.setBoolean(info, false);
|
||||||
|
geyserLogger.warning("We force-disabled query on port " + info.getQueryPort() + " in order for Geyser to boot up successfully. " +
|
||||||
|
"To remove this message, disable query in your proxy's config.");
|
||||||
|
} catch (NoSuchFieldException | IllegalAccessException e) {
|
||||||
|
geyserLogger.warning("Could not force-disable query. Geyser may not start correctly!");
|
||||||
|
if (geyserLogger.isDebug()) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (geyserConfig.getRemote().authType() == AuthType.FLOODGATE && getProxy().getPluginManager().getPlugin("floodgate") == null) {
|
if (geyserConfig.getRemote().authType() == AuthType.FLOODGATE && getProxy().getPluginManager().getPlugin("floodgate") == null) {
|
||||||
@ -120,22 +165,63 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap {
|
|||||||
|
|
||||||
geyserConfig.loadFloodgate(this);
|
geyserConfig.loadFloodgate(this);
|
||||||
|
|
||||||
this.geyser = GeyserImpl.start(PlatformType.BUNGEECORD, this);
|
// Big hack - Bungee does not provide us an event to listen to, so schedule a repeating
|
||||||
|
// task that waits for a field to be filled which is set after the plugin enable
|
||||||
|
// process is complete
|
||||||
|
this.awaitStartupCompletion(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private void awaitStartupCompletion(int tries) {
|
||||||
|
// After 20 tries give up waiting. This will happen
|
||||||
|
// just after 3 minutes approximately
|
||||||
|
if (tries >= 20) {
|
||||||
|
this.geyserLogger.warning("BungeeCord plugin startup is taking abnormally long, so Geyser is starting now. " +
|
||||||
|
"If all your plugins are loaded properly, this is a bug! " +
|
||||||
|
"If not, consider cutting down the amount of plugins on your proxy as it is causing abnormally slow starting times.");
|
||||||
|
this.postStartup();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Field listenersField = BungeeCord.getInstance().getClass().getDeclaredField("listeners");
|
||||||
|
listenersField.setAccessible(true);
|
||||||
|
|
||||||
|
Collection<Channel> listeners = (Collection<Channel>) listenersField.get(BungeeCord.getInstance());
|
||||||
|
if (listeners.isEmpty()) {
|
||||||
|
this.getProxy().getScheduler().schedule(this, this::postStartup, tries, TimeUnit.SECONDS);
|
||||||
|
} else {
|
||||||
|
this.awaitStartupCompletion(++tries);
|
||||||
|
}
|
||||||
|
} catch (NoSuchFieldException | IllegalAccessException ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void postStartup() {
|
||||||
|
GeyserImpl.start();
|
||||||
|
|
||||||
this.geyserInjector = new GeyserBungeeInjector(this);
|
this.geyserInjector = new GeyserBungeeInjector(this);
|
||||||
this.geyserInjector.initializeLocalChannel(this);
|
this.geyserInjector.initializeLocalChannel(this);
|
||||||
|
|
||||||
this.geyserCommandManager = new GeyserBungeeCommandManager(geyser);
|
this.geyserCommandManager = new GeyserCommandManager(geyser);
|
||||||
this.geyserCommandManager.init();
|
this.geyserCommandManager.init();
|
||||||
|
|
||||||
|
this.getProxy().getPluginManager().registerCommand(this, new GeyserBungeeCommandExecutor("geyser", this.geyser, this.geyserCommandManager.getCommands()));
|
||||||
|
for (Map.Entry<Extension, Map<String, Command>> entry : this.geyserCommandManager.extensionCommands().entrySet()) {
|
||||||
|
Map<String, Command> commands = entry.getValue();
|
||||||
|
if (commands.isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.getProxy().getPluginManager().registerCommand(this, new GeyserBungeeCommandExecutor(entry.getKey().description().id(), this.geyser, commands));
|
||||||
|
}
|
||||||
|
|
||||||
if (geyserConfig.isLegacyPingPassthrough()) {
|
if (geyserConfig.isLegacyPingPassthrough()) {
|
||||||
this.geyserBungeePingPassthrough = GeyserLegacyPingPassthrough.init(geyser);
|
this.geyserBungeePingPassthrough = GeyserLegacyPingPassthrough.init(geyser);
|
||||||
} else {
|
} else {
|
||||||
this.geyserBungeePingPassthrough = new GeyserBungeePingPassthrough(getProxy());
|
this.geyserBungeePingPassthrough = new GeyserBungeePingPassthrough(getProxy());
|
||||||
}
|
}
|
||||||
|
|
||||||
this.getProxy().getPluginManager().registerCommand(this, new GeyserBungeeCommandExecutor("geyser", geyser, geyserCommandManager.getCommands()));
|
|
||||||
this.getProxy().getPluginManager().registerCommand(this, new GeyserBungeeCommandExecutor("geyserext", geyser, geyserCommandManager.commands()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* @author GeyserMC
|
||||||
|
* @link https://github.com/GeyserMC/Geyser
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.geysermc.geyser.platform.bungeecord;
|
||||||
|
|
||||||
|
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||||
|
import net.md_5.bungee.api.event.PostLoginEvent;
|
||||||
|
import net.md_5.bungee.api.plugin.Listener;
|
||||||
|
import net.md_5.bungee.event.EventHandler;
|
||||||
|
import org.geysermc.geyser.Constants;
|
||||||
|
import org.geysermc.geyser.GeyserImpl;
|
||||||
|
import org.geysermc.geyser.platform.bungeecord.command.BungeeCommandSource;
|
||||||
|
import org.geysermc.geyser.util.VersionCheckUtils;
|
||||||
|
|
||||||
|
public final class GeyserBungeeUpdateListener implements Listener {
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onPlayerJoin(final PostLoginEvent event) {
|
||||||
|
if (GeyserImpl.getInstance().getConfig().isNotifyOnNewBedrockUpdate()) {
|
||||||
|
final ProxiedPlayer player = event.getPlayer();
|
||||||
|
if (player.hasPermission(Constants.UPDATE_PERMISSION)) {
|
||||||
|
VersionCheckUtils.checkForGeyserUpdate(() -> new BungeeCommandSource(player));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -25,11 +25,15 @@
|
|||||||
|
|
||||||
package org.geysermc.geyser.platform.bungeecord.command;
|
package org.geysermc.geyser.platform.bungeecord.command;
|
||||||
|
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.serializer.bungeecord.BungeeComponentSerializer;
|
||||||
import net.md_5.bungee.api.chat.TextComponent;
|
import net.md_5.bungee.api.chat.TextComponent;
|
||||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||||
import org.geysermc.geyser.command.GeyserCommandSource;
|
import org.geysermc.geyser.command.GeyserCommandSource;
|
||||||
import org.geysermc.geyser.text.GeyserLocale;
|
import org.geysermc.geyser.text.GeyserLocale;
|
||||||
|
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
public class BungeeCommandSource implements GeyserCommandSource {
|
public class BungeeCommandSource implements GeyserCommandSource {
|
||||||
|
|
||||||
private final net.md_5.bungee.api.CommandSender handle;
|
private final net.md_5.bungee.api.CommandSender handle;
|
||||||
@ -50,6 +54,18 @@ public class BungeeCommandSource implements GeyserCommandSource {
|
|||||||
handle.sendMessage(TextComponent.fromLegacyText(message));
|
handle.sendMessage(TextComponent.fromLegacyText(message));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final int PROTOCOL_HEX_COLOR = 713; // Added 20w17a
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendMessage(Component message) {
|
||||||
|
if (handle instanceof ProxiedPlayer player && player.getPendingConnection().getVersion() >= PROTOCOL_HEX_COLOR) {
|
||||||
|
// Include hex colors
|
||||||
|
handle.sendMessage(BungeeComponentSerializer.get().serialize(message));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
handle.sendMessage(BungeeComponentSerializer.legacy().serialize(message));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isConsole() {
|
public boolean isConsole() {
|
||||||
return !(handle instanceof ProxiedPlayer);
|
return !(handle instanceof ProxiedPlayer);
|
||||||
@ -58,8 +74,11 @@ public class BungeeCommandSource implements GeyserCommandSource {
|
|||||||
@Override
|
@Override
|
||||||
public String locale() {
|
public String locale() {
|
||||||
if (handle instanceof ProxiedPlayer player) {
|
if (handle instanceof ProxiedPlayer player) {
|
||||||
String locale = player.getLocale().getLanguage() + "_" + player.getLocale().getCountry();
|
Locale locale = player.getLocale();
|
||||||
return GeyserLocale.formatLocale(locale);
|
if (locale != null) {
|
||||||
|
// Locale can be null early on in the conneciton
|
||||||
|
return GeyserLocale.formatLocale(locale.getLanguage() + "_" + locale.getCountry());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return GeyserLocale.getDefaultLocale();
|
return GeyserLocale.getDefaultLocale();
|
||||||
}
|
}
|
||||||
|
@ -69,6 +69,9 @@ public class GeyserBungeeCommandExecutor extends Command implements TabExecutor
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
command.execute(session, commandSender, args.length > 1 ? Arrays.copyOfRange(args, 1, args.length) : new String[0]);
|
command.execute(session, commandSender, args.length > 1 ? Arrays.copyOfRange(args, 1, args.length) : new String[0]);
|
||||||
|
} else {
|
||||||
|
String message = GeyserLocale.getPlayerLocaleString("geyser.bootstrap.command.not_found", commandSender.locale());
|
||||||
|
commandSender.sendMessage(ChatColor.RED + message);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.commandExecutor.getCommand("help").execute(session, commandSender, new String[0]);
|
this.commandExecutor.getCommand("help").execute(session, commandSender, new String[0]);
|
||||||
|
77
bootstrap/fabric/build.gradle.kts
Normale Datei
77
bootstrap/fabric/build.gradle.kts
Normale Datei
@ -0,0 +1,77 @@
|
|||||||
|
plugins {
|
||||||
|
id("fabric-loom") version "1.0-SNAPSHOT"
|
||||||
|
}
|
||||||
|
|
||||||
|
java {
|
||||||
|
targetCompatibility = JavaVersion.VERSION_17
|
||||||
|
sourceCompatibility = JavaVersion.VERSION_17
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
//to change the versions see the gradle.properties file
|
||||||
|
minecraft(libs.fabric.minecraft)
|
||||||
|
mappings(loom.officialMojangMappings())
|
||||||
|
modImplementation(libs.fabric.loader)
|
||||||
|
|
||||||
|
// Fabric API. This is technically optional, but you probably want it anyway.
|
||||||
|
modImplementation(libs.fabric.api)
|
||||||
|
|
||||||
|
// This should be in the libs TOML, but something about modImplementation AND include just doesn't work
|
||||||
|
include(modImplementation("me.lucko", "fabric-permissions-api", "0.2-SNAPSHOT"))
|
||||||
|
|
||||||
|
// PSA: Some older mods, compiled on Loom 0.2.1, might have outdated Maven POMs.
|
||||||
|
// You may need to force-disable transitiveness on them.
|
||||||
|
|
||||||
|
api(projects.core)
|
||||||
|
shadow(projects.core) {
|
||||||
|
exclude(group = "com.google.guava", module = "guava")
|
||||||
|
exclude(group = "com.google.code.gson", module = "gson")
|
||||||
|
exclude(group = "org.slf4j")
|
||||||
|
exclude(group = "com.nukkitx.fastutil")
|
||||||
|
exclude(group = "io.netty.incubator")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenLocal()
|
||||||
|
maven("https://repo.opencollab.dev/maven-releases/")
|
||||||
|
maven("https://repo.opencollab.dev/maven-snapshots/")
|
||||||
|
maven("https://jitpack.io")
|
||||||
|
maven("https://oss.sonatype.org/content/repositories/snapshots/")
|
||||||
|
maven("https://s01.oss.sonatype.org/content/repositories/snapshots/")
|
||||||
|
}
|
||||||
|
|
||||||
|
application {
|
||||||
|
mainClass.set("org.geysermc.geyser.platform.fabric.GeyserFabricMain")
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks {
|
||||||
|
// Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task
|
||||||
|
// if it is present.
|
||||||
|
// If you remove this task, sources will not be generated.
|
||||||
|
sourcesJar {
|
||||||
|
archiveClassifier.set("sources")
|
||||||
|
from(sourceSets.main.get().allSource)
|
||||||
|
}
|
||||||
|
|
||||||
|
shadowJar {
|
||||||
|
// Mirrors the example fabric project, otherwise tons of dependencies are shaded that shouldn't be
|
||||||
|
configurations = listOf(project.configurations.shadow.get())
|
||||||
|
// The remapped shadowJar is the final desired Geyser-Fabric.jar
|
||||||
|
archiveVersion.set(project.version.toString())
|
||||||
|
archiveClassifier.set("shaded")
|
||||||
|
|
||||||
|
relocate("org.objectweb.asm", "org.geysermc.relocate.asm")
|
||||||
|
relocate("org.yaml", "org.geysermc.relocate.yaml") // https://github.com/CardboardPowered/cardboard/issues/139
|
||||||
|
relocate("com.fasterxml.jackson", "org.geysermc.relocate.jackson")
|
||||||
|
relocate("net.kyori", "org.geysermc.relocate.kyori")
|
||||||
|
}
|
||||||
|
|
||||||
|
remapJar {
|
||||||
|
dependsOn(shadowJar)
|
||||||
|
inputFile.set(shadowJar.get().archiveFile)
|
||||||
|
archiveBaseName.set("Geyser-Fabric")
|
||||||
|
archiveClassifier.set("")
|
||||||
|
archiveVersion.set("")
|
||||||
|
}
|
||||||
|
}
|
@ -23,34 +23,29 @@
|
|||||||
* @link https://github.com/GeyserMC/Geyser
|
* @link https://github.com/GeyserMC/Geyser
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.geysermc.geyser.platform.spigot.world.manager;
|
package org.geysermc.geyser.platform.fabric;
|
||||||
|
|
||||||
import org.bukkit.plugin.Plugin;
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import org.geysermc.geyser.level.block.BlockStateValues;
|
import net.fabricmc.loader.api.FabricLoader;
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
import net.fabricmc.loader.api.ModContainer;
|
||||||
|
import org.geysermc.geyser.FloodgateKeyLoader;
|
||||||
|
import org.geysermc.geyser.configuration.GeyserJacksonConfiguration;
|
||||||
|
|
||||||
/**
|
import java.nio.file.Path;
|
||||||
* Should only be used when we know {@link GeyserSpigotWorldManager#getBlockAt(GeyserSession, int, int, int)}
|
|
||||||
* cannot be accurate. Typically, this is when ViaVersion is not installed but a client still manages to connect.
|
public class GeyserFabricConfiguration extends GeyserJacksonConfiguration {
|
||||||
* If this occurs to you somehow, please let us know!!
|
@JsonIgnore
|
||||||
*/
|
private Path floodgateKeyPath;
|
||||||
public class GeyserSpigotFallbackWorldManager extends GeyserSpigotWorldManager {
|
|
||||||
public GeyserSpigotFallbackWorldManager(Plugin plugin) {
|
public void loadFloodgate(GeyserFabricMod geyser, ModContainer floodgate) {
|
||||||
super(plugin);
|
Path geyserDataFolder = geyser.getConfigFolder();
|
||||||
|
Path floodgateDataFolder = floodgate != null ? FabricLoader.getInstance().getConfigDir().resolve("floodgate") : null;
|
||||||
|
|
||||||
|
floodgateKeyPath = FloodgateKeyLoader.getKeyPath(this, floodgateDataFolder, geyserDataFolder, geyser.getGeyserLogger());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getBlockAt(GeyserSession session, int x, int y, int z) {
|
public Path getFloodgateKeyPath() {
|
||||||
return BlockStateValues.JAVA_AIR_ID;
|
return floodgateKeyPath;
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean hasOwnChunkCache() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isLegacy() {
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* @author GeyserMC
|
||||||
|
* @link https://github.com/GeyserMC/Geyser
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.geysermc.geyser.platform.fabric;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
import net.fabricmc.api.EnvType;
|
||||||
|
import net.fabricmc.loader.api.FabricLoader;
|
||||||
|
import net.fabricmc.loader.api.ModContainer;
|
||||||
|
import net.fabricmc.loader.api.metadata.ModMetadata;
|
||||||
|
import net.fabricmc.loader.api.metadata.Person;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import org.geysermc.geyser.dump.BootstrapDumpInfo;
|
||||||
|
import org.geysermc.geyser.text.AsteriskSerializer;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public class GeyserFabricDumpInfo extends BootstrapDumpInfo {
|
||||||
|
|
||||||
|
private String platformVersion = null;
|
||||||
|
private final EnvType environmentType;
|
||||||
|
|
||||||
|
@AsteriskSerializer.Asterisk(isIp = true)
|
||||||
|
private final String serverIP;
|
||||||
|
private final int serverPort;
|
||||||
|
private final List<ModInfo> mods;
|
||||||
|
|
||||||
|
public GeyserFabricDumpInfo(MinecraftServer server) {
|
||||||
|
FabricLoader.getInstance().getModContainer("fabricloader").ifPresent(mod ->
|
||||||
|
this.platformVersion = mod.getMetadata().getVersion().getFriendlyString());
|
||||||
|
|
||||||
|
this.environmentType = FabricLoader.getInstance().getEnvironmentType();
|
||||||
|
this.serverIP = server.getLocalIp() == null ? "unknown" : server.getLocalIp();
|
||||||
|
this.serverPort = server.getPort();
|
||||||
|
this.mods = new ArrayList<>();
|
||||||
|
|
||||||
|
for (ModContainer mod : FabricLoader.getInstance().getAllMods()) {
|
||||||
|
ModMetadata meta = mod.getMetadata();
|
||||||
|
this.mods.add(new ModInfo(
|
||||||
|
FabricLoader.getInstance().isModLoaded(meta.getId()),
|
||||||
|
meta.getId(),
|
||||||
|
meta.getVersion().getFriendlyString(),
|
||||||
|
meta.getAuthors().stream().map(Person::getName).collect(Collectors.toList()))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public static class ModInfo {
|
||||||
|
public boolean enabled;
|
||||||
|
public String name;
|
||||||
|
public String version;
|
||||||
|
public List<String> authors;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* @author GeyserMC
|
||||||
|
* @link https://github.com/GeyserMC/Geyser
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.geysermc.geyser.platform.fabric;
|
||||||
|
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import org.geysermc.geyser.GeyserLogger;
|
||||||
|
import org.geysermc.geyser.text.ChatColor;
|
||||||
|
|
||||||
|
public class GeyserFabricLogger implements GeyserLogger {
|
||||||
|
private final Logger logger = LogManager.getLogger("geyser-fabric");
|
||||||
|
|
||||||
|
private boolean debug;
|
||||||
|
|
||||||
|
public GeyserFabricLogger(boolean isDebug) {
|
||||||
|
debug = isDebug;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void severe(String message) {
|
||||||
|
logger.fatal(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void severe(String message, Throwable error) {
|
||||||
|
logger.fatal(message, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void error(String message) {
|
||||||
|
logger.error(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void error(String message, Throwable error) {
|
||||||
|
logger.error(message, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void warning(String message) {
|
||||||
|
logger.warn(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void info(String message) {
|
||||||
|
logger.info(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendMessage(Component message) {
|
||||||
|
// As of Java Edition 1.19.2, Fabric's console doesn't natively support legacy format
|
||||||
|
String flattened = LegacyComponentSerializer.legacySection().serialize(message);
|
||||||
|
// Add the reset at the end, or else format will persist... forever.
|
||||||
|
// https://cdn.discordapp.com/attachments/573909525132738590/1033904509170225242/unknown.png
|
||||||
|
String text = ChatColor.toANSI(flattened) + ChatColor.ANSI_RESET;
|
||||||
|
info(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void debug(String message) {
|
||||||
|
if (debug) {
|
||||||
|
logger.info(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDebug(boolean debug) {
|
||||||
|
this.debug = debug;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isDebug() {
|
||||||
|
return debug;
|
||||||
|
}
|
||||||
|
}
|
@ -23,19 +23,23 @@
|
|||||||
* @link https://github.com/GeyserMC/Geyser
|
* @link https://github.com/GeyserMC/Geyser
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.geysermc.geyser.platform.bungeecord.command;
|
package org.geysermc.geyser.platform.fabric;
|
||||||
|
|
||||||
import org.geysermc.geyser.GeyserImpl;
|
import org.geysermc.geyser.GeyserMain;
|
||||||
import org.geysermc.geyser.command.GeyserCommandManager;
|
|
||||||
|
|
||||||
public class GeyserBungeeCommandManager extends GeyserCommandManager {
|
public class GeyserFabricMain extends GeyserMain {
|
||||||
|
|
||||||
public GeyserBungeeCommandManager(GeyserImpl geyser) {
|
public static void main(String[] args) {
|
||||||
super(geyser);
|
new GeyserFabricMain().displayMessage();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String description(String command) {
|
public String getPluginType() {
|
||||||
return ""; // no support for command descriptions in bungee
|
return "Fabric";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPluginFolder() {
|
||||||
|
return "mods";
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,270 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* @author GeyserMC
|
||||||
|
* @link https://github.com/GeyserMC/Geyser
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.geysermc.geyser.platform.fabric;
|
||||||
|
|
||||||
|
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||||
|
import net.fabricmc.api.EnvType;
|
||||||
|
import net.fabricmc.api.ModInitializer;
|
||||||
|
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
|
||||||
|
import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents;
|
||||||
|
import net.fabricmc.loader.api.FabricLoader;
|
||||||
|
import net.fabricmc.loader.api.ModContainer;
|
||||||
|
import net.minecraft.commands.CommandSourceStack;
|
||||||
|
import net.minecraft.commands.Commands;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.geysermc.common.PlatformType;
|
||||||
|
import org.geysermc.geyser.GeyserBootstrap;
|
||||||
|
import org.geysermc.geyser.GeyserImpl;
|
||||||
|
import org.geysermc.geyser.GeyserLogger;
|
||||||
|
import org.geysermc.geyser.api.command.Command;
|
||||||
|
import org.geysermc.geyser.api.network.AuthType;
|
||||||
|
import org.geysermc.geyser.command.GeyserCommand;
|
||||||
|
import org.geysermc.geyser.command.GeyserCommandManager;
|
||||||
|
import org.geysermc.geyser.configuration.GeyserConfiguration;
|
||||||
|
import org.geysermc.geyser.dump.BootstrapDumpInfo;
|
||||||
|
import org.geysermc.geyser.level.WorldManager;
|
||||||
|
import org.geysermc.geyser.ping.GeyserLegacyPingPassthrough;
|
||||||
|
import org.geysermc.geyser.ping.IGeyserPingPassthrough;
|
||||||
|
import org.geysermc.geyser.platform.fabric.command.GeyserFabricCommandExecutor;
|
||||||
|
import org.geysermc.geyser.platform.fabric.world.GeyserFabricWorldManager;
|
||||||
|
import org.geysermc.geyser.text.GeyserLocale;
|
||||||
|
import org.geysermc.geyser.util.FileUtils;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class GeyserFabricMod implements ModInitializer, GeyserBootstrap {
|
||||||
|
private static GeyserFabricMod instance;
|
||||||
|
|
||||||
|
private boolean reloading;
|
||||||
|
|
||||||
|
private GeyserImpl geyser;
|
||||||
|
private ModContainer mod;
|
||||||
|
private Path dataFolder;
|
||||||
|
private MinecraftServer server;
|
||||||
|
|
||||||
|
private GeyserCommandManager geyserCommandManager;
|
||||||
|
private GeyserFabricConfiguration geyserConfig;
|
||||||
|
private GeyserFabricLogger geyserLogger;
|
||||||
|
private IGeyserPingPassthrough geyserPingPassthrough;
|
||||||
|
private WorldManager geyserWorldManager;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onInitialize() {
|
||||||
|
instance = this;
|
||||||
|
mod = FabricLoader.getInstance().getModContainer("geyser-fabric").orElseThrow();
|
||||||
|
|
||||||
|
this.onEnable();
|
||||||
|
if (FabricLoader.getInstance().getEnvironmentType() == EnvType.SERVER) {
|
||||||
|
// Set as an event so we can get the proper IP and port if needed
|
||||||
|
ServerLifecycleEvents.SERVER_STARTED.register(this::startGeyser);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEnable() {
|
||||||
|
dataFolder = FabricLoader.getInstance().getConfigDir().resolve("Geyser-Fabric");
|
||||||
|
if (!dataFolder.toFile().exists()) {
|
||||||
|
//noinspection ResultOfMethodCallIgnored
|
||||||
|
dataFolder.toFile().mkdir();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init dataFolder first as local language overrides call getConfigFolder()
|
||||||
|
GeyserLocale.init(this);
|
||||||
|
|
||||||
|
try {
|
||||||
|
File configFile = FileUtils.fileOrCopiedFromResource(dataFolder.resolve("config.yml").toFile(), "config.yml",
|
||||||
|
(x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()), this);
|
||||||
|
this.geyserConfig = FileUtils.loadConfig(configFile, GeyserFabricConfiguration.class);
|
||||||
|
} catch (IOException ex) {
|
||||||
|
LogManager.getLogger("geyser-fabric").error(GeyserLocale.getLocaleStringLog("geyser.config.failed"), ex);
|
||||||
|
ex.printStackTrace();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.geyserLogger = new GeyserFabricLogger(geyserConfig.isDebugMode());
|
||||||
|
|
||||||
|
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
|
||||||
|
|
||||||
|
this.geyser = GeyserImpl.load(PlatformType.FABRIC, this);
|
||||||
|
|
||||||
|
if (server == null) {
|
||||||
|
// Server has yet to start
|
||||||
|
// Register onDisable so players are properly kicked
|
||||||
|
ServerLifecycleEvents.SERVER_STOPPING.register((server) -> onDisable());
|
||||||
|
|
||||||
|
ServerPlayConnectionEvents.JOIN.register((handler, $, $$) -> GeyserFabricUpdateListener.onPlayReady(handler));
|
||||||
|
} else {
|
||||||
|
// Server has started and this is a reload
|
||||||
|
startGeyser(this.server);
|
||||||
|
reloading = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize core Geyser.
|
||||||
|
* A function, as it needs to be called in different places depending on if Geyser is being reloaded or not.
|
||||||
|
*
|
||||||
|
* @param server The minecraft server.
|
||||||
|
*/
|
||||||
|
public void startGeyser(MinecraftServer server) {
|
||||||
|
this.server = server;
|
||||||
|
|
||||||
|
if (this.geyserConfig.getRemote().address().equalsIgnoreCase("auto")) {
|
||||||
|
this.geyserConfig.setAutoconfiguredRemote(true);
|
||||||
|
String ip = server.getLocalIp();
|
||||||
|
int port = ((GeyserServerPortGetter) server).geyser$getServerPort();
|
||||||
|
if (ip != null && !ip.isEmpty() && !ip.equals("0.0.0.0")) {
|
||||||
|
this.geyserConfig.getRemote().setAddress(ip);
|
||||||
|
}
|
||||||
|
this.geyserConfig.getRemote().setPort(port);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (geyserConfig.getBedrock().isCloneRemotePort()) {
|
||||||
|
geyserConfig.getBedrock().setPort(geyserConfig.getRemote().port());
|
||||||
|
}
|
||||||
|
|
||||||
|
Optional<ModContainer> floodgate = FabricLoader.getInstance().getModContainer("floodgate");
|
||||||
|
boolean floodgatePresent = floodgate.isPresent();
|
||||||
|
if (geyserConfig.getRemote().authType() == AuthType.FLOODGATE && !floodgatePresent) {
|
||||||
|
geyserLogger.severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.not_installed") + " " + GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.disabling"));
|
||||||
|
return;
|
||||||
|
} else if (geyserConfig.isAutoconfiguredRemote() && floodgatePresent) {
|
||||||
|
// Floodgate installed means that the user wants Floodgate authentication
|
||||||
|
geyserLogger.debug("Auto-setting to Floodgate authentication.");
|
||||||
|
geyserConfig.getRemote().setAuthType(AuthType.FLOODGATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
geyserConfig.loadFloodgate(this, floodgate.orElse(null));
|
||||||
|
|
||||||
|
GeyserImpl.start();
|
||||||
|
|
||||||
|
this.geyserPingPassthrough = GeyserLegacyPingPassthrough.init(geyser);
|
||||||
|
|
||||||
|
this.geyserCommandManager = new GeyserCommandManager(geyser);
|
||||||
|
this.geyserCommandManager.init();
|
||||||
|
|
||||||
|
this.geyserWorldManager = new GeyserFabricWorldManager(server);
|
||||||
|
|
||||||
|
// Start command building
|
||||||
|
// Set just "geyser" as the help command
|
||||||
|
GeyserFabricCommandExecutor helpExecutor = new GeyserFabricCommandExecutor(geyser,
|
||||||
|
(GeyserCommand) geyser.commandManager().getCommands().get("help"));
|
||||||
|
LiteralArgumentBuilder<CommandSourceStack> builder = Commands.literal("geyser").executes(helpExecutor);
|
||||||
|
|
||||||
|
// Register all subcommands as valid
|
||||||
|
for (Map.Entry<String, Command> command : geyser.commandManager().getCommands().entrySet()) {
|
||||||
|
GeyserFabricCommandExecutor executor = new GeyserFabricCommandExecutor(geyser, (GeyserCommand) command.getValue());
|
||||||
|
builder.then(Commands.literal(command.getKey())
|
||||||
|
.executes(executor)
|
||||||
|
// Could also test for Bedrock but depending on when this is called it may backfire
|
||||||
|
.requires(executor::testPermission));
|
||||||
|
}
|
||||||
|
server.getCommands().getDispatcher().register(builder);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDisable() {
|
||||||
|
if (geyser != null) {
|
||||||
|
geyser.shutdown();
|
||||||
|
geyser = null;
|
||||||
|
}
|
||||||
|
if (!reloading) {
|
||||||
|
this.server = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GeyserConfiguration getGeyserConfig() {
|
||||||
|
return geyserConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GeyserLogger getGeyserLogger() {
|
||||||
|
return geyserLogger;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GeyserCommandManager getGeyserCommandManager() {
|
||||||
|
return geyserCommandManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IGeyserPingPassthrough getGeyserPingPassthrough() {
|
||||||
|
return geyserPingPassthrough;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WorldManager getWorldManager() {
|
||||||
|
return geyserWorldManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Path getConfigFolder() {
|
||||||
|
return dataFolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BootstrapDumpInfo getDumpInfo() {
|
||||||
|
return new GeyserFabricDumpInfo(server);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getMinecraftServerVersion() {
|
||||||
|
return this.server.getServerVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public InputStream getResourceOrNull(String resource) {
|
||||||
|
// We need to handle this differently, because Fabric shares the classloader across multiple mods
|
||||||
|
Path path = this.mod.findPath(resource).orElse(null);
|
||||||
|
if (path == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return path.getFileSystem()
|
||||||
|
.provider()
|
||||||
|
.newInputStream(path);
|
||||||
|
} catch (IOException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setReloading(boolean reloading) {
|
||||||
|
this.reloading = reloading;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GeyserFabricMod getInstance() {
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* @author GeyserMC
|
||||||
|
* @link https://github.com/GeyserMC/Geyser
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.geysermc.geyser.platform.fabric;
|
||||||
|
|
||||||
|
import me.lucko.fabric.api.permissions.v0.Permissions;
|
||||||
|
import net.minecraft.server.network.ServerGamePacketListenerImpl;
|
||||||
|
import org.geysermc.geyser.Constants;
|
||||||
|
import org.geysermc.geyser.platform.fabric.command.FabricCommandSender;
|
||||||
|
import org.geysermc.geyser.util.VersionCheckUtils;
|
||||||
|
|
||||||
|
public final class GeyserFabricUpdateListener {
|
||||||
|
public static void onPlayReady(ServerGamePacketListenerImpl handler) {
|
||||||
|
if (Permissions.check(handler.player, Constants.UPDATE_PERMISSION, 2)) {
|
||||||
|
VersionCheckUtils.checkForGeyserUpdate(() -> new FabricCommandSender(handler.player.createCommandSourceStack()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private GeyserFabricUpdateListener() {
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* @author GeyserMC
|
||||||
|
* @link https://github.com/GeyserMC/Geyser
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.geysermc.geyser.platform.fabric;
|
||||||
|
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a getter to the server port in the dedicated server and in the integrated server.
|
||||||
|
*/
|
||||||
|
public interface GeyserServerPortGetter {
|
||||||
|
/**
|
||||||
|
* Returns the server port.
|
||||||
|
*
|
||||||
|
* <ul>
|
||||||
|
* <li>If it's a dedicated server, it will return the server port specified in the {@code server.properties} file.</li>
|
||||||
|
* <li>If it's an integrated server, it will return the LAN port if opened, else -1.</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* The reason is that {@link MinecraftServer#getPort()} doesn't return the LAN port if it's the integrated server,
|
||||||
|
* and changing the behavior of this method via a mixin should be avoided as it could have unexpected consequences.
|
||||||
|
*
|
||||||
|
* @return The server port.
|
||||||
|
*/
|
||||||
|
int geyser$getServerPort();
|
||||||
|
}
|
@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* @author GeyserMC
|
||||||
|
* @link https://github.com/GeyserMC/Geyser
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.geysermc.geyser.platform.fabric.command;
|
||||||
|
|
||||||
|
import me.lucko.fabric.api.permissions.v0.Permissions;
|
||||||
|
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||||
|
import net.minecraft.commands.CommandSourceStack;
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import org.geysermc.geyser.GeyserImpl;
|
||||||
|
import org.geysermc.geyser.command.GeyserCommandSource;
|
||||||
|
import org.geysermc.geyser.text.ChatColor;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
|
public class FabricCommandSender implements GeyserCommandSource {
|
||||||
|
|
||||||
|
private final CommandSourceStack source;
|
||||||
|
|
||||||
|
public FabricCommandSender(CommandSourceStack source) {
|
||||||
|
this.source = source;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String name() {
|
||||||
|
return source.getTextName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendMessage(@Nonnull String message) {
|
||||||
|
if (source.getEntity() instanceof ServerPlayer) {
|
||||||
|
((ServerPlayer) source.getEntity()).displayClientMessage(Component.literal(message), false);
|
||||||
|
} else {
|
||||||
|
GeyserImpl.getInstance().getLogger().info(ChatColor.toANSI(message + ChatColor.RESET));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendMessage(net.kyori.adventure.text.Component message) {
|
||||||
|
if (source.getEntity() instanceof ServerPlayer player) {
|
||||||
|
String decoded = GsonComponentSerializer.gson().serialize(message);
|
||||||
|
player.displayClientMessage(Component.Serializer.fromJson(decoded), false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
GeyserCommandSource.super.sendMessage(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isConsole() {
|
||||||
|
return !(source.getEntity() instanceof ServerPlayer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasPermission(String permission) {
|
||||||
|
return Permissions.check(source, permission);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* @author GeyserMC
|
||||||
|
* @link https://github.com/GeyserMC/Geyser
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.geysermc.geyser.platform.fabric.command;
|
||||||
|
|
||||||
|
import com.mojang.brigadier.Command;
|
||||||
|
import com.mojang.brigadier.context.CommandContext;
|
||||||
|
import me.lucko.fabric.api.permissions.v0.Permissions;
|
||||||
|
import net.minecraft.commands.CommandSourceStack;
|
||||||
|
import org.geysermc.geyser.GeyserImpl;
|
||||||
|
import org.geysermc.geyser.command.GeyserCommand;
|
||||||
|
import org.geysermc.geyser.command.GeyserCommandExecutor;
|
||||||
|
import org.geysermc.geyser.platform.fabric.GeyserFabricMod;
|
||||||
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
|
import org.geysermc.geyser.text.ChatColor;
|
||||||
|
import org.geysermc.geyser.text.GeyserLocale;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
|
public class GeyserFabricCommandExecutor extends GeyserCommandExecutor implements Command<CommandSourceStack> {
|
||||||
|
private final GeyserCommand command;
|
||||||
|
|
||||||
|
public GeyserFabricCommandExecutor(GeyserImpl connector, GeyserCommand command) {
|
||||||
|
super(connector, Collections.singletonMap(command.name(), command));
|
||||||
|
this.command = command;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean testPermission(CommandSourceStack source) {
|
||||||
|
return Permissions.check(source, command.permission(), command.isSuggestedOpOnly() ? 2 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int run(CommandContext context) {
|
||||||
|
CommandSourceStack source = (CommandSourceStack) context.getSource();
|
||||||
|
FabricCommandSender sender = new FabricCommandSender(source);
|
||||||
|
GeyserSession session = getGeyserSession(sender);
|
||||||
|
if (!testPermission(source)) {
|
||||||
|
sender.sendMessage(ChatColor.RED + GeyserLocale.getPlayerLocaleString("geyser.bootstrap.command.permission_fail", sender.locale()));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (this.command.name().equals("reload")) {
|
||||||
|
GeyserFabricMod.getInstance().setReloading(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (command.isBedrockOnly() && session == null) {
|
||||||
|
sender.sendMessage(ChatColor.RED + GeyserLocale.getPlayerLocaleString("geyser.bootstrap.command.bedrock_only", sender.locale()));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
command.execute(session, sender, new String[0]);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* @author GeyserMC
|
||||||
|
* @link https://github.com/GeyserMC/Geyser
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.geysermc.geyser.platform.fabric.mixin.client;
|
||||||
|
|
||||||
|
import net.fabricmc.api.EnvType;
|
||||||
|
import net.fabricmc.api.Environment;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.server.IntegratedServer;
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.minecraft.world.level.GameType;
|
||||||
|
import org.geysermc.geyser.platform.fabric.GeyserFabricMod;
|
||||||
|
import org.geysermc.geyser.platform.fabric.GeyserServerPortGetter;
|
||||||
|
import org.geysermc.geyser.text.GeyserLocale;
|
||||||
|
import org.spongepowered.asm.mixin.Final;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
|
@Environment(EnvType.CLIENT)
|
||||||
|
@Mixin(IntegratedServer.class)
|
||||||
|
public class IntegratedServerMixin implements GeyserServerPortGetter {
|
||||||
|
@Shadow
|
||||||
|
private int publishedPort;
|
||||||
|
|
||||||
|
@Shadow @Final private Minecraft minecraft;
|
||||||
|
|
||||||
|
@Inject(method = "publishServer", at = @At("RETURN"))
|
||||||
|
private void onOpenToLan(GameType gameType, boolean cheatsAllowed, int port, CallbackInfoReturnable<Boolean> cir) {
|
||||||
|
if (cir.getReturnValueZ()) {
|
||||||
|
// If the LAN is opened, starts Geyser.
|
||||||
|
GeyserFabricMod.getInstance().startGeyser((MinecraftServer) (Object) this);
|
||||||
|
// Ensure player locale has been loaded, in case it's different from Java system language
|
||||||
|
GeyserLocale.loadGeyserLocale(this.minecraft.options.languageCode);
|
||||||
|
// Give indication that Geyser is loaded
|
||||||
|
this.minecraft.player.displayClientMessage(Component.literal(GeyserLocale.getPlayerLocaleString("geyser.core.start",
|
||||||
|
this.minecraft.options.languageCode, "localhost", String.valueOf(this.publishedPort))), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int geyser$getServerPort() {
|
||||||
|
return this.publishedPort;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* @author GeyserMC
|
||||||
|
* @link https://github.com/GeyserMC/Geyser
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.geysermc.geyser.platform.fabric.mixin.server;
|
||||||
|
|
||||||
|
import com.mojang.datafixers.DataFixer;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.minecraft.server.Services;
|
||||||
|
import net.minecraft.server.WorldStem;
|
||||||
|
import net.minecraft.server.dedicated.DedicatedServer;
|
||||||
|
import net.minecraft.server.level.progress.ChunkProgressListenerFactory;
|
||||||
|
import net.minecraft.server.packs.repository.PackRepository;
|
||||||
|
import net.minecraft.world.level.storage.LevelStorageSource;
|
||||||
|
import org.geysermc.geyser.platform.fabric.GeyserServerPortGetter;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
|
||||||
|
import java.net.Proxy;
|
||||||
|
|
||||||
|
@Mixin(DedicatedServer.class)
|
||||||
|
public abstract class MinecraftDedicatedServerMixin extends MinecraftServer implements GeyserServerPortGetter {
|
||||||
|
public MinecraftDedicatedServerMixin(Thread thread, LevelStorageSource.LevelStorageAccess levelStorageAccess, PackRepository packRepository, WorldStem worldStem, Proxy proxy, DataFixer dataFixer, Services services, ChunkProgressListenerFactory chunkProgressListenerFactory) {
|
||||||
|
super(thread, levelStorageAccess, packRepository, worldStem, proxy, dataFixer, services, chunkProgressListenerFactory);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int geyser$getServerPort() {
|
||||||
|
return this.getPort();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,133 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* @author GeyserMC
|
||||||
|
* @link https://github.com/GeyserMC/Geyser
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.geysermc.geyser.platform.fabric.world;
|
||||||
|
|
||||||
|
import com.nukkitx.math.vector.Vector3i;
|
||||||
|
import com.nukkitx.nbt.NbtMap;
|
||||||
|
import com.nukkitx.nbt.NbtMapBuilder;
|
||||||
|
import com.nukkitx.nbt.NbtType;
|
||||||
|
import me.lucko.fabric.api.permissions.v0.Permissions;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.nbt.ListTag;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.item.WritableBookItem;
|
||||||
|
import net.minecraft.world.item.WrittenBookItem;
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
|
import net.minecraft.world.level.block.entity.LecternBlockEntity;
|
||||||
|
import org.geysermc.geyser.level.GeyserWorldManager;
|
||||||
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
|
import org.geysermc.geyser.translator.inventory.LecternInventoryTranslator;
|
||||||
|
import org.geysermc.geyser.util.BlockEntityUtils;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
public class GeyserFabricWorldManager extends GeyserWorldManager {
|
||||||
|
private final MinecraftServer server;
|
||||||
|
|
||||||
|
public GeyserFabricWorldManager(MinecraftServer server) {
|
||||||
|
this.server = server;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean shouldExpectLecternHandled() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NbtMap getLecternDataAt(GeyserSession session, int x, int y, int z, boolean isChunkLoad) {
|
||||||
|
Runnable lecternGet = () -> {
|
||||||
|
// Mostly a reimplementation of Spigot lectern support
|
||||||
|
ServerPlayer player = getPlayer(session);
|
||||||
|
if (player != null) {
|
||||||
|
BlockEntity blockEntity = player.level.getBlockEntity(new BlockPos(x, y, z));
|
||||||
|
if (!(blockEntity instanceof LecternBlockEntity lectern)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!lectern.hasBook()) {
|
||||||
|
if (!isChunkLoad) {
|
||||||
|
BlockEntityUtils.updateBlockEntity(session, LecternInventoryTranslator.getBaseLecternTag(x, y, z, 0).build(), Vector3i.from(x, y, z));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemStack book = lectern.getBook();
|
||||||
|
int pageCount = WrittenBookItem.getPageCount(book);
|
||||||
|
boolean hasBookPages = pageCount > 0;
|
||||||
|
NbtMapBuilder lecternTag = LecternInventoryTranslator.getBaseLecternTag(x, y, z, hasBookPages ? pageCount : 1);
|
||||||
|
lecternTag.putInt("page", lectern.getPage() / 2);
|
||||||
|
NbtMapBuilder bookTag = NbtMap.builder()
|
||||||
|
.putByte("Count", (byte) book.getCount())
|
||||||
|
.putShort("Damage", (short) 0)
|
||||||
|
.putString("Name", "minecraft:writable_book");
|
||||||
|
List<NbtMap> pages = new ArrayList<>(hasBookPages ? pageCount : 1);
|
||||||
|
if (hasBookPages && WritableBookItem.makeSureTagIsValid(book.getTag())) {
|
||||||
|
ListTag listTag = book.getTag().getList("pages", 8);
|
||||||
|
|
||||||
|
for (int i = 0; i < listTag.size(); i++) {
|
||||||
|
String page = listTag.getString(i);
|
||||||
|
NbtMapBuilder pageBuilder = NbtMap.builder()
|
||||||
|
.putString("photoname", "")
|
||||||
|
.putString("text", page);
|
||||||
|
pages.add(pageBuilder.build());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Empty page
|
||||||
|
NbtMapBuilder pageBuilder = NbtMap.builder()
|
||||||
|
.putString("photoname", "")
|
||||||
|
.putString("text", "");
|
||||||
|
pages.add(pageBuilder.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
bookTag.putCompound("tag", NbtMap.builder().putList("pages", NbtType.COMPOUND, pages).build());
|
||||||
|
lecternTag.putCompound("book", bookTag.build());
|
||||||
|
NbtMap blockEntityTag = lecternTag.build();
|
||||||
|
BlockEntityUtils.updateBlockEntity(session, blockEntityTag, Vector3i.from(x, y, z));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (isChunkLoad) {
|
||||||
|
// Hacky hacks to allow lectern loading to be delayed
|
||||||
|
session.scheduleInEventLoop(() -> server.execute(lecternGet), 1, TimeUnit.SECONDS);
|
||||||
|
} else {
|
||||||
|
server.execute(lecternGet);
|
||||||
|
}
|
||||||
|
return LecternInventoryTranslator.getBaseLecternTag(x, y, z, 0).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasPermission(GeyserSession session, String permission) {
|
||||||
|
ServerPlayer player = getPlayer(session);
|
||||||
|
return Permissions.check(player, permission);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ServerPlayer getPlayer(GeyserSession session) {
|
||||||
|
return server.getPlayerList().getPlayer(session.getPlayerEntity().getUuid());
|
||||||
|
}
|
||||||
|
}
|
BIN
bootstrap/fabric/src/main/resources/assets/geyser-fabric/icon.png
Normale Datei
BIN
bootstrap/fabric/src/main/resources/assets/geyser-fabric/icon.png
Normale Datei
Binäre Datei nicht angezeigt.
Nachher Breite: | Höhe: | Größe: 113 KiB |
31
bootstrap/fabric/src/main/resources/fabric.mod.json
Normale Datei
31
bootstrap/fabric/src/main/resources/fabric.mod.json
Normale Datei
@ -0,0 +1,31 @@
|
|||||||
|
{
|
||||||
|
"schemaVersion": 1,
|
||||||
|
"id": "${id}-fabric",
|
||||||
|
"version": "${version}",
|
||||||
|
"name": "${name}-Fabric",
|
||||||
|
"description": "A bridge/proxy allowing you to connect to Minecraft: Java Edition servers with Minecraft: Bedrock Edition. ",
|
||||||
|
"authors": [
|
||||||
|
"${author}"
|
||||||
|
],
|
||||||
|
"contact": {
|
||||||
|
"website": "${url}",
|
||||||
|
"repo": "https://github.com/GeyserMC/Geyser-Fabric"
|
||||||
|
},
|
||||||
|
"license": "MIT",
|
||||||
|
"icon": "assets/geyser-fabric/icon.png",
|
||||||
|
"environment": "*",
|
||||||
|
"entrypoints": {
|
||||||
|
"main": [
|
||||||
|
"org.geysermc.geyser.platform.fabric.GeyserFabricMod"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"mixins": [
|
||||||
|
"geyser-fabric.mixins.json"
|
||||||
|
],
|
||||||
|
"depends": {
|
||||||
|
"fabricloader": ">=0.14.8",
|
||||||
|
"fabric": "*",
|
||||||
|
"minecraft": ">=1.19",
|
||||||
|
"fabric-permissions-api-v0": "*"
|
||||||
|
}
|
||||||
|
}
|
14
bootstrap/fabric/src/main/resources/geyser-fabric.mixins.json
Normale Datei
14
bootstrap/fabric/src/main/resources/geyser-fabric.mixins.json
Normale Datei
@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"required": true,
|
||||||
|
"package": "org.geysermc.geyser.platform.fabric.mixin",
|
||||||
|
"compatibilityLevel": "JAVA_16",
|
||||||
|
"client": [
|
||||||
|
"client.IntegratedServerMixin"
|
||||||
|
],
|
||||||
|
"server": [
|
||||||
|
"server.MinecraftDedicatedServerMixin"
|
||||||
|
],
|
||||||
|
"injectors": {
|
||||||
|
"defaultRequire": 1
|
||||||
|
}
|
||||||
|
}
|
@ -1,22 +1,19 @@
|
|||||||
val paperVersion = "1.19-R0.1-SNAPSHOT"
|
|
||||||
val viaVersion = "4.0.0"
|
|
||||||
val adaptersVersion = "1.5-SNAPSHOT"
|
|
||||||
val commodoreVersion = "1.13"
|
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
api(projects.core)
|
api(projects.core)
|
||||||
|
|
||||||
implementation("org.geysermc.geyser.adapters", "spigot-all", adaptersVersion)
|
implementation(libs.adapters.spigot)
|
||||||
|
|
||||||
implementation("me.lucko", "commodore", commodoreVersion)
|
implementation(libs.commodore)
|
||||||
|
|
||||||
|
implementation(libs.adventure.text.serializer.bungeecord)
|
||||||
|
|
||||||
// Both paper-api and paper-mojangapi only provide Java 17 versions for 1.19
|
// Both paper-api and paper-mojangapi only provide Java 17 versions for 1.19
|
||||||
compileOnly("io.papermc.paper", "paper-api", paperVersion) {
|
compileOnly(libs.paper.api) {
|
||||||
attributes {
|
attributes {
|
||||||
attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 17)
|
attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 17)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
compileOnly("io.papermc.paper", "paper-mojangapi", paperVersion) {
|
compileOnly(libs.paper.mojangapi) {
|
||||||
attributes {
|
attributes {
|
||||||
attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 17)
|
attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 17)
|
||||||
}
|
}
|
||||||
@ -25,13 +22,14 @@ dependencies {
|
|||||||
|
|
||||||
platformRelocate("it.unimi.dsi.fastutil")
|
platformRelocate("it.unimi.dsi.fastutil")
|
||||||
platformRelocate("com.fasterxml.jackson")
|
platformRelocate("com.fasterxml.jackson")
|
||||||
platformRelocate("net.kyori")
|
// Relocate net.kyori but exclude the component logger
|
||||||
|
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("io.netty.channel.kqueue")
|
platformRelocate("io.netty.channel.kqueue")
|
||||||
|
|
||||||
// These dependencies are already present on the platform
|
// These dependencies are already present on the platform
|
||||||
provided("com.viaversion", "viaversion", viaVersion)
|
provided(libs.viaversion)
|
||||||
|
|
||||||
application {
|
application {
|
||||||
mainClass.set("org.geysermc.geyser.platform.spigot.GeyserSpigotMain")
|
mainClass.set("org.geysermc.geyser.platform.spigot.GeyserSpigotMain")
|
||||||
|
@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* 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.spigot;
|
||||||
|
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.logger.slf4j.ComponentLogger;
|
||||||
|
import org.bukkit.plugin.Plugin;
|
||||||
|
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
public final class GeyserPaperLogger extends GeyserSpigotLogger {
|
||||||
|
private final ComponentLogger componentLogger;
|
||||||
|
|
||||||
|
public GeyserPaperLogger(Plugin plugin, Logger logger, boolean debug) {
|
||||||
|
super(logger, debug);
|
||||||
|
componentLogger = plugin.getComponentLogger();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Since 1.18.2 this is required so legacy format symbols don't show up in the console for colors
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void sendMessage(Component message) {
|
||||||
|
// Done like this so the native component object field isn't relocated
|
||||||
|
componentLogger.info("{}", PaperAdventure.toNativeComponent(message));
|
||||||
|
}
|
||||||
|
|
||||||
|
static boolean supported() {
|
||||||
|
try {
|
||||||
|
Plugin.class.getMethod("getComponentLogger");
|
||||||
|
return true;
|
||||||
|
} catch (NoSuchMethodException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -41,6 +41,8 @@ public class GeyserSpigotDumpInfo extends BootstrapDumpInfo {
|
|||||||
private final String platformVersion;
|
private final String platformVersion;
|
||||||
private final String platformAPIVersion;
|
private final String platformAPIVersion;
|
||||||
private final boolean onlineMode;
|
private final boolean onlineMode;
|
||||||
|
|
||||||
|
@AsteriskSerializer.Asterisk(isIp = true)
|
||||||
private final String serverIP;
|
private final String serverIP;
|
||||||
private final int serverPort;
|
private final int serverPort;
|
||||||
private final List<PluginInfo> plugins;
|
private final List<PluginInfo> plugins;
|
||||||
@ -51,11 +53,7 @@ public class GeyserSpigotDumpInfo extends BootstrapDumpInfo {
|
|||||||
this.platformVersion = Bukkit.getVersion();
|
this.platformVersion = Bukkit.getVersion();
|
||||||
this.platformAPIVersion = Bukkit.getBukkitVersion();
|
this.platformAPIVersion = Bukkit.getBukkitVersion();
|
||||||
this.onlineMode = Bukkit.getOnlineMode();
|
this.onlineMode = Bukkit.getOnlineMode();
|
||||||
if (AsteriskSerializer.showSensitive || (Bukkit.getIp().equals("") || Bukkit.getIp().equals("0.0.0.0"))) {
|
this.serverIP = Bukkit.getIp();
|
||||||
this.serverIP = Bukkit.getIp();
|
|
||||||
} else {
|
|
||||||
this.serverIP = "***";
|
|
||||||
}
|
|
||||||
this.serverPort = Bukkit.getPort();
|
this.serverPort = Bukkit.getPort();
|
||||||
this.plugins = new ArrayList<>();
|
this.plugins = new ArrayList<>();
|
||||||
|
|
||||||
|
@ -32,9 +32,15 @@ import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
|
|||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import me.lucko.commodore.CommodoreProvider;
|
import me.lucko.commodore.CommodoreProvider;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.block.data.BlockData;
|
||||||
|
import org.bukkit.command.CommandMap;
|
||||||
import org.bukkit.command.PluginCommand;
|
import org.bukkit.command.PluginCommand;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.server.ServerLoadEvent;
|
||||||
import org.bukkit.permissions.Permission;
|
import org.bukkit.permissions.Permission;
|
||||||
import org.bukkit.permissions.PermissionDefault;
|
import org.bukkit.permissions.PermissionDefault;
|
||||||
|
import org.bukkit.plugin.Plugin;
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
import org.geysermc.common.PlatformType;
|
import org.geysermc.common.PlatformType;
|
||||||
import org.geysermc.geyser.Constants;
|
import org.geysermc.geyser.Constants;
|
||||||
@ -42,6 +48,7 @@ import org.geysermc.geyser.GeyserBootstrap;
|
|||||||
import org.geysermc.geyser.GeyserImpl;
|
import org.geysermc.geyser.GeyserImpl;
|
||||||
import org.geysermc.geyser.adapters.spigot.SpigotAdapters;
|
import org.geysermc.geyser.adapters.spigot.SpigotAdapters;
|
||||||
import org.geysermc.geyser.api.command.Command;
|
import org.geysermc.geyser.api.command.Command;
|
||||||
|
import org.geysermc.geyser.api.extension.Extension;
|
||||||
import org.geysermc.geyser.api.network.AuthType;
|
import org.geysermc.geyser.api.network.AuthType;
|
||||||
import org.geysermc.geyser.command.GeyserCommandManager;
|
import org.geysermc.geyser.command.GeyserCommandManager;
|
||||||
import org.geysermc.geyser.configuration.GeyserConfiguration;
|
import org.geysermc.geyser.configuration.GeyserConfiguration;
|
||||||
@ -53,7 +60,6 @@ import org.geysermc.geyser.ping.IGeyserPingPassthrough;
|
|||||||
import org.geysermc.geyser.platform.spigot.command.GeyserBrigadierSupport;
|
import org.geysermc.geyser.platform.spigot.command.GeyserBrigadierSupport;
|
||||||
import org.geysermc.geyser.platform.spigot.command.GeyserSpigotCommandExecutor;
|
import org.geysermc.geyser.platform.spigot.command.GeyserSpigotCommandExecutor;
|
||||||
import org.geysermc.geyser.platform.spigot.command.GeyserSpigotCommandManager;
|
import org.geysermc.geyser.platform.spigot.command.GeyserSpigotCommandManager;
|
||||||
import org.geysermc.geyser.platform.spigot.command.SpigotCommandSource;
|
|
||||||
import org.geysermc.geyser.platform.spigot.world.GeyserPistonListener;
|
import org.geysermc.geyser.platform.spigot.world.GeyserPistonListener;
|
||||||
import org.geysermc.geyser.platform.spigot.world.GeyserSpigotBlockPlaceListener;
|
import org.geysermc.geyser.platform.spigot.world.GeyserSpigotBlockPlaceListener;
|
||||||
import org.geysermc.geyser.platform.spigot.world.manager.*;
|
import org.geysermc.geyser.platform.spigot.world.manager.*;
|
||||||
@ -62,6 +68,8 @@ import org.geysermc.geyser.util.FileUtils;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.net.SocketAddress;
|
import java.net.SocketAddress;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -90,9 +98,40 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
|
|||||||
private String minecraftVersion;
|
private String minecraftVersion;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onEnable() {
|
public void onLoad() {
|
||||||
GeyserLocale.init(this);
|
GeyserLocale.init(this);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// AvailableCommandsSerializer_v291 complains otherwise - affects at least 1.8
|
||||||
|
ByteBuf.class.getMethod("writeShortLE", int.class);
|
||||||
|
// Only available in 1.13.x
|
||||||
|
Class.forName("org.bukkit.event.server.ServerLoadEvent");
|
||||||
|
// We depend on this as a fallback in certain scenarios
|
||||||
|
BlockData.class.getMethod("getAsString");
|
||||||
|
} catch (ClassNotFoundException | NoSuchMethodException e) {
|
||||||
|
getLogger().severe("*********************************************");
|
||||||
|
getLogger().severe("");
|
||||||
|
getLogger().severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_server.header"));
|
||||||
|
getLogger().severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_server.message", "1.13.2"));
|
||||||
|
getLogger().severe("");
|
||||||
|
getLogger().severe("*********************************************");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Class.forName("net.md_5.bungee.chat.ComponentSerializer");
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
if (!PaperAdventure.canSendMessageUsingComponent()) { // Prepare for Paper eventually removing Bungee chat
|
||||||
|
getLogger().severe("*********************************************");
|
||||||
|
getLogger().severe("");
|
||||||
|
getLogger().severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_server_type.header", getServer().getName()));
|
||||||
|
getLogger().severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_server_type.message", "Paper"));
|
||||||
|
getLogger().severe("");
|
||||||
|
getLogger().severe("*********************************************");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// This is manually done instead of using Bukkit methods to save the config because otherwise comments get removed
|
// This is manually done instead of using Bukkit methods to save the config because otherwise comments get removed
|
||||||
try {
|
try {
|
||||||
if (!getDataFolder().exists()) {
|
if (!getDataFolder().exists()) {
|
||||||
@ -108,21 +147,29 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
this.geyserLogger = GeyserPaperLogger.supported() ? new GeyserPaperLogger(this, getLogger(), geyserConfig.isDebugMode())
|
||||||
// AvailableCommandsSerializer_v291 complains otherwise
|
: new GeyserSpigotLogger(getLogger(), geyserConfig.isDebugMode());
|
||||||
ByteBuf.class.getMethod("writeShortLE", int.class);
|
|
||||||
} catch (NoSuchMethodException e) {
|
|
||||||
getLogger().severe("*********************************************");
|
|
||||||
getLogger().severe("");
|
|
||||||
getLogger().severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_server.header"));
|
|
||||||
getLogger().severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_server.message", "1.12.2"));
|
|
||||||
getLogger().severe("");
|
|
||||||
getLogger().severe("*********************************************");
|
|
||||||
|
|
||||||
|
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
|
||||||
|
|
||||||
|
this.geyser = GeyserImpl.load(PlatformType.SPIGOT, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEnable() {
|
||||||
|
if (this.geyserConfig == null) {
|
||||||
|
// We failed to initialize correctly
|
||||||
Bukkit.getPluginManager().disablePlugin(this);
|
Bukkit.getPluginManager().disablePlugin(this);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove this in like a year
|
||||||
|
if (Bukkit.getPluginManager().getPlugin("floodgate-bukkit") != null) {
|
||||||
|
geyserLogger.severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.outdated", Constants.FLOODGATE_DOWNLOAD_LOCATION));
|
||||||
|
this.getPluginLoader().disablePlugin(this);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// By default this should be localhost but may need to be changed in some circumstances
|
// By default this should be localhost but may need to be changed in some circumstances
|
||||||
if (this.geyserConfig.getRemote().address().equalsIgnoreCase("auto")) {
|
if (this.geyserConfig.getRemote().address().equalsIgnoreCase("auto")) {
|
||||||
geyserConfig.setAutoconfiguredRemote(true);
|
geyserConfig.setAutoconfiguredRemote(true);
|
||||||
@ -137,20 +184,9 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
|
|||||||
geyserConfig.getBedrock().setPort(Bukkit.getPort());
|
geyserConfig.getBedrock().setPort(Bukkit.getPort());
|
||||||
}
|
}
|
||||||
|
|
||||||
this.geyserLogger = new GeyserSpigotLogger(getLogger(), geyserConfig.isDebugMode());
|
|
||||||
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
|
|
||||||
|
|
||||||
// Remove this in like a year
|
|
||||||
if (Bukkit.getPluginManager().getPlugin("floodgate-bukkit") != null) {
|
|
||||||
geyserLogger.severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.outdated", Constants.FLOODGATE_DOWNLOAD_LOCATION));
|
|
||||||
this.getPluginLoader().disablePlugin(this);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (geyserConfig.getRemote().authType() == AuthType.FLOODGATE && Bukkit.getPluginManager().getPlugin("floodgate") == null) {
|
if (geyserConfig.getRemote().authType() == AuthType.FLOODGATE && Bukkit.getPluginManager().getPlugin("floodgate") == null) {
|
||||||
geyserLogger.severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.not_installed") + " " + GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.disabling"));
|
geyserLogger.severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.not_installed") + " " + GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.disabling"));
|
||||||
this.getPluginLoader().disablePlugin(this);
|
this.getPluginLoader().disablePlugin(this);
|
||||||
return;
|
|
||||||
} else if (geyserConfig.isAutoconfiguredRemote() && Bukkit.getPluginManager().getPlugin("floodgate") != null) {
|
} else if (geyserConfig.isAutoconfiguredRemote() && Bukkit.getPluginManager().getPlugin("floodgate") != null) {
|
||||||
// Floodgate installed means that the user wants Floodgate authentication
|
// Floodgate installed means that the user wants Floodgate authentication
|
||||||
geyserLogger.debug("Auto-setting to Floodgate authentication.");
|
geyserLogger.debug("Auto-setting to Floodgate authentication.");
|
||||||
@ -159,11 +195,52 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
|
|||||||
|
|
||||||
geyserConfig.loadFloodgate(this);
|
geyserConfig.loadFloodgate(this);
|
||||||
|
|
||||||
|
if (!INITIALIZED) {
|
||||||
|
// Needs to be an anonymous inner class otherwise Bukkit complains about missing classes
|
||||||
|
Bukkit.getPluginManager().registerEvents(new Listener() {
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onServerLoaded(ServerLoadEvent event) {
|
||||||
|
// Wait until all plugins have loaded so Geyser can start
|
||||||
|
postStartup();
|
||||||
|
}
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
this.geyserCommandManager = new GeyserSpigotCommandManager(geyser);
|
||||||
|
this.geyserCommandManager.init();
|
||||||
|
|
||||||
|
// Because Bukkit locks its command map upon startup, we need to
|
||||||
|
// add our plugin commands in onEnable, but populating the executor
|
||||||
|
// can happen at any time
|
||||||
|
CommandMap commandMap = GeyserSpigotCommandManager.getCommandMap();
|
||||||
|
for (Extension extension : this.geyserCommandManager.extensionCommands().keySet()) {
|
||||||
|
// Thanks again, Bukkit
|
||||||
|
try {
|
||||||
|
Constructor<PluginCommand> constructor = PluginCommand.class.getDeclaredConstructor(String.class, Plugin.class);
|
||||||
|
constructor.setAccessible(true);
|
||||||
|
|
||||||
|
PluginCommand pluginCommand = constructor.newInstance(extension.description().id(), this);
|
||||||
|
pluginCommand.setDescription("The main command for the " + extension.name() + " Geyser extension!");
|
||||||
|
|
||||||
|
commandMap.register(extension.description().id(), "geyserext", pluginCommand);
|
||||||
|
} catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException ex) {
|
||||||
|
this.geyserLogger.error("Failed to construct PluginCommand for extension " + extension.description().name(), ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (INITIALIZED) {
|
||||||
|
// Reload; continue with post startup
|
||||||
|
postStartup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void postStartup() {
|
||||||
|
GeyserImpl.start();
|
||||||
|
|
||||||
// Turn "(MC: 1.16.4)" into 1.16.4.
|
// Turn "(MC: 1.16.4)" into 1.16.4.
|
||||||
this.minecraftVersion = Bukkit.getServer().getVersion().split("\\(MC: ")[1].split("\\)")[0];
|
this.minecraftVersion = Bukkit.getServer().getVersion().split("\\(MC: ")[1].split("\\)")[0];
|
||||||
|
|
||||||
this.geyser = GeyserImpl.start(PlatformType.SPIGOT, this);
|
|
||||||
|
|
||||||
if (geyserConfig.isLegacyPingPassthrough()) {
|
if (geyserConfig.isLegacyPingPassthrough()) {
|
||||||
this.geyserSpigotPingPassthrough = GeyserLegacyPingPassthrough.init(geyser);
|
this.geyserSpigotPingPassthrough = GeyserLegacyPingPassthrough.init(geyser);
|
||||||
} else {
|
} else {
|
||||||
@ -176,10 +253,7 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
|
|||||||
this.geyserSpigotPingPassthrough = GeyserLegacyPingPassthrough.init(geyser);
|
this.geyserSpigotPingPassthrough = GeyserLegacyPingPassthrough.init(geyser);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
geyserLogger.info("Spigot ping passthrough type: " + (this.geyserSpigotPingPassthrough == null ? null : this.geyserSpigotPingPassthrough.getClass()));
|
geyserLogger.debug("Spigot ping passthrough type: " + (this.geyserSpigotPingPassthrough == null ? null : this.geyserSpigotPingPassthrough.getClass()));
|
||||||
|
|
||||||
this.geyserCommandManager = new GeyserSpigotCommandManager(geyser);
|
|
||||||
this.geyserCommandManager.init();
|
|
||||||
|
|
||||||
boolean isViaVersion = Bukkit.getPluginManager().getPlugin("ViaVersion") != null;
|
boolean isViaVersion = Bukkit.getPluginManager().getPlugin("ViaVersion") != null;
|
||||||
if (isViaVersion) {
|
if (isViaVersion) {
|
||||||
@ -194,14 +268,6 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Used to determine if Block.getBlockData() is present.
|
|
||||||
boolean isLegacy = !isCompatible(Bukkit.getServer().getVersion(), "1.13.0");
|
|
||||||
if (isLegacy)
|
|
||||||
geyserLogger.debug("Legacy version of Minecraft (1.12.2 or older) detected; falling back to ViaVersion for block state retrieval.");
|
|
||||||
|
|
||||||
boolean isPre1_12 = !isCompatible(Bukkit.getServer().getVersion(), "1.12.0");
|
|
||||||
// Set if we need to use a different method for getting a player's locale
|
|
||||||
SpigotCommandSource.setUseLegacyLocaleMethod(isPre1_12);
|
|
||||||
|
|
||||||
// We want to do this late in the server startup process to allow plugins such as ViaVersion and ProtocolLib
|
// We want to do this late in the server startup process to allow plugins such as ViaVersion and ProtocolLib
|
||||||
// To do their job injecting, then connect into *that*
|
// To do their job injecting, then connect into *that*
|
||||||
@ -214,13 +280,7 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
|
|||||||
String nmsVersion = name.substring(name.lastIndexOf('.') + 1);
|
String nmsVersion = name.substring(name.lastIndexOf('.') + 1);
|
||||||
SpigotAdapters.registerWorldAdapter(nmsVersion);
|
SpigotAdapters.registerWorldAdapter(nmsVersion);
|
||||||
if (isViaVersion && isViaVersionNeeded()) {
|
if (isViaVersion && isViaVersionNeeded()) {
|
||||||
if (isLegacy) {
|
this.geyserWorldManager = new GeyserSpigotLegacyNativeWorldManager(this);
|
||||||
// Pre-1.13
|
|
||||||
this.geyserWorldManager = new GeyserSpigot1_12NativeWorldManager(this);
|
|
||||||
} else {
|
|
||||||
// Post-1.13
|
|
||||||
this.geyserWorldManager = new GeyserSpigotLegacyNativeWorldManager(this);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// No ViaVersion
|
// No ViaVersion
|
||||||
this.geyserWorldManager = new GeyserSpigotNativeWorldManager(this);
|
this.geyserWorldManager = new GeyserSpigotNativeWorldManager(this);
|
||||||
@ -237,28 +297,31 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
|
|||||||
}
|
}
|
||||||
if (this.geyserWorldManager == null) {
|
if (this.geyserWorldManager == null) {
|
||||||
// No NMS adapter
|
// No NMS adapter
|
||||||
if (isLegacy && isViaVersion) {
|
this.geyserWorldManager = new GeyserSpigotWorldManager(this);
|
||||||
// Use ViaVersion for converting pre-1.13 block states
|
geyserLogger.debug("Using default world manager.");
|
||||||
this.geyserWorldManager = new GeyserSpigot1_12WorldManager(this);
|
|
||||||
} else if (isLegacy) {
|
|
||||||
// Not sure how this happens - without ViaVersion, we don't know any block states, so just assume everything is air
|
|
||||||
this.geyserWorldManager = new GeyserSpigotFallbackWorldManager(this);
|
|
||||||
} else {
|
|
||||||
// Post-1.13
|
|
||||||
this.geyserWorldManager = new GeyserSpigotWorldManager(this);
|
|
||||||
}
|
|
||||||
geyserLogger.debug("Using default world manager: " + this.geyserWorldManager.getClass());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PluginCommand geyserCommand = this.getCommand("geyser");
|
PluginCommand geyserCommand = this.getCommand("geyser");
|
||||||
geyserCommand.setExecutor(new GeyserSpigotCommandExecutor(geyser, geyserCommandManager.getCommands()));
|
geyserCommand.setExecutor(new GeyserSpigotCommandExecutor(geyser, geyserCommandManager.getCommands()));
|
||||||
PluginCommand geyserExtCommand = this.getCommand("geyserext");
|
|
||||||
geyserExtCommand.setExecutor(new GeyserSpigotCommandExecutor(geyser, geyserCommandManager.getCommands()));
|
for (Map.Entry<Extension, Map<String, Command>> entry : this.geyserCommandManager.extensionCommands().entrySet()) {
|
||||||
|
Map<String, Command> commands = entry.getValue();
|
||||||
|
if (commands.isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
PluginCommand command = this.getCommand(entry.getKey().description().id());
|
||||||
|
if (command == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
command.setExecutor(new GeyserSpigotCommandExecutor(this.geyser, commands));
|
||||||
|
}
|
||||||
|
|
||||||
if (!INITIALIZED) {
|
if (!INITIALIZED) {
|
||||||
// Register permissions so they appear in, for example, LuckPerms' UI
|
// Register permissions so they appear in, for example, LuckPerms' UI
|
||||||
// Re-registering permissions throws an error
|
// Re-registering permissions throws an error
|
||||||
for (Map.Entry<String, Command> entry : geyserCommandManager.getCommands().entrySet()) {
|
for (Map.Entry<String, Command> entry : geyserCommandManager.commands().entrySet()) {
|
||||||
Command command = entry.getValue();
|
Command command = entry.getValue();
|
||||||
if (command.aliases().contains(entry.getKey())) {
|
if (command.aliases().contains(entry.getKey())) {
|
||||||
// Don't register aliases
|
// Don't register aliases
|
||||||
@ -270,11 +333,35 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
|
|||||||
command.isSuggestedOpOnly() ? PermissionDefault.OP : PermissionDefault.TRUE));
|
command.isSuggestedOpOnly() ? PermissionDefault.OP : PermissionDefault.TRUE));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Register permissions for extension commands
|
||||||
|
for (Map.Entry<Extension, Map<String, Command>> commandEntry : this.geyserCommandManager.extensionCommands().entrySet()) {
|
||||||
|
for (Map.Entry<String, Command> entry : commandEntry.getValue().entrySet()) {
|
||||||
|
Command command = entry.getValue();
|
||||||
|
if (command.aliases().contains(entry.getKey())) {
|
||||||
|
// Don't register aliases
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (command.permission().isBlank()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bukkit.getPluginManager().addPermission(new Permission(command.permission(),
|
||||||
|
GeyserLocale.getLocaleStringLog(command.description()),
|
||||||
|
command.isSuggestedOpOnly() ? PermissionDefault.OP : PermissionDefault.TRUE));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Bukkit.getPluginManager().addPermission(new Permission(Constants.UPDATE_PERMISSION,
|
||||||
|
"Whether update notifications can be seen", PermissionDefault.OP));
|
||||||
|
|
||||||
// Events cannot be unregistered - re-registering results in duplicate firings
|
// Events cannot be unregistered - re-registering results in duplicate firings
|
||||||
GeyserSpigotBlockPlaceListener blockPlaceListener = new GeyserSpigotBlockPlaceListener(geyser, this.geyserWorldManager);
|
GeyserSpigotBlockPlaceListener blockPlaceListener = new GeyserSpigotBlockPlaceListener(geyser, this.geyserWorldManager);
|
||||||
Bukkit.getServer().getPluginManager().registerEvents(blockPlaceListener, this);
|
Bukkit.getServer().getPluginManager().registerEvents(blockPlaceListener, this);
|
||||||
|
|
||||||
Bukkit.getServer().getPluginManager().registerEvents(new GeyserPistonListener(geyser, this.geyserWorldManager), this);
|
Bukkit.getServer().getPluginManager().registerEvents(new GeyserPistonListener(geyser, this.geyserWorldManager), this);
|
||||||
|
|
||||||
|
Bukkit.getServer().getPluginManager().registerEvents(new GeyserSpigotUpdateListener(), this);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean brigadierSupported = CommodoreProvider.isSupported();
|
boolean brigadierSupported = CommodoreProvider.isSupported();
|
||||||
|
@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* 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.spigot;
|
||||||
|
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.player.PlayerJoinEvent;
|
||||||
|
import org.geysermc.geyser.Constants;
|
||||||
|
import org.geysermc.geyser.GeyserImpl;
|
||||||
|
import org.geysermc.geyser.platform.spigot.command.SpigotCommandSource;
|
||||||
|
import org.geysermc.geyser.util.VersionCheckUtils;
|
||||||
|
|
||||||
|
public final class GeyserSpigotUpdateListener implements Listener {
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onPlayerJoin(final PlayerJoinEvent event) {
|
||||||
|
if (GeyserImpl.getInstance().getConfig().isNotifyOnNewBedrockUpdate()) {
|
||||||
|
final Player player = event.getPlayer();
|
||||||
|
if (player.hasPermission(Constants.UPDATE_PERMISSION)) {
|
||||||
|
VersionCheckUtils.checkForGeyserUpdate(() -> new SpigotCommandSource(player));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,154 @@
|
|||||||
|
/*
|
||||||
|
* 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.spigot;
|
||||||
|
|
||||||
|
import com.github.steveice10.mc.protocol.data.DefaultComponentSerializer;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.geysermc.geyser.GeyserImpl;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.lang.invoke.MethodHandle;
|
||||||
|
import java.lang.invoke.MethodHandles;
|
||||||
|
import java.lang.invoke.MethodType;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility class for converting our shaded Adventure into the Adventure bundled in Paper.
|
||||||
|
*
|
||||||
|
* Code mostly taken from https://github.com/KyoriPowered/adventure-platform/blob/94d5821f2e755170f42bd8a5fe1d5bf6f66d04ad/platform-bukkit/src/main/java/net/kyori/adventure/platform/bukkit/PaperFacet.java#L46
|
||||||
|
* and the MinecraftReflection class.
|
||||||
|
*/
|
||||||
|
public final class PaperAdventure {
|
||||||
|
private static final MethodHandle NATIVE_GSON_COMPONENT_SERIALIZER_DESERIALIZE_METHOD_BOUND;
|
||||||
|
private static final Method SEND_MESSAGE_COMPONENT;
|
||||||
|
|
||||||
|
static {
|
||||||
|
final MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||||
|
|
||||||
|
MethodHandle nativeGsonComponentSerializerDeserializeMethodBound = null;
|
||||||
|
|
||||||
|
// String.join because otherwise the class name will be relocated
|
||||||
|
final Class<?> nativeGsonComponentSerializerClass = findClass(String.join(".",
|
||||||
|
"net", "kyori", "adventure", "text", "serializer", "gson", "GsonComponentSerializer"));
|
||||||
|
final Class<?> nativeGsonComponentSerializerImplClass = findClass(String.join(".",
|
||||||
|
"net", "kyori", "adventure", "text", "serializer", "gson", "GsonComponentSerializerImpl"));
|
||||||
|
if (nativeGsonComponentSerializerClass != null && nativeGsonComponentSerializerImplClass != null) {
|
||||||
|
MethodHandle nativeGsonComponentSerializerGsonGetter = null;
|
||||||
|
try {
|
||||||
|
nativeGsonComponentSerializerGsonGetter = lookup.findStatic(nativeGsonComponentSerializerClass,
|
||||||
|
"gson", MethodType.methodType(nativeGsonComponentSerializerClass));
|
||||||
|
} catch (final NoSuchMethodException | IllegalAccessException ignored) {
|
||||||
|
}
|
||||||
|
|
||||||
|
MethodHandle nativeGsonComponentSerializerDeserializeMethod = null;
|
||||||
|
try {
|
||||||
|
final Method method = nativeGsonComponentSerializerImplClass.getDeclaredMethod("deserialize", String.class);
|
||||||
|
method.setAccessible(true);
|
||||||
|
nativeGsonComponentSerializerDeserializeMethod = lookup.unreflect(method);
|
||||||
|
} catch (final NoSuchMethodException | IllegalAccessException ignored) {
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nativeGsonComponentSerializerGsonGetter != null) {
|
||||||
|
if (nativeGsonComponentSerializerDeserializeMethod != null) {
|
||||||
|
try {
|
||||||
|
nativeGsonComponentSerializerDeserializeMethodBound = nativeGsonComponentSerializerDeserializeMethod
|
||||||
|
.bindTo(nativeGsonComponentSerializerGsonGetter.invoke());
|
||||||
|
} catch (final Throwable throwable) {
|
||||||
|
GeyserImpl.getInstance().getLogger().error("Failed to access native GsonComponentSerializer", throwable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NATIVE_GSON_COMPONENT_SERIALIZER_DESERIALIZE_METHOD_BOUND = nativeGsonComponentSerializerDeserializeMethodBound;
|
||||||
|
|
||||||
|
Method playerComponentSendMessage = null;
|
||||||
|
final Class<?> nativeComponentClass = findClass(String.join(".",
|
||||||
|
"net", "kyori", "adventure", "text", "Component"));
|
||||||
|
if (nativeComponentClass != null) {
|
||||||
|
try {
|
||||||
|
playerComponentSendMessage = CommandSender.class.getMethod("sendMessage", nativeComponentClass);
|
||||||
|
} catch (final NoSuchMethodException e) {
|
||||||
|
if (GeyserImpl.getInstance().getLogger().isDebug()) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SEND_MESSAGE_COMPONENT = playerComponentSendMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Object toNativeComponent(final Component component) {
|
||||||
|
if (NATIVE_GSON_COMPONENT_SERIALIZER_DESERIALIZE_METHOD_BOUND == null) {
|
||||||
|
GeyserImpl.getInstance().getLogger().error("Illegal state where Component serialization was called when it wasn't available!");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return NATIVE_GSON_COMPONENT_SERIALIZER_DESERIALIZE_METHOD_BOUND.invoke(DefaultComponentSerializer.get().serialize(component));
|
||||||
|
} catch (final Throwable throwable) {
|
||||||
|
GeyserImpl.getInstance().getLogger().error("Failed to create native Component message", throwable);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void sendMessage(final CommandSender sender, final Component component) {
|
||||||
|
if (SEND_MESSAGE_COMPONENT == null) {
|
||||||
|
GeyserImpl.getInstance().getLogger().error("Illegal state where Component sendMessage was called when it wasn't available!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final Object nativeComponent = toNativeComponent(component);
|
||||||
|
if (nativeComponent != null) {
|
||||||
|
try {
|
||||||
|
SEND_MESSAGE_COMPONENT.invoke(sender, nativeComponent);
|
||||||
|
} catch (final InvocationTargetException | IllegalAccessException e) {
|
||||||
|
GeyserImpl.getInstance().getLogger().error("Failed to send native Component message", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean canSendMessageUsingComponent() {
|
||||||
|
return SEND_MESSAGE_COMPONENT != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a class by the first name available.
|
||||||
|
*
|
||||||
|
* @return a class or {@code null} if not found
|
||||||
|
*/
|
||||||
|
private static @Nullable Class<?> findClass(final String className) {
|
||||||
|
try {
|
||||||
|
return Class.forName(className);
|
||||||
|
} catch (final ClassNotFoundException ignored) {
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private PaperAdventure() {
|
||||||
|
}
|
||||||
|
}
|
@ -66,6 +66,9 @@ public class GeyserSpigotCommandExecutor extends GeyserCommandExecutor implement
|
|||||||
}
|
}
|
||||||
geyserCommand.execute(session, commandSender, args.length > 1 ? Arrays.copyOfRange(args, 1, args.length) : new String[0]);
|
geyserCommand.execute(session, commandSender, args.length > 1 ? Arrays.copyOfRange(args, 1, args.length) : new String[0]);
|
||||||
return true;
|
return true;
|
||||||
|
} else {
|
||||||
|
String message = GeyserLocale.getPlayerLocaleString("geyser.bootstrap.command.not_found", commandSender.locale());
|
||||||
|
commandSender.sendMessage(ChatColor.RED + message);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
getCommand("help").execute(session, commandSender, new String[0]);
|
getCommand("help").execute(session, commandSender, new String[0]);
|
||||||
|
@ -65,4 +65,8 @@ public class GeyserSpigotCommandManager extends GeyserCommandManager {
|
|||||||
Command cmd = COMMAND_MAP.getCommand(command.replace("/", ""));
|
Command cmd = COMMAND_MAP.getCommand(command.replace("/", ""));
|
||||||
return cmd != null ? cmd.getDescription() : "";
|
return cmd != null ? cmd.getDescription() : "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static CommandMap getCommandMap() {
|
||||||
|
return COMMAND_MAP;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,32 +25,21 @@
|
|||||||
|
|
||||||
package org.geysermc.geyser.platform.spigot.command;
|
package org.geysermc.geyser.platform.spigot.command;
|
||||||
|
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.serializer.bungeecord.BungeeComponentSerializer;
|
||||||
import org.bukkit.command.ConsoleCommandSender;
|
import org.bukkit.command.ConsoleCommandSender;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.geysermc.geyser.GeyserImpl;
|
|
||||||
import org.geysermc.geyser.command.GeyserCommandSource;
|
import org.geysermc.geyser.command.GeyserCommandSource;
|
||||||
|
import org.geysermc.geyser.platform.spigot.PaperAdventure;
|
||||||
import org.geysermc.geyser.text.GeyserLocale;
|
import org.geysermc.geyser.text.GeyserLocale;
|
||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
|
|
||||||
public class SpigotCommandSource implements GeyserCommandSource {
|
public class SpigotCommandSource implements GeyserCommandSource {
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether to use {@code Player.getLocale()} or {@code Player.spigot().getLocale()}, depending on version.
|
|
||||||
* 1.12 or greater should not use the legacy method.
|
|
||||||
*/
|
|
||||||
private static boolean USE_LEGACY_METHOD = false;
|
|
||||||
private static Method LOCALE_METHOD;
|
|
||||||
|
|
||||||
private final org.bukkit.command.CommandSender handle;
|
private final org.bukkit.command.CommandSender handle;
|
||||||
private final String locale;
|
|
||||||
|
|
||||||
public SpigotCommandSource(org.bukkit.command.CommandSender handle) {
|
public SpigotCommandSource(org.bukkit.command.CommandSender handle) {
|
||||||
this.handle = handle;
|
this.handle = handle;
|
||||||
this.locale = getSpigotLocale();
|
|
||||||
// Ensure even Java players' languages are loaded
|
// Ensure even Java players' languages are loaded
|
||||||
GeyserLocale.loadGeyserLocale(locale);
|
GeyserLocale.loadGeyserLocale(locale());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -63,6 +52,17 @@ public class SpigotCommandSource implements GeyserCommandSource {
|
|||||||
handle.sendMessage(message);
|
handle.sendMessage(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendMessage(Component message) {
|
||||||
|
if (PaperAdventure.canSendMessageUsingComponent()) {
|
||||||
|
PaperAdventure.sendMessage(handle, message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CommandSender#sendMessage(BaseComponent[]) is Paper-only
|
||||||
|
handle.spigot().sendMessage(BungeeComponentSerializer.get().serialize(message));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isConsole() {
|
public boolean isConsole() {
|
||||||
return handle instanceof ConsoleCommandSender;
|
return handle instanceof ConsoleCommandSender;
|
||||||
@ -70,50 +70,15 @@ public class SpigotCommandSource implements GeyserCommandSource {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String locale() {
|
public String locale() {
|
||||||
return locale;
|
if (this.handle instanceof Player player) {
|
||||||
|
return player.getLocale();
|
||||||
|
}
|
||||||
|
|
||||||
|
return GeyserLocale.getDefaultLocale();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasPermission(String permission) {
|
public boolean hasPermission(String permission) {
|
||||||
return handle.hasPermission(permission);
|
return handle.hasPermission(permission);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Set if we are on pre-1.12, and therefore {@code player.getLocale()} doesn't exist and we have to get
|
|
||||||
* {@code player.spigot().getLocale()}.
|
|
||||||
*
|
|
||||||
* @param useLegacyMethod if we are running pre-1.12 and therefore need to use reflection to get the player locale
|
|
||||||
*/
|
|
||||||
public static void setUseLegacyLocaleMethod(boolean useLegacyMethod) {
|
|
||||||
USE_LEGACY_METHOD = useLegacyMethod;
|
|
||||||
if (USE_LEGACY_METHOD) {
|
|
||||||
try {
|
|
||||||
//noinspection JavaReflectionMemberAccess - of course it doesn't exist; that's why we're doing it
|
|
||||||
LOCALE_METHOD = Player.Spigot.class.getMethod("getLocale");
|
|
||||||
} catch (NoSuchMethodException e) {
|
|
||||||
GeyserImpl.getInstance().getLogger().debug("Player.Spigot.getLocale() doesn't exist? Not a big deal but if you're seeing this please report it to the developers!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* So we only have to do nasty reflection stuff once per command
|
|
||||||
*
|
|
||||||
* @return the locale of the Spigot player
|
|
||||||
*/
|
|
||||||
private String getSpigotLocale() {
|
|
||||||
if (handle instanceof Player player) {
|
|
||||||
if (USE_LEGACY_METHOD) {
|
|
||||||
try {
|
|
||||||
// sigh
|
|
||||||
// This was the only option on older Spigot instances and now it's gone
|
|
||||||
return (String) LOCALE_METHOD.invoke(player.spigot());
|
|
||||||
} catch (IllegalAccessException | InvocationTargetException ignored) {
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return player.getLocale();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return GeyserLocale.getDefaultLocale();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -105,13 +105,10 @@ public class GeyserPistonListener implements Listener {
|
|||||||
// Trying to grab the blocks from the world like other platforms would result in the moving piston block
|
// Trying to grab the blocks from the world like other platforms would result in the moving piston block
|
||||||
// being returned instead.
|
// being returned instead.
|
||||||
if (!blocksFilled) {
|
if (!blocksFilled) {
|
||||||
// Blocks currently require a player for 1.12, so let's just leech off one player to get all blocks
|
|
||||||
// and call it a day for the rest of the sessions (mostly to save on execution time)
|
|
||||||
List<Block> blocks = isExtend ? ((BlockPistonExtendEvent) event).getBlocks() : ((BlockPistonRetractEvent) event).getBlocks();
|
List<Block> blocks = isExtend ? ((BlockPistonExtendEvent) event).getBlocks() : ((BlockPistonRetractEvent) event).getBlocks();
|
||||||
for (Block block : blocks) {
|
for (Block block : blocks) {
|
||||||
Location attachedLocation = block.getLocation();
|
Location attachedLocation = block.getLocation();
|
||||||
int blockId = worldManager.getBlockNetworkId(player, block,
|
int blockId = worldManager.getBlockNetworkId(block);
|
||||||
attachedLocation.getBlockX(), attachedLocation.getBlockY(), attachedLocation.getBlockZ());
|
|
||||||
// Ignore blocks that will be destroyed
|
// Ignore blocks that will be destroyed
|
||||||
if (BlockStateValues.canPistonMoveBlock(blockId, isExtend)) {
|
if (BlockStateValues.canPistonMoveBlock(blockId, isExtend)) {
|
||||||
attachedBlocks.put(getVector(attachedLocation), blockId);
|
attachedBlocks.put(getVector(attachedLocation), blockId);
|
||||||
@ -120,7 +117,7 @@ public class GeyserPistonListener implements Listener {
|
|||||||
blocksFilled = true;
|
blocksFilled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int pistonBlockId = worldManager.getBlockNetworkId(player, event.getBlock(), location.getBlockX(), location.getBlockY(), location.getBlockZ());
|
int pistonBlockId = worldManager.getBlockNetworkId(event.getBlock());
|
||||||
// event.getDirection() is unreliable
|
// event.getDirection() is unreliable
|
||||||
Direction orientation = BlockStateValues.getPistonOrientation(pistonBlockId);
|
Direction orientation = BlockStateValues.getPistonOrientation(pistonBlockId);
|
||||||
|
|
||||||
|
@ -1,61 +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.spigot.world.manager;
|
|
||||||
|
|
||||||
import com.viaversion.viaversion.api.Via;
|
|
||||||
import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.storage.BlockStorage;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.plugin.Plugin;
|
|
||||||
import org.geysermc.geyser.adapters.spigot.SpigotAdapters;
|
|
||||||
import org.geysermc.geyser.adapters.spigot.SpigotWorldAdapter;
|
|
||||||
import org.geysermc.geyser.level.block.BlockStateValues;
|
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used with ViaVersion and pre-1.13.
|
|
||||||
*/
|
|
||||||
public class GeyserSpigot1_12NativeWorldManager extends GeyserSpigot1_12WorldManager {
|
|
||||||
private final SpigotWorldAdapter adapter;
|
|
||||||
|
|
||||||
public GeyserSpigot1_12NativeWorldManager(Plugin plugin) {
|
|
||||||
super(plugin);
|
|
||||||
this.adapter = SpigotAdapters.getWorldAdapter();
|
|
||||||
// Unlike post-1.13, we can't build up a cache of block states, because block entities need some special conversion
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getBlockAt(GeyserSession session, int x, int y, int z) {
|
|
||||||
Player player = Bukkit.getPlayer(session.getPlayerEntity().getUsername());
|
|
||||||
if (player == null) {
|
|
||||||
return BlockStateValues.JAVA_AIR_ID;
|
|
||||||
}
|
|
||||||
// Get block entity storage
|
|
||||||
BlockStorage storage = Via.getManager().getConnectionManager().getConnectedClient(player.getUniqueId()).get(BlockStorage.class);
|
|
||||||
int blockId = adapter.getBlockAt(player.getWorld(), x, y, z);
|
|
||||||
return getLegacyBlock(storage, blockId, x, y, z);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,125 +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.spigot.world.manager;
|
|
||||||
|
|
||||||
import com.viaversion.viaversion.api.Via;
|
|
||||||
import com.viaversion.viaversion.api.data.MappingData;
|
|
||||||
import com.viaversion.viaversion.api.minecraft.Position;
|
|
||||||
import com.viaversion.viaversion.api.protocol.ProtocolPathEntry;
|
|
||||||
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
|
|
||||||
import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.Protocol1_13To1_12_2;
|
|
||||||
import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.storage.BlockStorage;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.block.Block;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.plugin.Plugin;
|
|
||||||
import org.geysermc.geyser.level.block.BlockStateValues;
|
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Should be used when ViaVersion is present, no NMS adapter is being used, and we are pre-1.13.
|
|
||||||
*
|
|
||||||
* You need ViaVersion to connect to an older server with the Geyser-Spigot plugin.
|
|
||||||
*/
|
|
||||||
public class GeyserSpigot1_12WorldManager extends GeyserSpigotWorldManager {
|
|
||||||
/**
|
|
||||||
* Specific mapping data for 1.12 to 1.13. Used to convert the 1.12 block into the 1.13 block state.
|
|
||||||
* (Block IDs did not change between server versions until 1.13 and after)
|
|
||||||
*/
|
|
||||||
private final MappingData mappingData1_12to1_13;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The list of all protocols from the client's version to 1.13.
|
|
||||||
*/
|
|
||||||
private final List<ProtocolPathEntry> protocolList;
|
|
||||||
|
|
||||||
public GeyserSpigot1_12WorldManager(Plugin plugin) {
|
|
||||||
super(plugin);
|
|
||||||
this.mappingData1_12to1_13 = Via.getManager().getProtocolManager().getProtocol(Protocol1_13To1_12_2.class).getMappingData();
|
|
||||||
this.protocolList = Via.getManager().getProtocolManager().getProtocolPath(CLIENT_PROTOCOL_VERSION,
|
|
||||||
ProtocolVersion.v1_13.getVersion());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getBlockAt(GeyserSession session, int x, int y, int z) {
|
|
||||||
Player player = Bukkit.getPlayer(session.getPlayerEntity().getUsername());
|
|
||||||
if (player == null) {
|
|
||||||
return BlockStateValues.JAVA_AIR_ID;
|
|
||||||
}
|
|
||||||
if (!player.getWorld().isChunkLoaded(x >> 4, z >> 4)) {
|
|
||||||
// Prevent nasty async errors if a player is loading in
|
|
||||||
return BlockStateValues.JAVA_AIR_ID;
|
|
||||||
}
|
|
||||||
|
|
||||||
Block block = player.getWorld().getBlockAt(x, y, z);
|
|
||||||
return getBlockNetworkId(player, block, x, y, z);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
public int getBlockNetworkId(Player player, Block block, int x, int y, int z) {
|
|
||||||
// Get block entity storage
|
|
||||||
BlockStorage storage = Via.getManager().getConnectionManager().getConnectedClient(player.getUniqueId()).get(BlockStorage.class);
|
|
||||||
// Black magic that gets the old block state ID
|
|
||||||
int oldBlockId = (block.getType().getId() << 4) | (block.getData() & 0xF);
|
|
||||||
return getLegacyBlock(storage, oldBlockId, x, y, z);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param storage ViaVersion's block entity storage (used to fix block entity state differences)
|
|
||||||
* @param blockId the pre-1.13 block id
|
|
||||||
* @param x X coordinate of block
|
|
||||||
* @param y Y coordinate of block
|
|
||||||
* @param z Z coordinate of block
|
|
||||||
* @return the block state updated to the latest Minecraft version
|
|
||||||
*/
|
|
||||||
public int getLegacyBlock(BlockStorage storage, int blockId, int x, int y, int z) {
|
|
||||||
// Convert block state from old version (1.12.2) -> 1.13 -> 1.13.1 -> 1.14 -> 1.15 -> 1.16 -> 1.16.2
|
|
||||||
blockId = mappingData1_12to1_13.getNewBlockId(blockId);
|
|
||||||
// Translate block entity differences - some information was stored in block tags and not block states
|
|
||||||
if (storage.isWelcome(blockId)) { // No getOrDefault method
|
|
||||||
BlockStorage.ReplacementData data = storage.get(new Position(x, (short) y, z));
|
|
||||||
if (data != null && data.getReplacement() != -1) {
|
|
||||||
blockId = data.getReplacement();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (int i = protocolList.size() - 1; i >= 0; i--) {
|
|
||||||
MappingData mappingData = protocolList.get(i).getProtocol().getMappingData();
|
|
||||||
if (mappingData != null) {
|
|
||||||
blockId = mappingData.getNewBlockStateId(blockId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return blockId;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isLegacy() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
@ -32,6 +32,7 @@ import org.geysermc.geyser.adapters.spigot.SpigotAdapters;
|
|||||||
import org.geysermc.geyser.adapters.spigot.SpigotWorldAdapter;
|
import org.geysermc.geyser.adapters.spigot.SpigotWorldAdapter;
|
||||||
import org.geysermc.geyser.level.block.BlockStateValues;
|
import org.geysermc.geyser.level.block.BlockStateValues;
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
public class GeyserSpigotNativeWorldManager extends GeyserSpigotWorldManager {
|
public class GeyserSpigotNativeWorldManager extends GeyserSpigotWorldManager {
|
||||||
protected final SpigotWorldAdapter adapter;
|
protected final SpigotWorldAdapter adapter;
|
||||||
@ -49,4 +50,12 @@ public class GeyserSpigotNativeWorldManager extends GeyserSpigotWorldManager {
|
|||||||
}
|
}
|
||||||
return adapter.getBlockAt(player.getWorld(), x, y, z);
|
return adapter.getBlockAt(player.getWorld(), x, y, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public String[] getBiomeIdentifiers(boolean withTags) {
|
||||||
|
// Biome identifiers will basically always be the same for one server, since you have to re-send the
|
||||||
|
// ClientboundLoginPacket to change the registry. Therefore, don't bother caching for each player.
|
||||||
|
return adapter.getBiomeSuggestions(withTags);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,15 +33,13 @@ import org.bukkit.Bukkit;
|
|||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.block.Block;
|
import org.bukkit.block.Block;
|
||||||
import org.bukkit.block.Lectern;
|
import org.bukkit.block.Lectern;
|
||||||
import org.bukkit.block.data.BlockData;
|
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.bukkit.inventory.meta.BookMeta;
|
import org.bukkit.inventory.meta.BookMeta;
|
||||||
import org.bukkit.plugin.Plugin;
|
import org.bukkit.plugin.Plugin;
|
||||||
import org.geysermc.geyser.level.GameRule;
|
import org.geysermc.geyser.level.GameRule;
|
||||||
import org.geysermc.geyser.level.GeyserWorldManager;
|
import org.geysermc.geyser.level.WorldManager;
|
||||||
import org.geysermc.geyser.level.block.BlockStateValues;
|
import org.geysermc.geyser.level.block.BlockStateValues;
|
||||||
import org.geysermc.geyser.network.GameProtocol;
|
|
||||||
import org.geysermc.geyser.registry.BlockRegistries;
|
import org.geysermc.geyser.registry.BlockRegistries;
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
import org.geysermc.geyser.translator.inventory.LecternInventoryTranslator;
|
import org.geysermc.geyser.translator.inventory.LecternInventoryTranslator;
|
||||||
@ -53,12 +51,7 @@ import java.util.List;
|
|||||||
/**
|
/**
|
||||||
* The base world manager to use when there is no supported NMS revision
|
* The base world manager to use when there is no supported NMS revision
|
||||||
*/
|
*/
|
||||||
public class GeyserSpigotWorldManager extends GeyserWorldManager {
|
public class GeyserSpigotWorldManager extends WorldManager {
|
||||||
/**
|
|
||||||
* The current client protocol version for ViaVersion usage.
|
|
||||||
*/
|
|
||||||
protected static final int CLIENT_PROTOCOL_VERSION = GameProtocol.getJavaProtocolVersion();
|
|
||||||
|
|
||||||
private final Plugin plugin;
|
private final Plugin plugin;
|
||||||
|
|
||||||
public GeyserSpigotWorldManager(Plugin plugin) {
|
public GeyserSpigotWorldManager(Plugin plugin) {
|
||||||
@ -77,10 +70,10 @@ public class GeyserSpigotWorldManager extends GeyserWorldManager {
|
|||||||
return BlockStateValues.JAVA_AIR_ID;
|
return BlockStateValues.JAVA_AIR_ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
return getBlockNetworkId(bukkitPlayer, world.getBlockAt(x, y, z), x, y, z);
|
return getBlockNetworkId(world.getBlockAt(x, y, z));
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getBlockNetworkId(Player player, Block block, int x, int y, int z) {
|
public int getBlockNetworkId(Block block) {
|
||||||
return BlockRegistries.JAVA_IDENTIFIERS.getOrDefault(block.getBlockData().getAsString(), BlockStateValues.JAVA_AIR_ID);
|
return BlockRegistries.JAVA_IDENTIFIERS.getOrDefault(block.getBlockData().getAsString(), BlockStateValues.JAVA_AIR_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -158,12 +151,12 @@ public class GeyserSpigotWorldManager extends GeyserWorldManager {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Boolean getGameRuleBool(GeyserSession session, GameRule gameRule) {
|
public boolean getGameRuleBool(GeyserSession session, GameRule gameRule) {
|
||||||
String value = Bukkit.getPlayer(session.getPlayerEntity().getUsername()).getWorld().getGameRuleValue(gameRule.getJavaID());
|
String value = Bukkit.getPlayer(session.getPlayerEntity().getUsername()).getWorld().getGameRuleValue(gameRule.getJavaID());
|
||||||
if (!value.isEmpty()) {
|
if (!value.isEmpty()) {
|
||||||
return Boolean.parseBoolean(value);
|
return Boolean.parseBoolean(value);
|
||||||
}
|
}
|
||||||
return (Boolean) gameRule.getDefaultValue();
|
return gameRule.getDefaultBooleanValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -172,7 +165,7 @@ public class GeyserSpigotWorldManager extends GeyserWorldManager {
|
|||||||
if (!value.isEmpty()) {
|
if (!value.isEmpty()) {
|
||||||
return Integer.parseInt(value);
|
return Integer.parseInt(value);
|
||||||
}
|
}
|
||||||
return (int) gameRule.getDefaultValue();
|
return gameRule.getDefaultIntValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -181,8 +174,6 @@ public class GeyserSpigotWorldManager extends GeyserWorldManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This must be set to true if we are pre-1.13, and {@link BlockData#getAsString() does not exist}.
|
|
||||||
*
|
|
||||||
* This should be set to true if we are post-1.13 but before the latest version, and we should convert the old block state id
|
* This should be set to true if we are post-1.13 but before the latest version, and we should convert the old block state id
|
||||||
* to the current one.
|
* to the current one.
|
||||||
*
|
*
|
||||||
|
@ -8,7 +8,4 @@ api-version: 1.13
|
|||||||
commands:
|
commands:
|
||||||
geyser:
|
geyser:
|
||||||
description: The main command for Geyser.
|
description: The main command for Geyser.
|
||||||
usage: /geyser <subcommand>
|
usage: /geyser <subcommand>
|
||||||
geyserext:
|
|
||||||
description: The command any extensions can register to.
|
|
||||||
usage: /geyserext <subcommand>
|
|
@ -1,5 +1,3 @@
|
|||||||
val spongeVersion = "7.1.0"
|
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
api(projects.core)
|
api(projects.core)
|
||||||
}
|
}
|
||||||
@ -9,16 +7,11 @@ platformRelocate("io.netty")
|
|||||||
platformRelocate("it.unimi.dsi.fastutil")
|
platformRelocate("it.unimi.dsi.fastutil")
|
||||||
platformRelocate("com.google.common")
|
platformRelocate("com.google.common")
|
||||||
platformRelocate("com.google.guava")
|
platformRelocate("com.google.guava")
|
||||||
platformRelocate("net.kyori")
|
platformRelocate("net.kyori.adventure.text.serializer.gson.legacyimpl")
|
||||||
|
platformRelocate("net.kyori.adventure.nbt")
|
||||||
// Exclude these dependencies
|
|
||||||
exclude("com.google.code.gson:*")
|
|
||||||
exclude("org.yaml:*")
|
|
||||||
exclude("org.slf4j:*")
|
|
||||||
exclude("org.ow2.asm:*")
|
|
||||||
|
|
||||||
// These dependencies are already present on the platform
|
// These dependencies are already present on the platform
|
||||||
provided("org.spongepowered", "spongeapi", spongeVersion)
|
provided(libs.sponge.api)
|
||||||
|
|
||||||
application {
|
application {
|
||||||
mainClass.set("org.geysermc.geyser.platform.sponge.GeyserSpongeMain")
|
mainClass.set("org.geysermc.geyser.platform.sponge.GeyserSpongeMain")
|
||||||
@ -32,5 +25,14 @@ tasks.withType<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar> {
|
|||||||
exclude(dependency("org.yaml:.*"))
|
exclude(dependency("org.yaml:.*"))
|
||||||
exclude(dependency("org.slf4j:.*"))
|
exclude(dependency("org.slf4j:.*"))
|
||||||
exclude(dependency("org.ow2.asm:.*"))
|
exclude(dependency("org.ow2.asm:.*"))
|
||||||
|
|
||||||
|
// Exclude all Kyori dependencies except the legacy NBT serializer 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:.*"))
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -27,35 +27,45 @@ package org.geysermc.geyser.platform.sponge;
|
|||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import org.geysermc.geyser.dump.BootstrapDumpInfo;
|
import org.geysermc.geyser.dump.BootstrapDumpInfo;
|
||||||
|
import org.geysermc.geyser.text.AsteriskSerializer;
|
||||||
import org.spongepowered.api.Platform;
|
import org.spongepowered.api.Platform;
|
||||||
import org.spongepowered.api.Sponge;
|
import org.spongepowered.api.Sponge;
|
||||||
import org.spongepowered.api.plugin.PluginContainer;
|
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.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
public class GeyserSpongeDumpInfo extends BootstrapDumpInfo {
|
public class GeyserSpongeDumpInfo extends BootstrapDumpInfo {
|
||||||
private final String platformName;
|
private final String platformName;
|
||||||
private final String platformVersion;
|
private final String platformVersion;
|
||||||
private final boolean onlineMode;
|
private final boolean onlineMode;
|
||||||
|
|
||||||
|
@AsteriskSerializer.Asterisk(isIp = true)
|
||||||
private final String serverIP;
|
private final String serverIP;
|
||||||
private final int serverPort;
|
private final int serverPort;
|
||||||
private final List<PluginInfo> plugins;
|
private final List<PluginInfo> plugins;
|
||||||
|
|
||||||
GeyserSpongeDumpInfo() {
|
GeyserSpongeDumpInfo() {
|
||||||
super();
|
PluginContainer container = Sponge.platform().container(Platform.Component.IMPLEMENTATION);
|
||||||
PluginContainer container = Sponge.getPlatform().getContainer(Platform.Component.IMPLEMENTATION);
|
PluginMetadata platformMeta = container.metadata();
|
||||||
this.platformName = container.getName();
|
this.platformName = platformMeta.name().orElse("unknown");
|
||||||
this.platformVersion = container.getVersion().get();
|
this.platformVersion = platformMeta.version().getQualifier();
|
||||||
this.onlineMode = Sponge.getServer().getOnlineMode();
|
this.onlineMode = Sponge.server().isOnlineModeEnabled();
|
||||||
this.serverIP = Sponge.getServer().getBoundAddress().get().getHostString();
|
Optional<InetSocketAddress> socketAddress = Sponge.server().boundAddress();
|
||||||
this.serverPort = Sponge.getServer().getBoundAddress().get().getPort();
|
this.serverIP = socketAddress.map(InetSocketAddress::getHostString).orElse("unknown");
|
||||||
|
this.serverPort = socketAddress.map(InetSocketAddress::getPort).orElse(-1);
|
||||||
this.plugins = new ArrayList<>();
|
this.plugins = new ArrayList<>();
|
||||||
|
|
||||||
for (PluginContainer plugin : Sponge.getPluginManager().getPlugins()) {
|
for (PluginContainer plugin : Sponge.pluginManager().plugins()) {
|
||||||
String pluginClass = plugin.getInstance().map((pl) -> pl.getClass().getName()).orElse("unknown");
|
PluginMetadata meta = plugin.metadata();
|
||||||
this.plugins.add(new PluginInfo(true, plugin.getName(), plugin.getVersion().get(), pluginClass, plugin.getAuthors()));
|
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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,7 @@ import lombok.AllArgsConstructor;
|
|||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import org.geysermc.geyser.GeyserLogger;
|
import org.geysermc.geyser.GeyserLogger;
|
||||||
import org.slf4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public class GeyserSpongeLogger implements GeyserLogger {
|
public class GeyserSpongeLogger implements GeyserLogger {
|
||||||
|
@ -28,11 +28,12 @@ package org.geysermc.geyser.platform.sponge;
|
|||||||
import org.geysermc.geyser.network.GameProtocol;
|
import org.geysermc.geyser.network.GameProtocol;
|
||||||
import org.geysermc.geyser.ping.GeyserPingInfo;
|
import org.geysermc.geyser.ping.GeyserPingInfo;
|
||||||
import org.geysermc.geyser.ping.IGeyserPingPassthrough;
|
import org.geysermc.geyser.ping.IGeyserPingPassthrough;
|
||||||
|
import org.geysermc.geyser.translator.text.MessageTranslator;
|
||||||
import org.spongepowered.api.MinecraftVersion;
|
import org.spongepowered.api.MinecraftVersion;
|
||||||
import org.spongepowered.api.Sponge;
|
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.SpongeEventFactory;
|
||||||
import org.spongepowered.api.event.cause.Cause;
|
|
||||||
import org.spongepowered.api.event.cause.EventContext;
|
|
||||||
import org.spongepowered.api.event.server.ClientPingServerEvent;
|
import org.spongepowered.api.event.server.ClientPingServerEvent;
|
||||||
import org.spongepowered.api.network.status.StatusClient;
|
import org.spongepowered.api.network.status.StatusClient;
|
||||||
import org.spongepowered.api.profile.GameProfile;
|
import org.spongepowered.api.profile.GameProfile;
|
||||||
@ -43,7 +44,7 @@ import java.util.Optional;
|
|||||||
|
|
||||||
public class GeyserSpongePingPassthrough implements IGeyserPingPassthrough {
|
public class GeyserSpongePingPassthrough implements IGeyserPingPassthrough {
|
||||||
|
|
||||||
private static final Cause CAUSE = Cause.of(EventContext.empty(), Sponge.getServer());
|
private static final Cause CAUSE = Cause.of(EventContext.empty(), Sponge.server());
|
||||||
|
|
||||||
private static Method SpongeStatusResponse_create;
|
private static Method SpongeStatusResponse_create;
|
||||||
|
|
||||||
@ -59,50 +60,46 @@ public class GeyserSpongePingPassthrough implements IGeyserPingPassthrough {
|
|||||||
SpongeStatusResponse_create = SpongeStatusResponse.getDeclaredMethod("create", MinecraftServer);
|
SpongeStatusResponse_create = SpongeStatusResponse.getDeclaredMethod("create", MinecraftServer);
|
||||||
}
|
}
|
||||||
|
|
||||||
Object response = SpongeStatusResponse_create.invoke(null, Sponge.getServer());
|
Object response = SpongeStatusResponse_create.invoke(null, Sponge.server());
|
||||||
event = SpongeEventFactory.createClientPingServerEvent(CAUSE, new GeyserStatusClient(inetSocketAddress), (ClientPingServerEvent.Response) response);
|
event = SpongeEventFactory.createClientPingServerEvent(CAUSE, new GeyserStatusClient(inetSocketAddress), (ClientPingServerEvent.Response) response);
|
||||||
} catch (ReflectiveOperationException e) {
|
} catch (ReflectiveOperationException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
Sponge.getEventManager().post(event);
|
Sponge.eventManager().post(event);
|
||||||
GeyserPingInfo geyserPingInfo = new GeyserPingInfo(
|
GeyserPingInfo geyserPingInfo = new GeyserPingInfo(
|
||||||
event.getResponse().getDescription().toPlain(),
|
MessageTranslator.convertMessage(event.response().description()),
|
||||||
new GeyserPingInfo.Players(
|
new GeyserPingInfo.Players(
|
||||||
event.getResponse().getPlayers().orElseThrow(IllegalStateException::new).getMax(),
|
event.response().players().orElseThrow(IllegalStateException::new).max(),
|
||||||
event.getResponse().getPlayers().orElseThrow(IllegalStateException::new).getOnline()
|
event.response().players().orElseThrow(IllegalStateException::new).online()
|
||||||
),
|
),
|
||||||
new GeyserPingInfo.Version(
|
new GeyserPingInfo.Version(
|
||||||
event.getResponse().getVersion().getName(),
|
event.response().version().name(),
|
||||||
GameProtocol.getJavaProtocolVersion()) // thanks for also not exposing this sponge
|
GameProtocol.getJavaProtocolVersion()) // thanks for also not exposing this sponge
|
||||||
);
|
);
|
||||||
event.getResponse().getPlayers().get().getProfiles().stream()
|
event.response().players().ifPresent(players -> players.profiles().stream()
|
||||||
.map(GameProfile::getName)
|
.map(GameProfile::name)
|
||||||
.map(op -> op.orElseThrow(IllegalStateException::new))
|
.filter(Optional::isPresent)
|
||||||
.forEach(geyserPingInfo.getPlayerList()::add);
|
.map(Optional::get)
|
||||||
|
.forEach(geyserPingInfo.getPlayerList()::add)
|
||||||
|
);
|
||||||
|
|
||||||
return geyserPingInfo;
|
return geyserPingInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("NullableProblems")
|
private record GeyserStatusClient(InetSocketAddress remote) implements StatusClient {
|
||||||
private static class GeyserStatusClient implements StatusClient {
|
|
||||||
|
|
||||||
private final InetSocketAddress remote;
|
|
||||||
|
|
||||||
public GeyserStatusClient(InetSocketAddress remote) {
|
|
||||||
this.remote = remote;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public InetSocketAddress getAddress() {
|
public InetSocketAddress address() {
|
||||||
return this.remote;
|
return this.remote;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MinecraftVersion getVersion() {
|
public MinecraftVersion version() {
|
||||||
return Sponge.getPlatform().getMinecraftVersion();
|
return Sponge.platform().minecraftVersion();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<InetSocketAddress> getVirtualHost() {
|
public Optional<InetSocketAddress> virtualHost() {
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,81 +26,169 @@
|
|||||||
package org.geysermc.geyser.platform.sponge;
|
package org.geysermc.geyser.platform.sponge;
|
||||||
|
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.geysermc.common.PlatformType;
|
import org.geysermc.common.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.extension.Extension;
|
||||||
import org.geysermc.geyser.command.GeyserCommandManager;
|
import org.geysermc.geyser.command.GeyserCommandManager;
|
||||||
import org.geysermc.geyser.configuration.GeyserConfiguration;
|
import org.geysermc.geyser.configuration.GeyserConfiguration;
|
||||||
import org.geysermc.geyser.dump.BootstrapDumpInfo;
|
import org.geysermc.geyser.dump.BootstrapDumpInfo;
|
||||||
import org.geysermc.geyser.ping.GeyserLegacyPingPassthrough;
|
import org.geysermc.geyser.ping.GeyserLegacyPingPassthrough;
|
||||||
import org.geysermc.geyser.ping.IGeyserPingPassthrough;
|
import org.geysermc.geyser.ping.IGeyserPingPassthrough;
|
||||||
import org.geysermc.geyser.platform.sponge.command.GeyserSpongeCommandExecutor;
|
|
||||||
import org.geysermc.geyser.platform.sponge.command.GeyserSpongeCommandManager;
|
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.FileUtils;
|
||||||
import org.slf4j.Logger;
|
import org.geysermc.geyser.text.GeyserLocale;
|
||||||
|
import org.geysermc.geyser.platform.sponge.command.GeyserSpongeCommandExecutor;
|
||||||
|
import org.spongepowered.api.Server;
|
||||||
import org.spongepowered.api.Sponge;
|
import org.spongepowered.api.Sponge;
|
||||||
import org.spongepowered.api.config.ConfigDir;
|
import org.spongepowered.api.config.ConfigDir;
|
||||||
import org.spongepowered.api.event.Listener;
|
import org.spongepowered.api.event.Listener;
|
||||||
import org.spongepowered.api.event.game.state.GameStartedServerEvent;
|
import org.spongepowered.api.event.lifecycle.ConstructPluginEvent;
|
||||||
import org.spongepowered.api.event.game.state.GameStoppedEvent;
|
import org.spongepowered.api.event.lifecycle.RegisterCommandEvent;
|
||||||
import org.spongepowered.api.plugin.Plugin;
|
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.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@Plugin(id = "geyser", name = GeyserImpl.NAME + "-Sponge", version = GeyserImpl.VERSION, url = "https://geysermc.org", authors = "GeyserMC")
|
@Plugin(value = "geyser")
|
||||||
public class GeyserSpongePlugin implements GeyserBootstrap {
|
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
|
@Inject
|
||||||
private Logger logger;
|
private Logger logger;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
@ConfigDir(sharedRoot = false)
|
@ConfigDir(sharedRoot = false)
|
||||||
private File configDir;
|
private Path configPath;
|
||||||
|
|
||||||
private GeyserSpongeCommandManager geyserCommandManager;
|
// Available after construction lifecycle
|
||||||
private GeyserSpongeConfiguration geyserConfig;
|
private GeyserSpongeConfiguration geyserConfig;
|
||||||
private GeyserSpongeLogger geyserLogger;
|
private GeyserSpongeLogger geyserLogger;
|
||||||
|
private GeyserImpl geyser;
|
||||||
|
private GeyserSpongeCommandManager geyserCommandManager; // Commands are only registered after command registration lifecycle
|
||||||
|
|
||||||
|
// Available after StartedEngine lifecycle
|
||||||
private IGeyserPingPassthrough geyserSpongePingPassthrough;
|
private IGeyserPingPassthrough geyserSpongePingPassthrough;
|
||||||
|
|
||||||
private GeyserImpl geyser;
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Only to be used for reloading
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void onEnable() {
|
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);
|
GeyserLocale.init(this);
|
||||||
|
|
||||||
if (!configDir.exists())
|
File configDir = configPath.toFile();
|
||||||
|
if (!configDir.exists()) {
|
||||||
configDir.mkdirs();
|
configDir.mkdirs();
|
||||||
|
}
|
||||||
|
|
||||||
File configFile;
|
File configFile;
|
||||||
try {
|
try {
|
||||||
configFile = FileUtils.fileOrCopiedFromResource(new File(configDir, "config.yml"), "config.yml",
|
configFile = FileUtils.fileOrCopiedFromResource(new File(configDir, "config.yml"), "config.yml",
|
||||||
(file) -> file.replaceAll("generateduuid", UUID.randomUUID().toString()), this);
|
(file) -> file.replaceAll("generateduuid", UUID.randomUUID().toString()), this);
|
||||||
|
|
||||||
|
this.geyserConfig = FileUtils.loadConfig(configFile, GeyserSpongeConfiguration.class);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
logger.error(GeyserLocale.getLocaleStringLog("geyser.config.failed"));
|
logger.error(GeyserLocale.getLocaleStringLog("geyser.config.failed"));
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
|
onDisable();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
|
||||||
this.geyserConfig = FileUtils.loadConfig(configFile, GeyserSpongeConfiguration.class);
|
this.geyserLogger = new GeyserSpongeLogger(logger, geyserConfig.isDebugMode());
|
||||||
} catch (IOException ex) {
|
|
||||||
logger.warn(GeyserLocale.getLocaleStringLog("geyser.config.failed"));
|
this.geyser = GeyserImpl.load(PlatformType.SPONGE, this);
|
||||||
ex.printStackTrace();
|
|
||||||
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Sponge.getServer().getBoundAddress().isPresent()) {
|
if (Sponge.server().boundAddress().isPresent()) {
|
||||||
InetSocketAddress javaAddr = Sponge.getServer().getBoundAddress().get();
|
InetSocketAddress javaAddr = Sponge.server().boundAddress().get();
|
||||||
|
|
||||||
// Don't change the ip if its listening on all interfaces
|
|
||||||
// By default this should be 127.0.0.1 but may need to be changed in some circumstances
|
// By default this should be 127.0.0.1 but may need to be changed in some circumstances
|
||||||
if (this.geyserConfig.getRemote().address().equalsIgnoreCase("auto")) {
|
if (this.geyserConfig.getRemote().address().equalsIgnoreCase("auto")) {
|
||||||
this.geyserConfig.setAutoconfiguredRemote(true);
|
this.geyserConfig.setAutoconfiguredRemote(true);
|
||||||
|
// Don't change the ip if its listening on all interfaces
|
||||||
|
if (!javaAddr.getHostString().equals("0.0.0.0") && !javaAddr.getHostString().equals("")) {
|
||||||
|
this.geyserConfig.getRemote().setAddress(javaAddr.getHostString());
|
||||||
|
}
|
||||||
geyserConfig.getRemote().setPort(javaAddr.getPort());
|
geyserConfig.getRemote().setPort(javaAddr.getPort());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -109,25 +197,18 @@ public class GeyserSpongePlugin implements GeyserBootstrap {
|
|||||||
geyserConfig.getBedrock().setPort(geyserConfig.getRemote().port());
|
geyserConfig.getBedrock().setPort(geyserConfig.getRemote().port());
|
||||||
}
|
}
|
||||||
|
|
||||||
this.geyserLogger = new GeyserSpongeLogger(logger, geyserConfig.isDebugMode());
|
GeyserImpl.start();
|
||||||
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
|
|
||||||
this.geyser = GeyserImpl.start(PlatformType.SPONGE, this);
|
|
||||||
|
|
||||||
if (geyserConfig.isLegacyPingPassthrough()) {
|
if (geyserConfig.isLegacyPingPassthrough()) {
|
||||||
this.geyserSpongePingPassthrough = GeyserLegacyPingPassthrough.init(geyser);
|
this.geyserSpongePingPassthrough = GeyserLegacyPingPassthrough.init(geyser);
|
||||||
} else {
|
} else {
|
||||||
this.geyserSpongePingPassthrough = new GeyserSpongePingPassthrough();
|
this.geyserSpongePingPassthrough = new GeyserSpongePingPassthrough();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.geyserCommandManager = new GeyserSpongeCommandManager(Sponge.getCommandManager(), geyser);
|
|
||||||
this.geyserCommandManager.init();
|
|
||||||
Sponge.getCommandManager().register(this, new GeyserSpongeCommandExecutor(geyser, geyserCommandManager.getCommands()), "geyser");
|
|
||||||
Sponge.getCommandManager().register(this, new GeyserSpongeCommandExecutor(geyser, geyserCommandManager.commands()), "geyserext");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Listener
|
||||||
public void onDisable() {
|
public void onEngineStopping(StoppingEngineEvent<Server> event) {
|
||||||
geyser.shutdown();
|
onDisable();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -142,7 +223,7 @@ public class GeyserSpongePlugin implements GeyserBootstrap {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GeyserCommandManager getGeyserCommandManager() {
|
public GeyserCommandManager getGeyserCommandManager() {
|
||||||
return this.geyserCommandManager;
|
return geyserCommandManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -152,17 +233,7 @@ public class GeyserSpongePlugin implements GeyserBootstrap {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Path getConfigFolder() {
|
public Path getConfigFolder() {
|
||||||
return configDir.toPath();
|
return configPath;
|
||||||
}
|
|
||||||
|
|
||||||
@Listener
|
|
||||||
public void onServerStart(GameStartedServerEvent event) {
|
|
||||||
onEnable();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Listener
|
|
||||||
public void onServerStop(GameStoppedEvent event) {
|
|
||||||
onDisable();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -172,6 +243,6 @@ public class GeyserSpongePlugin implements GeyserBootstrap {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getMinecraftServerVersion() {
|
public String getMinecraftServerVersion() {
|
||||||
return Sponge.getPlatform().getMinecraftVersion().getName();
|
return Sponge.platform().minecraftVersion().name();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,81 +25,88 @@
|
|||||||
|
|
||||||
package org.geysermc.geyser.platform.sponge.command;
|
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.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;
|
||||||
import org.geysermc.geyser.command.GeyserCommandExecutor;
|
import org.geysermc.geyser.command.GeyserCommandExecutor;
|
||||||
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.ChatColor;
|
|
||||||
import org.geysermc.geyser.text.GeyserLocale;
|
import org.geysermc.geyser.text.GeyserLocale;
|
||||||
import org.spongepowered.api.command.CommandCallable;
|
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.CommandResult;
|
||||||
import org.spongepowered.api.command.CommandSource;
|
import org.spongepowered.api.command.parameter.ArgumentReader;
|
||||||
import org.spongepowered.api.text.Text;
|
|
||||||
import org.spongepowered.api.world.Location;
|
|
||||||
import org.spongepowered.api.world.World;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class GeyserSpongeCommandExecutor extends GeyserCommandExecutor implements CommandCallable {
|
public class GeyserSpongeCommandExecutor extends GeyserCommandExecutor implements org.spongepowered.api.command.Command.Raw {
|
||||||
|
|
||||||
public GeyserSpongeCommandExecutor(GeyserImpl geyser, Map<String, Command> commands) {
|
public GeyserSpongeCommandExecutor(GeyserImpl geyser, Map<String, Command> commands) {
|
||||||
super(geyser, commands);
|
super(geyser, commands);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CommandResult process(CommandSource source, String arguments) {
|
public CommandResult process(CommandCause cause, ArgumentReader.Mutable arguments) {
|
||||||
GeyserCommandSource commandSender = new SpongeCommandSource(source);
|
GeyserCommandSource commandSource = new SpongeCommandSource(cause);
|
||||||
GeyserSession session = getGeyserSession(commandSender);
|
GeyserSession session = getGeyserSession(commandSource);
|
||||||
|
|
||||||
String[] args = arguments.split(" ");
|
String[] args = arguments.input().split(" ");
|
||||||
if (args.length > 0) {
|
// 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]);
|
GeyserCommand command = getCommand(args[0]);
|
||||||
if (command != null) {
|
if (command != null) {
|
||||||
if (!source.hasPermission(command.permission())) {
|
if (!cause.hasPermission(command.permission())) {
|
||||||
// Not ideal to use log here but we dont get a session
|
cause.audience().sendMessage(Component.text(GeyserLocale.getLocaleStringLog("geyser.bootstrap.command.permission_fail")).color(NamedTextColor.RED));
|
||||||
source.sendMessage(Text.of(ChatColor.RED + GeyserLocale.getLocaleStringLog("geyser.bootstrap.command.permission_fail")));
|
|
||||||
return CommandResult.success();
|
return CommandResult.success();
|
||||||
}
|
}
|
||||||
if (command.isBedrockOnly() && session == null) {
|
if (command.isBedrockOnly() && session == null) {
|
||||||
source.sendMessage(Text.of(ChatColor.RED + GeyserLocale.getLocaleStringLog("geyser.bootstrap.command.bedrock_only")));
|
cause.audience().sendMessage(Component.text(GeyserLocale.getLocaleStringLog("geyser.bootstrap.command.bedrock_only")).color(NamedTextColor.RED));
|
||||||
return CommandResult.success();
|
return CommandResult.success();
|
||||||
}
|
}
|
||||||
getCommand(args[0]).execute(session, commandSender, args.length > 1 ? Arrays.copyOfRange(args, 1, args.length) : new String[0]);
|
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 {
|
} else {
|
||||||
getCommand("help").execute(session, commandSender, new String[0]);
|
getCommand("help").execute(session, commandSource, new String[0]);
|
||||||
}
|
}
|
||||||
return CommandResult.success();
|
return CommandResult.success();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> getSuggestions(CommandSource source, String arguments, @Nullable Location<World> targetPosition) {
|
public List<CommandCompletion> complete(CommandCause cause, ArgumentReader.Mutable arguments) {
|
||||||
if (arguments.split(" ").length == 1) {
|
if (arguments.input().split(" ").length == 1) {
|
||||||
return tabComplete(new SpongeCommandSource(source));
|
return tabComplete(new SpongeCommandSource(cause)).stream().map(CommandCompletion::of).collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean testPermission(CommandSource source) {
|
public boolean canExecute(CommandCause cause) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<Text> getShortDescription(CommandSource source) {
|
public Optional<Component> shortDescription(CommandCause cause) {
|
||||||
return Optional.of(Text.of("The main command for Geyser."));
|
return Optional.of(Component.text("The main command for Geyser."));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<Text> getHelp(CommandSource source) {
|
public Optional<Component> extendedDescription(CommandCause cause) {
|
||||||
return Optional.of(Text.of("/geyser help"));
|
return shortDescription(cause);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Text getUsage(CommandSource source) {
|
public Optional<Component> help(@NotNull CommandCause cause) {
|
||||||
return Text.of("/geyser help");
|
return Optional.of(Component.text("/geyser help"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Component usage(CommandCause cause) {
|
||||||
|
return Component.text("/geyser help");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,25 +25,37 @@
|
|||||||
|
|
||||||
package org.geysermc.geyser.platform.sponge.command;
|
package org.geysermc.geyser.platform.sponge.command;
|
||||||
|
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
import org.geysermc.geyser.GeyserImpl;
|
import org.geysermc.geyser.GeyserImpl;
|
||||||
import org.geysermc.geyser.command.GeyserCommandManager;
|
import org.geysermc.geyser.command.GeyserCommandManager;
|
||||||
|
import org.geysermc.geyser.translator.text.MessageTranslator;
|
||||||
import org.spongepowered.api.Sponge;
|
import org.spongepowered.api.Sponge;
|
||||||
import org.spongepowered.api.command.CommandMapping;
|
import org.spongepowered.api.command.CommandCause;
|
||||||
import org.spongepowered.api.text.Text;
|
import org.spongepowered.api.command.manager.CommandMapping;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
public class GeyserSpongeCommandManager extends GeyserCommandManager {
|
public class GeyserSpongeCommandManager extends GeyserCommandManager {
|
||||||
private final org.spongepowered.api.command.CommandManager handle;
|
|
||||||
|
|
||||||
public GeyserSpongeCommandManager(org.spongepowered.api.command.CommandManager handle, GeyserImpl geyser) {
|
public GeyserSpongeCommandManager(GeyserImpl geyser) {
|
||||||
super(geyser);
|
super(geyser);
|
||||||
|
|
||||||
this.handle = handle;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String description(String command) {
|
public String description(String command) {
|
||||||
return handle.get(command).map(CommandMapping::getCallable)
|
if (!Sponge.isServerAvailable()) {
|
||||||
.map(callable -> callable.getShortDescription(Sponge.getServer().getConsole()).orElse(Text.EMPTY))
|
return "";
|
||||||
.orElse(Text.EMPTY).toPlain();
|
}
|
||||||
|
|
||||||
|
// Note: The command manager may be replaced at any point during the game lifecycle
|
||||||
|
return Sponge.server().commandManager().commandMapping(command)
|
||||||
|
.map(this::description)
|
||||||
|
.map(Optional::get)
|
||||||
|
.map(MessageTranslator::convertMessage)
|
||||||
|
.orElse("");
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<Component> description(CommandMapping mapping) {
|
||||||
|
return mapping.registrar().shortDescription(CommandCause.create(), mapping);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,29 +26,30 @@
|
|||||||
package org.geysermc.geyser.platform.sponge.command;
|
package org.geysermc.geyser.platform.sponge.command;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
|
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||||
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
import org.geysermc.geyser.command.GeyserCommandSource;
|
import org.geysermc.geyser.command.GeyserCommandSource;
|
||||||
import org.spongepowered.api.command.CommandSource;
|
import org.spongepowered.api.command.CommandCause;
|
||||||
import org.spongepowered.api.command.source.ConsoleSource;
|
import org.spongepowered.api.entity.living.player.server.ServerPlayer;
|
||||||
import org.spongepowered.api.text.Text;
|
|
||||||
|
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public class SpongeCommandSource implements GeyserCommandSource {
|
public class SpongeCommandSource implements GeyserCommandSource {
|
||||||
|
|
||||||
private CommandSource handle;
|
private final CommandCause handle;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String name() {
|
public String name() {
|
||||||
return handle.getName();
|
return handle.friendlyIdentifier().orElse(handle.identifier());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void sendMessage(String message) {
|
public void sendMessage(@NonNull String message) {
|
||||||
handle.sendMessage(Text.of(message));
|
handle.audience().sendMessage(LegacyComponentSerializer.legacySection().deserialize(message));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isConsole() {
|
public boolean isConsole() {
|
||||||
return handle instanceof ConsoleSource;
|
return !(handle.cause().root() instanceof ServerPlayer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
30
bootstrap/sponge/src/main/resources/META-INF/sponge_plugins.json
Normale Datei
30
bootstrap/sponge/src/main/resources/META-INF/sponge_plugins.json
Normale Datei
@ -0,0 +1,30 @@
|
|||||||
|
{
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
6
bootstrap/sponge/src/main/resources/pack.mcmeta
Normale Datei
6
bootstrap/sponge/src/main/resources/pack.mcmeta
Normale Datei
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"pack": {
|
||||||
|
"description": "Geyser for Sponge",
|
||||||
|
"pack_format": 6
|
||||||
|
}
|
||||||
|
}
|
@ -6,20 +6,16 @@ val jlineVersion = "3.21.0"
|
|||||||
dependencies {
|
dependencies {
|
||||||
api(projects.core)
|
api(projects.core)
|
||||||
|
|
||||||
implementation("net.minecrell", "terminalconsoleappender", terminalConsoleVersion) {
|
implementation(libs.terminalconsoleappender) {
|
||||||
exclude("org.apache.logging.log4j", "log4j-core")
|
exclude("org.apache.logging.log4j", "log4j-core")
|
||||||
exclude("org.jline", "jline-reader")
|
exclude("org.jline", "jline-reader")
|
||||||
exclude("org.jline", "jline-terminal")
|
exclude("org.jline", "jline-terminal")
|
||||||
exclude("org.jline", "jline-terminal-jna")
|
exclude("org.jline", "jline-terminal-jna")
|
||||||
}
|
}
|
||||||
|
|
||||||
implementation("org.jline", "jline-terminal", jlineVersion)
|
implementation(libs.bundles.jline)
|
||||||
implementation("org.jline", "jline-terminal-jna", jlineVersion)
|
|
||||||
implementation("org.jline", "jline-reader", jlineVersion)
|
|
||||||
|
|
||||||
implementation("org.apache.logging.log4j", "log4j-api", Versions.log4jVersion)
|
implementation(libs.bundles.log4j)
|
||||||
implementation("org.apache.logging.log4j", "log4j-core", Versions.log4jVersion)
|
|
||||||
implementation("org.apache.logging.log4j", "log4j-slf4j18-impl", Versions.log4jVersion)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
application {
|
application {
|
||||||
@ -27,7 +23,7 @@ application {
|
|||||||
}
|
}
|
||||||
|
|
||||||
tasks.withType<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar> {
|
tasks.withType<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar> {
|
||||||
archiveBaseName.set("Geyser")
|
archiveBaseName.set("Geyser-Standalone")
|
||||||
|
|
||||||
transform(Log4j2PluginsCacheFileTransformer())
|
transform(Log4j2PluginsCacheFileTransformer())
|
||||||
}
|
}
|
@ -47,10 +47,10 @@ import org.geysermc.geyser.configuration.GeyserJacksonConfiguration;
|
|||||||
import org.geysermc.geyser.dump.BootstrapDumpInfo;
|
import org.geysermc.geyser.dump.BootstrapDumpInfo;
|
||||||
import org.geysermc.geyser.ping.GeyserLegacyPingPassthrough;
|
import org.geysermc.geyser.ping.GeyserLegacyPingPassthrough;
|
||||||
import org.geysermc.geyser.ping.IGeyserPingPassthrough;
|
import org.geysermc.geyser.ping.IGeyserPingPassthrough;
|
||||||
import org.geysermc.geyser.platform.standalone.command.GeyserStandaloneCommandManager;
|
|
||||||
import org.geysermc.geyser.platform.standalone.gui.GeyserStandaloneGUI;
|
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 java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -63,7 +63,7 @@ import java.util.stream.Collectors;
|
|||||||
|
|
||||||
public class GeyserStandaloneBootstrap implements GeyserBootstrap {
|
public class GeyserStandaloneBootstrap implements GeyserBootstrap {
|
||||||
|
|
||||||
private GeyserStandaloneCommandManager geyserCommandManager;
|
private GeyserCommandManager geyserCommandManager;
|
||||||
private GeyserStandaloneConfiguration geyserConfig;
|
private GeyserStandaloneConfiguration geyserConfig;
|
||||||
private GeyserStandaloneLogger geyserLogger;
|
private GeyserStandaloneLogger geyserLogger;
|
||||||
private IGeyserPingPassthrough geyserPingPassthrough;
|
private IGeyserPingPassthrough geyserPingPassthrough;
|
||||||
@ -188,7 +188,7 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap {
|
|||||||
|
|
||||||
geyserLogger = new GeyserStandaloneLogger();
|
geyserLogger = new GeyserStandaloneLogger();
|
||||||
|
|
||||||
LoopbackUtil.checkLoopback(geyserLogger);
|
LoopbackUtil.checkAndApplyLoopback(geyserLogger);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
File configFile = FileUtils.fileOrCopiedFromResource(new File(configFilename), "config.yml",
|
File configFile = FileUtils.fileOrCopiedFromResource(new File(configFilename), "config.yml",
|
||||||
@ -216,8 +216,10 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap {
|
|||||||
// Allow libraries like Protocol to have their debug information passthrough
|
// Allow libraries like Protocol to have their debug information passthrough
|
||||||
logger.get().setLevel(geyserConfig.isDebugMode() ? Level.DEBUG : Level.INFO);
|
logger.get().setLevel(geyserConfig.isDebugMode() ? Level.DEBUG : Level.INFO);
|
||||||
|
|
||||||
geyser = GeyserImpl.start(PlatformType.STANDALONE, this);
|
geyser = GeyserImpl.load(PlatformType.STANDALONE, this);
|
||||||
geyserCommandManager = new GeyserStandaloneCommandManager(geyser);
|
GeyserImpl.start();
|
||||||
|
|
||||||
|
geyserCommandManager = new GeyserCommandManager(geyser);
|
||||||
geyserCommandManager.init();
|
geyserCommandManager.init();
|
||||||
|
|
||||||
if (gui != null) {
|
if (gui != null) {
|
||||||
|
@ -95,24 +95,4 @@ public class GeyserStandaloneLogger extends SimpleTerminalConsole implements Gey
|
|||||||
public boolean isDebug() {
|
public boolean isDebug() {
|
||||||
return log.isDebugEnabled();
|
return log.isDebugEnabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String name() {
|
|
||||||
return "CONSOLE";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void sendMessage(String message) {
|
|
||||||
info(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isConsole() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean hasPermission(String permission) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -28,8 +28,8 @@ 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.api.command.Command;
|
||||||
import org.geysermc.geyser.command.GeyserCommand;
|
import org.geysermc.geyser.command.GeyserCommand;
|
||||||
|
import org.geysermc.geyser.command.GeyserCommandManager;
|
||||||
import org.geysermc.geyser.platform.standalone.GeyserStandaloneLogger;
|
import org.geysermc.geyser.platform.standalone.GeyserStandaloneLogger;
|
||||||
import org.geysermc.geyser.platform.standalone.command.GeyserStandaloneCommandManager;
|
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
import org.geysermc.geyser.text.GeyserLocale;
|
import org.geysermc.geyser.text.GeyserLocale;
|
||||||
|
|
||||||
@ -256,7 +256,7 @@ public class GeyserStandaloneGUI {
|
|||||||
* @param geyserStandaloneLogger The current logger
|
* @param geyserStandaloneLogger The current logger
|
||||||
* @param geyserCommandManager The commands manager
|
* @param geyserCommandManager The commands manager
|
||||||
*/
|
*/
|
||||||
public void setupInterface(GeyserStandaloneLogger geyserStandaloneLogger, GeyserStandaloneCommandManager geyserCommandManager) {
|
public void setupInterface(GeyserStandaloneLogger geyserStandaloneLogger, GeyserCommandManager geyserCommandManager) {
|
||||||
commandsMenu.removeAll();
|
commandsMenu.removeAll();
|
||||||
optionsMenu.removeAll();
|
optionsMenu.removeAll();
|
||||||
|
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
val velocityVersion = "3.0.0"
|
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
annotationProcessor("com.velocitypowered", "velocity-api", velocityVersion)
|
annotationProcessor(libs.velocity.api)
|
||||||
api(projects.core)
|
api(projects.core)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,7 +32,7 @@ exclude("net.kyori:adventure-text-serializer-legacy:*")
|
|||||||
exclude("net.kyori:adventure-nbt:*")
|
exclude("net.kyori:adventure-nbt:*")
|
||||||
|
|
||||||
// These dependencies are already present on the platform
|
// These dependencies are already present on the platform
|
||||||
provided("com.velocitypowered", "velocity-api", velocityVersion)
|
provided(libs.velocity.api)
|
||||||
|
|
||||||
application {
|
application {
|
||||||
mainClass.set("org.geysermc.geyser.platform.velocity.GeyserVelocityMain")
|
mainClass.set("org.geysermc.geyser.platform.velocity.GeyserVelocityMain")
|
||||||
|
@ -41,6 +41,8 @@ public class GeyserVelocityDumpInfo extends BootstrapDumpInfo {
|
|||||||
private final String platformVersion;
|
private final String platformVersion;
|
||||||
private final String platformVendor;
|
private final String platformVendor;
|
||||||
private final boolean onlineMode;
|
private final boolean onlineMode;
|
||||||
|
|
||||||
|
@AsteriskSerializer.Asterisk(isIp = true)
|
||||||
private final String serverIP;
|
private final String serverIP;
|
||||||
private final int serverPort;
|
private final int serverPort;
|
||||||
private final List<PluginInfo> plugins;
|
private final List<PluginInfo> plugins;
|
||||||
@ -51,11 +53,7 @@ public class GeyserVelocityDumpInfo extends BootstrapDumpInfo {
|
|||||||
this.platformVersion = proxy.getVersion().getVersion();
|
this.platformVersion = proxy.getVersion().getVersion();
|
||||||
this.platformVendor = proxy.getVersion().getVendor();
|
this.platformVendor = proxy.getVersion().getVendor();
|
||||||
this.onlineMode = proxy.getConfiguration().isOnlineMode();
|
this.onlineMode = proxy.getConfiguration().isOnlineMode();
|
||||||
if (AsteriskSerializer.showSensitive || (proxy.getBoundAddress().getHostString().equals("") || proxy.getBoundAddress().getHostString().equals("0.0.0.0"))) {
|
this.serverIP = proxy.getBoundAddress().getHostString();
|
||||||
this.serverIP = proxy.getBoundAddress().getHostString();
|
|
||||||
} else {
|
|
||||||
this.serverIP = "***";
|
|
||||||
}
|
|
||||||
this.serverPort = proxy.getBoundAddress().getPort();
|
this.serverPort = proxy.getBoundAddress().getPort();
|
||||||
this.plugins = new ArrayList<>();
|
this.plugins = new ArrayList<>();
|
||||||
|
|
||||||
|
@ -35,9 +35,12 @@ import com.velocitypowered.api.network.ListenerType;
|
|||||||
import com.velocitypowered.api.plugin.Plugin;
|
import com.velocitypowered.api.plugin.Plugin;
|
||||||
import com.velocitypowered.api.proxy.ProxyServer;
|
import com.velocitypowered.api.proxy.ProxyServer;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
import net.kyori.adventure.util.Codec;
|
||||||
import org.geysermc.common.PlatformType;
|
import org.geysermc.common.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.extension.Extension;
|
||||||
import org.geysermc.geyser.api.network.AuthType;
|
import org.geysermc.geyser.api.network.AuthType;
|
||||||
import org.geysermc.geyser.command.GeyserCommandManager;
|
import org.geysermc.geyser.command.GeyserCommandManager;
|
||||||
import org.geysermc.geyser.configuration.GeyserConfiguration;
|
import org.geysermc.geyser.configuration.GeyserConfiguration;
|
||||||
@ -45,7 +48,6 @@ import org.geysermc.geyser.dump.BootstrapDumpInfo;
|
|||||||
import org.geysermc.geyser.ping.GeyserLegacyPingPassthrough;
|
import org.geysermc.geyser.ping.GeyserLegacyPingPassthrough;
|
||||||
import org.geysermc.geyser.ping.IGeyserPingPassthrough;
|
import org.geysermc.geyser.ping.IGeyserPingPassthrough;
|
||||||
import org.geysermc.geyser.platform.velocity.command.GeyserVelocityCommandExecutor;
|
import org.geysermc.geyser.platform.velocity.command.GeyserVelocityCommandExecutor;
|
||||||
import org.geysermc.geyser.platform.velocity.command.GeyserVelocityCommandManager;
|
|
||||||
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.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
@ -57,6 +59,7 @@ import java.net.InetSocketAddress;
|
|||||||
import java.net.SocketAddress;
|
import java.net.SocketAddress;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@Plugin(id = "geyser", name = GeyserImpl.NAME + "-Velocity", version = GeyserImpl.VERSION, url = "https://geysermc.org", authors = "GeyserMC")
|
@Plugin(id = "geyser", name = GeyserImpl.NAME + "-Velocity", version = GeyserImpl.VERSION, url = "https://geysermc.org", authors = "GeyserMC")
|
||||||
@ -71,7 +74,7 @@ public class GeyserVelocityPlugin implements GeyserBootstrap {
|
|||||||
@Inject
|
@Inject
|
||||||
private CommandManager commandManager;
|
private CommandManager commandManager;
|
||||||
|
|
||||||
private GeyserVelocityCommandManager geyserCommandManager;
|
private GeyserCommandManager geyserCommandManager;
|
||||||
private GeyserVelocityConfiguration geyserConfig;
|
private GeyserVelocityConfiguration geyserConfig;
|
||||||
private GeyserVelocityInjector geyserInjector;
|
private GeyserVelocityInjector geyserInjector;
|
||||||
private GeyserVelocityLogger geyserLogger;
|
private GeyserVelocityLogger geyserLogger;
|
||||||
@ -84,6 +87,15 @@ public class GeyserVelocityPlugin implements GeyserBootstrap {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onEnable() {
|
public void onEnable() {
|
||||||
|
try {
|
||||||
|
Codec.class.getMethod("codec", Codec.Decoder.class, Codec.Encoder.class);
|
||||||
|
} catch (NoSuchMethodException e) {
|
||||||
|
// velocitypowered.com has a build that is very outdated
|
||||||
|
logger.error("Please download Velocity from https://papermc.io/downloads#Velocity - the 'stable' Velocity version " +
|
||||||
|
"that has likely been downloaded is very outdated and does not support 1.19.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
GeyserLocale.init(this);
|
GeyserLocale.init(this);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -118,6 +130,8 @@ public class GeyserVelocityPlugin implements GeyserBootstrap {
|
|||||||
this.geyserLogger = new GeyserVelocityLogger(logger, geyserConfig.isDebugMode());
|
this.geyserLogger = new GeyserVelocityLogger(logger, geyserConfig.isDebugMode());
|
||||||
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
|
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
|
||||||
|
|
||||||
|
this.geyser = GeyserImpl.load(PlatformType.VELOCITY, this);
|
||||||
|
|
||||||
// Remove this in like a year
|
// Remove this in like a year
|
||||||
try {
|
try {
|
||||||
// Should only exist on 1.0
|
// Should only exist on 1.0
|
||||||
@ -140,21 +154,34 @@ public class GeyserVelocityPlugin implements GeyserBootstrap {
|
|||||||
|
|
||||||
geyserConfig.loadFloodgate(this, proxyServer, configFolder.toFile());
|
geyserConfig.loadFloodgate(this, proxyServer, configFolder.toFile());
|
||||||
|
|
||||||
this.geyser = GeyserImpl.start(PlatformType.VELOCITY, this);
|
}
|
||||||
|
|
||||||
|
private void postStartup() {
|
||||||
|
GeyserImpl.start();
|
||||||
|
|
||||||
this.geyserInjector = new GeyserVelocityInjector(proxyServer);
|
this.geyserInjector = new GeyserVelocityInjector(proxyServer);
|
||||||
// Will be initialized after the proxy has been bound
|
// Will be initialized after the proxy has been bound
|
||||||
|
|
||||||
this.geyserCommandManager = new GeyserVelocityCommandManager(geyser);
|
this.geyserCommandManager = new GeyserCommandManager(geyser);
|
||||||
this.geyserCommandManager.init();
|
this.geyserCommandManager.init();
|
||||||
|
|
||||||
this.commandManager.register("geyser", new GeyserVelocityCommandExecutor(geyser, geyserCommandManager.getCommands()));
|
this.commandManager.register("geyser", new GeyserVelocityCommandExecutor(geyser, geyserCommandManager.getCommands()));
|
||||||
this.commandManager.register("geyserext", new GeyserVelocityCommandExecutor(geyser, geyserCommandManager.commands()));
|
for (Map.Entry<Extension, Map<String, Command>> entry : this.geyserCommandManager.extensionCommands().entrySet()) {
|
||||||
|
Map<String, Command> commands = entry.getValue();
|
||||||
|
if (commands.isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.commandManager.register(entry.getKey().description().id(), new GeyserVelocityCommandExecutor(this.geyser, commands));
|
||||||
|
}
|
||||||
|
|
||||||
if (geyserConfig.isLegacyPingPassthrough()) {
|
if (geyserConfig.isLegacyPingPassthrough()) {
|
||||||
this.geyserPingPassthrough = GeyserLegacyPingPassthrough.init(geyser);
|
this.geyserPingPassthrough = GeyserLegacyPingPassthrough.init(geyser);
|
||||||
} else {
|
} else {
|
||||||
this.geyserPingPassthrough = new GeyserVelocityPingPassthrough(proxyServer);
|
this.geyserPingPassthrough = new GeyserVelocityPingPassthrough(proxyServer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
proxyServer.getEventManager().register(this, new GeyserVelocityUpdateListener());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -199,9 +226,14 @@ public class GeyserVelocityPlugin implements GeyserBootstrap {
|
|||||||
|
|
||||||
@Subscribe
|
@Subscribe
|
||||||
public void onProxyBound(ListenerBoundEvent event) {
|
public void onProxyBound(ListenerBoundEvent event) {
|
||||||
if (event.getListenerType() == ListenerType.MINECRAFT && geyserInjector != null) {
|
if (event.getListenerType() == ListenerType.MINECRAFT) {
|
||||||
// After this bound, we know that the channel initializer cannot change without it being ineffective for Velocity, too
|
// Once listener is bound, do our startup process
|
||||||
geyserInjector.initializeLocalChannel(this);
|
this.postStartup();
|
||||||
|
|
||||||
|
if (geyserInjector != null) {
|
||||||
|
// After this bound, we know that the channel initializer cannot change without it being ineffective for Velocity, too
|
||||||
|
geyserInjector.initializeLocalChannel(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* 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.velocity;
|
||||||
|
|
||||||
|
import com.velocitypowered.api.event.Subscribe;
|
||||||
|
import com.velocitypowered.api.event.connection.PostLoginEvent;
|
||||||
|
import com.velocitypowered.api.proxy.Player;
|
||||||
|
import org.geysermc.geyser.Constants;
|
||||||
|
import org.geysermc.geyser.GeyserImpl;
|
||||||
|
import org.geysermc.geyser.platform.velocity.command.VelocityCommandSource;
|
||||||
|
import org.geysermc.geyser.util.VersionCheckUtils;
|
||||||
|
|
||||||
|
public final class GeyserVelocityUpdateListener {
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
public void onPlayerJoin(PostLoginEvent event) {
|
||||||
|
if (GeyserImpl.getInstance().getConfig().isNotifyOnNewBedrockUpdate()) {
|
||||||
|
final Player player = event.getPlayer();
|
||||||
|
if (player.hasPermission(Constants.UPDATE_PERMISSION)) {
|
||||||
|
VersionCheckUtils.checkForGeyserUpdate(() -> new VelocityCommandSource(player));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -63,6 +63,9 @@ public class GeyserVelocityCommandExecutor extends GeyserCommandExecutor impleme
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
command.execute(session, sender, invocation.arguments().length > 1 ? Arrays.copyOfRange(invocation.arguments(), 1, invocation.arguments().length) : new String[0]);
|
command.execute(session, sender, invocation.arguments().length > 1 ? Arrays.copyOfRange(invocation.arguments(), 1, invocation.arguments().length) : new String[0]);
|
||||||
|
} else {
|
||||||
|
String message = GeyserLocale.getPlayerLocaleString("geyser.bootstrap.command.not_found", sender.locale());
|
||||||
|
sender.sendMessage(ChatColor.RED + message);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
getCommand("help").execute(session, sender, new String[0]);
|
getCommand("help").execute(session, sender, new String[0]);
|
||||||
|
@ -28,6 +28,7 @@ package org.geysermc.geyser.platform.velocity.command;
|
|||||||
import com.velocitypowered.api.command.CommandSource;
|
import com.velocitypowered.api.command.CommandSource;
|
||||||
import com.velocitypowered.api.proxy.ConsoleCommandSource;
|
import com.velocitypowered.api.proxy.ConsoleCommandSource;
|
||||||
import com.velocitypowered.api.proxy.Player;
|
import com.velocitypowered.api.proxy.Player;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||||
import org.geysermc.geyser.command.GeyserCommandSource;
|
import org.geysermc.geyser.command.GeyserCommandSource;
|
||||||
import org.geysermc.geyser.text.GeyserLocale;
|
import org.geysermc.geyser.text.GeyserLocale;
|
||||||
@ -59,6 +60,12 @@ public class VelocityCommandSource implements GeyserCommandSource {
|
|||||||
handle.sendMessage(LegacyComponentSerializer.legacy('§').deserialize(message));
|
handle.sendMessage(LegacyComponentSerializer.legacy('§').deserialize(message));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendMessage(Component message) {
|
||||||
|
// Be careful that we don't shade in Adventure!!
|
||||||
|
handle.sendMessage(message);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isConsole() {
|
public boolean isConsole() {
|
||||||
return handle instanceof ConsoleCommandSource;
|
return handle instanceof ConsoleCommandSource;
|
||||||
|
@ -6,16 +6,21 @@ plugins {
|
|||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
gradlePluginPortal()
|
gradlePluginPortal()
|
||||||
|
maven("https://repo.opencollab.dev/maven-snapshots")
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("net.kyori", "indra-common", "2.0.6")
|
implementation("net.kyori", "indra-common", "2.0.6")
|
||||||
implementation("org.jfrog.buildinfo", "build-info-extractor-gradle", "4.26.1")
|
implementation("org.jfrog.buildinfo", "build-info-extractor-gradle", "4.26.1")
|
||||||
implementation("gradle.plugin.com.github.johnrengelman", "shadow", "7.1.1")
|
implementation("com.github.johnrengelman", "shadow", "7.1.3-SNAPSHOT")
|
||||||
|
|
||||||
|
// Within the gradle plugin classpath, there is a version conflict between loom and some other
|
||||||
|
// plugin for databind. This fixes it: minimum 2.13.2 is required by loom.
|
||||||
|
implementation("com.fasterxml.jackson.core:jackson-databind:2.14.0")
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.withType<KotlinCompile> {
|
tasks.withType<KotlinCompile> {
|
||||||
kotlinOptions {
|
kotlinOptions {
|
||||||
jvmTarget = "16"
|
jvmTarget = "16"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,46 +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
|
|
||||||
*/
|
|
||||||
|
|
||||||
object Versions {
|
|
||||||
const val jacksonVersion = "2.13.2"
|
|
||||||
const val fastutilVersion = "8.5.2"
|
|
||||||
const val nettyVersion = "4.1.66.Final"
|
|
||||||
const val guavaVersion = "29.0-jre"
|
|
||||||
const val nbtVersion = "2.1.0"
|
|
||||||
const val websocketVersion = "1.5.1"
|
|
||||||
const val protocolVersion = "a78a64b"
|
|
||||||
// Not pinned to specific version due to possible gradle bug
|
|
||||||
// See comment in settings.gradle.kts
|
|
||||||
const val raknetVersion = "1.6.28-SNAPSHOT"
|
|
||||||
const val mcauthlibVersion = "d9d773e"
|
|
||||||
const val mcprotocollibversion = "54fc9f0"
|
|
||||||
const val packetlibVersion = "3.0"
|
|
||||||
const val adventureVersion = "4.9.3"
|
|
||||||
const val eventVersion = "3.0.0"
|
|
||||||
const val junitVersion = "4.13.1"
|
|
||||||
const val checkerQualVersion = "3.19.0"
|
|
||||||
const val cumulusVersion = "1.1"
|
|
||||||
const val log4jVersion = "2.17.1"
|
|
||||||
}
|
|
@ -25,7 +25,9 @@
|
|||||||
|
|
||||||
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
|
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
|
||||||
import org.gradle.api.Project
|
import org.gradle.api.Project
|
||||||
|
import org.gradle.api.artifacts.MinimalExternalModuleDependency
|
||||||
import org.gradle.api.artifacts.ProjectDependency
|
import org.gradle.api.artifacts.ProjectDependency
|
||||||
|
import org.gradle.api.provider.Provider
|
||||||
import org.gradle.kotlin.dsl.named
|
import org.gradle.kotlin.dsl.named
|
||||||
|
|
||||||
fun Project.isSnapshot(): Boolean =
|
fun Project.isSnapshot(): Boolean =
|
||||||
@ -43,9 +45,11 @@ fun Project.exclude(group: String) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Project.platformRelocate(pattern: String) {
|
fun Project.platformRelocate(pattern: String, exclusion: String = "") {
|
||||||
tasks.named<ShadowJar>("shadowJar") {
|
tasks.named<ShadowJar>("shadowJar") {
|
||||||
relocate(pattern, "org.geysermc.geyser.platform.${project.name}.shaded.$pattern")
|
relocate(pattern, "org.geysermc.geyser.platform.${project.name}.shaded.$pattern") {
|
||||||
|
exclude(exclusion)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,5 +66,11 @@ fun Project.provided(pattern: String, name: String, version: String, excludedOn:
|
|||||||
fun Project.provided(dependency: ProjectDependency) =
|
fun Project.provided(dependency: ProjectDependency) =
|
||||||
provided(dependency.group!!, dependency.name, dependency.version!!)
|
provided(dependency.group!!, dependency.name, dependency.version!!)
|
||||||
|
|
||||||
|
fun Project.provided(dependency: MinimalExternalModuleDependency) =
|
||||||
|
provided(dependency.module.group, dependency.module.name, dependency.versionConstraint.requiredVersion)
|
||||||
|
|
||||||
|
fun Project.provided(provider: Provider<MinimalExternalModuleDependency>) =
|
||||||
|
provided(provider.get())
|
||||||
|
|
||||||
private fun calcExclusion(section: String, bit: Int, excludedOn: Int): String =
|
private fun calcExclusion(section: String, bit: Int, excludedOn: Int): String =
|
||||||
if (excludedOn and bit > 0) section else ""
|
if (excludedOn and bit > 0) section else ""
|
@ -4,14 +4,15 @@ plugins {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compileOnly("org.checkerframework", "checker-qual", Versions.checkerQualVersion)
|
compileOnly("org.checkerframework", "checker-qual", "3.19.0")
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks {
|
tasks {
|
||||||
processResources {
|
processResources {
|
||||||
filesMatching(listOf("plugin.yml", "bungee.yml", "velocity-plugin.json")) {
|
// Spigot, BungeeCord, Velocity, Sponge, Fabric
|
||||||
|
filesMatching(listOf("plugin.yml", "bungee.yml", "velocity-plugin.json", "META-INF/sponge_plugins.json", "fabric.mod.json")) {
|
||||||
expand(
|
expand(
|
||||||
"id" to "Geyser",
|
"id" to "geyser",
|
||||||
"name" to "Geyser",
|
"name" to "Geyser",
|
||||||
"version" to project.version,
|
"version" to project.version,
|
||||||
"description" to project.description,
|
"description" to project.description,
|
||||||
@ -30,4 +31,4 @@ java {
|
|||||||
targetCompatibility = JavaVersion.VERSION_16
|
targetCompatibility = JavaVersion.VERSION_16
|
||||||
|
|
||||||
withSourcesJar()
|
withSourcesJar()
|
||||||
}
|
}
|
||||||
|
@ -5,27 +5,29 @@ plugins {
|
|||||||
}
|
}
|
||||||
|
|
||||||
publishing {
|
publishing {
|
||||||
publications.create<MavenPublication>("mavenJava") {
|
publications {
|
||||||
groupId = project.group as String
|
create<MavenPublication>("mavenJava") {
|
||||||
artifactId = project.name
|
groupId = project.group as String
|
||||||
version = project.version as String
|
artifactId = project.name
|
||||||
|
version = project.version as String
|
||||||
|
|
||||||
artifact(tasks["shadowJar"])
|
from(components["java"])
|
||||||
artifact(tasks["sourcesJar"])
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
artifactory {
|
artifactory {
|
||||||
|
setContextUrl("https://repo.opencollab.dev/artifactory")
|
||||||
publish {
|
publish {
|
||||||
repository {
|
repository {
|
||||||
setRepoKey(if (isSnapshot()) "maven-snapshots" else "maven-releases")
|
setRepoKey(if (isSnapshot()) "maven-snapshots" else "maven-releases")
|
||||||
setMavenCompatible(true)
|
setMavenCompatible(true)
|
||||||
}
|
}
|
||||||
defaults {
|
defaults {
|
||||||
publishConfigs("archives")
|
publications("mavenJava")
|
||||||
setPublishArtifacts(true)
|
setPublishArtifacts(true)
|
||||||
setPublishPom(true)
|
setPublishPom(true)
|
||||||
setPublishIvy(false)
|
setPublishIvy(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ allprojects {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val platforms = setOf(
|
val platforms = setOf(
|
||||||
|
projects.fabric,
|
||||||
projects.bungeecord,
|
projects.bungeecord,
|
||||||
projects.spigot,
|
projects.spigot,
|
||||||
projects.sponge,
|
projects.sponge,
|
||||||
|
@ -1,3 +1,8 @@
|
|||||||
|
plugins {
|
||||||
|
id("geyser.publish-conventions")
|
||||||
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
api("org.geysermc.cumulus", "cumulus", Versions.cumulusVersion)
|
api(libs.cumulus)
|
||||||
}
|
api(libs.gson)
|
||||||
|
}
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
|
|
||||||
package org.geysermc.floodgate.pluginmessage;
|
package org.geysermc.floodgate.pluginmessage;
|
||||||
|
|
||||||
import com.google.common.base.Charsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
public final class PluginMessageChannels {
|
public final class PluginMessageChannels {
|
||||||
public static final String SKIN = "floodgate:skin";
|
public static final String SKIN = "floodgate:skin";
|
||||||
@ -35,7 +35,7 @@ public final class PluginMessageChannels {
|
|||||||
|
|
||||||
private static final byte[] FLOODGATE_REGISTER_DATA =
|
private static final byte[] FLOODGATE_REGISTER_DATA =
|
||||||
String.join("\0", SKIN, FORM, TRANSFER, PACKET)
|
String.join("\0", SKIN, FORM, TRANSFER, PACKET)
|
||||||
.getBytes(Charsets.UTF_8);
|
.getBytes(StandardCharsets.UTF_8);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the prebuilt register data as a byte array
|
* Get the prebuilt register data as a byte array
|
||||||
|
Einige Dateien werden nicht angezeigt, da zu viele Dateien in diesem Diff geändert wurden Mehr anzeigen
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren