Compare commits
	
		
			34 Commits
		
	
	
		
			adaebb32f5
			...
			6bb83c4e61
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 6bb83c4e61 | |||
| e28802d3ff | |||
| 754798b372 | |||
| 0bc21968d9 | |||
| e41691bd57 | |||
| c237bd3895 | |||
| ![dependabot[bot]](/assets/img/avatar_default.png)  | 3e9a7e45c4 | ||
| ![dependabot[bot]](/assets/img/avatar_default.png)  | f6c5332c1a | ||
|   | d0fa62d424 | ||
|   | 464ed0184c | ||
|   | eda268b481 | ||
|   | 3e1007527c | ||
|   | b52b14696c | ||
|   | 94d5b0d03c | ||
|   | c3f228f626 | ||
|   | 02c5c1ee76 | ||
|   | c69acf728c | ||
|   | a1cd694363 | ||
|   | 3e2bc8e2d7 | ||
| ![dependabot[bot]](/assets/img/avatar_default.png)  | ad7163d2d6 | ||
|   | 19918c694f | ||
|   | 21c8f2815a | ||
|   | 737d545fb6 | ||
| ![dependabot[bot]](/assets/img/avatar_default.png)  | b23a51825e | ||
|   | 708c5b6254 | ||
|   | f5af11193c | ||
|   | b711e4033f | ||
|   | 3deaaadc3a | ||
| ![dependabot[bot]](/assets/img/avatar_default.png)  | 51b9a6b0b8 | ||
| ![dependabot[bot]](/assets/img/avatar_default.png)  | 1a807731a5 | ||
| ![dependabot[bot]](/assets/img/avatar_default.png)  | 772ad9951f | ||
| ![dependabot[bot]](/assets/img/avatar_default.png)  | 2431c40a5c | ||
| ![dependabot[bot]](/assets/img/avatar_default.png)  | 8144ae8d7b | ||
|   | 0757c39a6f | 
							
								
								
									
										3
									
								
								.github/dependabot.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.github/dependabot.yml
									
									
									
									
										vendored
									
									
								
							| @@ -13,10 +13,9 @@ updates: | |||||||
|       - dependency-name: "com.puppycrawl.tools:checkstyle" |       - dependency-name: "com.puppycrawl.tools:checkstyle" | ||||||
|         # Newer versions have issues, see #1909 and #2050 |         # Newer versions have issues, see #1909 and #2050 | ||||||
|       - dependency-name: "jline:jline" |       - dependency-name: "jline:jline" | ||||||
|         # Later versions of these Maven dependencies are incompatible and require careful management - see SPIGOT-7400 |         # Needs to be synchronised with maven-resolver-provider dependencies | ||||||
|       - dependency-name: "org.apache.maven.resolver:maven-resolver-connector-basic" |       - dependency-name: "org.apache.maven.resolver:maven-resolver-connector-basic" | ||||||
|       - dependency-name: "org.apache.maven.resolver:maven-resolver-transport-http" |       - dependency-name: "org.apache.maven.resolver:maven-resolver-transport-http" | ||||||
|       - dependency-name: "org.apache.maven:maven-resolver-provider" |  | ||||||
|         # Used with maven-resolver dependencies; 2.0 update breaks other providers |         # Used with maven-resolver dependencies; 2.0 update breaks other providers | ||||||
|       - dependency-name: "org.slf4j:slf4j-api" |       - dependency-name: "org.slf4j:slf4j-api" | ||||||
|         update-types: ["version-update:semver-major"] |         update-types: ["version-update:semver-major"] | ||||||
|   | |||||||
							
								
								
									
										2
									
								
								.github/workflows/maven.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/maven.yml
									
									
									
									
										vendored
									
									
								
							| @@ -15,7 +15,7 @@ jobs: | |||||||
|  |  | ||||||
|     steps: |     steps: | ||||||
|     - uses: actions/checkout@v4 |     - uses: actions/checkout@v4 | ||||||
|     - uses: actions/setup-java@v3 |     - uses: actions/setup-java@v4 | ||||||
|       with: |       with: | ||||||
|         distribution: zulu |         distribution: zulu | ||||||
|         java-version: ${{ matrix.java }} |         java-version: ${{ matrix.java }} | ||||||
|   | |||||||
							
								
								
									
										21
									
								
								api/pom.xml
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								api/pom.xml
									
									
									
									
									
								
							| @@ -4,15 +4,14 @@ | |||||||
