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"> <component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173"> <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="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> <JetCodeStyleSettings>
<option name="PACKAGES_TO_USE_STAR_IMPORTS"> <option name="PACKAGES_TO_USE_STAR_IMPORTS">
<value> <value>
@@ -20,8 +77,357 @@
</value> </value>
</option> </option>
</JetCodeStyleSettings> </JetCodeStyleSettings>
<ScalaCodeStyleSettings> <XML>
<option name="MULTILINE_STRING_CLOSING_QUOTES_ON_NEW_LINE" value="true" /> <option name="XML_ALIGN_ATTRIBUTES" value="false" />
</ScalaCodeStyleSettings> <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> </code_scheme>
</component> </component>

View File

@@ -2,14 +2,55 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" <project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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"> 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> <parent>
<artifactId>parent</artifactId> <artifactId>parent</artifactId>
<groupId>org.geysermc.floodgate</groupId> <groupId>org.geysermc.floodgate</groupId>
<version>1.0-SNAPSHOT</version> <version>1.0-SNAPSHOT</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>api</artifactId>
<repositories> <repositories>
<repository> <repository>
@@ -33,45 +74,4 @@
</snapshots> </snapshots>
</repository> </repository>
</repositories> </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> </project>

View File

@@ -25,12 +25,18 @@
package org.geysermc.floodgate.api; package org.geysermc.floodgate.api;
import java.util.UUID;
import org.geysermc.floodgate.api.link.PlayerLink; import org.geysermc.floodgate.api.link.PlayerLink;
import org.geysermc.floodgate.api.player.FloodgatePlayer; import org.geysermc.floodgate.api.player.FloodgatePlayer;
import java.util.UUID;
public interface FloodgateApi { 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 * 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); UUID createJavaPlayerId(long xuid);
/** /**
* Checks if the uuid of the player has the {@link #createJavaPlayerId(long)} format. * Checks if the uuid of the player has the {@link #createJavaPlayerId(long)} format. This
* This method can't validate a linked player uuid, since that doesn't equal the format. * method can't validate a linked player uuid, since that doesn't equal the format. Use {@link
* Use {@link #isBedrockPlayer(UUID)} if you want to include linked accounts. * #isBedrockPlayer(UUID)} if you want to include linked accounts.
* *
* @param uuid the uuid to check * @param uuid the uuid to check
* @return true if the given uuid has the correct format. * @return true if the given uuid has the correct format.
@@ -71,11 +77,4 @@ public interface FloodgateApi {
default PlayerLink getPlayerLink() { default PlayerLink getPlayerLink() {
return InstanceHolder.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; package org.geysermc.floodgate.api;
import java.util.UUID;
import lombok.Getter; import lombok.Getter;
import org.geysermc.floodgate.api.inject.PlatformInjector; import org.geysermc.floodgate.api.inject.PlatformInjector;
import org.geysermc.floodgate.api.link.PlayerLink; import org.geysermc.floodgate.api.link.PlayerLink;
import java.util.UUID;
public final class InstanceHolder { public final class InstanceHolder {
@Getter private static FloodgateApi instance; @Getter private static FloodgateApi instance;
@Getter private static PlayerLink playerLink; @Getter private static PlayerLink playerLink;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -2,47 +2,7 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" <project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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"> 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> <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> <build>
<resources> <resources>
<resource> <resource>
@@ -70,4 +30,44 @@
</plugin> </plugin>
</plugins> </plugins>
</build> </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> </project>

View File

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

View File

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

View File

@@ -25,10 +25,16 @@
package org.geysermc.floodgate.handler; 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.Inject;
import com.google.inject.name.Named; import com.google.inject.name.Named;
import io.netty.channel.Channel; import io.netty.channel.Channel;
import io.netty.util.AttributeKey; 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.connection.ProxiedPlayer;
import net.md_5.bungee.api.event.PreLoginEvent; import net.md_5.bungee.api.event.PreLoginEvent;
import net.md_5.bungee.api.plugin.Plugin; 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.BedrockData;
import org.geysermc.floodgate.util.ReflectionUtils; 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 { public final class BungeeDataHandler {
private static final Field EXTRA_HANDSHAKE_DATA; private static final Field EXTRA_HANDSHAKE_DATA;
private static final Field PLAYER_NAME; 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 PLAYER_REMOTE_ADDRESS;
private static final Field CACHED_HANDSHAKE_PACKET; private static final Field CACHED_HANDSHAKE_PACKET;
@Inject static {
private Plugin plugin; Class<?> initialHandler = ReflectionUtils.getPrefixedClass("connection.InitialHandler");
@Inject EXTRA_HANDSHAKE_DATA = ReflectionUtils.getField(initialHandler, "extraDataInHandshake");
private ProxyFloodgateConfig config; checkNotNull(EXTRA_HANDSHAKE_DATA, "extraDataInHandshake field cannot be null");
@Inject
private ProxyFloodgateApi api; PLAYER_NAME = ReflectionUtils.getField(initialHandler, "name");
@Inject checkNotNull(PLAYER_NAME, "Initial name field cannot be null");
private HandshakeHandler handler;
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 @Inject
@Named("playerAttribute") @Named("playerAttribute")
private AttributeKey<FloodgatePlayer> playerAttribute; private AttributeKey<FloodgatePlayer> playerAttribute;
@Inject
private FloodgateLogger logger;
public BungeeDataHandler(Plugin plugin, ProxyFloodgateConfig config, @Inject private Plugin plugin;
ProxyFloodgateApi api, HandshakeHandler handshakeHandler, @Inject private ProxyFloodgateConfig config;
AttributeKey<FloodgatePlayer> playerAttribute, @Inject private ProxyFloodgateApi api;
FloodgateLogger logger) { @Inject private HandshakeHandler handler;
this.plugin = plugin; @Inject private FloodgateLogger logger;
this.config = config;
this.handler = handshakeHandler;
this.api = api;
this.playerAttribute = playerAttribute;
this.logger = logger;
}
public void handlePreLogin(PreLoginEvent event) { public void handlePreLogin(PreLoginEvent event) {
event.registerIntent(plugin); event.registerIntent(plugin);
@@ -129,8 +135,8 @@ public final class BungeeDataHandler {
channel.attr(playerAttribute).set(player); channel.attr(playerAttribute).set(player);
if (!(remoteAddress instanceof InetSocketAddress)) { if (!(remoteAddress instanceof InetSocketAddress)) {
logger.info("Player {} doesn't use an InetSocketAddress. " + logger.info("Player {} doesn't use an InetSocketAddress, it uses {}. " +
"It uses {}. Ignoring the player, I guess.", "Ignoring the player, I guess.",
player.getUsername(), remoteAddress.getClass().getSimpleName() player.getUsername(), remoteAddress.getClass().getSimpleName()
); );
} else { } else {
@@ -159,27 +165,4 @@ public final class BungeeDataHandler {
// Bungeecord will add his data after our data // 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; package org.geysermc.floodgate.inject.bungee;
import io.netty.channel.Channel; 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.Getter;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.geysermc.floodgate.api.logger.FloodgateLogger; import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.inject.CommonPlatformInjector; import org.geysermc.floodgate.inject.CommonPlatformInjector;
import org.geysermc.floodgate.util.ReflectionUtils; import org.geysermc.floodgate.util.ReflectionUtils;
import javax.naming.OperationNotSupportedException;
import java.util.function.Consumer;
@RequiredArgsConstructor @RequiredArgsConstructor
public final class BungeeInjector extends CommonPlatformInjector { public final class BungeeInjector extends CommonPlatformInjector {
private final FloodgateLogger logger; private final FloodgateLogger logger;
@Getter @Getter private boolean injected;
private boolean injected;
@Override @Override
public boolean inject() { public boolean inject() {
@@ -54,7 +56,8 @@ public final class BungeeInjector extends CommonPlatformInjector {
// create a new field that we can access // create a new field that we can access
CtField channelConsumerField = new CtField( 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); channelConsumerField.setModifiers(Modifier.PUBLIC | Modifier.STATIC);
handlerBossClass.addField(channelConsumerField); 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 // edit a method to call the new field when we need it
CtMethod channelActiveMethod = handlerBossClass.getMethod( CtMethod channelActiveMethod = handlerBossClass.getMethod(
"channelActive", "(Lio/netty/channel/ChannelHandlerContext;)V"); "channelActive", "(Lio/netty/channel/ChannelHandlerContext;)V");
channelActiveMethod.insertBefore("" + channelActiveMethod.insertBefore(
"{if (handler != null) {channelConsumer.accept(ctx.channel());}}"); "{if (handler != null) {channelConsumer.accept(ctx.channel());}}");
Class<?> clazz = handlerBossClass.toClass(); Class<?> clazz = handlerBossClass.toClass();

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -25,9 +25,15 @@
package org.geysermc.floodgate; package org.geysermc.floodgate;
import static org.geysermc.floodgate.util.BedrockData.EXPECTED_LENGTH;
import com.google.common.base.Charsets; import com.google.common.base.Charsets;
import com.google.inject.Inject; 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.SimpleFloodgateApi;
import org.geysermc.floodgate.api.player.FloodgatePlayer; import org.geysermc.floodgate.api.player.FloodgatePlayer;
import org.geysermc.floodgate.config.FloodgateConfig; 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.InvalidFormatException;
import org.geysermc.floodgate.util.RawSkin; import org.geysermc.floodgate.util.RawSkin;
import static org.geysermc.floodgate.util.BedrockData.EXPECTED_LENGTH;
@RequiredArgsConstructor @RequiredArgsConstructor
public final class HandshakeHandler { public final class HandshakeHandler {
private final SimpleFloodgateApi api; 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 { public enum ResultType {
EXCEPTION, EXCEPTION,
NOT_FLOODGATE_DATA, NOT_FLOODGATE_DATA,
@@ -148,4 +139,17 @@ public final class HandshakeHandler {
cachedResult = new HandshakeResult(this, null, null, null); 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; @Inject private CommonPlatformInjector injector;
@Override @Override
public void onInject(Channel channel, boolean proxyToServer) { public void onInject(Channel channel, boolean toServer) {
channel.pipeline().addLast("floodgate_addon", new AddonManagerHandler(injector, channel)); 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.Inject;
import com.google.inject.name.Named; import com.google.inject.name.Named;
import io.netty.channel.Channel; import io.netty.channel.Channel;
import io.netty.channel.ChannelPipeline;
import org.geysermc.floodgate.addon.debug.ChannelInDebugHandler; import org.geysermc.floodgate.addon.debug.ChannelInDebugHandler;
import org.geysermc.floodgate.addon.debug.ChannelOutDebugHandler; import org.geysermc.floodgate.addon.debug.ChannelOutDebugHandler;
import org.geysermc.floodgate.api.inject.InjectorAddon; import org.geysermc.floodgate.api.inject.InjectorAddon;
@@ -51,13 +52,13 @@ public final class DebugAddon implements InjectorAddon {
private String packetDecoder; private String packetDecoder;
@Override @Override
public void onInject(Channel channel, boolean proxyToServer) { public void onInject(Channel channel, boolean toServer) {
channel.pipeline().addBefore( channel.pipeline().addBefore(
packetEncoder, "floodgate_debug_out", packetEncoder, "floodgate_debug_out",
new ChannelOutDebugHandler(implementationName, !proxyToServer, logger) new ChannelOutDebugHandler(implementationName, toServer, logger)
).addBefore( ).addBefore(
packetDecoder, "floodgate_debug_in", 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 @Override
public void onRemoveInject(Channel channel) { public void onRemoveInject(Channel channel) {
channel.pipeline().remove("floodgate_debug_out"); ChannelPipeline pipeline = channel.pipeline();
channel.pipeline().remove("floodgate_debug_in");
pipeline.remove("floodgate_debug_out");
pipeline.remove("floodgate_debug_in");
} }
@Override @Override

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -26,6 +26,7 @@
package org.geysermc.floodgate.command; package org.geysermc.floodgate.command;
import com.google.inject.Inject; import com.google.inject.Inject;
import java.util.UUID;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import org.geysermc.floodgate.api.FloodgateApi; 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.CommandMessage;
import org.geysermc.floodgate.platform.command.CommandUtil; import org.geysermc.floodgate.platform.command.CommandUtil;
import java.util.UUID;
@NoArgsConstructor @NoArgsConstructor
public final class UnlinkAccountCommand implements Command { public final class UnlinkAccountCommand implements Command {
@Inject private FloodgateApi api; @Inject private FloodgateApi api;
@@ -49,8 +48,9 @@ public final class UnlinkAccountCommand implements Command {
return; return;
} }
link.isLinkedPlayer(uuid).whenComplete((linked, throwable) -> { link.isLinkedPlayer(uuid)
if (throwable != null) { .whenComplete((linked, error) -> {
if (error != null) {
sendMessage(player, locale, CommonCommandMessage.IS_LINKED_ERROR); sendMessage(player, locale, CommonCommandMessage.IS_LINKED_ERROR);
return; return;
} }
@@ -60,13 +60,15 @@ public final class UnlinkAccountCommand implements Command {
return; return;
} }
link.unlinkPlayer(uuid).whenComplete((aVoid, throwable1) -> link.unlinkPlayer(uuid)
sendMessage(player, locale, .whenComplete((unused, error1) -> {
throwable1 == null ? if (error1 != null) {
Message.UNLINK_SUCCESS : sendMessage(player, locale, Message.UNLINK_ERROR);
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"), UNLINK_ERROR("floodgate.command.unlink_account.error"),
LINKING_NOT_ENABLED("floodgate.commands.linking_disabled"); LINKING_NOT_ENABLED("floodgate.commands.linking_disabled");
@Getter @Getter private final String message;
private final String message;
Message(String message) { Message(String message) {
this.message = 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.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import java.security.Key;
import lombok.Getter; import lombok.Getter;
import java.security.Key;
/** /**
* The global Floodgate configuration file used in every platform. * The global Floodgate configuration file used in every platform. Some platforms have their own
* Some platforms have their own addition to the global configuration like * addition to the global configuration like {@link ProxyFloodgateConfig} for the proxies.
* {@link ProxyFloodgateConfig} for the proxies.
*/ */
@Getter @Getter
public class FloodgateConfig { public class FloodgateConfig {
@@ -63,6 +61,16 @@ public class FloodgateConfig {
@JsonIgnore @JsonIgnore
private Key key = null; private Key key = null;
public void setKey(Key key) {
if (this.key == null) {
this.key = key;
}
}
public boolean isProxy() {
return this instanceof ProxyFloodgateConfig;
}
@Getter @Getter
public static class DisconnectMessages { public static class DisconnectMessages {
@JsonProperty("invalid-key") @JsonProperty("invalid-key")
@@ -84,14 +92,4 @@ public class FloodgateConfig {
@JsonProperty("auto-download") @JsonProperty("auto-download")
private boolean autoDownload; 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. * The Floodgate configuration used by proxy platforms, currently Velocity and Bungeecord.
*/ */
public final class ProxyFloodgateConfig extends FloodgateConfig { public final class ProxyFloodgateConfig extends FloodgateConfig {
@Getter
@JsonProperty(value = "send-floodgate-data") @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.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; 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 lombok.RequiredArgsConstructor;
import org.geysermc.floodgate.api.logger.FloodgateLogger; import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.config.FloodgateConfig; 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.FloodgateCipher;
import org.geysermc.floodgate.crypto.KeyProducer; 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 @RequiredArgsConstructor
public class ConfigLoader { public final class ConfigLoader {
private final Path dataFolder; private final Path dataFolder;
private final Class<? extends FloodgateConfig> configClass; private final Class<? extends FloodgateConfig> configClass;
private final ConfigUpdater updater; private final ConfigUpdater updater;
@@ -116,14 +114,16 @@ public class ConfigLoader {
updater.update(defaultConfigPath); updater.update(defaultConfigPath);
} }
configInstance = (T) new ObjectMapper(new YAMLFactory()) FloodgateConfig config =
new ObjectMapper(new YAMLFactory())
.readValue(Files.readAllBytes(configPath), configClass); .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 {
"Try to contact the platform developer"); configInstance = (T) config;
} catch (ClassCastException exception) {
logger.error("Failed to cast config file to required class.", exception);
throw new RuntimeException(exception);
}
} catch (Exception exception) { } catch (Exception exception) {
logger.error("Error while loading config", exception); logger.error("Error while loading config", exception);
throw new RuntimeException("Failed to load the config! Try to delete the config file"); 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; package org.geysermc.floodgate.config.updater;
import com.google.inject.Inject; import com.google.inject.Inject;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
public class ConfigFileUpdater { public final class ConfigFileUpdater {
@Inject @Inject private FloodgateLogger logger;
private FloodgateLogger logger;
/** /**
* Simple config file updater. * Simple config file updater. Please note that all the keys should be unique and that this
* Please note that all the keys should be unique and that this system wasn't made for complex * system wasn't made for complex configurations.
* configurations.
* *
* @param configLocation the location of the Floodgate config * @param configLocation the location of the Floodgate config
* @param currentVersion the key value map of the current 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 * @param defaultConfigLocation the location of the default Floodgate config
* @throws IOException if an I/O error occurs * @throws IOException if an I/O error occurs
*/ */
@@ -59,7 +57,9 @@ public class ConfigFileUpdater {
for (int i = 0; i < newConfig.size(); i++) { for (int i = 0; i < newConfig.size(); i++) {
line = newConfig.get(i); line = newConfig.get(i);
// we don't have to check comments // we don't have to check comments
if (line.startsWith("#")) continue; if (line.startsWith("#")) {
continue;
}
int splitIndex = line.indexOf(':'); int splitIndex = line.indexOf(':');
// if the line has a 'key: value' structure // if the line has a 'key: value' structure
@@ -69,11 +69,7 @@ public class ConfigFileUpdater {
Object value; Object value;
logger.info(name); logger.info(name);
if (renames.containsKey(name)) { value = currentVersion.get(renames.getOrDefault(name, name));
value = currentVersion.get(renames.get(name));
} else {
value = currentVersion.get(name);
}
if (value == null) { if (value == null) {
notFound.add(name); notFound.add(name);
@@ -102,9 +98,7 @@ public class ConfigFileUpdater {
if (notFound.size() > 0) { if (notFound.size() > 0) {
StringBuilder messageBuilder = new StringBuilder( StringBuilder messageBuilder = new StringBuilder(
"Please note that the following keys we not found in the old config and " + "Please note that the following keys we not found in the old config and " +
"are now using the default Floodgate config value. " + "are now using the default Floodgate config value. Missing/new keys: ");
"Missing/new keys: "
);
boolean first = true; boolean first = true;
for (String value : notFound) { for (String value : notFound) {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -25,17 +25,18 @@
package org.geysermc.floodgate.logger; package org.geysermc.floodgate.logger;
import lombok.RequiredArgsConstructor; import static org.geysermc.floodgate.util.MessageFormatter.format;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import lombok.RequiredArgsConstructor;
import static org.geysermc.floodgate.util.MessageFormatter.format; import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.util.LanguageManager;
@RequiredArgsConstructor @RequiredArgsConstructor
public final class JavaUtilFloodgateLogger implements FloodgateLogger { public final class JavaUtilFloodgateLogger implements FloodgateLogger {
private final Logger logger; private final Logger logger;
private final LanguageManager languageManager;
private Level originLevel = null; private Level originLevel = null;
@Override @Override
@@ -58,6 +59,11 @@ public final class JavaUtilFloodgateLogger implements FloodgateLogger {
logger.info(format(message, args)); logger.info(format(message, args));
} }
@Override
public void translatedInfo(String message, Object... args) {
logger.info(languageManager.getLogString(message, args));
}
@Override @Override
public void debug(String message, Object... args) { public void debug(String message, Object... args) {
logger.fine(format(message, 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.Singleton;
import com.google.inject.name.Named; import com.google.inject.name.Named;
import io.netty.util.AttributeKey; import io.netty.util.AttributeKey;
import java.nio.file.Path;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.geysermc.floodgate.HandshakeHandler; import org.geysermc.floodgate.HandshakeHandler;
import org.geysermc.floodgate.api.FloodgateApi; 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.loader.ConfigLoader;
import org.geysermc.floodgate.config.updater.ConfigFileUpdater; import org.geysermc.floodgate.config.updater.ConfigFileUpdater;
import org.geysermc.floodgate.config.updater.ConfigUpdater; 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.inject.CommonPlatformInjector;
import org.geysermc.floodgate.link.PlayerLinkLoader; import org.geysermc.floodgate.link.PlayerLinkLoader;
import org.geysermc.floodgate.util.LanguageManager; import org.geysermc.floodgate.util.LanguageManager;
import java.nio.file.Path;
@RequiredArgsConstructor @RequiredArgsConstructor
public final class CommonModule extends AbstractModule { public final class CommonModule extends AbstractModule {
private final Path dataDirectory; private final Path dataDirectory;
@@ -79,9 +82,11 @@ public final class CommonModule extends AbstractModule {
@Provides @Provides
@Singleton @Singleton
public ConfigLoader configLoader(@Named("configClass") Class<? extends FloodgateConfig> configClass, public ConfigLoader configLoader(
@Named("configClass") Class<? extends FloodgateConfig> configClass,
ConfigUpdater configUpdater, KeyProducer producer, ConfigUpdater configUpdater, KeyProducer producer,
FloodgateCipher cipher, FloodgateLogger logger) { FloodgateCipher cipher, FloodgateLogger logger) {
return new ConfigLoader( return new ConfigLoader(
dataDirectory, configClass, configUpdater, producer, cipher, logger dataDirectory, configClass, configUpdater, producer, cipher, logger
); );

View File

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

View File

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

View File

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

View File

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

View File

@@ -26,9 +26,9 @@
package org.geysermc.floodgate.platform.listener; package org.geysermc.floodgate.platform.listener;
/** /**
* This class is responsible for registering listeners to the listener manager of the platform * This class is responsible for registering listeners to the listener manager of the platform that
* that is currently in use. Unfortunately due to the major differences between the platforms * is currently in use. Unfortunately due to the major differences between the platforms (when it
* (when it comes to listeners) every Floodgate platform has to implement their own listeners. * comes to listeners) every Floodgate platform has to implement their own listeners.
* *
* @param <T> the platform-specific listener class * @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.Inject;
import com.google.inject.Injector; import com.google.inject.Injector;
import java.util.Set;
import org.geysermc.floodgate.api.inject.InjectorAddon; import org.geysermc.floodgate.api.inject.InjectorAddon;
import org.geysermc.floodgate.api.inject.PlatformInjector; import org.geysermc.floodgate.api.inject.PlatformInjector;
import java.util.Set;
public final class AddonRegister { public final class AddonRegister {
@Inject private Injector guice; @Inject private Injector guice;
@Inject private PlatformInjector injector; @Inject private PlatformInjector injector;

View File

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

View File

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

View File

@@ -26,25 +26,25 @@
package org.geysermc.floodgate.util; package org.geysermc.floodgate.util;
import com.google.inject.Inject; 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.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.HashMap; import java.util.HashMap;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Properties; 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 * Manages translations for strings in Floodgate
*/ */
@RequiredArgsConstructor @RequiredArgsConstructor
public class LanguageManager { public final class LanguageManager {
private final Map<String, Properties> LOCALE_MAPPINGS = new HashMap<>(); private final Map<String, Properties> LOCALE_MAPPINGS = new HashMap<>();
private final FloodgateLogger logger; private final FloodgateLogger logger;
@@ -52,8 +52,22 @@ public class LanguageManager {
/** /**
* The locale used in console and as a fallback * The locale used in console and as a fallback
*/ */
@Getter @Getter private String defaultLocale;
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 * Loads the log's locale file once Floodgate loads the config
@@ -72,8 +86,7 @@ public class LanguageManager {
} }
String systemLocale = formatLocale( String systemLocale = formatLocale(
Locale.getDefault().getLanguage() + "_" + Locale.getDefault().getLanguage() + "_" + Locale.getDefault().getCountry()
Locale.getDefault().getCountry()
); );
if (isValidLanguage(systemLocale)) { 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 * 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) { public void loadLocale(String locale) {
locale = formatLocale(locale); locale = formatLocale(locale);
@@ -120,9 +133,9 @@ public class LanguageManager {
/** /**
* Get a formatted language string with the default locale for Floodgate * Get a formatted language string with the default locale for Floodgate
* *
* @param key Language string to translate * @param key language string to translate
* @param values Values to put into the string * @param values values to put into the string
* @return Translated string or the original message if it was not found in the given locale * @return translated string or the original message if it was not found in the given locale
*/ */
public String getLogString(String key, Object... values) { public String getLogString(String key, Object... values) {
return getString(key, defaultLocale, values); return getString(key, defaultLocale, values);
@@ -131,10 +144,10 @@ public class LanguageManager {
/** /**
* Get a formatted language string with the given locale for Floodgate * Get a formatted language string with the given locale for Floodgate
* *
* @param key Language string to translate * @param key language string to translate
* @param locale Locale to translate to * @param locale locale to translate to
* @param values Values to put into the string * @param values values to put into the string
* @return Translated string or the original message if it was not found in the given locale * @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) { public String getString(String key, String locale, Object... values) {
locale = formatLocale(locale); locale = formatLocale(locale);
@@ -162,23 +175,9 @@ public class LanguageManager {
return MessageFormat.format(formatString.replace("'", "''").replace("&", "\u00a7"), values); 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 * Ensures that the given locale is supported by Floodgate
*
* @param locale the locale to validate * @param locale the locale to validate
* @return true if the given locale is supported by Floodgate * @return true if the given locale is supported by Floodgate
*/ */
@@ -187,7 +186,10 @@ public class LanguageManager {
return false; 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."); logger.warn(locale + " is not a supported Floodgate language.");
return false; return false;
} }

View File

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

View File

@@ -25,30 +25,69 @@
package org.geysermc.floodgate.util; 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 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 { public final class ReflectionUtils {
private static final Field MODIFIERS_FIELD; private static final Field MODIFIERS_FIELD;
/** /**
* The package name that is shared between all the {@link #getPrefixedClass(String)} calls so * The package name that is shared between all the {@link #getPrefixedClass(String)} calls so
* that the className will be a lot shorter. * that the className will be a lot shorter. Example net.minecraft.server.v1_8R3.PacketHandshakingInSetProtocol
* Example net.minecraft.server.v1_8R3.PacketHandshakingInSetProtocol will become * will become PacketHandshakingInSetProtocol if the prefix is set to
* PacketHandshakingInSetProtocol if the prefix is set to net.minecraft.server.v1_8R3 * net.minecraft.server.v1_8R3
*/ */
@Setter @Setter private static String prefix = null;
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)}. * Get a class that is prefixed with the prefix provided in {@link #setPrefix(String)}. Calling
* Calling this method is equal to calling {@link #getClass(String)} * this method is equal to calling {@link #getClass(String)} with <i>prefix</i>.<i>classname</i>
* with <i>prefix</i>.<i>classname</i> as class name. * as class name.
* *
* @param className the prefix class to find * @param className the prefix class to find
* @return the class if found, otherwise null * @return the class if found, otherwise null
@@ -59,11 +98,10 @@ public final class ReflectionUtils {
} }
/** /**
* Get the class from a class name. * Get the class from a class name. Calling this method is equal to calling {@link
* Calling this method is equal to calling {@link Class#forName(String)} where String is the * Class#forName(String)} where String is the class name.<br> This method will return null when
* class name.<br> * the class isn't found instead of throwing the exception, but the exception will be printed to
* This method will return null when the class isn't found instead of throwing the exception, * the console.
* but the exception will be printed to the console.
* *
* @param className the name of the class to find * @param className the name of the class to find
* @return the class or null if the class wasn't found. * @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. * Get a field of a class. Calling this method is equal to calling {@link
* Calling this method is equal to calling {@link Class#getField(String)} where String is the * Class#getField(String)} where String is the fieldName when isPublic is true and calling this
* fieldName when isPublic is true and calling this method is equal to calling * method is equal to calling {@link Class#getDeclaredField(String)} where String is the
* {@link Class#getDeclaredField(String)} where String is the fieldName when isPublic is * fieldName when isPublic is false.<br> Please note that this method will return null instead
* false.<br> * of throwing the exception.
* Please note that this method will return null instead of throwing the exception.
* *
* @param clazz the class name to get the field from * @param clazz the class name to get the field from
* @param fieldName the name of the field * @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. * Get a field from a class, it doesn't matter if the field is public or not. This method will
* This method will first try to get a declared field and if that failed it'll try to get a * first try to get a declared field and if that failed it'll try to get a public field.
* public field.
* *
* @param clazz the class to get the field from * @param clazz the class to get the field from
* @param fieldName the name of the field * @param fieldName the name of the field
@@ -134,15 +170,17 @@ public final class ReflectionUtils {
Field[] fields = declared ? clazz.getDeclaredFields() : clazz.getFields(); Field[] fields = declared ? clazz.getDeclaredFields() : clazz.getFields();
for (Field field : fields) { for (Field field : fields) {
makeAccessible(field); makeAccessible(field);
if (field.getType() == fieldType) return field; if (field.getType() == fieldType) {
return field;
}
} }
return null; return null;
} }
/** /**
* Get a declared field from a class without having to provide a field name.<br> * Get a declared field from a class without having to provide a field name.<br> Calling this
* Calling this method is equal to calling {@link #getFieldOfType(Class, Class, boolean)} * method is equal to calling {@link #getFieldOfType(Class, Class, boolean)} with declared =
* with declared = true. * true.
* *
* @param clazz the class to search the field from * @param clazz the class to search the field from
* @param fieldType the type of the declared field * @param fieldType the type of the declared field
@@ -154,10 +192,9 @@ public final class ReflectionUtils {
} }
/** /**
* Get the value of a field. * Get the value of a field. This method first makes the field accessible and then gets the
* This method first makes the field accessible and then gets the value.<br> * value.<br> This method will return null instead of throwing an exception, but it'll log the
* This method will return null instead of throwing an exception, * stacktrace to the console.
* but it'll log the stacktrace to the console.
* *
* @param instance the instance to get the value from * @param instance the instance to get the value from
* @param field the field 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. * Set the value of a field. This method make the field accessible and then sets the value.<br>
* 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. * 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 * @param instance the instance to set the value to
@@ -219,8 +255,8 @@ public final class ReflectionUtils {
} }
/** /**
* Set the value of a field. * Set the value of a field. This method finds the field, and then calls {@link
* This method finds the field, and then calls {@link #setValue(Object, Field, Object)}. * #setValue(Object, Field, Object)}.
* *
* @param instance the instance to set the value to * @param instance the instance to set the value to
* @param fieldName the field 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. * Set the value of a <b>final</b> field. This method first makes the field accessible, then
* This method first makes the field accessible, then removes the final modifier and then * removes the final modifier and then sets the value.<br> This method will not throw exceptions
* sets the value.<br> * when failed, but it'll log the error to the console.
* 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 instance the instance to set the value to
* @param field the field 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. * Get a method from a class, it doesn't matter if the field is public or not. This method will
* This method will first try to get a declared field and if that failed it'll try to get a * first try to get a declared field and if that failed it'll try to get a public field.<br>
* public field.<br> * Instead of throwing an exception when the method wasn't found, it will return null, but the
* Instead of throwing an exception when the method wasn't found, it will return null, but * exception will be printed in the console.
* the exception will be printed in the console.
* *
* @param clazz the class to get the method from * @param clazz the class to get the method from
* @param method the name of the method to find * @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. * Get a method from a class, it doesn't matter if the method is public or not. This method will
* This method will first try to get a declared method and if that fails it'll try to get a * first try to get a declared method and if that fails it'll try to get a public method.
* public method.
* *
* @param clazz the class to get the method from * @param clazz the class to get the method from
* @param methodName the name of the method to find * @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. * Get a method from a class, it doesn't matter if the method is public or not. This method will
* This method will first try to get a declared method and if that fails it'll try to get a * first try to get a declared method and if that fails it'll try to get a public method.
* public method.
* *
* @param instance the class to get the method from * @param instance the class to get the method from
* @param methodName the name of the method to find * @param methodName the name of the method to find
@@ -402,41 +434,4 @@ public final class ReflectionUtils {
} }
return accessibleObject; 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"?> <?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" <project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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"> 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> <parent>
<artifactId>parent</artifactId> <artifactId>parent</artifactId>
<groupId>org.geysermc.floodgate</groupId> <groupId>org.geysermc.floodgate</groupId>
<version>1.0-SNAPSHOT</version> <version>1.0-SNAPSHOT</version>
</parent> </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> <properties>
<outputName>floodgate-${project.name}-database</outputName> <outputName>floodgate-${project.name}-database</outputName>
</properties> </properties>
<version>1.0-SNAPSHOT</version>
</project> </project>

View File

@@ -1,62 +1,8 @@
<?xml version="1.0" encoding="UTF-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" <project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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"> 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> <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> <build>
<resources> <resources>
<resource> <resource>
@@ -84,4 +30,33 @@
</plugin> </plugin>
</plugins> </plugins>
</build> </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> </project>

View File

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

64
pom.xml
View File

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

View File

@@ -2,48 +2,7 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" <project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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"> 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> <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> <build>
<resources> <resources>
<resource> <resource>
@@ -71,4 +30,45 @@
</plugin> </plugin>
</plugins> </plugins>
</build> </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> </project>

View File

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

View File

@@ -28,7 +28,12 @@ package org.geysermc.floodgate;
import com.google.inject.Guice; import com.google.inject.Guice;
import com.google.inject.Injector; import com.google.inject.Injector;
import org.bukkit.plugin.java.JavaPlugin; 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; import org.geysermc.floodgate.util.ReflectionUtils;
public final class SpigotPlugin extends JavaPlugin { public final class SpigotPlugin extends JavaPlugin {
@@ -48,10 +53,8 @@ public final class SpigotPlugin extends JavaPlugin {
platform = injector.getInstance(SpigotPlatform.class); platform = injector.getInstance(SpigotPlatform.class);
long endCtm = System.currentTimeMillis(); long endCtm = System.currentTimeMillis();
getLogger().info(platform.getLanguageManager().getLogString( injector.getInstance(FloodgateLogger.class)
"floodgate.core.finish", .translatedInfo("floodgate.core.finish", endCtm - ctm);
endCtm - ctm
));
} }
@Override @Override

View File

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

View File

@@ -25,9 +25,23 @@
package org.geysermc.floodgate.addon.data; 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.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler; import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.util.AttributeKey; 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 lombok.RequiredArgsConstructor;
import org.geysermc.floodgate.HandshakeHandler; import org.geysermc.floodgate.HandshakeHandler;
import org.geysermc.floodgate.HandshakeHandler.HandshakeResult; 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.BedrockData;
import org.geysermc.floodgate.util.ReflectionUtils; 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 @RequiredArgsConstructor
public final class SpigotDataHandler extends SimpleChannelInboundHandler<Object> { public final class SpigotDataHandler extends SimpleChannelInboundHandler<Object> {
private static final Field SOCKET_ADDRESS; 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 Field PROTOCOL_STATE;
private static final Object READY_TO_ACCEPT_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 */ /* per player stuff */
private final FloodgateConfig config; private final FloodgateConfig config;
private final HandshakeHandler handshakeHandler; private final HandshakeHandler handshakeHandler;
private final AttributeKey<FloodgatePlayer> playerAttribute; private final AttributeKey<FloodgatePlayer> playerAttribute;
private final FloodgateLogger logger; private final FloodgateLogger logger;
private Object networkManager; private Object networkManager;
private FloodgatePlayer fPlayer; private FloodgatePlayer fPlayer;
private boolean bungee; private boolean bungee;
private boolean done; private boolean done;
@Override @Override
@@ -103,8 +180,10 @@ public final class SpigotDataHandler extends SimpleChannelInboundHandler<Object>
break; break;
case INVALID_DATA_LENGTH: case INVALID_DATA_LENGTH:
int dataLength = result.getBedrockData().getDataLength(); int dataLength = result.getBedrockData().getDataLength();
logger.info(config.getMessages().getInvalidArgumentsLength(), logger.info(
BedrockData.EXPECTED_LENGTH, dataLength); config.getMessages().getInvalidArgumentsLength(),
BedrockData.EXPECTED_LENGTH, dataLength
);
ctx.close(); ctx.close();
return; return;
default: // only continue when SUCCESS default: // only continue when SUCCESS
@@ -182,78 +261,4 @@ public final class SpigotDataHandler extends SimpleChannelInboundHandler<Object>
super.exceptionCaught(ctx, cause); super.exceptionCaught(ctx, cause);
cause.printStackTrace(); 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) { public void register(Command command) {
String defaultLocale = languageManager.getDefaultLocale(); String defaultLocale = languageManager.getDefaultLocale();
plugin.getCommand(command.getName()).setExecutor( plugin.getCommand(command.getName())
new SpigotCommandWrapper(commandUtil, command, defaultLocale) .setExecutor(new SpigotCommandWrapper(commandUtil, command, defaultLocale));
);
} }
@RequiredArgsConstructor @RequiredArgsConstructor

View File

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

View File

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

View File

@@ -26,6 +26,7 @@
package org.geysermc.floodgate.listener; package org.geysermc.floodgate.listener;
import com.google.inject.Inject; import com.google.inject.Inject;
import java.util.UUID;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority; 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.api.player.FloodgatePlayer;
import org.geysermc.floodgate.util.LanguageManager; import org.geysermc.floodgate.util.LanguageManager;
import java.util.UUID;
public final class SpigotListener implements Listener { public final class SpigotListener implements Listener {
@Inject private SimpleFloodgateApi api; @Inject private SimpleFloodgateApi api;
@Inject private FloodgateLogger logger; @Inject private FloodgateLogger logger;
@@ -66,8 +65,10 @@ public final class SpigotListener implements Listener {
FloodgatePlayer player = api.getPlayer(uniqueId); FloodgatePlayer player = api.getPlayer(uniqueId);
if (player != null) { if (player != null) {
player.as(FloodgatePlayerImpl.class).setLogin(false); player.as(FloodgatePlayerImpl.class).setLogin(false);
logger.info(languageManager.getLogString("floodgate.ingame.login_name", logger.translatedInfo(
player.getCorrectUsername(), player.getCorrectUniqueId())); "floodgate.ingame.login_name",
player.getCorrectUsername(), player.getCorrectUniqueId()
);
languageManager.loadLocale(player.getLanguageCode()); languageManager.loadLocale(player.getLanguageCode());
} }
} }
@@ -76,9 +77,7 @@ public final class SpigotListener implements Listener {
public void onPlayerQuit(PlayerQuitEvent event) { public void onPlayerQuit(PlayerQuitEvent event) {
Player player = event.getPlayer(); Player player = event.getPlayer();
if (api.removePlayer(player.getUniqueId()) != null) { if (api.removePlayer(player.getUniqueId()) != null) {
logger.info(languageManager.getLogString( logger.translatedInfo("floodgate.ingame.disconnect_name", player.getName());
"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.Singleton;
import com.google.inject.multibindings.ProvidesIntoSet; import com.google.inject.multibindings.ProvidesIntoSet;
import org.geysermc.floodgate.addon.AddonManagerAddon; import org.geysermc.floodgate.addon.AddonManagerAddon;
import org.geysermc.floodgate.addon.DebugAddon;
import org.geysermc.floodgate.addon.data.SpigotDataAddon; import org.geysermc.floodgate.addon.data.SpigotDataAddon;
import org.geysermc.floodgate.api.inject.InjectorAddon; import org.geysermc.floodgate.api.inject.InjectorAddon;
import org.geysermc.floodgate.addon.DebugAddon;
import org.geysermc.floodgate.register.AddonRegister; import org.geysermc.floodgate.register.AddonRegister;
public final class SpigotAddonModule extends AbstractModule { public final class SpigotAddonModule extends AbstractModule {

View File

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

View File

@@ -2,64 +2,7 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" <project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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"> 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> <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> <build>
<resources> <resources>
<resource> <resource>
@@ -87,4 +30,61 @@
</plugin> </plugin>
</plugins> </plugins>
</build> </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> </project>

View File

@@ -30,17 +30,20 @@ import com.google.inject.Injector;
import com.velocitypowered.api.event.Subscribe; import com.velocitypowered.api.event.Subscribe;
import com.velocitypowered.api.event.proxy.ProxyInitializeEvent; import com.velocitypowered.api.event.proxy.ProxyInitializeEvent;
import com.velocitypowered.api.plugin.annotation.DataDirectory; 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 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 { public final class VelocityPlugin {
private final FloodgatePlatform platform; private final FloodgatePlatform platform;
@Inject @Inject
public VelocityPlugin(@DataDirectory Path dataDirectory, Injector guice, Logger logger) { public VelocityPlugin(@DataDirectory Path dataDirectory, Injector guice) {
ReflectionUtils.setPrefix("com.velocitypowered.proxy"); ReflectionUtils.setPrefix("com.velocitypowered.proxy");
long ctm = System.currentTimeMillis(); long ctm = System.currentTimeMillis();
@@ -52,15 +55,15 @@ public final class VelocityPlugin {
platform = injector.getInstance(FloodgatePlatform.class); platform = injector.getInstance(FloodgatePlatform.class);
long endCtm = System.currentTimeMillis(); long endCtm = System.currentTimeMillis();
logger.info(platform.getLanguageManager().getLogString( injector.getInstance(FloodgateLogger.class)
"floodgate.core.finish", .translatedInfo("floodgate.core.finish", endCtm - ctm);
endCtm - ctm
));
} }
@Subscribe @Subscribe
public void onProxyInitialization(ProxyInitializeEvent event) { public void onProxyInitialization(ProxyInitializeEvent event) {
platform.enable(new CommandModule(), new VelocityListenerModule(), platform.enable(
new VelocityAddonModule()); 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.Inject;
import com.google.inject.name.Named; import com.google.inject.name.Named;
import io.netty.channel.Channel; import io.netty.channel.Channel;
import io.netty.channel.EventLoop;
import io.netty.util.AttributeKey; import io.netty.util.AttributeKey;
import org.geysermc.floodgate.HandshakeHandler; import org.geysermc.floodgate.HandshakeHandler;
import org.geysermc.floodgate.api.ProxyFloodgateApi; 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.api.player.FloodgatePlayer;
import org.geysermc.floodgate.config.ProxyFloodgateConfig; import org.geysermc.floodgate.config.ProxyFloodgateConfig;
import java.util.HashMap;
import java.util.Map;
public final class VelocityDataAddon implements InjectorAddon { public final class VelocityDataAddon implements InjectorAddon {
@Inject private HandshakeHandler handshakeHandler; @Inject private HandshakeHandler handshakeHandler;
@Inject private ProxyFloodgateConfig config; @Inject private ProxyFloodgateConfig config;
@@ -63,8 +59,8 @@ public final class VelocityDataAddon implements InjectorAddon {
private AttributeKey<String> kickMessageAttribute; private AttributeKey<String> kickMessageAttribute;
@Override @Override
public void onInject(Channel channel, boolean proxyToServer) { public void onInject(Channel channel, boolean toServer) {
if (proxyToServer) { if (toServer) {
channel.pipeline().addAfter( channel.pipeline().addAfter(
packetEncoder, "floodgate_data_handler", packetEncoder, "floodgate_data_handler",
new VelocityServerDataHandler(config, api) new VelocityServerDataHandler(config, api)

View File

@@ -25,10 +25,16 @@
package org.geysermc.floodgate.addon.data; 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.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler; import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.util.AttributeKey; import io.netty.util.AttributeKey;
import io.netty.util.ReferenceCountUtil; import io.netty.util.ReferenceCountUtil;
import java.lang.reflect.Field;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.geysermc.floodgate.HandshakeHandler; import org.geysermc.floodgate.HandshakeHandler;
import org.geysermc.floodgate.HandshakeHandler.HandshakeResult; 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.api.player.FloodgatePlayer;
import org.geysermc.floodgate.config.ProxyFloodgateConfig; 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 @RequiredArgsConstructor
public final class VelocityProxyDataHandler extends SimpleChannelInboundHandler<Object> { public final class VelocityProxyDataHandler extends SimpleChannelInboundHandler<Object> {
private static final Field HANDSHAKE; private static final Field HANDSHAKE;
private static final Class<?> HANDSHAKE_PACKET; private static final Class<?> HANDSHAKE_PACKET;
private static final Field HANDSHAKE_SERVER_ADDRESS; 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 ProxyFloodgateConfig config;
private final ProxyFloodgateApi api; private final ProxyFloodgateApi api;
private final HandshakeHandler handshakeHandler; private final HandshakeHandler handshakeHandler;
private final AttributeKey<FloodgatePlayer> playerAttribute; private final AttributeKey<FloodgatePlayer> playerAttribute;
private final AttributeKey<String> kickMessageAttribute; private final AttributeKey<String> kickMessageAttribute;
private final FloodgateLogger logger; private final FloodgateLogger logger;
private boolean done; private boolean done;
@Override @Override
@@ -102,19 +114,4 @@ public final class VelocityProxyDataHandler extends SimpleChannelInboundHandler<
logger.info("Floodgate player who is logged in as {} {} joined", logger.info("Floodgate player who is logged in as {} {} joined",
player.getCorrectUsername(), player.getCorrectUniqueId()); 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; 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 com.velocitypowered.api.proxy.Player;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageEncoder; import io.netty.handler.codec.MessageToMessageEncoder;
import io.netty.util.ReferenceCountUtil; import io.netty.util.ReferenceCountUtil;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.geysermc.floodgate.api.ProxyFloodgateApi; import org.geysermc.floodgate.api.ProxyFloodgateApi;
import org.geysermc.floodgate.api.player.FloodgatePlayer; import org.geysermc.floodgate.api.player.FloodgatePlayer;
import org.geysermc.floodgate.config.ProxyFloodgateConfig; 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 @RequiredArgsConstructor
public class VelocityServerDataHandler extends MessageToMessageEncoder<Object> { public final class VelocityServerDataHandler extends MessageToMessageEncoder<Object> {
private static final Class<?> HANDSHAKE_PACKET; private static final Class<?> HANDSHAKE_PACKET;
private static final Field HANDSHAKE_ADDRESS; private static final Field HANDSHAKE_ADDRESS;
private static final Method GET_ASSOCIATION; private static final Method GET_ASSOCIATION;
private static final Method GET_PLAYER; 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 ProxyFloodgateConfig config;
private final ProxyFloodgateApi api; private final ProxyFloodgateApi api;
private boolean done; private boolean done;
@Override @Override
@@ -63,7 +85,8 @@ public class VelocityServerDataHandler extends MessageToMessageEncoder<Object> {
} }
if (!HANDSHAKE_PACKET.isInstance(packet) || !config.isSendFloodgateData()) { 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; done = true;
out.add(packet); out.add(packet);
return; return;
@@ -99,22 +122,4 @@ public class VelocityServerDataHandler extends MessageToMessageEncoder<Object> {
done = true; done = true;
out.add(packet); 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.CommandManager;
import com.velocitypowered.api.command.CommandSource; import com.velocitypowered.api.command.CommandSource;
import com.velocitypowered.api.proxy.Player; import com.velocitypowered.api.proxy.Player;
import java.util.Locale;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.NonNull;
import org.geysermc.floodgate.platform.command.Command; 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.platform.command.CommandUtil;
import org.geysermc.floodgate.util.LanguageManager; import org.geysermc.floodgate.util.LanguageManager;
import java.util.Locale;
@RequiredArgsConstructor @RequiredArgsConstructor
public final class VelocityCommandRegistration implements CommandRegistration { public final class VelocityCommandRegistration implements CommandRegistration {
private final CommandManager commandManager; private final CommandManager commandManager;

View File

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

View File

@@ -25,6 +25,11 @@
package org.geysermc.floodgate.listener; 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.Cache;
import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheBuilder;
import com.google.inject.Inject; import com.google.inject.Inject;
@@ -40,23 +45,36 @@ import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.api.util.GameProfile; import com.velocitypowered.api.util.GameProfile;
import io.netty.channel.Channel; import io.netty.channel.Channel;
import io.netty.util.AttributeKey; 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 net.kyori.adventure.text.TextComponent;
import org.geysermc.floodgate.api.ProxyFloodgateApi; import org.geysermc.floodgate.api.ProxyFloodgateApi;
import org.geysermc.floodgate.api.logger.FloodgateLogger; import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.api.player.FloodgatePlayer; import org.geysermc.floodgate.api.player.FloodgatePlayer;
import org.geysermc.floodgate.util.LanguageManager; 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 { public final class VelocityListener {
private static final Field INITIAL_MINECRAFT_CONNECTION; private static final Field INITIAL_MINECRAFT_CONNECTION;
private static final Field MINECRAFT_CONNECTION; private static final Field MINECRAFT_CONNECTION;
private static final Field CHANNEL; 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 ProxyFloodgateApi api;
@Inject private LanguageManager languageManager; @Inject private LanguageManager languageManager;
@Inject private FloodgateLogger logger; @Inject private FloodgateLogger logger;
@@ -69,12 +87,6 @@ public final class VelocityListener {
@Named("kickMessageAttribute") @Named("kickMessageAttribute")
private AttributeKey<String> kickMessageAttribute; private AttributeKey<String> kickMessageAttribute;
private final Cache<InboundConnection, FloodgatePlayer> playerCache =
CacheBuilder.newBuilder()
.maximumSize(500)
.expireAfterAccess(20, TimeUnit.SECONDS)
.build();
@Subscribe(order = PostOrder.EARLY) @Subscribe(order = PostOrder.EARLY)
public void onPreLogin(PreLoginEvent event) { public void onPreLogin(PreLoginEvent event) {
FloodgatePlayer player = null; FloodgatePlayer player = null;
@@ -91,7 +103,9 @@ public final class VelocityListener {
} }
if (kickMessage != null) { if (kickMessage != null) {
event.setResult(PreLoginEvent.PreLoginComponentResult.denied(TextComponent.of(kickMessage))); event.setResult(
PreLoginEvent.PreLoginComponentResult.denied(TextComponent.of(kickMessage))
);
return; return;
} }
@@ -111,13 +125,15 @@ public final class VelocityListener {
} }
} }
@Subscribe @Subscribe(order = PostOrder.LAST)
public void onLogin(LoginEvent event) { public void onLogin(LoginEvent event) {
if (event.getResult().isAllowed()) {
FloodgatePlayer player = api.getPlayer(event.getPlayer().getUniqueId()); FloodgatePlayer player = api.getPlayer(event.getPlayer().getUniqueId());
if (player != null) { if (player != null) {
languageManager.loadLocale(player.getLanguageCode()); languageManager.loadLocale(player.getLanguageCode());
} }
} }
}
@Subscribe(order = PostOrder.LAST) @Subscribe(order = PostOrder.LAST)
public void onDisconnect(DisconnectEvent event) { public void onDisconnect(DisconnectEvent event) {
@@ -129,22 +145,10 @@ public final class VelocityListener {
if (fPlayer != null && api.removePlayer(fPlayer)) { if (fPlayer != null && api.removePlayer(fPlayer)) {
api.removeEncryptedData(event.getPlayer().getUniqueId()); api.removeEncryptedData(event.getPlayer().getUniqueId());
logger.info(languageManager.getLogString( logger.translatedInfo("floodgate.ingame.disconnect_name", player.getUsername());
"floodgate.ingame.disconnect_name", player.getUsername()
));
} }
} catch (Exception exception) { } catch (Exception exception) {
logger.error("Failed to remove the player", 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; package org.geysermc.floodgate.logger;
import static org.geysermc.floodgate.util.MessageFormatter.format;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.apache.logging.log4j.Level; import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.core.config.Configurator; import org.apache.logging.log4j.core.config.Configurator;
import org.geysermc.floodgate.api.logger.FloodgateLogger; import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.util.LanguageManager;
import org.slf4j.Logger; import org.slf4j.Logger;
import static org.geysermc.floodgate.util.MessageFormatter.format;
@RequiredArgsConstructor @RequiredArgsConstructor
public final class Slf4jFloodgateLogger implements FloodgateLogger { public final class Slf4jFloodgateLogger implements FloodgateLogger {
private final Logger logger; private final Logger logger;
private final LanguageManager languageManager;
@Override @Override
public void error(String message, Object... args) { public void error(String message, Object... args) {
@@ -57,6 +59,11 @@ public final class Slf4jFloodgateLogger implements FloodgateLogger {
logger.info(message, args); logger.info(message, args);
} }
@Override
public void translatedInfo(String message, Object... args) {
logger.info(languageManager.getLogString(message, args));
}
@Override @Override
public void debug(String message, Object... args) { public void debug(String message, Object... args) {
logger.debug(message, args); logger.debug(message, args);

View File

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

View File

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