1
0
mirror of https://github.com/GeyserMC/Floodgate.git synced 2025-12-19 14:59:20 +00:00

Added a translate method to the logger and changed the code style a bit

This commit is contained in:
Tim203
2020-10-13 20:04:20 +02:00
parent e9c4433a53
commit c4971d5bf3
78 changed files with 1644 additions and 1264 deletions

View File

@@ -1,7 +1,64 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<option name="OTHER_INDENT_OPTIONS">
<value>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="4" />
<option name="TAB_SIZE" value="2" />
</value>
</option>
<option name="INSERT_INNER_CLASS_IMPORTS" value="true" />
<option name="CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND" value="999" />
<option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="999" />
<option name="PACKAGES_TO_USE_IMPORT_ON_DEMAND">
<value />
</option>
<option name="IMPORT_LAYOUT_TABLE">
<value>
<package name="" withSubpackages="true" static="true" />
<emptyLine />
<package name="" withSubpackages="true" static="false" />
</value>
</option>
<option name="RIGHT_MARGIN" value="100" />
<option name="WRAP_WHEN_TYPING_REACHES_RIGHT_MARGIN" value="true" />
<option name="KEEP_CONTROL_STATEMENT_IN_ONE_LINE" value="false" />
<option name="KEEP_BLANK_LINES_IN_CODE" value="1" />
<option name="KEEP_BLANK_LINES_BEFORE_RBRACE" value="0" />
<option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
<option name="ALIGN_MULTILINE_FOR" value="false" />
<option name="SPACE_BEFORE_ARRAY_INITIALIZER_LBRACE" value="true" />
<option name="CALL_PARAMETERS_WRAP" value="1" />
<option name="METHOD_PARAMETERS_WRAP" value="1" />
<option name="EXTENDS_LIST_WRAP" value="1" />
<option name="THROWS_KEYWORD_WRAP" value="1" />
<option name="METHOD_CALL_CHAIN_WRAP" value="1" />
<option name="BINARY_OPERATION_WRAP" value="1" />
<option name="BINARY_OPERATION_SIGN_ON_NEXT_LINE" value="true" />
<option name="TERNARY_OPERATION_WRAP" value="1" />
<option name="TERNARY_OPERATION_SIGNS_ON_NEXT_LINE" value="true" />
<option name="FOR_STATEMENT_WRAP" value="1" />
<option name="ARRAY_INITIALIZER_WRAP" value="1" />
<option name="WRAP_COMMENTS" value="true" />
<option name="IF_BRACE_FORCE" value="3" />
<option name="DOWHILE_BRACE_FORCE" value="3" />
<option name="WHILE_BRACE_FORCE" value="3" />
<option name="FOR_BRACE_FORCE" value="3" />
<JavaCodeStyleSettings>
<option name="DO_NOT_WRAP_AFTER_SINGLE_ANNOTATION" value="true" />
<option name="INSERT_INNER_CLASS_IMPORTS" value="true" />
<option name="CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND" value="999" />
<option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="999" />
<option name="PACKAGES_TO_USE_IMPORT_ON_DEMAND">
<value />
</option>
<option name="IMPORT_LAYOUT_TABLE">
<value>
<package name="" withSubpackages="true" static="true" />
<emptyLine />
<package name="" withSubpackages="true" static="false" />
</value>
</option>
</JavaCodeStyleSettings>
<JetCodeStyleSettings>
<option name="PACKAGES_TO_USE_STAR_IMPORTS">
<value>
@@ -20,8 +77,357 @@
</value>
</option>
</JetCodeStyleSettings>
<ScalaCodeStyleSettings>
<option name="MULTILINE_STRING_CLOSING_QUOTES_ON_NEW_LINE" value="true" />
</ScalaCodeStyleSettings>
<XML>
<option name="XML_ALIGN_ATTRIBUTES" value="false" />
<option name="XML_LEGACY_SETTINGS_IMPORTED" value="true" />
</XML>
<codeStyleSettings language="JAVA">
<option name="RIGHT_MARGIN" value="100" />
<option name="KEEP_BLANK_LINES_IN_CODE" value="1" />
<option name="CALL_PARAMETERS_WRAP" value="1" />
<option name="METHOD_PARAMETERS_WRAP" value="1" />
<option name="EXTENDS_LIST_WRAP" value="1" />
<option name="THROWS_KEYWORD_WRAP" value="1" />
<option name="BINARY_OPERATION_WRAP" value="1" />
<option name="TERNARY_OPERATION_WRAP" value="1" />
<option name="TERNARY_OPERATION_SIGNS_ON_NEXT_LINE" value="true" />
<option name="KEEP_SIMPLE_CLASSES_IN_ONE_LINE" value="true" />
<option name="ARRAY_INITIALIZER_WRAP" value="1" />
<option name="WRAP_COMMENTS" value="true" />
<option name="IF_BRACE_FORCE" value="3" />
<option name="DOWHILE_BRACE_FORCE" value="3" />
<option name="WHILE_BRACE_FORCE" value="3" />
<option name="FOR_BRACE_FORCE" value="3" />
<option name="WRAP_ON_TYPING" value="0" />
</codeStyleSettings>
<codeStyleSettings language="JSON">
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="4" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="XML">
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="2" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
<arrangement>
<rules>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:android</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:id</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android\n</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>style</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:.*Style</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android\n</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_width</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android\n</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_height</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android\n</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_weight</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android\n</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_margin</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android\n</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_marginTop</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android\n</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_marginBottom</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android\n</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_marginStart</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android\n</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_marginEnd</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android\n</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_marginLeft</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android\n</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_marginRight</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android\n</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android\n</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:padding</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android\n</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:paddingTop</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android\n</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:paddingBottom</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android\n</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:paddingStart</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android\n</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:paddingEnd</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android\n</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:paddingLeft</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android\n</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:paddingRight</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android\n</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android\n</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res-auto\n</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_NAMESPACE>http://schemas.android.com/tools</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_NAMESPACE>.*</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
</rules>
</arrangement>
</codeStyleSettings>
</code_scheme>
</component>

View File

@@ -2,14 +2,55 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<artifactId>api</artifactId>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
<configuration>
<finalName>${outputName}</finalName>
<shadedArtifactAttached>true</shadedArtifactAttached>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.geysermc</groupId>
<artifactId>common</artifactId>
<version>${geyser.version}</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-transport</artifactId>
<version>4.1.49.Final</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>jsr305</artifactId>
<version>3.0.2</version>
</dependency>
</dependencies>
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>parent</artifactId>
<groupId>org.geysermc.floodgate</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>api</artifactId>
<repositories>
<repository>
@@ -33,45 +74,4 @@
</snapshots>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.geysermc</groupId>
<artifactId>common</artifactId>
<version>${geyser.version}</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-transport</artifactId>
<version>4.1.49.Final</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>jsr305</artifactId>
<version>3.0.2</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
<configuration>
<finalName>${outputName}</finalName>
<shadedArtifactAttached>true</shadedArtifactAttached>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -25,12 +25,18 @@
package org.geysermc.floodgate.api;
import java.util.UUID;
import org.geysermc.floodgate.api.link.PlayerLink;
import org.geysermc.floodgate.api.player.FloodgatePlayer;
import java.util.UUID;
public interface FloodgateApi {
/**
* Returns the Floodgate API instance.
*/
static FloodgateApi getInstance() {
return InstanceHolder.getInstance();
}
/**
* Method to determine if the given <b>online</b> player is a bedrock player
*
@@ -56,9 +62,9 @@ public interface FloodgateApi {
UUID createJavaPlayerId(long xuid);
/**
* Checks if the uuid of the player has the {@link #createJavaPlayerId(long)} format.
* This method can't validate a linked player uuid, since that doesn't equal the format.
* Use {@link #isBedrockPlayer(UUID)} if you want to include linked accounts.
* Checks if the uuid of the player has the {@link #createJavaPlayerId(long)} format. This
* method can't validate a linked player uuid, since that doesn't equal the format. Use {@link
* #isBedrockPlayer(UUID)} if you want to include linked accounts.
*
* @param uuid the uuid to check
* @return true if the given uuid has the correct format.
@@ -71,11 +77,4 @@ public interface FloodgateApi {
default PlayerLink getPlayerLink() {
return InstanceHolder.getPlayerLink();
}
/**
* Returns the Floodgate API instance.
*/
static FloodgateApi getInstance() {
return InstanceHolder.getInstance();
}
}

View File