|     <modelVersion>4.0.0</modelVersion> |     <modelVersion>4.0.0</modelVersion> | ||||||
|  |  | ||||||
|     <parent> |     <parent> | ||||||
|         <groupId>net.md-5</groupId> |         <groupId>fr.pandacube.bungeecord</groupId> | ||||||
|         <artifactId>bungeecord-parent</artifactId> |         <artifactId>bungeecord-parent</artifactId> | ||||||
|         <version>1.20-R0.2-SNAPSHOT</version> |         <version>1.20-R0.3-SNAPSHOT</version> | ||||||
|         <relativePath>../pom.xml</relativePath> |         <relativePath>../pom.xml</relativePath> | ||||||
|     </parent> |     </parent> | ||||||
|  |  | ||||||
|     <groupId>net.md-5</groupId> |  | ||||||
|     <artifactId>bungeecord-api</artifactId> |     <artifactId>bungeecord-api</artifactId> | ||||||
|     <version>1.20-R0.2-SNAPSHOT</version> |     <version>1.20-R0.3-SNAPSHOT</version> | ||||||
|     <packaging>jar</packaging> |     <packaging>jar</packaging> | ||||||
|  |  | ||||||
|     <name>BungeeCord-API</name> |     <name>BungeeCord-API</name> | ||||||
| @@ -20,25 +19,25 @@ | |||||||
|  |  | ||||||
|     <dependencies> |     <dependencies> | ||||||
|         <dependency> |         <dependency> | ||||||
|             <groupId>net.md-5</groupId> |             <groupId>fr.pandacube.bungeecord</groupId> | ||||||
|             <artifactId>bungeecord-chat</artifactId> |             <artifactId>bungeecord-chat</artifactId> | ||||||
|             <version>${project.version}</version> |             <version>${project.version}</version> | ||||||
|             <scope>compile</scope> |             <scope>compile</scope> | ||||||
|         </dependency> |         </dependency> | ||||||
|         <dependency> |         <dependency> | ||||||
|             <groupId>net.md-5</groupId> |             <groupId>fr.pandacube.bungeecord</groupId> | ||||||
|             <artifactId>bungeecord-config</artifactId> |             <artifactId>bungeecord-config</artifactId> | ||||||
|             <version>${project.version}</version> |             <version>${project.version}</version> | ||||||
|             <scope>compile</scope> |             <scope>compile</scope> | ||||||
|         </dependency> |         </dependency> | ||||||
|         <dependency> |         <dependency> | ||||||
|             <groupId>net.md-5</groupId> |             <groupId>fr.pandacube.bungeecord</groupId> | ||||||
|             <artifactId>bungeecord-event</artifactId> |             <artifactId>bungeecord-event</artifactId> | ||||||
|             <version>${project.version}</version> |             <version>${project.version}</version> | ||||||
|             <scope>compile</scope> |             <scope>compile</scope> | ||||||
|         </dependency> |         </dependency> | ||||||
|         <dependency> |         <dependency> | ||||||
|             <groupId>net.md-5</groupId> |             <groupId>fr.pandacube.bungeecord</groupId> | ||||||
|             <artifactId>bungeecord-protocol</artifactId> |             <artifactId>bungeecord-protocol</artifactId> | ||||||
|             <version>${project.version}</version> |             <version>${project.version}</version> | ||||||
|             <scope>compile</scope> |             <scope>compile</scope> | ||||||
| @@ -51,21 +50,21 @@ | |||||||
|         <dependency> |         <dependency> | ||||||
|             <groupId>org.apache.maven</groupId> |             <groupId>org.apache.maven</groupId> | ||||||
|             <artifactId>maven-resolver-provider</artifactId> |             <artifactId>maven-resolver-provider</artifactId> | ||||||
|             <version>3.8.5</version> |             <version>3.9.6</version> | ||||||
|             <!-- not part of the API proper --> |             <!-- not part of the API proper --> | ||||||
|             <scope>provided</scope> |             <scope>provided</scope> | ||||||
|         </dependency> |         </dependency> | ||||||
|         <dependency> |         <dependency> | ||||||
|             <groupId>org.apache.maven.resolver</groupId> |             <groupId>org.apache.maven.resolver</groupId> | ||||||
|             <artifactId>maven-resolver-connector-basic</artifactId> |             <artifactId>maven-resolver-connector-basic</artifactId> | ||||||
|             <version>1.7.3</version> |             <version>1.9.18</version> | ||||||
|             <!-- not part of the API proper --> |             <!-- not part of the API proper --> | ||||||
|             <scope>provided</scope> |             <scope>provided</scope> | ||||||
|         </dependency> |         </dependency> | ||||||
|         <dependency> |         <dependency> | ||||||
|             <groupId>org.apache.maven.resolver</groupId> |             <groupId>org.apache.maven.resolver</groupId> | ||||||
|             <artifactId>maven-resolver-transport-http</artifactId> |             <artifactId>maven-resolver-transport-http</artifactId> | ||||||
|             <version>1.7.3</version> |             <version>1.9.18</version> | ||||||
|             <!-- not part of the API proper --> |             <!-- not part of the API proper --> | ||||||
|             <scope>provided</scope> |             <scope>provided</scope> | ||||||
|         </dependency> |         </dependency> | ||||||
|   | |||||||
| @@ -2,7 +2,9 @@ package net.md_5.bungee.api.connection; | |||||||
|  |  | ||||||
| import java.net.InetSocketAddress; | import java.net.InetSocketAddress; | ||||||
| import java.util.UUID; | import java.util.UUID; | ||||||
|  | import java.util.concurrent.CompletableFuture; | ||||||
| import net.md_5.bungee.api.config.ListenerInfo; | import net.md_5.bungee.api.config.ListenerInfo; | ||||||
|  | import org.jetbrains.annotations.ApiStatus; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Represents a user attempting to log into the proxy. |  * Represents a user attempting to log into the proxy. | ||||||
| @@ -89,4 +91,26 @@ public interface PendingConnection extends Connection | |||||||
|      * @return Whether the client is using a legacy client. |      * @return Whether the client is using a legacy client. | ||||||
|      */ |      */ | ||||||
|     boolean isLegacy(); |     boolean isLegacy(); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Gets if this connection has been transferred from another server. | ||||||
|  |      * | ||||||
|  |      * @return true if the connection has been transferred | ||||||
|  |      */ | ||||||
|  |     @ApiStatus.Experimental | ||||||
|  |     boolean isTransferred(); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Retrieves a cookie from this pending connection. | ||||||
|  |      * | ||||||
|  |      * @param cookie the resource location of the cookie, for example | ||||||
|  |      * "bungeecord:my_cookie" | ||||||
|  |      * @return a {@link CompletableFuture} that will be completed when the | ||||||
|  |      * Cookie response is received. If the cookie is not set in the client, the | ||||||
|  |      * {@link CompletableFuture} will complete with a null value | ||||||
|  |      * @throws IllegalStateException if the player's version is not at least | ||||||
|  |      * 1.20.5 | ||||||
|  |      */ | ||||||
|  |     @ApiStatus.Experimental | ||||||
|  |     CompletableFuture<byte[]> retrieveCookie(String cookie); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -3,6 +3,7 @@ package net.md_5.bungee.api.connection; | |||||||
| import java.util.Locale; | import java.util.Locale; | ||||||
| import java.util.Map; | import java.util.Map; | ||||||
| import java.util.UUID; | import java.util.UUID; | ||||||
|  | import java.util.concurrent.CompletableFuture; | ||||||
| import net.md_5.bungee.api.Callback; | import net.md_5.bungee.api.Callback; | ||||||
| import net.md_5.bungee.api.ChatMessageType; | import net.md_5.bungee.api.ChatMessageType; | ||||||
| import net.md_5.bungee.api.CommandSender; | import net.md_5.bungee.api.CommandSender; | ||||||
| @@ -13,6 +14,7 @@ import net.md_5.bungee.api.chat.BaseComponent; | |||||||
| import net.md_5.bungee.api.config.ServerInfo; | import net.md_5.bungee.api.config.ServerInfo; | ||||||
| import net.md_5.bungee.api.event.ServerConnectEvent; | import net.md_5.bungee.api.event.ServerConnectEvent; | ||||||
| import net.md_5.bungee.api.score.Scoreboard; | import net.md_5.bungee.api.score.Scoreboard; | ||||||
|  | import org.jetbrains.annotations.ApiStatus; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Represents a player whose connection is being connected to somewhere else, |  * Represents a player whose connection is being connected to somewhere else, | ||||||
| @@ -339,4 +341,45 @@ public interface ProxiedPlayer extends Connection, CommandSender | |||||||
|      */ |      */ | ||||||
|     @Deprecated |     @Deprecated | ||||||
|     Scoreboard getScoreboard(); |     Scoreboard getScoreboard(); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Retrieves a cookie from this player. | ||||||
|  |      * | ||||||
|  |      * @param cookie the resource location of the cookie, for example | ||||||
|  |      * "bungeecord:my_cookie" | ||||||
|  |      * @return a {@link CompletableFuture} that will be completed when the | ||||||
|  |      * Cookie response is received. If the cookie is not set in the client, the | ||||||
|  |      * {@link CompletableFuture} will complete with a null value | ||||||
|  |      * @throws IllegalStateException if the player's version is not at least | ||||||
|  |      * 1.20.5 | ||||||
|  |      */ | ||||||
|  |     @ApiStatus.Experimental | ||||||
|  |     CompletableFuture<byte[]> retrieveCookie(String cookie); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Stores a cookie in this player's client. | ||||||
|  |      * | ||||||
|  |      * @param cookie the resource location of the cookie, for example | ||||||
|  |      * "bungeecord:my_cookie" | ||||||
|  |      * @param data the data to store in the cookie | ||||||
|  |      * @throws IllegalStateException if the player's version is not at least | ||||||
|  |      * 1.20.5 | ||||||
|  |      */ | ||||||
|  |     @ApiStatus.Experimental | ||||||
|  |     void storeCookie(String cookie, byte[] data); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Requests this player to connect to a different server specified by host | ||||||
|  |      * and port. | ||||||
|  |      * | ||||||
|  |      * This is a client-side transfer - host and port should not specify a | ||||||
|  |      * BungeeCord backend server. | ||||||
|  |      * | ||||||
|  |      * @param host the host of the server to transfer to | ||||||
|  |      * @param port the port of the server to transfer to | ||||||
|  |      * @throws IllegalStateException if the players version is not at least | ||||||
|  |      * 1.20.5 | ||||||
|  |      */ | ||||||
|  |     @ApiStatus.Experimental | ||||||
|  |     void transfer(String host, int port); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -0,0 +1,157 @@ | |||||||
|  | package net.md_5.bungee.api.event; | ||||||
|  |  | ||||||
|  | import com.mojang.brigadier.arguments.ArgumentType; | ||||||
|  | import com.mojang.brigadier.arguments.IntegerArgumentType; | ||||||
|  | import com.mojang.brigadier.arguments.StringArgumentType; | ||||||
|  | import com.mojang.brigadier.builder.ArgumentBuilder; | ||||||
|  | import com.mojang.brigadier.builder.RequiredArgumentBuilder; | ||||||
|  | import com.mojang.brigadier.suggestion.SuggestionProvider; | ||||||
|  | import com.mojang.brigadier.tree.CommandNode; | ||||||
|  | import com.mojang.brigadier.tree.RootCommandNode; | ||||||
|  | import lombok.AccessLevel; | ||||||
|  | import lombok.Data; | ||||||
|  | import lombok.EqualsAndHashCode; | ||||||
|  | import lombok.Setter; | ||||||
|  | import lombok.ToString; | ||||||
|  | import net.md_5.bungee.api.CommandSender; | ||||||
|  | import net.md_5.bungee.api.connection.Connection; | ||||||
|  | import net.md_5.bungee.api.plugin.Command; | ||||||
|  | import net.md_5.bungee.api.plugin.Plugin; | ||||||
|  | import net.md_5.bungee.api.plugin.PluginManager; | ||||||
|  | import net.md_5.bungee.api.plugin.TabExecutor; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Event called when a downstream server (on 1.13+) sends the command structure | ||||||
|  |  * to a player, but before BungeeCord adds the dummy command nodes of | ||||||
|  |  * registered commands. | ||||||
|  |  * <p> | ||||||
|  |  * BungeeCord will not overwrite the modifications made by the listeners. | ||||||
|  |  * | ||||||
|  |  * <h2>Usage example</h2> | ||||||
|  |  * Here is a usage example of this event, to declare a command structure. | ||||||
|  |  * This illustrates the commands /server and /send of Bungee. | ||||||
|  |  * <pre> | ||||||
|  |  * event.getRoot().addChild( LiteralArgumentBuilder.<CommandSender>literal( "server" ) | ||||||
|  |  *         .requires( sender -> sender.hasPermission( "bungeecord.command.server" ) ) | ||||||
|  |  *         .executes( a -> 0 ) | ||||||
|  |  *         .then( RequiredArgumentBuilder.argument( "serverName", StringArgumentType.greedyString() ) | ||||||
|  |  *                 .suggests( SuggestionRegistry.ASK_SERVER ) | ||||||
|  |  *         ) | ||||||
|  |  *         .build() | ||||||
|  |  * ); | ||||||
|  |  * event.getRoot().addChild( LiteralArgumentBuilder.<CommandSender>literal( "send" ) | ||||||
|  |  *         .requires( sender -> sender.hasPermission( "bungeecord.command.send" ) ) | ||||||
|  |  *         .then( RequiredArgumentBuilder.argument( "playerName", StringArgumentType.word() ) | ||||||
|  |  *                 .suggests( SuggestionRegistry.ASK_SERVER ) | ||||||
|  |  *                 .then( RequiredArgumentBuilder.argument( "serverName", StringArgumentType.greedyString() ) | ||||||
|  |  *                         .suggests( SuggestionRegistry.ASK_SERVER ) | ||||||
|  |  *                 ) | ||||||
|  |  *         ) | ||||||
|  |  *         .build() | ||||||
|  |  * ); | ||||||
|  |  * </pre> | ||||||
|  |  * | ||||||
|  |  * <h2>Flag a {@link CommandNode} as executable or not</h2> | ||||||
|  |  * The implementation of a {@link com.mojang.brigadier.Command Command} used in | ||||||
|  |  * {@link ArgumentBuilder#executes(com.mojang.brigadier.Command)} will never be | ||||||
|  |  * executed. This will only tell to the client if the current node is | ||||||
|  |  * executable or not. | ||||||
|  |  * <ul> | ||||||
|  |  *     <li> | ||||||
|  |  *         {@code builder.executes(null)} (default) to mark the node as not | ||||||
|  |  *         executable. | ||||||
|  |  *     </li> | ||||||
|  |  *     <li> | ||||||
|  |  *         {@code builder.executes(a -> 0)}, or any non null argument, to mark | ||||||
|  |  *         the node as executable (the child arguments are displayed as | ||||||
|  |  *         optional). | ||||||
|  |  *     </li> | ||||||
|  |  * </ul> | ||||||
|  |  * | ||||||
|  |  * <h2>{@link CommandNode}’s suggestions management</h2> | ||||||
|  |  * The implementation of a SuggestionProvider used in | ||||||
|  |  * {@link RequiredArgumentBuilder#suggests(SuggestionProvider)} will never be | ||||||
|  |  * executed. This will only tell to the client how to deal with the | ||||||
|  |  * auto-completion of the argument. | ||||||
|  |  * <ul> | ||||||
|  |  *     <li> | ||||||
|  |  *         {@code builder.suggests(null)} (default) to disable auto-completion | ||||||
|  |  *         for this argument. | ||||||
|  |  *     </li> | ||||||
|  |  *     <li> | ||||||
|  |  *         {@code builder.suggests(SuggestionRegistry.ALL_RECIPES)} to suggest | ||||||
|  |  *         Minecraft’s recipes. | ||||||
|  |  *     </li> | ||||||
|  |  *     <li> | ||||||
|  |  *         {@code builder.suggests(SuggestionRegistry.AVAILABLE_SOUNDS)} to | ||||||
|  |  *         suggest Minecraft’s default sound identifiers. | ||||||
|  |  *     </li> | ||||||
|  |  *     <li> | ||||||
|  |  *         {@code builder.suggests(SuggestionRegistry.SUMMONABLE_ENTITIES)} to | ||||||
|  |  *         suggest Minecraft’s default summonable entities identifiers. | ||||||
|  |  *     </li> | ||||||
|  |  *     <li> | ||||||
|  |  *         {@code builder.suggests(SuggestionRegistry.ASK_SERVER)}, or any | ||||||
|  |  *         other non null argument, to make the Minecraft client ask | ||||||
|  |  *         auto-completion to the server. Any specified implementation of | ||||||
|  |  *         {@link SuggestionProvider} will never be executed. | ||||||
|  |  *     </li> | ||||||
|  |  * </ul> | ||||||
|  |  * | ||||||
|  |  * <h2>Argument types</h2> | ||||||
|  |  * When building a new argument command node using | ||||||
|  |  * {@link RequiredArgumentBuilder#argument(String, ArgumentType)}, you have to | ||||||
|  |  * specify an {@link ArgumentType}. You can use all subclasses of | ||||||
|  |  * {@link ArgumentType} provided with brigadier (for instance, | ||||||
|  |  * {@link StringArgumentType} or {@link IntegerArgumentType}), or call any | ||||||
|  |  * {@code ArgumentRegistry.minecraft*()} methods to use a {@code minecraft:*} | ||||||
|  |  * argument type. | ||||||
|  |  * | ||||||
|  |  * <h2>Limitations with brigadier API</h2> | ||||||
|  |  * This event is only used for the client to show command syntax, suggest | ||||||
|  |  * sub-commands and color the arguments in the chat box. The command execution | ||||||
|  |  * needs to be implemented using {@link PluginManager#registerCommand(Plugin, | ||||||
|  |  * Command)} and the server-side tab-completion using {@link TabCompleteEvent} | ||||||
|  |  * or {@link TabExecutor}. | ||||||
|  |  */ | ||||||
|  | @Data | ||||||
|  | @ToString(callSuper = true) | ||||||
|  | @EqualsAndHashCode(callSuper = true) | ||||||
|  | public class CommandsDeclareEvent extends TargetedEvent | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Wether or not the command tree is modified by this event. | ||||||
|  |      * | ||||||
|  |      * If this value is set to true, BungeeCord will ensure that the | ||||||
|  |      * modifications made in the command tree, will be sent to the player. | ||||||
|  |      * If this is false, the modifications may not be taken into account. | ||||||
|  |      * | ||||||
|  |      * When calling {@link #getRoot()}, this value is automatically set | ||||||
|  |      * to true. | ||||||
|  |      */ | ||||||
|  |     @Setter(value = AccessLevel.NONE) | ||||||
|  |     private boolean modified = false; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * The root command node of the command structure that will be send to the | ||||||
|  |      * player. | ||||||
|  |      */ | ||||||
|  |     private final RootCommandNode<CommandSender> root; | ||||||
|  |  | ||||||
|  |     public CommandsDeclareEvent(Connection sender, Connection receiver, RootCommandNode<CommandSender> root) | ||||||
|  |     { | ||||||
|  |         super( sender, receiver ); | ||||||
|  |         this.root = root; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * The root command node of the command structure that will be send to the | ||||||
|  |      * player. | ||||||
|  |      * @return The root command node | ||||||
|  |      */ | ||||||
|  |     public RootCommandNode<CommandSender> getRoot() | ||||||
|  |     { | ||||||
|  |         modified = true; | ||||||
|  |         return root; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -9,7 +9,9 @@ import net.md_5.bungee.api.plugin.Cancellable; | |||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Event called when a player uses tab completion. |  * Event called when a player uses tab completion. | ||||||
|  |  * @deprecated please use {@link TabCompleteRequestEvent} to support 1.13+ suggestions. | ||||||
|  */ |  */ | ||||||
|  | @Deprecated | ||||||
| @Data | @Data | ||||||
| @ToString(callSuper = true) | @ToString(callSuper = true) | ||||||
| @EqualsAndHashCode(callSuper = true) | @EqualsAndHashCode(callSuper = true) | ||||||
|   | |||||||
| @@ -0,0 +1,85 @@ | |||||||
|  | package net.md_5.bungee.api.event; | ||||||
|  |  | ||||||
|  | import com.google.common.base.Preconditions; | ||||||
|  | import com.mojang.brigadier.context.StringRange; | ||||||
|  | import com.mojang.brigadier.suggestion.Suggestions; | ||||||
|  | import lombok.Data; | ||||||
|  | import lombok.EqualsAndHashCode; | ||||||
|  | import lombok.ToString; | ||||||
|  | import net.md_5.bungee.api.connection.Connection; | ||||||
|  | import net.md_5.bungee.api.connection.ProxiedPlayer; | ||||||
|  | import net.md_5.bungee.api.plugin.Cancellable; | ||||||
|  | import net.md_5.bungee.protocol.ProtocolConstants; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Event called when a player uses tab completion. | ||||||
|  |  */ | ||||||
|  | @Data | ||||||
|  | @ToString(callSuper = true) | ||||||
|  | @EqualsAndHashCode(callSuper = true) | ||||||
|  | public class TabCompleteRequestEvent extends TargetedEvent implements Cancellable | ||||||
|  | { | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Cancelled state. | ||||||
|  |      */ | ||||||
|  |     private boolean cancelled; | ||||||
|  |     /** | ||||||
|  |      * The message the player has already entered. | ||||||
|  |      */ | ||||||
|  |     private final String cursor; | ||||||
|  |     /** | ||||||
|  |      * Range corresponding to the last word of {@link #getCursor()}. | ||||||
|  |      * If you want your suggestions to be compatible with 1.12 and older | ||||||
|  |      * clients, you need to {@link #setSuggestions(Suggestions)} with | ||||||
|  |      * a range equals to this one. | ||||||
|  |      * For 1.13 and newer clients, any other range that cover any part of | ||||||
|  |      * {@link #getCursor()} is fine.<br> | ||||||
|  |      * To check if the client supports custom ranges, use | ||||||
|  |      * {@link #supportsCustomRange()}. | ||||||
|  |      */ | ||||||
|  |     private final StringRange legacyCompatibleRange; | ||||||
|  |     /** | ||||||
|  |      * The suggestions that will be sent to the client. If this list is empty, | ||||||
|  |      * the request will be forwarded to the server. | ||||||
|  |      */ | ||||||
|  |     private Suggestions suggestions; | ||||||
|  |  | ||||||
|  |     public TabCompleteRequestEvent(Connection sender, Connection receiver, String cursor, StringRange legacyCompatibleRange, Suggestions suggestions) | ||||||
|  |     { | ||||||
|  |         super( sender, receiver ); | ||||||
|  |         this.cursor = cursor; | ||||||
|  |         this.legacyCompatibleRange = legacyCompatibleRange; | ||||||
|  |         this.suggestions = suggestions; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Sets the suggestions that will be sent to the client. | ||||||
|  |      * If this list is empty, the request will be forwarded to the server. | ||||||
|  |      * @param suggestions the new Suggestions. Cannot be null. | ||||||
|  |      * @throws IllegalArgumentException if the client is on 1.12 or lower and | ||||||
|  |      * {@code suggestions.getRange()} is not equals to {@link #legacyCompatibleRange}. | ||||||
|  |      */ | ||||||
|  |     public void setSuggestions(Suggestions suggestions) | ||||||
|  |     { | ||||||
|  |         Preconditions.checkNotNull( suggestions ); | ||||||
|  |         Preconditions.checkArgument( supportsCustomRange() || legacyCompatibleRange.equals( suggestions.getRange() ), | ||||||
|  |                 "Clients on 1.12 or lower versions don't support the provided range for tab-completion: " + suggestions.getRange() | ||||||
|  |                 + ". Please use TabCompleteRequestEvent.getLegacyCompatibleRange() for legacy clients." ); | ||||||
|  |         this.suggestions = suggestions; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Convenient method to tell if the client supports custom range for | ||||||
|  |      * suggestions. | ||||||
|  |      * If the client is on 1.13 or above, this methods returns true, and any | ||||||
|  |      * range can be used for {@link #setSuggestions(Suggestions)}. Otherwise, | ||||||
|  |      * it returns false and the defined range must be equals to | ||||||
|  |      * {@link #legacyCompatibleRange}. | ||||||
|  |      * @return true if the client is on 1.13 or newer version, false otherwise. | ||||||
|  |      */ | ||||||
|  |     public boolean supportsCustomRange() | ||||||
|  |     { | ||||||
|  |         return ( (ProxiedPlayer) getSender() ).getPendingConnection().getVersion() >= ProtocolConstants.MINECRAFT_1_13; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -4,15 +4,14 @@ | |||||||
|     <modelVersion>4.0.0</modelVersion> |     <modelVersion>4.0.0</modelVersion> | ||||||
|  |  | ||||||
|     <parent> |     <parent> | ||||||
|         <groupId>net.md-5</groupId> |         <groupId>fr.pandacube.bungeecord</groupId> | ||||||
|         <artifactId>bungeecord-parent</artifactId> |         <artifactId>bungeecord-parent</artifactId> | ||||||
|         <version>1.20-R0.2-SNAPSHOT</version> |         <version>1.20-R0.3-SNAPSHOT</version> | ||||||
|         <relativePath>../pom.xml</relativePath> |         <relativePath>../pom.xml</relativePath> | ||||||
|     </parent> |     </parent> | ||||||
|  |  | ||||||
|     <groupId>net.md-5</groupId> |  | ||||||
|     <artifactId>bungeecord-bootstrap</artifactId> |     <artifactId>bungeecord-bootstrap</artifactId> | ||||||
|     <version>1.20-R0.2-SNAPSHOT</version> |     <version>1.20-R0.3-SNAPSHOT</version> | ||||||
|     <packaging>jar</packaging> |     <packaging>jar</packaging> | ||||||
|  |  | ||||||
|     <name>BungeeCord-Bootstrap</name> |     <name>BungeeCord-Bootstrap</name> | ||||||
| @@ -21,14 +20,12 @@ | |||||||
|     <properties> |     <properties> | ||||||
|         <maven.deploy.skip>true</maven.deploy.skip> |         <maven.deploy.skip>true</maven.deploy.skip> | ||||||
|         <maven.javadoc.skip>true</maven.javadoc.skip> |         <maven.javadoc.skip>true</maven.javadoc.skip> | ||||||
|         <maven.compiler.source>1.6</maven.compiler.source> |  | ||||||
|         <maven.compiler.target>1.6</maven.compiler.target> |  | ||||||
|         <maven.build.timestamp.format>yyyyMMdd</maven.build.timestamp.format> |         <maven.build.timestamp.format>yyyyMMdd</maven.build.timestamp.format> | ||||||
|     </properties> |     </properties> | ||||||
|  |  | ||||||
|     <dependencies> |     <dependencies> | ||||||
|         <dependency> |         <dependency> | ||||||
|             <groupId>net.md-5</groupId> |             <groupId>fr.pandacube.bungeecord</groupId> | ||||||
|             <artifactId>bungeecord-proxy</artifactId> |             <artifactId>bungeecord-proxy</artifactId> | ||||||
|             <version>${project.version}</version> |             <version>${project.version}</version> | ||||||
|             <scope>compile</scope> |             <scope>compile</scope> | ||||||
|   | |||||||
| @@ -4,15 +4,14 @@ | |||||||
|     <modelVersion>4.0.0</modelVersion> |     <modelVersion>4.0.0</modelVersion> | ||||||
|  |  | ||||||
|     <parent> |     <parent> | ||||||
|         <groupId>net.md-5</groupId> |         <groupId>fr.pandacube.bungeecord</groupId> | ||||||
|         <artifactId>bungeecord-parent</artifactId> |         <artifactId>bungeecord-parent</artifactId> | ||||||
|         <version>1.20-R0.2-SNAPSHOT</version> |         <version>1.20-R0.3-SNAPSHOT</version> | ||||||
|         <relativePath>../pom.xml</relativePath> |         <relativePath>../pom.xml</relativePath> | ||||||
|     </parent> |     </parent> | ||||||
|  |  | ||||||
|     <groupId>net.md-5</groupId> |  | ||||||
|     <artifactId>bungeecord-chat</artifactId> |     <artifactId>bungeecord-chat</artifactId> | ||||||
|     <version>1.20-R0.2-SNAPSHOT</version> |     <version>1.20-R0.3-SNAPSHOT</version> | ||||||
|     <packaging>jar</packaging> |     <packaging>jar</packaging> | ||||||
|  |  | ||||||
|     <name>BungeeCord-Chat</name> |     <name>BungeeCord-Chat</name> | ||||||
|   | |||||||
| @@ -20,38 +20,10 @@ public abstract class BaseComponent | |||||||
|     BaseComponent parent; |     BaseComponent parent; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * The color of this component and any child components (unless overridden) |      * The component's style. | ||||||
|      */ |      */ | ||||||
|     private ChatColor color; |     @Getter | ||||||
|     /** |     private ComponentStyle style = new ComponentStyle(); | ||||||
|      * The font of this component and any child components (unless overridden) |  | ||||||
|      */ |  | ||||||
|     private String font; |  | ||||||
|     /** |  | ||||||
|      * Whether this component and any child components (unless overridden) is |  | ||||||
|      * bold |  | ||||||
|      */ |  | ||||||
|     private Boolean bold; |  | ||||||
|     /** |  | ||||||
|      * Whether this component and any child components (unless overridden) is |  | ||||||
|      * italic |  | ||||||
|      */ |  | ||||||
|     private Boolean italic; |  | ||||||
|     /** |  | ||||||
|      * Whether this component and any child components (unless overridden) is |  | ||||||
|      * underlined |  | ||||||
|      */ |  | ||||||
|     private Boolean underlined; |  | ||||||
|     /** |  | ||||||
|      * Whether this component and any child components (unless overridden) is |  | ||||||
|      * strikethrough |  | ||||||
|      */ |  | ||||||
|     private Boolean strikethrough; |  | ||||||
|     /** |  | ||||||
|      * Whether this component and any child components (unless overridden) is |  | ||||||
|      * obfuscated |  | ||||||
|      */ |  | ||||||
|     private Boolean obfuscated; |  | ||||||
|     /** |     /** | ||||||
|      * The text to insert into the chat when this component (and child |      * The text to insert into the chat when this component (and child | ||||||
|      * components) are clicked while pressing the shift key |      * components) are clicked while pressing the shift key | ||||||
| @@ -153,31 +125,31 @@ public abstract class BaseComponent | |||||||
|         } |         } | ||||||
|         if ( retention == FormatRetention.FORMATTING || retention == FormatRetention.ALL ) |         if ( retention == FormatRetention.FORMATTING || retention == FormatRetention.ALL ) | ||||||
|         { |         { | ||||||
|             if ( replace || color == null ) |             if ( replace || !style.hasColor() ) | ||||||
|             { |             { | ||||||
|                 setColor( component.getColorRaw() ); |                 setColor( component.getColorRaw() ); | ||||||
|             } |             } | ||||||
|             if ( replace || font == null ) |             if ( replace || !style.hasFont() ) | ||||||
|             { |             { | ||||||
|                 setFont( component.getFontRaw() ); |                 setFont( component.getFontRaw() ); | ||||||
|             } |             } | ||||||
|             if ( replace || bold == null ) |             if ( replace || style.isBoldRaw() == null ) | ||||||
|             { |             { | ||||||
|                 setBold( component.isBoldRaw() ); |                 setBold( component.isBoldRaw() ); | ||||||
|             } |             } | ||||||
|             if ( replace || italic == null ) |             if ( replace || style.isItalicRaw() == null ) | ||||||
|             { |             { | ||||||
|                 setItalic( component.isItalicRaw() ); |                 setItalic( component.isItalicRaw() ); | ||||||
|             } |             } | ||||||
|             if ( replace || underlined == null ) |             if ( replace || style.isUnderlinedRaw() == null ) | ||||||
|             { |             { | ||||||
|                 setUnderlined( component.isUnderlinedRaw() ); |                 setUnderlined( component.isUnderlinedRaw() ); | ||||||
|             } |             } | ||||||
|             if ( replace || strikethrough == null ) |             if ( replace || style.isStrikethroughRaw() == null ) | ||||||
|             { |             { | ||||||
|                 setStrikethrough( component.isStrikethroughRaw() ); |                 setStrikethrough( component.isStrikethroughRaw() ); | ||||||
|             } |             } | ||||||
|             if ( replace || obfuscated == null ) |             if ( replace || style.isObfuscatedRaw() == null ) | ||||||
|             { |             { | ||||||
|                 setObfuscated( component.isObfuscatedRaw() ); |                 setObfuscated( component.isObfuscatedRaw() ); | ||||||
|             } |             } | ||||||
| @@ -266,6 +238,29 @@ public abstract class BaseComponent | |||||||
|         return builder.toString(); |         return builder.toString(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Set the {@link ComponentStyle} for this component. | ||||||
|  |      * <p> | ||||||
|  |      * Unlike {@link #applyStyle(ComponentStyle)}, this method will overwrite | ||||||
|  |      * all style values on this component. | ||||||
|  |      * | ||||||
|  |      * @param style the style to set, or null to set all style values to default | ||||||
|  |      */ | ||||||
|  |     public void setStyle(ComponentStyle style) | ||||||
|  |     { | ||||||
|  |         this.style = ( style != null ) ? style.clone() : new ComponentStyle(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Set this component's color. | ||||||
|  |      * | ||||||
|  |      * @param color the component color, or null to use the default | ||||||
|  |      */ | ||||||
|  |     public void setColor(ChatColor color) | ||||||
|  |     { | ||||||
|  |         this.style.setColor( color ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Returns the color of this component. This uses the parent's color if this |      * Returns the color of this component. This uses the parent's color if this | ||||||
|      * component doesn't have one. {@link net.md_5.bungee.api.ChatColor#WHITE} |      * component doesn't have one. {@link net.md_5.bungee.api.ChatColor#WHITE} | ||||||
| @@ -275,7 +270,7 @@ public abstract class BaseComponent | |||||||
|      */ |      */ | ||||||
|     public ChatColor getColor() |     public ChatColor getColor() | ||||||
|     { |     { | ||||||
|         if ( color == null ) |         if ( !style.hasColor() ) | ||||||
|         { |         { | ||||||
|             if ( parent == null ) |             if ( parent == null ) | ||||||
|             { |             { | ||||||
| @@ -283,7 +278,7 @@ public abstract class BaseComponent | |||||||
|             } |             } | ||||||
|             return parent.getColor(); |             return parent.getColor(); | ||||||
|         } |         } | ||||||
|         return color; |         return style.getColor(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
| @@ -294,7 +289,17 @@ public abstract class BaseComponent | |||||||
|      */ |      */ | ||||||
|     public ChatColor getColorRaw() |     public ChatColor getColorRaw() | ||||||
|     { |     { | ||||||
|         return color; |         return style.getColor(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Set this component's font. | ||||||
|  |      * | ||||||
|  |      * @param font the font to set, or null to use the default | ||||||
|  |      */ | ||||||
|  |     public void setFont(String font) | ||||||
|  |     { | ||||||
|  |         this.style.setFont( font ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
| @@ -305,7 +310,7 @@ public abstract class BaseComponent | |||||||
|      */ |      */ | ||||||
|     public String getFont() |     public String getFont() | ||||||
|     { |     { | ||||||
|         if ( font == null ) |         if ( !style.hasFont() ) | ||||||
|         { |         { | ||||||
|             if ( parent == null ) |             if ( parent == null ) | ||||||
|             { |             { | ||||||
| @@ -313,7 +318,7 @@ public abstract class BaseComponent | |||||||
|             } |             } | ||||||
|             return parent.getFont(); |             return parent.getFont(); | ||||||
|         } |         } | ||||||
|         return font; |         return style.getFont(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
| @@ -324,7 +329,17 @@ public abstract class BaseComponent | |||||||
|      */ |      */ | ||||||
|     public String getFontRaw() |     public String getFontRaw() | ||||||
|     { |     { | ||||||
|         return font; |         return style.getFont(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Set whether or not this component is bold. | ||||||
|  |      * | ||||||
|  |      * @param bold the new bold state, or null to use the default | ||||||
|  |      */ | ||||||
|  |     public void setBold(Boolean bold) | ||||||
|  |     { | ||||||
|  |         this.style.setBold( bold ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
| @@ -336,11 +351,11 @@ public abstract class BaseComponent | |||||||
|      */ |      */ | ||||||
|     public boolean isBold() |     public boolean isBold() | ||||||
|     { |     { | ||||||
|         if ( bold == null ) |         if ( style.isBoldRaw() == null ) | ||||||
|         { |         { | ||||||
|             return parent != null && parent.isBold(); |             return parent != null && parent.isBold(); | ||||||
|         } |         } | ||||||
|         return bold; |         return style.isBold(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
| @@ -351,7 +366,17 @@ public abstract class BaseComponent | |||||||
|      */ |      */ | ||||||
|     public Boolean isBoldRaw() |     public Boolean isBoldRaw() | ||||||
|     { |     { | ||||||
|         return bold; |         return style.isBoldRaw(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Set whether or not this component is italic. | ||||||
|  |      * | ||||||
|  |      * @param italic the new italic state, or null to use the default | ||||||
|  |      */ | ||||||
|  |     public void setItalic(Boolean italic) | ||||||
|  |     { | ||||||
|  |         this.style.setItalic( italic ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
| @@ -363,11 +388,11 @@ public abstract class BaseComponent | |||||||
|      */ |      */ | ||||||
|     public boolean isItalic() |     public boolean isItalic() | ||||||
|     { |     { | ||||||
|         if ( italic == null ) |         if ( style.isItalicRaw() == null ) | ||||||
|         { |         { | ||||||
|             return parent != null && parent.isItalic(); |             return parent != null && parent.isItalic(); | ||||||
|         } |         } | ||||||
|         return italic; |         return style.isItalic(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
| @@ -378,7 +403,17 @@ public abstract class BaseComponent | |||||||
|      */ |      */ | ||||||
|     public Boolean isItalicRaw() |     public Boolean isItalicRaw() | ||||||
|     { |     { | ||||||
|         return italic; |         return style.isItalicRaw(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Set whether or not this component is underlined. | ||||||
|  |      * | ||||||
|  |      * @param underlined the new underlined state, or null to use the default | ||||||
|  |      */ | ||||||
|  |     public void setUnderlined(Boolean underlined) | ||||||
|  |     { | ||||||
|  |         this.style.setUnderlined( underlined ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
| @@ -390,11 +425,11 @@ public abstract class BaseComponent | |||||||
|      */ |      */ | ||||||
|     public boolean isUnderlined() |     public boolean isUnderlined() | ||||||
|     { |     { | ||||||
|         if ( underlined == null ) |         if ( style.isUnderlinedRaw() == null ) | ||||||
|         { |         { | ||||||
|             return parent != null && parent.isUnderlined(); |             return parent != null && parent.isUnderlined(); | ||||||
|         } |         } | ||||||
|         return underlined; |         return style.isUnderlined(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
| @@ -405,7 +440,18 @@ public abstract class BaseComponent | |||||||
|      */ |      */ | ||||||
|     public Boolean isUnderlinedRaw() |     public Boolean isUnderlinedRaw() | ||||||
|     { |     { | ||||||
|         return underlined; |         return style.isUnderlinedRaw(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Set whether or not this component is strikethrough. | ||||||
|  |      * | ||||||
|  |      * @param strikethrough the new strikethrough state, or null to use the | ||||||
|  |      * default | ||||||
|  |      */ | ||||||
|  |     public void setStrikethrough(Boolean strikethrough) | ||||||
|  |     { | ||||||
|  |         this.style.setStrikethrough( strikethrough ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
| @@ -417,11 +463,11 @@ public abstract class BaseComponent | |||||||
|      */ |      */ | ||||||
|     public boolean isStrikethrough() |     public boolean isStrikethrough() | ||||||
|     { |     { | ||||||
|         if ( strikethrough == null ) |         if ( style.isStrikethroughRaw() == null ) | ||||||
|         { |         { | ||||||
|             return parent != null && parent.isStrikethrough(); |             return parent != null && parent.isStrikethrough(); | ||||||
|         } |         } | ||||||
|         return strikethrough; |         return style.isStrikethrough(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
| @@ -432,7 +478,17 @@ public abstract class BaseComponent | |||||||
|      */ |      */ | ||||||
|     public Boolean isStrikethroughRaw() |     public Boolean isStrikethroughRaw() | ||||||
|     { |     { | ||||||
|         return strikethrough; |         return style.isStrikethroughRaw(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Set whether or not this component is obfuscated. | ||||||
|  |      * | ||||||
|  |      * @param obfuscated the new obfuscated state, or null to use the default | ||||||
|  |      */ | ||||||
|  |     public void setObfuscated(Boolean obfuscated) | ||||||
|  |     { | ||||||
|  |         this.style.setObfuscated( obfuscated ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
| @@ -444,11 +500,11 @@ public abstract class BaseComponent | |||||||
|      */ |      */ | ||||||
|     public boolean isObfuscated() |     public boolean isObfuscated() | ||||||
|     { |     { | ||||||
|         if ( obfuscated == null ) |         if ( style.isObfuscatedRaw() == null ) | ||||||
|         { |         { | ||||||
|             return parent != null && parent.isObfuscated(); |             return parent != null && parent.isObfuscated(); | ||||||
|         } |         } | ||||||
|         return obfuscated; |         return style.isObfuscated(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
| @@ -459,7 +515,48 @@ public abstract class BaseComponent | |||||||
|      */ |      */ | ||||||
|     public Boolean isObfuscatedRaw() |     public Boolean isObfuscatedRaw() | ||||||
|     { |     { | ||||||
|         return obfuscated; |         return style.isObfuscatedRaw(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Apply the style from the given {@link ComponentStyle} to this component. | ||||||
|  |      * <p> | ||||||
|  |      * Any style values that have been explicitly set in the style will be | ||||||
|  |      * applied to this component. If a value is not set in the style, it will | ||||||
|  |      * not override the style set in this component. | ||||||
|  |      * | ||||||
|  |      * @param style the style to apply | ||||||
|  |      */ | ||||||
|  |     public void applyStyle(ComponentStyle style) | ||||||
|  |     { | ||||||
|  |         if ( style.hasColor() ) | ||||||
|  |         { | ||||||
|  |             setColor( style.getColor() ); | ||||||
|  |         } | ||||||
|  |         if ( style.hasFont() ) | ||||||
|  |         { | ||||||
|  |             setFont( style.getFont() ); | ||||||
|  |         } | ||||||
|  |         if ( style.isBoldRaw() != null ) | ||||||
|  |         { | ||||||
|  |             setBold( style.isBoldRaw() ); | ||||||
|  |         } | ||||||
|  |         if ( style.isItalicRaw() != null ) | ||||||
|  |         { | ||||||
|  |             setItalic( style.isItalicRaw() ); | ||||||
|  |         } | ||||||
|  |         if ( style.isUnderlinedRaw() != null ) | ||||||
|  |         { | ||||||
|  |             setUnderlined( style.isUnderlinedRaw() ); | ||||||
|  |         } | ||||||
|  |         if ( style.isStrikethroughRaw() != null ) | ||||||
|  |         { | ||||||
|  |             setStrikethrough( style.isStrikethroughRaw() ); | ||||||
|  |         } | ||||||
|  |         if ( style.isObfuscatedRaw() != null ) | ||||||
|  |         { | ||||||
|  |             setObfuscated( style.isObfuscatedRaw() ); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public void setExtra(List<BaseComponent> components) |     public void setExtra(List<BaseComponent> components) | ||||||
| @@ -498,6 +595,16 @@ public abstract class BaseComponent | |||||||
|         extra.add( component ); |         extra.add( component ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Returns whether the component has any styling applied to it. | ||||||
|  |      * | ||||||
|  |      * @return Whether any styling is applied | ||||||
|  |      */ | ||||||
|  |     public boolean hasStyle() | ||||||
|  |     { | ||||||
|  |         return !style.isEmpty(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Returns whether the component has any formatting or events applied to it |      * Returns whether the component has any formatting or events applied to it | ||||||
|      * |      * | ||||||
| @@ -505,10 +612,8 @@ public abstract class BaseComponent | |||||||
|      */ |      */ | ||||||
|     public boolean hasFormatting() |     public boolean hasFormatting() | ||||||
|     { |     { | ||||||
|         return color != null || font != null || bold != null |         return hasStyle() || insertion != null | ||||||
|                 || italic != null || underlined != null |                 || hoverEvent != null || clickEvent != null; | ||||||
|                 || strikethrough != null || obfuscated != null |  | ||||||
|                 || insertion != null || hoverEvent != null || clickEvent != null; |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|   | |||||||
| @@ -423,6 +423,18 @@ public final class ComponentBuilder | |||||||
|         return this; |         return this; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Applies the provided {@link ComponentStyle} to the current part. | ||||||
|  |      * | ||||||
|  |      * @param style the style to apply | ||||||
|  |      * @return this ComponentBuilder for chaining | ||||||
|  |      */ | ||||||
|  |     public ComponentBuilder style(ComponentStyle style) | ||||||
|  |     { | ||||||
|  |         getCurrentComponent().applyStyle( style ); | ||||||
|  |         return this; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Sets the insertion text for the current part. |      * Sets the insertion text for the current part. | ||||||
|      * |      * | ||||||
|   | |||||||
							
								
								
									
										234
									
								
								chat/src/main/java/net/md_5/bungee/api/chat/ComponentStyle.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										234
									
								
								chat/src/main/java/net/md_5/bungee/api/chat/ComponentStyle.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,234 @@ | |||||||
|  | package net.md_5.bungee.api.chat; | ||||||
|  |  | ||||||
|  | import lombok.AllArgsConstructor; | ||||||
|  | import lombok.EqualsAndHashCode; | ||||||
|  | import lombok.NoArgsConstructor; | ||||||
|  | import lombok.Setter; | ||||||
|  | import net.md_5.bungee.api.ChatColor; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Represents a style that may be applied to a {@link BaseComponent}. | ||||||
|  |  */ | ||||||
|  | @Setter | ||||||
|  | @AllArgsConstructor | ||||||
|  | @NoArgsConstructor | ||||||
|  | @EqualsAndHashCode | ||||||
|  | public final class ComponentStyle implements Cloneable | ||||||
|  | { | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * The color of this style. | ||||||
|  |      */ | ||||||
|  |     private ChatColor color; | ||||||
|  |     /** | ||||||
|  |      * The font of this style. | ||||||
|  |      */ | ||||||
|  |     private String font; | ||||||
|  |     /** | ||||||
|  |      * Whether this style is bold. | ||||||
|  |      */ | ||||||
|  |     private Boolean bold; | ||||||
|  |     /** | ||||||
|  |      * Whether this style is italic. | ||||||
|  |      */ | ||||||
|  |     private Boolean italic; | ||||||
|  |     /** | ||||||
|  |      * Whether this style is underlined. | ||||||
|  |      */ | ||||||
|  |     private Boolean underlined; | ||||||
|  |     /** | ||||||
|  |      * Whether this style is strikethrough. | ||||||
|  |      */ | ||||||
|  |     private Boolean strikethrough; | ||||||
|  |     /** | ||||||
|  |      * Whether this style is obfuscated. | ||||||
|  |      */ | ||||||
|  |     private Boolean obfuscated; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Returns the color of this style. May return null. | ||||||
|  |      * | ||||||
|  |      * @return the color of this style, or null if default color | ||||||
|  |      */ | ||||||
|  |     public ChatColor getColor() | ||||||
|  |     { | ||||||
|  |         return color; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Returns whether or not this style has a color set. | ||||||
|  |      * | ||||||
|  |      * @return whether a color is set | ||||||
|  |      */ | ||||||
|  |     public boolean hasColor() | ||||||
|  |     { | ||||||
|  |         return ( color != null ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Returns the font of this style. May return null. | ||||||
|  |      * | ||||||
|  |      * @return the font of this style, or null if default font | ||||||
|  |      */ | ||||||
|  |     public String getFont() | ||||||
|  |     { | ||||||
|  |         return font; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Returns whether or not this style has a font set. | ||||||
|  |      * | ||||||
|  |      * @return whether a font is set | ||||||
|  |      */ | ||||||
|  |     public boolean hasFont() | ||||||
|  |     { | ||||||
|  |         return ( font != null ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Returns whether this style is bold. | ||||||
|  |      * | ||||||
|  |      * @return whether the style is bold | ||||||
|  |      */ | ||||||
|  |     public boolean isBold() | ||||||
|  |     { | ||||||
|  |         return ( bold != null ) && bold.booleanValue(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Returns whether this style is bold. May return null. | ||||||
|  |      * | ||||||
|  |      * @return whether the style is bold, or null if not set | ||||||
|  |      */ | ||||||
|  |     public Boolean isBoldRaw() | ||||||
|  |     { | ||||||
|  |         return bold; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Returns whether this style is italic. May return null. | ||||||
|  |      * | ||||||
|  |      * @return whether the style is italic | ||||||
|  |      */ | ||||||
|  |     public boolean isItalic() | ||||||
|  |     { | ||||||
|  |         return ( italic != null ) && italic.booleanValue(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Returns whether this style is italic. May return null. | ||||||
|  |      * | ||||||
|  |      * @return whether the style is italic, or null if not set | ||||||
|  |      */ | ||||||
|  |     public Boolean isItalicRaw() | ||||||
|  |     { | ||||||
|  |         return italic; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Returns whether this style is underlined. | ||||||
|  |      * | ||||||
|  |      * @return whether the style is underlined | ||||||
|  |      */ | ||||||
|  |     public boolean isUnderlined() | ||||||
|  |     { | ||||||
|  |         return ( underlined != null ) && underlined.booleanValue(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Returns whether this style is underlined. May return null. | ||||||
|  |      * | ||||||
|  |      * @return whether the style is underlined, or null if not set | ||||||
|  |      */ | ||||||
|  |     public Boolean isUnderlinedRaw() | ||||||
|  |     { | ||||||
|  |         return underlined; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Returns whether this style is strikethrough | ||||||
|  |      * | ||||||
|  |      * @return whether the style is strikethrough | ||||||
|  |      */ | ||||||
|  |     public boolean isStrikethrough() | ||||||
|  |     { | ||||||
|  |         return ( strikethrough != null ) && strikethrough.booleanValue(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Returns whether this style is strikethrough. May return null. | ||||||
|  |      * | ||||||
|  |      * @return whether the style is strikethrough, or null if not set | ||||||
|  |      */ | ||||||
|  |     public Boolean isStrikethroughRaw() | ||||||
|  |     { | ||||||
|  |         return strikethrough; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Returns whether this style is obfuscated. | ||||||
|  |      * | ||||||
|  |      * @return whether the style is obfuscated | ||||||
|  |      */ | ||||||
|  |     public boolean isObfuscated() | ||||||
|  |     { | ||||||
|  |         return ( obfuscated != null ) && obfuscated.booleanValue(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Returns whether this style is obfuscated. May return null. | ||||||
|  |      * | ||||||
|  |      * @return whether the style is obfuscated, or null if not set | ||||||
|  |      */ | ||||||
|  |     public Boolean isObfuscatedRaw() | ||||||
|  |     { | ||||||
|  |         return obfuscated; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Returns whether this style has no formatting explicitly set. | ||||||
|  |      * | ||||||
|  |      * @return true if no value is set, false if at least one is set | ||||||
|  |      */ | ||||||
|  |     public boolean isEmpty() | ||||||
|  |     { | ||||||
|  |         return color == null && font == null && bold == null | ||||||
|  |                 && italic == null && underlined == null | ||||||
|  |                 && strikethrough == null && obfuscated == null; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public ComponentStyle clone() | ||||||
|  |     { | ||||||
|  |         return new ComponentStyle( color, font, bold, italic, underlined, strikethrough, obfuscated ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Get a new {@link ComponentStyleBuilder}. | ||||||
|  |      * | ||||||
|  |      * @return the builder | ||||||
|  |      */ | ||||||
|  |     public static ComponentStyleBuilder builder() | ||||||
|  |     { | ||||||
|  |         return new ComponentStyleBuilder(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Get a new {@link ComponentStyleBuilder} with values initialized to the | ||||||
|  |      * style values of the supplied {@link ComponentStyle}. | ||||||
|  |      * | ||||||
|  |      * @param other the component style whose values to copy into the builder | ||||||
|  |      * @return the builder | ||||||
|  |      */ | ||||||
|  |     public static ComponentStyleBuilder builder(ComponentStyle other) | ||||||
|  |     { | ||||||
|  |         return new ComponentStyleBuilder() | ||||||
|  |                 .color( other.color ) | ||||||
|  |                 .font( other.font ) | ||||||
|  |                 .bold( other.bold ) | ||||||
|  |                 .italic( other.italic ) | ||||||
|  |                 .underlined( other.underlined ) | ||||||
|  |                 .strikethrough( other.strikethrough ) | ||||||
|  |                 .obfuscated( other.obfuscated ); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,126 @@ | |||||||
|  | package net.md_5.bungee.api.chat; | ||||||
|  |  | ||||||
|  | import net.md_5.bungee.api.ChatColor; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * <p> | ||||||
|  |  * ComponentStyleBuilder simplifies creating component styles by allowing the | ||||||
|  |  * use of a chainable builder. | ||||||
|  |  * </p> | ||||||
|  |  * <pre> | ||||||
|  |  * ComponentStyle style = ComponentStyle.builder() | ||||||
|  |  *     .color(ChatColor.RED) | ||||||
|  |  *     .font("custom:font") | ||||||
|  |  *     .bold(true).italic(true).create(); | ||||||
|  |  * | ||||||
|  |  * BaseComponent component = new ComponentBuilder("Hello world").style(style).create(); | ||||||
|  |  * // Or it can be used directly on a component | ||||||
|  |  * TextComponent text = new TextComponent("Hello world"); | ||||||
|  |  * text.applyStyle(style); | ||||||
|  |  * </pre> | ||||||
|  |  * | ||||||
|  |  * @see ComponentStyle#builder() | ||||||
|  |  * @see ComponentStyle#builder(ComponentStyle) | ||||||
|  |  */ | ||||||
|  | public final class ComponentStyleBuilder | ||||||
|  | { | ||||||
|  |  | ||||||
|  |     private ChatColor color; | ||||||
|  |     private String font; | ||||||
|  |     private Boolean bold, italic, underlined, strikethrough, obfuscated; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Set the style color. | ||||||
|  |      * | ||||||
|  |      * @param color the color to set, or null to use the default | ||||||
|  |      * @return this ComponentStyleBuilder for chaining | ||||||
|  |      */ | ||||||
|  |     public ComponentStyleBuilder color(ChatColor color) | ||||||
|  |     { | ||||||
|  |         this.color = color; | ||||||
|  |         return this; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Set the style font. | ||||||
|  |      * | ||||||
|  |      * @param font the font key to set, or null to use the default | ||||||
|  |      * @return this ComponentStyleBuilder for chaining | ||||||
|  |      */ | ||||||
|  |     public ComponentStyleBuilder font(String font) | ||||||
|  |     { | ||||||
|  |         this.font = font; | ||||||
|  |         return this; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Set the style's bold property. | ||||||
|  |      * | ||||||
|  |      * @param bold the bold value to set, or null to use the default | ||||||
|  |      * @return this ComponentStyleBuilder for chaining | ||||||
|  |      */ | ||||||
|  |     public ComponentStyleBuilder bold(Boolean bold) | ||||||
|  |     { | ||||||
|  |         this.bold = bold; | ||||||
|  |         return this; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Set the style's italic property. | ||||||
|  |      * | ||||||
|  |      * @param italic the italic value to set, or null to use the default | ||||||
|  |      * @return this ComponentStyleBuilder for chaining | ||||||
|  |      */ | ||||||
|  |     public ComponentStyleBuilder italic(Boolean italic) | ||||||
|  |     { | ||||||
|  |         this.italic = italic; | ||||||
|  |         return this; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Set the style's underlined property. | ||||||
|  |      * | ||||||
|  |      * @param underlined the underlined value to set, or null to use the default | ||||||
|  |      * @return this ComponentStyleBuilder for chaining | ||||||
|  |      */ | ||||||
|  |     public ComponentStyleBuilder underlined(Boolean underlined) | ||||||
|  |     { | ||||||
|  |         this.underlined = underlined; | ||||||
|  |         return this; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Set the style's strikethrough property. | ||||||
|  |      * | ||||||
|  |      * @param strikethrough the strikethrough value to set, or null to use the | ||||||
|  |      * default | ||||||
|  |      * @return this ComponentStyleBuilder for chaining | ||||||
|  |      */ | ||||||
|  |     public ComponentStyleBuilder strikethrough(Boolean strikethrough) | ||||||
|  |     { | ||||||
|  |         this.strikethrough = strikethrough; | ||||||
|  |         return this; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Set the style's obfuscated property. | ||||||
|  |      * | ||||||
|  |      * @param obfuscated the obfuscated value to set, or null to use the default | ||||||
|  |      * @return this ComponentStyleBuilder for chaining | ||||||
|  |      */ | ||||||
|  |     public ComponentStyleBuilder obfuscated(Boolean obfuscated) | ||||||
|  |     { | ||||||
|  |         this.obfuscated = obfuscated; | ||||||
|  |         return this; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Build the {@link ComponentStyle} using the values set in this builder. | ||||||
|  |      * | ||||||
|  |      * @return the created ComponentStyle | ||||||
|  |      */ | ||||||
|  |     public ComponentStyle build() | ||||||
|  |     { | ||||||
|  |         return new ComponentStyle( color, font, bold, italic, underlined, strikethrough, obfuscated ); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -8,6 +8,7 @@ import com.google.gson.JsonParseException; | |||||||
| import com.google.gson.JsonSerializationContext; | import com.google.gson.JsonSerializationContext; | ||||||
| import com.google.gson.JsonSerializer; | import com.google.gson.JsonSerializer; | ||||||
| import java.lang.reflect.Type; | import java.lang.reflect.Type; | ||||||
|  | import java.util.UUID; | ||||||
| import net.md_5.bungee.api.chat.BaseComponent; | import net.md_5.bungee.api.chat.BaseComponent; | ||||||
|  |  | ||||||
| public class EntitySerializer implements JsonSerializer<Entity>, JsonDeserializer<Entity> | public class EntitySerializer implements JsonSerializer<Entity>, JsonDeserializer<Entity> | ||||||
| @@ -18,9 +19,19 @@ public class EntitySerializer implements JsonSerializer<Entity>, JsonDeserialize | |||||||
|     { |     { | ||||||
|         JsonObject value = element.getAsJsonObject(); |         JsonObject value = element.getAsJsonObject(); | ||||||
|  |  | ||||||
|  |         String idString; | ||||||
|  |         JsonElement id = value.get( "id" ); | ||||||
|  |         if ( id.isJsonArray() ) | ||||||
|  |         { | ||||||
|  |             idString = parseUUID( context.deserialize( id, int[].class ) ).toString(); | ||||||
|  |         } else | ||||||
|  |         { | ||||||
|  |             idString = id.getAsString(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|         return new Entity( |         return new Entity( | ||||||
|                 ( value.has( "type" ) ) ? value.get( "type" ).getAsString() : null, |                 ( value.has( "type" ) ) ? value.get( "type" ).getAsString() : null, | ||||||
|                 value.get( "id" ).getAsString(), |                 idString, | ||||||
|                 ( value.has( "name" ) ) ? context.deserialize( value.get( "name" ), BaseComponent.class ) : null |                 ( value.has( "name" ) ) ? context.deserialize( value.get( "name" ), BaseComponent.class ) : null | ||||||
|         ); |         ); | ||||||
|     } |     } | ||||||
| @@ -37,4 +48,9 @@ public class EntitySerializer implements JsonSerializer<Entity>, JsonDeserialize | |||||||
|         } |         } | ||||||
|         return object; |         return object; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     private static UUID parseUUID(int[] array) | ||||||
|  |     { | ||||||
|  |         return new UUID( (long) array[0] << 32 | (long) array[1] & 0XFFFFFFFFL, (long) array[2] << 32 | (long) array[3] & 0XFFFFFFFFL ); | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -4,73 +4,25 @@ import com.google.common.base.Preconditions; | |||||||
| import com.google.gson.JsonDeserializationContext; | import com.google.gson.JsonDeserializationContext; | ||||||
| import com.google.gson.JsonElement; | import com.google.gson.JsonElement; | ||||||
| import com.google.gson.JsonObject; | import com.google.gson.JsonObject; | ||||||
| import com.google.gson.JsonParseException; |  | ||||||
| import com.google.gson.JsonPrimitive; |  | ||||||
| import com.google.gson.JsonSerializationContext; | import com.google.gson.JsonSerializationContext; | ||||||
| import java.util.ArrayList; | import java.util.ArrayList; | ||||||
| import java.util.Arrays; | import java.util.Arrays; | ||||||
| import java.util.Collections; | import java.util.Collections; | ||||||
| import java.util.IdentityHashMap; | import java.util.IdentityHashMap; | ||||||
| import java.util.Locale; | import java.util.Locale; | ||||||
| import net.md_5.bungee.api.ChatColor; |  | ||||||
| import net.md_5.bungee.api.chat.BaseComponent; | import net.md_5.bungee.api.chat.BaseComponent; | ||||||
| import net.md_5.bungee.api.chat.ClickEvent; | import net.md_5.bungee.api.chat.ClickEvent; | ||||||
|  | import net.md_5.bungee.api.chat.ComponentStyle; | ||||||
| import net.md_5.bungee.api.chat.HoverEvent; | import net.md_5.bungee.api.chat.HoverEvent; | ||||||
| import net.md_5.bungee.api.chat.hover.content.Content; | import net.md_5.bungee.api.chat.hover.content.Content; | ||||||
|  |  | ||||||
| public class BaseComponentSerializer | public class BaseComponentSerializer | ||||||
| { | { | ||||||
|  |  | ||||||
|     private static boolean getAsBoolean(JsonElement el) |  | ||||||
|     { |  | ||||||
|         if ( el.isJsonPrimitive() ) |  | ||||||
|         { |  | ||||||
|             JsonPrimitive primitive = (JsonPrimitive) el; |  | ||||||
|  |  | ||||||
|             if ( primitive.isBoolean() ) |  | ||||||
|             { |  | ||||||
|                 return primitive.getAsBoolean(); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             if ( primitive.isNumber() ) |  | ||||||
|             { |  | ||||||
|                 Number number = primitive.getAsNumber(); |  | ||||||
|                 if ( number instanceof Byte ) |  | ||||||
|                 { |  | ||||||
|                     return number.byteValue() != 0; |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     protected void deserialize(JsonObject object, BaseComponent component, JsonDeserializationContext context) |     protected void deserialize(JsonObject object, BaseComponent component, JsonDeserializationContext context) | ||||||
|     { |     { | ||||||
|         if ( object.has( "bold" ) ) |         component.applyStyle( context.deserialize( object, ComponentStyle.class ) ); | ||||||
|         { |  | ||||||
|             component.setBold( getAsBoolean( object.get( "bold" ) ) ); |  | ||||||
|         } |  | ||||||
|         if ( object.has( "italic" ) ) |  | ||||||
|         { |  | ||||||
|             component.setItalic( getAsBoolean( object.get( "italic" ) ) ); |  | ||||||
|         } |  | ||||||
|         if ( object.has( "underlined" ) ) |  | ||||||
|         { |  | ||||||
|             component.setUnderlined( getAsBoolean( object.get( "underlined" ) ) ); |  | ||||||
|         } |  | ||||||
|         if ( object.has( "strikethrough" ) ) |  | ||||||
|         { |  | ||||||
|             component.setStrikethrough( getAsBoolean( object.get( "strikethrough" ) ) ); |  | ||||||
|         } |  | ||||||
|         if ( object.has( "obfuscated" ) ) |  | ||||||
|         { |  | ||||||
|             component.setObfuscated( getAsBoolean( object.get( "obfuscated" ) ) ); |  | ||||||
|         } |  | ||||||
|         if ( object.has( "color" ) ) |  | ||||||
|         { |  | ||||||
|             component.setColor( ChatColor.of( object.get( "color" ).getAsString() ) ); |  | ||||||
|         } |  | ||||||
|         if ( object.has( "insertion" ) ) |         if ( object.has( "insertion" ) ) | ||||||
|         { |         { | ||||||
|             component.setInsertion( object.get( "insertion" ).getAsString() ); |             component.setInsertion( object.get( "insertion" ).getAsString() ); | ||||||
| @@ -90,15 +42,9 @@ public class BaseComponentSerializer | |||||||
|             HoverEvent hoverEvent = null; |             HoverEvent hoverEvent = null; | ||||||
|             HoverEvent.Action action = HoverEvent.Action.valueOf( event.get( "action" ).getAsString().toUpperCase( Locale.ROOT ) ); |             HoverEvent.Action action = HoverEvent.Action.valueOf( event.get( "action" ).getAsString().toUpperCase( Locale.ROOT ) ); | ||||||
|  |  | ||||||
|             for ( String type : Arrays.asList( "value", "contents" ) ) |             if ( event.has( "value" ) ) | ||||||
|             { |  | ||||||
|                 if ( !event.has( type ) ) |  | ||||||
|                 { |  | ||||||
|                     continue; |  | ||||||
|                 } |  | ||||||
|                 JsonElement contents = event.get( type ); |  | ||||||
|                 try |  | ||||||
|             { |             { | ||||||
|  |                 JsonElement contents = event.get( "value" ); | ||||||
|  |  | ||||||
|                 // Plugins previously had support to pass BaseComponent[] into any action. |                 // Plugins previously had support to pass BaseComponent[] into any action. | ||||||
|                 // If the GSON is possible to be parsed as BaseComponent, attempt to parse as so. |                 // If the GSON is possible to be parsed as BaseComponent, attempt to parse as so. | ||||||
| @@ -114,8 +60,10 @@ public class BaseComponentSerializer | |||||||
|                     }; |                     }; | ||||||
|                 } |                 } | ||||||
|                 hoverEvent = new HoverEvent( action, components ); |                 hoverEvent = new HoverEvent( action, components ); | ||||||
|                 } catch ( JsonParseException ex ) |             } else if ( event.has( "contents" ) ) | ||||||
|             { |             { | ||||||
|  |                 JsonElement contents = event.get( "contents" ); | ||||||
|  |  | ||||||
|                 Content[] list; |                 Content[] list; | ||||||
|                 if ( contents.isJsonArray() ) |                 if ( contents.isJsonArray() ) | ||||||
|                 { |                 { | ||||||
| @@ -130,19 +78,12 @@ public class BaseComponentSerializer | |||||||
|                 hoverEvent = new HoverEvent( action, new ArrayList<>( Arrays.asList( list ) ) ); |                 hoverEvent = new HoverEvent( action, new ArrayList<>( Arrays.asList( list ) ) ); | ||||||
|             } |             } | ||||||
|  |  | ||||||
|                 // stop the loop as soon as either one is found |  | ||||||
|                 break; |  | ||||||
|             } |  | ||||||
|             if ( hoverEvent != null ) |             if ( hoverEvent != null ) | ||||||
|             { |             { | ||||||
|                 component.setHoverEvent( hoverEvent ); |                 component.setHoverEvent( hoverEvent ); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if ( object.has( "font" ) ) |  | ||||||
|         { |  | ||||||
|             component.setFont( object.get( "font" ).getAsString() ); |  | ||||||
|         } |  | ||||||
|         if ( object.has( "extra" ) ) |         if ( object.has( "extra" ) ) | ||||||
|         { |         { | ||||||
|             component.setExtra( Arrays.asList( context.<BaseComponent[]>deserialize( object.get( "extra" ), BaseComponent[].class ) ) ); |             component.setExtra( Arrays.asList( context.<BaseComponent[]>deserialize( object.get( "extra" ), BaseComponent[].class ) ) ); | ||||||
| @@ -161,30 +102,9 @@ public class BaseComponentSerializer | |||||||
|         { |         { | ||||||
|             Preconditions.checkArgument( !ComponentSerializer.serializedComponents.get().contains( component ), "Component loop" ); |             Preconditions.checkArgument( !ComponentSerializer.serializedComponents.get().contains( component ), "Component loop" ); | ||||||
|             ComponentSerializer.serializedComponents.get().add( component ); |             ComponentSerializer.serializedComponents.get().add( component ); | ||||||
|             if ( component.isBoldRaw() != null ) |  | ||||||
|             { |             ComponentStyleSerializer.serializeTo( component.getStyle(), object ); | ||||||
|                 object.addProperty( "bold", component.isBoldRaw() ); |  | ||||||
|             } |  | ||||||
|             if ( component.isItalicRaw() != null ) |  | ||||||
|             { |  | ||||||
|                 object.addProperty( "italic", component.isItalicRaw() ); |  | ||||||
|             } |  | ||||||
|             if ( component.isUnderlinedRaw() != null ) |  | ||||||
|             { |  | ||||||
|                 object.addProperty( "underlined", component.isUnderlinedRaw() ); |  | ||||||
|             } |  | ||||||
|             if ( component.isStrikethroughRaw() != null ) |  | ||||||
|             { |  | ||||||
|                 object.addProperty( "strikethrough", component.isStrikethroughRaw() ); |  | ||||||
|             } |  | ||||||
|             if ( component.isObfuscatedRaw() != null ) |  | ||||||
|             { |  | ||||||
|                 object.addProperty( "obfuscated", component.isObfuscatedRaw() ); |  | ||||||
|             } |  | ||||||
|             if ( component.getColorRaw() != null ) |  | ||||||
|             { |  | ||||||
|                 object.addProperty( "color", component.getColorRaw().getName() ); |  | ||||||
|             } |  | ||||||
|             if ( component.getInsertion() != null ) |             if ( component.getInsertion() != null ) | ||||||
|             { |             { | ||||||
|                 object.addProperty( "insertion", component.getInsertion() ); |                 object.addProperty( "insertion", component.getInsertion() ); | ||||||
| @@ -213,10 +133,6 @@ public class BaseComponentSerializer | |||||||
|                 object.add( "hoverEvent", hoverEvent ); |                 object.add( "hoverEvent", hoverEvent ); | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             if ( component.getFontRaw() != null ) |  | ||||||
|             { |  | ||||||
|                 object.addProperty( "font", component.getFontRaw() ); |  | ||||||
|             } |  | ||||||
|             if ( component.getExtra() != null ) |             if ( component.getExtra() != null ) | ||||||
|             { |             { | ||||||
|                 object.add( "extra", context.serialize( component.getExtra() ) ); |                 object.add( "extra", context.serialize( component.getExtra() ) ); | ||||||
|   | |||||||
| @@ -13,6 +13,7 @@ import com.google.gson.JsonPrimitive; | |||||||
| import java.lang.reflect.Type; | import java.lang.reflect.Type; | ||||||
| import java.util.Set; | import java.util.Set; | ||||||
| import net.md_5.bungee.api.chat.BaseComponent; | import net.md_5.bungee.api.chat.BaseComponent; | ||||||
|  | import net.md_5.bungee.api.chat.ComponentStyle; | ||||||
| import net.md_5.bungee.api.chat.ItemTag; | import net.md_5.bungee.api.chat.ItemTag; | ||||||
| import net.md_5.bungee.api.chat.KeybindComponent; | import net.md_5.bungee.api.chat.KeybindComponent; | ||||||
| import net.md_5.bungee.api.chat.ScoreComponent; | import net.md_5.bungee.api.chat.ScoreComponent; | ||||||
| @@ -36,6 +37,7 @@ public class ComponentSerializer implements JsonDeserializer<BaseComponent> | |||||||
|             registerTypeAdapter( KeybindComponent.class, new KeybindComponentSerializer() ). |             registerTypeAdapter( KeybindComponent.class, new KeybindComponentSerializer() ). | ||||||
|             registerTypeAdapter( ScoreComponent.class, new ScoreComponentSerializer() ). |             registerTypeAdapter( ScoreComponent.class, new ScoreComponentSerializer() ). | ||||||
|             registerTypeAdapter( SelectorComponent.class, new SelectorComponentSerializer() ). |             registerTypeAdapter( SelectorComponent.class, new SelectorComponentSerializer() ). | ||||||
|  |             registerTypeAdapter( ComponentStyle.class, new ComponentStyleSerializer() ). | ||||||
|             registerTypeAdapter( Entity.class, new EntitySerializer() ). |             registerTypeAdapter( Entity.class, new EntitySerializer() ). | ||||||
|             registerTypeAdapter( Text.class, new TextSerializer() ). |             registerTypeAdapter( Text.class, new TextSerializer() ). | ||||||
|             registerTypeAdapter( Item.class, new ItemSerializer() ). |             registerTypeAdapter( Item.class, new ItemSerializer() ). | ||||||
| @@ -118,11 +120,44 @@ public class ComponentSerializer implements JsonDeserializer<BaseComponent> | |||||||
|         return gson.fromJson( jsonElement, BaseComponent.class ); |         return gson.fromJson( jsonElement, BaseComponent.class ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Deserialize a JSON-compliant String as a component style. | ||||||
|  |      * | ||||||
|  |      * @param json the component style json to parse | ||||||
|  |      * @return the deserialized component style | ||||||
|  |      * @throws IllegalArgumentException if anything other than a valid JSON | ||||||
|  |      * component style string is passed as input | ||||||
|  |      */ | ||||||
|  |     public static ComponentStyle deserializeStyle(String json) | ||||||
|  |     { | ||||||
|  |         JsonElement jsonElement = JsonParser.parseString( json ); | ||||||
|  |  | ||||||
|  |         return deserializeStyle( jsonElement ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Deserialize a JSON element as a component style. | ||||||
|  |      * | ||||||
|  |      * @param jsonElement the component style json to parse | ||||||
|  |      * @return the deserialized component style | ||||||
|  |      * @throws IllegalArgumentException if anything other than a valid JSON | ||||||
|  |      * component style is passed as input | ||||||
|  |      */ | ||||||
|  |     public static ComponentStyle deserializeStyle(JsonElement jsonElement) | ||||||
|  |     { | ||||||
|  |         return gson.fromJson( jsonElement, ComponentStyle.class ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     public static JsonElement toJson(BaseComponent component) |     public static JsonElement toJson(BaseComponent component) | ||||||
|     { |     { | ||||||
|         return gson.toJsonTree( component ); |         return gson.toJsonTree( component ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     public static JsonElement toJson(ComponentStyle style) | ||||||
|  |     { | ||||||
|  |         return gson.toJsonTree( style ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     public static String toString(Object object) |     public static String toString(Object object) | ||||||
|     { |     { | ||||||
|         return gson.toJson( object ); |         return gson.toJson( object ); | ||||||
| @@ -144,6 +179,11 @@ public class ComponentSerializer implements JsonDeserializer<BaseComponent> | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     public static String toString(ComponentStyle style) | ||||||
|  |     { | ||||||
|  |         return gson.toJson( style ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public BaseComponent deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException |     public BaseComponent deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException | ||||||
|     { |     { | ||||||
|   | |||||||
| @@ -0,0 +1,118 @@ | |||||||
|  | package net.md_5.bungee.chat; | ||||||
|  |  | ||||||
|  | import com.google.gson.JsonDeserializationContext; | ||||||
|  | import com.google.gson.JsonDeserializer; | ||||||
|  | import com.google.gson.JsonElement; | ||||||
|  | import com.google.gson.JsonObject; | ||||||
|  | import com.google.gson.JsonParseException; | ||||||
|  | import com.google.gson.JsonPrimitive; | ||||||
|  | import com.google.gson.JsonSerializationContext; | ||||||
|  | import com.google.gson.JsonSerializer; | ||||||
|  | import java.lang.reflect.Type; | ||||||
|  | import net.md_5.bungee.api.ChatColor; | ||||||
|  | import net.md_5.bungee.api.chat.ComponentStyle; | ||||||
|  | import net.md_5.bungee.api.chat.ComponentStyleBuilder; | ||||||
|  |  | ||||||
|  | public class ComponentStyleSerializer implements JsonSerializer<ComponentStyle>, JsonDeserializer<ComponentStyle> | ||||||
|  | { | ||||||
|  |  | ||||||
|  |     private static boolean getAsBoolean(JsonElement el) | ||||||
|  |     { | ||||||
|  |         if ( el.isJsonPrimitive() ) | ||||||
|  |         { | ||||||
|  |             JsonPrimitive primitive = (JsonPrimitive) el; | ||||||
|  |  | ||||||
|  |             if ( primitive.isBoolean() ) | ||||||
|  |             { | ||||||
|  |                 return primitive.getAsBoolean(); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if ( primitive.isNumber() ) | ||||||
|  |             { | ||||||
|  |                 Number number = primitive.getAsNumber(); | ||||||
|  |                 if ( number instanceof Byte ) | ||||||
|  |                 { | ||||||
|  |                     return number.byteValue() != 0; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     static void serializeTo(ComponentStyle style, JsonObject object) | ||||||
|  |     { | ||||||
|  |         if ( style.isBoldRaw() != null ) | ||||||
|  |         { | ||||||
|  |             object.addProperty( "bold", style.isBoldRaw() ); | ||||||
|  |         } | ||||||
|  |         if ( style.isItalicRaw() != null ) | ||||||
|  |         { | ||||||
|  |             object.addProperty( "italic", style.isItalicRaw() ); | ||||||
|  |         } | ||||||
|  |         if ( style.isUnderlinedRaw() != null ) | ||||||
|  |         { | ||||||
|  |             object.addProperty( "underlined", style.isUnderlinedRaw() ); | ||||||
|  |         } | ||||||
|  |         if ( style.isStrikethroughRaw() != null ) | ||||||
|  |         { | ||||||
|  |             object.addProperty( "strikethrough", style.isStrikethroughRaw() ); | ||||||
|  |         } | ||||||
|  |         if ( style.isObfuscatedRaw() != null ) | ||||||
|  |         { | ||||||
|  |             object.addProperty( "obfuscated", style.isObfuscatedRaw() ); | ||||||
|  |         } | ||||||
|  |         if ( style.hasColor() ) | ||||||
|  |         { | ||||||
|  |             object.addProperty( "color", style.getColor().getName() ); | ||||||
|  |         } | ||||||
|  |         if ( style.hasFont() ) | ||||||
|  |         { | ||||||
|  |             object.addProperty( "font", style.getFont() ); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public ComponentStyle deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException | ||||||
|  |     { | ||||||
|  |         ComponentStyleBuilder builder = ComponentStyle.builder(); | ||||||
|  |         JsonObject object = json.getAsJsonObject(); | ||||||
|  |         if ( object.has( "bold" ) ) | ||||||
|  |         { | ||||||
|  |             builder.bold( getAsBoolean( object.get( "bold" ) ) ); | ||||||
|  |         } | ||||||
|  |         if ( object.has( "italic" ) ) | ||||||
|  |         { | ||||||
|  |             builder.italic( getAsBoolean( object.get( "italic" ) ) ); | ||||||
|  |         } | ||||||
|  |         if ( object.has( "underlined" ) ) | ||||||
|  |         { | ||||||
|  |             builder.underlined( getAsBoolean( object.get( "underlined" ) ) ); | ||||||
|  |         } | ||||||
|  |         if ( object.has( "strikethrough" ) ) | ||||||
|  |         { | ||||||
|  |             builder.strikethrough( getAsBoolean( object.get( "strikethrough" ) ) ); | ||||||
|  |         } | ||||||
|  |         if ( object.has( "obfuscated" ) ) | ||||||
|  |         { | ||||||
|  |             builder.obfuscated( getAsBoolean( object.get( "obfuscated" ) ) ); | ||||||
|  |         } | ||||||
|  |         if ( object.has( "color" ) ) | ||||||
|  |         { | ||||||
|  |             builder.color( ChatColor.of( object.get( "color" ).getAsString() ) ); | ||||||
|  |         } | ||||||
|  |         if ( object.has( "font" ) ) | ||||||
|  |         { | ||||||
|  |             builder.font( object.get( "font" ).getAsString() ); | ||||||
|  |         } | ||||||
|  |         return builder.build(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public JsonElement serialize(ComponentStyle src, Type typeOfSrc, JsonSerializationContext context) | ||||||
|  |     { | ||||||
|  |         JsonObject object = new JsonObject(); | ||||||
|  |         serializeTo( src, object ); | ||||||
|  |         return object; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -8,6 +8,7 @@ import java.util.function.Function; | |||||||
| import java.util.function.ObjIntConsumer; | import java.util.function.ObjIntConsumer; | ||||||
| import java.util.function.Supplier; | import java.util.function.Supplier; | ||||||
| import net.md_5.bungee.api.ChatColor; | import net.md_5.bungee.api.ChatColor; | ||||||
|  | import net.md_5.bungee.api.chat.hover.content.Entity; | ||||||
| import net.md_5.bungee.api.chat.hover.content.Text; | import net.md_5.bungee.api.chat.hover.content.Text; | ||||||
| import net.md_5.bungee.chat.ComponentSerializer; | import net.md_5.bungee.chat.ComponentSerializer; | ||||||
| import org.junit.jupiter.api.Test; | import org.junit.jupiter.api.Test; | ||||||
| @@ -88,6 +89,14 @@ public class ComponentsTest | |||||||
|          */ |          */ | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     @Test | ||||||
|  |     public void testArrayUUIDParse() | ||||||
|  |     { | ||||||
|  |         BaseComponent[] uuidComponent = ComponentSerializer.parse( "{\"translate\":\"multiplayer.player.joined\",\"with\":[{\"text\":\"Rexcantor64\",\"hoverEvent\":{\"contents\":{\"type\":\"minecraft:player\",\"id\":[1328556382,-2138814985,-1895806765,-1039963041],\"name\":\"Rexcantor64\"},\"action\":\"show_entity\"},\"insertion\":\"Rexcantor64\",\"clickEvent\":{\"action\":\"suggest_command\",\"value\":\"/tell Rexcantor64 \"}}],\"color\":\"yellow\"}" ); | ||||||
|  |         assertEquals( "4f30295e-8084-45f7-8f00-48d3c2036c5f", ( (Entity) ( (TranslatableComponent) uuidComponent[0] ).getWith().get( 0 ).getHoverEvent().getContents().get( 0 ) ).getId() ); | ||||||
|  |         testDissembleReassemble( uuidComponent ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     @Test |     @Test | ||||||
|     public void testEmptyComponentBuilderCreate() |     public void testEmptyComponentBuilderCreate() | ||||||
|     { |     { | ||||||
| @@ -421,6 +430,16 @@ public class ComponentsTest | |||||||
|         assertArrayEquals( component, reparsed ); |         assertArrayEquals( component, reparsed ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     @Test | ||||||
|  |     public void testStyle() | ||||||
|  |     { | ||||||
|  |         ComponentStyle style = ComponentSerializer.deserializeStyle( "{\"color\":\"red\",\"font\":\"minecraft:example\",\"bold\":true,\"italic\":false,\"obfuscated\":true}" ); | ||||||
|  |         String text = ComponentSerializer.toString( style ); | ||||||
|  |         ComponentStyle reparsed = ComponentSerializer.deserializeStyle( text ); | ||||||
|  |  | ||||||
|  |         assertEquals( style, reparsed ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     @Test |     @Test | ||||||
|     public void testBuilderAppendCreate() |     public void testBuilderAppendCreate() | ||||||
|     { |     { | ||||||
| @@ -806,6 +825,28 @@ public class ComponentsTest | |||||||
|         ); |         ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     @Test | ||||||
|  |     public void testHasFormatting() | ||||||
|  |     { | ||||||
|  |         BaseComponent component = new TextComponent(); | ||||||
|  |         assertFalse( component.hasFormatting() ); | ||||||
|  |  | ||||||
|  |         component.setBold( true ); | ||||||
|  |         assertTrue( component.hasFormatting() ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Test | ||||||
|  |     public void testStyleIsEmpty() | ||||||
|  |     { | ||||||
|  |         ComponentStyle style = ComponentStyle.builder().build(); | ||||||
|  |         assertTrue( style.isEmpty() ); | ||||||
|  |  | ||||||
|  |         style = ComponentStyle.builder() | ||||||
|  |             .bold( true ) | ||||||
|  |             .build(); | ||||||
|  |         assertFalse( style.isEmpty() ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /* |     /* | ||||||
|      * In legacy chat, colors and reset both reset all formatting. |      * In legacy chat, colors and reset both reset all formatting. | ||||||
|      * Make sure it works in combination with ComponentBuilder. |      * Make sure it works in combination with ComponentBuilder. | ||||||
|   | |||||||
| @@ -4,15 +4,14 @@ | |||||||
|     <modelVersion>4.0.0</modelVersion> |     <modelVersion>4.0.0</modelVersion> | ||||||
|  |  | ||||||
|     <parent> |     <parent> | ||||||
|         <groupId>net.md-5</groupId> |         <groupId>fr.pandacube.bungeecord</groupId> | ||||||
|         <artifactId>bungeecord-parent</artifactId> |         <artifactId>bungeecord-parent</artifactId> | ||||||
|         <version>1.20-R0.2-SNAPSHOT</version> |         <version>1.20-R0.3-SNAPSHOT</version> | ||||||
|         <relativePath>../pom.xml</relativePath> |         <relativePath>../pom.xml</relativePath> | ||||||
|     </parent> |     </parent> | ||||||
|  |  | ||||||
|     <groupId>net.md-5</groupId> |  | ||||||
|     <artifactId>bungeecord-config</artifactId> |     <artifactId>bungeecord-config</artifactId> | ||||||
|     <version>1.20-R0.2-SNAPSHOT</version> |     <version>1.20-R0.3-SNAPSHOT</version> | ||||||
|     <packaging>jar</packaging> |     <packaging>jar</packaging> | ||||||
|  |  | ||||||
|     <name>BungeeCord-Config</name> |     <name>BungeeCord-Config</name> | ||||||
|   | |||||||
| @@ -4,15 +4,14 @@ | |||||||
|     <modelVersion>4.0.0</modelVersion> |     <modelVersion>4.0.0</modelVersion> | ||||||
|  |  | ||||||
|     <parent> |     <parent> | ||||||
|         <groupId>net.md-5</groupId> |         <groupId>fr.pandacube.bungeecord</groupId> | ||||||
|         <artifactId>bungeecord-parent</artifactId> |         <artifactId>bungeecord-parent</artifactId> | ||||||
|         <version>1.20-R0.2-SNAPSHOT</version> |         <version>1.20-R0.3-SNAPSHOT</version> | ||||||
|         <relativePath>../pom.xml</relativePath> |         <relativePath>../pom.xml</relativePath> | ||||||
|     </parent> |     </parent> | ||||||
|  |  | ||||||
|     <groupId>net.md-5</groupId> |  | ||||||
|     <artifactId>bungeecord-event</artifactId> |     <artifactId>bungeecord-event</artifactId> | ||||||
|     <version>1.20-R0.2-SNAPSHOT</version> |     <version>1.20-R0.3-SNAPSHOT</version> | ||||||
|     <packaging>jar</packaging> |     <packaging>jar</packaging> | ||||||
|  |  | ||||||
|     <name>BungeeCord-Event</name> |     <name>BungeeCord-Event</name> | ||||||
|   | |||||||
| @@ -4,15 +4,14 @@ | |||||||
|     <modelVersion>4.0.0</modelVersion> |     <modelVersion>4.0.0</modelVersion> | ||||||
|  |  | ||||||
|     <parent> |     <parent> | ||||||
|         <groupId>net.md-5</groupId> |         <groupId>fr.pandacube.bungeecord</groupId> | ||||||
|         <artifactId>bungeecord-parent</artifactId> |         <artifactId>bungeecord-parent</artifactId> | ||||||
|         <version>1.20-R0.2-SNAPSHOT</version> |         <version>1.20-R0.3-SNAPSHOT</version> | ||||||
|         <relativePath>../pom.xml</relativePath> |         <relativePath>../pom.xml</relativePath> | ||||||
|     </parent> |     </parent> | ||||||
|  |  | ||||||
|     <groupId>net.md-5</groupId> |  | ||||||
|     <artifactId>bungeecord-log</artifactId> |     <artifactId>bungeecord-log</artifactId> | ||||||
|     <version>1.20-R0.2-SNAPSHOT</version> |     <version>1.20-R0.3-SNAPSHOT</version> | ||||||
|     <packaging>jar</packaging> |     <packaging>jar</packaging> | ||||||
|  |  | ||||||
|     <name>BungeeCord-Log</name> |     <name>BungeeCord-Log</name> | ||||||
| @@ -26,7 +25,7 @@ | |||||||
|             <scope>compile</scope> |             <scope>compile</scope> | ||||||
|         </dependency> |         </dependency> | ||||||
|         <dependency> |         <dependency> | ||||||
|             <groupId>net.md-5</groupId> |             <groupId>fr.pandacube.bungeecord</groupId> | ||||||
|             <artifactId>bungeecord-chat</artifactId> |             <artifactId>bungeecord-chat</artifactId> | ||||||
|             <version>${project.version}</version> |             <version>${project.version}</version> | ||||||
|             <scope>compile</scope> |             <scope>compile</scope> | ||||||
|   | |||||||
| @@ -1,31 +0,0 @@ | |||||||
| <?xml version="1.0" encoding="UTF-8"?> |  | ||||||
| <project-shared-configuration> |  | ||||||
|     <!-- |  | ||||||
|     This file contains additional configuration written by modules in the NetBeans IDE. |  | ||||||
|     The configuration is intended to be shared among all the users of project and |  | ||||||
|     therefore it is assumed to be part of version control checkout. |  | ||||||
|     Without this configuration present, some functionality in the IDE may be limited or fail altogether. |  | ||||||
|     --> |  | ||||||
|     <properties xmlns="http://www.netbeans.org/ns/maven-properties-data/1"> |  | ||||||
|         <!-- |  | ||||||
|         Properties that influence various parts of the IDE, especially code formatting and the like.  |  | ||||||
|         You can copy and paste the single properties, into the pom.xml file and the IDE will pick them up. |  | ||||||
|         That way multiple projects can share the same settings (useful for formatting rules for example). |  | ||||||
|         Any value defined here will override the pom.xml file value but is only applicable to the current project. |  | ||||||
|         --> |  | ||||||
|         <org-netbeans-modules-editor-indent.CodeStyle.usedProfile>project</org-netbeans-modules-editor-indent.CodeStyle.usedProfile> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens> |  | ||||||
|     </properties> |  | ||||||
| </project-shared-configuration> |  | ||||||
| @@ -1,20 +0,0 @@ | |||||||
|  |  | ||||||
| <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |  | ||||||
|          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |  | ||||||
|     <modelVersion>4.0.0</modelVersion> |  | ||||||
|  |  | ||||||
|     <parent> |  | ||||||
|         <groupId>net.md-5</groupId> |  | ||||||
|         <artifactId>bungeecord-module</artifactId> |  | ||||||
|         <version>1.20-R0.2-SNAPSHOT</version> |  | ||||||
|         <relativePath>../pom.xml</relativePath> |  | ||||||
|     </parent> |  | ||||||
|  |  | ||||||
|     <groupId>net.md-5</groupId> |  | ||||||
|     <artifactId>bungeecord-module-cmd-alert</artifactId> |  | ||||||
|     <version>1.20-R0.2-SNAPSHOT</version> |  | ||||||
|     <packaging>jar</packaging> |  | ||||||
|  |  | ||||||
|     <name>cmd_alert</name> |  | ||||||
|     <description>Provides the alert and alertraw commands</description> |  | ||||||
| </project> |  | ||||||
| @@ -1,47 +0,0 @@ | |||||||
| package net.md_5.bungee.module.cmd.alert; |  | ||||||
|  |  | ||||||
| import java.util.Locale; |  | ||||||
| import net.md_5.bungee.api.ChatColor; |  | ||||||
| import net.md_5.bungee.api.CommandSender; |  | ||||||
| import net.md_5.bungee.api.ProxyServer; |  | ||||||
| import net.md_5.bungee.api.chat.TextComponent; |  | ||||||
| import net.md_5.bungee.api.plugin.Command; |  | ||||||
|  |  | ||||||
| public class CommandAlert extends Command |  | ||||||
| { |  | ||||||
|  |  | ||||||
|     public CommandAlert() |  | ||||||
|     { |  | ||||||
|         super( "alert", "bungeecord.command.alert" ); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @Override |  | ||||||
|     public void execute(CommandSender sender, String[] args) |  | ||||||
|     { |  | ||||||
|         if ( args.length == 0 ) |  | ||||||
|         { |  | ||||||
|             sender.sendMessage( ProxyServer.getInstance().getTranslation( "message_needed" ) ); |  | ||||||
|         } else |  | ||||||
|         { |  | ||||||
|             StringBuilder builder = new StringBuilder(); |  | ||||||
|             if ( args[0].toLowerCase( Locale.ROOT ).startsWith( "&h" ) ) |  | ||||||
|             { |  | ||||||
|                 // Remove &h |  | ||||||
|                 args[0] = args[0].substring( 2 ); |  | ||||||
|             } else |  | ||||||
|             { |  | ||||||
|                 builder.append( ProxyServer.getInstance().getTranslation( "alert" ) ); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             for ( String s : args ) |  | ||||||
|             { |  | ||||||
|                 builder.append( ChatColor.translateAlternateColorCodes( '&', s ) ); |  | ||||||
|                 builder.append( " " ); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             String message = builder.substring( 0, builder.length() - 1 ); |  | ||||||
|  |  | ||||||
|             ProxyServer.getInstance().broadcast( TextComponent.fromLegacy( message ) ); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,56 +0,0 @@ | |||||||
| package net.md_5.bungee.module.cmd.alert; |  | ||||||
|  |  | ||||||
| import com.google.common.base.Joiner; |  | ||||||
| import net.md_5.bungee.api.ChatColor; |  | ||||||
| import net.md_5.bungee.api.CommandSender; |  | ||||||
| import net.md_5.bungee.api.ProxyServer; |  | ||||||
| import net.md_5.bungee.api.chat.ComponentBuilder; |  | ||||||
| import net.md_5.bungee.api.chat.HoverEvent; |  | ||||||
| import net.md_5.bungee.api.connection.ProxiedPlayer; |  | ||||||
| import net.md_5.bungee.api.plugin.Command; |  | ||||||
| import net.md_5.bungee.chat.ComponentSerializer; |  | ||||||
|  |  | ||||||
| public class CommandAlertRaw extends Command |  | ||||||
| { |  | ||||||
|  |  | ||||||
|     public CommandAlertRaw() |  | ||||||
|     { |  | ||||||
|         super( "alertraw", "bungeecord.command.alert" ); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @Override |  | ||||||
|     public void execute(CommandSender sender, String[] args) |  | ||||||
|     { |  | ||||||
|         if ( args.length == 0 ) |  | ||||||
|         { |  | ||||||
|             sender.sendMessage( ProxyServer.getInstance().getTranslation( "message_needed" ) ); |  | ||||||
|         } else |  | ||||||
|         { |  | ||||||
|             String message = Joiner.on( ' ' ).join( args ); |  | ||||||
|  |  | ||||||
|             try |  | ||||||
|             { |  | ||||||
|                 ProxyServer.getInstance().broadcast( ComponentSerializer.parse( message ) ); |  | ||||||
|             } catch ( Exception e ) |  | ||||||
|             { |  | ||||||
|                 Throwable error = e; |  | ||||||
|                 while ( error.getCause() != null ) |  | ||||||
|                 { |  | ||||||
|                     error = error.getCause(); |  | ||||||
|                 } |  | ||||||
|                 if ( sender instanceof ProxiedPlayer ) |  | ||||||
|                 { |  | ||||||
|                     sender.sendMessage( new ComponentBuilder( ProxyServer.getInstance().getTranslation( "error_occurred_player" ) ) |  | ||||||
|                             .event( new HoverEvent( HoverEvent.Action.SHOW_TEXT, new ComponentBuilder( error.getMessage() ) |  | ||||||
|                                     .color( ChatColor.RED ) |  | ||||||
|                                     .create() ) ) |  | ||||||
|                             .create() |  | ||||||
|                     ); |  | ||||||
|                 } else |  | ||||||
|                 { |  | ||||||
|                     sender.sendMessage( ProxyServer.getInstance().getTranslation( "error_occurred_console", error.getMessage() ) ); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,14 +0,0 @@ | |||||||
| package net.md_5.bungee.module.cmd.alert; |  | ||||||
|  |  | ||||||
| import net.md_5.bungee.api.plugin.Plugin; |  | ||||||
|  |  | ||||||
| public class PluginAlert extends Plugin |  | ||||||
| { |  | ||||||
|  |  | ||||||
|     @Override |  | ||||||
|     public void onEnable() |  | ||||||
|     { |  | ||||||
|         getProxy().getPluginManager().registerCommand( this, new CommandAlert() ); |  | ||||||
|         getProxy().getPluginManager().registerCommand( this, new CommandAlertRaw() ); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,5 +0,0 @@ | |||||||
| name: ${project.name} |  | ||||||
| main: net.md_5.bungee.module.cmd.alert.PluginAlert |  | ||||||
| version: ${describe} |  | ||||||
| description: ${project.description} |  | ||||||
| author: ${module.author} |  | ||||||
| @@ -1,31 +0,0 @@ | |||||||
| <?xml version="1.0" encoding="UTF-8"?> |  | ||||||
| <project-shared-configuration> |  | ||||||
|     <!-- |  | ||||||
|     This file contains additional configuration written by modules in the NetBeans IDE. |  | ||||||
|     The configuration is intended to be shared among all the users of project and |  | ||||||
|     therefore it is assumed to be part of version control checkout. |  | ||||||
|     Without this configuration present, some functionality in the IDE may be limited or fail altogether. |  | ||||||
|     --> |  | ||||||
|     <properties xmlns="http://www.netbeans.org/ns/maven-properties-data/1"> |  | ||||||
|         <!-- |  | ||||||
|         Properties that influence various parts of the IDE, especially code formatting and the like.  |  | ||||||
|         You can copy and paste the single properties, into the pom.xml file and the IDE will pick them up. |  | ||||||
|         That way multiple projects can share the same settings (useful for formatting rules for example). |  | ||||||
|         Any value defined here will override the pom.xml file value but is only applicable to the current project. |  | ||||||
|         --> |  | ||||||
|         <org-netbeans-modules-editor-indent.CodeStyle.usedProfile>project</org-netbeans-modules-editor-indent.CodeStyle.usedProfile> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens> |  | ||||||
|     </properties> |  | ||||||
| </project-shared-configuration> |  | ||||||
| @@ -1,20 +0,0 @@ | |||||||
|  |  | ||||||
| <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |  | ||||||
|          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |  | ||||||
|     <modelVersion>4.0.0</modelVersion> |  | ||||||
|  |  | ||||||
|     <parent> |  | ||||||
|         <groupId>net.md-5</groupId> |  | ||||||
|         <artifactId>bungeecord-module</artifactId> |  | ||||||
|         <version>1.20-R0.2-SNAPSHOT</version> |  | ||||||
|         <relativePath>../pom.xml</relativePath> |  | ||||||
|     </parent> |  | ||||||
|  |  | ||||||
|     <groupId>net.md-5</groupId> |  | ||||||
|     <artifactId>bungeecord-module-cmd-find</artifactId> |  | ||||||
|     <version>1.20-R0.2-SNAPSHOT</version> |  | ||||||
|     <packaging>jar</packaging> |  | ||||||
|  |  | ||||||
|     <name>cmd_find</name> |  | ||||||
|     <description>Provides the find command</description> |  | ||||||
| </project> |  | ||||||
| @@ -1,58 +0,0 @@ | |||||||
| package net.md_5.bungee.module.cmd.find; |  | ||||||
|  |  | ||||||
| import java.util.Collections; |  | ||||||
| import net.md_5.bungee.api.CommandSender; |  | ||||||
| import net.md_5.bungee.api.ProxyServer; |  | ||||||
| import net.md_5.bungee.api.chat.ClickEvent; |  | ||||||
| import net.md_5.bungee.api.chat.ComponentBuilder; |  | ||||||
| import net.md_5.bungee.api.chat.HoverEvent; |  | ||||||
| import net.md_5.bungee.api.config.ServerInfo; |  | ||||||
| import net.md_5.bungee.api.connection.ProxiedPlayer; |  | ||||||
| import net.md_5.bungee.command.PlayerCommand; |  | ||||||
|  |  | ||||||
| public class CommandFind extends PlayerCommand |  | ||||||
| { |  | ||||||
|  |  | ||||||
|     public CommandFind() |  | ||||||
|     { |  | ||||||
|         super( "find", "bungeecord.command.find" ); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @Override |  | ||||||
|     public void execute(CommandSender sender, String[] args) |  | ||||||
|     { |  | ||||||
|         if ( args.length != 1 ) |  | ||||||
|         { |  | ||||||
|             sender.sendMessage( ProxyServer.getInstance().getTranslation( "username_needed" ) ); |  | ||||||
|         } else |  | ||||||
|         { |  | ||||||
|             ProxiedPlayer player = ProxyServer.getInstance().getPlayer( args[0] ); |  | ||||||
|             if ( player == null || player.getServer() == null ) |  | ||||||
|             { |  | ||||||
|                 sender.sendMessage( ProxyServer.getInstance().getTranslation( "user_not_online" ) ); |  | ||||||
|             } else |  | ||||||
|             { |  | ||||||
|                 boolean moduleLoaded = ProxyServer.getInstance().getPluginManager().getPlugin( "cmd_server" ) != null; |  | ||||||
|                 ServerInfo server = player.getServer().getInfo(); |  | ||||||
|                 ComponentBuilder componentBuilder = new ComponentBuilder().appendLegacy( ProxyServer.getInstance().getTranslation( "user_online_at", player.getName(), server.getName() ) ); |  | ||||||
|  |  | ||||||
|                 if ( moduleLoaded && server.canAccess( sender ) ) |  | ||||||
|                 { |  | ||||||
|                     componentBuilder.event( new HoverEvent( |  | ||||||
|                             HoverEvent.Action.SHOW_TEXT, |  | ||||||
|                             new ComponentBuilder().appendLegacy( ProxyServer.getInstance().getTranslation( "click_to_connect" ) ).create() ) |  | ||||||
|                     ); |  | ||||||
|                     componentBuilder.event( new ClickEvent( ClickEvent.Action.RUN_COMMAND, "/server " + server.getName() ) ); |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|                 sender.sendMessage( componentBuilder.create() ); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @Override |  | ||||||
|     public Iterable<String> onTabComplete(CommandSender sender, String[] args) |  | ||||||
|     { |  | ||||||
|         return args.length == 1 ? super.onTabComplete( sender, args ) : Collections.emptyList(); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,13 +0,0 @@ | |||||||
| package net.md_5.bungee.module.cmd.find; |  | ||||||
|  |  | ||||||
| import net.md_5.bungee.api.plugin.Plugin; |  | ||||||
|  |  | ||||||
| public class PluginFind extends Plugin |  | ||||||
| { |  | ||||||
|  |  | ||||||
|     @Override |  | ||||||
|     public void onEnable() |  | ||||||
|     { |  | ||||||
|         getProxy().getPluginManager().registerCommand( this, new CommandFind() ); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,5 +0,0 @@ | |||||||
| name: ${project.name} |  | ||||||
| main: net.md_5.bungee.module.cmd.find.PluginFind |  | ||||||
| version: ${describe} |  | ||||||
| description: ${project.description} |  | ||||||
| author: ${module.author} |  | ||||||
| @@ -1,31 +0,0 @@ | |||||||
| <?xml version="1.0" encoding="UTF-8"?> |  | ||||||
| <project-shared-configuration> |  | ||||||
|     <!-- |  | ||||||
|     This file contains additional configuration written by modules in the NetBeans IDE. |  | ||||||
|     The configuration is intended to be shared among all the users of project and |  | ||||||
|     therefore it is assumed to be part of version control checkout. |  | ||||||
|     Without this configuration present, some functionality in the IDE may be limited or fail altogether. |  | ||||||
|     --> |  | ||||||
|     <properties xmlns="http://www.netbeans.org/ns/maven-properties-data/1"> |  | ||||||
|         <!-- |  | ||||||
|         Properties that influence various parts of the IDE, especially code formatting and the like.  |  | ||||||
|         You can copy and paste the single properties, into the pom.xml file and the IDE will pick them up. |  | ||||||
|         That way multiple projects can share the same settings (useful for formatting rules for example). |  | ||||||
|         Any value defined here will override the pom.xml file value but is only applicable to the current project. |  | ||||||
|         --> |  | ||||||
|         <org-netbeans-modules-editor-indent.CodeStyle.usedProfile>project</org-netbeans-modules-editor-indent.CodeStyle.usedProfile> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens> |  | ||||||
|     </properties> |  | ||||||
| </project-shared-configuration> |  | ||||||
| @@ -1,20 +0,0 @@ | |||||||
|  |  | ||||||
| <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |  | ||||||
|          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |  | ||||||
|     <modelVersion>4.0.0</modelVersion> |  | ||||||
|  |  | ||||||
|     <parent> |  | ||||||
|         <groupId>net.md-5</groupId> |  | ||||||
|         <artifactId>bungeecord-module</artifactId> |  | ||||||
|         <version>1.20-R0.2-SNAPSHOT</version> |  | ||||||
|         <relativePath>../pom.xml</relativePath> |  | ||||||
|     </parent> |  | ||||||
|  |  | ||||||
|     <groupId>net.md-5</groupId> |  | ||||||
|     <artifactId>bungeecord-module-cmd-kick</artifactId> |  | ||||||
|     <version>1.20-R0.2-SNAPSHOT</version> |  | ||||||
|     <packaging>jar</packaging> |  | ||||||
|  |  | ||||||
|     <name>cmd_kick</name> |  | ||||||
|     <description>Provides the gkick command</description> |  | ||||||
| </project> |  | ||||||
| @@ -1,72 +0,0 @@ | |||||||
| package net.md_5.bungee.module.cmd.kick; |  | ||||||
|  |  | ||||||
| import com.google.common.base.Joiner; |  | ||||||
| import com.google.common.collect.ImmutableSet; |  | ||||||
| import java.util.HashSet; |  | ||||||
| import java.util.Locale; |  | ||||||
| import java.util.Set; |  | ||||||
| import net.md_5.bungee.api.ChatColor; |  | ||||||
| import net.md_5.bungee.api.CommandSender; |  | ||||||
| import net.md_5.bungee.api.ProxyServer; |  | ||||||
| import net.md_5.bungee.api.chat.TextComponent; |  | ||||||
| import net.md_5.bungee.api.connection.ProxiedPlayer; |  | ||||||
| import net.md_5.bungee.api.plugin.Command; |  | ||||||
| import net.md_5.bungee.api.plugin.TabExecutor; |  | ||||||
|  |  | ||||||
| public class CommandKick extends Command implements TabExecutor |  | ||||||
| { |  | ||||||
|  |  | ||||||
|     public CommandKick() |  | ||||||
|     { |  | ||||||
|         super( "gkick", "bungeecord.command.kick" ); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @Override |  | ||||||
|     public void execute(CommandSender sender, String[] args) |  | ||||||
|     { |  | ||||||
|         if ( args.length == 0 ) |  | ||||||
|         { |  | ||||||
|             sender.sendMessage( ProxyServer.getInstance().getTranslation( "username_needed" ) ); |  | ||||||
|         } else |  | ||||||
|         { |  | ||||||
|             ProxiedPlayer player = ProxyServer.getInstance().getPlayer( args[0] ); |  | ||||||
|  |  | ||||||
|             if ( player == null ) |  | ||||||
|             { |  | ||||||
|                 sender.sendMessage( TextComponent.fromLegacy( ProxyServer.getInstance().getTranslation( "user_not_online" ) ) ); |  | ||||||
|                 return; |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             if ( args.length == 1 ) |  | ||||||
|             { |  | ||||||
|                 player.disconnect( TextComponent.fromLegacy( ProxyServer.getInstance().getTranslation( "kick_message" ) ) ); |  | ||||||
|             } else |  | ||||||
|             { |  | ||||||
|                 String[] reason = new String[ args.length - 1 ]; |  | ||||||
|                 System.arraycopy( args, 1, reason, 0, reason.length ); |  | ||||||
|                 player.disconnect( TextComponent.fromLegacy( ChatColor.translateAlternateColorCodes( '&', Joiner.on( ' ' ).join( reason ) ) ) ); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @Override |  | ||||||
|     public Iterable<String> onTabComplete(CommandSender sender, String[] args) |  | ||||||
|     { |  | ||||||
|         if ( args.length == 1 ) |  | ||||||
|         { |  | ||||||
|             Set<String> matches = new HashSet<>(); |  | ||||||
|             String search = args[0].toLowerCase( Locale.ROOT ); |  | ||||||
|             for ( ProxiedPlayer player : ProxyServer.getInstance().getPlayers() ) |  | ||||||
|             { |  | ||||||
|                 if ( player.getName().toLowerCase( Locale.ROOT ).startsWith( search ) ) |  | ||||||
|                 { |  | ||||||
|                     matches.add( player.getName() ); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             return matches; |  | ||||||
|         } else |  | ||||||
|         { |  | ||||||
|             return ImmutableSet.of(); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,13 +0,0 @@ | |||||||
| package net.md_5.bungee.module.cmd.kick; |  | ||||||
|  |  | ||||||
| import net.md_5.bungee.api.plugin.Plugin; |  | ||||||
|  |  | ||||||
| public class PluginKick extends Plugin |  | ||||||
| { |  | ||||||
|  |  | ||||||
|     @Override |  | ||||||
|     public void onEnable() |  | ||||||
|     { |  | ||||||
|         getProxy().getPluginManager().registerCommand( this, new CommandKick() ); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,5 +0,0 @@ | |||||||
| name: ${project.name} |  | ||||||
| main: net.md_5.bungee.module.cmd.kick.PluginKick |  | ||||||
| version: ${describe} |  | ||||||
| description: ${project.description} |  | ||||||
| author: ${module.author} |  | ||||||
| @@ -1,31 +0,0 @@ | |||||||
| <?xml version="1.0" encoding="UTF-8"?> |  | ||||||
| <project-shared-configuration> |  | ||||||
|     <!-- |  | ||||||
|     This file contains additional configuration written by modules in the NetBeans IDE. |  | ||||||
|     The configuration is intended to be shared among all the users of project and |  | ||||||
|     therefore it is assumed to be part of version control checkout. |  | ||||||
|     Without this configuration present, some functionality in the IDE may be limited or fail altogether. |  | ||||||
|     --> |  | ||||||
|     <properties xmlns="http://www.netbeans.org/ns/maven-properties-data/1"> |  | ||||||
|         <!-- |  | ||||||
|         Properties that influence various parts of the IDE, especially code formatting and the like.  |  | ||||||
|         You can copy and paste the single properties, into the pom.xml file and the IDE will pick them up. |  | ||||||
|         That way multiple projects can share the same settings (useful for formatting rules for example). |  | ||||||
|         Any value defined here will override the pom.xml file value but is only applicable to the current project. |  | ||||||
|         --> |  | ||||||
|         <org-netbeans-modules-editor-indent.CodeStyle.usedProfile>project</org-netbeans-modules-editor-indent.CodeStyle.usedProfile> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens> |  | ||||||
|     </properties> |  | ||||||
| </project-shared-configuration> |  | ||||||
| @@ -1,20 +0,0 @@ | |||||||
|  |  | ||||||
| <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |  | ||||||
|          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |  | ||||||
|     <modelVersion>4.0.0</modelVersion> |  | ||||||
|  |  | ||||||
|     <parent> |  | ||||||
|         <groupId>net.md-5</groupId> |  | ||||||
|         <artifactId>bungeecord-module</artifactId> |  | ||||||
|         <version>1.20-R0.2-SNAPSHOT</version> |  | ||||||
|         <relativePath>../pom.xml</relativePath> |  | ||||||
|     </parent> |  | ||||||
|  |  | ||||||
|     <groupId>net.md-5</groupId> |  | ||||||
|     <artifactId>bungeecord-module-cmd-list</artifactId> |  | ||||||
|     <version>1.20-R0.2-SNAPSHOT</version> |  | ||||||
|     <packaging>jar</packaging> |  | ||||||
|  |  | ||||||
|     <name>cmd_list</name> |  | ||||||
|     <description>Provides the glist command</description> |  | ||||||
| </project> |  | ||||||
| @@ -1,62 +0,0 @@ | |||||||
| package net.md_5.bungee.module.cmd.list; |  | ||||||
|  |  | ||||||
| import java.util.ArrayList; |  | ||||||
| import java.util.Collection; |  | ||||||
| import java.util.Collections; |  | ||||||
| import java.util.List; |  | ||||||
| import net.md_5.bungee.api.ChatColor; |  | ||||||
| import net.md_5.bungee.api.CommandSender; |  | ||||||
| import net.md_5.bungee.api.ProxyServer; |  | ||||||
| import net.md_5.bungee.api.config.ServerInfo; |  | ||||||
| import net.md_5.bungee.api.connection.ProxiedPlayer; |  | ||||||
| import net.md_5.bungee.api.plugin.Command; |  | ||||||
| import net.md_5.bungee.api.plugin.TabExecutor; |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Command to list all players connected to the proxy. |  | ||||||
|  */ |  | ||||||
| public class CommandList extends Command implements TabExecutor |  | ||||||
| { |  | ||||||
|  |  | ||||||
|     public CommandList() |  | ||||||
|     { |  | ||||||
|         super( "glist", "bungeecord.command.list" ); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @Override |  | ||||||
|     public void execute(CommandSender sender, String[] args) |  | ||||||
|     { |  | ||||||
|         boolean hideEmptyServers = ( args.length == 0 ) || !args[0].equalsIgnoreCase( "all" ); |  | ||||||
|  |  | ||||||
|         for ( ServerInfo server : ProxyServer.getInstance().getServers().values() ) |  | ||||||
|         { |  | ||||||
|             if ( !server.canAccess( sender ) ) |  | ||||||
|             { |  | ||||||
|                 continue; |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             Collection<ProxiedPlayer> serverPlayers = server.getPlayers(); |  | ||||||
|             if ( hideEmptyServers && serverPlayers.isEmpty() ) |  | ||||||
|             { |  | ||||||
|                 continue; |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             List<String> players = new ArrayList<>(); |  | ||||||
|             for ( ProxiedPlayer player : serverPlayers ) |  | ||||||
|             { |  | ||||||
|                 players.add( player.getDisplayName() ); |  | ||||||
|             } |  | ||||||
|             Collections.sort( players, String.CASE_INSENSITIVE_ORDER ); |  | ||||||
|  |  | ||||||
|             sender.sendMessage( ProxyServer.getInstance().getTranslation( "command_list", server.getName(), players.size(), String.join( ChatColor.RESET + ", ", players ) ) ); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         sender.sendMessage( ProxyServer.getInstance().getTranslation( "total_players", ProxyServer.getInstance().getOnlineCount() ) ); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @Override |  | ||||||
|     public Iterable<String> onTabComplete(CommandSender sender, String[] args) |  | ||||||
|     { |  | ||||||
|         return ( args.length > 1 ) ? Collections.emptyList() : Collections.singletonList( "all" ); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,13 +0,0 @@ | |||||||
| package net.md_5.bungee.module.cmd.list; |  | ||||||
|  |  | ||||||
| import net.md_5.bungee.api.plugin.Plugin; |  | ||||||
|  |  | ||||||
| public class PluginList extends Plugin |  | ||||||
| { |  | ||||||
|  |  | ||||||
|     @Override |  | ||||||
|     public void onEnable() |  | ||||||
|     { |  | ||||||
|         getProxy().getPluginManager().registerCommand( this, new CommandList() ); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,5 +0,0 @@ | |||||||
| name: ${project.name} |  | ||||||
| main: net.md_5.bungee.module.cmd.list.PluginList |  | ||||||
| version: ${describe} |  | ||||||
| description: ${project.description} |  | ||||||
| author: ${module.author} |  | ||||||
| @@ -1,31 +0,0 @@ | |||||||
| <?xml version="1.0" encoding="UTF-8"?> |  | ||||||
| <project-shared-configuration> |  | ||||||
|     <!-- |  | ||||||
|     This file contains additional configuration written by modules in the NetBeans IDE. |  | ||||||
|     The configuration is intended to be shared among all the users of project and |  | ||||||
|     therefore it is assumed to be part of version control checkout. |  | ||||||
|     Without this configuration present, some functionality in the IDE may be limited or fail altogether. |  | ||||||
|     --> |  | ||||||
|     <properties xmlns="http://www.netbeans.org/ns/maven-properties-data/1"> |  | ||||||
|         <!-- |  | ||||||
|         Properties that influence various parts of the IDE, especially code formatting and the like.  |  | ||||||
|         You can copy and paste the single properties, into the pom.xml file and the IDE will pick them up. |  | ||||||
|         That way multiple projects can share the same settings (useful for formatting rules for example). |  | ||||||
|         Any value defined here will override the pom.xml file value but is only applicable to the current project. |  | ||||||
|         --> |  | ||||||
|         <org-netbeans-modules-editor-indent.CodeStyle.usedProfile>project</org-netbeans-modules-editor-indent.CodeStyle.usedProfile> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens> |  | ||||||
|     </properties> |  | ||||||
| </project-shared-configuration> |  | ||||||
| @@ -1,20 +0,0 @@ | |||||||
|  |  | ||||||
| <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |  | ||||||
|          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |  | ||||||
|     <modelVersion>4.0.0</modelVersion> |  | ||||||
|  |  | ||||||
|     <parent> |  | ||||||
|         <groupId>net.md-5</groupId> |  | ||||||
|         <artifactId>bungeecord-module</artifactId> |  | ||||||
|         <version>1.20-R0.2-SNAPSHOT</version> |  | ||||||
|         <relativePath>../pom.xml</relativePath> |  | ||||||
|     </parent> |  | ||||||
|  |  | ||||||
|     <groupId>net.md-5</groupId> |  | ||||||
|     <artifactId>bungeecord-module-cmd-send</artifactId> |  | ||||||
|     <version>1.20-R0.2-SNAPSHOT</version> |  | ||||||
|     <packaging>jar</packaging> |  | ||||||
|  |  | ||||||
|     <name>cmd_send</name> |  | ||||||
|     <description>Provides the gsend command</description> |  | ||||||
| </project> |  | ||||||
| @@ -1,200 +0,0 @@ | |||||||
| package net.md_5.bungee.module.cmd.send; |  | ||||||
|  |  | ||||||
| import com.google.common.base.Joiner; |  | ||||||
| import com.google.common.collect.ImmutableSet; |  | ||||||
| import java.util.ArrayList; |  | ||||||
| import java.util.Collections; |  | ||||||
| import java.util.HashMap; |  | ||||||
| import java.util.HashSet; |  | ||||||
| import java.util.List; |  | ||||||
| import java.util.Locale; |  | ||||||
| import java.util.Map; |  | ||||||
| import java.util.Set; |  | ||||||
| import net.md_5.bungee.api.Callback; |  | ||||||
| import net.md_5.bungee.api.ChatColor; |  | ||||||
| import net.md_5.bungee.api.CommandSender; |  | ||||||
| import net.md_5.bungee.api.ProxyServer; |  | ||||||
| import net.md_5.bungee.api.ServerConnectRequest; |  | ||||||
| import net.md_5.bungee.api.chat.ComponentBuilder; |  | ||||||
| import net.md_5.bungee.api.chat.HoverEvent; |  | ||||||
| import net.md_5.bungee.api.config.ServerInfo; |  | ||||||
| import net.md_5.bungee.api.connection.ProxiedPlayer; |  | ||||||
| import net.md_5.bungee.api.event.ServerConnectEvent; |  | ||||||
| import net.md_5.bungee.api.plugin.Command; |  | ||||||
| import net.md_5.bungee.api.plugin.TabExecutor; |  | ||||||
|  |  | ||||||
| public class CommandSend extends Command implements TabExecutor |  | ||||||
| { |  | ||||||
|  |  | ||||||
|     protected static class SendCallback |  | ||||||
|     { |  | ||||||
|  |  | ||||||
|         private final Map<ServerConnectRequest.Result, List<String>> results = new HashMap<>(); |  | ||||||
|         private final CommandSender sender; |  | ||||||
|         private int count = 0; |  | ||||||
|  |  | ||||||
|         public SendCallback(CommandSender sender) |  | ||||||
|         { |  | ||||||
|             this.sender = sender; |  | ||||||
|             for ( ServerConnectRequest.Result result : ServerConnectRequest.Result.values() ) |  | ||||||
|             { |  | ||||||
|                 results.put( result, Collections.synchronizedList( new ArrayList<>() ) ); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         public void lastEntryDone() |  | ||||||
|         { |  | ||||||
|             sender.sendMessage( ChatColor.GREEN.toString() + ChatColor.BOLD + "Send Results:" ); |  | ||||||
|             for ( Map.Entry<ServerConnectRequest.Result, List<String>> entry : results.entrySet() ) |  | ||||||
|             { |  | ||||||
|                 ComponentBuilder builder = new ComponentBuilder( "" ); |  | ||||||
|                 if ( !entry.getValue().isEmpty() ) |  | ||||||
|                 { |  | ||||||
|                     builder.event( new HoverEvent( HoverEvent.Action.SHOW_TEXT, |  | ||||||
|                             new ComponentBuilder( Joiner.on( ", " ).join( entry.getValue() ) ).color( ChatColor.YELLOW ).create() ) ); |  | ||||||
|                 } |  | ||||||
|                 builder.append( entry.getKey().name() + ": " ).color( ChatColor.GREEN ); |  | ||||||
|                 builder.append( "" + entry.getValue().size() ).bold( true ); |  | ||||||
|                 sender.sendMessage( builder.create() ); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         public static class Entry implements Callback<ServerConnectRequest.Result> |  | ||||||
|         { |  | ||||||
|  |  | ||||||
|             private final SendCallback callback; |  | ||||||
|             private final ProxiedPlayer player; |  | ||||||
|             private final ServerInfo target; |  | ||||||
|  |  | ||||||
|             public Entry(SendCallback callback, ProxiedPlayer player, ServerInfo target) |  | ||||||
|             { |  | ||||||
|                 this.callback = callback; |  | ||||||
|                 this.player = player; |  | ||||||
|                 this.target = target; |  | ||||||
|                 this.callback.count++; |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             @Override |  | ||||||
|             public void done(ServerConnectRequest.Result result, Throwable error) |  | ||||||
|             { |  | ||||||
|                 callback.results.get( result ).add( player.getName() ); |  | ||||||
|                 if ( result == ServerConnectRequest.Result.SUCCESS ) |  | ||||||
|                 { |  | ||||||
|                     player.sendMessage( ProxyServer.getInstance().getTranslation( "you_got_summoned", target.getName(), callback.sender.getName() ) ); |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|                 if ( --callback.count == 0 ) |  | ||||||
|                 { |  | ||||||
|                     callback.lastEntryDone(); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public CommandSend() |  | ||||||
|     { |  | ||||||
|         super( "send", "bungeecord.command.send" ); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @Override |  | ||||||
|     public void execute(CommandSender sender, String[] args) |  | ||||||
|     { |  | ||||||
|         if ( args.length != 2 ) |  | ||||||
|         { |  | ||||||
|             sender.sendMessage( ProxyServer.getInstance().getTranslation( "send_cmd_usage" ) ); |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|         ServerInfo server = ProxyServer.getInstance().getServerInfo( args[1] ); |  | ||||||
|         if ( server == null ) |  | ||||||
|         { |  | ||||||
|             sender.sendMessage( ProxyServer.getInstance().getTranslation( "no_server" ) ); |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         List<ProxiedPlayer> targets; |  | ||||||
|         if ( args[0].equalsIgnoreCase( "all" ) ) |  | ||||||
|         { |  | ||||||
|             targets = new ArrayList<>( ProxyServer.getInstance().getPlayers() ); |  | ||||||
|         } else if ( args[0].equalsIgnoreCase( "current" ) ) |  | ||||||
|         { |  | ||||||
|             if ( !( sender instanceof ProxiedPlayer ) ) |  | ||||||
|             { |  | ||||||
|                 sender.sendMessage( ProxyServer.getInstance().getTranslation( "player_only" ) ); |  | ||||||
|                 return; |  | ||||||
|             } |  | ||||||
|             ProxiedPlayer player = (ProxiedPlayer) sender; |  | ||||||
|             targets = new ArrayList<>( player.getServer().getInfo().getPlayers() ); |  | ||||||
|         } else |  | ||||||
|         { |  | ||||||
|             // If we use a server name, send the entire server. This takes priority over players. |  | ||||||
|             ServerInfo serverTarget = ProxyServer.getInstance().getServerInfo( args[0] ); |  | ||||||
|             if ( serverTarget != null ) |  | ||||||
|             { |  | ||||||
|                 targets = new ArrayList<>( serverTarget.getPlayers() ); |  | ||||||
|             } else |  | ||||||
|             { |  | ||||||
|                 ProxiedPlayer player = ProxyServer.getInstance().getPlayer( args[0] ); |  | ||||||
|                 if ( player == null ) |  | ||||||
|                 { |  | ||||||
|                     sender.sendMessage( ProxyServer.getInstance().getTranslation( "user_not_online" ) ); |  | ||||||
|                     return; |  | ||||||
|                 } |  | ||||||
|                 targets = Collections.singletonList( player ); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         final SendCallback callback = new SendCallback( sender ); |  | ||||||
|         for ( ProxiedPlayer player : targets ) |  | ||||||
|         { |  | ||||||
|             ServerConnectRequest request = ServerConnectRequest.builder() |  | ||||||
|                     .target( server ) |  | ||||||
|                     .reason( ServerConnectEvent.Reason.COMMAND ) |  | ||||||
|                     .callback( new SendCallback.Entry( callback, player, server ) ) |  | ||||||
|                     .build(); |  | ||||||
|             player.connect( request ); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         sender.sendMessage( ChatColor.DARK_GREEN + "Attempting to send " + targets.size() + " players to " + server.getName() ); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @Override |  | ||||||
|     public Iterable<String> onTabComplete(CommandSender sender, String[] args) |  | ||||||
|     { |  | ||||||
|         if ( args.length > 2 || args.length == 0 ) |  | ||||||
|         { |  | ||||||
|             return ImmutableSet.of(); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         Set<String> matches = new HashSet<>(); |  | ||||||
|         if ( args.length == 1 ) |  | ||||||
|         { |  | ||||||
|             String search = args[0].toLowerCase( Locale.ROOT ); |  | ||||||
|             for ( ProxiedPlayer player : ProxyServer.getInstance().getPlayers() ) |  | ||||||
|             { |  | ||||||
|                 if ( player.getName().toLowerCase( Locale.ROOT ).startsWith( search ) ) |  | ||||||
|                 { |  | ||||||
|                     matches.add( player.getName() ); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             if ( "all".startsWith( search ) ) |  | ||||||
|             { |  | ||||||
|                 matches.add( "all" ); |  | ||||||
|             } |  | ||||||
|             if ( "current".startsWith( search ) ) |  | ||||||
|             { |  | ||||||
|                 matches.add( "current" ); |  | ||||||
|             } |  | ||||||
|         } else |  | ||||||
|         { |  | ||||||
|             String search = args[1].toLowerCase( Locale.ROOT ); |  | ||||||
|             for ( String server : ProxyServer.getInstance().getServers().keySet() ) |  | ||||||
|             { |  | ||||||
|                 if ( server.toLowerCase( Locale.ROOT ).startsWith( search ) ) |  | ||||||
|                 { |  | ||||||
|                     matches.add( server ); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         return matches; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,13 +0,0 @@ | |||||||
| package net.md_5.bungee.module.cmd.send; |  | ||||||
|  |  | ||||||
| import net.md_5.bungee.api.plugin.Plugin; |  | ||||||
|  |  | ||||||
| public class PluginSend extends Plugin |  | ||||||
| { |  | ||||||
|  |  | ||||||
|     @Override |  | ||||||
|     public void onEnable() |  | ||||||
|     { |  | ||||||
|         getProxy().getPluginManager().registerCommand( this, new CommandSend() ); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,5 +0,0 @@ | |||||||
| name: ${project.name} |  | ||||||
| main: net.md_5.bungee.module.cmd.send.PluginSend |  | ||||||
| version: ${describe} |  | ||||||
| description: ${project.description} |  | ||||||
| author: ${module.author} |  | ||||||
| @@ -1,31 +0,0 @@ | |||||||
| <?xml version="1.0" encoding="UTF-8"?> |  | ||||||
| <project-shared-configuration> |  | ||||||
|     <!-- |  | ||||||
|     This file contains additional configuration written by modules in the NetBeans IDE. |  | ||||||
|     The configuration is intended to be shared among all the users of project and |  | ||||||
|     therefore it is assumed to be part of version control checkout. |  | ||||||
|     Without this configuration present, some functionality in the IDE may be limited or fail altogether. |  | ||||||
|     --> |  | ||||||
|     <properties xmlns="http://www.netbeans.org/ns/maven-properties-data/1"> |  | ||||||
|         <!-- |  | ||||||
|         Properties that influence various parts of the IDE, especially code formatting and the like.  |  | ||||||
|         You can copy and paste the single properties, into the pom.xml file and the IDE will pick them up. |  | ||||||
|         That way multiple projects can share the same settings (useful for formatting rules for example). |  | ||||||
|         Any value defined here will override the pom.xml file value but is only applicable to the current project. |  | ||||||
|         --> |  | ||||||
|         <org-netbeans-modules-editor-indent.CodeStyle.usedProfile>project</org-netbeans-modules-editor-indent.CodeStyle.usedProfile> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens> |  | ||||||
|     </properties> |  | ||||||
| </project-shared-configuration> |  | ||||||
| @@ -1,20 +0,0 @@ | |||||||
|  |  | ||||||
| <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |  | ||||||
|          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |  | ||||||
|     <modelVersion>4.0.0</modelVersion> |  | ||||||
|  |  | ||||||
|     <parent> |  | ||||||
|         <groupId>net.md-5</groupId> |  | ||||||
|         <artifactId>bungeecord-module</artifactId> |  | ||||||
|         <version>1.20-R0.2-SNAPSHOT</version> |  | ||||||
|         <relativePath>../pom.xml</relativePath> |  | ||||||
|     </parent> |  | ||||||
|  |  | ||||||
|     <groupId>net.md-5</groupId> |  | ||||||
|     <artifactId>bungeecord-module-cmd-server</artifactId> |  | ||||||
|     <version>1.20-R0.2-SNAPSHOT</version> |  | ||||||
|     <packaging>jar</packaging> |  | ||||||
|  |  | ||||||
|     <name>cmd_server</name> |  | ||||||
|     <description>Provides the server command</description> |  | ||||||
| </project> |  | ||||||
| @@ -1,104 +0,0 @@ | |||||||
| package net.md_5.bungee.module.cmd.server; |  | ||||||
|  |  | ||||||
| import com.google.common.base.Function; |  | ||||||
| import com.google.common.base.Predicate; |  | ||||||
| import com.google.common.collect.Iterables; |  | ||||||
| import java.util.Collections; |  | ||||||
| import java.util.Locale; |  | ||||||
| import java.util.Map; |  | ||||||
| import net.md_5.bungee.api.CommandSender; |  | ||||||
| import net.md_5.bungee.api.ProxyServer; |  | ||||||
| import net.md_5.bungee.api.chat.ClickEvent; |  | ||||||
| import net.md_5.bungee.api.chat.ComponentBuilder; |  | ||||||
| import net.md_5.bungee.api.chat.HoverEvent; |  | ||||||
| import net.md_5.bungee.api.chat.TextComponent; |  | ||||||
| import net.md_5.bungee.api.config.ServerInfo; |  | ||||||
| import net.md_5.bungee.api.connection.ProxiedPlayer; |  | ||||||
| import net.md_5.bungee.api.event.ServerConnectEvent; |  | ||||||
| import net.md_5.bungee.api.plugin.Command; |  | ||||||
| import net.md_5.bungee.api.plugin.TabExecutor; |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Command to list and switch a player between available servers. |  | ||||||
|  */ |  | ||||||
| public class CommandServer extends Command implements TabExecutor |  | ||||||
| { |  | ||||||
|  |  | ||||||
|     public CommandServer() |  | ||||||
|     { |  | ||||||
|         super( "server", "bungeecord.command.server" ); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @Override |  | ||||||
|     public void execute(CommandSender sender, String[] args) |  | ||||||
|     { |  | ||||||
|         Map<String, ServerInfo> servers = ProxyServer.getInstance().getServers(); |  | ||||||
|         if ( args.length == 0 ) |  | ||||||
|         { |  | ||||||
|             if ( sender instanceof ProxiedPlayer ) |  | ||||||
|             { |  | ||||||
|                 sender.sendMessage( ProxyServer.getInstance().getTranslation( "current_server", ( (ProxiedPlayer) sender ).getServer().getInfo().getName() ) ); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             ComponentBuilder serverList = new ComponentBuilder().appendLegacy( ProxyServer.getInstance().getTranslation( "server_list" ) ); |  | ||||||
|             boolean first = true; |  | ||||||
|             for ( ServerInfo server : servers.values() ) |  | ||||||
|             { |  | ||||||
|                 if ( server.canAccess( sender ) ) |  | ||||||
|                 { |  | ||||||
|                     TextComponent serverTextComponent = new TextComponent( first ? server.getName() : ", " + server.getName() ); |  | ||||||
|                     int count = server.getPlayers().size(); |  | ||||||
|                     serverTextComponent.setHoverEvent( new HoverEvent( |  | ||||||
|                             HoverEvent.Action.SHOW_TEXT, |  | ||||||
|                             new ComponentBuilder( count + ( count == 1 ? " player" : " players" ) + "\n" ).appendLegacy( ProxyServer.getInstance().getTranslation( "click_to_connect" ) ).create() ) |  | ||||||
|                     ); |  | ||||||
|                     serverTextComponent.setClickEvent( new ClickEvent( ClickEvent.Action.RUN_COMMAND, "/server " + server.getName() ) ); |  | ||||||
|                     serverList.append( serverTextComponent ); |  | ||||||
|                     first = false; |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             sender.sendMessage( serverList.create() ); |  | ||||||
|         } else |  | ||||||
|         { |  | ||||||
|             if ( !( sender instanceof ProxiedPlayer ) ) |  | ||||||
|             { |  | ||||||
|                 return; |  | ||||||
|             } |  | ||||||
|             ProxiedPlayer player = (ProxiedPlayer) sender; |  | ||||||
|  |  | ||||||
|             ServerInfo server = servers.get( args[0] ); |  | ||||||
|             if ( server == null ) |  | ||||||
|             { |  | ||||||
|                 player.sendMessage( ProxyServer.getInstance().getTranslation( "no_server" ) ); |  | ||||||
|             } else if ( !server.canAccess( player ) ) |  | ||||||
|             { |  | ||||||
|                 player.sendMessage( ProxyServer.getInstance().getTranslation( "no_server_permission" ) ); |  | ||||||
|             } else |  | ||||||
|             { |  | ||||||
|                 player.connect( server, ServerConnectEvent.Reason.COMMAND ); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @Override |  | ||||||
|     public Iterable<String> onTabComplete(final CommandSender sender, final String[] args) |  | ||||||
|     { |  | ||||||
|         return ( args.length > 1 ) ? Collections.EMPTY_LIST : Iterables.transform( Iterables.filter( ProxyServer.getInstance().getServers().values(), new Predicate<ServerInfo>() |  | ||||||
|         { |  | ||||||
|             private final String lower = ( args.length == 0 ) ? "" : args[0].toLowerCase( Locale.ROOT ); |  | ||||||
|  |  | ||||||
|             @Override |  | ||||||
|             public boolean apply(ServerInfo input) |  | ||||||
|             { |  | ||||||
|                 return input.getName().toLowerCase( Locale.ROOT ).startsWith( lower ) && input.canAccess( sender ); |  | ||||||
|             } |  | ||||||
|         } ), new Function<ServerInfo, String>() |  | ||||||
|         { |  | ||||||
|             @Override |  | ||||||
|             public String apply(ServerInfo input) |  | ||||||
|             { |  | ||||||
|                 return input.getName(); |  | ||||||
|             } |  | ||||||
|         } ); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,13 +0,0 @@ | |||||||
| package net.md_5.bungee.module.cmd.server; |  | ||||||
|  |  | ||||||
| import net.md_5.bungee.api.plugin.Plugin; |  | ||||||
|  |  | ||||||
| public class PluginServer extends Plugin |  | ||||||
| { |  | ||||||
|  |  | ||||||
|     @Override |  | ||||||
|     public void onEnable() |  | ||||||
|     { |  | ||||||
|         getProxy().getPluginManager().registerCommand( this, new CommandServer() ); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,5 +0,0 @@ | |||||||
| name: ${project.name} |  | ||||||
| main: net.md_5.bungee.module.cmd.server.PluginServer |  | ||||||
| version: ${describe} |  | ||||||
| description: ${project.description} |  | ||||||
| author: ${module.author} |  | ||||||
| @@ -1,55 +0,0 @@ | |||||||
|  |  | ||||||
| <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |  | ||||||
|          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |  | ||||||
|     <modelVersion>4.0.0</modelVersion> |  | ||||||
|  |  | ||||||
|     <parent> |  | ||||||
|         <groupId>net.md-5</groupId> |  | ||||||
|         <artifactId>bungeecord-parent</artifactId> |  | ||||||
|         <version>1.20-R0.2-SNAPSHOT</version> |  | ||||||
|         <relativePath>../pom.xml</relativePath> |  | ||||||
|     </parent> |  | ||||||
|  |  | ||||||
|     <groupId>net.md-5</groupId> |  | ||||||
|     <artifactId>bungeecord-module</artifactId> |  | ||||||
|     <version>1.20-R0.2-SNAPSHOT</version> |  | ||||||
|     <packaging>pom</packaging> |  | ||||||
|  |  | ||||||
|     <name>BungeeCord Modules</name> |  | ||||||
|     <description>Parent project for all BungeeCord modules.</description> |  | ||||||
|  |  | ||||||
|     <modules> |  | ||||||
|         <module>cmd-alert</module> |  | ||||||
|         <module>cmd-find</module> |  | ||||||
|         <module>cmd-kick</module> |  | ||||||
|         <module>cmd-list</module> |  | ||||||
|         <module>cmd-send</module> |  | ||||||
|         <module>cmd-server</module> |  | ||||||
|         <module>reconnect-yaml</module> |  | ||||||
|     </modules> |  | ||||||
|  |  | ||||||
|     <properties> |  | ||||||
|         <module.author>SpigotMC</module.author> |  | ||||||
|         <maven.deploy.skip>true</maven.deploy.skip> |  | ||||||
|         <maven.javadoc.skip>true</maven.javadoc.skip> |  | ||||||
|     </properties> |  | ||||||
|  |  | ||||||
|     <dependencies> |  | ||||||
|         <dependency> |  | ||||||
|             <groupId>net.md-5</groupId> |  | ||||||
|             <artifactId>bungeecord-api</artifactId> |  | ||||||
|             <version>${project.version}</version> |  | ||||||
|             <scope>compile</scope> |  | ||||||
|         </dependency> |  | ||||||
|     </dependencies> |  | ||||||
|  |  | ||||||
|     <build> |  | ||||||
|         <finalName>${project.name}</finalName> |  | ||||||
|         <resources> |  | ||||||
|             <resource> |  | ||||||
|                 <filtering>true</filtering> |  | ||||||
|                 <directory>${basedir}/src/main/resources</directory> |  | ||||||
|             </resource> |  | ||||||
|         </resources> |  | ||||||
|     </build> |  | ||||||
| </project> |  | ||||||
| @@ -1,31 +0,0 @@ | |||||||
| <?xml version="1.0" encoding="UTF-8"?> |  | ||||||
| <project-shared-configuration> |  | ||||||
|     <!-- |  | ||||||
|     This file contains additional configuration written by modules in the NetBeans IDE. |  | ||||||
|     The configuration is intended to be shared among all the users of project and |  | ||||||
|     therefore it is assumed to be part of version control checkout. |  | ||||||
|     Without this configuration present, some functionality in the IDE may be limited or fail altogether. |  | ||||||
|     --> |  | ||||||
|     <properties xmlns="http://www.netbeans.org/ns/maven-properties-data/1"> |  | ||||||
|         <!-- |  | ||||||
|         Properties that influence various parts of the IDE, especially code formatting and the like.  |  | ||||||
|         You can copy and paste the single properties, into the pom.xml file and the IDE will pick them up. |  | ||||||
|         That way multiple projects can share the same settings (useful for formatting rules for example). |  | ||||||
|         Any value defined here will override the pom.xml file value but is only applicable to the current project. |  | ||||||
|         --> |  | ||||||
|         <org-netbeans-modules-editor-indent.CodeStyle.usedProfile>project</org-netbeans-modules-editor-indent.CodeStyle.usedProfile> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens> |  | ||||||
|         <org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens> |  | ||||||
|     </properties> |  | ||||||
| </project-shared-configuration> |  | ||||||
| @@ -1,20 +0,0 @@ | |||||||
|  |  | ||||||
| <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |  | ||||||
|          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |  | ||||||
|     <modelVersion>4.0.0</modelVersion> |  | ||||||
|  |  | ||||||
|     <parent> |  | ||||||
|         <groupId>net.md-5</groupId> |  | ||||||
|         <artifactId>bungeecord-module</artifactId> |  | ||||||
|         <version>1.20-R0.2-SNAPSHOT</version> |  | ||||||
|         <relativePath>../pom.xml</relativePath> |  | ||||||
|     </parent> |  | ||||||
|  |  | ||||||
|     <groupId>net.md-5</groupId> |  | ||||||
|     <artifactId>bungeecord-module-reconnect-yaml</artifactId> |  | ||||||
|     <version>1.20-R0.2-SNAPSHOT</version> |  | ||||||
|     <packaging>jar</packaging> |  | ||||||
|  |  | ||||||
|     <name>reconnect_yaml</name> |  | ||||||
|     <description>Provides reconnect location functionality in locations.yml</description> |  | ||||||
| </project> |  | ||||||
| @@ -1,22 +0,0 @@ | |||||||
| package net.md_5.bungee.module.reconnect.yaml; |  | ||||||
|  |  | ||||||
| import net.md_5.bungee.api.config.ListenerInfo; |  | ||||||
| import net.md_5.bungee.api.plugin.Plugin; |  | ||||||
|  |  | ||||||
| public class PluginYaml extends Plugin |  | ||||||
| { |  | ||||||
|  |  | ||||||
|     @Override |  | ||||||
|     public void onEnable() |  | ||||||
|     { |  | ||||||
|         // TODO: Abstract this for other reconnect modules |  | ||||||
|         for ( ListenerInfo info : getProxy().getConfig().getListeners() ) |  | ||||||
|         { |  | ||||||
|             if ( !info.isForceDefault() && getProxy().getReconnectHandler() == null ) |  | ||||||
|             { |  | ||||||
|                 getProxy().setReconnectHandler( new YamlReconnectHandler() ); |  | ||||||
|                 break; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,115 +0,0 @@ | |||||||
| package net.md_5.bungee.module.reconnect.yaml; |  | ||||||
|  |  | ||||||
| import java.io.File; |  | ||||||
| import java.io.FileReader; |  | ||||||
| import java.io.FileWriter; |  | ||||||
| import java.io.IOException; |  | ||||||
| import java.net.InetSocketAddress; |  | ||||||
| import java.util.HashMap; |  | ||||||
| import java.util.Map; |  | ||||||
| import java.util.concurrent.locks.ReadWriteLock; |  | ||||||
| import java.util.concurrent.locks.ReentrantReadWriteLock; |  | ||||||
| import java.util.logging.Level; |  | ||||||
| import net.md_5.bungee.api.AbstractReconnectHandler; |  | ||||||
| import net.md_5.bungee.api.ProxyServer; |  | ||||||
| import net.md_5.bungee.api.config.ServerInfo; |  | ||||||
| import net.md_5.bungee.api.connection.ProxiedPlayer; |  | ||||||
| import net.md_5.bungee.util.CaseInsensitiveMap; |  | ||||||
| import org.yaml.snakeyaml.Yaml; |  | ||||||
|  |  | ||||||
| public class YamlReconnectHandler extends AbstractReconnectHandler |  | ||||||
| { |  | ||||||
|  |  | ||||||
|     private final Yaml yaml = new Yaml(); |  | ||||||
|     private final File file = new File( "locations.yml" ); |  | ||||||
|     private final ReadWriteLock lock = new ReentrantReadWriteLock(); |  | ||||||
|     /*========================================================================*/ |  | ||||||
|     private CaseInsensitiveMap<String> data; |  | ||||||
|  |  | ||||||
|     @SuppressWarnings("unchecked") |  | ||||||
|     public YamlReconnectHandler() |  | ||||||
|     { |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             file.createNewFile(); |  | ||||||
|             try ( FileReader rd = new FileReader( file ) ) |  | ||||||
|             { |  | ||||||
|                 Map map = yaml.loadAs( rd, Map.class ); |  | ||||||
|                 if ( map != null ) |  | ||||||
|                 { |  | ||||||
|                     data = new CaseInsensitiveMap<>( map ); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } catch ( Exception ex ) |  | ||||||
|         { |  | ||||||
|             file.renameTo( new File( "locations.yml.old" ) ); |  | ||||||
|             ProxyServer.getInstance().getLogger().log( Level.WARNING, "Could not load reconnect locations, resetting them" ); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if ( data == null ) |  | ||||||
|         { |  | ||||||
|             data = new CaseInsensitiveMap<>(); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @Override |  | ||||||
|     protected ServerInfo getStoredServer(ProxiedPlayer player) |  | ||||||
|     { |  | ||||||
|         ServerInfo server = null; |  | ||||||
|         lock.readLock().lock(); |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             server = ProxyServer.getInstance().getServerInfo( data.get( key( player ) ) ); |  | ||||||
|         } finally |  | ||||||
|         { |  | ||||||
|             lock.readLock().unlock(); |  | ||||||
|         } |  | ||||||
|         return server; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @Override |  | ||||||
|     public void setServer(ProxiedPlayer player) |  | ||||||
|     { |  | ||||||
|         lock.writeLock().lock(); |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             data.put( key( player ), ( player.getReconnectServer() != null ) ? player.getReconnectServer().getName() : player.getServer().getInfo().getName() ); |  | ||||||
|         } finally |  | ||||||
|         { |  | ||||||
|             lock.writeLock().unlock(); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private String key(ProxiedPlayer player) |  | ||||||
|     { |  | ||||||
|         InetSocketAddress host = player.getPendingConnection().getVirtualHost(); |  | ||||||
|         return player.getName() + ";" + host.getHostString() + ":" + host.getPort(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @Override |  | ||||||
|     public void save() |  | ||||||
|     { |  | ||||||
|         Map<String, String> copy = new HashMap<>(); |  | ||||||
|         lock.readLock().lock(); |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             copy.putAll( data ); |  | ||||||
|         } finally |  | ||||||
|         { |  | ||||||
|             lock.readLock().unlock(); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         try ( FileWriter wr = new FileWriter( file ) ) |  | ||||||
|         { |  | ||||||
|             yaml.dump( copy, wr ); |  | ||||||
|         } catch ( IOException ex ) |  | ||||||
|         { |  | ||||||
|             ProxyServer.getInstance().getLogger().log( Level.WARNING, "Could not save reconnect locations", ex ); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @Override |  | ||||||
|     public void close() |  | ||||||
|     { |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,5 +0,0 @@ | |||||||
| name: ${project.name} |  | ||||||
| main: net.md_5.bungee.module.reconnect.yaml.PluginYaml |  | ||||||
| version: ${describe} |  | ||||||
| description: ${project.description} |  | ||||||
| author: ${module.author} |  | ||||||
| @@ -4,15 +4,14 @@ | |||||||
|     <modelVersion>4.0.0</modelVersion> |     <modelVersion>4.0.0</modelVersion> | ||||||
|  |  | ||||||
|     <parent> |     <parent> | ||||||
|         <groupId>net.md-5</groupId> |         <groupId>fr.pandacube.bungeecord</groupId> | ||||||
|         <artifactId>bungeecord-parent</artifactId> |         <artifactId>bungeecord-parent</artifactId> | ||||||
|         <version>1.20-R0.2-SNAPSHOT</version> |         <version>1.20-R0.3-SNAPSHOT</version> | ||||||
|         <relativePath>../pom.xml</relativePath> |         <relativePath>../pom.xml</relativePath> | ||||||
|     </parent> |     </parent> | ||||||
|  |  | ||||||
|     <groupId>net.md-5</groupId> |  | ||||||
|     <artifactId>bungeecord-native</artifactId> |     <artifactId>bungeecord-native</artifactId> | ||||||
|     <version>1.20-R0.2-SNAPSHOT</version> |     <version>1.20-R0.3-SNAPSHOT</version> | ||||||
|     <packaging>jar</packaging> |     <packaging>jar</packaging> | ||||||
|  |  | ||||||
|     <name>BungeeCord-Native</name> |     <name>BungeeCord-Native</name> | ||||||
|   | |||||||
							
								
								
									
										21
									
								
								pom.xml
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								pom.xml
									
									
									
									
									
								
							| @@ -3,9 +3,9 @@ | |||||||
|          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> |     <modelVersion>4.0.0</modelVersion> | ||||||
|  |  | ||||||
|     <groupId>net.md-5</groupId> |     <groupId>fr.pandacube.bungeecord</groupId> | ||||||
|     <artifactId>bungeecord-parent</artifactId> |     <artifactId>bungeecord-parent</artifactId> | ||||||
|     <version>1.20-R0.2-SNAPSHOT</version> |     <version>1.20-R0.3-SNAPSHOT</version> | ||||||
|     <packaging>pom</packaging> |     <packaging>pom</packaging> | ||||||
|  |  | ||||||
|     <name>BungeeCord-Parent</name> |     <name>BungeeCord-Parent</name> | ||||||
| @@ -37,7 +37,6 @@ | |||||||
|         <module>config</module> |         <module>config</module> | ||||||
|         <module>event</module> |         <module>event</module> | ||||||
|         <module>log</module> |         <module>log</module> | ||||||
|         <module>module</module> |  | ||||||
|         <module>protocol</module> |         <module>protocol</module> | ||||||
|         <module>proxy</module> |         <module>proxy</module> | ||||||
|         <module>query</module> |         <module>query</module> | ||||||
| @@ -83,7 +82,7 @@ | |||||||
|             <dependency> |             <dependency> | ||||||
|                 <groupId>io.netty</groupId> |                 <groupId>io.netty</groupId> | ||||||
|                 <artifactId>netty-bom</artifactId> |                 <artifactId>netty-bom</artifactId> | ||||||
|                 <version>4.1.100.Final</version> |                 <version>4.1.107.Final</version> | ||||||
|                 <type>pom</type> |                 <type>pom</type> | ||||||
|                 <scope>import</scope> |                 <scope>import</scope> | ||||||
|             </dependency> |             </dependency> | ||||||
| @@ -93,7 +92,7 @@ | |||||||
|         <dependency> |         <dependency> | ||||||
|             <groupId>org.junit.jupiter</groupId> |             <groupId>org.junit.jupiter</groupId> | ||||||
|             <artifactId>junit-jupiter</artifactId> |             <artifactId>junit-jupiter</artifactId> | ||||||
|             <version>5.10.1</version> |             <version>5.10.2</version> | ||||||
|             <scope>test</scope> |             <scope>test</scope> | ||||||
|         </dependency> |         </dependency> | ||||||
|         <dependency> |         <dependency> | ||||||
| @@ -108,6 +107,12 @@ | |||||||
|             <version>3.0.1</version> |             <version>3.0.1</version> | ||||||
|             <scope>provided</scope> |             <scope>provided</scope> | ||||||
|         </dependency> |         </dependency> | ||||||
|  |         <dependency> | ||||||
|  |             <groupId>org.jetbrains</groupId> | ||||||
|  |             <artifactId>annotations-java5</artifactId> | ||||||
|  |             <version>24.1.0</version> | ||||||
|  |             <scope>provided</scope> | ||||||
|  |         </dependency> | ||||||
|         <dependency> |         <dependency> | ||||||
|             <groupId>org.projectlombok</groupId> |             <groupId>org.projectlombok</groupId> | ||||||
|             <artifactId>lombok</artifactId> |             <artifactId>lombok</artifactId> | ||||||
| @@ -122,7 +127,7 @@ | |||||||
|                 <plugin> |                 <plugin> | ||||||
|                     <groupId>org.apache.maven.plugins</groupId> |                     <groupId>org.apache.maven.plugins</groupId> | ||||||
|                     <artifactId>maven-javadoc-plugin</artifactId> |                     <artifactId>maven-javadoc-plugin</artifactId> | ||||||
|                     <version>3.6.2</version> |                     <version>3.6.3</version> | ||||||
|                 </plugin> |                 </plugin> | ||||||
|             </plugins> |             </plugins> | ||||||
|         </pluginManagement> |         </pluginManagement> | ||||||
| @@ -132,7 +137,7 @@ | |||||||
|                 <artifactId>scriptus</artifactId> |                 <artifactId>scriptus</artifactId> | ||||||
|                 <version>0.5.0</version> |                 <version>0.5.0</version> | ||||||
|                 <configuration> |                 <configuration> | ||||||
|                     <format>git:${project.name}:${project.version}:%s:${build.number}</format> |                     <format>git:${project.name}-Pandacube:${project.version}:%s:${build.number}</format> | ||||||
|                 </configuration> |                 </configuration> | ||||||
|                 <executions> |                 <executions> | ||||||
|                     <execution> |                     <execution> | ||||||
| @@ -146,7 +151,7 @@ | |||||||
|             <plugin> |             <plugin> | ||||||
|                 <groupId>org.apache.maven.plugins</groupId> |                 <groupId>org.apache.maven.plugins</groupId> | ||||||
|                 <artifactId>maven-compiler-plugin</artifactId> |                 <artifactId>maven-compiler-plugin</artifactId> | ||||||
|                 <version>3.11.0</version> |                 <version>3.12.1</version> | ||||||
|             </plugin> |             </plugin> | ||||||
|             <plugin> |             <plugin> | ||||||
|                 <groupId>org.apache.maven.plugins</groupId> |                 <groupId>org.apache.maven.plugins</groupId> | ||||||
|   | |||||||
| @@ -4,15 +4,14 @@ | |||||||
|     <modelVersion>4.0.0</modelVersion> |     <modelVersion>4.0.0</modelVersion> | ||||||
|  |  | ||||||
|     <parent> |     <parent> | ||||||
|         <groupId>net.md-5</groupId> |         <groupId>fr.pandacube.bungeecord</groupId> | ||||||
|         <artifactId>bungeecord-parent</artifactId> |         <artifactId>bungeecord-parent</artifactId> | ||||||
|         <version>1.20-R0.2-SNAPSHOT</version> |         <version>1.20-R0.3-SNAPSHOT</version> | ||||||
|         <relativePath>../pom.xml</relativePath> |         <relativePath>../pom.xml</relativePath> | ||||||
|     </parent> |     </parent> | ||||||
|  |  | ||||||
|     <groupId>net.md-5</groupId> |  | ||||||
|     <artifactId>bungeecord-protocol</artifactId> |     <artifactId>bungeecord-protocol</artifactId> | ||||||
|     <version>1.20-R0.2-SNAPSHOT</version> |     <version>1.20-R0.3-SNAPSHOT</version> | ||||||
|     <packaging>jar</packaging> |     <packaging>jar</packaging> | ||||||
|  |  | ||||||
|     <name>BungeeCord-Protocol</name> |     <name>BungeeCord-Protocol</name> | ||||||
| @@ -35,7 +34,7 @@ | |||||||
|             <scope>compile</scope> |             <scope>compile</scope> | ||||||
|         </dependency> |         </dependency> | ||||||
|         <dependency> |         <dependency> | ||||||
|             <groupId>net.md-5</groupId> |             <groupId>fr.pandacube.bungeecord</groupId> | ||||||
|             <artifactId>bungeecord-chat</artifactId> |             <artifactId>bungeecord-chat</artifactId> | ||||||
|             <version>${project.version}</version> |             <version>${project.version}</version> | ||||||
|             <scope>compile</scope> |             <scope>compile</scope> | ||||||
|   | |||||||
| @@ -8,6 +8,8 @@ import net.md_5.bungee.protocol.packet.ClientCommand; | |||||||
| import net.md_5.bungee.protocol.packet.ClientSettings; | import net.md_5.bungee.protocol.packet.ClientSettings; | ||||||
| import net.md_5.bungee.protocol.packet.ClientStatus; | import net.md_5.bungee.protocol.packet.ClientStatus; | ||||||
| import net.md_5.bungee.protocol.packet.Commands; | import net.md_5.bungee.protocol.packet.Commands; | ||||||
|  | import net.md_5.bungee.protocol.packet.CookieRequest; | ||||||
|  | import net.md_5.bungee.protocol.packet.CookieResponse; | ||||||
| import net.md_5.bungee.protocol.packet.EncryptionRequest; | import net.md_5.bungee.protocol.packet.EncryptionRequest; | ||||||
| import net.md_5.bungee.protocol.packet.EncryptionResponse; | import net.md_5.bungee.protocol.packet.EncryptionResponse; | ||||||
| import net.md_5.bungee.protocol.packet.EntityStatus; | import net.md_5.bungee.protocol.packet.EntityStatus; | ||||||
| @@ -40,6 +42,7 @@ import net.md_5.bungee.protocol.packet.SetCompression; | |||||||
| import net.md_5.bungee.protocol.packet.StartConfiguration; | import net.md_5.bungee.protocol.packet.StartConfiguration; | ||||||
| import net.md_5.bungee.protocol.packet.StatusRequest; | import net.md_5.bungee.protocol.packet.StatusRequest; | ||||||
| import net.md_5.bungee.protocol.packet.StatusResponse; | import net.md_5.bungee.protocol.packet.StatusResponse; | ||||||
|  | import net.md_5.bungee.protocol.packet.StoreCookie; | ||||||
| import net.md_5.bungee.protocol.packet.Subtitle; | import net.md_5.bungee.protocol.packet.Subtitle; | ||||||
| import net.md_5.bungee.protocol.packet.SystemChat; | import net.md_5.bungee.protocol.packet.SystemChat; | ||||||
| import net.md_5.bungee.protocol.packet.TabCompleteRequest; | import net.md_5.bungee.protocol.packet.TabCompleteRequest; | ||||||
| @@ -47,6 +50,7 @@ import net.md_5.bungee.protocol.packet.TabCompleteResponse; | |||||||
| import net.md_5.bungee.protocol.packet.Team; | import net.md_5.bungee.protocol.packet.Team; | ||||||
| import net.md_5.bungee.protocol.packet.Title; | import net.md_5.bungee.protocol.packet.Title; | ||||||
| import net.md_5.bungee.protocol.packet.TitleTimes; | import net.md_5.bungee.protocol.packet.TitleTimes; | ||||||
|  | import net.md_5.bungee.protocol.packet.Transfer; | ||||||
| import net.md_5.bungee.protocol.packet.ViewDistance; | import net.md_5.bungee.protocol.packet.ViewDistance; | ||||||
|  |  | ||||||
| public abstract class AbstractPacketHandler | public abstract class AbstractPacketHandler | ||||||
| @@ -243,4 +247,20 @@ public abstract class AbstractPacketHandler | |||||||
|     public void handle(FinishConfiguration finishConfiguration) throws Exception |     public void handle(FinishConfiguration finishConfiguration) throws Exception | ||||||
|     { |     { | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     public void handle(Transfer transfer) throws Exception | ||||||
|  |     { | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public void handle(StoreCookie storeCookie) throws Exception | ||||||
|  |     { | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public void handle(CookieRequest cookieRequest) throws Exception | ||||||
|  |     { | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public void handle(CookieResponse cookieResponse) throws Exception | ||||||
|  |     { | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -19,6 +19,7 @@ import java.util.UUID; | |||||||
| import java.util.function.BiConsumer; | import java.util.function.BiConsumer; | ||||||
| import lombok.RequiredArgsConstructor; | import lombok.RequiredArgsConstructor; | ||||||
| import net.md_5.bungee.api.chat.BaseComponent; | import net.md_5.bungee.api.chat.BaseComponent; | ||||||
|  | import net.md_5.bungee.api.chat.ComponentStyle; | ||||||
| import net.md_5.bungee.chat.ComponentSerializer; | import net.md_5.bungee.chat.ComponentSerializer; | ||||||
| import se.llbit.nbt.ErrorTag; | import se.llbit.nbt.ErrorTag; | ||||||
| import se.llbit.nbt.NamedTag; | import se.llbit.nbt.NamedTag; | ||||||
| @@ -118,6 +119,14 @@ public abstract class DefinedPacket | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     public static ComponentStyle readComponentStyle(ByteBuf buf, int protocolVersion) | ||||||
|  |     { | ||||||
|  |         SpecificTag nbt = (SpecificTag) readTag( buf, protocolVersion ); | ||||||
|  |         JsonElement json = TagUtil.toJson( nbt ); | ||||||
|  |  | ||||||
|  |         return ComponentSerializer.deserializeStyle( json ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     public static void writeEitherBaseComponent(Either<String, BaseComponent> message, ByteBuf buf, int protocolVersion) |     public static void writeEitherBaseComponent(Either<String, BaseComponent> message, ByteBuf buf, int protocolVersion) | ||||||
|     { |     { | ||||||
|         if ( message.isLeft() ) |         if ( message.isLeft() ) | ||||||
| @@ -145,6 +154,14 @@ public abstract class DefinedPacket | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     public static void writeComponentStyle(ComponentStyle style, ByteBuf buf, int protocolVersion) | ||||||
|  |     { | ||||||
|  |         JsonElement json = ComponentSerializer.toJson( style ); | ||||||
|  |         SpecificTag nbt = TagUtil.fromJson( json ); | ||||||
|  |  | ||||||
|  |         writeTag( nbt, buf, protocolVersion ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     public static void writeArray(byte[] b, ByteBuf buf) |     public static void writeArray(byte[] b, ByteBuf buf) | ||||||
|     { |     { | ||||||
|         if ( b.length > Short.MAX_VALUE ) |         if ( b.length > Short.MAX_VALUE ) | ||||||
| @@ -231,7 +248,7 @@ public abstract class DefinedPacket | |||||||
|  |  | ||||||
|             if ( bytes > maxBytes ) |             if ( bytes > maxBytes ) | ||||||
|             { |             { | ||||||
|                 throw new RuntimeException( "VarInt too big" ); |                 throw new OverflowPacketException( "VarInt too big (max " + maxBytes + ")" ); | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             if ( ( in & 0x80 ) != 0x80 ) |             if ( ( in & 0x80 ) != 0x80 ) | ||||||
| @@ -378,7 +395,7 @@ public abstract class DefinedPacket | |||||||
|             case BLANK: |             case BLANK: | ||||||
|                 break; |                 break; | ||||||
|             case STYLED: |             case STYLED: | ||||||
|                 writeBaseComponent( (BaseComponent) format.getValue(), buf, protocolVersion ); // TODO: style |                 writeComponentStyle( (ComponentStyle) format.getValue(), buf, protocolVersion ); | ||||||
|                 break; |                 break; | ||||||
|             case FIXED: |             case FIXED: | ||||||
|                 writeBaseComponent( (BaseComponent) format.getValue(), buf, protocolVersion ); |                 writeBaseComponent( (BaseComponent) format.getValue(), buf, protocolVersion ); | ||||||
| @@ -394,7 +411,7 @@ public abstract class DefinedPacket | |||||||
|             case 0: |             case 0: | ||||||
|                 return new NumberFormat( NumberFormat.Type.BLANK, null ); |                 return new NumberFormat( NumberFormat.Type.BLANK, null ); | ||||||
|             case 1: |             case 1: | ||||||
|                 return new NumberFormat( NumberFormat.Type.STYLED, readBaseComponent( buf, protocolVersion ) ); // TODO: style |                 return new NumberFormat( NumberFormat.Type.STYLED, readComponentStyle( buf, protocolVersion ) ); | ||||||
|             case 2: |             case 2: | ||||||
|                 return new NumberFormat( NumberFormat.Type.FIXED, readBaseComponent( buf, protocolVersion ) ); |                 return new NumberFormat( NumberFormat.Type.FIXED, readBaseComponent( buf, protocolVersion ) ); | ||||||
|             default: |             default: | ||||||
|   | |||||||
| @@ -16,6 +16,8 @@ import net.md_5.bungee.protocol.packet.ClientChat; | |||||||
| import net.md_5.bungee.protocol.packet.ClientCommand; | import net.md_5.bungee.protocol.packet.ClientCommand; | ||||||
| import net.md_5.bungee.protocol.packet.ClientSettings; | import net.md_5.bungee.protocol.packet.ClientSettings; | ||||||
| import net.md_5.bungee.protocol.packet.Commands; | import net.md_5.bungee.protocol.packet.Commands; | ||||||
|  | import net.md_5.bungee.protocol.packet.CookieRequest; | ||||||
|  | import net.md_5.bungee.protocol.packet.CookieResponse; | ||||||
| import net.md_5.bungee.protocol.packet.EncryptionRequest; | import net.md_5.bungee.protocol.packet.EncryptionRequest; | ||||||
| import net.md_5.bungee.protocol.packet.EncryptionResponse; | import net.md_5.bungee.protocol.packet.EncryptionResponse; | ||||||
| import net.md_5.bungee.protocol.packet.EntityStatus; | import net.md_5.bungee.protocol.packet.EntityStatus; | ||||||
| @@ -46,6 +48,7 @@ import net.md_5.bungee.protocol.packet.SetCompression; | |||||||
| import net.md_5.bungee.protocol.packet.StartConfiguration; | import net.md_5.bungee.protocol.packet.StartConfiguration; | ||||||
| import net.md_5.bungee.protocol.packet.StatusRequest; | import net.md_5.bungee.protocol.packet.StatusRequest; | ||||||
| import net.md_5.bungee.protocol.packet.StatusResponse; | import net.md_5.bungee.protocol.packet.StatusResponse; | ||||||
|  | import net.md_5.bungee.protocol.packet.StoreCookie; | ||||||
| import net.md_5.bungee.protocol.packet.Subtitle; | import net.md_5.bungee.protocol.packet.Subtitle; | ||||||
| import net.md_5.bungee.protocol.packet.SystemChat; | import net.md_5.bungee.protocol.packet.SystemChat; | ||||||
| import net.md_5.bungee.protocol.packet.TabCompleteRequest; | import net.md_5.bungee.protocol.packet.TabCompleteRequest; | ||||||
| @@ -53,6 +56,7 @@ import net.md_5.bungee.protocol.packet.TabCompleteResponse; | |||||||
| import net.md_5.bungee.protocol.packet.Team; | import net.md_5.bungee.protocol.packet.Team; | ||||||
| import net.md_5.bungee.protocol.packet.Title; | import net.md_5.bungee.protocol.packet.Title; | ||||||
| import net.md_5.bungee.protocol.packet.TitleTimes; | import net.md_5.bungee.protocol.packet.TitleTimes; | ||||||
|  | import net.md_5.bungee.protocol.packet.Transfer; | ||||||
| import net.md_5.bungee.protocol.packet.ViewDistance; | import net.md_5.bungee.protocol.packet.ViewDistance; | ||||||
|  |  | ||||||
| public enum Protocol | public enum Protocol | ||||||
| @@ -90,7 +94,8 @@ public enum Protocol | |||||||
|                     map( ProtocolConstants.MINECRAFT_1_19_1, 0x20 ), |                     map( ProtocolConstants.MINECRAFT_1_19_1, 0x20 ), | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_19_3, 0x1F ), |                     map( ProtocolConstants.MINECRAFT_1_19_3, 0x1F ), | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_19_4, 0x23 ), |                     map( ProtocolConstants.MINECRAFT_1_19_4, 0x23 ), | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_20_2, 0x24 ) |                     map( ProtocolConstants.MINECRAFT_1_20_2, 0x24 ), | ||||||
|  |                     map( ProtocolConstants.MINECRAFT_1_20_5, 0x26 ) | ||||||
|             ); |             ); | ||||||
|             TO_CLIENT.registerPacket( |             TO_CLIENT.registerPacket( | ||||||
|                     Login.class, |                     Login.class, | ||||||
| @@ -106,7 +111,8 @@ public enum Protocol | |||||||
|                     map( ProtocolConstants.MINECRAFT_1_19_1, 0x25 ), |                     map( ProtocolConstants.MINECRAFT_1_19_1, 0x25 ), | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_19_3, 0x24 ), |                     map( ProtocolConstants.MINECRAFT_1_19_3, 0x24 ), | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_19_4, 0x28 ), |                     map( ProtocolConstants.MINECRAFT_1_19_4, 0x28 ), | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_20_2, 0x29 ) |                     map( ProtocolConstants.MINECRAFT_1_20_2, 0x29 ), | ||||||
|  |                     map( ProtocolConstants.MINECRAFT_1_20_5, 0x2B ) | ||||||
|             ); |             ); | ||||||
|             TO_CLIENT.registerPacket( Chat.class, |             TO_CLIENT.registerPacket( Chat.class, | ||||||
|                     Chat::new, |                     Chat::new, | ||||||
| @@ -136,7 +142,8 @@ public enum Protocol | |||||||
|                     map( ProtocolConstants.MINECRAFT_1_19_3, 0x3D ), |                     map( ProtocolConstants.MINECRAFT_1_19_3, 0x3D ), | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_19_4, 0x41 ), |                     map( ProtocolConstants.MINECRAFT_1_19_4, 0x41 ), | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_20_2, 0x43 ), |                     map( ProtocolConstants.MINECRAFT_1_20_2, 0x43 ), | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_20_3, 0x45 ) |                     map( ProtocolConstants.MINECRAFT_1_20_3, 0x45 ), | ||||||
|  |                     map( ProtocolConstants.MINECRAFT_1_20_5, 0x47 ) | ||||||
|             ); |             ); | ||||||
|             TO_CLIENT.registerPacket( |             TO_CLIENT.registerPacket( | ||||||
|                     BossBar.class, |                     BossBar.class, | ||||||
| @@ -195,7 +202,8 @@ public enum Protocol | |||||||
|                     map( ProtocolConstants.MINECRAFT_1_19_3, 0x54 ), |                     map( ProtocolConstants.MINECRAFT_1_19_3, 0x54 ), | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_19_4, 0x58 ), |                     map( ProtocolConstants.MINECRAFT_1_19_4, 0x58 ), | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_20_2, 0x5A ), |                     map( ProtocolConstants.MINECRAFT_1_20_2, 0x5A ), | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_20_3, 0x5C ) |                     map( ProtocolConstants.MINECRAFT_1_20_3, 0x5C ), | ||||||
|  |                     map( ProtocolConstants.MINECRAFT_1_20_5, 0x5E ) | ||||||
|             ); |             ); | ||||||
|             TO_CLIENT.registerPacket( |             TO_CLIENT.registerPacket( | ||||||
|                     ScoreboardScore.class, |                     ScoreboardScore.class, | ||||||
| @@ -212,12 +220,14 @@ public enum Protocol | |||||||
|                     map( ProtocolConstants.MINECRAFT_1_19_3, 0x57 ), |                     map( ProtocolConstants.MINECRAFT_1_19_3, 0x57 ), | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_19_4, 0x5B ), |                     map( ProtocolConstants.MINECRAFT_1_19_4, 0x5B ), | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_20_2, 0x5D ), |                     map( ProtocolConstants.MINECRAFT_1_20_2, 0x5D ), | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_20_3, 0x5F ) |                     map( ProtocolConstants.MINECRAFT_1_20_3, 0x5F ), | ||||||
|  |                     map( ProtocolConstants.MINECRAFT_1_20_5, 0x61 ) | ||||||
|             ); |             ); | ||||||
|             TO_CLIENT.registerPacket( |             TO_CLIENT.registerPacket( | ||||||
|                     ScoreboardScoreReset.class, |                     ScoreboardScoreReset.class, | ||||||
|                     ScoreboardScoreReset::new, |                     ScoreboardScoreReset::new, | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_20_3, 0x42 ) |                     map( ProtocolConstants.MINECRAFT_1_20_3, 0x42 ), | ||||||
|  |                     map( ProtocolConstants.MINECRAFT_1_20_5, 0x44 ) | ||||||
|             ); |             ); | ||||||
|             TO_CLIENT.registerPacket( |             TO_CLIENT.registerPacket( | ||||||
|                     ScoreboardDisplay.class, |                     ScoreboardDisplay.class, | ||||||
| @@ -234,7 +244,8 @@ public enum Protocol | |||||||
|                     map( ProtocolConstants.MINECRAFT_1_19_3, 0x4D ), |                     map( ProtocolConstants.MINECRAFT_1_19_3, 0x4D ), | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_19_4, 0x51 ), |                     map( ProtocolConstants.MINECRAFT_1_19_4, 0x51 ), | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_20_2, 0x53 ), |                     map( ProtocolConstants.MINECRAFT_1_20_2, 0x53 ), | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_20_3, 0x55 ) |                     map( ProtocolConstants.MINECRAFT_1_20_3, 0x55 ), | ||||||
|  |                     map( ProtocolConstants.MINECRAFT_1_20_5, 0x57 ) | ||||||
|             ); |             ); | ||||||
|             TO_CLIENT.registerPacket( |             TO_CLIENT.registerPacket( | ||||||
|                     Team.class, |                     Team.class, | ||||||
| @@ -251,7 +262,8 @@ public enum Protocol | |||||||
|                     map( ProtocolConstants.MINECRAFT_1_19_3, 0x56 ), |                     map( ProtocolConstants.MINECRAFT_1_19_3, 0x56 ), | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_19_4, 0x5A ), |                     map( ProtocolConstants.MINECRAFT_1_19_4, 0x5A ), | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_20_2, 0x5C ), |                     map( ProtocolConstants.MINECRAFT_1_20_2, 0x5C ), | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_20_3, 0x5E ) |                     map( ProtocolConstants.MINECRAFT_1_20_3, 0x5E ), | ||||||
|  |                     map( ProtocolConstants.MINECRAFT_1_20_5, 0x60 ) | ||||||
|             ); |             ); | ||||||
|             TO_CLIENT.registerPacket( |             TO_CLIENT.registerPacket( | ||||||
|                     PluginMessage.class, |                     PluginMessage.class, | ||||||
| @@ -268,7 +280,8 @@ public enum Protocol | |||||||
|                     map( ProtocolConstants.MINECRAFT_1_19_1, 0x16 ), |                     map( ProtocolConstants.MINECRAFT_1_19_1, 0x16 ), | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_19_3, 0x15 ), |                     map( ProtocolConstants.MINECRAFT_1_19_3, 0x15 ), | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_19_4, 0x17 ), |                     map( ProtocolConstants.MINECRAFT_1_19_4, 0x17 ), | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_20_2, 0x18 ) |                     map( ProtocolConstants.MINECRAFT_1_20_2, 0x18 ), | ||||||
|  |                     map( ProtocolConstants.MINECRAFT_1_20_5, 0x19 ) | ||||||
|             ); |             ); | ||||||
|             TO_CLIENT.registerPacket( |             TO_CLIENT.registerPacket( | ||||||
|                     Kick.class, |                     Kick.class, | ||||||
| @@ -285,7 +298,8 @@ public enum Protocol | |||||||
|                     map( ProtocolConstants.MINECRAFT_1_19_1, 0x19 ), |                     map( ProtocolConstants.MINECRAFT_1_19_1, 0x19 ), | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_19_3, 0x17 ), |                     map( ProtocolConstants.MINECRAFT_1_19_3, 0x17 ), | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_19_4, 0x1A ), |                     map( ProtocolConstants.MINECRAFT_1_19_4, 0x1A ), | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_20_2, 0x1B ) |                     map( ProtocolConstants.MINECRAFT_1_20_2, 0x1B ), | ||||||
|  |                     map( ProtocolConstants.MINECRAFT_1_20_5, 0x1D ) | ||||||
|             ); |             ); | ||||||
|             TO_CLIENT.registerPacket( |             TO_CLIENT.registerPacket( | ||||||
|                     Title.class, |                     Title.class, | ||||||
| @@ -303,7 +317,8 @@ public enum Protocol | |||||||
|                     map( ProtocolConstants.MINECRAFT_1_19_3, 0x5B ), |                     map( ProtocolConstants.MINECRAFT_1_19_3, 0x5B ), | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_19_4, 0x5F ), |                     map( ProtocolConstants.MINECRAFT_1_19_4, 0x5F ), | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_20_2, 0x61 ), |                     map( ProtocolConstants.MINECRAFT_1_20_2, 0x61 ), | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_20_3, 0x63 ) |                     map( ProtocolConstants.MINECRAFT_1_20_3, 0x63 ), | ||||||
|  |                     map( ProtocolConstants.MINECRAFT_1_20_5, 0x65 ) | ||||||
|             ); |             ); | ||||||
|             TO_CLIENT.registerPacket( |             TO_CLIENT.registerPacket( | ||||||
|                     ClearTitles.class, |                     ClearTitles.class, | ||||||
| @@ -323,7 +338,8 @@ public enum Protocol | |||||||
|                     map( ProtocolConstants.MINECRAFT_1_19_3, 0x59 ), |                     map( ProtocolConstants.MINECRAFT_1_19_3, 0x59 ), | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_19_4, 0x5D ), |                     map( ProtocolConstants.MINECRAFT_1_19_4, 0x5D ), | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_20_2, 0x5F ), |                     map( ProtocolConstants.MINECRAFT_1_20_2, 0x5F ), | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_20_3, 0x61 ) |                     map( ProtocolConstants.MINECRAFT_1_20_3, 0x61 ), | ||||||
|  |                     map( ProtocolConstants.MINECRAFT_1_20_5, 0x63 ) | ||||||
|             ); |             ); | ||||||
|             TO_CLIENT.registerPacket( |             TO_CLIENT.registerPacket( | ||||||
|                     TitleTimes.class, |                     TitleTimes.class, | ||||||
| @@ -334,7 +350,8 @@ public enum Protocol | |||||||
|                     map( ProtocolConstants.MINECRAFT_1_19_3, 0x5C ), |                     map( ProtocolConstants.MINECRAFT_1_19_3, 0x5C ), | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_19_4, 0x60 ), |                     map( ProtocolConstants.MINECRAFT_1_19_4, 0x60 ), | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_20_2, 0x62 ), |                     map( ProtocolConstants.MINECRAFT_1_20_2, 0x62 ), | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_20_3, 0x64 ) |                     map( ProtocolConstants.MINECRAFT_1_20_3, 0x64 ), | ||||||
|  |                     map( ProtocolConstants.MINECRAFT_1_20_5, 0x66 ) | ||||||
|             ); |             ); | ||||||
|             TO_CLIENT.registerPacket( |             TO_CLIENT.registerPacket( | ||||||
|                     SystemChat.class, |                     SystemChat.class, | ||||||
| @@ -344,7 +361,8 @@ public enum Protocol | |||||||
|                     map( ProtocolConstants.MINECRAFT_1_19_3, 0x60 ), |                     map( ProtocolConstants.MINECRAFT_1_19_3, 0x60 ), | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_19_4, 0x64 ), |                     map( ProtocolConstants.MINECRAFT_1_19_4, 0x64 ), | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_20_2, 0x67 ), |                     map( ProtocolConstants.MINECRAFT_1_20_2, 0x67 ), | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_20_3, 0x69 ) |                     map( ProtocolConstants.MINECRAFT_1_20_3, 0x69 ), | ||||||
|  |                     map( ProtocolConstants.MINECRAFT_1_20_5, 0x6C ) | ||||||
|             ); |             ); | ||||||
|             TO_CLIENT.registerPacket( |             TO_CLIENT.registerPacket( | ||||||
|                     PlayerListHeaderFooter.class, |                     PlayerListHeaderFooter.class, | ||||||
| @@ -365,7 +383,8 @@ public enum Protocol | |||||||
|                     map( ProtocolConstants.MINECRAFT_1_19_3, 0x61 ), |                     map( ProtocolConstants.MINECRAFT_1_19_3, 0x61 ), | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_19_4, 0x65 ), |                     map( ProtocolConstants.MINECRAFT_1_19_4, 0x65 ), | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_20_2, 0x68 ), |                     map( ProtocolConstants.MINECRAFT_1_20_2, 0x68 ), | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_20_3, 0x6A ) |                     map( ProtocolConstants.MINECRAFT_1_20_3, 0x6A ), | ||||||
|  |                     map( ProtocolConstants.MINECRAFT_1_20_5, 0x6D ) | ||||||
|             ); |             ); | ||||||
|             TO_CLIENT.registerPacket( |             TO_CLIENT.registerPacket( | ||||||
|                     EntityStatus.class, |                     EntityStatus.class, | ||||||
| @@ -382,7 +401,8 @@ public enum Protocol | |||||||
|                     map( ProtocolConstants.MINECRAFT_1_19_1, 0x1A ), |                     map( ProtocolConstants.MINECRAFT_1_19_1, 0x1A ), | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_19_3, 0x19 ), |                     map( ProtocolConstants.MINECRAFT_1_19_3, 0x19 ), | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_19_4, 0x1C ), |                     map( ProtocolConstants.MINECRAFT_1_19_4, 0x1C ), | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_20_2, 0x1D ) |                     map( ProtocolConstants.MINECRAFT_1_20_2, 0x1D ), | ||||||
|  |                     map( ProtocolConstants.MINECRAFT_1_20_5, 0x1F ) | ||||||
|             ); |             ); | ||||||
|             TO_CLIENT.registerPacket( |             TO_CLIENT.registerPacket( | ||||||
|                     Commands.class, |                     Commands.class, | ||||||
| @@ -408,7 +428,8 @@ public enum Protocol | |||||||
|                     map( ProtocolConstants.MINECRAFT_1_19_1, 0x1D ), |                     map( ProtocolConstants.MINECRAFT_1_19_1, 0x1D ), | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_19_3, 0x1C ), |                     map( ProtocolConstants.MINECRAFT_1_19_3, 0x1C ), | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_19_4, 0x1F ), |                     map( ProtocolConstants.MINECRAFT_1_19_4, 0x1F ), | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_20_2, 0x20 ) |                     map( ProtocolConstants.MINECRAFT_1_20_2, 0x20 ), | ||||||
|  |                     map( ProtocolConstants.MINECRAFT_1_20_5, 0x22 ) | ||||||
|             ); |             ); | ||||||
|             TO_CLIENT.registerPacket( |             TO_CLIENT.registerPacket( | ||||||
|                     ViewDistance.class, |                     ViewDistance.class, | ||||||
| @@ -422,7 +443,8 @@ public enum Protocol | |||||||
|                     map( ProtocolConstants.MINECRAFT_1_19_3, 0x4B ), |                     map( ProtocolConstants.MINECRAFT_1_19_3, 0x4B ), | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_19_4, 0x4F ), |                     map( ProtocolConstants.MINECRAFT_1_19_4, 0x4F ), | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_20_2, 0x51 ), |                     map( ProtocolConstants.MINECRAFT_1_20_2, 0x51 ), | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_20_3, 0x53 ) |                     map( ProtocolConstants.MINECRAFT_1_20_3, 0x53 ), | ||||||
|  |                     map( ProtocolConstants.MINECRAFT_1_20_5, 0x62 ) | ||||||
|             ); |             ); | ||||||
|             TO_CLIENT.registerPacket( |             TO_CLIENT.registerPacket( | ||||||
|                     ServerData.class, |                     ServerData.class, | ||||||
| @@ -432,27 +454,46 @@ public enum Protocol | |||||||
|                     map( ProtocolConstants.MINECRAFT_1_19_3, 0x41 ), |                     map( ProtocolConstants.MINECRAFT_1_19_3, 0x41 ), | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_19_4, 0x45 ), |                     map( ProtocolConstants.MINECRAFT_1_19_4, 0x45 ), | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_20_2, 0x47 ), |                     map( ProtocolConstants.MINECRAFT_1_20_2, 0x47 ), | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_20_3, 0x49 ) |                     map( ProtocolConstants.MINECRAFT_1_20_3, 0x49 ), | ||||||
|  |                     map( ProtocolConstants.MINECRAFT_1_20_5, 0x4B ) | ||||||
|             ); |             ); | ||||||
|             TO_CLIENT.registerPacket( |             TO_CLIENT.registerPacket( | ||||||
|                     PlayerListItemRemove.class, |                     PlayerListItemRemove.class, | ||||||
|                     PlayerListItemRemove::new, |                     PlayerListItemRemove::new, | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_19_3, 0x35 ), |                     map( ProtocolConstants.MINECRAFT_1_19_3, 0x35 ), | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_19_4, 0x39 ), |                     map( ProtocolConstants.MINECRAFT_1_19_4, 0x39 ), | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_20_2, 0x3B ) |                     map( ProtocolConstants.MINECRAFT_1_20_2, 0x3B ), | ||||||
|  |                     map( ProtocolConstants.MINECRAFT_1_20_5, 0x3D ) | ||||||
|             ); |             ); | ||||||
|             TO_CLIENT.registerPacket( |             TO_CLIENT.registerPacket( | ||||||
|                     PlayerListItemUpdate.class, |                     PlayerListItemUpdate.class, | ||||||
|                     PlayerListItemUpdate::new, |                     PlayerListItemUpdate::new, | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_19_3, 0x36 ), |                     map( ProtocolConstants.MINECRAFT_1_19_3, 0x36 ), | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_19_4, 0x3A ), |                     map( ProtocolConstants.MINECRAFT_1_19_4, 0x3A ), | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_20_2, 0x3C ) |                     map( ProtocolConstants.MINECRAFT_1_20_2, 0x3C ), | ||||||
|  |                     map( ProtocolConstants.MINECRAFT_1_20_5, 0x3E ) | ||||||
|             ); |             ); | ||||||
|             TO_CLIENT.registerPacket( |             TO_CLIENT.registerPacket( | ||||||
|                     StartConfiguration.class, |                     StartConfiguration.class, | ||||||
|                     StartConfiguration::new, |                     StartConfiguration::new, | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_20_2, 0x65 ), |                     map( ProtocolConstants.MINECRAFT_1_20_2, 0x65 ), | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_20_3, 0x67 ) |                     map( ProtocolConstants.MINECRAFT_1_20_3, 0x67 ), | ||||||
|  |                     map( ProtocolConstants.MINECRAFT_1_20_5, 0x69 ) | ||||||
|  |             ); | ||||||
|  |             TO_CLIENT.registerPacket( | ||||||
|  |                     CookieRequest.class, | ||||||
|  |                     CookieRequest::new, | ||||||
|  |                     map( ProtocolConstants.MINECRAFT_1_20_5, 0x16 ) | ||||||
|  |             ); | ||||||
|  |             TO_CLIENT.registerPacket( | ||||||
|  |                     StoreCookie.class, | ||||||
|  |                     StoreCookie::new, | ||||||
|  |                     map( ProtocolConstants.MINECRAFT_1_20_5, 0x6B ) | ||||||
|  |             ); | ||||||
|  |             TO_CLIENT.registerPacket( | ||||||
|  |                     Transfer.class, | ||||||
|  |                     Transfer::new, | ||||||
|  |                     map( ProtocolConstants.MINECRAFT_1_20_5, 0x73 ) | ||||||
|             ); |             ); | ||||||
|  |  | ||||||
|             TO_SERVER.registerPacket( |             TO_SERVER.registerPacket( | ||||||
| @@ -471,7 +512,8 @@ public enum Protocol | |||||||
|                     map( ProtocolConstants.MINECRAFT_1_19_3, 0x11 ), |                     map( ProtocolConstants.MINECRAFT_1_19_3, 0x11 ), | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_19_4, 0x12 ), |                     map( ProtocolConstants.MINECRAFT_1_19_4, 0x12 ), | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_20_2, 0x14 ), |                     map( ProtocolConstants.MINECRAFT_1_20_2, 0x14 ), | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_20_3, 0x15 ) |                     map( ProtocolConstants.MINECRAFT_1_20_3, 0x15 ), | ||||||
|  |                     map( ProtocolConstants.MINECRAFT_1_20_5, 0x17 ) | ||||||
|             ); |             ); | ||||||
|             TO_SERVER.registerPacket( Chat.class, |             TO_SERVER.registerPacket( Chat.class, | ||||||
|                     Chat::new, |                     Chat::new, | ||||||
| @@ -538,13 +580,19 @@ public enum Protocol | |||||||
|                     map( ProtocolConstants.MINECRAFT_1_19_3, 0x0C ), |                     map( ProtocolConstants.MINECRAFT_1_19_3, 0x0C ), | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_19_4, 0x0D ), |                     map( ProtocolConstants.MINECRAFT_1_19_4, 0x0D ), | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_20_2, 0x0F ), |                     map( ProtocolConstants.MINECRAFT_1_20_2, 0x0F ), | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_20_3, 0x10 ) |                     map( ProtocolConstants.MINECRAFT_1_20_3, 0x10 ), | ||||||
|  |                     map( ProtocolConstants.MINECRAFT_1_20_5, 0x11 ) | ||||||
|             ); |             ); | ||||||
|             TO_SERVER.registerPacket( |             TO_SERVER.registerPacket( | ||||||
|                     StartConfiguration.class, |                     StartConfiguration.class, | ||||||
|                     StartConfiguration::new, |                     StartConfiguration::new, | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_20_2, 0x0B ) |                     map( ProtocolConstants.MINECRAFT_1_20_2, 0x0B ) | ||||||
|             ); |             ); | ||||||
|  |             TO_SERVER.registerPacket( | ||||||
|  |                     CookieResponse.class, | ||||||
|  |                     CookieResponse::new, | ||||||
|  |                     map( ProtocolConstants.MINECRAFT_1_20_5, 0x10 ) | ||||||
|  |             ); | ||||||
|         } |         } | ||||||
|     }, |     }, | ||||||
|     // 1 |     // 1 | ||||||
| @@ -605,6 +653,11 @@ public enum Protocol | |||||||
|                     LoginPayloadRequest::new, |                     LoginPayloadRequest::new, | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_13, 0x04 ) |                     map( ProtocolConstants.MINECRAFT_1_13, 0x04 ) | ||||||
|             ); |             ); | ||||||
|  |             TO_CLIENT.registerPacket( | ||||||
|  |                     CookieRequest.class, | ||||||
|  |                     CookieRequest::new, | ||||||
|  |                     map( ProtocolConstants.MINECRAFT_1_20_5, 0x05 ) | ||||||
|  |             ); | ||||||
|  |  | ||||||
|             TO_SERVER.registerPacket( |             TO_SERVER.registerPacket( | ||||||
|                     LoginRequest.class, |                     LoginRequest.class, | ||||||
| @@ -626,6 +679,11 @@ public enum Protocol | |||||||
|                     LoginAcknowledged::new, |                     LoginAcknowledged::new, | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_20_2, 0x03 ) |                     map( ProtocolConstants.MINECRAFT_1_20_2, 0x03 ) | ||||||
|             ); |             ); | ||||||
|  |             TO_SERVER.registerPacket( | ||||||
|  |                     CookieResponse.class, | ||||||
|  |                     CookieResponse::new, | ||||||
|  |                     map( ProtocolConstants.MINECRAFT_1_20_5, 0x04 ) | ||||||
|  |             ); | ||||||
|         } |         } | ||||||
|     }, |     }, | ||||||
|     // 3 |     // 3 | ||||||
| @@ -633,25 +691,45 @@ public enum Protocol | |||||||
|     { |     { | ||||||
|  |  | ||||||
|         { |         { | ||||||
|  |  | ||||||
|  |             TO_CLIENT.registerPacket( | ||||||
|  |                     CookieRequest.class, | ||||||
|  |                     CookieRequest::new, | ||||||
|  |                     map( ProtocolConstants.MINECRAFT_1_20_5, 0x00 ) | ||||||
|  |             ); | ||||||
|             TO_CLIENT.registerPacket( |             TO_CLIENT.registerPacket( | ||||||
|                     PluginMessage.class, |                     PluginMessage.class, | ||||||
|                     PluginMessage::new, |                     PluginMessage::new, | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_20_2, 0x00 ) |                     map( ProtocolConstants.MINECRAFT_1_20_2, 0x00 ), | ||||||
|  |                     map( ProtocolConstants.MINECRAFT_1_20_5, 0x01 ) | ||||||
|             ); |             ); | ||||||
|             TO_CLIENT.registerPacket( |             TO_CLIENT.registerPacket( | ||||||
|                     Kick.class, |                     Kick.class, | ||||||
|                     Kick::new, |                     Kick::new, | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_20_2, 0x01 ) |                     map( ProtocolConstants.MINECRAFT_1_20_2, 0x01 ), | ||||||
|  |                     map( ProtocolConstants.MINECRAFT_1_20_5, 0x02 ) | ||||||
|             ); |             ); | ||||||
|             TO_CLIENT.registerPacket( |             TO_CLIENT.registerPacket( | ||||||
|                     FinishConfiguration.class, |                     FinishConfiguration.class, | ||||||
|                     FinishConfiguration::new, |                     FinishConfiguration::new, | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_20_2, 0x02 ) |                     map( ProtocolConstants.MINECRAFT_1_20_2, 0x02 ), | ||||||
|  |                     map( ProtocolConstants.MINECRAFT_1_20_5, 0x03 ) | ||||||
|             ); |             ); | ||||||
|             TO_CLIENT.registerPacket( |             TO_CLIENT.registerPacket( | ||||||
|                     KeepAlive.class, |                     KeepAlive.class, | ||||||
|                     KeepAlive::new, |                     KeepAlive::new, | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_20_2, 0x03 ) |                     map( ProtocolConstants.MINECRAFT_1_20_2, 0x03 ), | ||||||
|  |                     map( ProtocolConstants.MINECRAFT_1_20_5, 0x04 ) | ||||||
|  |             ); | ||||||
|  |             TO_CLIENT.registerPacket( | ||||||
|  |                     StoreCookie.class, | ||||||
|  |                     StoreCookie::new, | ||||||
|  |                     map( ProtocolConstants.MINECRAFT_1_20_5, 0x09 ) | ||||||
|  |             ); | ||||||
|  |             TO_CLIENT.registerPacket( | ||||||
|  |                     Transfer.class, | ||||||
|  |                     Transfer::new, | ||||||
|  |                     map( ProtocolConstants.MINECRAFT_1_20_5, 0x0A ) | ||||||
|             ); |             ); | ||||||
|  |  | ||||||
|             TO_SERVER.registerPacket( |             TO_SERVER.registerPacket( | ||||||
| @@ -662,17 +740,20 @@ public enum Protocol | |||||||
|             TO_SERVER.registerPacket( |             TO_SERVER.registerPacket( | ||||||
|                     PluginMessage.class, |                     PluginMessage.class, | ||||||
|                     PluginMessage::new, |                     PluginMessage::new, | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_20_2, 0x01 ) |                     map( ProtocolConstants.MINECRAFT_1_20_2, 0x01 ), | ||||||
|  |                     map( ProtocolConstants.MINECRAFT_1_20_5, 0x02 ) | ||||||
|             ); |             ); | ||||||
|             TO_SERVER.registerPacket( |             TO_SERVER.registerPacket( | ||||||
|                     FinishConfiguration.class, |                     FinishConfiguration.class, | ||||||
|                     FinishConfiguration::new, |                     FinishConfiguration::new, | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_20_2, 0x02 ) |                     map( ProtocolConstants.MINECRAFT_1_20_2, 0x02 ), | ||||||
|  |                     map( ProtocolConstants.MINECRAFT_1_20_5, 0x03 ) | ||||||
|             ); |             ); | ||||||
|             TO_SERVER.registerPacket( |             TO_SERVER.registerPacket( | ||||||
|                     KeepAlive.class, |                     KeepAlive.class, | ||||||
|                     KeepAlive::new, |                     KeepAlive::new, | ||||||
|                     map( ProtocolConstants.MINECRAFT_1_20_2, 0x03 ) |                     map( ProtocolConstants.MINECRAFT_1_20_2, 0x03 ), | ||||||
|  |                     map( ProtocolConstants.MINECRAFT_1_20_5, 0x04 ) | ||||||
|             ); |             ); | ||||||
|         } |         } | ||||||
|     }; |     }; | ||||||
|   | |||||||
| @@ -45,6 +45,7 @@ public class ProtocolConstants | |||||||
|     public static final int MINECRAFT_1_20 = 763; |     public static final int MINECRAFT_1_20 = 763; | ||||||
|     public static final int MINECRAFT_1_20_2 = 764; |     public static final int MINECRAFT_1_20_2 = 764; | ||||||
|     public static final int MINECRAFT_1_20_3 = 765; |     public static final int MINECRAFT_1_20_3 = 765; | ||||||
|  |     public static final int MINECRAFT_1_20_5 = 1073742000; | ||||||
|     public static final List<String> SUPPORTED_VERSIONS; |     public static final List<String> SUPPORTED_VERSIONS; | ||||||
|     public static final List<Integer> SUPPORTED_VERSION_IDS; |     public static final List<Integer> SUPPORTED_VERSION_IDS; | ||||||
|  |  | ||||||
| @@ -109,7 +110,7 @@ public class ProtocolConstants | |||||||
|         if ( SNAPSHOT_SUPPORT ) |         if ( SNAPSHOT_SUPPORT ) | ||||||
|         { |         { | ||||||
|             // supportedVersions.add( "1.20.x" ); |             // supportedVersions.add( "1.20.x" ); | ||||||
|             // supportedVersionIds.add( ProtocolConstants.MINECRAFT_1_20_3 ); |             supportedVersionIds.add( ProtocolConstants.MINECRAFT_1_20_5 ); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         SUPPORTED_VERSIONS = supportedVersions.build(); |         SUPPORTED_VERSIONS = supportedVersions.build(); | ||||||
|   | |||||||
| @@ -124,9 +124,11 @@ public final class TagUtil | |||||||
|                     for ( JsonElement jsonEl : jsonArray ) |                     for ( JsonElement jsonEl : jsonArray ) | ||||||
|                     { |                     { | ||||||
|                         SpecificTag subTag = fromJson( jsonEl ); |                         SpecificTag subTag = fromJson( jsonEl ); | ||||||
|                         if ( subTag.tagType() != listType ) |                         if ( !( subTag instanceof CompoundTag ) ) | ||||||
|                         { |                         { | ||||||
|                             throw new IllegalArgumentException( "Cannot convert mixed JsonArray to Tag" ); |                             CompoundTag wrapper = new CompoundTag(); | ||||||
|  |                             wrapper.add( "", subTag ); | ||||||
|  |                             subTag = wrapper; | ||||||
|                         } |                         } | ||||||
|  |  | ||||||
|                         tagItems.add( subTag ); |                         tagItems.add( subTag ); | ||||||
| @@ -179,6 +181,20 @@ public final class TagUtil | |||||||
|                 JsonArray jsonList = new JsonArray( items.size() ); |                 JsonArray jsonList = new JsonArray( items.size() ); | ||||||
|                 for ( SpecificTag subTag : items ) |                 for ( SpecificTag subTag : items ) | ||||||
|                 { |                 { | ||||||
|  |                     if ( subTag instanceof CompoundTag ) | ||||||
|  |                     { | ||||||
|  |                         CompoundTag compound = (CompoundTag) subTag; | ||||||
|  |                         if ( compound.size() == 1 ) | ||||||
|  |                         { | ||||||
|  |                             SpecificTag first = (SpecificTag) compound.get( "" ); | ||||||
|  |                             if ( !first.isError() ) | ||||||
|  |                             { | ||||||
|  |                                 jsonList.add( toJson( first ) ); | ||||||
|  |                                 continue; | ||||||
|  |                             } | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |  | ||||||
|                     jsonList.add( toJson( subTag ) ); |                     jsonList.add( toJson( subTag ) ); | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -4,6 +4,7 @@ import com.google.common.base.Preconditions; | |||||||
| import com.mojang.brigadier.Command; | import com.mojang.brigadier.Command; | ||||||
| import com.mojang.brigadier.StringReader; | import com.mojang.brigadier.StringReader; | ||||||
| import com.mojang.brigadier.arguments.ArgumentType; | import com.mojang.brigadier.arguments.ArgumentType; | ||||||
|  | import com.mojang.brigadier.arguments.BoolArgumentType; | ||||||
| import com.mojang.brigadier.arguments.DoubleArgumentType; | import com.mojang.brigadier.arguments.DoubleArgumentType; | ||||||
| import com.mojang.brigadier.arguments.FloatArgumentType; | import com.mojang.brigadier.arguments.FloatArgumentType; | ||||||
| import com.mojang.brigadier.arguments.IntegerArgumentType; | import com.mojang.brigadier.arguments.IntegerArgumentType; | ||||||
| @@ -303,7 +304,7 @@ public class Commands extends DefinedPacket | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Data |     @Data | ||||||
|     private static class ArgumentRegistry |     public static class ArgumentRegistry | ||||||
|     { |     { | ||||||
|  |  | ||||||
|         private static final Map<String, ArgumentSerializer> PROVIDERS = new HashMap<>(); |         private static final Map<String, ArgumentSerializer> PROVIDERS = new HashMap<>(); | ||||||
| @@ -326,18 +327,29 @@ public class Commands extends DefinedPacket | |||||||
|             { |             { | ||||||
|             } |             } | ||||||
|         }; |         }; | ||||||
|         private static final ArgumentSerializer<Boolean> BOOLEAN = new ArgumentSerializer<Boolean>() |         private static final ProperArgumentSerializer<BoolArgumentType> BOOLEAN = new ProperArgumentSerializer<BoolArgumentType>() | ||||||
|         { |         { | ||||||
|             @Override |             @Override | ||||||
|             protected Boolean read(ByteBuf buf) |             protected BoolArgumentType read(ByteBuf buf) | ||||||
|             { |             { | ||||||
|                 return buf.readBoolean(); |                 return BoolArgumentType.bool(); | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             @Override |             @Override | ||||||
|             protected void write(ByteBuf buf, Boolean t) |             protected void write(ByteBuf buf, BoolArgumentType t) | ||||||
|             { |             { | ||||||
|                 buf.writeBoolean( t ); |             } | ||||||
|  |  | ||||||
|  |             @Override | ||||||
|  |             protected int getIntKey() | ||||||
|  |             { | ||||||
|  |                 return 0; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             @Override | ||||||
|  |             protected String getKey() | ||||||
|  |             { | ||||||
|  |                 return "brigadier:bool"; | ||||||
|             } |             } | ||||||
|         }; |         }; | ||||||
|         private static final ArgumentSerializer<Byte> BYTE = new ArgumentSerializer<Byte>() |         private static final ArgumentSerializer<Byte> BYTE = new ArgumentSerializer<Byte>() | ||||||
| @@ -354,7 +366,7 @@ public class Commands extends DefinedPacket | |||||||
|                 buf.writeByte( t ); |                 buf.writeByte( t ); | ||||||
|             } |             } | ||||||
|         }; |         }; | ||||||
|         private static final ArgumentSerializer<FloatArgumentType> FLOAT_RANGE = new ArgumentSerializer<FloatArgumentType>() |         private static final ProperArgumentSerializer<FloatArgumentType> FLOAT_RANGE = new ProperArgumentSerializer<FloatArgumentType>() | ||||||
|         { |         { | ||||||
|             @Override |             @Override | ||||||
|             protected FloatArgumentType read(ByteBuf buf) |             protected FloatArgumentType read(ByteBuf buf) | ||||||
| @@ -382,8 +394,20 @@ public class Commands extends DefinedPacket | |||||||
|                     buf.writeFloat( t.getMaximum() ); |                     buf.writeFloat( t.getMaximum() ); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  |  | ||||||
|  |             @Override | ||||||
|  |             protected int getIntKey() | ||||||
|  |             { | ||||||
|  |                 return 1; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             @Override | ||||||
|  |             protected String getKey() | ||||||
|  |             { | ||||||
|  |                 return "brigadier:float"; | ||||||
|  |             } | ||||||
|         }; |         }; | ||||||
|         private static final ArgumentSerializer<DoubleArgumentType> DOUBLE_RANGE = new ArgumentSerializer<DoubleArgumentType>() |         private static final ProperArgumentSerializer<DoubleArgumentType> DOUBLE_RANGE = new ProperArgumentSerializer<DoubleArgumentType>() | ||||||
|         { |         { | ||||||
|             @Override |             @Override | ||||||
|             protected DoubleArgumentType read(ByteBuf buf) |             protected DoubleArgumentType read(ByteBuf buf) | ||||||
| @@ -411,8 +435,20 @@ public class Commands extends DefinedPacket | |||||||
|                     buf.writeDouble( t.getMaximum() ); |                     buf.writeDouble( t.getMaximum() ); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  |  | ||||||
|  |             @Override | ||||||
|  |             protected int getIntKey() | ||||||
|  |             { | ||||||
|  |                 return 2; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             @Override | ||||||
|  |             protected String getKey() | ||||||
|  |             { | ||||||
|  |                 return "brigadier:double"; | ||||||
|  |             } | ||||||
|         }; |         }; | ||||||
|         private static final ArgumentSerializer<IntegerArgumentType> INTEGER_RANGE = new ArgumentSerializer<IntegerArgumentType>() |         private static final ProperArgumentSerializer<IntegerArgumentType> INTEGER_RANGE = new ProperArgumentSerializer<IntegerArgumentType>() | ||||||
|         { |         { | ||||||
|             @Override |             @Override | ||||||
|             protected IntegerArgumentType read(ByteBuf buf) |             protected IntegerArgumentType read(ByteBuf buf) | ||||||
| @@ -440,6 +476,18 @@ public class Commands extends DefinedPacket | |||||||
|                     buf.writeInt( t.getMaximum() ); |                     buf.writeInt( t.getMaximum() ); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  |  | ||||||
|  |             @Override | ||||||
|  |             protected int getIntKey() | ||||||
|  |             { | ||||||
|  |                 return 3; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             @Override | ||||||
|  |             protected String getKey() | ||||||
|  |             { | ||||||
|  |                 return "brigadier:integer"; | ||||||
|  |             } | ||||||
|         }; |         }; | ||||||
|         private static final ArgumentSerializer<Integer> INTEGER = new ArgumentSerializer<Integer>() |         private static final ArgumentSerializer<Integer> INTEGER = new ArgumentSerializer<Integer>() | ||||||
|         { |         { | ||||||
| @@ -455,7 +503,7 @@ public class Commands extends DefinedPacket | |||||||
|                 buf.writeInt( t ); |                 buf.writeInt( t ); | ||||||
|             } |             } | ||||||
|         }; |         }; | ||||||
|         private static final ArgumentSerializer<LongArgumentType> LONG_RANGE = new ArgumentSerializer<LongArgumentType>() |         private static final ProperArgumentSerializer<LongArgumentType> LONG_RANGE = new ProperArgumentSerializer<LongArgumentType>() | ||||||
|         { |         { | ||||||
|             @Override |             @Override | ||||||
|             protected LongArgumentType read(ByteBuf buf) |             protected LongArgumentType read(ByteBuf buf) | ||||||
| @@ -483,6 +531,18 @@ public class Commands extends DefinedPacket | |||||||
|                     buf.writeLong( t.getMaximum() ); |                     buf.writeLong( t.getMaximum() ); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  |  | ||||||
|  |             @Override | ||||||
|  |             protected int getIntKey() | ||||||
|  |             { | ||||||
|  |                 return 4; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             @Override | ||||||
|  |             protected String getKey() | ||||||
|  |             { | ||||||
|  |                 return "brigadier:long"; | ||||||
|  |             } | ||||||
|         }; |         }; | ||||||
|         private static final ProperArgumentSerializer<StringArgumentType> STRING = new ProperArgumentSerializer<StringArgumentType>() |         private static final ProperArgumentSerializer<StringArgumentType> STRING = new ProperArgumentSerializer<StringArgumentType>() | ||||||
|         { |         { | ||||||
| @@ -538,11 +598,20 @@ public class Commands extends DefinedPacket | |||||||
|  |  | ||||||
|         static |         static | ||||||
|         { |         { | ||||||
|             register( "brigadier:bool", VOID ); |             register( "brigadier:bool", BOOLEAN ); | ||||||
|  |             PROPER_PROVIDERS.put( BoolArgumentType.class, BOOLEAN ); | ||||||
|  |  | ||||||
|             register( "brigadier:float", FLOAT_RANGE ); |             register( "brigadier:float", FLOAT_RANGE ); | ||||||
|  |             PROPER_PROVIDERS.put( FloatArgumentType.class, FLOAT_RANGE ); | ||||||
|  |  | ||||||
|             register( "brigadier:double", DOUBLE_RANGE ); |             register( "brigadier:double", DOUBLE_RANGE ); | ||||||
|  |             PROPER_PROVIDERS.put( DoubleArgumentType.class, DOUBLE_RANGE ); | ||||||
|  |  | ||||||
|             register( "brigadier:integer", INTEGER_RANGE ); |             register( "brigadier:integer", INTEGER_RANGE ); | ||||||
|             register( "brigadier:long", LONG_RANGE ); |             PROPER_PROVIDERS.put( IntegerArgumentType.class, INTEGER_RANGE ); | ||||||
|  |  | ||||||
|  |             register( "brigadier:long", LONG_RANGE ); // 1.14+ | ||||||
|  |             PROPER_PROVIDERS.put( LongArgumentType.class, LONG_RANGE ); | ||||||
|  |  | ||||||
|             register( "brigadier:string", STRING ); |             register( "brigadier:string", STRING ); | ||||||
|             PROPER_PROVIDERS.put( StringArgumentType.class, STRING ); |             PROPER_PROVIDERS.put( StringArgumentType.class, STRING ); | ||||||
| @@ -811,6 +880,404 @@ public class Commands extends DefinedPacket | |||||||
|             return serializer; |             return serializer; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Returns the Minecraft ArgumentType {@code minecraft:entity}. | ||||||
|  |          * @param singleEntity if the argument restrict to only one entity | ||||||
|  |          * @param onlyPlayers if the argument restrict to players only | ||||||
|  |          * @return an ArgumentType instance | ||||||
|  |          */ | ||||||
|  |         public static ArgumentType<?> minecraftEntity(boolean singleEntity, boolean onlyPlayers) | ||||||
|  |         { | ||||||
|  |             byte flags = 0; | ||||||
|  |             if ( singleEntity ) | ||||||
|  |             { | ||||||
|  |                 flags |= 1; | ||||||
|  |             } | ||||||
|  |             if ( onlyPlayers ) | ||||||
|  |             { | ||||||
|  |                 flags |= 2; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             return minecraftArgumentType( "minecraft:entity", flags ); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Returns the Minecraft ArgumentType {@code minecraft:game_profile}. | ||||||
|  |          * @return an ArgumentType instance | ||||||
|  |          */ | ||||||
|  |         public static ArgumentType<?> minecraftGameProfile() | ||||||
|  |         { | ||||||
|  |             return minecraftArgumentType( "minecraft:game_profile", null ); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Returns the Minecraft ArgumentType {@code minecraft:block_pos}. | ||||||
|  |          * @return an ArgumentType instance | ||||||
|  |          */ | ||||||
|  |         public static ArgumentType<?> minecraftBlockPos() | ||||||
|  |         { | ||||||
|  |             return minecraftArgumentType( "minecraft:block_pos", null ); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Returns the Minecraft ArgumentType {@code minecraft:column_pos}. | ||||||
|  |          * @return an ArgumentType instance | ||||||
|  |          */ | ||||||
|  |         public static ArgumentType<?> minecraftColumnPos() | ||||||
|  |         { | ||||||
|  |             return minecraftArgumentType( "minecraft:column_pos", null ); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Returns the Minecraft ArgumentType {@code minecraft:vec3}. | ||||||
|  |          * @return an ArgumentType instance | ||||||
|  |          */ | ||||||
|  |         public static ArgumentType<?> minecraftVec3() | ||||||
|  |         { | ||||||
|  |             return minecraftArgumentType( "minecraft:vec3", null ); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Returns the Minecraft ArgumentType {@code minecraft:vec2}. | ||||||
|  |          * @return an ArgumentType instance | ||||||
|  |          */ | ||||||
|  |         public static ArgumentType<?> minecraftVec2() | ||||||
|  |         { | ||||||
|  |             return minecraftArgumentType( "minecraft:vec2", null ); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Returns the Minecraft ArgumentType {@code minecraft:block_state}. | ||||||
|  |          * @return an ArgumentType instance | ||||||
|  |          */ | ||||||
|  |         public static ArgumentType<?> minecraftBlockState() | ||||||
|  |         { | ||||||
|  |             return minecraftArgumentType( "minecraft:block_state", null ); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Returns the Minecraft ArgumentType {@code minecraft:block_predicate}. | ||||||
|  |          * @return an ArgumentType instance | ||||||
|  |          */ | ||||||
|  |         public static ArgumentType<?> minecraftBlockPredicate() | ||||||
|  |         { | ||||||
|  |             return minecraftArgumentType( "minecraft:block_predicate", null ); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Returns the Minecraft ArgumentType {@code minecraft:item_stack}. | ||||||
|  |          * @return an ArgumentType instance | ||||||
|  |          */ | ||||||
|  |         public static ArgumentType<?> minecraftItemStack() | ||||||
|  |         { | ||||||
|  |             return minecraftArgumentType( "minecraft:item_stack", null ); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Returns the Minecraft ArgumentType {@code minecraft:item_predicate}. | ||||||
|  |          * @return an ArgumentType instance | ||||||
|  |          */ | ||||||
|  |         public static ArgumentType<?> minecraftItemPredicate() | ||||||
|  |         { | ||||||
|  |             return minecraftArgumentType( "minecraft:item_predicate", null ); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Returns the Minecraft ArgumentType {@code minecraft:color}. | ||||||
|  |          * @return an ArgumentType instance | ||||||
|  |          */ | ||||||
|  |         public static ArgumentType<?> minecraftColor() | ||||||
|  |         { | ||||||
|  |             return minecraftArgumentType( "minecraft:color", null ); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Returns the Minecraft ArgumentType {@code minecraft:component}. | ||||||
|  |          * @return an ArgumentType instance | ||||||
|  |          */ | ||||||
|  |         public static ArgumentType<?> minecraftComponent() | ||||||
|  |         { | ||||||
|  |             return minecraftArgumentType( "minecraft:component", null ); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Returns the Minecraft ArgumentType {@code minecraft:message}. | ||||||
|  |          * @return an ArgumentType instance | ||||||
|  |          */ | ||||||
|  |         public static ArgumentType<?> minecraftMessage() | ||||||
|  |         { | ||||||
|  |             return minecraftArgumentType( "minecraft:message", null ); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Returns the Minecraft ArgumentType {@code minecraft:nbt_compound_tag}. | ||||||
|  |          * @return an ArgumentType instance | ||||||
|  |          */ | ||||||
|  |         public static ArgumentType<?> minecraftNBTCompoundTag() | ||||||
|  |         { | ||||||
|  |             return minecraftArgumentType( "minecraft:nbt_compound_tag", null ); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Returns the Minecraft ArgumentType {@code minecraft:nbt_tag}. | ||||||
|  |          * @return an ArgumentType instance | ||||||
|  |          */ | ||||||
|  |         public static ArgumentType<?> minecraftNBTTag() | ||||||
|  |         { | ||||||
|  |             return minecraftArgumentType( "minecraft:nbt_tag", null ); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Returns the Minecraft ArgumentType {@code minecraft:nbt}. | ||||||
|  |          * @return an ArgumentType instance | ||||||
|  |          */ | ||||||
|  |         public static ArgumentType<?> minecraftNBT() | ||||||
|  |         { | ||||||
|  |             return minecraftArgumentType( "minecraft:nbt", null ); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Returns the Minecraft ArgumentType {@code minecraft:nbt_path}. | ||||||
|  |          * @return an ArgumentType instance | ||||||
|  |          */ | ||||||
|  |         public static ArgumentType<?> minecraftNBTPath() | ||||||
|  |         { | ||||||
|  |             return minecraftArgumentType( "minecraft:nbt_path", null ); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Returns the Minecraft ArgumentType {@code minecraft:objective}. | ||||||
|  |          * @return an ArgumentType instance | ||||||
|  |          */ | ||||||
|  |         public static ArgumentType<?> minecraftObjective() | ||||||
|  |         { | ||||||
|  |             return minecraftArgumentType( "minecraft:objective", null ); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Returns the Minecraft ArgumentType {@code minecraft:objective_criteria}. | ||||||
|  |          * @return an ArgumentType instance | ||||||
|  |          */ | ||||||
|  |         public static ArgumentType<?> minecraftObjectiveCriteria() | ||||||
|  |         { | ||||||
|  |             return minecraftArgumentType( "minecraft:objective_criteria", null ); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Returns the Minecraft ArgumentType {@code minecraft:operation}. | ||||||
|  |          * @return an ArgumentType instance | ||||||
|  |          */ | ||||||
|  |         public static ArgumentType<?> minecraftOperation() | ||||||
|  |         { | ||||||
|  |             return minecraftArgumentType( "minecraft:operation", null ); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Returns the Minecraft ArgumentType {@code minecraft:particle}. | ||||||
|  |          * @return an ArgumentType instance | ||||||
|  |          */ | ||||||
|  |         public static ArgumentType<?> minecraftParticle() | ||||||
|  |         { | ||||||
|  |             return minecraftArgumentType( "minecraft:particle", null ); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Returns the Minecraft ArgumentType {@code minecraft:rotation}. | ||||||
|  |          * @return an ArgumentType instance | ||||||
|  |          */ | ||||||
|  |         public static ArgumentType<?> minecraftRotation() | ||||||
|  |         { | ||||||
|  |             return minecraftArgumentType( "minecraft:rotation", null ); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Returns the Minecraft ArgumentType {@code minecraft:scoreboard_slot}. | ||||||
|  |          * @return an ArgumentType instance | ||||||
|  |          */ | ||||||
|  |         public static ArgumentType<?> minecraftScoreboardSlot() | ||||||
|  |         { | ||||||
|  |             return minecraftArgumentType( "minecraft:scoreboard_slot", null ); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Returns the Minecraft ArgumentType {@code minecraft:score_holder}. | ||||||
|  |          * @param allowMultiple if the argument allows multiple entities | ||||||
|  |          * @return an ArgumentType instance | ||||||
|  |          */ | ||||||
|  |         public static ArgumentType<?> minecraftScoreHolder(boolean allowMultiple) | ||||||
|  |         { | ||||||
|  |             byte flags = 0; | ||||||
|  |             if ( allowMultiple ) | ||||||
|  |             { | ||||||
|  |                 flags |= 1; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             return minecraftArgumentType( "minecraft:score_holder", flags ); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Returns the Minecraft ArgumentType {@code minecraft:swizzle}. | ||||||
|  |          * @return an ArgumentType instance | ||||||
|  |          */ | ||||||
|  |         public static ArgumentType<?> minecraftSwizzle() | ||||||
|  |         { | ||||||
|  |             return minecraftArgumentType( "minecraft:swizzle", null ); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Returns the Minecraft ArgumentType {@code minecraft:team}. | ||||||
|  |          * @return an ArgumentType instance | ||||||
|  |          */ | ||||||
|  |         public static ArgumentType<?> minecraftTeam() | ||||||
|  |         { | ||||||
|  |             return minecraftArgumentType( "minecraft:team", null ); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Returns the Minecraft ArgumentType {@code minecraft:item_slot}. | ||||||
|  |          * @return an ArgumentType instance | ||||||
|  |          */ | ||||||
|  |         public static ArgumentType<?> minecraftItemSlot() | ||||||
|  |         { | ||||||
|  |             return minecraftArgumentType( "minecraft:item_slot", null ); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Returns the Minecraft ArgumentType {@code minecraft:resource_location}. | ||||||
|  |          * @return an ArgumentType instance | ||||||
|  |          */ | ||||||
|  |         public static ArgumentType<?> minecraftResourceLocation() | ||||||
|  |         { | ||||||
|  |             return minecraftArgumentType( "minecraft:resource_location", null ); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Returns the Minecraft ArgumentType {@code minecraft:mob_effect}. | ||||||
|  |          * @return an ArgumentType instance | ||||||
|  |          */ | ||||||
|  |         public static ArgumentType<?> minecraftMobEffect() | ||||||
|  |         { | ||||||
|  |             return minecraftArgumentType( "minecraft:mob_effect", null ); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Returns the Minecraft ArgumentType {@code minecraft:function}. | ||||||
|  |          * @return an ArgumentType instance | ||||||
|  |          */ | ||||||
|  |         public static ArgumentType<?> minecraftFunction() | ||||||
|  |         { | ||||||
|  |             return minecraftArgumentType( "minecraft:function", null ); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Returns the Minecraft ArgumentType {@code minecraft:entity_anchor}. | ||||||
|  |          * @return an ArgumentType instance | ||||||
|  |          */ | ||||||
|  |         public static ArgumentType<?> minecraftEntityAnchor() | ||||||
|  |         { | ||||||
|  |             return minecraftArgumentType( "minecraft:entity_anchor", null ); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Returns the Minecraft ArgumentType {@code minecraft:int_range}. | ||||||
|  |          * @return an ArgumentType instance | ||||||
|  |          */ | ||||||
|  |         public static ArgumentType<?> minecraftIntRange() | ||||||
|  |         { | ||||||
|  |             return minecraftArgumentType( "minecraft:int_range", null ); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Returns the Minecraft ArgumentType {@code minecraft:float_range}. | ||||||
|  |          * @return an ArgumentType instance | ||||||
|  |          */ | ||||||
|  |         public static ArgumentType<?> minecraftFloatRange() | ||||||
|  |         { | ||||||
|  |             return minecraftArgumentType( "minecraft:float_range", null ); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Returns the Minecraft ArgumentType {@code minecraft:item_enchantment}. | ||||||
|  |          * @return an ArgumentType instance | ||||||
|  |          */ | ||||||
|  |         public static ArgumentType<?> minecraftItemEnchantment() | ||||||
|  |         { | ||||||
|  |             return minecraftArgumentType( "minecraft:item_enchantment", null ); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Returns the Minecraft ArgumentType {@code minecraft:entity_summon}. | ||||||
|  |          * @return an ArgumentType instance | ||||||
|  |          */ | ||||||
|  |         public static ArgumentType<?> minecraftEntitySummon() | ||||||
|  |         { | ||||||
|  |             return minecraftArgumentType( "minecraft:entity_summon", null ); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Returns the Minecraft ArgumentType {@code minecraft:dimension}. | ||||||
|  |          * @return an ArgumentType instance | ||||||
|  |          */ | ||||||
|  |         public static ArgumentType<?> minecraftDimension() | ||||||
|  |         { | ||||||
|  |             return minecraftArgumentType( "minecraft:dimension", null ); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Returns the Minecraft ArgumentType {@code minecraft:time}. | ||||||
|  |          * @return an ArgumentType instance | ||||||
|  |          */ | ||||||
|  |         public static ArgumentType<?> minecraftTime() | ||||||
|  |         { | ||||||
|  |             return minecraftArgumentType( "minecraft:time", null ); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Returns the Minecraft ArgumentType {@code minecraft:uuid}. | ||||||
|  |          * @return an ArgumentType instance | ||||||
|  |          */ | ||||||
|  |         public static ArgumentType<?> minecraftUUID() | ||||||
|  |         { | ||||||
|  |             return minecraftArgumentType( "minecraft:uuid", null ); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Returns the Minecraft ArgumentType {@code minecraft:angle}. | ||||||
|  |          * @return an ArgumentType instance | ||||||
|  |          */ | ||||||
|  |         public static ArgumentType<?> minecraftAngle() | ||||||
|  |         { | ||||||
|  |             return minecraftArgumentType( "minecraft:angle", null ); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Returns the Minecraft ArgumentType {@code minecraft:resource}. | ||||||
|  |          * @param rawString the raw string for the argument | ||||||
|  |          * @return an ArgumentType instance | ||||||
|  |          */ | ||||||
|  |         public static ArgumentType<?> minecraftResource(String rawString) | ||||||
|  |         { | ||||||
|  |             return minecraftArgumentType( "minecraft:resource", rawString ); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Returns the Minecraft ArgumentType {@code minecraft:resource_or_tag}. | ||||||
|  |          * @param rawString the raw string for the argument | ||||||
|  |          * @return an ArgumentType instance | ||||||
|  |          */ | ||||||
|  |         public static ArgumentType<?> minecraftResourceOrTag(String rawString) | ||||||
|  |         { | ||||||
|  |             return minecraftArgumentType( "minecraft:resource_or_tag", rawString ); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         private static ArgumentType<?> minecraftArgumentType(String key, Object rawValue) | ||||||
|  |         { | ||||||
|  |             ArgumentSerializer reader = PROVIDERS.get( key ); | ||||||
|  |             Preconditions.checkArgument( reader != null, "No provider for argument " + key ); | ||||||
|  |  | ||||||
|  |             return new DummyType( key, reader, rawValue ); | ||||||
|  |         } | ||||||
|  |  | ||||||
|         private static ArgumentType<?> read(ByteBuf buf, int protocolVersion) |         private static ArgumentType<?> read(ByteBuf buf, int protocolVersion) | ||||||
|         { |         { | ||||||
|             Object key; |             Object key; | ||||||
| @@ -937,11 +1404,15 @@ public class Commands extends DefinedPacket | |||||||
|  |  | ||||||
|         private static String getKey(SuggestionProvider<DummyProvider> provider) |         private static String getKey(SuggestionProvider<DummyProvider> provider) | ||||||
|         { |         { | ||||||
|             Preconditions.checkArgument( provider instanceof DummyProvider, "Non dummy provider " + provider ); |             Preconditions.checkNotNull( provider ); | ||||||
|  |             if ( provider instanceof DummyProvider ) | ||||||
|  |             { | ||||||
|                 return ( (DummyProvider) provider ).key; |                 return ( (DummyProvider) provider ).key; | ||||||
|             } |             } | ||||||
|  |  | ||||||
|  |             return ( (DummyProvider) ASK_SERVER ).key; | ||||||
|  |         } | ||||||
|  |  | ||||||
|         @Data |         @Data | ||||||
|         private static final class DummyProvider implements SuggestionProvider<DummyProvider> |         private static final class DummyProvider implements SuggestionProvider<DummyProvider> | ||||||
|         { |         { | ||||||
|   | |||||||
| @@ -0,0 +1,38 @@ | |||||||
|  | package net.md_5.bungee.protocol.packet; | ||||||
|  |  | ||||||
|  | import io.netty.buffer.ByteBuf; | ||||||
|  | import lombok.AllArgsConstructor; | ||||||
|  | import lombok.Data; | ||||||
|  | import lombok.EqualsAndHashCode; | ||||||
|  | import lombok.NoArgsConstructor; | ||||||
|  | import net.md_5.bungee.protocol.AbstractPacketHandler; | ||||||
|  | import net.md_5.bungee.protocol.DefinedPacket; | ||||||
|  | import net.md_5.bungee.protocol.ProtocolConstants; | ||||||
|  |  | ||||||
|  | @Data | ||||||
|  | @NoArgsConstructor | ||||||
|  | @AllArgsConstructor | ||||||
|  | @EqualsAndHashCode(callSuper = false) | ||||||
|  | public class CookieRequest extends DefinedPacket | ||||||
|  | { | ||||||
|  |  | ||||||
|  |     private String cookie; | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion) | ||||||
|  |     { | ||||||
|  |         cookie = readString( buf ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void write(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion) | ||||||
|  |     { | ||||||
|  |         writeString( cookie, buf ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void handle(AbstractPacketHandler handler) throws Exception | ||||||
|  |     { | ||||||
|  |         handler.handle( this ); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,41 @@ | |||||||
|  | package net.md_5.bungee.protocol.packet; | ||||||
|  |  | ||||||
|  | import io.netty.buffer.ByteBuf; | ||||||
|  | import lombok.AllArgsConstructor; | ||||||
|  | import lombok.Data; | ||||||
|  | import lombok.EqualsAndHashCode; | ||||||
|  | import lombok.NoArgsConstructor; | ||||||
|  | import net.md_5.bungee.protocol.AbstractPacketHandler; | ||||||
|  | import net.md_5.bungee.protocol.DefinedPacket; | ||||||
|  | import net.md_5.bungee.protocol.ProtocolConstants; | ||||||
|  |  | ||||||
|  | @Data | ||||||
|  | @NoArgsConstructor | ||||||
|  | @AllArgsConstructor | ||||||
|  | @EqualsAndHashCode(callSuper = false) | ||||||
|  | public class CookieResponse extends DefinedPacket | ||||||
|  | { | ||||||
|  |  | ||||||
|  |     private String cookie; | ||||||
|  |     private byte[] data; | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion) | ||||||
|  |     { | ||||||
|  |         cookie = readString( buf ); | ||||||
|  |         data = readNullable( DefinedPacket::readArray, buf ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void write(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion) | ||||||
|  |     { | ||||||
|  |         writeString( cookie, buf ); | ||||||
|  |         writeNullable( data, DefinedPacket::writeArray, buf ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void handle(AbstractPacketHandler handler) throws Exception | ||||||
|  |     { | ||||||
|  |         handler.handle( this ); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -19,6 +19,7 @@ public class EncryptionRequest extends DefinedPacket | |||||||
|     private String serverId; |     private String serverId; | ||||||
|     private byte[] publicKey; |     private byte[] publicKey; | ||||||
|     private byte[] verifyToken; |     private byte[] verifyToken; | ||||||
|  |     private boolean shouldAuthenticate; | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion) |     public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion) | ||||||
| @@ -26,6 +27,10 @@ public class EncryptionRequest extends DefinedPacket | |||||||
|         serverId = readString( buf ); |         serverId = readString( buf ); | ||||||
|         publicKey = readArray( buf ); |         publicKey = readArray( buf ); | ||||||
|         verifyToken = readArray( buf ); |         verifyToken = readArray( buf ); | ||||||
|  |         if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_20_5 ) | ||||||
|  |         { | ||||||
|  |             shouldAuthenticate = buf.readBoolean(); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
| @@ -34,6 +39,10 @@ public class EncryptionRequest extends DefinedPacket | |||||||
|         writeString( serverId, buf ); |         writeString( serverId, buf ); | ||||||
|         writeArray( publicKey, buf ); |         writeArray( publicKey, buf ); | ||||||
|         writeArray( verifyToken, buf ); |         writeArray( verifyToken, buf ); | ||||||
|  |         if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_20_5 ) | ||||||
|  |         { | ||||||
|  |             buf.writeBoolean( shouldAuthenticate ); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|   | |||||||
| @@ -41,6 +41,7 @@ public class Login extends DefinedPacket | |||||||
|     private boolean flat; |     private boolean flat; | ||||||
|     private Location deathLocation; |     private Location deathLocation; | ||||||
|     private int portalCooldown; |     private int portalCooldown; | ||||||
|  |     private boolean secureProfile; | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion) |     public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion) | ||||||
| @@ -154,6 +155,11 @@ public class Login extends DefinedPacket | |||||||
|         { |         { | ||||||
|             portalCooldown = readVarInt( buf ); |             portalCooldown = readVarInt( buf ); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_20_5 ) | ||||||
|  |         { | ||||||
|  |             secureProfile = buf.readBoolean(); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
| @@ -275,6 +281,11 @@ public class Login extends DefinedPacket | |||||||
|         { |         { | ||||||
|             writeVarInt( portalCooldown, buf ); |             writeVarInt( portalCooldown, buf ); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_20_5 ) | ||||||
|  |         { | ||||||
|  |             buf.writeBoolean( secureProfile ); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|   | |||||||
| @@ -33,7 +33,7 @@ public class ServerData extends DefinedPacket | |||||||
|         { |         { | ||||||
|             if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_19_4 ) |             if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_19_4 ) | ||||||
|             { |             { | ||||||
|                 icon = DefinedPacket.readArray( buf ); |                 icon = readArray( buf ); | ||||||
|             } else |             } else | ||||||
|             { |             { | ||||||
|                 icon = readString( buf ); |                 icon = readString( buf ); | ||||||
| @@ -45,7 +45,7 @@ public class ServerData extends DefinedPacket | |||||||
|             preview = buf.readBoolean(); |             preview = buf.readBoolean(); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_19_1 ) |         if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_19_1 && protocolVersion < ProtocolConstants.MINECRAFT_1_20_5 ) | ||||||
|         { |         { | ||||||
|             enforceSecure = buf.readBoolean(); |             enforceSecure = buf.readBoolean(); | ||||||
|         } |         } | ||||||
| @@ -76,7 +76,7 @@ public class ServerData extends DefinedPacket | |||||||
|             buf.writeBoolean( true ); |             buf.writeBoolean( true ); | ||||||
|             if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_19_4 ) |             if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_19_4 ) | ||||||
|             { |             { | ||||||
|                 DefinedPacket.writeArray( (byte[]) icon, buf ); |                 writeArray( (byte[]) icon, buf ); | ||||||
|             } else |             } else | ||||||
|             { |             { | ||||||
|                 writeString( (String) icon, buf ); |                 writeString( (String) icon, buf ); | ||||||
| @@ -91,7 +91,7 @@ public class ServerData extends DefinedPacket | |||||||
|             buf.writeBoolean( preview ); |             buf.writeBoolean( preview ); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_19_1 ) |         if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_19_1 && protocolVersion < ProtocolConstants.MINECRAFT_1_20_5 ) | ||||||
|         { |         { | ||||||
|             buf.writeBoolean( enforceSecure ); |             buf.writeBoolean( enforceSecure ); | ||||||
|         } |         } | ||||||
|   | |||||||
| @@ -0,0 +1,41 @@ | |||||||
|  | package net.md_5.bungee.protocol.packet; | ||||||
|  |  | ||||||
|  | import io.netty.buffer.ByteBuf; | ||||||
|  | import lombok.AllArgsConstructor; | ||||||
|  | import lombok.Data; | ||||||
|  | import lombok.EqualsAndHashCode; | ||||||
|  | import lombok.NoArgsConstructor; | ||||||
|  | import net.md_5.bungee.protocol.AbstractPacketHandler; | ||||||
|  | import net.md_5.bungee.protocol.DefinedPacket; | ||||||
|  | import net.md_5.bungee.protocol.ProtocolConstants; | ||||||
|  |  | ||||||
|  | @Data | ||||||
|  | @NoArgsConstructor | ||||||
|  | @AllArgsConstructor | ||||||
|  | @EqualsAndHashCode(callSuper = false) | ||||||
|  | public class StoreCookie extends DefinedPacket | ||||||
|  | { | ||||||
|  |  | ||||||
|  |     private String key; | ||||||
|  |     private byte[] data; | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion) | ||||||
|  |     { | ||||||
|  |         key = readString( buf ); | ||||||
|  |         data = readArray( buf, 5120 ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void write(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion) | ||||||
|  |     { | ||||||
|  |         writeString( key, buf ); | ||||||
|  |         writeArray( data, buf ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void handle(AbstractPacketHandler handler) throws Exception | ||||||
|  |     { | ||||||
|  |         handler.handle( this ); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,41 @@ | |||||||
|  | package net.md_5.bungee.protocol.packet; | ||||||
|  |  | ||||||
|  | import io.netty.buffer.ByteBuf; | ||||||
|  | import lombok.AllArgsConstructor; | ||||||
|  | import lombok.Data; | ||||||
|  | import lombok.EqualsAndHashCode; | ||||||
|  | import lombok.NoArgsConstructor; | ||||||
|  | import net.md_5.bungee.protocol.AbstractPacketHandler; | ||||||
|  | import net.md_5.bungee.protocol.DefinedPacket; | ||||||
|  | import net.md_5.bungee.protocol.ProtocolConstants; | ||||||
|  |  | ||||||
|  | @Data | ||||||
|  | @NoArgsConstructor | ||||||
|  | @AllArgsConstructor | ||||||
|  | @EqualsAndHashCode(callSuper = false) | ||||||
|  | public class Transfer extends DefinedPacket | ||||||
|  | { | ||||||
|  |  | ||||||
|  |     private String host; | ||||||
|  |     private int port; | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion) | ||||||
|  |     { | ||||||
|  |         host = readString( buf ); | ||||||
|  |         port = readVarInt( buf ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void write(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion) | ||||||
|  |     { | ||||||
|  |         writeString( host, buf ); | ||||||
|  |         writeVarInt( port, buf ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void handle(AbstractPacketHandler handler) throws Exception | ||||||
|  |     { | ||||||
|  |         handler.handle( this ); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,29 @@ | |||||||
|  | package net.md_5.bungee.protocol; | ||||||
|  |  | ||||||
|  | import static org.junit.jupiter.api.Assertions.*; | ||||||
|  | import com.google.gson.Gson; | ||||||
|  | import com.google.gson.JsonElement; | ||||||
|  | import org.junit.jupiter.api.Test; | ||||||
|  | import se.llbit.nbt.SpecificTag; | ||||||
|  |  | ||||||
|  | public class TagUtilTest | ||||||
|  | { | ||||||
|  |  | ||||||
|  |     private static final Gson GSON = new Gson(); | ||||||
|  |  | ||||||
|  |     private static void testDissembleReassemble(String json) | ||||||
|  |     { | ||||||
|  |         JsonElement parsedJson = GSON.fromJson( json, JsonElement.class ); | ||||||
|  |         SpecificTag nbt = TagUtil.fromJson( parsedJson ); | ||||||
|  |         JsonElement convertedElement = TagUtil.toJson( nbt ); | ||||||
|  |  | ||||||
|  |         String convertedJson = GSON.toJson( convertedElement ); | ||||||
|  |         assertEquals( json, convertedJson ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Test | ||||||
|  |     public void testStringLiteral() | ||||||
|  |     { | ||||||
|  |         testDissembleReassemble( "{\"text\":\"\",\"extra\":[\"hello\",{\"text\":\"there\",\"color\":\"#ff0000\"},{\"text\":\"friend\",\"font\":\"minecraft:default\"}]}" ); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -4,15 +4,14 @@ | |||||||
|     <modelVersion>4.0.0</modelVersion> |     <modelVersion>4.0.0</modelVersion> | ||||||
|  |  | ||||||
|     <parent> |     <parent> | ||||||
|         <groupId>net.md-5</groupId> |         <groupId>fr.pandacube.bungeecord</groupId> | ||||||
|         <artifactId>bungeecord-parent</artifactId> |         <artifactId>bungeecord-parent</artifactId> | ||||||
|         <version>1.20-R0.2-SNAPSHOT</version> |         <version>1.20-R0.3-SNAPSHOT</version> | ||||||
|         <relativePath>../pom.xml</relativePath> |         <relativePath>../pom.xml</relativePath> | ||||||
|     </parent> |     </parent> | ||||||
|  |  | ||||||
|     <groupId>net.md-5</groupId> |  | ||||||
|     <artifactId>bungeecord-proxy</artifactId> |     <artifactId>bungeecord-proxy</artifactId> | ||||||
|     <version>1.20-R0.2-SNAPSHOT</version> |     <version>1.20-R0.3-SNAPSHOT</version> | ||||||
|     <packaging>jar</packaging> |     <packaging>jar</packaging> | ||||||
|  |  | ||||||
|     <name>BungeeCord-Proxy</name> |     <name>BungeeCord-Proxy</name> | ||||||
| @@ -52,37 +51,37 @@ | |||||||
|             <scope>compile</scope> |             <scope>compile</scope> | ||||||
|         </dependency> |         </dependency> | ||||||
|         <dependency> |         <dependency> | ||||||
|             <groupId>net.md-5</groupId> |             <groupId>fr.pandacube.bungeecord</groupId> | ||||||
|             <artifactId>bungeecord-api</artifactId> |             <artifactId>bungeecord-api</artifactId> | ||||||
|             <version>${project.version}</version> |             <version>${project.version}</version> | ||||||
|             <scope>compile</scope> |             <scope>compile</scope> | ||||||
|         </dependency> |         </dependency> | ||||||
|         <dependency> |         <dependency> | ||||||
|             <groupId>net.md-5</groupId> |             <groupId>fr.pandacube.bungeecord</groupId> | ||||||
|             <artifactId>bungeecord-log</artifactId> |             <artifactId>bungeecord-log</artifactId> | ||||||
|             <version>${project.version}</version> |             <version>${project.version}</version> | ||||||
|             <scope>compile</scope> |             <scope>compile</scope> | ||||||
|         </dependency> |         </dependency> | ||||||
|         <dependency> |         <dependency> | ||||||
|             <groupId>net.md-5</groupId> |             <groupId>fr.pandacube.bungeecord</groupId> | ||||||
|             <artifactId>bungeecord-native</artifactId> |             <artifactId>bungeecord-native</artifactId> | ||||||
|             <version>${project.version}</version> |             <version>${project.version}</version> | ||||||
|             <scope>compile</scope> |             <scope>compile</scope> | ||||||
|         </dependency> |         </dependency> | ||||||
|         <dependency> |         <dependency> | ||||||
|             <groupId>net.md-5</groupId> |             <groupId>fr.pandacube.bungeecord</groupId> | ||||||
|             <artifactId>bungeecord-protocol</artifactId> |             <artifactId>bungeecord-protocol</artifactId> | ||||||
|             <version>${project.version}</version> |             <version>${project.version}</version> | ||||||
|             <scope>compile</scope> |             <scope>compile</scope> | ||||||
|         </dependency> |         </dependency> | ||||||
|         <dependency> |         <dependency> | ||||||
|             <groupId>net.md-5</groupId> |             <groupId>fr.pandacube.bungeecord</groupId> | ||||||
|             <artifactId>bungeecord-query</artifactId> |             <artifactId>bungeecord-query</artifactId> | ||||||
|             <version>${project.version}</version> |             <version>${project.version}</version> | ||||||
|             <scope>compile</scope> |             <scope>compile</scope> | ||||||
|         </dependency> |         </dependency> | ||||||
|         <dependency> |         <dependency> | ||||||
|             <groupId>net.md-5</groupId> |             <groupId>fr.pandacube.bungeecord</groupId> | ||||||
|             <artifactId>bungeecord-slf4j</artifactId> |             <artifactId>bungeecord-slf4j</artifactId> | ||||||
|             <version>${project.version}</version> |             <version>${project.version}</version> | ||||||
|             <scope>compile</scope> |             <scope>compile</scope> | ||||||
| @@ -96,26 +95,26 @@ | |||||||
|         <dependency> |         <dependency> | ||||||
|             <groupId>com.mysql</groupId> |             <groupId>com.mysql</groupId> | ||||||
|             <artifactId>mysql-connector-j</artifactId> |             <artifactId>mysql-connector-j</artifactId> | ||||||
|             <version>8.1.0</version> |             <version>8.2.0</version> | ||||||
|             <scope>runtime</scope> |             <scope>runtime</scope> | ||||||
|         </dependency> |         </dependency> | ||||||
|         <!-- add these back in as they are not exposed by the API --> |         <!-- add these back in as they are not exposed by the API --> | ||||||
|         <dependency> |         <dependency> | ||||||
|             <groupId>org.apache.maven</groupId> |             <groupId>org.apache.maven</groupId> | ||||||
|             <artifactId>maven-resolver-provider</artifactId> |             <artifactId>maven-resolver-provider</artifactId> | ||||||
|             <version>3.8.5</version> |             <version>3.9.6</version> | ||||||
|             <scope>runtime</scope> |             <scope>runtime</scope> | ||||||
|         </dependency> |         </dependency> | ||||||
|         <dependency> |         <dependency> | ||||||
|             <groupId>org.apache.maven.resolver</groupId> |             <groupId>org.apache.maven.resolver</groupId> | ||||||
|             <artifactId>maven-resolver-connector-basic</artifactId> |             <artifactId>maven-resolver-connector-basic</artifactId> | ||||||
|             <version>1.7.3</version> |             <version>1.9.18</version> | ||||||
|             <scope>runtime</scope> |             <scope>runtime</scope> | ||||||
|         </dependency> |         </dependency> | ||||||
|         <dependency> |         <dependency> | ||||||
|             <groupId>org.apache.maven.resolver</groupId> |             <groupId>org.apache.maven.resolver</groupId> | ||||||
|             <artifactId>maven-resolver-transport-http</artifactId> |             <artifactId>maven-resolver-transport-http</artifactId> | ||||||
|             <version>1.7.3</version> |             <version>1.9.18</version> | ||||||
|             <scope>runtime</scope> |             <scope>runtime</scope> | ||||||
|         </dependency> |         </dependency> | ||||||
|     </dependencies> |     </dependencies> | ||||||
|   | |||||||
| @@ -58,6 +58,7 @@ import net.md_5.bungee.api.ReconnectHandler; | |||||||
| import net.md_5.bungee.api.ServerPing; | import net.md_5.bungee.api.ServerPing; | ||||||
| import net.md_5.bungee.api.Title; | import net.md_5.bungee.api.Title; | ||||||
| import net.md_5.bungee.api.chat.BaseComponent; | import net.md_5.bungee.api.chat.BaseComponent; | ||||||
|  | import net.md_5.bungee.api.chat.ComponentStyle; | ||||||
| import net.md_5.bungee.api.chat.KeybindComponent; | import net.md_5.bungee.api.chat.KeybindComponent; | ||||||
| import net.md_5.bungee.api.chat.ScoreComponent; | import net.md_5.bungee.api.chat.ScoreComponent; | ||||||
| import net.md_5.bungee.api.chat.SelectorComponent; | import net.md_5.bungee.api.chat.SelectorComponent; | ||||||
| @@ -70,6 +71,7 @@ import net.md_5.bungee.api.connection.ProxiedPlayer; | |||||||
| import net.md_5.bungee.api.plugin.Plugin; | import net.md_5.bungee.api.plugin.Plugin; | ||||||
| import net.md_5.bungee.api.plugin.PluginManager; | import net.md_5.bungee.api.plugin.PluginManager; | ||||||
| import net.md_5.bungee.chat.ComponentSerializer; | import net.md_5.bungee.chat.ComponentSerializer; | ||||||
|  | import net.md_5.bungee.chat.ComponentStyleSerializer; | ||||||
| import net.md_5.bungee.chat.KeybindComponentSerializer; | import net.md_5.bungee.chat.KeybindComponentSerializer; | ||||||
| import net.md_5.bungee.chat.ScoreComponentSerializer; | import net.md_5.bungee.chat.ScoreComponentSerializer; | ||||||
| import net.md_5.bungee.chat.SelectorComponentSerializer; | import net.md_5.bungee.chat.SelectorComponentSerializer; | ||||||
| @@ -89,7 +91,6 @@ import net.md_5.bungee.forge.ForgeConstants; | |||||||
| import net.md_5.bungee.log.BungeeLogger; | import net.md_5.bungee.log.BungeeLogger; | ||||||
| import net.md_5.bungee.log.LoggingForwardHandler; | import net.md_5.bungee.log.LoggingForwardHandler; | ||||||
| import net.md_5.bungee.log.LoggingOutputStream; | import net.md_5.bungee.log.LoggingOutputStream; | ||||||
| import net.md_5.bungee.module.ModuleManager; |  | ||||||
| import net.md_5.bungee.netty.PipelineUtils; | import net.md_5.bungee.netty.PipelineUtils; | ||||||
| import net.md_5.bungee.protocol.DefinedPacket; | import net.md_5.bungee.protocol.DefinedPacket; | ||||||
| import net.md_5.bungee.protocol.ProtocolConstants; | import net.md_5.bungee.protocol.ProtocolConstants; | ||||||
| @@ -169,11 +170,11 @@ public class BungeeCord extends ProxyServer | |||||||
|             .registerTypeAdapter( KeybindComponent.class, new KeybindComponentSerializer() ) |             .registerTypeAdapter( KeybindComponent.class, new KeybindComponentSerializer() ) | ||||||
|             .registerTypeAdapter( ScoreComponent.class, new ScoreComponentSerializer() ) |             .registerTypeAdapter( ScoreComponent.class, new ScoreComponentSerializer() ) | ||||||
|             .registerTypeAdapter( SelectorComponent.class, new SelectorComponentSerializer() ) |             .registerTypeAdapter( SelectorComponent.class, new SelectorComponentSerializer() ) | ||||||
|  |             .registerTypeAdapter( ComponentStyle.class, new ComponentStyleSerializer() ) | ||||||
|             .registerTypeAdapter( ServerPing.PlayerInfo.class, new PlayerInfoSerializer() ) |             .registerTypeAdapter( ServerPing.PlayerInfo.class, new PlayerInfoSerializer() ) | ||||||
|             .registerTypeAdapter( Favicon.class, Favicon.getFaviconTypeAdapter() ).create(); |             .registerTypeAdapter( Favicon.class, Favicon.getFaviconTypeAdapter() ).create(); | ||||||
|     @Getter |     @Getter | ||||||
|     private ConnectionThrottle connectionThrottle; |     private ConnectionThrottle connectionThrottle; | ||||||
|     private final ModuleManager moduleManager = new ModuleManager(); |  | ||||||
|  |  | ||||||
|     { |     { | ||||||
|         // TODO: Proper fallback when we interface the manager |         // TODO: Proper fallback when we interface the manager | ||||||
| @@ -271,10 +272,6 @@ public class BungeeCord extends ProxyServer | |||||||
|  |  | ||||||
|         eventLoops = PipelineUtils.newEventLoopGroup( 0, new ThreadFactoryBuilder().setNameFormat( "Netty IO Thread #%1$d" ).build() ); |         eventLoops = PipelineUtils.newEventLoopGroup( 0, new ThreadFactoryBuilder().setNameFormat( "Netty IO Thread #%1$d" ).build() ); | ||||||
|  |  | ||||||
|         File moduleDirectory = new File( "modules" ); |  | ||||||
|         moduleManager.load( this, moduleDirectory ); |  | ||||||
|         pluginManager.detectPlugins( moduleDirectory ); |  | ||||||
|  |  | ||||||
|         pluginsFolder.mkdir(); |         pluginsFolder.mkdir(); | ||||||
|         pluginManager.detectPlugins( pluginsFolder ); |         pluginManager.detectPlugins( pluginsFolder ); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -5,7 +5,6 @@ import java.text.SimpleDateFormat; | |||||||
| import java.util.Arrays; | import java.util.Arrays; | ||||||
| import java.util.Calendar; | import java.util.Calendar; | ||||||
| import java.util.Date; | import java.util.Date; | ||||||
| import java.util.concurrent.TimeUnit; |  | ||||||
| import joptsimple.OptionParser; | import joptsimple.OptionParser; | ||||||
| import joptsimple.OptionSet; | import joptsimple.OptionSet; | ||||||
| import net.md_5.bungee.api.ChatColor; | import net.md_5.bungee.api.ChatColor; | ||||||
| @@ -56,8 +55,7 @@ public class BungeeCordLauncher | |||||||
|                 System.err.println( "*** Warning, this build is outdated ***" ); |                 System.err.println( "*** Warning, this build is outdated ***" ); | ||||||
|                 System.err.println( "*** Please download a new build from http://ci.md-5.net/job/BungeeCord ***" ); |                 System.err.println( "*** Please download a new build from http://ci.md-5.net/job/BungeeCord ***" ); | ||||||
|                 System.err.println( "*** You will get NO support regarding this build ***" ); |                 System.err.println( "*** You will get NO support regarding this build ***" ); | ||||||
|                 System.err.println( "*** Server will start in 10 seconds ***" ); |  | ||||||
|                 Thread.sleep( TimeUnit.SECONDS.toMillis( 10 ) ); |  | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -73,7 +73,8 @@ public class EncryptionUtil | |||||||
|         byte[] pubKey = keys.getPublic().getEncoded(); |         byte[] pubKey = keys.getPublic().getEncoded(); | ||||||
|         byte[] verify = new byte[ 4 ]; |         byte[] verify = new byte[ 4 ]; | ||||||
|         random.nextBytes( verify ); |         random.nextBytes( verify ); | ||||||
|         return new EncryptionRequest( hash, pubKey, verify ); |         // always auth for now | ||||||
|  |         return new EncryptionRequest( hash, pubKey, verify, true ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public static boolean check(PlayerPublicKey publicKey, UUID uuid) throws GeneralSecurityException |     public static boolean check(PlayerPublicKey publicKey, UUID uuid) throws GeneralSecurityException | ||||||
|   | |||||||
| @@ -10,6 +10,7 @@ import java.util.Locale; | |||||||
| import java.util.Queue; | import java.util.Queue; | ||||||
| import java.util.Set; | import java.util.Set; | ||||||
| import java.util.UUID; | import java.util.UUID; | ||||||
|  | import java.util.logging.Level; | ||||||
| import lombok.Getter; | import lombok.Getter; | ||||||
| import lombok.RequiredArgsConstructor; | import lombok.RequiredArgsConstructor; | ||||||
| import net.md_5.bungee.api.ChatColor; | import net.md_5.bungee.api.ChatColor; | ||||||
| @@ -39,6 +40,8 @@ import net.md_5.bungee.protocol.Either; | |||||||
| import net.md_5.bungee.protocol.PacketWrapper; | import net.md_5.bungee.protocol.PacketWrapper; | ||||||
| import net.md_5.bungee.protocol.Protocol; | import net.md_5.bungee.protocol.Protocol; | ||||||
| import net.md_5.bungee.protocol.ProtocolConstants; | import net.md_5.bungee.protocol.ProtocolConstants; | ||||||
|  | import net.md_5.bungee.protocol.packet.CookieRequest; | ||||||
|  | import net.md_5.bungee.protocol.packet.CookieResponse; | ||||||
| import net.md_5.bungee.protocol.packet.EncryptionRequest; | import net.md_5.bungee.protocol.packet.EncryptionRequest; | ||||||
| import net.md_5.bungee.protocol.packet.EntityStatus; | import net.md_5.bungee.protocol.packet.EntityStatus; | ||||||
| import net.md_5.bungee.protocol.packet.GameState; | import net.md_5.bungee.protocol.packet.GameState; | ||||||
| @@ -187,6 +190,12 @@ public class ServerConnector extends PacketHandler | |||||||
|         ch.setCompressionThreshold( setCompression.getThreshold() ); |         ch.setCompressionThreshold( setCompression.getThreshold() ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void handle(CookieRequest cookieRequest) throws Exception | ||||||
|  |     { | ||||||
|  |         user.retrieveCookie( cookieRequest.getCookie() ).thenAccept( (cookie) -> ch.write( new CookieResponse( cookieRequest.getCookie(), cookie ) ) ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public void handle(Login login) throws Exception |     public void handle(Login login) throws Exception | ||||||
|     { |     { | ||||||
| @@ -243,7 +252,7 @@ public class ServerConnector extends PacketHandler | |||||||
|             // Set tab list size, TODO: what shall we do about packet mutability |             // Set tab list size, TODO: what shall we do about packet mutability | ||||||
|             Login modLogin = new Login( login.getEntityId(), login.isHardcore(), login.getGameMode(), login.getPreviousGameMode(), login.getWorldNames(), login.getDimensions(), login.getDimension(), login.getWorldName(), login.getSeed(), login.getDifficulty(), |             Login modLogin = new Login( login.getEntityId(), login.isHardcore(), login.getGameMode(), login.getPreviousGameMode(), login.getWorldNames(), login.getDimensions(), login.getDimension(), login.getWorldName(), login.getSeed(), login.getDifficulty(), | ||||||
|                     (byte) user.getPendingConnection().getListener().getTabListSize(), login.getLevelType(), login.getViewDistance(), login.getSimulationDistance(), login.isReducedDebugInfo(), login.isNormalRespawn(), login.isLimitedCrafting(), login.isDebug(), login.isFlat(), login.getDeathLocation(), |                     (byte) user.getPendingConnection().getListener().getTabListSize(), login.getLevelType(), login.getViewDistance(), login.getSimulationDistance(), login.isReducedDebugInfo(), login.isNormalRespawn(), login.isLimitedCrafting(), login.isDebug(), login.isFlat(), login.getDeathLocation(), | ||||||
|                     login.getPortalCooldown() ); |                     login.getPortalCooldown(), login.isSecureProfile() ); | ||||||
|  |  | ||||||
|             user.unsafe().sendPacket( modLogin ); |             user.unsafe().sendPacket( modLogin ); | ||||||
|  |  | ||||||
| @@ -339,6 +348,14 @@ public class ServerConnector extends PacketHandler | |||||||
|  |  | ||||||
|     private void cutThrough(ServerConnection server) |     private void cutThrough(ServerConnection server) | ||||||
|     { |     { | ||||||
|  |         // TODO: Fix this? | ||||||
|  |         if ( !user.isActive() ) | ||||||
|  |         { | ||||||
|  |             server.disconnect( "Quitting" ); | ||||||
|  |             bungee.getLogger().log( Level.WARNING, "[{0}] No client connected for pending server!", user ); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|         if ( user.getPendingConnection().getVersion() >= ProtocolConstants.MINECRAFT_1_20_2 ) |         if ( user.getPendingConnection().getVersion() >= ProtocolConstants.MINECRAFT_1_20_2 ) | ||||||
|         { |         { | ||||||
|             if ( user.getServer() != null ) |             if ( user.getServer() != null ) | ||||||
| @@ -360,15 +377,6 @@ public class ServerConnector extends PacketHandler | |||||||
|             user.getServer().disconnect( "Quitting" ); |             user.getServer().disconnect( "Quitting" ); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         // TODO: Fix this? |  | ||||||
|         if ( !user.isActive() ) |  | ||||||
|         { |  | ||||||
|             server.disconnect( "Quitting" ); |  | ||||||
|             // Silly server admins see stack trace and die |  | ||||||
|             bungee.getLogger().warning( "No client connected for pending server!" ); |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         // Add to new server |         // Add to new server | ||||||
|         // TODO: Move this to the connected() method of DownstreamBridge |         // TODO: Move this to the connected() method of DownstreamBridge | ||||||
|         target.addPlayer( user ); |         target.addPlayer( user ); | ||||||
|   | |||||||
| @@ -20,6 +20,7 @@ import java.util.Map; | |||||||
| import java.util.Objects; | import java.util.Objects; | ||||||
| import java.util.Queue; | import java.util.Queue; | ||||||
| import java.util.UUID; | import java.util.UUID; | ||||||
|  | import java.util.concurrent.CompletableFuture; | ||||||
| import java.util.concurrent.ConcurrentLinkedQueue; | import java.util.concurrent.ConcurrentLinkedQueue; | ||||||
| import java.util.logging.Level; | import java.util.logging.Level; | ||||||
| import lombok.Getter; | import lombok.Getter; | ||||||
| @@ -60,7 +61,9 @@ import net.md_5.bungee.protocol.packet.Kick; | |||||||
| import net.md_5.bungee.protocol.packet.PlayerListHeaderFooter; | import net.md_5.bungee.protocol.packet.PlayerListHeaderFooter; | ||||||
| import net.md_5.bungee.protocol.packet.PluginMessage; | import net.md_5.bungee.protocol.packet.PluginMessage; | ||||||
| import net.md_5.bungee.protocol.packet.SetCompression; | import net.md_5.bungee.protocol.packet.SetCompression; | ||||||
|  | import net.md_5.bungee.protocol.packet.StoreCookie; | ||||||
| import net.md_5.bungee.protocol.packet.SystemChat; | import net.md_5.bungee.protocol.packet.SystemChat; | ||||||
|  | import net.md_5.bungee.protocol.packet.Transfer; | ||||||
| import net.md_5.bungee.tab.ServerUnique; | import net.md_5.bungee.tab.ServerUnique; | ||||||
| import net.md_5.bungee.tab.TabList; | import net.md_5.bungee.tab.TabList; | ||||||
| import net.md_5.bungee.util.CaseInsensitiveSet; | import net.md_5.bungee.util.CaseInsensitiveSet; | ||||||
| @@ -771,4 +774,26 @@ public final class UserConnection implements ProxiedPlayer | |||||||
|     { |     { | ||||||
|         return serverSentScoreboard; |         return serverSentScoreboard; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public CompletableFuture<byte[]> retrieveCookie(String cookie) | ||||||
|  |     { | ||||||
|  |         return pendingConnection.retrieveCookie( cookie ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void storeCookie(String cookie, byte[] data) | ||||||
|  |     { | ||||||
|  |         Preconditions.checkState( getPendingConnection().getVersion() >= ProtocolConstants.MINECRAFT_1_20_5, "Cookies are only supported in 1.20.5 and above" ); | ||||||
|  |  | ||||||
|  |         unsafe().sendPacket( new StoreCookie( cookie, data ) ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void transfer(String host, int port) | ||||||
|  |     { | ||||||
|  |         Preconditions.checkState( getPendingConnection().getVersion() >= ProtocolConstants.MINECRAFT_1_20_5, "Transfers are only supported in 1.20.5 and above" ); | ||||||
|  |  | ||||||
|  |         unsafe().sendPacket( new Transfer( host, port ) ); | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -68,6 +68,7 @@ public class Configuration implements ProxyConfig | |||||||
|     private int compressionThreshold = 256; |     private int compressionThreshold = 256; | ||||||
|     private boolean preventProxyConnections; |     private boolean preventProxyConnections; | ||||||
|     private boolean forgeSupport; |     private boolean forgeSupport; | ||||||
|  |     private boolean rejectTransfers; | ||||||
|  |  | ||||||
|     public void load() |     public void load() | ||||||
|     { |     { | ||||||
| @@ -103,6 +104,7 @@ public class Configuration implements ProxyConfig | |||||||
|         compressionThreshold = adapter.getInt( "network_compression_threshold", compressionThreshold ); |         compressionThreshold = adapter.getInt( "network_compression_threshold", compressionThreshold ); | ||||||
|         preventProxyConnections = adapter.getBoolean( "prevent_proxy_connections", preventProxyConnections ); |         preventProxyConnections = adapter.getBoolean( "prevent_proxy_connections", preventProxyConnections ); | ||||||
|         forgeSupport = adapter.getBoolean( "forge_support", forgeSupport ); |         forgeSupport = adapter.getBoolean( "forge_support", forgeSupport ); | ||||||
|  |         rejectTransfers = adapter.getBoolean( "reject_transfers", rejectTransfers ); | ||||||
|  |  | ||||||
|         disabledCommands = new CaseInsensitiveSet( (Collection<String>) adapter.getList( "disabled_commands", Arrays.asList( "disabledcommandhere" ) ) ); |         disabledCommands = new CaseInsensitiveSet( (Collection<String>) adapter.getList( "disabled_commands", Arrays.asList( "disabledcommandhere" ) ) ); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -6,6 +6,7 @@ import com.google.common.collect.Lists; | |||||||
| import com.google.common.io.ByteArrayDataOutput; | import com.google.common.io.ByteArrayDataOutput; | ||||||
| import com.google.common.io.ByteStreams; | import com.google.common.io.ByteStreams; | ||||||
| import com.mojang.brigadier.arguments.StringArgumentType; | import com.mojang.brigadier.arguments.StringArgumentType; | ||||||
|  | import com.mojang.brigadier.builder.ArgumentBuilder; | ||||||
| import com.mojang.brigadier.builder.LiteralArgumentBuilder; | import com.mojang.brigadier.builder.LiteralArgumentBuilder; | ||||||
| import com.mojang.brigadier.builder.RequiredArgumentBuilder; | import com.mojang.brigadier.builder.RequiredArgumentBuilder; | ||||||
| import com.mojang.brigadier.context.StringRange; | import com.mojang.brigadier.context.StringRange; | ||||||
| @@ -19,9 +20,12 @@ import io.netty.channel.unix.DomainSocketAddress; | |||||||
| import java.io.DataInput; | import java.io.DataInput; | ||||||
| import java.net.InetSocketAddress; | import java.net.InetSocketAddress; | ||||||
| import java.util.ArrayList; | import java.util.ArrayList; | ||||||
|  | import java.util.Collection; | ||||||
|  | import java.util.IdentityHashMap; | ||||||
| import java.util.List; | import java.util.List; | ||||||
| import java.util.Locale; | import java.util.Locale; | ||||||
| import java.util.Map; | import java.util.Map; | ||||||
|  | import java.util.logging.Level; | ||||||
| import java.util.stream.Collectors; | import java.util.stream.Collectors; | ||||||
| import lombok.RequiredArgsConstructor; | import lombok.RequiredArgsConstructor; | ||||||
| import net.md_5.bungee.ServerConnection; | import net.md_5.bungee.ServerConnection; | ||||||
| @@ -35,6 +39,7 @@ import net.md_5.bungee.api.chat.TextComponent; | |||||||
| import net.md_5.bungee.api.config.ServerInfo; | import net.md_5.bungee.api.config.ServerInfo; | ||||||
| import net.md_5.bungee.api.connection.ProxiedPlayer; | import net.md_5.bungee.api.connection.ProxiedPlayer; | ||||||
| import net.md_5.bungee.api.connection.Server; | import net.md_5.bungee.api.connection.Server; | ||||||
|  | import net.md_5.bungee.api.event.CommandsDeclareEvent; | ||||||
| import net.md_5.bungee.api.event.PluginMessageEvent; | import net.md_5.bungee.api.event.PluginMessageEvent; | ||||||
| import net.md_5.bungee.api.event.ServerConnectEvent; | import net.md_5.bungee.api.event.ServerConnectEvent; | ||||||
| import net.md_5.bungee.api.event.ServerDisconnectEvent; | import net.md_5.bungee.api.event.ServerDisconnectEvent; | ||||||
| @@ -312,7 +317,7 @@ public class DownstreamBridge extends PacketHandler | |||||||
|             Preconditions.checkState( !serverBrand.contains( bungee.getName() ), "Cannot connect proxy to itself!" ); |             Preconditions.checkState( !serverBrand.contains( bungee.getName() ), "Cannot connect proxy to itself!" ); | ||||||
|  |  | ||||||
|             brand = ByteBufAllocator.DEFAULT.heapBuffer(); |             brand = ByteBufAllocator.DEFAULT.heapBuffer(); | ||||||
|             DefinedPacket.writeString( bungee.getName() + " (" + bungee.getVersion() + ")" + " <- " + serverBrand, brand ); |             DefinedPacket.writeString( bungee.getName() + " (" + bungee.getVersion() + ")" + " <- " + server.getInfo().getName() + " (" + serverBrand + ")", brand ); | ||||||
|             pluginMessage.setData( DefinedPacket.toArray( brand ) ); |             pluginMessage.setData( DefinedPacket.toArray( brand ) ); | ||||||
|             brand.release(); |             brand.release(); | ||||||
|             // changes in the packet are ignored so we need to send it manually |             // changes in the packet are ignored so we need to send it manually | ||||||
| @@ -745,6 +750,11 @@ public class DownstreamBridge extends PacketHandler | |||||||
|     { |     { | ||||||
|         boolean modified = false; |         boolean modified = false; | ||||||
|  |  | ||||||
|  |         CommandsDeclareEvent commandsDeclareEvent = new CommandsDeclareEvent( server, con, commands.getRoot() ); | ||||||
|  |         bungee.getPluginManager().callEvent( commandsDeclareEvent ); | ||||||
|  |  | ||||||
|  |         modified = commandsDeclareEvent.isModified(); | ||||||
|  |  | ||||||
|         for ( Map.Entry<String, Command> command : bungee.getPluginManager().getCommands() ) |         for ( Map.Entry<String, Command> command : bungee.getPluginManager().getCommands() ) | ||||||
|         { |         { | ||||||
|             if ( !bungee.getDisabledCommands().contains( command.getKey() ) && commands.getRoot().getChild( command.getKey() ) == null && command.getValue().hasPermission( con ) ) |             if ( !bungee.getDisabledCommands().contains( command.getKey() ) && commands.getRoot().getChild( command.getKey() ) == null && command.getValue().hasPermission( con ) ) | ||||||
| @@ -761,11 +771,65 @@ public class DownstreamBridge extends PacketHandler | |||||||
|  |  | ||||||
|         if ( modified ) |         if ( modified ) | ||||||
|         { |         { | ||||||
|  |             commands.setRoot( (com.mojang.brigadier.tree.RootCommandNode) filterCommandNode( commands.getRoot(), new IdentityHashMap<>() ) ); | ||||||
|             con.unsafe().sendPacket( commands ); |             con.unsafe().sendPacket( commands ); | ||||||
|             throw CancelSendSignal.INSTANCE; |             throw CancelSendSignal.INSTANCE; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /* | ||||||
|  |      * Create a deep copy of the provided command node but removes any node that are not accessible by the player | ||||||
|  |      * (using {@link CommandNode#getRequirement()}) | ||||||
|  |      */ | ||||||
|  |     private CommandNode filterCommandNode(CommandNode source, IdentityHashMap<CommandNode, CommandNode> commandNodeMapping) | ||||||
|  |     { | ||||||
|  |         CommandNode dest; | ||||||
|  |         if ( source instanceof com.mojang.brigadier.tree.RootCommandNode ) | ||||||
|  |         { | ||||||
|  |             dest = new com.mojang.brigadier.tree.RootCommandNode(); | ||||||
|  |         } else | ||||||
|  |         { | ||||||
|  |             if ( source.getRequirement() != null ) | ||||||
|  |             { | ||||||
|  |                 try | ||||||
|  |                 { | ||||||
|  |                     if ( !source.getRequirement().test( con ) ) | ||||||
|  |                     { | ||||||
|  |                         commandNodeMapping.put( source, null ); | ||||||
|  |                         return null; | ||||||
|  |                     } | ||||||
|  |                 } catch ( Throwable t ) | ||||||
|  |                 { | ||||||
|  |                     ProxyServer.getInstance().getLogger().log( Level.SEVERE, "Requirement test for command node " + source + " encountered an exception", t ); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             ArgumentBuilder destChildBuilder = source.createBuilder(); | ||||||
|  |             destChildBuilder.requires( sender -> true ); | ||||||
|  |             if ( destChildBuilder.getRedirect() != null ) | ||||||
|  |             { | ||||||
|  |                 if ( commandNodeMapping.containsKey( destChildBuilder.getRedirect() ) ) | ||||||
|  |                     destChildBuilder.redirect( commandNodeMapping.get( destChildBuilder.getRedirect() ) ); | ||||||
|  |                 else | ||||||
|  |                     destChildBuilder.redirect( filterCommandNode( destChildBuilder.getRedirect(), commandNodeMapping ) ); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             dest = destChildBuilder.build(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         commandNodeMapping.put( source, dest ); | ||||||
|  |  | ||||||
|  |         for ( CommandNode sourceChild : (Collection<CommandNode>) source.getChildren() ) | ||||||
|  |         { | ||||||
|  |             CommandNode destChild = filterCommandNode( sourceChild, commandNodeMapping ); | ||||||
|  |             if ( destChild == null ) | ||||||
|  |                 continue; | ||||||
|  |             dest.addChild( destChild ); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return dest; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public void handle(ServerData serverData) throws Exception |     public void handle(ServerData serverData) throws Exception | ||||||
|     { |     { | ||||||
|   | |||||||
| @@ -11,12 +11,19 @@ import java.security.GeneralSecurityException; | |||||||
| import java.security.MessageDigest; | import java.security.MessageDigest; | ||||||
| import java.time.Instant; | import java.time.Instant; | ||||||
| import java.util.HashSet; | import java.util.HashSet; | ||||||
|  | import java.util.LinkedList; | ||||||
|  | import java.util.Queue; | ||||||
| import java.util.Set; | import java.util.Set; | ||||||
| import java.util.UUID; | import java.util.UUID; | ||||||
|  | import java.util.concurrent.CompletableFuture; | ||||||
| import java.util.logging.Level; | import java.util.logging.Level; | ||||||
| import javax.crypto.SecretKey; | import javax.crypto.SecretKey; | ||||||
|  | import lombok.AllArgsConstructor; | ||||||
|  | import lombok.Data; | ||||||
|  | import lombok.EqualsAndHashCode; | ||||||
| import lombok.Getter; | import lombok.Getter; | ||||||
| import lombok.RequiredArgsConstructor; | import lombok.RequiredArgsConstructor; | ||||||
|  | import lombok.ToString; | ||||||
| import net.md_5.bungee.BungeeCord; | import net.md_5.bungee.BungeeCord; | ||||||
| import net.md_5.bungee.BungeeServerInfo; | import net.md_5.bungee.BungeeServerInfo; | ||||||
| import net.md_5.bungee.EncryptionUtil; | import net.md_5.bungee.EncryptionUtil; | ||||||
| @@ -51,6 +58,8 @@ import net.md_5.bungee.protocol.PacketWrapper; | |||||||
| import net.md_5.bungee.protocol.PlayerPublicKey; | import net.md_5.bungee.protocol.PlayerPublicKey; | ||||||
| import net.md_5.bungee.protocol.Protocol; | import net.md_5.bungee.protocol.Protocol; | ||||||
| import net.md_5.bungee.protocol.ProtocolConstants; | import net.md_5.bungee.protocol.ProtocolConstants; | ||||||
|  | import net.md_5.bungee.protocol.packet.CookieRequest; | ||||||
|  | import net.md_5.bungee.protocol.packet.CookieResponse; | ||||||
| import net.md_5.bungee.protocol.packet.EncryptionRequest; | import net.md_5.bungee.protocol.packet.EncryptionRequest; | ||||||
| import net.md_5.bungee.protocol.packet.EncryptionResponse; | import net.md_5.bungee.protocol.packet.EncryptionResponse; | ||||||
| import net.md_5.bungee.protocol.packet.Handshake; | import net.md_5.bungee.protocol.packet.Handshake; | ||||||
| @@ -86,6 +95,19 @@ public class InitialHandler extends PacketHandler implements PendingConnection | |||||||
|     @Getter |     @Getter | ||||||
|     private final Set<String> registeredChannels = new HashSet<>(); |     private final Set<String> registeredChannels = new HashSet<>(); | ||||||
|     private State thisState = State.HANDSHAKE; |     private State thisState = State.HANDSHAKE; | ||||||
|  |     private final Queue<CookieFuture> requestedCookies = new LinkedList<>(); | ||||||
|  |  | ||||||
|  |     @Data | ||||||
|  |     @ToString | ||||||
|  |     @EqualsAndHashCode | ||||||
|  |     @AllArgsConstructor | ||||||
|  |     public static class CookieFuture | ||||||
|  |     { | ||||||
|  |  | ||||||
|  |         private String cookie; | ||||||
|  |         private CompletableFuture<byte[]> future; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     private final Unsafe unsafe = new Unsafe() |     private final Unsafe unsafe = new Unsafe() | ||||||
|     { |     { | ||||||
|         @Override |         @Override | ||||||
| @@ -109,8 +131,19 @@ public class InitialHandler extends PacketHandler implements PendingConnection | |||||||
|     private boolean legacy; |     private boolean legacy; | ||||||
|     @Getter |     @Getter | ||||||
|     private String extraDataInHandshake = ""; |     private String extraDataInHandshake = ""; | ||||||
|  |     @Getter | ||||||
|  |     private boolean transferred; | ||||||
|     private UserConnection userCon; |     private UserConnection userCon; | ||||||
|  |  | ||||||
|  |     @Getter | ||||||
|  |     private boolean duplication = false; | ||||||
|  |  | ||||||
|  |     @Getter | ||||||
|  |     private String realName = null; | ||||||
|  |  | ||||||
|  |     @Getter | ||||||
|  |     private UUID realId = null; | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public boolean shouldHandle(PacketWrapper packet) throws Exception |     public boolean shouldHandle(PacketWrapper packet) throws Exception | ||||||
|     { |     { | ||||||
| @@ -349,6 +382,8 @@ public class InitialHandler extends PacketHandler implements PendingConnection | |||||||
|                 ch.setProtocol( Protocol.STATUS ); |                 ch.setProtocol( Protocol.STATUS ); | ||||||
|                 break; |                 break; | ||||||
|             case 2: |             case 2: | ||||||
|  |             case 3: | ||||||
|  |                 transferred = handshake.getRequestedProtocol() == 3; | ||||||
|                 // Login |                 // Login | ||||||
|                 bungee.getLogger().log( Level.INFO, "{0} has connected", this ); |                 bungee.getLogger().log( Level.INFO, "{0} has connected", this ); | ||||||
|                 thisState = State.USERNAME; |                 thisState = State.USERNAME; | ||||||
| @@ -365,6 +400,12 @@ public class InitialHandler extends PacketHandler implements PendingConnection | |||||||
|                     } |                     } | ||||||
|                     return; |                     return; | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|  |                 if ( transferred && bungee.config.isRejectTransfers() ) | ||||||
|  |                 { | ||||||
|  |                     disconnect( bungee.getTranslation( "reject_transfer" ) ); | ||||||
|  |                     return; | ||||||
|  |                 } | ||||||
|                 break; |                 break; | ||||||
|             default: |             default: | ||||||
|                 throw new QuietException( "Cannot request protocol " + handshake.getRequestedProtocol() ); |                 throw new QuietException( "Cannot request protocol " + handshake.getRequestedProtocol() ); | ||||||
| @@ -408,6 +449,7 @@ public class InitialHandler extends PacketHandler implements PendingConnection | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         this.loginRequest = loginRequest; |         this.loginRequest = loginRequest; | ||||||
|  |         setName( realName = loginRequest.getData() ); | ||||||
|  |  | ||||||
|         int limit = BungeeCord.getInstance().config.getPlayerLimit(); |         int limit = BungeeCord.getInstance().config.getPlayerLimit(); | ||||||
|         if ( limit > 0 && bungee.getOnlineCount() >= limit ) |         if ( limit > 0 && bungee.getOnlineCount() >= limit ) | ||||||
| @@ -416,14 +458,6 @@ public class InitialHandler extends PacketHandler implements PendingConnection | |||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         // If offline mode and they are already on, don't allow connect |  | ||||||
|         // We can just check by UUID here as names are based on UUID |  | ||||||
|         if ( !isOnlineMode() && bungee.getPlayer( getUniqueId() ) != null ) |  | ||||||
|         { |  | ||||||
|             disconnect( bungee.getTranslation( "already_connected_proxy" ) ); |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         Callback<PreLoginEvent> callback = new Callback<PreLoginEvent>() |         Callback<PreLoginEvent> callback = new Callback<PreLoginEvent>() | ||||||
|         { |         { | ||||||
|  |  | ||||||
| @@ -440,6 +474,16 @@ public class InitialHandler extends PacketHandler implements PendingConnection | |||||||
|                 { |                 { | ||||||
|                     return; |                     return; | ||||||
|                 } |                 } | ||||||
|  |                 if ( !realName.equals( name ) ) | ||||||
|  |                 { | ||||||
|  |                     // Floodgate changes the name attribute with reflexion | ||||||
|  |                     setName( realName = name ); | ||||||
|  |                 } | ||||||
|  |                 if ( uniqueId != null ) | ||||||
|  |                 { | ||||||
|  |                     // if plugin called setUniqueId() | ||||||
|  |                     realId = uniqueId; | ||||||
|  |                 } | ||||||
|                 if ( onlineMode ) |                 if ( onlineMode ) | ||||||
|                 { |                 { | ||||||
|                     thisState = State.ENCRYPT; |                     thisState = State.ENCRYPT; | ||||||
| @@ -494,8 +538,8 @@ public class InitialHandler extends PacketHandler implements PendingConnection | |||||||
|                     if ( obj != null && obj.getId() != null ) |                     if ( obj != null && obj.getId() != null ) | ||||||
|                     { |                     { | ||||||
|                         loginProfile = obj; |                         loginProfile = obj; | ||||||
|                         name = obj.getName(); |                         setName( realName = obj.getName() ); | ||||||
|                         uniqueId = Util.getUUID( obj.getId() ); |                         uniqueId = realId = Util.getUUID( obj.getId() ); | ||||||
|                         finish(); |                         finish(); | ||||||
|                         return; |                         return; | ||||||
|                     } |                     } | ||||||
| @@ -513,10 +557,25 @@ public class InitialHandler extends PacketHandler implements PendingConnection | |||||||
|  |  | ||||||
|     private void finish() |     private void finish() | ||||||
|     { |     { | ||||||
|         offlineId = UUID.nameUUIDFromBytes( ( "OfflinePlayer:" + getName() ).getBytes( StandardCharsets.UTF_8 ) ); |         if ( uniqueId == null ) // offline mode and no plugin used setUniqueId() | ||||||
|         if ( uniqueId == null ) |  | ||||||
|         { |         { | ||||||
|             uniqueId = offlineId; |             uniqueId = realId = offlineId; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /* | ||||||
|  |          * At this point, player is either authenticated by Mojang (online mode), | ||||||
|  |          * by a plugin (Floodgate ?) or the offline id is set. | ||||||
|  |          */ | ||||||
|  |         ProxiedPlayer existingPlayer = bungee.getPlayer( uniqueId ); | ||||||
|  |         if ( existingPlayer != null && existingPlayer.hasPermission( "bungeecord.multiple_connect" ) ) | ||||||
|  |         { | ||||||
|  |             UUID newId = generateDuplicatedId( uniqueId ); | ||||||
|  |             if ( !uniqueId.equals( newId ) ) | ||||||
|  |             { | ||||||
|  |                 uniqueId = newId; | ||||||
|  |                 setName( name + "." + getDuplicationIndex( newId ) ); | ||||||
|  |                 duplication = true; | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if ( BungeeCord.getInstance().config.isEnforceSecureProfile() ) |         if ( BungeeCord.getInstance().config.isEnforceSecureProfile() ) | ||||||
| @@ -621,6 +680,13 @@ public class InitialHandler extends PacketHandler implements PendingConnection | |||||||
|  |  | ||||||
|         ch.getHandle().pipeline().get( HandlerBoss.class ).setHandler( new UpstreamBridge( bungee, userCon ) ); |         ch.getHandle().pipeline().get( HandlerBoss.class ).setHandler( new UpstreamBridge( bungee, userCon ) ); | ||||||
|         bungee.getPluginManager().callEvent( new PostLoginEvent( userCon ) ); |         bungee.getPluginManager().callEvent( new PostLoginEvent( userCon ) ); | ||||||
|  |  | ||||||
|  |         // #3612: Don't progress further if disconnected during event | ||||||
|  |         if ( ch.isClosed() ) | ||||||
|  |         { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|         ServerInfo server; |         ServerInfo server; | ||||||
|         if ( bungee.getReconnectHandler() != null ) |         if ( bungee.getReconnectHandler() != null ) | ||||||
|         { |         { | ||||||
| @@ -643,6 +709,34 @@ public class InitialHandler extends PacketHandler implements PendingConnection | |||||||
|         disconnect( "Unexpected custom LoginPayloadResponse" ); |         disconnect( "Unexpected custom LoginPayloadResponse" ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void handle(CookieResponse cookieResponse) | ||||||
|  |     { | ||||||
|  |         // be careful, backend server could also make the client send a cookie response | ||||||
|  |         CookieFuture future; | ||||||
|  |         synchronized ( requestedCookies ) | ||||||
|  |         { | ||||||
|  |             future = requestedCookies.peek(); | ||||||
|  |             if ( future != null ) | ||||||
|  |             { | ||||||
|  |                 if ( future.cookie.equals( cookieResponse.getCookie() ) ) | ||||||
|  |                 { | ||||||
|  |                     Preconditions.checkState( future == requestedCookies.poll(), "requestedCookies queue mismatch" ); | ||||||
|  |                 } else | ||||||
|  |                 { | ||||||
|  |                     future = null; // leave for handling by backend | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if ( future != null ) | ||||||
|  |         { | ||||||
|  |             future.getFuture().complete( cookieResponse.getData() ); | ||||||
|  |  | ||||||
|  |             throw CancelSendSignal.INSTANCE; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public void disconnect(String reason) |     public void disconnect(String reason) | ||||||
|     { |     { | ||||||
| @@ -679,6 +773,59 @@ public class InitialHandler extends PacketHandler implements PendingConnection | |||||||
|         return ( name != null ) ? name : ( loginRequest == null ) ? null : loginRequest.getData(); |         return ( name != null ) ? name : ( loginRequest == null ) ? null : loginRequest.getData(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     private void setName(String name) | ||||||
|  |     { | ||||||
|  |         this.name = name; | ||||||
|  |         if ( loginRequest != null ) | ||||||
|  |         { | ||||||
|  |             loginRequest.setData( name ); // name transmitted to Spigot server | ||||||
|  |         } | ||||||
|  |         updateOfflineId(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private UUID generateDuplicatedId(UUID base) | ||||||
|  |     { | ||||||
|  |         // UUID version: offline = 3 ; Java online mode = 4 ; Floodgate xUID = 0 (and must be kept 0) | ||||||
|  |         // UUID variant: offline = 0xx ; Java online mode = 10x ; Floodgate xUID = xxx | ||||||
|  |         if ( base.version() == 0 ) | ||||||
|  |         { | ||||||
|  |             /* | ||||||
|  |              * Floodgate’s xUID converted to UUID are not supported | ||||||
|  |              * because it requires the 64 MSBs to be 0 (or Floodgate API would not | ||||||
|  |              * recognize a Bedrock account) and we cannot modify the 64 LSBs | ||||||
|  |              * without risking a collision with the xUID of another Bedrock account | ||||||
|  |              */ | ||||||
|  |             return base; | ||||||
|  |         } | ||||||
|  |         long MSB = base.getMostSignificantBits(); | ||||||
|  |         long LSB = base.getLeastSignificantBits(); | ||||||
|  |  | ||||||
|  |         MSB &= 0xFFFFFFFF_FFFF_70FFL; // reset bits we need | ||||||
|  |         MSB |= 0x00000000_0000_8000L; // set version to + 8 the current version | ||||||
|  |  | ||||||
|  |         for ( int i = 1; i <= 9; i++ ) | ||||||
|  |         { | ||||||
|  |             long newMSB = MSB | i << 8; | ||||||
|  |             UUID newUUID = new UUID( newMSB, LSB ); | ||||||
|  |             if ( bungee.getPlayer( newUUID ) != null ) | ||||||
|  |             { | ||||||
|  |                 continue; | ||||||
|  |             } | ||||||
|  |             return newUUID; | ||||||
|  |         } | ||||||
|  |         return base; // there are too many duplicated connections for this player | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private static int getDuplicationIndex(UUID duplicatedId) | ||||||
|  |     { | ||||||
|  |         return (int) ( duplicatedId.getMostSignificantBits() >> 8 ) & 0xF; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private void updateOfflineId() | ||||||
|  |     { | ||||||
|  |         offlineId = UUID.nameUUIDFromBytes( ( "OfflinePlayer:" + getName() ).getBytes( StandardCharsets.UTF_8 ) ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public int getVersion() |     public int getVersion() | ||||||
|     { |     { | ||||||
| @@ -775,4 +922,26 @@ public class InitialHandler extends PacketHandler implements PendingConnection | |||||||
|             brandMessage = input; |             brandMessage = input; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public CompletableFuture<byte[]> retrieveCookie(String cookie) | ||||||
|  |     { | ||||||
|  |         Preconditions.checkState( getVersion() >= ProtocolConstants.MINECRAFT_1_20_5, "Cookies are only supported in 1.20.5 and above" ); | ||||||
|  |         Preconditions.checkState( loginRequest != null, "Cannot retrieve cookies for status or legacy connections" ); | ||||||
|  |  | ||||||
|  |         if ( cookie.indexOf( ':' ) == -1 ) | ||||||
|  |         { | ||||||
|  |             // if we request an invalid resource location (no prefix) the client will respond with "minecraft:" prefix | ||||||
|  |             cookie = "minecraft:" + cookie; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         CompletableFuture<byte[]> future = new CompletableFuture<>(); | ||||||
|  |         synchronized ( requestedCookies ) | ||||||
|  |         { | ||||||
|  |             requestedCookies.add( new CookieFuture( cookie, future ) ); | ||||||
|  |         } | ||||||
|  |         unsafe.sendPacket( new CookieRequest( cookie ) ); | ||||||
|  |  | ||||||
|  |         return future; | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -6,7 +6,6 @@ import com.mojang.brigadier.suggestion.Suggestion; | |||||||
| import com.mojang.brigadier.suggestion.Suggestions; | import com.mojang.brigadier.suggestion.Suggestions; | ||||||
| import io.netty.channel.Channel; | import io.netty.channel.Channel; | ||||||
| import java.util.ArrayList; | import java.util.ArrayList; | ||||||
| import java.util.LinkedList; |  | ||||||
| import java.util.List; | import java.util.List; | ||||||
| import java.util.UUID; | import java.util.UUID; | ||||||
| import net.md_5.bungee.BungeeCord; | import net.md_5.bungee.BungeeCord; | ||||||
| @@ -21,6 +20,7 @@ import net.md_5.bungee.api.event.PlayerDisconnectEvent; | |||||||
| import net.md_5.bungee.api.event.PluginMessageEvent; | import net.md_5.bungee.api.event.PluginMessageEvent; | ||||||
| import net.md_5.bungee.api.event.SettingsChangedEvent; | import net.md_5.bungee.api.event.SettingsChangedEvent; | ||||||
| import net.md_5.bungee.api.event.TabCompleteEvent; | import net.md_5.bungee.api.event.TabCompleteEvent; | ||||||
|  | import net.md_5.bungee.api.event.TabCompleteRequestEvent; | ||||||
| import net.md_5.bungee.entitymap.EntityMap; | import net.md_5.bungee.entitymap.EntityMap; | ||||||
| import net.md_5.bungee.forge.ForgeConstants; | import net.md_5.bungee.forge.ForgeConstants; | ||||||
| import net.md_5.bungee.netty.ChannelWrapper; | import net.md_5.bungee.netty.ChannelWrapper; | ||||||
| @@ -32,6 +32,7 @@ import net.md_5.bungee.protocol.packet.Chat; | |||||||
| import net.md_5.bungee.protocol.packet.ClientChat; | import net.md_5.bungee.protocol.packet.ClientChat; | ||||||
| import net.md_5.bungee.protocol.packet.ClientCommand; | import net.md_5.bungee.protocol.packet.ClientCommand; | ||||||
| import net.md_5.bungee.protocol.packet.ClientSettings; | import net.md_5.bungee.protocol.packet.ClientSettings; | ||||||
|  | import net.md_5.bungee.protocol.packet.CookieResponse; | ||||||
| import net.md_5.bungee.protocol.packet.FinishConfiguration; | import net.md_5.bungee.protocol.packet.FinishConfiguration; | ||||||
| import net.md_5.bungee.protocol.packet.KeepAlive; | import net.md_5.bungee.protocol.packet.KeepAlive; | ||||||
| import net.md_5.bungee.protocol.packet.LoginAcknowledged; | import net.md_5.bungee.protocol.packet.LoginAcknowledged; | ||||||
| @@ -128,7 +129,7 @@ public class UpstreamBridge extends PacketHandler | |||||||
|     @Override |     @Override | ||||||
|     public boolean shouldHandle(PacketWrapper packet) throws Exception |     public boolean shouldHandle(PacketWrapper packet) throws Exception | ||||||
|     { |     { | ||||||
|         return con.getServer() != null || packet.packet instanceof PluginMessage; |         return con.getServer() != null || packet.packet instanceof PluginMessage || packet.packet instanceof CookieResponse; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
| @@ -234,32 +235,42 @@ public class UpstreamBridge extends PacketHandler | |||||||
|         TabCompleteEvent tabCompleteEvent = new TabCompleteEvent( con, con.getServer(), tabComplete.getCursor(), suggestions ); |         TabCompleteEvent tabCompleteEvent = new TabCompleteEvent( con, con.getServer(), tabComplete.getCursor(), suggestions ); | ||||||
|         bungee.getPluginManager().callEvent( tabCompleteEvent ); |         bungee.getPluginManager().callEvent( tabCompleteEvent ); | ||||||
|  |  | ||||||
|         if ( tabCompleteEvent.isCancelled() ) |         List<String> legacyResults = tabCompleteEvent.getSuggestions(); | ||||||
|  |  | ||||||
|  |         int start = tabComplete.getCursor().lastIndexOf( ' ' ) + 1; | ||||||
|  |         int end = tabComplete.getCursor().length(); | ||||||
|  |         StringRange lastArgumentRange = StringRange.between( start, end ); | ||||||
|  |  | ||||||
|  |         List<Suggestion> brigadier = new ArrayList<>( legacyResults.size() ); | ||||||
|  |         for ( String s : legacyResults ) | ||||||
|  |         { | ||||||
|  |             brigadier.add( new Suggestion( lastArgumentRange, s ) ); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         TabCompleteRequestEvent tabCompleteRequestEvent = new TabCompleteRequestEvent( con, con.getServer(), tabComplete.getCursor(), lastArgumentRange, new Suggestions( lastArgumentRange, brigadier ) ); | ||||||
|  |         tabCompleteRequestEvent.setCancelled( tabCompleteEvent.isCancelled() ); | ||||||
|  |         bungee.getPluginManager().callEvent( tabCompleteRequestEvent ); | ||||||
|  |  | ||||||
|  |         if ( tabCompleteRequestEvent.isCancelled() ) | ||||||
|         { |         { | ||||||
|             throw CancelSendSignal.INSTANCE; |             throw CancelSendSignal.INSTANCE; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         List<String> results = tabCompleteEvent.getSuggestions(); |         Suggestions brigadierResults = tabCompleteRequestEvent.getSuggestions(); | ||||||
|         if ( !results.isEmpty() ) |  | ||||||
|  |         if ( !brigadierResults.isEmpty() ) | ||||||
|         { |         { | ||||||
|             // Unclear how to handle 1.13 commands at this point. Because we don't inject into the command packets we are unlikely to get this far unless |  | ||||||
|             // Bungee plugins are adding results for commands they don't own anyway |  | ||||||
|             if ( con.getPendingConnection().getVersion() < ProtocolConstants.MINECRAFT_1_13 ) |             if ( con.getPendingConnection().getVersion() < ProtocolConstants.MINECRAFT_1_13 ) | ||||||
|             { |             { | ||||||
|  |                 List<String> results = new ArrayList<>( brigadierResults.getList().size() ); | ||||||
|  |                 for ( Suggestion s : brigadierResults.getList() ) | ||||||
|  |                 { | ||||||
|  |                     results.add( s.getText() ); | ||||||
|  |                 } | ||||||
|                 con.unsafe().sendPacket( new TabCompleteResponse( results ) ); |                 con.unsafe().sendPacket( new TabCompleteResponse( results ) ); | ||||||
|             } else |             } else | ||||||
|             { |             { | ||||||
|                 int start = tabComplete.getCursor().lastIndexOf( ' ' ) + 1; |                 con.unsafe().sendPacket( new TabCompleteResponse( tabComplete.getTransactionId(), brigadierResults ) ); | ||||||
|                 int end = tabComplete.getCursor().length(); |  | ||||||
|                 StringRange range = StringRange.between( start, end ); |  | ||||||
|  |  | ||||||
|                 List<Suggestion> brigadier = new LinkedList<>(); |  | ||||||
|                 for ( String s : results ) |  | ||||||
|                 { |  | ||||||
|                     brigadier.add( new Suggestion( range, s ) ); |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|                 con.unsafe().sendPacket( new TabCompleteResponse( tabComplete.getTransactionId(), new Suggestions( range, brigadier ) ) ); |  | ||||||
|             } |             } | ||||||
|             throw CancelSendSignal.INSTANCE; |             throw CancelSendSignal.INSTANCE; | ||||||
|         } |         } | ||||||
| @@ -363,6 +374,12 @@ public class UpstreamBridge extends PacketHandler | |||||||
|         con.sendQueuedPackets(); |         con.sendQueuedPackets(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void handle(CookieResponse cookieResponse) throws Exception | ||||||
|  |     { | ||||||
|  |         con.getPendingConnection().handle( cookieResponse ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public String toString() |     public String toString() | ||||||
|     { |     { | ||||||
|   | |||||||
| @@ -86,6 +86,8 @@ public abstract class EntityMap | |||||||
|                 return EntityMap_1_16_2.INSTANCE_1_20_2; |                 return EntityMap_1_16_2.INSTANCE_1_20_2; | ||||||
|             case ProtocolConstants.MINECRAFT_1_20_3: |             case ProtocolConstants.MINECRAFT_1_20_3: | ||||||
|                 return EntityMap_1_16_2.INSTANCE_1_20_3; |                 return EntityMap_1_16_2.INSTANCE_1_20_3; | ||||||
|  |             case ProtocolConstants.MINECRAFT_1_20_5: | ||||||
|  |                 return EntityMap_1_16_2.INSTANCE_1_20_5; | ||||||
|         } |         } | ||||||
|         throw new RuntimeException( "Version " + version + " has no entity map" ); |         throw new RuntimeException( "Version " + version + " has no entity map" ); | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -22,6 +22,7 @@ class EntityMap_1_16_2 extends EntityMap | |||||||
|     static final EntityMap_1_16_2 INSTANCE_1_19_4 = new EntityMap_1_16_2( 0x03, 0x30 ); |     static final EntityMap_1_16_2 INSTANCE_1_19_4 = new EntityMap_1_16_2( 0x03, 0x30 ); | ||||||
|     static final EntityMap_1_16_2 INSTANCE_1_20_2 = new EntityMap_1_16_2( -1, 0x33 ); |     static final EntityMap_1_16_2 INSTANCE_1_20_2 = new EntityMap_1_16_2( -1, 0x33 ); | ||||||
|     static final EntityMap_1_16_2 INSTANCE_1_20_3 = new EntityMap_1_16_2( -1, 0x34 ); |     static final EntityMap_1_16_2 INSTANCE_1_20_3 = new EntityMap_1_16_2( -1, 0x34 ); | ||||||
|  |     static final EntityMap_1_16_2 INSTANCE_1_20_5 = new EntityMap_1_16_2( -1, 0x36 ); | ||||||
|     // |     // | ||||||
|     private final int spawnPlayerId; |     private final int spawnPlayerId; | ||||||
|     private final int spectateId; |     private final int spectateId; | ||||||
|   | |||||||
| @@ -1,34 +0,0 @@ | |||||||
| package net.md_5.bungee.module; |  | ||||||
|  |  | ||||||
| import com.google.common.io.ByteStreams; |  | ||||||
| import com.google.common.io.Files; |  | ||||||
| import java.io.IOException; |  | ||||||
| import java.net.URL; |  | ||||||
| import java.net.URLConnection; |  | ||||||
| import lombok.Data; |  | ||||||
| import net.md_5.bungee.Util; |  | ||||||
|  |  | ||||||
| @Data |  | ||||||
| public class JenkinsModuleSource implements ModuleSource |  | ||||||
| { |  | ||||||
|  |  | ||||||
|     @Override |  | ||||||
|     public void retrieve(ModuleSpec module, ModuleVersion version) |  | ||||||
|     { |  | ||||||
|         System.out.println( "Attempting to Jenkins download module " + module.getName() + " v" + version.getBuild() ); |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             URL website = new URL( "https://ci.md-5.net/job/BungeeCord/" + version.getBuild() + "/artifact/module/" + module.getName().replace( '_', '-' ) + "/target/" + module.getName() + ".jar" ); |  | ||||||
|             URLConnection con = website.openConnection(); |  | ||||||
|             // 15 second timeout at various stages |  | ||||||
|             con.setConnectTimeout( 15000 ); |  | ||||||
|             con.setReadTimeout( 15000 ); |  | ||||||
|  |  | ||||||
|             Files.write( ByteStreams.toByteArray( con.getInputStream() ), module.getFile() ); |  | ||||||
|             System.out.println( "Download complete" ); |  | ||||||
|         } catch ( IOException ex ) |  | ||||||
|         { |  | ||||||
|             System.out.println( "Failed to download: " + Util.exception( ex ) ); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,155 +0,0 @@ | |||||||
| package net.md_5.bungee.module; |  | ||||||
|  |  | ||||||
| import com.google.common.base.Preconditions; |  | ||||||
| import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; |  | ||||||
| import java.io.File; |  | ||||||
| import java.io.FileInputStream; |  | ||||||
| import java.io.FileWriter; |  | ||||||
| import java.io.InputStream; |  | ||||||
| import java.net.URI; |  | ||||||
| import java.util.ArrayList; |  | ||||||
| import java.util.Collection; |  | ||||||
| import java.util.HashMap; |  | ||||||
| import java.util.List; |  | ||||||
| import java.util.Map; |  | ||||||
| import java.util.jar.JarEntry; |  | ||||||
| import java.util.jar.JarFile; |  | ||||||
| import java.util.logging.Level; |  | ||||||
| import net.md_5.bungee.api.ProxyServer; |  | ||||||
| import net.md_5.bungee.api.plugin.PluginDescription; |  | ||||||
| import net.md_5.bungee.util.CaseInsensitiveMap; |  | ||||||
| import org.yaml.snakeyaml.DumperOptions; |  | ||||||
| import org.yaml.snakeyaml.Yaml; |  | ||||||
|  |  | ||||||
| public class ModuleManager |  | ||||||
| { |  | ||||||
|  |  | ||||||
|     private final Map<String, ModuleSource> knownSources = new HashMap<>(); |  | ||||||
|  |  | ||||||
|     public ModuleManager() |  | ||||||
|     { |  | ||||||
|         knownSources.put( "jenkins", new JenkinsModuleSource() ); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     // CHECKSTYLE:OFF |  | ||||||
|     @SuppressFBWarnings( |  | ||||||
|             { |  | ||||||
|                 "SF_SWITCH_FALLTHROUGH", "SF_SWITCH_NO_DEFAULT" |  | ||||||
|             }) |  | ||||||
|     // CHECKSTYLE:ON |  | ||||||
|     public void load(ProxyServer proxy, File moduleDirectory) throws Exception |  | ||||||
|     { |  | ||||||
|         moduleDirectory.mkdir(); |  | ||||||
|  |  | ||||||
|         ModuleVersion bungeeVersion = ModuleVersion.parse( proxy.getVersion() ); |  | ||||||
|         if ( bungeeVersion == null ) |  | ||||||
|         { |  | ||||||
|             System.out.println( "Couldn't detect bungee version. Custom build?" ); |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         List<ModuleSpec> modules = new ArrayList<>(); |  | ||||||
|         File configFile = new File( "modules.yml" ); |  | ||||||
|         // Start Yaml |  | ||||||
|         DumperOptions options = new DumperOptions(); |  | ||||||
|         options.setDefaultFlowStyle( DumperOptions.FlowStyle.BLOCK ); |  | ||||||
|         Yaml yaml = new Yaml( options ); |  | ||||||
|  |  | ||||||
|         Map<String, Object> config; |  | ||||||
|  |  | ||||||
|         configFile.createNewFile(); |  | ||||||
|         try ( InputStream is = new FileInputStream( configFile ) ) |  | ||||||
|         { |  | ||||||
|             config = (Map) yaml.load( is ); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if ( config == null ) |  | ||||||
|         { |  | ||||||
|             config = new CaseInsensitiveMap<>(); |  | ||||||
|         } else |  | ||||||
|         { |  | ||||||
|             config = new CaseInsensitiveMap<>( config ); |  | ||||||
|         } |  | ||||||
|         // End yaml |  | ||||||
|  |  | ||||||
|         List<String> defaults = new ArrayList<>(); |  | ||||||
|         Object readModules = config.get( "modules" ); |  | ||||||
|         if ( readModules != null ) |  | ||||||
|         { |  | ||||||
|             defaults.addAll( (Collection) readModules ); |  | ||||||
|         } |  | ||||||
|         int version = ( config.containsKey( "version" ) ) ? (int) config.get( "version" ) : 0; |  | ||||||
|         switch ( version ) |  | ||||||
|         { |  | ||||||
|             case 0: |  | ||||||
|                 defaults.add( "jenkins://cmd_alert" ); |  | ||||||
|                 defaults.add( "jenkins://cmd_find" ); |  | ||||||
|                 defaults.add( "jenkins://cmd_list" ); |  | ||||||
|                 defaults.add( "jenkins://cmd_send" ); |  | ||||||
|                 defaults.add( "jenkins://cmd_server" ); |  | ||||||
|             case 1: |  | ||||||
|                 defaults.add( "jenkins://reconnect_yaml" ); |  | ||||||
|         } |  | ||||||
|         config.put( "modules", defaults ); |  | ||||||
|         config.put( "version", 2 ); |  | ||||||
|  |  | ||||||
|         try ( FileWriter wr = new FileWriter( configFile ) ) |  | ||||||
|         { |  | ||||||
|             yaml.dump( config, wr ); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         for ( String s : (List<String>) config.get( "modules" ) ) |  | ||||||
|         { |  | ||||||
|             URI uri = new URI( s ); |  | ||||||
|  |  | ||||||
|             ModuleSource source = knownSources.get( uri.getScheme() ); |  | ||||||
|             if ( source == null ) |  | ||||||
|             { |  | ||||||
|                 System.out.println( "Unknown module source: " + s ); |  | ||||||
|                 continue; |  | ||||||
|             } |  | ||||||
|             String name = uri.getAuthority(); |  | ||||||
|             if ( name == null ) |  | ||||||
|             { |  | ||||||
|                 System.out.println( "Unknown module host: " + s ); |  | ||||||
|                 continue; |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             ModuleSpec spec = new ModuleSpec( name, new File( moduleDirectory, name + ".jar" ), source ); |  | ||||||
|             modules.add( spec ); |  | ||||||
|             System.out.println( "Discovered module: " + spec ); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         for ( ModuleSpec module : modules ) |  | ||||||
|         { |  | ||||||
|             ModuleVersion moduleVersion = ( module.getFile().exists() ) ? getVersion( module.getFile() ) : null; |  | ||||||
|  |  | ||||||
|             if ( !bungeeVersion.equals( moduleVersion ) ) |  | ||||||
|             { |  | ||||||
|                 System.out.println( "Attempting to update plugin from " + moduleVersion + " to " + bungeeVersion ); |  | ||||||
|                 module.getProvider().retrieve( module, bungeeVersion ); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @SuppressFBWarnings("REC_CATCH_EXCEPTION") |  | ||||||
|     private ModuleVersion getVersion(File file) |  | ||||||
|     { |  | ||||||
|         try ( JarFile jar = new JarFile( file ) ) |  | ||||||
|         { |  | ||||||
|             JarEntry pdf = jar.getJarEntry( "plugin.yml" ); |  | ||||||
|             Preconditions.checkNotNull( pdf, "Plugin must have a plugin.yml" ); |  | ||||||
|  |  | ||||||
|             try ( InputStream in = jar.getInputStream( pdf ) ) |  | ||||||
|             { |  | ||||||
|                 PluginDescription desc = new Yaml().loadAs( in, PluginDescription.class ); |  | ||||||
|                 return ModuleVersion.parse( desc.getVersion() ); |  | ||||||
|             } |  | ||||||
|         } catch ( Exception ex ) |  | ||||||
|         { |  | ||||||
|             ProxyServer.getInstance().getLogger().log( Level.WARNING, "Could not check module from file " + file, ex ); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         return null; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,7 +0,0 @@ | |||||||
| package net.md_5.bungee.module; |  | ||||||
|  |  | ||||||
| interface ModuleSource |  | ||||||
| { |  | ||||||
|  |  | ||||||
|     void retrieve(ModuleSpec module, ModuleVersion version); |  | ||||||
| } |  | ||||||
| @@ -1,13 +0,0 @@ | |||||||
| package net.md_5.bungee.module; |  | ||||||
|  |  | ||||||
| import java.io.File; |  | ||||||
| import lombok.Data; |  | ||||||
|  |  | ||||||
| @Data |  | ||||||
| public class ModuleSpec |  | ||||||
| { |  | ||||||
|  |  | ||||||
|     private final String name; |  | ||||||
|     private final File file; |  | ||||||
|     private final ModuleSource provider; |  | ||||||
| } |  | ||||||
| @@ -1,35 +0,0 @@ | |||||||
| package net.md_5.bungee.module; |  | ||||||
|  |  | ||||||
| import lombok.AccessLevel; |  | ||||||
| import lombok.Data; |  | ||||||
| import lombok.RequiredArgsConstructor; |  | ||||||
|  |  | ||||||
| @Data |  | ||||||
| @RequiredArgsConstructor(access = AccessLevel.PRIVATE) |  | ||||||
| public class ModuleVersion |  | ||||||
| { |  | ||||||
|  |  | ||||||
|     private final String build; |  | ||||||
|     private final String git; |  | ||||||
|  |  | ||||||
|     public static ModuleVersion parse(String version) |  | ||||||
|     { |  | ||||||
|         int lastColon = version.lastIndexOf( ':' ); |  | ||||||
|         int secondLastColon = version.lastIndexOf( ':', lastColon - 1 ); |  | ||||||
|  |  | ||||||
|         if ( lastColon == -1 || secondLastColon == -1 ) |  | ||||||
|         { |  | ||||||
|             return null; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         String buildNumber = version.substring( lastColon + 1, version.length() ); |  | ||||||
|         String gitCommit = version.substring( secondLastColon + 1, lastColon ).replaceAll( "\"", "" ); |  | ||||||
|  |  | ||||||
|         if ( "unknown".equals( buildNumber ) || "unknown".equals( gitCommit ) ) |  | ||||||
|         { |  | ||||||
|             return null; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         return new ModuleVersion( buildNumber, gitCommit ); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -40,3 +40,4 @@ command_perms_permission=\u00a79- {0} | |||||||
| command_ip=\u00a79IP of {0} is {1} | command_ip=\u00a79IP of {0} is {1} | ||||||
| illegal_chat_characters=\u00a7cIllegal characters in chat ({0}) | illegal_chat_characters=\u00a7cIllegal characters in chat ({0}) | ||||||
| kick_message=\u00a7cYou have been kicked off the proxy. | kick_message=\u00a7cYou have been kicked off the proxy. | ||||||
|  | reject_transfer=\u00a7cYour transfer was rejected. | ||||||
|   | |||||||
| @@ -4,15 +4,14 @@ | |||||||
|     <modelVersion>4.0.0</modelVersion> |     <modelVersion>4.0.0</modelVersion> | ||||||
|  |  | ||||||
|     <parent> |     <parent> | ||||||
|         <groupId>net.md-5</groupId> |         <groupId>fr.pandacube.bungeecord</groupId> | ||||||
|         <artifactId>bungeecord-parent</artifactId> |         <artifactId>bungeecord-parent</artifactId> | ||||||
|         <version>1.20-R0.2-SNAPSHOT</version> |         <version>1.20-R0.3-SNAPSHOT</version> | ||||||
|         <relativePath>../pom.xml</relativePath> |         <relativePath>../pom.xml</relativePath> | ||||||
|     </parent> |     </parent> | ||||||
|  |  | ||||||
|     <groupId>net.md-5</groupId> |  | ||||||
|     <artifactId>bungeecord-query</artifactId> |     <artifactId>bungeecord-query</artifactId> | ||||||
|     <version>1.20-R0.2-SNAPSHOT</version> |     <version>1.20-R0.3-SNAPSHOT</version> | ||||||
|     <packaging>jar</packaging> |     <packaging>jar</packaging> | ||||||
|  |  | ||||||
|     <name>BungeeCord-Query</name> |     <name>BungeeCord-Query</name> | ||||||
| @@ -25,7 +24,7 @@ | |||||||
|             <scope>compile</scope> |             <scope>compile</scope> | ||||||
|         </dependency> |         </dependency> | ||||||
|         <dependency> |         <dependency> | ||||||
|             <groupId>net.md-5</groupId> |             <groupId>fr.pandacube.bungeecord</groupId> | ||||||
|             <artifactId>bungeecord-api</artifactId> |             <artifactId>bungeecord-api</artifactId> | ||||||
|             <version>${project.version}</version> |             <version>${project.version}</version> | ||||||
|             <scope>compile</scope> |             <scope>compile</scope> | ||||||
|   | |||||||
| @@ -4,15 +4,14 @@ | |||||||
|     <modelVersion>4.0.0</modelVersion> |     <modelVersion>4.0.0</modelVersion> | ||||||
|  |  | ||||||
|     <parent> |     <parent> | ||||||
|         <groupId>net.md-5</groupId> |         <groupId>fr.pandacube.bungeecord</groupId> | ||||||
|         <artifactId>bungeecord-parent</artifactId> |         <artifactId>bungeecord-parent</artifactId> | ||||||
|         <version>1.20-R0.2-SNAPSHOT</version> |         <version>1.20-R0.3-SNAPSHOT</version> | ||||||
|         <relativePath>../pom.xml</relativePath> |         <relativePath>../pom.xml</relativePath> | ||||||
|     </parent> |     </parent> | ||||||
|  |  | ||||||
|     <groupId>net.md-5</groupId> |  | ||||||
|     <artifactId>bungeecord-slf4j</artifactId> |     <artifactId>bungeecord-slf4j</artifactId> | ||||||
|     <version>1.20-R0.2-SNAPSHOT</version> |     <version>1.20-R0.3-SNAPSHOT</version> | ||||||
|     <packaging>jar</packaging> |     <packaging>jar</packaging> | ||||||
|  |  | ||||||
|     <name>BungeeCord-SLF4J</name> |     <name>BungeeCord-SLF4J</name> | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user