@@ -25,12 +25,11 @@
package org.geysermc.floodgate.api;
import java.util.UUID;
import lombok.Getter;
import org.geysermc.floodgate.api.inject.PlatformInjector;
import org.geysermc.floodgate.api.link.PlayerLink;
import java.util.UUID;
public final class InstanceHolder {
@Getter private static FloodgateApi instance;
@Getter private static PlayerLink playerLink;

View File

@@ -29,30 +29,27 @@ import io.netty.channel.Channel;
public interface InjectorAddon {
/**
* Called when injecting a specific channel
* (every client that is connected to the server has his own channel).
* Internally used for the Floodgate debugger and data handler but can also be used for
* third party things.
* Called when injecting a specific channel (every client that is connected to the server has
* his own channel). Internally used for the Floodgate debugger and data handler but can also be
* used for third party things.
*
* @param channel the channel that the injector is injecting
* @param proxyToServer if the the connection is between the proxy and a server
* @param toServer if the the connection is between a proxy and a server
*/
void onInject(Channel channel, boolean proxyToServer);
void onInject(Channel channel, boolean toServer);
/**
* Called when the player successfully logged in.
* That is the moment that most of the addons can deregister.
* Note that it is entirely optional to remove the addon from the channel,
* the injector won't force the addon to remove.
* Called when the player successfully logged in. That is the moment that most of the addons can
* deregister. Note that it is entirely optional to remove the addon from the channel, the
* injector won't force the addon to remove.
*
* @param channel the channel that the injector injected
*/
void onLoginDone(Channel channel);
/**
* Called when Floodgate is removing the injection from the server.
* The addon should remove his traces otherwise it is likely that an error will popup after
* the server is injected again.
* Called when Floodgate is removing the injection from the server. The addon should remove his
* traces otherwise it is likely that an error will popup after the server is injected again.
*
* @param channel the channel that the injector injected
*/

View File

@@ -26,17 +26,16 @@
package org.geysermc.floodgate.api.inject;
/**
* The global interface of all the Platform Injectors.
* The injector can be used for various things. It is used internally for getting Floodgate
* data out of the handshake packet and for debug mode, but there is also an option to add your
* own addons.
* Note that every Floodgate platform that supports netty should implement this,
* but the platform implementation isn't required to implement this.
* The global interface of all the Platform Injectors. The injector can be used for various things.
* It is used internally for getting Floodgate data out of the handshake packet and for debug mode,
* but there is also an option to add your own addons. Note that every Floodgate platform that
* supports netty should implement this, but the platform implementation isn't required to implement
* this.
*/
public interface PlatformInjector {
/**
* Injects the server connection.
* This will allow various addons (like getting the Floodgate data and debug mode) to work.
* Injects the server connection. This will allow various addons (like getting the Floodgate
* data and debug mode) to work.
*
* @return true if the connection has successfully been injected
* @throws Exception if something went wrong while injecting the server connection
@@ -44,9 +43,8 @@ public interface PlatformInjector {
boolean inject() throws Exception;
/**
* Removes the injection from the server.
* Please note that this function should only be used internally (on plugin shutdown).
* This method will also remove every added addon.
* Removes the injection from the server. Please note that this function should only be used
* internally (on plugin shutdown). This method will also remove every added addon.
*
* @return true if the injection has successfully been removed
* @throws Exception if something went wrong while removing the injection
@@ -61,9 +59,8 @@ public interface PlatformInjector {
boolean isInjected();
/**
* Adds an addon to the addon list of the Floodgate Injector
* (the addon is called when Floodgate injects a channel).
* See {@link InjectorAddon} for more info.
* Adds an addon to the addon list of the Floodgate Injector (the addon is called when Floodgate
* injects a channel). See {@link InjectorAddon} for more info.
*
* @param addon the addon to add to the addon list
* @return true if the addon has been added, false if the addon is already present
@@ -71,9 +68,8 @@ public interface PlatformInjector {
boolean addAddon(InjectorAddon addon);
/**
* Removes an addon from the addon list of the Floodgate Injector
* (the addon is called when Floodgate injects a channel).
* See {@link InjectorAddon} for more info.
* Removes an addon from the addon list of the Floodgate Injector (the addon is called when
* Floodgate injects a channel). See {@link InjectorAddon} for more info.
*
* @param addon the class of the addon to remove from the addon list
* @param <T> the addon type

View File

@@ -25,9 +25,8 @@
package org.geysermc.floodgate.api.link;
import org.geysermc.floodgate.api.player.FloodgatePlayer;
import java.util.UUID;
import org.geysermc.floodgate.api.player.FloodgatePlayer;
public interface LinkRequest {
/**
@@ -64,10 +63,10 @@ public interface LinkRequest {
boolean isExpired(long linkTimeout);
/**
* Checks if the given FloodgatePlayer is the player requested in this LinkRequest.
* This method will check both the real bedrock username
* {@link FloodgatePlayer#getUsername()} and the edited username
* {@link FloodgatePlayer#getJavaUsername()} and returns true if one of the two matches.
* Checks if the given FloodgatePlayer is the player requested in this LinkRequest. This method
* will check both the real bedrock username {@link FloodgatePlayer#getUsername()} and the
* edited username {@link FloodgatePlayer#getJavaUsername()} and returns true if one of the two
* matches.
*
* @param player the player to check
* @return true if the given player is the player requested

View File

@@ -25,22 +25,20 @@
package org.geysermc.floodgate.api.link;
import org.geysermc.floodgate.util.LinkedPlayer;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import org.geysermc.floodgate.util.LinkedPlayer;
/**
* The base class of the PlayerLink database implementation.
* The implementation is responsible for making a connection with the database
* and keeping that connection alive so that Floodgate (or a third party plugin)
* can check for example if a given player is linked.
* The base class of the PlayerLink database implementation. The implementation is responsible for
* making a connection with the database and keeping that connection alive so that Floodgate (or a
* third party plugin) can check for example if a given player is linked.
*/
public interface PlayerLink {
/**
* Called by Floodgate after the initialization of the class.
* In this method the implementation should start the connection with the database and
* create the collections if they don't exist already.
* Called by Floodgate after the initialization of the class. In this method the implementation
* should start the connection with the database and create the collections if they don't exist
* already.
*/
void load();
@@ -48,8 +46,8 @@ public interface PlayerLink {
* Get a linked player by the bedrock uuid
*
* @param bedrockId the uuid of the bedrock player
* @return a completable future with the {@link LinkedPlayer}.
* The future will have a null value if that Bedrock player isn't linked
* @return a completable future with the {@link LinkedPlayer}. The future will have a null value
* if that Bedrock player isn't linked
*/
CompletableFuture<LinkedPlayer> getLinkedPlayer(UUID bedrockId);
@@ -80,10 +78,9 @@ public interface PlayerLink {
CompletableFuture<Void> unlinkPlayer(UUID javaId);
/**
* Return if account linking is enabled.
* The difference between enabled and allowed is that 'enabled' still allows already linked
* people to join with their linked account while 'allow linking' allows people to link
* accounts using the commands.
* Return if account linking is enabled. The difference between enabled and allowed is that
* 'enabled' still allows already linked people to join with their linked account while 'allow
* linking' allows people to link accounts using the commands.
*/
boolean isEnabled();
@@ -93,10 +90,9 @@ public interface PlayerLink {
long getVerifyLinkTimeout();
/**
* Return if account linking is allowed.
* The difference between enabled and allowed is that 'enabled' still allows already linked
* people to join with their linked account while 'allow linking' allows people to link
* accounts using the commands.
* Return if account linking is allowed. The difference between enabled and allowed is that
* 'enabled' still allows already linked people to join with their linked account while 'allow
* linking' allows people to link accounts using the commands.
*/
boolean isAllowLinking();

View File

@@ -61,6 +61,8 @@ public interface FloodgateLogger {
*/
void info(String message, Object... args);
void translatedInfo(String message, Object... args);
/**
* Logs a debug message to the console, with 0 or more arguments.
*
@@ -83,9 +85,8 @@ public interface FloodgateLogger {
void enableDebug();
/**
* Disables debug mode for the Floodgate logger.
* Debug messages can still be sent after running this method,
* but they will be hidden from the console.
* Disables debug mode for the Floodgate logger. Debug messages can still be sent after running
* this method, but they will be hidden from the console.
*/
void disableDebug();
}

View File

@@ -25,35 +25,36 @@
package org.geysermc.floodgate.api.player;
import org.geysermc.floodgate.util.*;
import java.util.UUID;
import org.geysermc.floodgate.util.DeviceOs;
import org.geysermc.floodgate.util.InputMode;
import org.geysermc.floodgate.util.LinkedPlayer;
import org.geysermc.floodgate.util.RawSkin;
import org.geysermc.floodgate.util.UiProfile;
public interface FloodgatePlayer {
/**
* Returns the Bedrock username that will be used as username on the server.
* This includes replace spaces (if enabled), username shortened and prefix appended.<br>
* Note that this field is not used when the player is a {@link LinkedPlayer LinkedPlayer}
* Returns the Bedrock username that will be used as username on the server. This includes
* replace spaces (if enabled), username shortened and prefix appended.<br> Note that this field
* is not used when the player is a {@link LinkedPlayer LinkedPlayer}
*/
String getJavaUsername();
/**
* Returns the uuid that will be used as UUID on the server.<br>
* Note that this field is not used when the player is a {@link LinkedPlayer LinkedPlayer}
* Returns the uuid that will be used as UUID on the server.<br> Note that this field is not
* used when the player is a {@link LinkedPlayer LinkedPlayer}
*/
UUID getJavaUniqueId();
/**
* Returns the uuid that the server will use as uuid of that player.
* Will return {@link #getJavaUniqueId()} when not linked or
* {@link LinkedPlayer#getJavaUniqueId()} when linked.
* Returns the uuid that the server will use as uuid of that player. Will return {@link
* #getJavaUniqueId()} when not linked or {@link LinkedPlayer#getJavaUniqueId()} when linked.
*/
UUID getCorrectUniqueId();
/**
* Returns the username the server will as username for that player.
* Will return {@link #getJavaUsername()} when not linked or
* {@link LinkedPlayer#getJavaUsername()} when linked.
* Returns the username the server will as username for that player. Will return {@link
* #getJavaUsername()} when not linked or {@link LinkedPlayer#getJavaUsername()} when linked.
*/
String getCorrectUsername();
@@ -63,9 +64,8 @@ public interface FloodgatePlayer {
String getVersion();
/**
* Returns the real username of the Bedrock client.
* This username doesn't have a prefix, spaces aren't replaced and the username hasn't been
* shortened.
* Returns the real username of the Bedrock client. This username doesn't have a prefix, spaces
* aren't replaced and the username hasn't been shortened.
*/
String getUsername();

View File

@@ -2,47 +2,7 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>parent</artifactId>
<groupId>org.geysermc.floodgate</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>bungee</artifactId>
<repositories>
<repository>
<id>bungeecord-repo</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-api</artifactId>
<version>${bungee.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-protocol</artifactId>
<version>${bungee.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.geysermc.floodgate</groupId>
<artifactId>common</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.27.0-GA</version>
</dependency>
</dependencies>
<build>
<resources>
<resource>
@@ -70,4 +30,44 @@
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-api</artifactId>
<version>${bungee.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-protocol</artifactId>
<version>${bungee.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.geysermc.floodgate</groupId>
<artifactId>common</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.27.0-GA</version>
</dependency>
</dependencies>
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>parent</artifactId>
<groupId>org.geysermc.floodgate</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<repositories>
<repository>
<id>bungeecord-repo</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
</repository>
</repositories>
</project>

View File

@@ -28,7 +28,12 @@ package org.geysermc.floodgate;
import com.google.inject.Guice;
import com.google.inject.Injector;
import net.md_5.bungee.api.plugin.Plugin;
import org.geysermc.floodgate.module.*;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.module.BungeeAddonModule;
import org.geysermc.floodgate.module.BungeeListenerModule;
import org.geysermc.floodgate.module.BungeePlatformModule;
import org.geysermc.floodgate.module.CommandModule;
import org.geysermc.floodgate.module.CommonModule;
import org.geysermc.floodgate.util.ReflectionUtils;
public final class BungeePlugin extends Plugin {
@@ -49,10 +54,8 @@ public final class BungeePlugin extends Plugin {
platform = injector.getInstance(FloodgatePlatform.class);
long endCtm = System.currentTimeMillis();
getLogger().info(platform.getLanguageManager().getLogString(
"floodgate.core.finish",
endCtm - ctm
));
injector.getInstance(FloodgateLogger.class)
.translatedInfo("floodgate.core.finish", endCtm - ctm);
}
@Override

View File

@@ -25,6 +25,7 @@
package org.geysermc.floodgate.command;
import java.util.Locale;
import lombok.RequiredArgsConstructor;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.ProxyServer;
@@ -35,8 +36,6 @@ import org.geysermc.floodgate.platform.command.CommandRegistration;
import org.geysermc.floodgate.platform.command.CommandUtil;
import org.geysermc.floodgate.util.LanguageManager;
import java.util.Locale;
@RequiredArgsConstructor
public final class BungeeCommandRegistration implements CommandRegistration {
private final BungeePlugin plugin;

View File

@@ -25,10 +25,16 @@
package org.geysermc.floodgate.handler;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.geysermc.floodgate.HandshakeHandler.ResultType;
import com.google.inject.Inject;
import com.google.inject.name.Named;
import io.netty.channel.Channel;
import io.netty.util.AttributeKey;
import java.lang.reflect.Field;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.event.PreLoginEvent;
import net.md_5.bungee.api.plugin.Plugin;
@@ -42,13 +48,6 @@ import org.geysermc.floodgate.config.ProxyFloodgateConfig;
import org.geysermc.floodgate.util.BedrockData;
import org.geysermc.floodgate.util.ReflectionUtils;
import java.lang.reflect.Field;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.geysermc.floodgate.HandshakeHandler.ResultType;
public final class BungeeDataHandler {
private static final Field EXTRA_HANDSHAKE_DATA;
private static final Field PLAYER_NAME;
@@ -57,31 +56,38 @@ public final class BungeeDataHandler {
private static final Field PLAYER_REMOTE_ADDRESS;
private static final Field CACHED_HANDSHAKE_PACKET;
@Inject
private Plugin plugin;
@Inject
private ProxyFloodgateConfig config;
@Inject
private ProxyFloodgateApi api;
@Inject
private HandshakeHandler handler;
static {
Class<?> initialHandler = ReflectionUtils.getPrefixedClass("connection.InitialHandler");
EXTRA_HANDSHAKE_DATA = ReflectionUtils.getField(initialHandler, "extraDataInHandshake");
checkNotNull(EXTRA_HANDSHAKE_DATA, "extraDataInHandshake field cannot be null");
PLAYER_NAME = ReflectionUtils.getField(initialHandler, "name");
checkNotNull(PLAYER_NAME, "Initial name field cannot be null");
Class<?> channelWrapper = ReflectionUtils.getPrefixedClass("netty.ChannelWrapper");
PLAYER_CHANNEL_WRAPPER = ReflectionUtils.getFieldOfType(initialHandler, channelWrapper);
checkNotNull(PLAYER_CHANNEL_WRAPPER, "ChannelWrapper field cannot be null");
PLAYER_CHANNEL = ReflectionUtils.getFieldOfType(channelWrapper, Channel.class);
checkNotNull(PLAYER_CHANNEL, "Channel field cannot be null");
PLAYER_REMOTE_ADDRESS = ReflectionUtils.getFieldOfType(channelWrapper, SocketAddress.class);
checkNotNull(PLAYER_REMOTE_ADDRESS, "Remote address field cannot be null");
Class<?> handshakePacket = ReflectionUtils.getPrefixedClass("protocol.packet.Handshake");
CACHED_HANDSHAKE_PACKET = ReflectionUtils.getFieldOfType(initialHandler, handshakePacket);
checkNotNull(CACHED_HANDSHAKE_PACKET, "Cached handshake packet field cannot be null");
}
@Inject
@Named("playerAttribute")
private AttributeKey<FloodgatePlayer> playerAttribute;
@Inject
private FloodgateLogger logger;
public BungeeDataHandler(Plugin plugin, ProxyFloodgateConfig config,
ProxyFloodgateApi api, HandshakeHandler handshakeHandler,
AttributeKey<FloodgatePlayer> playerAttribute,
FloodgateLogger logger) {
this.plugin = plugin;
this.config = config;
this.handler = handshakeHandler;
this.api = api;
this.playerAttribute = playerAttribute;
this.logger = logger;
}
@Inject private Plugin plugin;
@Inject private ProxyFloodgateConfig config;
@Inject private ProxyFloodgateApi api;
@Inject private HandshakeHandler handler;
@Inject private FloodgateLogger logger;
public void handlePreLogin(PreLoginEvent event) {
event.registerIntent(plugin);
@@ -129,8 +135,8 @@ public final class BungeeDataHandler {
channel.attr(playerAttribute).set(player);
if (!(remoteAddress instanceof InetSocketAddress)) {
logger.info("Player {} doesn't use an InetSocketAddress. " +
"It uses {}. Ignoring the player, I guess.",
logger.info("Player {} doesn't use an InetSocketAddress, it uses {}. " +
"Ignoring the player, I guess.",
player.getUsername(), remoteAddress.getClass().getSimpleName()
);
} else {
@@ -159,27 +165,4 @@ public final class BungeeDataHandler {
// Bungeecord will add his data after our data
}
}
static {
Class<?> initialHandler = ReflectionUtils.getPrefixedClass("connection.InitialHandler");
EXTRA_HANDSHAKE_DATA = ReflectionUtils.getField(initialHandler, "extraDataInHandshake");
checkNotNull(EXTRA_HANDSHAKE_DATA, "extraDataInHandshake field cannot be null");
PLAYER_NAME = ReflectionUtils.getField(initialHandler, "name");
checkNotNull(PLAYER_NAME, "Initial name field cannot be null");
Class<?> channelWrapper = ReflectionUtils.getPrefixedClass("netty.ChannelWrapper");
PLAYER_CHANNEL_WRAPPER = ReflectionUtils.getFieldOfType(initialHandler, channelWrapper);
checkNotNull(PLAYER_CHANNEL_WRAPPER, "ChannelWrapper field cannot be null");
PLAYER_CHANNEL = ReflectionUtils.getFieldOfType(channelWrapper, Channel.class);
checkNotNull(PLAYER_CHANNEL, "Channel field cannot be null");
PLAYER_REMOTE_ADDRESS = ReflectionUtils.getFieldOfType(channelWrapper, SocketAddress.class);
checkNotNull(PLAYER_REMOTE_ADDRESS, "Remote address field cannot be null");
Class<?> handshakePacket = ReflectionUtils.getPrefixedClass("protocol.packet.Handshake");
CACHED_HANDSHAKE_PACKET = ReflectionUtils.getFieldOfType(initialHandler, handshakePacket);
checkNotNull(CACHED_HANDSHAKE_PACKET, "Cached handshake packet field cannot be null");
}
}

View File

@@ -26,21 +26,23 @@
package org.geysermc.floodgate.inject.bungee;
import io.netty.channel.Channel;
import javassist.*;
import java.util.function.Consumer;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtField;
import javassist.CtMethod;
import javassist.Modifier;
import javax.naming.OperationNotSupportedException;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.inject.CommonPlatformInjector;
import org.geysermc.floodgate.util.ReflectionUtils;
import javax.naming.OperationNotSupportedException;
import java.util.function.Consumer;
@RequiredArgsConstructor
public final class BungeeInjector extends CommonPlatformInjector {
private final FloodgateLogger logger;
@Getter
private boolean injected;
@Getter private boolean injected;
@Override
public boolean inject() {
@@ -54,7 +56,8 @@ public final class BungeeInjector extends CommonPlatformInjector {
// create a new field that we can access
CtField channelConsumerField = new CtField(
classPool.get("java.util.function.Consumer"), "channelConsumer", handlerBossClass
classPool.get("java.util.function.Consumer"), "channelConsumer",
handlerBossClass
);
channelConsumerField.setModifiers(Modifier.PUBLIC | Modifier.STATIC);
handlerBossClass.addField(channelConsumerField);
@@ -62,7 +65,7 @@ public final class BungeeInjector extends CommonPlatformInjector {
// edit a method to call the new field when we need it
CtMethod channelActiveMethod = handlerBossClass.getMethod(
"channelActive", "(Lio/netty/channel/ChannelHandlerContext;)V");
channelActiveMethod.insertBefore("" +
channelActiveMethod.insertBefore(
"{if (handler != null) {channelConsumer.accept(ctx.channel());}}");
Class<?> clazz = handlerBossClass.toClass();

View File

@@ -27,6 +27,7 @@ package org.geysermc.floodgate.listener;
import com.google.inject.Inject;
import com.google.inject.Injector;
import java.util.UUID;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.event.LoginEvent;
import net.md_5.bungee.api.event.PlayerDisconnectEvent;
@@ -42,8 +43,6 @@ import org.geysermc.floodgate.api.player.FloodgatePlayer;
import org.geysermc.floodgate.handler.BungeeDataHandler;
import org.geysermc.floodgate.util.LanguageManager;
import java.util.UUID;
public final class BungeeListener implements Listener {
private BungeeDataHandler dataHandler;
@Inject private ProxyFloodgateApi api;
@@ -80,8 +79,10 @@ public final class BungeeListener implements Listener {
FloodgatePlayer player = api.getPlayer(uniqueId);
if (player != null) {
player.as(FloodgatePlayerImpl.class).setLogin(false);
logger.info(languageManager.getLogString("floodgate.ingame.login_name",
player.getCorrectUsername(), player.getCorrectUniqueId()));
logger.translatedInfo(
"floodgate.ingame.login_name",
player.getCorrectUsername(), uniqueId
);
languageManager.loadLocale(player.getLanguageCode());
}
}
@@ -98,9 +99,7 @@ public final class BungeeListener implements Listener {
ProxiedPlayer player = event.getPlayer();
if (api.removePlayer(player.getUniqueId()) != null) {
api.removeEncryptedData(player.getUniqueId());
logger.info(languageManager.getLogString(
"floodgate.ingame.disconnect_name", player.getName())
);
logger.translatedInfo("floodgate.ingame.disconnect_name", player.getName());
}
}
}

View File

@@ -80,8 +80,8 @@ public final class BungeePlatformModule extends AbstractModule {
@Provides
@Singleton
public FloodgateLogger floodgateLogger() {
return new JavaUtilFloodgateLogger(plugin.getLogger());
public FloodgateLogger floodgateLogger(LanguageManager languageManager) {
return new JavaUtilFloodgateLogger(plugin.getLogger(), languageManager);
}
/*

View File

@@ -2,37 +2,28 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>parent</artifactId>
<groupId>org.geysermc.floodgate</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>common</artifactId>
<repositories>
<repository>
<id>nukkitx-release-repo</id>
<url>https://repo.nukkitx.com/maven-releases/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>nukkitx-snapshot-repo</id>
<url>https://repo.nukkitx.com/maven-snapshots/</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
<configuration>
<finalName>${outputName}</finalName>
<shadedArtifactAttached>true</shadedArtifactAttached>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
@@ -64,25 +55,34 @@
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
<configuration>
<finalName>${outputName}</finalName>
<shadedArtifactAttached>true</shadedArtifactAttached>
</configuration>
</plugin>
</plugins>
</build>
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>parent</artifactId>
<groupId>org.geysermc.floodgate</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<repositories>
<repository>
<id>nukkitx-release-repo</id>
<url>https://repo.nukkitx.com/maven-releases/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>nukkitx-snapshot-repo</id>
<url>https://repo.nukkitx.com/maven-snapshots/</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
</project>

View File

@@ -29,8 +29,9 @@ import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Module;
import com.google.inject.name.Named;
import lombok.AccessLevel;
import lombok.Getter;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.UUID;
import org.geysermc.floodgate.api.FloodgateApi;
import org.geysermc.floodgate.api.InstanceHolder;
import org.geysermc.floodgate.api.inject.PlatformInjector;
@@ -43,35 +44,30 @@ import org.geysermc.floodgate.module.ConfigLoadedModule;
import org.geysermc.floodgate.module.PostInitializeModule;
import org.geysermc.floodgate.util.LanguageManager;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.UUID;
public class FloodgatePlatform {
private static final UUID KEY = UUID.randomUUID();
private final FloodgateConfig config;
private final FloodgateApi api;
private final LanguageManager languageManager;
private final PlatformInjector injector;
private final FloodgateLogger logger;
@Getter(AccessLevel.PROTECTED)
private final LanguageManager languageManager;
private final Injector guice;
private FloodgateConfig config;
private Injector guice;
@Inject
private PlatformInjector injector;
@Inject
public FloodgatePlatform(@Named("dataDirectory") Path dataDirectory, FloodgateApi api,
ConfigLoader configLoader, PlayerLinkLoader playerLinkLoader,
HandshakeHandler handshakeHandler, FloodgateLogger logger,
PlatformInjector platformInjector, LanguageManager languageManager,
Injector injector) {
public FloodgatePlatform(FloodgateApi api, LanguageManager languageManager,
PlatformInjector platformInjector, FloodgateLogger logger) {
this.api = api;
this.logger = logger;
this.languageManager = languageManager;
this.injector = platformInjector;
this.logger = logger;
}
@Inject
public void init(@Named("dataDirectory") Path dataDirectory, ConfigLoader configLoader,
PlayerLinkLoader playerLinkLoader, HandshakeHandler handshakeHandler,
Injector injector) {
if (!Files.isDirectory(dataDirectory)) {
try {
@@ -96,7 +92,7 @@ public class FloodgatePlatform {
PlayerLink link = playerLinkLoader.load();
InstanceHolder.setInstance(api, link, platformInjector, KEY);
InstanceHolder.setInstance(api, link, this.injector, KEY);
}
public boolean enable(Module... postInitializeModules) {

View File

@@ -25,6 +25,9 @@
package org.geysermc.floodgate;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import lombok.Getter;
import lombok.Setter;
import org.geysermc.floodgate.api.FloodgateApi;
@@ -32,11 +35,12 @@ import org.geysermc.floodgate.api.InstanceHolder;
import org.geysermc.floodgate.api.ProxyFloodgateApi;
import org.geysermc.floodgate.api.link.PlayerLink;
import org.geysermc.floodgate.api.player.FloodgatePlayer;
import org.geysermc.floodgate.util.*;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import org.geysermc.floodgate.util.BedrockData;
import org.geysermc.floodgate.util.DeviceOs;
import org.geysermc.floodgate.util.InputMode;
import org.geysermc.floodgate.util.LinkedPlayer;
import org.geysermc.floodgate.util.RawSkin;
import org.geysermc.floodgate.util.UiProfile;
@Getter
public final class FloodgatePlayerImpl implements FloodgatePlayer {
@@ -57,8 +61,7 @@ public final class FloodgatePlayerImpl implements FloodgatePlayer {
/**
* Returns true if the player is still logging in
*/
@Setter
private boolean login = true;
@Setter private boolean login = true;
FloodgatePlayerImpl(BedrockData data, RawSkin skin, String prefix, boolean replaceSpaces) {
FloodgateApi api = FloodgateApi.getInstance();
@@ -130,8 +133,8 @@ public final class FloodgatePlayerImpl implements FloodgatePlayer {
/**
* Fetch and return the LinkedPlayer object associated to the player if the player is linked.
*
* @return a future holding the LinkedPlayer or null if the player isn't linked or when
* linking isn't enabled
* @return a future holding the LinkedPlayer or null if the player isn't linked or when linking
* isn't enabled
* @see #fetchLinkedPlayer(PlayerLink) for the sync version
*/
public CompletableFuture<LinkedPlayer> fetchLinkedPlayerAsync(PlayerLink link) {

View File

@@ -25,9 +25,15 @@
package org.geysermc.floodgate;
import static org.geysermc.floodgate.util.BedrockData.EXPECTED_LENGTH;
import com.google.common.base.Charsets;
import com.google.inject.Inject;
import lombok.*;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import org.geysermc.floodgate.api.SimpleFloodgateApi;
import org.geysermc.floodgate.api.player.FloodgatePlayer;
import org.geysermc.floodgate.config.FloodgateConfig;
@@ -37,8 +43,6 @@ import org.geysermc.floodgate.util.BedrockData;
import org.geysermc.floodgate.util.InvalidFormatException;
import org.geysermc.floodgate.util.RawSkin;
import static org.geysermc.floodgate.util.BedrockData.EXPECTED_LENGTH;
@RequiredArgsConstructor
public final class HandshakeHandler {
private final SimpleFloodgateApi api;
@@ -122,19 +126,6 @@ public final class HandshakeHandler {
}
}
@AllArgsConstructor(access = AccessLevel.PROTECTED)
@Getter
public static class HandshakeResult {
private final ResultType resultType;
private final String[] handshakeData;
private final BedrockData bedrockData;
private final FloodgatePlayer floodgatePlayer;
public boolean isBungeeData() {
return handshakeData.length == 4 || handshakeData.length == 5;
}
}
public enum ResultType {
EXCEPTION,
NOT_FLOODGATE_DATA,
@@ -148,4 +139,17 @@ public final class HandshakeHandler {
cachedResult = new HandshakeResult(this, null, null, null);
}
}
@AllArgsConstructor(access = AccessLevel.PROTECTED)
@Getter
public static class HandshakeResult {
private final ResultType resultType;
private final String[] handshakeData;
private final BedrockData bedrockData;
private final FloodgatePlayer floodgatePlayer;
public boolean isBungeeData() {
return handshakeData.length == 4 || handshakeData.length == 5;
}
}
}

View File

@@ -36,7 +36,7 @@ public final class AddonManagerAddon implements InjectorAddon {
@Inject private CommonPlatformInjector injector;
@Override
public void onInject(Channel channel, boolean proxyToServer) {
public void onInject(Channel channel, boolean toServer) {
channel.pipeline().addLast("floodgate_addon", new AddonManagerHandler(injector, channel));
}

View File

@@ -28,6 +28,7 @@ package org.geysermc.floodgate.addon;
import com.google.inject.Inject;
import com.google.inject.name.Named;
import io.netty.channel.Channel;
import io.netty.channel.ChannelPipeline;
import org.geysermc.floodgate.addon.debug.ChannelInDebugHandler;
import org.geysermc.floodgate.addon.debug.ChannelOutDebugHandler;
import org.geysermc.floodgate.api.inject.InjectorAddon;
@@ -51,13 +52,13 @@ public final class DebugAddon implements InjectorAddon {
private String packetDecoder;
@Override
public void onInject(Channel channel, boolean proxyToServer) {
public void onInject(Channel channel, boolean toServer) {
channel.pipeline().addBefore(
packetEncoder, "floodgate_debug_out",
new ChannelOutDebugHandler(implementationName, !proxyToServer, logger)
new ChannelOutDebugHandler(implementationName, toServer, logger)
).addBefore(
packetDecoder, "floodgate_debug_in",
new ChannelInDebugHandler(logger, implementationName, !proxyToServer)
new ChannelInDebugHandler(implementationName, toServer, logger)
);
}
@@ -68,8 +69,10 @@ public final class DebugAddon implements InjectorAddon {
@Override
public void onRemoveInject(Channel channel) {
channel.pipeline().remove("floodgate_debug_out");
channel.pipeline().remove("floodgate_debug_in");
ChannelPipeline pipeline = channel.pipeline();
pipeline.remove("floodgate_debug_out");
pipeline.remove("floodgate_debug_in");
}
@Override

View File

@@ -35,17 +35,21 @@ public final class ChannelInDebugHandler extends SimpleChannelInboundHandler<Byt
private final String message;
private final FloodgateLogger logger;
public ChannelInDebugHandler(FloodgateLogger logger, String implementationType,
boolean player) {
public ChannelInDebugHandler(String implementationType, boolean toServer,
FloodgateLogger logger) {
this.message = (toServer ? "Server ->" : "Player ->") + ' ' + implementationType;
this.logger = logger;
this.message = (player ? "Player ->" : "Server ->") + ' ' + implementationType;
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) {
int index = msg.readerIndex();
logger.info("{}:\n{}", message, ByteBufUtil.prettyHexDump(msg));
// reset index
msg.readerIndex(index);
ctx.fireChannelRead(msg.retain());
}
}

View File

@@ -35,18 +35,21 @@ public final class ChannelOutDebugHandler extends MessageToByteEncoder<ByteBuf>
private final String direction;
private final FloodgateLogger logger;
public ChannelOutDebugHandler(String implementationType, boolean player,
public ChannelOutDebugHandler(String implementationType, boolean toServer,
FloodgateLogger logger) {
this.direction = implementationType + (player ? " -> Player" : " -> Server");
this.direction = implementationType + (toServer ? " -> Server" : " -> Player");
this.logger = logger;
}
@Override
protected void encode(ChannelHandlerContext ctx, ByteBuf msg, ByteBuf out) {
int index = msg.readerIndex();
logger.info("{}:\n{}", direction, ByteBufUtil.prettyHexDump(msg));
// reset index
msg.readerIndex(index);
out.writeBytes(msg);
}
}

View File

@@ -25,15 +25,13 @@
package org.geysermc.floodgate.api;
import lombok.RequiredArgsConstructor;
import org.geysermc.floodgate.crypto.FloodgateCipher;
import org.geysermc.floodgate.util.BedrockData;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import lombok.RequiredArgsConstructor;
import org.geysermc.floodgate.crypto.FloodgateCipher;
import org.geysermc.floodgate.util.BedrockData;
@RequiredArgsConstructor
public final class ProxyFloodgateApi extends SimpleFloodgateApi {
@@ -55,9 +53,6 @@ public final class ProxyFloodgateApi extends SimpleFloodgateApi {
public void updateEncryptedData(UUID uuid, BedrockData bedrockData) {
try {
byte[] encryptedData = cipher.encryptFromString(bedrockData.toString());
encryptedData = Base64.getEncoder().encode(encryptedData);
//todo maybe bake Base64 support into it?
addEncryptedData(uuid, new String(encryptedData, StandardCharsets.UTF_8));
} catch (Exception exception) {
throw new IllegalStateException("We failed to update the BedrockData, " +

View File

@@ -25,14 +25,13 @@
package org.geysermc.floodgate.api;
import lombok.RequiredArgsConstructor;
import org.geysermc.floodgate.FloodgatePlayerImpl;
import org.geysermc.floodgate.api.player.FloodgatePlayer;
import javax.annotation.Nullable;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import javax.annotation.Nullable;
import lombok.RequiredArgsConstructor;
import org.geysermc.floodgate.FloodgatePlayerImpl;
import org.geysermc.floodgate.api.player.FloodgatePlayer;
@RequiredArgsConstructor
public class SimpleFloodgateApi implements FloodgateApi {
@@ -84,29 +83,34 @@ public class SimpleFloodgateApi implements FloodgateApi {
*/
@Nullable
public FloodgatePlayer removePlayer(UUID onlineId, boolean removeLogin) {
FloodgatePlayer player = players.get(onlineId);
FloodgatePlayer selfPlayer = players.get(onlineId);
// the player is a non-linked player or a linked player but somehow someone tried to
// remove the player by his xuid, we have to find out
if (player != null) {
if (selfPlayer != null) {
// we don't allow them to remove a player by his xuid
// because a linked player is never registered by his linked java uuid
if (player.getLinkedPlayer() != null) return null;
if (selfPlayer.getLinkedPlayer() != null) {
return null;
}
// removeLogin logic
if (!shouldRemove(player, removeLogin)) return null;
if (!shouldRemove(selfPlayer, removeLogin)) {
return null;
}
// passed the test
players.remove(onlineId);
// was the account linked?
return player;
return selfPlayer;
}
// we still want to be able to remove a linked-player by his linked java uuid
for (FloodgatePlayer player1 : players.values()) {
if (!shouldRemove(player1, removeLogin)) continue;
if (!player1.getCorrectUniqueId().equals(onlineId)) continue;
players.remove(player1.getJavaUniqueId());
return player1;
for (FloodgatePlayer player : players.values()) {
if (shouldRemove(player, removeLogin) && player.getCorrectUniqueId().equals(onlineId)) {
continue;
}
players.remove(player.getJavaUniqueId());
return player;
}
return null;
@@ -125,8 +129,8 @@ public class SimpleFloodgateApi implements FloodgateApi {
}
/**
* Equivalent of {@link #removePlayer(UUID, boolean)} except that it removes a
* FloodgatePlayer instance directly.
* Equivalent of {@link #removePlayer(UUID, boolean)} except that it removes a FloodgatePlayer
* instance directly.
*/
public boolean removePlayer(FloodgatePlayer player) {
boolean removed = players.remove(player.getJavaUniqueId(), player);

View File

@@ -26,6 +26,10 @@
package org.geysermc.floodgate.command;
import com.google.inject.Inject;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.UUID;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.geysermc.floodgate.api.FloodgateApi;
@@ -36,11 +40,6 @@ import org.geysermc.floodgate.platform.command.Command;
import org.geysermc.floodgate.platform.command.CommandMessage;
import org.geysermc.floodgate.platform.command.CommandUtil;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.UUID;
@NoArgsConstructor
public final class LinkAccountCommand implements Command {
private final Map<String, LinkRequest> activeLinkRequests = new HashMap<>();
@@ -56,7 +55,8 @@ public final class LinkAccountCommand implements Command {
return;
}
link.isLinkedPlayer(uuid).whenComplete((linked, throwable) -> {
link.isLinkedPlayer(uuid)
.whenComplete((linked, throwable) -> {
if (throwable != null) {
sendMessage(player, locale, CommonCommandMessage.IS_LINKED_ERROR);
return;
@@ -116,7 +116,7 @@ public final class LinkAccountCommand implements Command {
}
link.linkPlayer(uuid, request.getJavaUniqueId(), request.getJavaUsername())
.whenComplete((aVoid, error) -> {
.whenComplete((unused, error) -> {
if (error != null) {
sendMessage(player, locale, Message.LINK_REQUEST_ERROR);
return;
@@ -161,8 +161,7 @@ public final class LinkAccountCommand implements Command {
NO_LINK_REQUESTED("floodgate.command.link_account.no_link_requested"),
LINK_REQUEST_DISABLED("floodgate.commands.linking_disabled");
@Getter
private final String message;
@Getter private final String message;
Message(String message) {
this.message = message;

View File

@@ -26,6 +26,7 @@
package org.geysermc.floodgate.command;
import com.google.inject.Inject;
import java.util.UUID;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.geysermc.floodgate.api.FloodgateApi;
@@ -34,8 +35,6 @@ import org.geysermc.floodgate.platform.command.Command;
import org.geysermc.floodgate.platform.command.CommandMessage;
import org.geysermc.floodgate.platform.command.CommandUtil;
import java.util.UUID;
@NoArgsConstructor
public final class UnlinkAccountCommand implements Command {
@Inject private FloodgateApi api;
@@ -49,8 +48,9 @@ public final class UnlinkAccountCommand implements Command {
return;
}
link.isLinkedPlayer(uuid).whenComplete((linked, throwable) -> {
if (throwable != null) {
link.isLinkedPlayer(uuid)
.whenComplete((linked, error) -> {
if (error != null) {
sendMessage(player, locale, CommonCommandMessage.IS_LINKED_ERROR);
return;
}
@@ -60,13 +60,15 @@ public final class UnlinkAccountCommand implements Command {
return;
}
link.unlinkPlayer(uuid).whenComplete((aVoid, throwable1) ->
sendMessage(player, locale,
throwable1 == null ?
Message.UNLINK_SUCCESS :
Message.UNLINK_ERROR
)
);
link.unlinkPlayer(uuid)
.whenComplete((unused, error1) -> {
if (error1 != null) {
sendMessage(player, locale, Message.UNLINK_ERROR);
return;
}
sendMessage(player, locale, Message.UNLINK_SUCCESS);
});
});
}
@@ -96,8 +98,7 @@ public final class UnlinkAccountCommand implements Command {
UNLINK_ERROR("floodgate.command.unlink_account.error"),
LINKING_NOT_ENABLED("floodgate.commands.linking_disabled");
@Getter
private final String message;
@Getter private final String message;
Message(String message) {
this.message = message;

View File

@@ -27,14 +27,12 @@ package org.geysermc.floodgate.config;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.security.Key;
import lombok.Getter;
import java.security.Key;
/**
* The global Floodgate configuration file used in every platform.
* Some platforms have their own addition to the global configuration like
* {@link ProxyFloodgateConfig} for the proxies.
* The global Floodgate configuration file used in every platform. Some platforms have their own
* addition to the global configuration like {@link ProxyFloodgateConfig} for the proxies.
*/
@Getter
public class FloodgateConfig {
@@ -63,6 +61,16 @@ public class FloodgateConfig {
@JsonIgnore
private Key key = null;
public void setKey(Key key) {
if (this.key == null) {
this.key = key;
}
}
public boolean isProxy() {
return this instanceof ProxyFloodgateConfig;
}
@Getter
public static class DisconnectMessages {
@JsonProperty("invalid-key")
@@ -84,14 +92,4 @@ public class FloodgateConfig {
@JsonProperty("auto-download")
private boolean autoDownload;
}
public void setKey(Key key) {
if (this.key == null) {
this.key = key;
}
}
public boolean isProxy() {
return this instanceof ProxyFloodgateConfig;
}
}

View File

@@ -32,6 +32,7 @@ import lombok.Getter;
* The Floodgate configuration used by proxy platforms, currently Velocity and Bungeecord.
*/
public final class ProxyFloodgateConfig extends FloodgateConfig {
@Getter
@JsonProperty(value = "send-floodgate-data")
@Getter private boolean sendFloodgateData;
private boolean sendFloodgateData;
}

View File

@@ -27,6 +27,12 @@ package org.geysermc.floodgate.config.loader;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.Key;
import lombok.RequiredArgsConstructor;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.config.FloodgateConfig;
@@ -35,16 +41,8 @@ import org.geysermc.floodgate.config.updater.ConfigUpdater;
import org.geysermc.floodgate.crypto.FloodgateCipher;
import org.geysermc.floodgate.crypto.KeyProducer;
import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.Key;
@RequiredArgsConstructor
public class ConfigLoader {
public final class ConfigLoader {
private final Path dataFolder;
private final Class<? extends FloodgateConfig> configClass;
private final ConfigUpdater updater;
@@ -116,14 +114,16 @@ public class ConfigLoader {
updater.update(defaultConfigPath);
}
configInstance = (T) new ObjectMapper(new YAMLFactory())
FloodgateConfig config =
new ObjectMapper(new YAMLFactory())
.readValue(Files.readAllBytes(configPath), configClass);
} catch (ClassCastException exception) {
logger.error("Provided class {} cannot be cast to the required return type",
configClass.getName());
throw new RuntimeException("Failed to load cast the config! " +
"Try to contact the platform developer");
try {
configInstance = (T) config;
} catch (ClassCastException exception) {
logger.error("Failed to cast config file to required class.", exception);
throw new RuntimeException(exception);
}
} catch (Exception exception) {
logger.error("Error while loading config", exception);
throw new RuntimeException("Failed to load the config! Try to delete the config file");

View File

@@ -26,27 +26,25 @@
package org.geysermc.floodgate.config.updater;
import com.google.inject.Inject;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
public class ConfigFileUpdater {
@Inject
private FloodgateLogger logger;
public final class ConfigFileUpdater {
@Inject private FloodgateLogger logger;
/**
* Simple config file updater.
* Please note that all the keys should be unique and that this system wasn't made for complex
* configurations.
* Simple config file updater. Please note that all the keys should be unique and that this
* system wasn't made for complex configurations.
*
* @param configLocation the location of the Floodgate config
* @param currentVersion the key value map of the current config
* @param renames name changes introduced in this version. new (key) to old (value)
* @param renames name changes introduced in this version. new (key) to old
* (value)
* @param defaultConfigLocation the location of the default Floodgate config
* @throws IOException if an I/O error occurs
*/
@@ -59,7 +57,9 @@ public class ConfigFileUpdater {
for (int i = 0; i < newConfig.size(); i++) {
line = newConfig.get(i);
// we don't have to check comments
if (line.startsWith("#")) continue;
if (line.startsWith("#")) {
continue;
}
int splitIndex = line.indexOf(':');
// if the line has a 'key: value' structure
@@ -69,11 +69,7 @@ public class ConfigFileUpdater {
Object value;
logger.info(name);
if (renames.containsKey(name)) {
value = currentVersion.get(renames.get(name));
} else {
value = currentVersion.get(name);
}
value = currentVersion.get(renames.getOrDefault(name, name));
if (value == null) {
notFound.add(name);
@@ -102,9 +98,7 @@ public class ConfigFileUpdater {
if (notFound.size() > 0) {
StringBuilder messageBuilder = new StringBuilder(
"Please note that the following keys we not found in the old config and " +
"are now using the default Floodgate config value. " +
"Missing/new keys: "
);
"are now using the default Floodgate config value. Missing/new keys: ");
boolean first = true;
for (String value : notFound) {

View File

@@ -25,9 +25,8 @@
package org.geysermc.floodgate.config.updater;
import lombok.RequiredArgsConstructor;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.yaml.snakeyaml.Yaml;
import static com.google.common.base.Preconditions.checkArgument;
import static org.geysermc.floodgate.util.MessageFormatter.format;
import java.io.BufferedReader;
import java.io.IOException;
@@ -35,17 +34,17 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.Map;
import static com.google.common.base.Preconditions.checkArgument;
import lombok.RequiredArgsConstructor;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.yaml.snakeyaml.Yaml;
@RequiredArgsConstructor
public class ConfigUpdater {
public final class ConfigUpdater {
private static final int CONFIG_VERSION = 1;
private final Path dataFolder;
private final ConfigFileUpdater fileUpdater;
private final FloodgateLogger logger;
private static final int CONFIG_VERSION = 1;
public void update(Path defaultConfigLocation) {
Path configLocation = dataFolder.resolve("config.yml");
@@ -72,8 +71,8 @@ public class ConfigUpdater {
int version = (int) versionElement;
checkArgument(
version == CONFIG_VERSION,
"Config is newer then possible on this version! Expected " + CONFIG_VERSION + ", got " + version
);
format("Config is newer then possible on this version! Expected {}, got {}",
CONFIG_VERSION, version));
// config is already up-to-date
if (version == CONFIG_VERSION) {

View File

@@ -26,13 +26,12 @@
package org.geysermc.floodgate.inject;
import io.netty.channel.Channel;
import org.geysermc.floodgate.api.inject.InjectorAddon;
import org.geysermc.floodgate.api.inject.PlatformInjector;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.geysermc.floodgate.api.inject.InjectorAddon;
import org.geysermc.floodgate.api.inject.PlatformInjector;
public abstract class CommonPlatformInjector implements PlatformInjector {
private final Set<Channel> injectedClients = new HashSet<>();
@@ -58,13 +57,12 @@ public abstract class CommonPlatformInjector implements PlatformInjector {
}
/**
* Method to loop through all the addons and call
* {@link InjectorAddon#onInject(Channel, boolean)} if
* {@link InjectorAddon#shouldInject()}.
* Method to loop through all the addons and call {@link InjectorAddon#onInject(Channel,
* boolean)} if {@link InjectorAddon#shouldInject()}.
*
* @param channel the channel to inject
* @param proxyToServer true if the proxy is connecting to a server or false when the player
* is connecting to the proxy or false when the platform isn't a proxy
* @param proxyToServer true if the proxy is connecting to a server or false when the player is
* connecting to the proxy or false when the platform isn't a proxy
*/
public void injectAddonsCall(Channel channel, boolean proxyToServer) {
for (InjectorAddon addon : addons.values()) {
@@ -75,8 +73,7 @@ public abstract class CommonPlatformInjector implements PlatformInjector {
}
/**
* Method to loop through all the addons and call
* {@link InjectorAddon#onLoginDone(Channel)} if
* Method to loop through all the addons and call {@link InjectorAddon#onLoginDone(Channel)} if
* {@link InjectorAddon#shouldInject()}.
*
* @param channel the channel that was injected
@@ -90,9 +87,8 @@ public abstract class CommonPlatformInjector implements PlatformInjector {
}
/**
* Method to loop through all the addons and call
* {@link InjectorAddon#onRemoveInject(Channel)} if
* {@link InjectorAddon#shouldInject()}.
* Method to loop through all the addons and call {@link InjectorAddon#onRemoveInject(Channel)}
* if {@link InjectorAddon#shouldInject()}.
*
* @param channel the channel that was injected
*/

View File

@@ -26,24 +26,24 @@
package org.geysermc.floodgate.link;
import com.google.inject.Inject;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import lombok.AccessLevel;
import lombok.Getter;
import org.geysermc.floodgate.api.link.PlayerLink;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.config.FloodgateConfig;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public abstract class CommonPlayerLink implements PlayerLink {
@Getter(AccessLevel.PROTECTED)
private final ExecutorService executorService = Executors.newFixedThreadPool(11);
@Getter private boolean enabled;
@Getter private boolean allowLinking;
@Getter private long verifyLinkTimeout;
@Inject
@Getter(AccessLevel.PROTECTED)
private final ExecutorService executorService = Executors.newFixedThreadPool(11);
@Inject @Getter(AccessLevel.PROTECTED)
private FloodgateLogger logger;
@Inject

View File

@@ -25,17 +25,16 @@
package org.geysermc.floodgate.link;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import org.geysermc.floodgate.api.FloodgateApi;
import org.geysermc.floodgate.api.link.PlayerLink;
import org.geysermc.floodgate.util.LinkedPlayer;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
/**
* Simple class used when PlayerLinking is disabled.
* This class has been made because Floodgate doesn't have a default PlayerLink implementation
* anymore and {@link FloodgateApi#getPlayerLink()} returning null} is also not an option.
* Simple class used when PlayerLinking is disabled. This class has been made because Floodgate
* doesn't have a default PlayerLink implementation anymore and {@link FloodgateApi#getPlayerLink()}
* returning null} is also not an option.
*/
final class DisabledPlayerLink implements PlayerLink {
@Override

View File

@@ -25,11 +25,10 @@
package org.geysermc.floodgate.link;
import lombok.Getter;
import org.geysermc.floodgate.api.link.LinkRequest;
import java.time.Instant;
import java.util.UUID;
import lombok.Getter;
import org.geysermc.floodgate.api.link.LinkRequest;
@Getter
public final class LinkRequestImpl implements LinkRequest {

View File

@@ -25,15 +25,13 @@
package org.geysermc.floodgate.link;
import static java.util.Objects.requireNonNull;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.name.Named;
import org.geysermc.floodgate.api.link.PlayerLink;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.config.FloodgateConfig;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
@@ -43,17 +41,19 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.stream.Collectors;
import org.geysermc.floodgate.api.link.PlayerLink;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.config.FloodgateConfig;
import static java.util.Objects.requireNonNull;
public class PlayerLinkLoader {
@Named("dataDirectory")
@Inject private Path dataDirectory;
public final class PlayerLinkLoader {
@Inject private Injector injector;
@Inject private FloodgateConfig config;
@Inject private FloodgateLogger logger;
@Inject
@Named("dataDirectory")
private Path dataDirectory;
public PlayerLink load() {
FloodgateConfig.PlayerLinkConfig linkConfig = config.getPlayerLink();
if (!linkConfig.isEnabled()) {

View File

@@ -25,17 +25,18 @@
package org.geysermc.floodgate.logger;
import lombok.RequiredArgsConstructor;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import static org.geysermc.floodgate.util.MessageFormatter.format;
import java.util.logging.Level;
import java.util.logging.Logger;
import static org.geysermc.floodgate.util.MessageFormatter.format;
import lombok.RequiredArgsConstructor;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.util.LanguageManager;
@RequiredArgsConstructor
public final class JavaUtilFloodgateLogger implements FloodgateLogger {
private final Logger logger;
private final LanguageManager languageManager;
private Level originLevel = null;
@Override
@@ -58,6 +59,11 @@ public final class JavaUtilFloodgateLogger implements FloodgateLogger {
logger.info(format(message, args));
}
@Override
public void translatedInfo(String message, Object... args) {
logger.info(languageManager.getLogString(message, args));
}
@Override
public void debug(String message, Object... args) {
logger.fine(format(message, args));

View File

@@ -30,6 +30,7 @@ import com.google.inject.Provides;
import com.google.inject.Singleton;
import com.google.inject.name.Named;
import io.netty.util.AttributeKey;
import java.nio.file.Path;
import lombok.RequiredArgsConstructor;
import org.geysermc.floodgate.HandshakeHandler;
import org.geysermc.floodgate.api.FloodgateApi;
@@ -41,13 +42,15 @@ import org.geysermc.floodgate.config.FloodgateConfig;
import org.geysermc.floodgate.config.loader.ConfigLoader;
import org.geysermc.floodgate.config.updater.ConfigFileUpdater;
import org.geysermc.floodgate.config.updater.ConfigUpdater;
import org.geysermc.floodgate.crypto.*;
import org.geysermc.floodgate.crypto.AesCipher;
import org.geysermc.floodgate.crypto.AesKeyProducer;
import org.geysermc.floodgate.crypto.Base64Topping;
import org.geysermc.floodgate.crypto.FloodgateCipher;
import org.geysermc.floodgate.crypto.KeyProducer;
import org.geysermc.floodgate.inject.CommonPlatformInjector;
import org.geysermc.floodgate.link.PlayerLinkLoader;
import org.geysermc.floodgate.util.LanguageManager;
import java.nio.file.Path;
@RequiredArgsConstructor
public final class CommonModule extends AbstractModule {
private final Path dataDirectory;
@@ -79,9 +82,11 @@ public final class CommonModule extends AbstractModule {
@Provides
@Singleton
public ConfigLoader configLoader(@Named("configClass") Class<? extends FloodgateConfig> configClass,
public ConfigLoader configLoader(
@Named("configClass") Class<? extends FloodgateConfig> configClass,
ConfigUpdater configUpdater, KeyProducer producer,
FloodgateCipher cipher, FloodgateLogger logger) {
return new ConfigLoader(
dataDirectory, configClass, configUpdater, producer, cipher, logger
);

View File

@@ -32,11 +32,11 @@ import java.util.UUID;
*/
public interface Command {
/**
* Should be implemented when {@link #isRequirePlayer()} is true
* or when the source is a player.
* Should be implemented when {@link #isRequirePlayer()} is true or when the source is a
* player.
*
* @param player the player instance (used for example in combination with
* {@link CommandUtil#kickPlayer(Object, String, CommandMessage, Object...)}
* @param player the player instance (used for example in combination with {@link
* CommandUtil#kickPlayer(Object, String, CommandMessage, Object...)}
* @param uuid the uuid of the player
* @param username the username of the player
* @param locale the locale of the player
@@ -69,16 +69,16 @@ public interface Command {
String getName();
/**
* The permission that is required to execute the specific command.
* Should return null when there is no permission required.
* The permission that is required to execute the specific command. Should return null when
* there is no permission required.
*
* @return the permission required to execute the command
*/
String getPermission();
/**
* If the Command requires a Player to execute this command
* or if it doesn't matter if (for example) the console executes the command.
* If the Command requires a Player to execute this command or if it doesn't matter if (for
* example) the console executes the command.
*
* @return true if this command can only be executed by a player
*/

View File

@@ -26,8 +26,8 @@
package org.geysermc.floodgate.platform.command;
/**
* CommandMessage is the interface of a message that can be send to a command source after
* executing a command. Messages are generally implemented using enums.
* CommandMessage is the interface of a message that can be send to a command source after executing
* a command. Messages are generally implemented using enums.
*/
public interface CommandMessage {
/**

View File

@@ -26,10 +26,9 @@
package org.geysermc.floodgate.platform.command;
/**
* This class is responsible for registering commands to the command register of the platform
* that is currently in use. So that the commands only have to be written once
* (in the common module) and can be used across all platforms without the need of adding platform
* specific commands.
* This class is responsible for registering commands to the command register of the platform that
* is currently in use. So that the commands only have to be written once (in the common module) and
* can be used across all platforms without the need of adding platform specific commands.
*/
public interface CommandRegistration {
/**

View File

@@ -26,8 +26,8 @@
package org.geysermc.floodgate.platform.command;
/**
* An interface used across all Floodgate platforms to simple stuff in commands like kicking
* players and sending player messages independent of the Floodgate platform implementation.
* An interface used across all Floodgate platforms to simple stuff in commands like kicking players
* and sending player messages independent of the Floodgate platform implementation.
*/
public interface CommandUtil {
/**

View File

@@ -26,9 +26,9 @@
package org.geysermc.floodgate.platform.listener;
/**
* This class is responsible for registering listeners to the listener manager of the platform
* that is currently in use. Unfortunately due to the major differences between the platforms
* (when it comes to listeners) every Floodgate platform has to implement their own listeners.
* This class is responsible for registering listeners to the listener manager of the platform that
* is currently in use. Unfortunately due to the major differences between the platforms (when it
* comes to listeners) every Floodgate platform has to implement their own listeners.
*
* @param <T> the platform-specific listener class
*/

View File

@@ -27,11 +27,10 @@ package org.geysermc.floodgate.register;
import com.google.inject.Inject;
import com.google.inject.Injector;
import java.util.Set;
import org.geysermc.floodgate.api.inject.InjectorAddon;
import org.geysermc.floodgate.api.inject.PlatformInjector;
import java.util.Set;
public final class AddonRegister {
@Inject private Injector guice;
@Inject private PlatformInjector injector;

View File

@@ -27,12 +27,11 @@ package org.geysermc.floodgate.register;
import com.google.inject.Inject;
import com.google.inject.Injector;
import java.util.Set;
import lombok.RequiredArgsConstructor;
import org.geysermc.floodgate.platform.command.Command;
import org.geysermc.floodgate.platform.command.CommandRegistration;
import java.util.Set;
@RequiredArgsConstructor(onConstructor = @__(@Inject))
public final class CommandRegister {
private final CommandRegistration registration;

View File

@@ -27,11 +27,10 @@ package org.geysermc.floodgate.register;
import com.google.inject.Inject;
import com.google.inject.Injector;
import java.util.Set;
import lombok.RequiredArgsConstructor;
import org.geysermc.floodgate.platform.listener.ListenerRegistration;
import java.util.Set;
@RequiredArgsConstructor(onConstructor = @__(@Inject))
public final class ListenerRegister<T> {
private final ListenerRegistration<T> registration;

View File

@@ -26,25 +26,25 @@
package org.geysermc.floodgate.util;
import com.google.inject.Inject;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.config.FloodgateConfig;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.config.FloodgateConfig;
/**
* Manages translations for strings in Floodgate
*/
@RequiredArgsConstructor
public class LanguageManager {
public final class LanguageManager {
private final Map<String, Properties> LOCALE_MAPPINGS = new HashMap<>();
private final FloodgateLogger logger;
@@ -52,8 +52,22 @@ public class LanguageManager {
/**
* The locale used in console and as a fallback
*/
@Getter
private String defaultLocale;
@Getter private String defaultLocale;
/**
* Cleans up and formats a locale string
*
* @param locale the locale to format
* @return the formatted locale
*/
private static String formatLocale(String locale) {
try {
String[] parts = locale.toLowerCase().split("_");
return parts[0] + "_" + parts[1].toUpperCase();
} catch (Exception e) {
return locale;
}
}
/**
* Loads the log's locale file once Floodgate loads the config
@@ -72,8 +86,7 @@ public class LanguageManager {
}
String systemLocale = formatLocale(
Locale.getDefault().getLanguage() + "_" +
Locale.getDefault().getCountry()
Locale.getDefault().getLanguage() + "_" + Locale.getDefault().getCountry()
);
if (isValidLanguage(systemLocale)) {
@@ -88,7 +101,7 @@ public class LanguageManager {
/**
* Loads a Floodgate locale from resources; if the file doesn't exist it just logs a warning
*
* @param locale Locale to load
* @param locale locale to load
*/
public void loadLocale(String locale) {
locale = formatLocale(locale);
@@ -120,9 +133,9 @@ public class LanguageManager {
/**
* Get a formatted language string with the default locale for Floodgate
*
* @param key Language string to translate
* @param values Values to put into the string
* @return Translated string or the original message if it was not found in the given locale
* @param key language string to translate
* @param values values to put into the string
* @return translated string or the original message if it was not found in the given locale
*/
public String getLogString(String key, Object... values) {
return getString(key, defaultLocale, values);
@@ -131,10 +144,10 @@ public class LanguageManager {
/**
* Get a formatted language string with the given locale for Floodgate
*
* @param key Language string to translate
* @param locale Locale to translate to
* @param values Values to put into the string
* @return Translated string or the original message if it was not found in the given locale
* @param key language string to translate
* @param locale locale to translate to
* @param values values to put into the string
* @return translated string or the original message if it was not found in the given locale
*/
public String getString(String key, String locale, Object... values) {
locale = formatLocale(locale);
@@ -162,23 +175,9 @@ public class LanguageManager {
return MessageFormat.format(formatString.replace("'", "''").replace("&", "\u00a7"), values);
}
/**
* Cleans up and formats a locale string
*
* @param locale The locale to format
* @return The formatted locale
*/
private static String formatLocale(String locale) {
try {
String[] parts = locale.toLowerCase().split("_");
return parts[0] + "_" + parts[1].toUpperCase();
} catch (Exception e) {
return locale;
}
}
/**
* Ensures that the given locale is supported by Floodgate
*
* @param locale the locale to validate
* @return true if the given locale is supported by Floodgate
*/
@@ -187,7 +186,10 @@ public class LanguageManager {
return false;
}
if (LanguageManager.class.getResource("/languages/texts/" + locale + ".properties") == null) {
URL languageFile = LanguageManager.class
.getResource("/languages/texts/" + locale + ".properties");
if (languageFile == null) {
logger.warn(locale + " is not a supported Floodgate language.");
return false;
}

View File

@@ -31,7 +31,9 @@ public final class MessageFormatter {
public static String format(String message, Object... arguments) {
// simple variant of slf4j's parameters.
if (arguments == null || arguments.length == 0) return message;
if (arguments == null || arguments.length == 0) {
return message;
}
String[] args = new String[arguments.length];
for (int i = 0; i < arguments.length; i++) {
@@ -49,30 +51,36 @@ public final class MessageFormatter {
if (currentIndex == -1) {
// no parameter places left in message,
// we'll ignore the remaining parameters and return the message
if (previousIndex == -1) return message;
else {
if (previousIndex == -1) {
return message;
} else {
stringBuilder.append(message.substring(previousIndex));
return stringBuilder.toString();
}
}
if (previousIndex == -1) stringBuilder.append(message, 0, currentIndex);
else stringBuilder.append(message, previousIndex, currentIndex);
if (previousIndex == -1) {
stringBuilder.append(message, 0, currentIndex);
} else {
stringBuilder.append(message, previousIndex, currentIndex);
}
stringBuilder.append(argument);
// we finished this argument, so we're past the current delimiter
previousIndex = currentIndex + DELIM_LENGTH;
}
if (previousIndex != message.length())
if (previousIndex != message.length()) {
stringBuilder.append(message, previousIndex, message.length());
}
return stringBuilder.toString();
}
public static int getArgsContentLength(String... args) {
int length = 0;
for (String arg : args)
for (String arg : args) {
length += arg.length();
}
return length;
}
}

View File

@@ -25,30 +25,69 @@
package org.geysermc.floodgate.util;
import com.google.common.base.Preconditions;
import lombok.Setter;
import javax.annotation.Nullable;
import java.lang.reflect.*;
import static org.geysermc.floodgate.util.MessageFormatter.format;
import com.google.common.base.Preconditions;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import javax.annotation.Nullable;
import lombok.Setter;
public final class ReflectionUtils {
private static final Field MODIFIERS_FIELD;
/**
* The package name that is shared between all the {@link #getPrefixedClass(String)} calls so
* that the className will be a lot shorter.
* Example net.minecraft.server.v1_8R3.PacketHandshakingInSetProtocol will become
* PacketHandshakingInSetProtocol if the prefix is set to net.minecraft.server.v1_8R3
* that the className will be a lot shorter. Example net.minecraft.server.v1_8R3.PacketHandshakingInSetProtocol
* will become PacketHandshakingInSetProtocol if the prefix is set to
* net.minecraft.server.v1_8R3
*/
@Setter
private static String prefix = null;
@Setter private static String prefix = null;
static {
Field modifiersField = null;
try {
modifiersField = Field.class.getDeclaredField("modifiers");
} catch (NoSuchFieldException ignored) {
// Java 12 compatibility, thanks to https://github.com/powermock/powermock/pull/1010
try {
Method declaredFields = getMethod(Class.class, "getDeclaredFields0", boolean.class);
if (declaredFields == null) {
throw new NoSuchMethodException();
}
Field[] fields = castedInvoke(Field.class, declaredFields, false);
if (fields == null) {
throw new Exception();
}
for (Field field : fields) {
if ("modifiers".equals(field.getName())) {
modifiersField = field;
break;
}
}
} catch (Exception exception) {
throw new RuntimeException(format(
"Cannot find the modifiers field :/\nJava version: {}\nVendor: {} ({})",
System.getProperty("java.version"),
System.getProperty("java.vendor"),
System.getProperty("java.vendor.url")
));
}
}
Preconditions.checkNotNull(modifiersField, "Modifiers field cannot be null!");
MODIFIERS_FIELD = modifiersField;
}
/**
* Get a class that is prefixed with the prefix provided in {@link #setPrefix(String)}.
* Calling this method is equal to calling {@link #getClass(String)}
* with <i>prefix</i>.<i>classname</i> as class name.
* Get a class that is prefixed with the prefix provided in {@link #setPrefix(String)}. Calling
* this method is equal to calling {@link #getClass(String)} with <i>prefix</i>.<i>classname</i>
* as class name.
*
* @param className the prefix class to find
* @return the class if found, otherwise null
@@ -59,11 +98,10 @@ public final class ReflectionUtils {
}
/**
* Get the class from a class name.
* Calling this method is equal to calling {@link Class#forName(String)} where String is the
* class name.<br>
* This method will return null when the class isn't found instead of throwing the exception,
* but the exception will be printed to the console.
* Get the class from a class name. Calling this method is equal to calling {@link
* Class#forName(String)} where String is the class name.<br> This method will return null when
* the class isn't found instead of throwing the exception, but the exception will be printed to
* the console.
*
* @param className the name of the class to find
* @return the class or null if the class wasn't found.
@@ -79,12 +117,11 @@ public final class ReflectionUtils {
}
/**
* Get a field of a class.
* Calling this method is equal to calling {@link Class#getField(String)} where String is the
* fieldName when isPublic is true and calling this method is equal to calling
* {@link Class#getDeclaredField(String)} where String is the fieldName when isPublic is
* false.<br>
* Please note that this method will return null instead of throwing the exception.
* Get a field of a class. Calling this method is equal to calling {@link
* Class#getField(String)} where String is the fieldName when isPublic is true and calling this
* method is equal to calling {@link Class#getDeclaredField(String)} where String is the
* fieldName when isPublic is false.<br> Please note that this method will return null instead
* of throwing the exception.
*
* @param clazz the class name to get the field from
* @param fieldName the name of the field
@@ -104,9 +141,8 @@ public final class ReflectionUtils {
}
/**
* Get a field from a class, it doesn't matter if the field is public or not.
* This method will first try to get a declared field and if that failed it'll try to get a
* public field.
* Get a field from a class, it doesn't matter if the field is public or not. This method will
* first try to get a declared field and if that failed it'll try to get a public field.
*
* @param clazz the class to get the field from
* @param fieldName the name of the field
@@ -134,15 +170,17 @@ public final class ReflectionUtils {
Field[] fields = declared ? clazz.getDeclaredFields() : clazz.getFields();
for (Field field : fields) {
makeAccessible(field);
if (field.getType() == fieldType) return field;
if (field.getType() == fieldType) {
return field;
}
}
return null;
}
/**
* Get a declared field from a class without having to provide a field name.<br>
* Calling this method is equal to calling {@link #getFieldOfType(Class, Class, boolean)}
* with declared = true.
* Get a declared field from a class without having to provide a field name.<br> Calling this
* method is equal to calling {@link #getFieldOfType(Class, Class, boolean)} with declared =
* true.
*
* @param clazz the class to search the field from
* @param fieldType the type of the declared field
@@ -154,10 +192,9 @@ public final class ReflectionUtils {
}
/**
* Get the value of a field.
* This method first makes the field accessible and then gets the value.<br>
* This method will return null instead of throwing an exception,
* but it'll log the stacktrace to the console.
* Get the value of a field. This method first makes the field accessible and then gets the
* value.<br> This method will return null instead of throwing an exception, but it'll log the
* stacktrace to the console.
*
* @param instance the instance to get the value from
* @param field the field to get the value from
@@ -201,8 +238,7 @@ public final class ReflectionUtils {
}
/**
* Set the value of a field.
* This method make the field accessible and then sets the value.<br>
* Set the value of a field. This method make the field accessible and then sets the value.<br>
* This method doesn't throw an exception when failed, but it'll log the error to the console.
*
* @param instance the instance to set the value to
@@ -219,8 +255,8 @@ public final class ReflectionUtils {
}
/**
* Set the value of a field.
* This method finds the field, and then calls {@link #setValue(Object, Field, Object)}.
* Set the value of a field. This method finds the field, and then calls {@link
* #setValue(Object, Field, Object)}.
*
* @param instance the instance to set the value to
* @param fieldName the field to set the value to
@@ -236,10 +272,9 @@ public final class ReflectionUtils {
}
/**
* Set the value of a <b>final</b> field.
* This method first makes the field accessible, then removes the final modifier and then
* sets the value.<br>
* This method will not throw exceptions when failed, but it'll log the error to the console.
* Set the value of a <b>final</b> field. This method first makes the field accessible, then
* removes the final modifier and then sets the value.<br> This method will not throw exceptions
* when failed, but it'll log the error to the console.
*
* @param instance the instance to set the value to
* @param field the field to set the value to
@@ -264,11 +299,10 @@ public final class ReflectionUtils {
}
/**
* Get a method from a class, it doesn't matter if the field is public or not.
* This method will first try to get a declared field and if that failed it'll try to get a
* public field.<br>
* Instead of throwing an exception when the method wasn't found, it will return null, but
* the exception will be printed in the console.
* Get a method from a class, it doesn't matter if the field is public or not. This method will
* first try to get a declared field and if that failed it'll try to get a public field.<br>
* Instead of throwing an exception when the method wasn't found, it will return null, but the
* exception will be printed in the console.
*
* @param clazz the class to get the method from
* @param method the name of the method to find
@@ -290,9 +324,8 @@ public final class ReflectionUtils {
}
/**
* Get a method from a class, it doesn't matter if the method is public or not.
* This method will first try to get a declared method and if that fails it'll try to get a
* public method.
* Get a method from a class, it doesn't matter if the method is public or not. This method will
* first try to get a declared method and if that fails it'll try to get a public method.
*
* @param clazz the class to get the method from
* @param methodName the name of the method to find
@@ -309,9 +342,8 @@ public final class ReflectionUtils {
}
/**
* Get a method from a class, it doesn't matter if the method is public or not.
* This method will first try to get a declared method and if that fails it'll try to get a
* public method.
* Get a method from a class, it doesn't matter if the method is public or not. This method will
* first try to get a declared method and if that fails it'll try to get a public method.
*
* @param instance the class to get the method from
* @param methodName the name of the method to find
@@ -402,41 +434,4 @@ public final class ReflectionUtils {
}
return accessibleObject;
}
static {
Field modifiersField = null;
try {
modifiersField = Field.class.getDeclaredField("modifiers");
} catch (NoSuchFieldException ignored) {
// Java 12 compatibility, thanks to https://github.com/powermock/powermock/pull/1010
try {
Method declaredFields = getMethod(Class.class, "getDeclaredFields0", boolean.class);
if (declaredFields == null) {
throw new NoSuchMethodException();
}
Field[] fields = castedInvoke(Field.class, declaredFields, false);
if (fields == null) {
throw new Exception();
}
for (Field field : fields) {
if ("modifiers".equals(field.getName())) {
modifiersField = field;
break;
}
}
} catch (Exception exception) {
throw new RuntimeException(format("Cannot find the modifiers field :/\n" +
"Java version: {}\nVendor: {} ({})",
System.getProperty("java.version"),
System.getProperty("java.vendor"),
System.getProperty("java.vendor.url")
));
}
}
Preconditions.checkNotNull(modifiersField, "Modifiers field cannot be null!");
MODIFIERS_FIELD = modifiersField;
}
}

View File

@@ -1,51 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright (c) 2019-2020 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/Floodgate
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<artifactId>parent</artifactId>
<groupId>org.geysermc.floodgate.database</groupId>
<modelVersion>4.0.0</modelVersion>
<modules>
<module>sqlite</module>
</modules>
<name>database</name>
<packaging>pom</packaging>
<parent>
<artifactId>parent</artifactId>
<groupId>org.geysermc.floodgate</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.geysermc.floodgate.database</groupId>
<artifactId>parent</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<name>database</name>
<modules>
<module>sqlite</module>
</modules>
<properties>
<outputName>floodgate-${project.name}-database</outputName>
</properties>
<version>1.0-SNAPSHOT</version>
</project>

View File

@@ -1,62 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright (c) 2019-2020 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/Floodgate
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>parent</artifactId>
<groupId>org.geysermc.floodgate.database</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>sqlite</artifactId>
<dependencies>
<dependency>
<groupId>org.xerial</groupId>
<artifactId>sqlite-jdbc</artifactId>
<version>3.30.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.geysermc.floodgate</groupId>
<artifactId>common</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<resources>
<resource>
@@ -84,4 +30,33 @@
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.xerial</groupId>
<artifactId>sqlite-jdbc</artifactId>
<version>3.30.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.geysermc.floodgate</groupId>
<artifactId>common</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
<scope>provided</scope>
</dependency>
</dependencies>
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>parent</artifactId>
<groupId>org.geysermc.floodgate.database</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
</project>

View File

@@ -27,14 +27,18 @@ package org.geysermc.floodgate.database;
import com.google.inject.Inject;
import com.google.inject.name.Named;
import org.geysermc.floodgate.link.CommonPlayerLink;
import org.geysermc.floodgate.util.LinkedPlayer;
import java.nio.file.Path;
import java.sql.*;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import org.geysermc.floodgate.link.CommonPlayerLink;
import org.geysermc.floodgate.util.LinkedPlayer;
public class SqliteDatabase extends CommonPlayerLink {
private Connection connection;
@@ -51,7 +55,9 @@ public class SqliteDatabase extends CommonPlayerLink {
connection = DriverManager.getConnection("jdbc:sqlite:" + databasePath.toString());
Statement statement = connection.createStatement();
statement.setQueryTimeout(30); // set timeout to 30 sec.
statement.executeUpdate("create table if not exists LinkedPlayers (bedrockId string, javaUniqueId string, javaUsername string)");
statement.executeUpdate(
"create table if not exists LinkedPlayers (bedrockId string, javaUniqueId string, javaUsername string)"
);
} catch (ClassNotFoundException exception) {
getLogger().error("The required class to load the SQLite database wasn't found");
} catch (SQLException exception) {
@@ -73,10 +79,14 @@ public class SqliteDatabase extends CommonPlayerLink {
public CompletableFuture<LinkedPlayer> getLinkedPlayer(UUID bedrockId) {
return CompletableFuture.supplyAsync(() -> {
try {
PreparedStatement query = connection.prepareStatement("select * from LinkedPlayers where bedrockId = ?");
PreparedStatement query = connection.prepareStatement(
"select * from LinkedPlayers where bedrockId = ?"
);
query.setString(1, bedrockId.toString());
ResultSet result = query.executeQuery();
if (!result.next()) return null;
if (!result.next()) {
return null;
}
String javaUsername = result.getString("javaUsername");
UUID javaUniqueId = UUID.fromString(result.getString("javaUniqueId"));
@@ -92,7 +102,9 @@ public class SqliteDatabase extends CommonPlayerLink {
public CompletableFuture<Boolean> isLinkedPlayer(UUID bedrockId) {
return CompletableFuture.supplyAsync(() -> {
try {
PreparedStatement query = connection.prepareStatement("select javaUniqueId from LinkedPlayers where bedrockId = ? or javaUniqueId = ?");
PreparedStatement query = connection.prepareStatement(
"select javaUniqueId from LinkedPlayers where bedrockId = ? or javaUniqueId = ?"
);
query.setString(1, bedrockId.toString());
query.setString(2, bedrockId.toString());
ResultSet result = query.executeQuery();
@@ -110,7 +122,9 @@ public class SqliteDatabase extends CommonPlayerLink {
public CompletableFuture<Void> linkPlayer(UUID bedrockId, UUID javaId, String username) {
return CompletableFuture.runAsync(() -> {
try {
PreparedStatement query = connection.prepareStatement("insert into LinkedPlayers values(?, ?, ?)");
PreparedStatement query = connection.prepareStatement(
"insert into LinkedPlayers values(?, ?, ?)"
);
query.setString(1, bedrockId.toString());
query.setString(2, javaId.toString());
query.setString(3, username);
@@ -126,7 +140,9 @@ public class SqliteDatabase extends CommonPlayerLink {
public CompletableFuture<Void> unlinkPlayer(UUID javaId) {
return CompletableFuture.runAsync(() -> {
try {
PreparedStatement query = connection.prepareStatement("delete from LinkedPlayers where javaUniqueId = ? or bedrockId = ?");
PreparedStatement query = connection.prepareStatement(
"delete from LinkedPlayers where javaUniqueId = ? or bedrockId = ?"
);
query.setString(1, javaId.toString());
query.setString(2, javaId.toString());
query.executeUpdate();

64
pom.xml
View File

@@ -2,11 +2,31 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.geysermc.floodgate</groupId>
<artifactId>parent</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
<scope>provided</scope>
</dependency>
</dependencies>
<description>Allows Bedrock players to join Java edition servers while keeping the server in online mode</description>
<distributionManagement>
<repository>
<id>releases</id>
<name>nukkitx-releases</name>
<url>https://repo.nukkitx.com/maven-releases</url>
</repository>
<snapshotRepository>
<id>snapshots</id>
<name>nukkitx-snapshots</name>
<url>https://repo.nukkitx.com/maven-snapshots</url>
</snapshotRepository>
</distributionManagement>
<groupId>org.geysermc.floodgate</groupId>
<modelVersion>4.0.0</modelVersion>
<modules>
<module>api</module>
<module>common</module>
@@ -15,10 +35,13 @@
<module>velocity</module>
<module>database</module>
</modules>
<packaging>pom</packaging>
<name>floodgate</name>
<description>Allows Bedrock players to join Java edition servers while keeping online mode</description>
<url>https://github.com/GeyserMC/Floodgate</url>
<organization>
<name>GeyserMC</name>
<url>https://geysermc.org/</url>
</organization>
<packaging>pom</packaging>
<properties>
<geyser.version>1.1.0</geyser.version>
@@ -33,36 +56,13 @@
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<organization>
<name>GeyserMC</name>
<url>https://geysermc.org/</url>
</organization>
<scm>
<connection>scm:git:https://github.com/GeyserMC/Floodgate.git</connection>
<developerConnection>scm:git:git@github.com:GeyserMC/Floodgate.git</developerConnection>
<url>https://github.com/GeyserMC/Floodgate/</url>
</scm>
<distributionManagement>
<repository>
<id>releases</id>
<name>nukkitx-releases</name>
<url>https://repo.nukkitx.com/maven-releases</url>
</repository>
<snapshotRepository>
<id>snapshots</id>
<name>nukkitx-snapshots</name>
<url>https://repo.nukkitx.com/maven-snapshots</url>
</snapshotRepository>
</distributionManagement>
<url>https://github.com/GeyserMC/Floodgate</url>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
<scope>provided</scope>
</dependency>
</dependencies>
<version>1.0-SNAPSHOT</version>
</project>

View File

@@ -2,48 +2,7 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.geysermc.floodgate</groupId>
<artifactId>parent</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>spigot</artifactId>
<repositories>
<repository>
<id>spigot-repo</id>
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<version>${spigot.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-transport</artifactId>
<version>4.1.43.Final</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-codec</artifactId>
<version>4.1.43.Final</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.geysermc.floodgate</groupId>
<artifactId>common</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
<build>
<resources>
<resource>
@@ -71,4 +30,45 @@
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<version>${spigot.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-transport</artifactId>
<version>4.1.43.Final</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-codec</artifactId>
<version>4.1.43.Final</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.geysermc.floodgate</groupId>
<artifactId>common</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.geysermc.floodgate</groupId>
<artifactId>parent</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<repositories>
<repository>
<id>spigot-repo</id>
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
</repository>
</repositories>
</project>

View File

@@ -26,31 +26,21 @@
package org.geysermc.floodgate;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Module;
import com.google.inject.name.Named;
import org.bukkit.Bukkit;
import org.bukkit.plugin.java.JavaPlugin;
import org.geysermc.floodgate.api.FloodgateApi;
import org.geysermc.floodgate.api.inject.PlatformInjector;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.config.loader.ConfigLoader;
import org.geysermc.floodgate.link.PlayerLinkLoader;
import org.geysermc.floodgate.util.LanguageManager;
import java.nio.file.Path;
public final class SpigotPlatform extends FloodgatePlatform {
@Inject private JavaPlugin plugin;
@Inject
public SpigotPlatform(@Named("dataDirectory") Path dataDirectory, FloodgateApi api,
ConfigLoader configLoader, PlayerLinkLoader playerLinkLoader,
HandshakeHandler handshakeHandler, FloodgateLogger logger,
PlatformInjector platformInjector, LanguageManager languageManager,
Injector injector) {
super(dataDirectory, api, configLoader, playerLinkLoader, handshakeHandler,
logger, platformInjector, languageManager, injector);
public SpigotPlatform(FloodgateApi api, LanguageManager languageManager,
PlatformInjector platformInjector, FloodgateLogger logger) {
super(api, languageManager, platformInjector, logger);
}
@Override

View File

@@ -28,7 +28,12 @@ package org.geysermc.floodgate;
import com.google.inject.Guice;
import com.google.inject.Injector;
import org.bukkit.plugin.java.JavaPlugin;
import org.geysermc.floodgate.module.*;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.module.CommandModule;
import org.geysermc.floodgate.module.CommonModule;
import org.geysermc.floodgate.module.SpigotAddonModule;
import org.geysermc.floodgate.module.SpigotListenerModule;
import org.geysermc.floodgate.module.SpigotPlatformModule;
import org.geysermc.floodgate.util.ReflectionUtils;
public final class SpigotPlugin extends JavaPlugin {
@@ -48,10 +53,8 @@ public final class SpigotPlugin extends JavaPlugin {
platform = injector.getInstance(SpigotPlatform.class);
long endCtm = System.currentTimeMillis();
getLogger().info(platform.getLanguageManager().getLogString(
"floodgate.core.finish",
endCtm - ctm
));
injector.getInstance(FloodgateLogger.class)
.translatedInfo("floodgate.core.finish", endCtm - ctm);
}
@Override

View File

@@ -40,14 +40,16 @@ public final class SpigotDataAddon implements InjectorAddon {
@Inject private FloodgateConfig config;
@Inject private FloodgateLogger logger;
@Inject @Named("playerAttribute")
@Inject
@Named("playerAttribute")
private AttributeKey<FloodgatePlayer> playerAttribute;
@Inject @Named("packetHandler")
@Inject
@Named("packetHandler")
private String packetHandlerName;
@Override
public void onInject(Channel channel, boolean proxyToServer) {
public void onInject(Channel channel, boolean toServer) {
channel.pipeline().addBefore(
packetHandlerName, "floodgate_data_handler",
new SpigotDataHandler(config, handshakeHandler, playerAttribute, logger)

View File

@@ -25,9 +25,23 @@
package org.geysermc.floodgate.addon.data;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.geysermc.floodgate.util.ReflectionUtils.getCastedValue;
import static org.geysermc.floodgate.util.ReflectionUtils.getFieldOfType;
import static org.geysermc.floodgate.util.ReflectionUtils.getMethod;
import static org.geysermc.floodgate.util.ReflectionUtils.getPrefixedClass;
import static org.geysermc.floodgate.util.ReflectionUtils.makeAccessible;
import static org.geysermc.floodgate.util.ReflectionUtils.setValue;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.util.AttributeKey;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.UUID;
import lombok.RequiredArgsConstructor;
import org.geysermc.floodgate.HandshakeHandler;
import org.geysermc.floodgate.HandshakeHandler.HandshakeResult;
@@ -37,16 +51,6 @@ import org.geysermc.floodgate.config.FloodgateConfig;
import org.geysermc.floodgate.util.BedrockData;
import org.geysermc.floodgate.util.ReflectionUtils;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.UUID;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.geysermc.floodgate.util.ReflectionUtils.*;
@RequiredArgsConstructor
public final class SpigotDataHandler extends SimpleChannelInboundHandler<Object> {
private static final Field SOCKET_ADDRESS;
@@ -69,16 +73,89 @@ public final class SpigotDataHandler extends SimpleChannelInboundHandler<Object>
private static final Field PROTOCOL_STATE;
private static final Object READY_TO_ACCEPT_PROTOCOL_STATE;
static {
Class<?> networkManager = getPrefixedClass("NetworkManager");
checkNotNull(networkManager, "NetworkManager class cannot be null");
SOCKET_ADDRESS = getFieldOfType(networkManager, SocketAddress.class, false);
checkNotNull(SOCKET_ADDRESS, "SocketAddress field cannot be null");
HANDSHAKE_PACKET = getPrefixedClass("PacketHandshakingInSetProtocol");
checkNotNull(HANDSHAKE_PACKET, "PacketHandshakingInSetProtocol cannot be null");
HANDSHAKE_HOST = getFieldOfType(HANDSHAKE_PACKET, String.class);
checkNotNull(HANDSHAKE_HOST, "Host field from handshake packet cannot be null");
LOGIN_START_PACKET = getPrefixedClass("PacketLoginInStart");
checkNotNull(LOGIN_START_PACKET, "PacketLoginInStart cannot be null");
GAME_PROFILE = ReflectionUtils.getClass("com.mojang.authlib.GameProfile");
checkNotNull(GAME_PROFILE, "GameProfile class cannot be null");
Constructor<?> gameProfileConstructor = null;
try {
gameProfileConstructor = GAME_PROFILE.getConstructor(UUID.class, String.class);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
GAME_PROFILE_CONSTRUCTOR = gameProfileConstructor;
checkNotNull(GAME_PROFILE_CONSTRUCTOR, "GameProfileConstructor cannot be null");
LOGIN_LISTENER = getPrefixedClass("LoginListener");
checkNotNull(LOGIN_LISTENER, "LoginListener cannot be null");
LOGIN_PROFILE = getFieldOfType(LOGIN_LISTENER, GAME_PROFILE);
checkNotNull(LOGIN_PROFILE, "Profile from LoginListener cannot be null");
INIT_UUID = getMethod(LOGIN_LISTENER, "initUUID");
checkNotNull(INIT_UUID, "initUUID from LoginListener cannot be null");
Field protocolStateField = null;
for (Field field : LOGIN_LISTENER.getDeclaredFields()) {
if (field.getType().isEnum()) {
protocolStateField = field;
}
}
PROTOCOL_STATE = protocolStateField;
checkNotNull(PROTOCOL_STATE, "Protocol state field from LoginListener cannot be null");
Enum<?>[] protocolStates = (Enum<?>[]) PROTOCOL_STATE.getType().getEnumConstants();
Object readyToAcceptState = null;
for (Enum<?> protocolState : protocolStates) {
if (protocolState.name().equals("READY_TO_ACCEPT")) {
readyToAcceptState = protocolState;
}
}
READY_TO_ACCEPT_PROTOCOL_STATE = readyToAcceptState;
checkNotNull(READY_TO_ACCEPT_PROTOCOL_STATE,
"Ready to accept state from Protocol state cannot be null");
Class<?> packetListenerClass = getPrefixedClass("PacketListener");
PACKET_LISTENER = getFieldOfType(networkManager, packetListenerClass);
checkNotNull(PACKET_LISTENER, "PacketListener cannot be null");
LOGIN_HANDLER = getPrefixedClass("LoginListener$LoginHandler");
checkNotNull(LOGIN_HANDLER, "LoginHandler cannot be null");
Constructor<?> loginHandlerConstructor = null;
try {
loginHandlerConstructor = makeAccessible(
LOGIN_HANDLER.getDeclaredConstructor(LOGIN_LISTENER));
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
LOGIN_HANDLER_CONSTRUCTOR = loginHandlerConstructor;
checkNotNull(LOGIN_HANDLER_CONSTRUCTOR, "LoginHandler constructor cannot be null");
FIRE_LOGIN_EVENTS = getMethod(LOGIN_HANDLER, "fireEvents");
checkNotNull(FIRE_LOGIN_EVENTS, "fireEvents from LoginHandler cannot be null");
}
/* per player stuff */
private final FloodgateConfig config;
private final HandshakeHandler handshakeHandler;
private final AttributeKey<FloodgatePlayer> playerAttribute;
private final FloodgateLogger logger;
private Object networkManager;
private FloodgatePlayer fPlayer;
private boolean bungee;
private boolean done;
@Override
@@ -103,8 +180,10 @@ public final class SpigotDataHandler extends SimpleChannelInboundHandler<Object>
break;
case INVALID_DATA_LENGTH:
int dataLength = result.getBedrockData().getDataLength();
logger.info(config.getMessages().getInvalidArgumentsLength(),
BedrockData.EXPECTED_LENGTH, dataLength);
logger.info(
config.getMessages().getInvalidArgumentsLength(),
BedrockData.EXPECTED_LENGTH, dataLength
);
ctx.close();
return;
default: // only continue when SUCCESS
@@ -182,78 +261,4 @@ public final class SpigotDataHandler extends SimpleChannelInboundHandler<Object>
super.exceptionCaught(ctx, cause);
cause.printStackTrace();
}
static {
Class<?> networkManager = getPrefixedClass("NetworkManager");
checkNotNull(networkManager, "NetworkManager class cannot be null");
SOCKET_ADDRESS = getFieldOfType(networkManager, SocketAddress.class, false);
checkNotNull(SOCKET_ADDRESS, "SocketAddress field cannot be null");
HANDSHAKE_PACKET = getPrefixedClass("PacketHandshakingInSetProtocol");
checkNotNull(HANDSHAKE_PACKET, "PacketHandshakingInSetProtocol cannot be null");
HANDSHAKE_HOST = getFieldOfType(HANDSHAKE_PACKET, String.class);
checkNotNull(HANDSHAKE_HOST, "Host field from handshake packet cannot be null");
LOGIN_START_PACKET = getPrefixedClass("PacketLoginInStart");
checkNotNull(LOGIN_START_PACKET, "PacketLoginInStart cannot be null");
GAME_PROFILE = ReflectionUtils.getClass("com.mojang.authlib.GameProfile");
checkNotNull(GAME_PROFILE, "GameProfile class cannot be null");
Constructor<?> gameProfileConstructor = null;
try {
gameProfileConstructor = GAME_PROFILE.getConstructor(UUID.class, String.class);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
GAME_PROFILE_CONSTRUCTOR = gameProfileConstructor;
checkNotNull(GAME_PROFILE_CONSTRUCTOR, "GameProfileConstructor cannot be null");
LOGIN_LISTENER = getPrefixedClass("LoginListener");
checkNotNull(LOGIN_LISTENER, "LoginListener cannot be null");
LOGIN_PROFILE = getFieldOfType(LOGIN_LISTENER, GAME_PROFILE);
checkNotNull(LOGIN_PROFILE, "Profile from LoginListener cannot be null");
INIT_UUID = getMethod(LOGIN_LISTENER, "initUUID");
checkNotNull(INIT_UUID, "initUUID from LoginListener cannot be null");
Field protocolStateField = null;
for (Field field : LOGIN_LISTENER.getDeclaredFields()) {
if (field.getType().isEnum()) {
protocolStateField = field;
}
}
PROTOCOL_STATE = protocolStateField;
checkNotNull(PROTOCOL_STATE, "Protocol state field from LoginListener cannot be null");
Enum<?>[] protocolStates = (Enum<?>[]) PROTOCOL_STATE.getType().getEnumConstants();
Object readyToAcceptState = null;
for (Enum<?> protocolState : protocolStates) {
if (protocolState.name().equals("READY_TO_ACCEPT")) {
readyToAcceptState = protocolState;
}
}
READY_TO_ACCEPT_PROTOCOL_STATE = readyToAcceptState;
checkNotNull(READY_TO_ACCEPT_PROTOCOL_STATE,
"Ready to accept state from Protocol state cannot be null");
Class<?> packetListenerClass = getPrefixedClass("PacketListener");
PACKET_LISTENER = getFieldOfType(networkManager, packetListenerClass);
checkNotNull(PACKET_LISTENER, "PacketListener cannot be null");
LOGIN_HANDLER = getPrefixedClass("LoginListener$LoginHandler");
checkNotNull(LOGIN_HANDLER, "LoginHandler cannot be null");
Constructor<?> loginHandlerConstructor = null;
try {
loginHandlerConstructor = makeAccessible(LOGIN_HANDLER.getDeclaredConstructor(LOGIN_LISTENER));
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
LOGIN_HANDLER_CONSTRUCTOR = loginHandlerConstructor;
checkNotNull(LOGIN_HANDLER_CONSTRUCTOR, "LoginHandler constructor cannot be null");
FIRE_LOGIN_EVENTS = getMethod(LOGIN_HANDLER, "fireEvents");
checkNotNull(FIRE_LOGIN_EVENTS, "fireEvents from LoginHandler cannot be null");
}
}

View File

@@ -45,9 +45,8 @@ public final class SpigotCommandRegistration implements CommandRegistration {
public void register(Command command) {
String defaultLocale = languageManager.getDefaultLocale();
plugin.getCommand(command.getName()).setExecutor(
new SpigotCommandWrapper(commandUtil, command, defaultLocale)
);
plugin.getCommand(command.getName())
.setExecutor(new SpigotCommandWrapper(commandUtil, command, defaultLocale));
}
@RequiredArgsConstructor

View File

@@ -25,13 +25,12 @@
package org.geysermc.floodgate.inject.spigot;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import lombok.AllArgsConstructor;
import lombok.Getter;
@AllArgsConstructor
@SuppressWarnings({"unchecked", "rawtypes"})
@@ -78,11 +77,21 @@ public abstract class CustomList implements List {
}
}
@Override
public synchronized void add(int index, Object element) {
originalList.add(index, element);
}
@Override
public synchronized boolean remove(Object o) {
return originalList.remove(o);
}
@Override
public synchronized Object remove(int index) {
return originalList.remove(index);
}
@Override
public synchronized boolean containsAll(Collection c) {
return originalList.containsAll(c);
@@ -133,16 +142,6 @@ public abstract class CustomList implements List {
return originalList.set(index, element);
}
@Override
public synchronized void add(int index, Object element) {
originalList.add(index, element);
}
@Override
public synchronized Object remove(int index) {
return originalList.remove(index);
}
@Override
public synchronized int indexOf(Object o) {
return originalList.indexOf(o);

View File

@@ -25,23 +25,33 @@
package org.geysermc.floodgate.inject.spigot;
import io.netty.channel.*;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.geysermc.floodgate.inject.CommonPlatformInjector;
import org.geysermc.floodgate.util.ReflectionUtils;
import java.lang.reflect.*;
import java.util.*;
@RequiredArgsConstructor
public final class SpigotInjector extends CommonPlatformInjector {
private Object serverConnection;
private final Set<Channel> injectedClients = new HashSet<>();
@Getter private boolean injected = false;
private Object serverConnection;
private String injectedFieldName;
@Getter private boolean injected = false;
@Override
@SuppressWarnings("SynchronizationOnLocalVariableOrMethodParameter")
public boolean inject() throws Exception {
@@ -50,11 +60,11 @@ public final class SpigotInjector extends CommonPlatformInjector {
}
if (getServerConnection() != null) {
for (Field f : serverConnection.getClass().getDeclaredFields()) {
if (f.getType() == List.class) {
f.setAccessible(true);
for (Field field : serverConnection.getClass().getDeclaredFields()) {
if (field.getType() == List.class) {
field.setAccessible(true);
ParameterizedType parameterType = ((ParameterizedType) f.getGenericType());
ParameterizedType parameterType = ((ParameterizedType) field.getGenericType());
Type listType = parameterType.getActualTypeArguments()[0];
// the list we search has ChannelFuture as type
@@ -62,30 +72,30 @@ public final class SpigotInjector extends CommonPlatformInjector {
continue;
}
injectedFieldName = f.getName();
List<?> newList = new CustomList((List<?>) f.get(serverConnection)) {
injectedFieldName = field.getName();
List<?> newList = new CustomList((List<?>) field.get(serverConnection)) {
@Override
public void onAdd(Object o) {
public void onAdd(Object object) {
try {
injectClient((ChannelFuture) o);
} catch (Exception e) {
e.printStackTrace();
injectClient((ChannelFuture) object);
} catch (Exception exception) {
exception.printStackTrace();
}
}
};
// inject existing
synchronized (newList) {
for (Object o : newList) {
for (Object object : newList) {
try {
injectClient((ChannelFuture) o);
} catch (Exception e) {
e.printStackTrace();
injectClient((ChannelFuture) object);
} catch (Exception exception) {
exception.printStackTrace();
}
}
}
f.set(serverConnection, newList);
field.set(serverConnection, newList);
injected = true;
return true;
}
@@ -129,6 +139,7 @@ public final class SpigotInjector extends CommonPlatformInjector {
if (serverConnection != null) {
Field field = ReflectionUtils.getField(serverConnection.getClass(), injectedFieldName);
List<?> list = (List<?>) ReflectionUtils.getValue(serverConnection, field);
if (list instanceof CustomList) {
CustomList customList = (CustomList) list;
ReflectionUtils.setValue(serverConnection, field, customList.getOriginalList());
@@ -143,15 +154,17 @@ public final class SpigotInjector extends CommonPlatformInjector {
}
public Object getServerConnection() throws IllegalAccessException, InvocationTargetException {
if (serverConnection != null) return serverConnection;
if (serverConnection != null) {
return serverConnection;
}
Class<?> minecraftServer = ReflectionUtils.getPrefixedClass("MinecraftServer");
assert minecraftServer != null;
Object minecraftServerInstance = ReflectionUtils.invokeStatic(minecraftServer, "getServer");
for (Method m : minecraftServer.getDeclaredMethods()) {
if (m.getReturnType().getSimpleName().equals("ServerConnection")) {
if (m.getParameterTypes().length == 0) {
serverConnection = m.invoke(minecraftServerInstance);
for (Method method : minecraftServer.getDeclaredMethods()) {
if (method.getReturnType().getSimpleName().equals("ServerConnection")) {
if (method.getParameterTypes().length == 0) {
serverConnection = method.invoke(minecraftServerInstance);
}
}
}

View File

@@ -26,6 +26,7 @@
package org.geysermc.floodgate.listener;
import com.google.inject.Inject;
import java.util.UUID;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
@@ -39,8 +40,6 @@ import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.api.player.FloodgatePlayer;
import org.geysermc.floodgate.util.LanguageManager;
import java.util.UUID;
public final class SpigotListener implements Listener {
@Inject private SimpleFloodgateApi api;
@Inject private FloodgateLogger logger;
@@ -66,8 +65,10 @@ public final class SpigotListener implements Listener {
FloodgatePlayer player = api.getPlayer(uniqueId);
if (player != null) {
player.as(FloodgatePlayerImpl.class).setLogin(false);
logger.info(languageManager.getLogString("floodgate.ingame.login_name",
player.getCorrectUsername(), player.getCorrectUniqueId()));
logger.translatedInfo(
"floodgate.ingame.login_name",
player.getCorrectUsername(), player.getCorrectUniqueId()
);
languageManager.loadLocale(player.getLanguageCode());
}
}
@@ -76,9 +77,7 @@ public final class SpigotListener implements Listener {
public void onPlayerQuit(PlayerQuitEvent event) {
Player player = event.getPlayer();
if (api.removePlayer(player.getUniqueId()) != null) {
logger.info(languageManager.getLogString(
"floodgate.ingame.disconnect_name", player.getName())
);
logger.translatedInfo("floodgate.ingame.disconnect_name", player.getName());
}
}
}

View File

@@ -29,9 +29,9 @@ import com.google.inject.AbstractModule;
import com.google.inject.Singleton;
import com.google.inject.multibindings.ProvidesIntoSet;
import org.geysermc.floodgate.addon.AddonManagerAddon;
import org.geysermc.floodgate.addon.DebugAddon;
import org.geysermc.floodgate.addon.data.SpigotDataAddon;
import org.geysermc.floodgate.api.inject.InjectorAddon;
import org.geysermc.floodgate.addon.DebugAddon;
import org.geysermc.floodgate.register.AddonRegister;
public final class SpigotAddonModule extends AbstractModule {

View File

@@ -72,8 +72,8 @@ public final class SpigotPlatformModule extends AbstractModule {
@Provides
@Singleton
public FloodgateLogger floodgateLogger() {
return new JavaUtilFloodgateLogger(plugin.getLogger());
public FloodgateLogger floodgateLogger(LanguageManager languageManager) {
return new JavaUtilFloodgateLogger(plugin.getLogger(), languageManager);
}
/*

View File

@@ -2,64 +2,7 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>parent</artifactId>
<groupId>org.geysermc.floodgate</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<url>${parent.url}</url>
<artifactId>velocity</artifactId>
<properties>
<log4j.version>2.11.2</log4j.version>
</properties>
<repositories>
<repository>
<id>velocity-repo</id>
<url>https://repo.velocitypowered.com/snapshots/</url>
</repository>
<!-- Hotfix to support the newest velocity-api, because they depend on the minecraft repo
but for whatever reason they don't have it in the velocity-api -->
<repository>
<id>minecraft-repo</id>
<url>https://libraries.minecraft.net/</url>
</repository>
<repository>
<id>sponge-repo</id>
<url>https://repo.spongepowered.org/maven/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>com.velocitypowered</groupId>
<artifactId>velocity-api</artifactId>
<version>${velocity.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>${log4j.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.45.Final</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.geysermc.floodgate</groupId>
<artifactId>common</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<resources>
<resource>
@@ -87,4 +30,61 @@
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>com.velocitypowered</groupId>
<artifactId>velocity-api</artifactId>
<version>${velocity.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>${log4j.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.45.Final</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.geysermc.floodgate</groupId>
<artifactId>common</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
</dependencies>
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>parent</artifactId>
<groupId>org.geysermc.floodgate</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<properties>
<log4j.version>2.11.2</log4j.version>
</properties>
<repositories>
<repository>
<id>velocity-repo</id>
<url>https://repo.velocitypowered.com/snapshots/</url>
</repository>
<!-- Hotfix to support the newest velocity-api, because they depend on the minecraft repo
but for whatever reason they don't have it in the velocity-api -->
<repository>
<id>minecraft-repo</id>
<url>https://libraries.minecraft.net/</url>
</repository>
<repository>
<id>sponge-repo</id>
<url>https://repo.spongepowered.org/maven/</url>
</repository>
</repositories>
<url>${parent.url}</url>
</project>

View File

@@ -30,17 +30,20 @@ import com.google.inject.Injector;
import com.velocitypowered.api.event.Subscribe;
import com.velocitypowered.api.event.proxy.ProxyInitializeEvent;
import com.velocitypowered.api.plugin.annotation.DataDirectory;
import org.geysermc.floodgate.module.*;
import org.geysermc.floodgate.util.ReflectionUtils;
import org.slf4j.Logger;
import java.nio.file.Path;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.module.CommandModule;
import org.geysermc.floodgate.module.CommonModule;
import org.geysermc.floodgate.module.VelocityAddonModule;
import org.geysermc.floodgate.module.VelocityListenerModule;
import org.geysermc.floodgate.module.VelocityPlatformModule;
import org.geysermc.floodgate.util.ReflectionUtils;
public final class VelocityPlugin {
private final FloodgatePlatform platform;
@Inject
public VelocityPlugin(@DataDirectory Path dataDirectory, Injector guice, Logger logger) {
public VelocityPlugin(@DataDirectory Path dataDirectory, Injector guice) {
ReflectionUtils.setPrefix("com.velocitypowered.proxy");
long ctm = System.currentTimeMillis();
@@ -52,15 +55,15 @@ public final class VelocityPlugin {
platform = injector.getInstance(FloodgatePlatform.class);
long endCtm = System.currentTimeMillis();
logger.info(platform.getLanguageManager().getLogString(
"floodgate.core.finish",
endCtm - ctm
));
injector.getInstance(FloodgateLogger.class)
.translatedInfo("floodgate.core.finish", endCtm - ctm);
}
@Subscribe
public void onProxyInitialization(ProxyInitializeEvent event) {
platform.enable(new CommandModule(), new VelocityListenerModule(),
new VelocityAddonModule());
platform.enable(
new CommandModule(), new VelocityListenerModule(),
new VelocityAddonModule()
);
}
}

View File

@@ -28,7 +28,6 @@ package org.geysermc.floodgate.addon.data;
import com.google.inject.Inject;
import com.google.inject.name.Named;
import io.netty.channel.Channel;
import io.netty.channel.EventLoop;
import io.netty.util.AttributeKey;
import org.geysermc.floodgate.HandshakeHandler;
import org.geysermc.floodgate.api.ProxyFloodgateApi;
@@ -37,9 +36,6 @@ import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.api.player.FloodgatePlayer;
import org.geysermc.floodgate.config.ProxyFloodgateConfig;
import java.util.HashMap;
import java.util.Map;
public final class VelocityDataAddon implements InjectorAddon {
@Inject private HandshakeHandler handshakeHandler;
@Inject private ProxyFloodgateConfig config;
@@ -63,8 +59,8 @@ public final class VelocityDataAddon implements InjectorAddon {
private AttributeKey<String> kickMessageAttribute;
@Override
public void onInject(Channel channel, boolean proxyToServer) {
if (proxyToServer) {
public void onInject(Channel channel, boolean toServer) {
if (toServer) {
channel.pipeline().addAfter(
packetEncoder, "floodgate_data_handler",
new VelocityServerDataHandler(config, api)

View File

@@ -25,10 +25,16 @@
package org.geysermc.floodgate.addon.data;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.geysermc.floodgate.util.ReflectionUtils.getCastedValue;
import static org.geysermc.floodgate.util.ReflectionUtils.getField;
import static org.geysermc.floodgate.util.ReflectionUtils.getPrefixedClass;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.util.AttributeKey;
import io.netty.util.ReferenceCountUtil;
import java.lang.reflect.Field;
import lombok.RequiredArgsConstructor;
import org.geysermc.floodgate.HandshakeHandler;
import org.geysermc.floodgate.HandshakeHandler.HandshakeResult;
@@ -37,26 +43,32 @@ import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.api.player.FloodgatePlayer;
import org.geysermc.floodgate.config.ProxyFloodgateConfig;
import java.lang.reflect.Field;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.geysermc.floodgate.util.ReflectionUtils.*;
@RequiredArgsConstructor
public final class VelocityProxyDataHandler extends SimpleChannelInboundHandler<Object> {
private static final Field HANDSHAKE;
private static final Class<?> HANDSHAKE_PACKET;
private static final Field HANDSHAKE_SERVER_ADDRESS;
static {
Class<?> iic = getPrefixedClass("connection.client.InitialInboundConnection");
checkNotNull(iic, "InitialInboundConnection class cannot be null");
HANDSHAKE = getField(iic, "handshake");
checkNotNull(HANDSHAKE, "Handshake field cannot be null");
HANDSHAKE_PACKET = getPrefixedClass("protocol.packet.Handshake");
checkNotNull(HANDSHAKE_PACKET, "Handshake packet class cannot be null");
HANDSHAKE_SERVER_ADDRESS = getField(HANDSHAKE_PACKET, "serverAddress");
checkNotNull(HANDSHAKE_SERVER_ADDRESS, "Address in the Handshake packet cannot be null");
}
private final ProxyFloodgateConfig config;
private final ProxyFloodgateApi api;
private final HandshakeHandler handshakeHandler;
private final AttributeKey<FloodgatePlayer> playerAttribute;
private final AttributeKey<String> kickMessageAttribute;
private final FloodgateLogger logger;
private boolean done;
@Override
@@ -102,19 +114,4 @@ public final class VelocityProxyDataHandler extends SimpleChannelInboundHandler<
logger.info("Floodgate player who is logged in as {} {} joined",
player.getCorrectUsername(), player.getCorrectUniqueId());
}
static {
Class<?> initialInboundConnection =
getPrefixedClass("connection.client.InitialInboundConnection");
checkNotNull(initialInboundConnection, "InitialInboundConnection class cannot be null");
HANDSHAKE = getField(initialInboundConnection, "handshake");
checkNotNull(HANDSHAKE, "Handshake field cannot be null");
HANDSHAKE_PACKET = getPrefixedClass("protocol.packet.Handshake");
checkNotNull(HANDSHAKE_PACKET, "Handshake packet class cannot be null");
HANDSHAKE_SERVER_ADDRESS = getField(HANDSHAKE_PACKET, "serverAddress");
checkNotNull(HANDSHAKE_SERVER_ADDRESS, "Address field of the Handshake packet cannot be null");
}
}

View File

@@ -25,33 +25,55 @@
package org.geysermc.floodgate.addon.data;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.geysermc.floodgate.util.ReflectionUtils.castedInvoke;
import static org.geysermc.floodgate.util.ReflectionUtils.getCastedValue;
import static org.geysermc.floodgate.util.ReflectionUtils.getField;
import static org.geysermc.floodgate.util.ReflectionUtils.getMethod;
import static org.geysermc.floodgate.util.ReflectionUtils.getPrefixedClass;
import static org.geysermc.floodgate.util.ReflectionUtils.invoke;
import static org.geysermc.floodgate.util.ReflectionUtils.setValue;
import com.velocitypowered.api.proxy.Player;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageEncoder;
import io.netty.util.ReferenceCountUtil;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.geysermc.floodgate.api.ProxyFloodgateApi;
import org.geysermc.floodgate.api.player.FloodgatePlayer;
import org.geysermc.floodgate.config.ProxyFloodgateConfig;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.geysermc.floodgate.util.ReflectionUtils.*;
@RequiredArgsConstructor
public class VelocityServerDataHandler extends MessageToMessageEncoder<Object> {
public final class VelocityServerDataHandler extends MessageToMessageEncoder<Object> {
private static final Class<?> HANDSHAKE_PACKET;
private static final Field HANDSHAKE_ADDRESS;
private static final Method GET_ASSOCIATION;
private static final Method GET_PLAYER;
static {
HANDSHAKE_PACKET = getPrefixedClass("protocol.packet.Handshake");
checkNotNull(HANDSHAKE_PACKET, "Handshake packet class cannot be null");
HANDSHAKE_ADDRESS = getField(HANDSHAKE_PACKET, "serverAddress");
checkNotNull(HANDSHAKE_ADDRESS, "Address field of the Handshake packet cannot be null");
Class<?> minecraftConnection = getPrefixedClass("connection.MinecraftConnection");
GET_ASSOCIATION = getMethod(minecraftConnection, "getAssociation");
checkNotNull(GET_ASSOCIATION, "getAssociation in MinecraftConnection cannot be null");
Class<?> serverConnection = getPrefixedClass("connection.backend.VelocityServerConnection");
GET_PLAYER = getMethod(serverConnection, "getPlayer");
checkNotNull(GET_PLAYER, "getPlayer in VelocityServerConnection cannot be null");
}
private final ProxyFloodgateConfig config;
private final ProxyFloodgateApi api;
private boolean done;
@Override
@@ -63,7 +85,8 @@ public class VelocityServerDataHandler extends MessageToMessageEncoder<Object> {
}
if (!HANDSHAKE_PACKET.isInstance(packet) || !config.isSendFloodgateData()) {
System.out.println(HANDSHAKE_PACKET.isInstance(packet)+" "+config.isSendFloodgateData());
System.out.println(
HANDSHAKE_PACKET.isInstance(packet) + " " + config.isSendFloodgateData());
done = true;
out.add(packet);
return;
@@ -99,22 +122,4 @@ public class VelocityServerDataHandler extends MessageToMessageEncoder<Object> {
done = true;
out.add(packet);
}
static {
HANDSHAKE_PACKET = getPrefixedClass("protocol.packet.Handshake");
checkNotNull(HANDSHAKE_PACKET, "Handshake packet class cannot be null");
HANDSHAKE_ADDRESS = getField(HANDSHAKE_PACKET, "serverAddress");
checkNotNull(HANDSHAKE_ADDRESS, "Address field of the Handshake packet cannot be null");
Class<?> minecraftConnection = getPrefixedClass("connection.MinecraftConnection");
GET_ASSOCIATION = getMethod(minecraftConnection, "getAssociation");
checkNotNull(GET_ASSOCIATION, "getAssociation in MinecraftConnection cannot be null");
Class<?> serverConnection = getPrefixedClass("connection.backend.VelocityServerConnection");
GET_PLAYER = getMethod(serverConnection, "getPlayer");
checkNotNull(GET_PLAYER, "getPlayer in VelocityServerConnection cannot be null");
}
}

View File

@@ -28,6 +28,7 @@ package org.geysermc.floodgate.command;
import com.velocitypowered.api.command.CommandManager;
import com.velocitypowered.api.command.CommandSource;
import com.velocitypowered.api.proxy.Player;
import java.util.Locale;
import lombok.RequiredArgsConstructor;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.geysermc.floodgate.platform.command.Command;
@@ -35,8 +36,6 @@ import org.geysermc.floodgate.platform.command.CommandRegistration;
import org.geysermc.floodgate.platform.command.CommandUtil;
import org.geysermc.floodgate.util.LanguageManager;
import java.util.Locale;
@RequiredArgsConstructor
public final class VelocityCommandRegistration implements CommandRegistration {
private final CommandManager commandManager;

View File

@@ -25,26 +25,31 @@
package org.geysermc.floodgate.inject.velocity;
import static org.geysermc.floodgate.util.ReflectionUtils.castedInvoke;
import static org.geysermc.floodgate.util.ReflectionUtils.getMethod;
import static org.geysermc.floodgate.util.ReflectionUtils.getValue;
import static org.geysermc.floodgate.util.ReflectionUtils.invoke;
import com.velocitypowered.api.proxy.ProxyServer;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import java.lang.reflect.Method;
import javax.naming.OperationNotSupportedException;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.geysermc.floodgate.inject.CommonPlatformInjector;
import javax.naming.OperationNotSupportedException;
import java.lang.reflect.Method;
import static org.geysermc.floodgate.util.ReflectionUtils.*;
@RequiredArgsConstructor
public final class VelocityInjector extends CommonPlatformInjector {
private final ProxyServer server;
@Getter private boolean injected = false;
@SuppressWarnings("rawtypes")
public boolean inject() {
if (isInjected()) return true;
if (isInjected()) {
return true;
}
Object connectionManager = getValue(server, "cm");
@@ -80,6 +85,10 @@ public final class VelocityInjector extends CommonPlatformInjector {
private static final class VelocityChannelInitializer extends ChannelInitializer<Channel> {
private static final Method initChannel;
static {
initChannel = getMethod(ChannelInitializer.class, "initChannel", Channel.class);
}
private final VelocityInjector injector;
private final ChannelInitializer original;
private final boolean proxyToServer;
@@ -91,9 +100,5 @@ public final class VelocityInjector extends CommonPlatformInjector {
injector.injectAddonsCall(channel, proxyToServer);
injector.addInjectedClient(channel);
}
static {
initChannel = getMethod(ChannelInitializer.class, "initChannel", Channel.class);
}
}
}

View File

@@ -25,6 +25,11 @@
package org.geysermc.floodgate.listener;
import static org.geysermc.floodgate.util.ReflectionUtils.getCastedValue;
import static org.geysermc.floodgate.util.ReflectionUtils.getFieldOfType;
import static org.geysermc.floodgate.util.ReflectionUtils.getPrefixedClass;
import static org.geysermc.floodgate.util.ReflectionUtils.getValue;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.inject.Inject;
@@ -40,23 +45,36 @@ import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.api.util.GameProfile;
import io.netty.channel.Channel;
import io.netty.util.AttributeKey;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.concurrent.TimeUnit;
import net.kyori.adventure.text.TextComponent;
import org.geysermc.floodgate.api.ProxyFloodgateApi;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.api.player.FloodgatePlayer;
import org.geysermc.floodgate.util.LanguageManager;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.concurrent.TimeUnit;
import static org.geysermc.floodgate.util.ReflectionUtils.*;
public final class VelocityListener {
private static final Field INITIAL_MINECRAFT_CONNECTION;
private static final Field MINECRAFT_CONNECTION;
private static final Field CHANNEL;
static {
Class<?> initialConnection = getPrefixedClass("connection.client.InitialInboundConnection");
Class<?> minecraftConnection = getPrefixedClass("connection.MinecraftConnection");
INITIAL_MINECRAFT_CONNECTION = getFieldOfType(initialConnection, minecraftConnection);
Class<?> connectedPlayer = getPrefixedClass("connection.client.ConnectedPlayer");
MINECRAFT_CONNECTION = getFieldOfType(connectedPlayer, minecraftConnection);
CHANNEL = getFieldOfType(minecraftConnection, Channel.class);
}
private final Cache<InboundConnection, FloodgatePlayer> playerCache =
CacheBuilder.newBuilder()
.maximumSize(500)
.expireAfterAccess(20, TimeUnit.SECONDS)
.build();
@Inject private ProxyFloodgateApi api;
@Inject private LanguageManager languageManager;
@Inject private FloodgateLogger logger;
@@ -69,12 +87,6 @@ public final class VelocityListener {
@Named("kickMessageAttribute")
private AttributeKey<String> kickMessageAttribute;
private final Cache<InboundConnection, FloodgatePlayer> playerCache =
CacheBuilder.newBuilder()
.maximumSize(500)
.expireAfterAccess(20, TimeUnit.SECONDS)
.build();
@Subscribe(order = PostOrder.EARLY)
public void onPreLogin(PreLoginEvent event) {
FloodgatePlayer player = null;
@@ -91,7 +103,9 @@ public final class VelocityListener {
}
if (kickMessage != null) {
event.setResult(PreLoginEvent.PreLoginComponentResult.denied(TextComponent.of(kickMessage)));
event.setResult(
PreLoginEvent.PreLoginComponentResult.denied(TextComponent.of(kickMessage))
);
return;
}
@@ -111,13 +125,15 @@ public final class VelocityListener {
}
}
@Subscribe
@Subscribe(order = PostOrder.LAST)
public void onLogin(LoginEvent event) {
if (event.getResult().isAllowed()) {
FloodgatePlayer player = api.getPlayer(event.getPlayer().getUniqueId());
if (player != null) {
languageManager.loadLocale(player.getLanguageCode());
}
}
}
@Subscribe(order = PostOrder.LAST)
public void onDisconnect(DisconnectEvent event) {
@@ -129,22 +145,10 @@ public final class VelocityListener {
if (fPlayer != null && api.removePlayer(fPlayer)) {
api.removeEncryptedData(event.getPlayer().getUniqueId());
logger.info(languageManager.getLogString(
"floodgate.ingame.disconnect_name", player.getUsername()
));
logger.translatedInfo("floodgate.ingame.disconnect_name", player.getUsername());
}
} catch (Exception exception) {
logger.error("Failed to remove the player", exception);
}
}
static {
Class<?> initialConnection = getPrefixedClass("connection.client.InitialInboundConnection");
Class<?> minecraftConnection = getPrefixedClass("connection.MinecraftConnection");
INITIAL_MINECRAFT_CONNECTION = getFieldOfType(initialConnection, minecraftConnection);
Class<?> connectedPlayer = getPrefixedClass("connection.client.ConnectedPlayer");
MINECRAFT_CONNECTION = getFieldOfType(connectedPlayer, minecraftConnection);
CHANNEL = getFieldOfType(minecraftConnection, Channel.class);
}
}

View File

@@ -25,17 +25,19 @@
package org.geysermc.floodgate.logger;
import static org.geysermc.floodgate.util.MessageFormatter.format;
import lombok.RequiredArgsConstructor;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.core.config.Configurator;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.util.LanguageManager;
import org.slf4j.Logger;
import static org.geysermc.floodgate.util.MessageFormatter.format;
@RequiredArgsConstructor
public final class Slf4jFloodgateLogger implements FloodgateLogger {
private final Logger logger;
private final LanguageManager languageManager;
@Override
public void error(String message, Object... args) {
@@ -57,6 +59,11 @@ public final class Slf4jFloodgateLogger implements FloodgateLogger {
logger.info(message, args);
}
@Override
public void translatedInfo(String message, Object... args) {
logger.info(languageManager.getLogString(message, args));
}
@Override
public void debug(String message, Object... args) {
logger.debug(message, args);

View File

@@ -74,8 +74,8 @@ public final class VelocityPlatformModule extends AbstractModule {
@Provides
@Singleton
public FloodgateLogger floodgateLogger(Logger logger) {
return new Slf4jFloodgateLogger(logger);
public FloodgateLogger floodgateLogger(Logger logger, LanguageManager languageManager) {
return new Slf4jFloodgateLogger(logger, languageManager);
}
/*

View File

@@ -49,9 +49,7 @@ public final class VelocityCommandUtil implements CommandUtil {
public TextComponent translateAndTransform(String locale, CommandMessage message,
Object... args) {
return TextComponent.of(manager.getString(
message.getMessage(), locale, args
));
return TextComponent.of(manager.getString(message.getMessage(), locale, args));
}
protected Player cast(Object instance) {