Compare commits
	
		
			186 Commits
		
	
	
		
			18eae8a1a6
			...
			for-pandac
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 16646efb3c | |||
| ec1e8483b9 | |||
| d39b527c3e | |||
| af9e6d9118 | |||
| da736d8ad9 | |||
| 57da3ee6ca | |||
|   | 296b31bd56 | ||
|   | 8f6768ae00 | ||
|   | 70603d5413 | ||
|   | 2e12caad03 | ||
|   | f9ce9fad28 | ||
|   | 69b476fcbc | ||
|   | d37a430f5a | ||
|   | 4c02676b7a | ||
|   | a2558484f5 | ||
|   | 97c6167272 | ||
|   | c2162eeddb | ||
|   | 0124b66918 | ||
|   | 7be06f141d | ||
|   | 01048b4fca | ||
|   | d2a317eee2 | ||
|   | 0be632a4d6 | ||
|   | f27f4fbca9 | ||
|   | e62fc6c291 | ||
|   | 8e99a4c5bf | ||
|   | df53053677 | ||
|   | 4cd9a17a40 | ||
|   | e9558ab370 | ||
|   | 3a5c731826 | ||
|   | c13e6df67e | ||
|   | 704e866413 | ||
|   | aea5870ac8 | ||
|   | f1a4a42d51 | ||
|   | a485d9f314 | ||
|   | 131125c7d2 | ||
|   | 7fcc62067b | ||
|   | 7c7cb3de0f | ||
|   | 88436c44a6 | ||
|   | bdd32d5a58 | ||
|   | 5e59b6dc85 | ||
|   | bccce74c3c | ||
|   | 0e9e0b58d2 | ||
|   | 8cb49bc10a | ||
|   | 5b05934fe8 | ||
|   | 97f65726d2 | ||
|   | e3ab8ef15f | ||
|   | d5bcabdc60 | ||
|   | 3cd530f007 | ||
|   | 2b9808cd13 | ||
|   | 70fa02f3a4 | ||
|   | 4ebc3c96b2 | ||
|   | dd1531e28d | ||
|   | 5709a65785 | ||
|   | 5348aad094 | ||
|   | b60c1bdb37 | ||
|   | 93508d5083 | ||
|   | 1f159f8eaa | ||
|   | 31f7ef8c54 | ||
|   | 244412405a | ||
|   | 9cd0d3289f | ||
|   | 7cde213e63 | ||
|   | aa44ebe770 | ||
|   | 5dad41034b | ||
|   | cd1ceb4c31 | ||
|   | 23ba5141f1 | ||
|   | 415ac8c81e | ||
|   | 41e49dad6b | ||
|   | bec329352d | ||
|   | 89e66ed648 | ||
|   | d8f9d81b30 | ||
|   | 363003d8c7 | ||
|   | a696bb0e9f | ||
|   | 68f4f6bd40 | ||
|   | 442ff808f3 | ||
|   | fbbcc454d5 | ||
|   | f8de305477 | ||
|   | f1f5be18f9 | ||
|   | e05560976b | ||
|   | 8bff00f15b | ||
|   | 4d37c2488e | ||
|   | 75456b2c0a | ||
|   | 53365e4b18 | ||
|   | 69e4872f40 | ||
|   | a336efb8fa | ||
|   | ae2fc30b7b | ||
|   | 2bafb70581 | ||
|   | 617c2728a2 | ||
|   | 89069a362d | ||
|   | 1279cca971 | ||
|   | 26433bf021 | ||
|   | d81040cd6f | ||
|   | d7538df91b | ||
|   | 2516de6586 | ||
|   | 1da3a8c240 | ||
|   | f6151dce56 | ||
|   | 9667743735 | ||
|   | 7587f03306 | ||
|   | 77b81f2612 | ||
|   | fa6d47732d | ||
|   | 252e7b0027 | ||
|   | c820b3a062 | ||
|   | 687c302610 | ||
|   | 4b0262312e | ||
|   | 6f13c2d6b6 | ||
|   | cd186999e5 | ||
|   | e3c7fd8cc5 | ||
|   | 9476ffccdb | ||
|   | 47f8c29a7c | ||
|   | 458246505f | ||
|   | 362bd0f4c4 | ||
|   | 598d73e6f0 | ||
|   | f797bd488f | ||
|   | 0d153feee7 | ||
|   | 2a78233cc2 | ||
|   | 591e18753d | ||
|   | 556a15a6f8 | ||
|   | 774a6fd68c | ||
|   | 0070421549 | ||
|   | 4dad940a2f | ||
|   | ed4a80eb0b | ||
|   | dd2033bf1a | ||
|   | cceebdad2a | ||
|   | 05bdf5d3c1 | ||
|   | c3e4a6ef5b | ||
|   | 2337acfcc1 | ||
|   | 69861e5334 | ||
|   | 22aa6f5faf | ||
|   | 508c2f7ac3 | ||
|   | 9dd5fb626d | ||
|   | b5ae0196fc | ||
|   | 80bb237289 | ||
|   | 4fded9828f | ||
|   | 6b22690971 | ||
|   | 60a3bf082f | ||
|   | 0aa2871b26 | ||
|   | 1265a9927b | ||
|   | d99570214a | ||
|   | 15bd33b25b | ||
|   | 7340f1a035 | ||
|   | 8a80435e64 | ||
|   | 20a71b06a9 | ||
|   | b376f61578 | ||
|   | 373dab05ad | ||
|   | f6b40b1186 | ||
|   | 81b118a8ba | ||
|   | 7a42f12716 | ||
|   | 4886c4be01 | ||
|   | 7338d0f444 | ||
|   | 8212e10c7c | ||
|   | 2593130b3e | ||
|   | 6ea49962c5 | ||
|   | 672db9fe47 | ||
|   | 2bacf6572b | ||
|   | 9813e46e66 | ||
|   | 01a5f36012 | ||
|   | f0a30c43cd | ||
|   | acb85e30fa | ||
|   | 9437cedc48 | ||
|   | a89cf5f36d | ||
|   | b309e4ac50 | ||
|   | 477ea5983c | ||
|   | eca6090f1e | ||
|   | 8f8c270f3b | ||
|   | 84ac7ab944 | ||
|   | 5fbcc6b119 | ||
|   | 79f85a2ce2 | ||
|   | d32eedd333 | ||
|   | e1d4b6adc7 | ||
|   | 534148763f | ||
|   | cd56fb32c2 | ||
|   | 6b612302e1 | ||
|   | e49759025f | ||
|   | c310e3339f | ||
|   | b64615e298 | ||
|   | 45d2f44003 | ||
|   | a57adcce00 | ||
|   | 8b195d1d21 | ||
|   | cda4537fba | ||
| ![dependabot[bot]](/assets/img/avatar_default.png)  | df413f62db | ||
|   | 8a88ce464e | ||
|   | 006a14a75c | ||
|   | 07df657f3c | ||
|   | b8b373a53e | ||
|   | e7e0b97cff | ||
| ![dependabot[bot]](/assets/img/avatar_default.png)  | 52ab21b1ff | ||
|   | 8e8a635361 | 
							
								
								
									
										4
									
								
								.github/workflows/maven.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.github/workflows/maven.yml
									
									
									
									
										vendored
									
									
								
							| @@ -4,12 +4,12 @@ on: [push, pull_request] | ||||
|  | ||||
| jobs: | ||||
|   build: | ||||
|     runs-on: ubuntu-22.04 | ||||
|     runs-on: ubuntu-24.04 | ||||
|  | ||||
|     strategy: | ||||
|       fail-fast: false | ||||
|       matrix: | ||||
|         java: [8, 11, 17, 21] | ||||
|         java: [8, 11, 17, 21, 25] | ||||
|  | ||||
|     name: Java ${{ matrix.java }} | ||||
|  | ||||
|   | ||||
| @@ -23,4 +23,4 @@ Binaries | ||||
| -------- | ||||
| Precompiled binaries are available for end users on [Jenkins](https://www.spigotmc.org/go/bungeecord-dl). | ||||
|  | ||||
| (c) 2012-2024 SpigotMC Pty. Ltd. | ||||
| (c) 2012-2025 SpigotMC Pty. Ltd. | ||||
|   | ||||
							
								
								
									
										27
									
								
								api/pom.xml
									
									
									
									
									
								
							
							
						
						
									
										27
									
								
								api/pom.xml
									
									
									
									
									
								
							| @@ -4,15 +4,14 @@ | ||||
|     <modelVersion>4.0.0</modelVersion> | ||||
|  | ||||
|     <parent> | ||||
|         <groupId>net.md-5</groupId> | ||||
|         <groupId>fr.pandacube.bungeecord</groupId> | ||||
|         <artifactId>bungeecord-parent</artifactId> | ||||
|         <version>1.20-R0.3-SNAPSHOT</version> | ||||
|         <version>1.21-R0.5-SNAPSHOT</version> | ||||
|         <relativePath>../pom.xml</relativePath> | ||||
|     </parent> | ||||
|  | ||||
|     <groupId>net.md-5</groupId> | ||||
|     <artifactId>bungeecord-api</artifactId> | ||||
|     <version>1.20-R0.3-SNAPSHOT</version> | ||||
|     <version>1.21-R0.5-SNAPSHOT</version> | ||||
|     <packaging>jar</packaging> | ||||
|  | ||||
|     <name>BungeeCord-API</name> | ||||
| @@ -20,25 +19,31 @@ | ||||
|  | ||||
|     <dependencies> | ||||
|         <dependency> | ||||
|             <groupId>net.md-5</groupId> | ||||
|             <groupId>fr.pandacube.bungeecord</groupId> | ||||
|             <artifactId>bungeecord-chat</artifactId> | ||||
|             <version>${project.version}</version> | ||||
|             <scope>compile</scope> | ||||
|         </dependency> | ||||
|         <dependency> | ||||
|             <groupId>net.md-5</groupId> | ||||
|             <groupId>fr.pandacube.bungeecord</groupId> | ||||
|             <artifactId>bungeecord-config</artifactId> | ||||
|             <version>${project.version}</version> | ||||
|             <scope>compile</scope> | ||||
|         </dependency> | ||||
|         <dependency> | ||||
|             <groupId>net.md-5</groupId> | ||||
|             <groupId>fr.pandacube.bungeecord</groupId> | ||||
|             <artifactId>bungeecord-dialog</artifactId> | ||||
|             <version>${project.version}</version> | ||||
|             <scope>compile</scope> | ||||
|         </dependency> | ||||
|         <dependency> | ||||
|             <groupId>fr.pandacube.bungeecord</groupId> | ||||
|             <artifactId>bungeecord-event</artifactId> | ||||
|             <version>${project.version}</version> | ||||
|             <scope>compile</scope> | ||||
|         </dependency> | ||||
|         <dependency> | ||||
|             <groupId>net.md-5</groupId> | ||||
|             <groupId>fr.pandacube.bungeecord</groupId> | ||||
|             <artifactId>bungeecord-protocol</artifactId> | ||||
|             <version>${project.version}</version> | ||||
|             <scope>compile</scope> | ||||
| @@ -69,6 +74,12 @@ | ||||
|             <!-- not part of the API proper --> | ||||
|             <scope>provided</scope> | ||||
|         </dependency> | ||||
|         <dependency> | ||||
|             <groupId>org.ow2.asm</groupId> | ||||
|             <artifactId>asm-commons</artifactId> | ||||
|             <version>9.8</version> | ||||
|             <scope>compile</scope> | ||||
|         </dependency> | ||||
|         <dependency> | ||||
|             <groupId>org.yaml</groupId> | ||||
|             <artifactId>snakeyaml</artifactId> | ||||
|   | ||||
| @@ -16,6 +16,7 @@ import net.md_5.bungee.api.connection.ProxiedPlayer; | ||||
| import net.md_5.bungee.api.plugin.Plugin; | ||||
| import net.md_5.bungee.api.plugin.PluginManager; | ||||
| import net.md_5.bungee.api.scheduler.TaskScheduler; | ||||
| import net.md_5.bungee.protocol.channel.BungeeChannelInitializer; | ||||
|  | ||||
| public abstract class ProxyServer | ||||
| { | ||||
| @@ -311,4 +312,56 @@ public abstract class ProxyServer | ||||
|      */ | ||||
|     public abstract Title createTitle(); | ||||
|  | ||||
|     /** | ||||
|      * Get the unsafe methods of this class. | ||||
|      * | ||||
|      * @return the unsafe method interface | ||||
|      */ | ||||
|     public abstract Unsafe unsafe(); | ||||
|  | ||||
|     public interface Unsafe | ||||
|     { | ||||
|  | ||||
|         /** | ||||
|          * Gets the frontend channel initializer | ||||
|          * | ||||
|          * @return the frontend channel initializer | ||||
|          */ | ||||
|         BungeeChannelInitializer getFrontendChannelInitializer(); | ||||
|  | ||||
|         /** | ||||
|          * Set the frontend channel initializer of this proxy | ||||
|          * | ||||
|          * @param channelInitializer the frontend channelInitializer to set | ||||
|          */ | ||||
|         void setFrontendChannelInitializer(BungeeChannelInitializer channelInitializer); | ||||
|  | ||||
|         /** | ||||
|          * Gets the backend channel initializer | ||||
|          * | ||||
|          * @return the backend channel initializer | ||||
|          */ | ||||
|         BungeeChannelInitializer getBackendChannelInitializer(); | ||||
|  | ||||
|         /** | ||||
|          * Set the backend channel initializer of this proxy | ||||
|          * | ||||
|          * @param channelInitializer the backend channelInitializer to set | ||||
|          */ | ||||
|         void setBackendChannelInitializer(BungeeChannelInitializer channelInitializer); | ||||
|  | ||||
|         /** | ||||
|          * Gets the server info channel initializer | ||||
|          * | ||||
|          * @return the server info channel initializer | ||||
|          */ | ||||
|         BungeeChannelInitializer getServerInfoChannelInitializer(); | ||||
|  | ||||
|         /** | ||||
|          * Set the server info channel initializer of this proxy | ||||
|          * | ||||
|          * @param channelInitializer the server info channelInitializer to set | ||||
|          */ | ||||
|         void setServerInfoChannelInitializer(BungeeChannelInitializer channelInitializer); | ||||
|     } | ||||
| } | ||||
|   | ||||
							
								
								
									
										77
									
								
								api/src/main/java/net/md_5/bungee/api/ServerLink.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								api/src/main/java/net/md_5/bungee/api/ServerLink.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,77 @@ | ||||
| package net.md_5.bungee.api; | ||||
|  | ||||
| import lombok.AccessLevel; | ||||
| import lombok.Data; | ||||
| import lombok.NonNull; | ||||
| import lombok.RequiredArgsConstructor; | ||||
| import net.md_5.bungee.api.chat.BaseComponent; | ||||
|  | ||||
| /** | ||||
|  * Represents a server link which may be sent to the client. | ||||
|  */ | ||||
| @Data | ||||
| @RequiredArgsConstructor(access = AccessLevel.PRIVATE) | ||||
| public final class ServerLink | ||||
| { | ||||
|  | ||||
|     /** | ||||
|      * The links type. | ||||
|      * | ||||
|      * Note: This value is nullable, if null, label is non-null. | ||||
|      */ | ||||
|     private final LinkType type; | ||||
|  | ||||
|     /** | ||||
|      * The label for the link. | ||||
|      * | ||||
|      * Note: This value is nullable, if null, type is non-null. | ||||
|      */ | ||||
|     private final BaseComponent label; | ||||
|  | ||||
|     /** | ||||
|      * The URL that is displayed. | ||||
|      */ | ||||
|     @NonNull | ||||
|     private final String url; | ||||
|  | ||||
|     /** | ||||
|      * Creates a link with a specified type and URL. | ||||
|      * | ||||
|      * @param type the type of the link | ||||
|      * @param url the URL to be displayed | ||||
|      */ | ||||
|     public ServerLink(@NonNull LinkType type, @NonNull String url) | ||||
|     { | ||||
|         this.type = type; | ||||
|         this.label = null; | ||||
|         this.url = url; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates a link with a label and URL. | ||||
|      * | ||||
|      * @param label the label to be displayed | ||||
|      * @param url the URL to be displayed | ||||
|      */ | ||||
|     public ServerLink(@NonNull BaseComponent label, @NonNull String url) | ||||
|     { | ||||
|         this.type = null; | ||||
|         this.label = label; | ||||
|         this.url = url; | ||||
|     } | ||||
|  | ||||
|     public enum LinkType | ||||
|     { | ||||
|  | ||||
|         REPORT_BUG, | ||||
|         COMMUNITY_GUIDELINES, | ||||
|         SUPPORT, | ||||
|         STATUS, | ||||
|         FEEDBACK, | ||||
|         COMMUNITY, | ||||
|         WEBSITE, | ||||
|         FORUMS, | ||||
|         NEWS, | ||||
|         ANNOUNCEMENTS; | ||||
|     } | ||||
| } | ||||
| @@ -84,5 +84,17 @@ public interface Connection | ||||
|          * @param packet the packet to send | ||||
|          */ | ||||
|         void sendPacket(DefinedPacket packet); | ||||
|  | ||||
|         /** | ||||
|          * Queue a packet to this connection. | ||||
|          * | ||||
|          * If the packet is not registered for the connections current encoder | ||||
|          * protocol, it will be queued until it is, otherwise it will be sent | ||||
|          * immediately. | ||||
|          * | ||||
|          * @param packet the packet to be queued | ||||
|          * @throws UnsupportedOperationException if used for a PendingConnection | ||||
|          */ | ||||
|         void sendPacketQueued(DefinedPacket packet); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -113,4 +113,18 @@ public interface PendingConnection extends Connection | ||||
|      */ | ||||
|     @ApiStatus.Experimental | ||||
|     CompletableFuture<byte[]> retrieveCookie(String cookie); | ||||
|  | ||||
|     /** | ||||
|      * Sends a login payload request to the client. | ||||
|      * | ||||
|      * @param channel the channel to send this data via | ||||
|      * @param data the data to send | ||||
|      * @return a {@link CompletableFuture} that will be completed when the Login | ||||
|      * Payload response is received. If the Vanilla client doesn't know the | ||||
|      * channel, the {@link CompletableFuture} will complete with a null value | ||||
|      * @throws IllegalStateException if the player's version is not at least | ||||
|      * 1.13 | ||||
|      */ | ||||
|     @ApiStatus.Experimental | ||||
|     CompletableFuture<byte[]> sendData(String channel, byte[] data); | ||||
| } | ||||
|   | ||||
| @@ -1,5 +1,6 @@ | ||||
| package net.md_5.bungee.api.connection; | ||||
|  | ||||
| import java.util.List; | ||||
| import java.util.Locale; | ||||
| import java.util.Map; | ||||
| import java.util.UUID; | ||||
| @@ -8,10 +9,12 @@ import net.md_5.bungee.api.Callback; | ||||
| import net.md_5.bungee.api.ChatMessageType; | ||||
| import net.md_5.bungee.api.CommandSender; | ||||
| import net.md_5.bungee.api.ServerConnectRequest; | ||||
| import net.md_5.bungee.api.ServerLink; | ||||
| import net.md_5.bungee.api.SkinConfiguration; | ||||
| import net.md_5.bungee.api.Title; | ||||
| import net.md_5.bungee.api.chat.BaseComponent; | ||||
| import net.md_5.bungee.api.config.ServerInfo; | ||||
| import net.md_5.bungee.api.dialog.Dialog; | ||||
| import net.md_5.bungee.api.event.ServerConnectEvent; | ||||
| import net.md_5.bungee.api.score.Scoreboard; | ||||
| import org.jetbrains.annotations.ApiStatus; | ||||
| @@ -382,4 +385,44 @@ public interface ProxiedPlayer extends Connection, CommandSender | ||||
|      */ | ||||
|     @ApiStatus.Experimental | ||||
|     void transfer(String host, int port); | ||||
|  | ||||
|     /** | ||||
|      * Gets the client brand of this player. | ||||
|      * | ||||
|      * If the player has not sent a brand packet yet, it will return null. | ||||
|      * | ||||
|      * @return the brand of the client, or null if not received yet | ||||
|      */ | ||||
|     String getClientBrand(); | ||||
|  | ||||
|     /** | ||||
|      * Clear the player's open dialog. | ||||
|      * | ||||
|      * @throws IllegalStateException if the players version is not at least | ||||
|      * 1.21.6 | ||||
|      */ | ||||
|     @ApiStatus.Experimental | ||||
|     void clearDialog(); | ||||
|  | ||||
|     /** | ||||
|      * Show a dialog to the player. | ||||
|      * | ||||
|      * @param dialog the dialog to show | ||||
|      * @throws IllegalStateException if the players version is not at least | ||||
|      * 1.21.6 | ||||
|      */ | ||||
|     @ApiStatus.Experimental | ||||
|     void showDialog(Dialog dialog); | ||||
|  | ||||
|     /** | ||||
|      * Sends server links to the player. | ||||
|      * | ||||
|      * Note: The links already sent to the player will be overwritten. Also, the | ||||
|      * backend server is able to override links sent by the proxy. | ||||
|      * | ||||
|      * @param serverLinks the server links to send | ||||
|      * @throws IllegalStateException if the player's version is not at least | ||||
|      * 1.21 | ||||
|      */ | ||||
|     void sendServerLinks(List<ServerLink> serverLinks); | ||||
| } | ||||
|   | ||||
| @@ -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; | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,39 @@ | ||||
| package net.md_5.bungee.api.event; | ||||
|  | ||||
| import com.google.gson.JsonElement; | ||||
| import lombok.Data; | ||||
| import lombok.EqualsAndHashCode; | ||||
| import lombok.ToString; | ||||
| import net.md_5.bungee.api.connection.ProxiedPlayer; | ||||
| import net.md_5.bungee.api.plugin.Cancellable; | ||||
| import net.md_5.bungee.api.plugin.Event; | ||||
| import org.jetbrains.annotations.ApiStatus; | ||||
|  | ||||
| /** | ||||
|  * Called after a {@link ProxiedPlayer} runs a custom action from a chat event | ||||
|  * or form submission. | ||||
|  */ | ||||
| @Data | ||||
| @ToString(callSuper = false) | ||||
| @EqualsAndHashCode(callSuper = false) | ||||
| @ApiStatus.Experimental | ||||
| public class CustomClickEvent extends Event implements Cancellable | ||||
| { | ||||
|  | ||||
|     /** | ||||
|      * Player who clicked. | ||||
|      */ | ||||
|     private final ProxiedPlayer player; | ||||
|     /** | ||||
|      * Custom action ID. | ||||
|      */ | ||||
|     private final String id; | ||||
|     /** | ||||
|      * The data as submitted. | ||||
|      */ | ||||
|     private final JsonElement data; | ||||
|     /** | ||||
|      * Cancelled state. | ||||
|      */ | ||||
|     private boolean cancelled; | ||||
| } | ||||
| @@ -3,6 +3,7 @@ package net.md_5.bungee.api.event; | ||||
| import lombok.AllArgsConstructor; | ||||
| import lombok.EqualsAndHashCode; | ||||
| import lombok.Getter; | ||||
| import lombok.ToString; | ||||
| import net.md_5.bungee.api.CommandSender; | ||||
| import net.md_5.bungee.api.plugin.Event; | ||||
|  | ||||
| @@ -10,6 +11,7 @@ import net.md_5.bungee.api.plugin.Event; | ||||
|  * Called when somebody reloads BungeeCord | ||||
|  */ | ||||
| @Getter | ||||
| @ToString(callSuper = false) | ||||
| @AllArgsConstructor | ||||
| @EqualsAndHashCode(callSuper = false) | ||||
| public class ProxyReloadEvent extends Event | ||||
|   | ||||
| @@ -9,7 +9,9 @@ import net.md_5.bungee.api.plugin.Cancellable; | ||||
|  | ||||
| /** | ||||
|  * Event called when a player uses tab completion. | ||||
|  * @deprecated please use {@link TabCompleteRequestEvent} to support 1.13+ suggestions. | ||||
|  */ | ||||
| @Deprecated | ||||
| @Data | ||||
| @ToString(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; | ||||
|     } | ||||
| } | ||||
| @@ -35,6 +35,7 @@ import org.eclipse.aether.transport.http.HttpTransporterFactory; | ||||
| class LibraryLoader | ||||
| { | ||||
|  | ||||
|     private static final String REPOSITORY_PROPERTY = "net.md_5.bungee.api.plugin.centralURL"; | ||||
|     private final Logger logger; | ||||
|     private final RepositorySystem repository; | ||||
|     private final DefaultRepositorySystemSession session; | ||||
| @@ -68,7 +69,7 @@ class LibraryLoader | ||||
|         session.setSystemProperties( System.getProperties() ); | ||||
|         session.setReadOnly(); | ||||
|  | ||||
|         this.repositories = repository.newResolutionRepositories( session, Arrays.asList( new RemoteRepository.Builder( "central", "default", "https://repo.maven.apache.org/maven2" ).build() ) ); | ||||
|         this.repositories = repository.newResolutionRepositories( session, Arrays.asList( new RemoteRepository.Builder( "central", "default", System.getProperty( REPOSITORY_PROPERTY, "https://repo.maven.apache.org/maven2" ) ).build() ) ); | ||||
|     } | ||||
|  | ||||
|     public ClassLoader createLoader(PluginDescription desc) | ||||
|   | ||||
| @@ -11,6 +11,7 @@ import lombok.Getter; | ||||
| import net.md_5.bungee.api.ProxyServer; | ||||
| import net.md_5.bungee.api.config.ConfigurationAdapter; | ||||
| import net.md_5.bungee.api.scheduler.GroupedThreadFactory; | ||||
| import org.jetbrains.annotations.ApiStatus; | ||||
|  | ||||
| /** | ||||
|  * Represents any Plugin that may be loaded at runtime to enhance existing | ||||
| @@ -108,7 +109,14 @@ public class Plugin | ||||
|     // | ||||
|     private ExecutorService service; | ||||
|  | ||||
|     /** | ||||
|      * Returns the executor service associated with this plugin. | ||||
|      * | ||||
|      * @return the executor service for this plugin | ||||
|      * @deprecated internal API. Use {@link ProxyServer#getScheduler()} instead | ||||
|      */ | ||||
|     @Deprecated | ||||
|     @ApiStatus.Internal | ||||
|     public ExecutorService getExecutorService() | ||||
|     { | ||||
|         if ( service == null ) | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| package net.md_5.bungee.api.plugin; | ||||
|  | ||||
| import com.google.common.base.Preconditions; | ||||
| import com.google.common.collect.ImmutableMap; | ||||
| import com.google.common.io.ByteStreams; | ||||
| import java.io.File; | ||||
| import java.io.IOException; | ||||
| @@ -9,13 +10,20 @@ import java.net.URL; | ||||
| import java.net.URLClassLoader; | ||||
| import java.security.CodeSigner; | ||||
| import java.security.CodeSource; | ||||
| import java.util.Map; | ||||
| import java.util.Set; | ||||
| import java.util.concurrent.CopyOnWriteArraySet; | ||||
| import java.util.jar.JarEntry; | ||||
| import java.util.jar.JarFile; | ||||
| import java.util.jar.Manifest; | ||||
| import java.util.logging.Level; | ||||
| import java.util.logging.Logger; | ||||
| import lombok.ToString; | ||||
| import net.md_5.bungee.api.ProxyServer; | ||||
| import org.objectweb.asm.ClassReader; | ||||
| import org.objectweb.asm.ClassWriter; | ||||
| import org.objectweb.asm.commons.ClassRemapper; | ||||
| import org.objectweb.asm.commons.SimpleRemapper; | ||||
|  | ||||
| @ToString(of = "desc") | ||||
| final class PluginClassloader extends URLClassLoader | ||||
| @@ -121,6 +129,15 @@ final class PluginClassloader extends URLClassLoader | ||||
|                 throw new ClassNotFoundException( name, ex ); | ||||
|             } | ||||
|  | ||||
|             try | ||||
|             { | ||||
|                 classBytes = remap( classBytes ); | ||||
|             } catch ( Exception ex ) | ||||
|             { | ||||
|                 Logger logger = ( plugin != null ) ? plugin.getLogger() : proxy.getLogger(); | ||||
|                 logger.log( Level.SEVERE, "Error trying to remap class " + path, ex ); | ||||
|             } | ||||
|  | ||||
|             int dot = name.lastIndexOf( '.' ); | ||||
|             if ( dot != -1 ) | ||||
|             { | ||||
| @@ -155,6 +172,27 @@ final class PluginClassloader extends URLClassLoader | ||||
|         return super.findClass( name ); | ||||
|     } | ||||
|  | ||||
|     private static final Map<String, String> MAPPINGS = ImmutableMap.of( | ||||
|             "net/md_5/bungee/protocol/ChatChain", "net/md_5/bungee/protocol/data/ChatChain", | ||||
|             "net/md_5/bungee/protocol/Location", "net/md_5/bungee/protocol/data/Location", | ||||
|             "net/md_5/bungee/protocol/NumberFormat", "net/md_5/bungee/protocol/data/NumberFormat", | ||||
|             "net/md_5/bungee/protocol/PlayerPublicKey", "net/md_5/bungee/protocol/data/PlayerPublicKey", | ||||
|             "net/md_5/bungee/protocol/Property", "net/md_5/bungee/protocol/data/Property", | ||||
|             "net/md_5/bungee/protocol/SeenMessages", "net/md_5/bungee/protocol/data/SeenMessages", | ||||
|             "net/md_5/bungee/protocol/Either", "net/md_5/bungee/protocol/util/Either", | ||||
|             "net/md_5/bungee/protocol/TagUtil", "net/md_5/bungee/protocol/util/TagUtil" | ||||
|     ); | ||||
|  | ||||
|     private static byte[] remap(byte[] b) | ||||
|     { | ||||
|         ClassReader cr = new ClassReader( b ); | ||||
|         ClassWriter cw = new ClassWriter( cr, 0 ); | ||||
|  | ||||
|         cr.accept( new ClassRemapper( cw, new SimpleRemapper( MAPPINGS ) ), 0 ); | ||||
|  | ||||
|         return cw.toByteArray(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void close() throws IOException | ||||
|     { | ||||
|   | ||||
| @@ -23,9 +23,14 @@ import java.util.Locale; | ||||
| import java.util.Map; | ||||
| import java.util.Set; | ||||
| import java.util.Stack; | ||||
| import java.util.concurrent.locks.Lock; | ||||
| import java.util.concurrent.locks.ReadWriteLock; | ||||
| import java.util.concurrent.locks.ReentrantLock; | ||||
| import java.util.concurrent.locks.ReentrantReadWriteLock; | ||||
| import java.util.jar.JarEntry; | ||||
| import java.util.jar.JarFile; | ||||
| import java.util.logging.Level; | ||||
| import lombok.Locked; | ||||
| import lombok.RequiredArgsConstructor; | ||||
| import net.md_5.bungee.api.ChatColor; | ||||
| import net.md_5.bungee.api.CommandSender; | ||||
| @@ -59,6 +64,9 @@ public final class PluginManager | ||||
|     private final Multimap<Plugin, Command> commandsByPlugin = ArrayListMultimap.create(); | ||||
|     private final Multimap<Plugin, Listener> listenersByPlugin = ArrayListMultimap.create(); | ||||
|  | ||||
|     private final ReadWriteLock commandsLock = new ReentrantReadWriteLock(); | ||||
|     private final Lock listenersLock = new ReentrantLock(); | ||||
|  | ||||
|     @SuppressWarnings("unchecked") | ||||
|     public PluginManager(ProxyServer proxy) | ||||
|     { | ||||
| @@ -91,6 +99,7 @@ public final class PluginManager | ||||
|      * @param plugin the plugin owning this command | ||||
|      * @param command the command to register | ||||
|      */ | ||||
|     @Locked.Write("commandsLock") | ||||
|     public void registerCommand(Plugin plugin, Command command) | ||||
|     { | ||||
|         commandMap.put( command.getName().toLowerCase( Locale.ROOT ), command ); | ||||
| @@ -106,6 +115,7 @@ public final class PluginManager | ||||
|      * | ||||
|      * @param command the command to unregister | ||||
|      */ | ||||
|     @Locked.Write("commandsLock") | ||||
|     public void unregisterCommand(Command command) | ||||
|     { | ||||
|         while ( commandMap.values().remove( command ) ); | ||||
| @@ -117,6 +127,7 @@ public final class PluginManager | ||||
|      * | ||||
|      * @param plugin the plugin to register the commands of | ||||
|      */ | ||||
|     @Locked.Write("commandsLock") | ||||
|     public void unregisterCommands(Plugin plugin) | ||||
|     { | ||||
|         for ( Iterator<Command> it = commandsByPlugin.get( plugin ).iterator(); it.hasNext(); ) | ||||
| @@ -137,7 +148,14 @@ public final class PluginManager | ||||
|             return null; | ||||
|         } | ||||
|  | ||||
|         return commandMap.get( commandLower ); | ||||
|         commandsLock.readLock().lock(); | ||||
|         try | ||||
|         { | ||||
|             return commandMap.get( commandLower ); | ||||
|         } finally | ||||
|         { | ||||
|             commandsLock.readLock().unlock(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
| @@ -432,12 +450,12 @@ public final class PluginManager | ||||
|      * @param plugin the owning plugin | ||||
|      * @param listener the listener to register events for | ||||
|      */ | ||||
|     @Locked("listenersLock") | ||||
|     public void registerListener(Plugin plugin, Listener listener) | ||||
|     { | ||||
|         for ( Method method : listener.getClass().getDeclaredMethods() ) | ||||
|         { | ||||
|             Preconditions.checkArgument( !method.isAnnotationPresent( Subscribe.class ), | ||||
|                     "Listener %s has registered using deprecated subscribe annotation! Please update to @EventHandler.", listener ); | ||||
|             Preconditions.checkArgument( !method.isAnnotationPresent( Subscribe.class ), "Listener %s has registered using deprecated subscribe annotation! Please update to @EventHandler.", listener ); | ||||
|         } | ||||
|         eventBus.register( listener ); | ||||
|         listenersByPlugin.put( plugin, listener ); | ||||
| @@ -448,6 +466,7 @@ public final class PluginManager | ||||
|      * | ||||
|      * @param listener the listener to unregister | ||||
|      */ | ||||
|     @Locked("listenersLock") | ||||
|     public void unregisterListener(Listener listener) | ||||
|     { | ||||
|         eventBus.unregister( listener ); | ||||
| @@ -459,6 +478,7 @@ public final class PluginManager | ||||
|      * | ||||
|      * @param plugin target plugin | ||||
|      */ | ||||
|     @Locked("listenersLock") | ||||
|     public void unregisterListeners(Plugin plugin) | ||||
|     { | ||||
|         for ( Iterator<Listener> it = listenersByPlugin.get( plugin ).iterator(); it.hasNext(); ) | ||||
| @@ -473,6 +493,7 @@ public final class PluginManager | ||||
|      * | ||||
|      * @return commands | ||||
|      */ | ||||
|     @Locked.Read("commandsLock") | ||||
|     public Collection<Map.Entry<String, Command>> getCommands() | ||||
|     { | ||||
|         return Collections.unmodifiableCollection( commandMap.entrySet() ); | ||||
|   | ||||
| @@ -1,22 +1,37 @@ | ||||
| package net.md_5.bungee.util; | ||||
|  | ||||
| import gnu.trove.strategy.HashingStrategy; | ||||
| import it.unimi.dsi.fastutil.Hash; | ||||
| import java.util.Locale; | ||||
|  | ||||
| class CaseInsensitiveHashingStrategy implements HashingStrategy | ||||
| class CaseInsensitiveHashingStrategy implements Hash.Strategy<String> | ||||
| { | ||||
|  | ||||
|     static final CaseInsensitiveHashingStrategy INSTANCE = new CaseInsensitiveHashingStrategy(); | ||||
|  | ||||
|     @Override | ||||
|     public int computeHashCode(Object object) | ||||
|     public int hashCode(String object) | ||||
|     { | ||||
|         return ( (String) object ).toLowerCase( Locale.ROOT ).hashCode(); | ||||
|         if ( object == null ) | ||||
|         { | ||||
|             return 0; | ||||
|         } | ||||
|  | ||||
|         return object.toLowerCase( Locale.ROOT ).hashCode(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean equals(Object o1, Object o2) | ||||
|     public boolean equals(String o1, String o2) | ||||
|     { | ||||
|         return o1.equals( o2 ) || ( o1 instanceof String && o2 instanceof String && ( (String) o1 ).toLowerCase( Locale.ROOT ).equals( ( (String) o2 ).toLowerCase( Locale.ROOT ) ) ); | ||||
|         if ( o1 == o2 ) | ||||
|         { | ||||
|             return true; | ||||
|         } | ||||
|  | ||||
|         if ( o1 == null || o2 == null ) | ||||
|         { | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         return o1.equals( o2 ) || o1.toLowerCase( Locale.ROOT ).equals( o2.toLowerCase( Locale.ROOT ) ); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,9 +1,9 @@ | ||||
| package net.md_5.bungee.util; | ||||
|  | ||||
| import gnu.trove.map.hash.TCustomHashMap; | ||||
| import it.unimi.dsi.fastutil.objects.Object2ObjectOpenCustomHashMap; | ||||
| import java.util.Map; | ||||
|  | ||||
| public class CaseInsensitiveMap<V> extends TCustomHashMap<String, V> | ||||
| public class CaseInsensitiveMap<V> extends Object2ObjectOpenCustomHashMap<String, V> | ||||
| { | ||||
|  | ||||
|     public CaseInsensitiveMap() | ||||
| @@ -13,6 +13,6 @@ public class CaseInsensitiveMap<V> extends TCustomHashMap<String, V> | ||||
|  | ||||
|     public CaseInsensitiveMap(Map<? extends String, ? extends V> map) | ||||
|     { | ||||
|         super( CaseInsensitiveHashingStrategy.INSTANCE, map ); | ||||
|         super( map, CaseInsensitiveHashingStrategy.INSTANCE ); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,9 +1,9 @@ | ||||
| package net.md_5.bungee.util; | ||||
|  | ||||
| import gnu.trove.set.hash.TCustomHashSet; | ||||
| import it.unimi.dsi.fastutil.objects.ObjectOpenCustomHashSet; | ||||
| import java.util.Collection; | ||||
|  | ||||
| public class CaseInsensitiveSet extends TCustomHashSet<String> | ||||
| public class CaseInsensitiveSet extends ObjectOpenCustomHashSet<String> | ||||
| { | ||||
|  | ||||
|     public CaseInsensitiveSet() | ||||
| @@ -13,6 +13,6 @@ public class CaseInsensitiveSet extends TCustomHashSet<String> | ||||
|  | ||||
|     public CaseInsensitiveSet(Collection<? extends String> collection) | ||||
|     { | ||||
|         super( CaseInsensitiveHashingStrategy.INSTANCE, collection ); | ||||
|         super( collection, CaseInsensitiveHashingStrategy.INSTANCE ); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -13,12 +13,12 @@ public class CaseInsensitiveTest | ||||
|         CaseInsensitiveMap<Object> map = new CaseInsensitiveMap<>(); | ||||
|  | ||||
|         map.put( "FOO", obj ); | ||||
|         assertTrue( map.contains( "foo" ) ); // Assert that contains is case insensitive | ||||
|         assertTrue( map.containsKey( "foo" ) ); // Assert that contains is case insensitive | ||||
|         assertTrue( map.entrySet().iterator().next().getKey().equals( "FOO" ) ); // Assert that case is preserved | ||||
|  | ||||
|         // Assert that remove is case insensitive | ||||
|         map.remove( "FoO" ); | ||||
|         assertFalse( map.contains( "foo" ) ); | ||||
|         assertFalse( map.containsKey( "foo" ) ); | ||||
|     } | ||||
|  | ||||
|     @Test | ||||
|   | ||||
| @@ -4,31 +4,29 @@ | ||||
|     <modelVersion>4.0.0</modelVersion> | ||||
|  | ||||
|     <parent> | ||||
|         <groupId>net.md-5</groupId> | ||||
|         <groupId>fr.pandacube.bungeecord</groupId> | ||||
|         <artifactId>bungeecord-parent</artifactId> | ||||
|         <version>1.20-R0.3-SNAPSHOT</version> | ||||
|         <version>1.21-R0.5-SNAPSHOT</version> | ||||
|         <relativePath>../pom.xml</relativePath> | ||||
|     </parent> | ||||
|  | ||||
|     <groupId>net.md-5</groupId> | ||||
|     <artifactId>bungeecord-bootstrap</artifactId> | ||||
|     <version>1.20-R0.3-SNAPSHOT</version> | ||||
|     <version>1.21-R0.5-SNAPSHOT</version> | ||||
|     <packaging>jar</packaging> | ||||
|  | ||||
|     <name>BungeeCord-Bootstrap</name> | ||||
|     <description>Java 1.6 loader for BungeeCord</description> | ||||
|  | ||||
|     <properties> | ||||
|         <skipPublishing>true</skipPublishing> | ||||
|         <maven.deploy.skip>true</maven.deploy.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> | ||||
|     </properties> | ||||
|  | ||||
|     <dependencies> | ||||
|         <dependency> | ||||
|             <groupId>net.md-5</groupId> | ||||
|             <groupId>fr.pandacube.bungeecord</groupId> | ||||
|             <artifactId>bungeecord-proxy</artifactId> | ||||
|             <version>${project.version}</version> | ||||
|             <scope>compile</scope> | ||||
| @@ -36,7 +34,7 @@ | ||||
|     </dependencies> | ||||
|  | ||||
|     <build> | ||||
|         <finalName>BungeeCord</finalName> | ||||
|         <finalName>BungeeCord-${project.version}-${build.number}</finalName> | ||||
|         <plugins> | ||||
|             <plugin> | ||||
|                 <groupId>org.apache.maven.plugins</groupId> | ||||
| @@ -48,6 +46,7 @@ | ||||
|                             <Main-Class>net.md_5.bungee.Bootstrap</Main-Class>  | ||||
|                             <Implementation-Version>${describe}</Implementation-Version> | ||||
|                             <Specification-Version>${maven.build.timestamp}</Specification-Version> | ||||
|                             <Enable-Native-Access>ALL-UNNAMED</Enable-Native-Access> | ||||
|                         </manifestEntries> | ||||
|                     </archive> | ||||
|                 </configuration> | ||||
|   | ||||
| @@ -4,15 +4,14 @@ | ||||
|     <modelVersion>4.0.0</modelVersion> | ||||
|  | ||||
|     <parent> | ||||
|         <groupId>net.md-5</groupId> | ||||
|         <groupId>fr.pandacube.bungeecord</groupId> | ||||
|         <artifactId>bungeecord-parent</artifactId> | ||||
|         <version>1.20-R0.3-SNAPSHOT</version> | ||||
|         <version>1.21-R0.5-SNAPSHOT</version> | ||||
|         <relativePath>../pom.xml</relativePath> | ||||
|     </parent> | ||||
|  | ||||
|     <groupId>net.md-5</groupId> | ||||
|     <artifactId>bungeecord-chat</artifactId> | ||||
|     <version>1.20-R0.3-SNAPSHOT</version> | ||||
|     <version>1.21-R0.5-SNAPSHOT</version> | ||||
|     <packaging>jar</packaging> | ||||
|  | ||||
|     <name>BungeeCord-Chat</name> | ||||
| @@ -22,7 +21,7 @@ | ||||
|         <dependency> | ||||
|             <groupId>com.google.code.gson</groupId> | ||||
|             <artifactId>gson</artifactId> | ||||
|             <version>2.10.1</version> | ||||
|             <version>2.11.0</version> | ||||
|             <scope>compile</scope> | ||||
|         </dependency> | ||||
|     </dependencies> | ||||
|   | ||||
| @@ -1,8 +1,10 @@ | ||||
| package net.md_5.bungee.api.chat; | ||||
|  | ||||
| import java.awt.Color; | ||||
| import java.util.ArrayList; | ||||
| import java.util.List; | ||||
| import lombok.AccessLevel; | ||||
| import lombok.Data; | ||||
| import lombok.EqualsAndHashCode; | ||||
| import lombok.Getter; | ||||
| import lombok.Setter; | ||||
| @@ -129,6 +131,10 @@ public abstract class BaseComponent | ||||
|             { | ||||
|                 setColor( component.getColorRaw() ); | ||||
|             } | ||||
|             if ( replace || !style.hasShadowColor() ) | ||||
|             { | ||||
|                 setShadowColor( component.getShadowColorRaw() ); | ||||
|             } | ||||
|             if ( replace || !style.hasFont() ) | ||||
|             { | ||||
|                 setFont( component.getFontRaw() ); | ||||
| @@ -175,6 +181,7 @@ public abstract class BaseComponent | ||||
|         if ( retention == FormatRetention.EVENTS || retention == FormatRetention.NONE ) | ||||
|         { | ||||
|             setColor( null ); | ||||
|             setShadowColor( null ); | ||||
|             setBold( null ); | ||||
|             setItalic( null ); | ||||
|             setUnderlined( null ); | ||||
| @@ -295,6 +302,47 @@ public abstract class BaseComponent | ||||
|         return style.getColor(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Set this component's shadow color. | ||||
|      * | ||||
|      * @param color the component shadow color, or null to use the default | ||||
|      */ | ||||
|     public void setShadowColor(Color color) | ||||
|     { | ||||
|         this.style.setShadowColor( color ); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns the shadow color of this component. This uses the parent's shadow | ||||
|      * color if this component doesn't have one. null is returned if no shadow | ||||
|      * color is found. | ||||
|      * | ||||
|      * @return the shadow color of this component | ||||
|      */ | ||||
|     public Color getShadowColor() | ||||
|     { | ||||
|         if ( !style.hasShadowColor() ) | ||||
|         { | ||||
|             if ( parent == null ) | ||||
|             { | ||||
|                 return null; | ||||
|             } | ||||
|             return parent.getShadowColor(); | ||||
|         } | ||||
|         return style.getShadowColor(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns the shadow color of this component without checking the parents | ||||
|      * shadow color. May return null | ||||
|      * | ||||
|      * @return the shadow color of this component | ||||
|      */ | ||||
|     public Color getShadowColorRaw() | ||||
|     { | ||||
|         return style.getShadowColor(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Set this component's font. | ||||
|      * | ||||
| @@ -536,6 +584,10 @@ public abstract class BaseComponent | ||||
|         { | ||||
|             setColor( style.getColor() ); | ||||
|         } | ||||
|         if ( style.hasShadowColor() ) | ||||
|         { | ||||
|             setShadowColor( style.getShadowColor() ); | ||||
|         } | ||||
|         if ( style.hasFont() ) | ||||
|         { | ||||
|             setFont( style.getFont() ); | ||||
| @@ -627,11 +679,11 @@ public abstract class BaseComponent | ||||
|     public String toPlainText() | ||||
|     { | ||||
|         StringBuilder builder = new StringBuilder(); | ||||
|         toPlainText( builder ); | ||||
|         toPlainText( new LimitedStringVisitor( builder, Short.MAX_VALUE ) ); | ||||
|         return builder.toString(); | ||||
|     } | ||||
|  | ||||
|     void toPlainText(StringBuilder builder) | ||||
|     void toPlainText(StringVisitor builder) | ||||
|     { | ||||
|         if ( extra != null ) | ||||
|         { | ||||
| @@ -651,11 +703,11 @@ public abstract class BaseComponent | ||||
|     public String toLegacyText() | ||||
|     { | ||||
|         StringBuilder builder = new StringBuilder(); | ||||
|         toLegacyText( builder ); | ||||
|         toLegacyText( new LimitedStringVisitor( builder, Short.MAX_VALUE ) ); | ||||
|         return builder.toString(); | ||||
|     } | ||||
|  | ||||
|     void toLegacyText(StringBuilder builder) | ||||
|     void toLegacyText(StringVisitor builder) | ||||
|     { | ||||
|         if ( extra != null ) | ||||
|         { | ||||
| @@ -666,7 +718,7 @@ public abstract class BaseComponent | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     void addFormat(StringBuilder builder) | ||||
|     void addFormat(StringVisitor builder) | ||||
|     { | ||||
|         builder.append( getColor() ); | ||||
|         if ( isBold() ) | ||||
| @@ -690,4 +742,35 @@ public abstract class BaseComponent | ||||
|             builder.append( ChatColor.MAGIC ); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @FunctionalInterface | ||||
|     protected static interface StringVisitor | ||||
|     { | ||||
|  | ||||
|         void append(String s); | ||||
|  | ||||
|         default void append(Object obj) | ||||
|         { | ||||
|             append( String.valueOf( obj ) ); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Data | ||||
|     protected static class LimitedStringVisitor implements StringVisitor | ||||
|     { | ||||
|  | ||||
|         private final StringBuilder builder; | ||||
|         private final int maxLength; | ||||
|  | ||||
|         @Override | ||||
|         public void append(String s) | ||||
|         { | ||||
|             if ( builder.length() >= maxLength ) | ||||
|             { | ||||
|                 throw new IllegalArgumentException( "String exceeded maximum length " + maxLength ); | ||||
|             } | ||||
|  | ||||
|             builder.append( s ); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -4,12 +4,14 @@ import lombok.EqualsAndHashCode; | ||||
| import lombok.Getter; | ||||
| import lombok.RequiredArgsConstructor; | ||||
| import lombok.ToString; | ||||
| import org.jetbrains.annotations.ApiStatus; | ||||
|  | ||||
| @Getter | ||||
| @ToString | ||||
| @EqualsAndHashCode | ||||
| @RequiredArgsConstructor | ||||
| public final class ClickEvent | ||||
| @ApiStatus.NonExtendable | ||||
| public class ClickEvent | ||||
| { | ||||
|  | ||||
|     /** | ||||
| @@ -52,11 +54,19 @@ public final class ClickEvent | ||||
|          * {@link net.md_5.bungee.api.chat.ClickEvent#value} in a book. | ||||
|          */ | ||||
|         CHANGE_PAGE, | ||||
|         /** | ||||
|          * Must use subclass ShowDialogClickEvent. | ||||
|          */ | ||||
|         SHOW_DIALOG, | ||||
|         /** | ||||
|          * Copy the string given by | ||||
|          * {@link net.md_5.bungee.api.chat.ClickEvent#value} into the player's | ||||
|          * clipboard. | ||||
|          */ | ||||
|         COPY_TO_CLIPBOARD | ||||
|         COPY_TO_CLIPBOARD, | ||||
|         /** | ||||
|          * Must use subclass {@link ClickEventCustom}. | ||||
|          */ | ||||
|         CUSTOM, | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -0,0 +1,30 @@ | ||||
| package net.md_5.bungee.api.chat; | ||||
|  | ||||
| import lombok.Data; | ||||
| import lombok.EqualsAndHashCode; | ||||
| import lombok.ToString; | ||||
|  | ||||
| /** | ||||
|  * Click event which sends a custom payload to the server. | ||||
|  */ | ||||
| @Data | ||||
| @ToString(callSuper = true) | ||||
| @EqualsAndHashCode(callSuper = true) | ||||
| public class ClickEventCustom extends ClickEvent | ||||
| { | ||||
|  | ||||
|     /** | ||||
|      * The custom payload. | ||||
|      */ | ||||
|     private final String payload; | ||||
|  | ||||
|     /** | ||||
|      * @param id identifier for the event (lower case, no special characters) | ||||
|      * @param payload custom payload | ||||
|      */ | ||||
|     public ClickEventCustom(String id, String payload) | ||||
|     { | ||||
|         super( ClickEvent.Action.CUSTOM, id ); | ||||
|         this.payload = payload; | ||||
|     } | ||||
| } | ||||
| @@ -1,6 +1,7 @@ | ||||
| package net.md_5.bungee.api.chat; | ||||
|  | ||||
| import com.google.common.base.Preconditions; | ||||
| import java.awt.Color; | ||||
| import java.util.ArrayList; | ||||
| import java.util.List; | ||||
| import lombok.Getter; | ||||
| @@ -351,6 +352,19 @@ public final class ComponentBuilder | ||||
|         return this; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Sets the shadow color of the current part. | ||||
|      * | ||||
|      * @param color the new shadow color | ||||
|      * @return this ComponentBuilder for chaining | ||||
|      * @since Minecraft 1.21.4-pre1 | ||||
|      */ | ||||
|     public ComponentBuilder shadowColor(Color color) | ||||
|     { | ||||
|         getCurrentComponent().setShadowColor( color ); | ||||
|         return this; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Sets the font of the current part. | ||||
|      * | ||||
|   | ||||
| @@ -1,5 +1,6 @@ | ||||
| package net.md_5.bungee.api.chat; | ||||
|  | ||||
| import java.awt.Color; | ||||
| import lombok.AllArgsConstructor; | ||||
| import lombok.EqualsAndHashCode; | ||||
| import lombok.NoArgsConstructor; | ||||
| @@ -23,6 +24,10 @@ public final class ComponentStyle implements Cloneable | ||||
|      * {@link ChatColor#color} should not be null).</b> | ||||
|      */ | ||||
|     private ChatColor color; | ||||
|     /** | ||||
|      * The shadow color of this style. | ||||
|      */ | ||||
|     private Color shadowColor; | ||||
|     /** | ||||
|      * The font of this style. | ||||
|      */ | ||||
| @@ -68,6 +73,26 @@ public final class ComponentStyle implements Cloneable | ||||
|         return ( color != null ); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns the shadow color of this style. May return null. | ||||
|      * | ||||
|      * @return the shadow color of this style, or null if default color | ||||
|      */ | ||||
|     public Color getShadowColor() | ||||
|     { | ||||
|         return shadowColor; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns whether or not this style has a shadow color set. | ||||
|      * | ||||
|      * @return whether a shadow color is set | ||||
|      */ | ||||
|     public boolean hasShadowColor() | ||||
|     { | ||||
|         return ( shadowColor != null ); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns the font of this style. May return null. | ||||
|      * | ||||
| @@ -195,7 +220,7 @@ public final class ComponentStyle implements Cloneable | ||||
|      */ | ||||
|     public boolean isEmpty() | ||||
|     { | ||||
|         return color == null && font == null && bold == null | ||||
|         return color == null && shadowColor == null && font == null && bold == null | ||||
|                 && italic == null && underlined == null | ||||
|                 && strikethrough == null && obfuscated == null; | ||||
|     } | ||||
| @@ -203,7 +228,7 @@ public final class ComponentStyle implements Cloneable | ||||
|     @Override | ||||
|     public ComponentStyle clone() | ||||
|     { | ||||
|         return new ComponentStyle( color, font, bold, italic, underlined, strikethrough, obfuscated ); | ||||
|         return new ComponentStyle( color, shadowColor, font, bold, italic, underlined, strikethrough, obfuscated ); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
| @@ -227,6 +252,7 @@ public final class ComponentStyle implements Cloneable | ||||
|     { | ||||
|         return new ComponentStyleBuilder() | ||||
|                 .color( other.color ) | ||||
|                 .shadowColor( other.shadowColor ) | ||||
|                 .font( other.font ) | ||||
|                 .bold( other.bold ) | ||||
|                 .italic( other.italic ) | ||||
|   | ||||
| @@ -1,5 +1,6 @@ | ||||
| package net.md_5.bungee.api.chat; | ||||
|  | ||||
| import java.awt.Color; | ||||
| import net.md_5.bungee.api.ChatColor; | ||||
|  | ||||
| /** | ||||
| @@ -26,6 +27,7 @@ public final class ComponentStyleBuilder | ||||
| { | ||||
|  | ||||
|     private ChatColor color; | ||||
|     private Color shadowColor; | ||||
|     private String font; | ||||
|     private Boolean bold, italic, underlined, strikethrough, obfuscated; | ||||
|  | ||||
| @@ -41,6 +43,18 @@ public final class ComponentStyleBuilder | ||||
|         return this; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Set the style shadow color. | ||||
|      * | ||||
|      * @param shadowColor the shadow color to set, or null to use the default | ||||
|      * @return this ComponentStyleBuilder for chaining | ||||
|      */ | ||||
|     public ComponentStyleBuilder shadowColor(Color shadowColor) | ||||
|     { | ||||
|         this.shadowColor = shadowColor; | ||||
|         return this; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Set the style font. | ||||
|      * | ||||
| @@ -121,6 +135,6 @@ public final class ComponentStyleBuilder | ||||
|      */ | ||||
|     public ComponentStyle build() | ||||
|     { | ||||
|         return new ComponentStyle( color, font, bold, italic, underlined, strikethrough, obfuscated ); | ||||
|         return new ComponentStyle( color, shadowColor, font, bold, italic, underlined, strikethrough, obfuscated ); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -13,7 +13,7 @@ import net.md_5.bungee.api.chat.hover.content.Content; | ||||
| import net.md_5.bungee.api.chat.hover.content.Entity; | ||||
| import net.md_5.bungee.api.chat.hover.content.Item; | ||||
| import net.md_5.bungee.api.chat.hover.content.Text; | ||||
| import net.md_5.bungee.chat.ComponentSerializer; | ||||
| import org.jetbrains.annotations.ApiStatus; | ||||
|  | ||||
| @Getter | ||||
| @ToString | ||||
| @@ -34,6 +34,7 @@ public final class HoverEvent | ||||
|      * Returns whether this hover event is prior to 1.16 | ||||
|      */ | ||||
|     @Setter | ||||
|     @ApiStatus.Internal | ||||
|     private boolean legacy = false; | ||||
|  | ||||
|     /** | ||||
| @@ -71,22 +72,6 @@ public final class HoverEvent | ||||
|         this.legacy = true; | ||||
|     } | ||||
|  | ||||
|     @Deprecated | ||||
|     public BaseComponent[] getValue() | ||||
|     { | ||||
|         Content content = contents.get( 0 ); | ||||
|         if ( content instanceof Text && ( (Text) content ).getValue() instanceof BaseComponent[] ) | ||||
|         { | ||||
|             return (BaseComponent[]) ( (Text) content ).getValue(); | ||||
|         } | ||||
|  | ||||
|         TextComponent component = new TextComponent( ComponentSerializer.toString( content ) ); | ||||
|         return new BaseComponent[] | ||||
|         { | ||||
|             component | ||||
|         }; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Adds a content to this hover event. | ||||
|      * | ||||
|   | ||||
| @@ -50,14 +50,14 @@ public final class KeybindComponent extends BaseComponent | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void toPlainText(StringBuilder builder) | ||||
|     protected void toPlainText(StringVisitor builder) | ||||
|     { | ||||
|         builder.append( getKeybind() ); | ||||
|         super.toPlainText( builder ); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void toLegacyText(StringBuilder builder) | ||||
|     protected void toLegacyText(StringVisitor builder) | ||||
|     { | ||||
|         addFormat( builder ); | ||||
|         builder.append( getKeybind() ); | ||||
|   | ||||
| @@ -0,0 +1,73 @@ | ||||
| package net.md_5.bungee.api.chat; | ||||
|  | ||||
| import lombok.EqualsAndHashCode; | ||||
| import lombok.Getter; | ||||
| import lombok.NonNull; | ||||
| import lombok.Setter; | ||||
| import lombok.ToString; | ||||
| import net.md_5.bungee.api.chat.objects.ChatObject; | ||||
|  | ||||
| /** | ||||
|  * An object component that can be used to display objects. | ||||
|  * <p> | ||||
|  * It can either display a player's head or an object by a specific sprite and | ||||
|  * an atlas. | ||||
|  * <p> | ||||
|  * Note: this was added in Minecraft 1.21.9. | ||||
|  */ | ||||
| @Getter | ||||
| @Setter | ||||
| @ToString | ||||
| @EqualsAndHashCode(callSuper = true) | ||||
| public final class ObjectComponent extends BaseComponent | ||||
| { | ||||
|  | ||||
|     private ChatObject object; | ||||
|  | ||||
|     /** | ||||
|      * Creates a ObjectComponent from a given ChatObject. | ||||
|      * | ||||
|      * See {@link net.md_5.bungee.api.chat.objects.PlayerObject} and | ||||
|      * {@link net.md_5.bungee.api.chat.objects.SpriteObject}. | ||||
|      * | ||||
|      * @param object the ChatObject | ||||
|      */ | ||||
|     public ObjectComponent(@NonNull ChatObject object) | ||||
|     { | ||||
|         this.object = object; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates an object component from the original to clone it. | ||||
|      * | ||||
|      * @param original the original for the new score component | ||||
|      */ | ||||
|     public ObjectComponent(ObjectComponent original) | ||||
|     { | ||||
|         super( original ); | ||||
|         setObject( original.object ); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public ObjectComponent duplicate() | ||||
|     { | ||||
|         return new ObjectComponent( this ); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void toPlainText(StringVisitor builder) | ||||
|     { | ||||
|         // I guess we cannot convert this to plain text | ||||
|         // builder.append( this.value ); | ||||
|         super.toPlainText( builder ); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void toLegacyText(StringVisitor builder) | ||||
|     { | ||||
|         addFormat( builder ); | ||||
|         // Same here... | ||||
|         // builder.append( this.value ); | ||||
|         super.toLegacyText( builder ); | ||||
|     } | ||||
| } | ||||
| @@ -85,14 +85,14 @@ public final class ScoreComponent extends BaseComponent | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void toPlainText(StringBuilder builder) | ||||
|     protected void toPlainText(StringVisitor builder) | ||||
|     { | ||||
|         builder.append( this.value ); | ||||
|         super.toPlainText( builder ); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void toLegacyText(StringBuilder builder) | ||||
|     protected void toLegacyText(StringVisitor builder) | ||||
|     { | ||||
|         addFormat( builder ); | ||||
|         builder.append( this.value ); | ||||
|   | ||||
| @@ -69,14 +69,14 @@ public final class SelectorComponent extends BaseComponent | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void toPlainText(StringBuilder builder) | ||||
|     protected void toPlainText(StringVisitor builder) | ||||
|     { | ||||
|         builder.append( this.selector ); | ||||
|         super.toPlainText( builder ); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void toLegacyText(StringBuilder builder) | ||||
|     protected void toLegacyText(StringVisitor builder) | ||||
|     { | ||||
|         addFormat( builder ); | ||||
|         builder.append( this.selector ); | ||||
|   | ||||
| @@ -170,7 +170,7 @@ public final class TextComponent extends BaseComponent | ||||
|                 } | ||||
|                 continue; | ||||
|             } | ||||
|             int pos = message.indexOf( ' ', i ); | ||||
|             int pos = indexOfSpecial( message, i ); | ||||
|             if ( pos == -1 ) | ||||
|             { | ||||
|                 pos = message.length(); | ||||
| @@ -205,6 +205,20 @@ public final class TextComponent extends BaseComponent | ||||
|         appender.accept( component ); | ||||
|     } | ||||
|  | ||||
|     private static int indexOfSpecial(String message, int pos) | ||||
|     { | ||||
|         for ( int i = pos; i < message.length(); i++ ) | ||||
|         { | ||||
|             char c = message.charAt( i ); | ||||
|  | ||||
|             if ( c == ' ' || Character.isISOControl( c ) ) | ||||
|             { | ||||
|                 return i; | ||||
|             } | ||||
|         } | ||||
|         return -1; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Internal compatibility method to transform an array of components to a | ||||
|      * single component. | ||||
| @@ -280,14 +294,14 @@ public final class TextComponent extends BaseComponent | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void toPlainText(StringBuilder builder) | ||||
|     protected void toPlainText(StringVisitor builder) | ||||
|     { | ||||
|         builder.append( text ); | ||||
|         super.toPlainText( builder ); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void toLegacyText(StringBuilder builder) | ||||
|     protected void toLegacyText(StringVisitor builder) | ||||
|     { | ||||
|         addFormat( builder ); | ||||
|         builder.append( text ); | ||||
|   | ||||
| @@ -156,20 +156,20 @@ public final class TranslatableComponent extends BaseComponent | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void toPlainText(StringBuilder builder) | ||||
|     protected void toPlainText(StringVisitor builder) | ||||
|     { | ||||
|         convert( builder, false ); | ||||
|         super.toPlainText( builder ); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void toLegacyText(StringBuilder builder) | ||||
|     protected void toLegacyText(StringVisitor builder) | ||||
|     { | ||||
|         convert( builder, true ); | ||||
|         super.toLegacyText( builder ); | ||||
|     } | ||||
|  | ||||
|     private void convert(StringBuilder builder, boolean applyFormat) | ||||
|     private void convert(StringVisitor builder, boolean applyFormat) | ||||
|     { | ||||
|         String trans = TranslationRegistry.INSTANCE.translate( translate ); | ||||
|  | ||||
|   | ||||
| @@ -0,0 +1,5 @@ | ||||
| package net.md_5.bungee.api.chat.objects; | ||||
|  | ||||
| public interface ChatObject | ||||
| { | ||||
| } | ||||
| @@ -0,0 +1,39 @@ | ||||
| package net.md_5.bungee.api.chat.objects; | ||||
|  | ||||
| import java.util.UUID; | ||||
| import lombok.AllArgsConstructor; | ||||
| import lombok.Data; | ||||
| import lombok.NonNull; | ||||
| import net.md_5.bungee.api.chat.player.Profile; | ||||
| import net.md_5.bungee.api.chat.player.Property; | ||||
|  | ||||
| @Data | ||||
| @AllArgsConstructor | ||||
| public final class PlayerObject implements ChatObject | ||||
| { | ||||
|  | ||||
|     /** | ||||
|      * The profile of the player. | ||||
|      */ | ||||
|     @NonNull | ||||
|     private Profile profile; | ||||
|     /** | ||||
|      * If true, a hat layer will be rendered on the head. (default: true) | ||||
|      */ | ||||
|     private Boolean hat; | ||||
|  | ||||
|     public PlayerObject(@NonNull String name) | ||||
|     { | ||||
|         this.profile = new Profile( name ); | ||||
|     } | ||||
|  | ||||
|     public PlayerObject(@NonNull UUID uuid) | ||||
|     { | ||||
|         this.profile = new Profile( uuid ); | ||||
|     } | ||||
|  | ||||
|     public PlayerObject(@NonNull Property[] properties) | ||||
|     { | ||||
|         this.profile = new Profile( properties ); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,21 @@ | ||||
| package net.md_5.bungee.api.chat.objects; | ||||
|  | ||||
| import lombok.AllArgsConstructor; | ||||
| import lombok.Data; | ||||
| import lombok.NonNull; | ||||
|  | ||||
| @Data | ||||
| @AllArgsConstructor | ||||
| public final class SpriteObject implements ChatObject | ||||
| { | ||||
|  | ||||
|     /** | ||||
|      * The namespaced ID of a sprite atlas, default value: minecraft:blocks. | ||||
|      */ | ||||
|     private String atlas; | ||||
|     /** | ||||
|      * The namespaced ID of a sprite in atlas, for example item/porkchop. | ||||
|      */ | ||||
|     @NonNull | ||||
|     private String sprite; | ||||
| } | ||||
| @@ -0,0 +1,40 @@ | ||||
| package net.md_5.bungee.api.chat.player; | ||||
|  | ||||
| import java.util.UUID; | ||||
| import lombok.AllArgsConstructor; | ||||
| import lombok.Data; | ||||
| import lombok.NonNull; | ||||
|  | ||||
| @Data | ||||
| @AllArgsConstructor | ||||
| public class Profile | ||||
| { | ||||
|  | ||||
|     /** | ||||
|      * The name of the profile. Can be null. | ||||
|      */ | ||||
|     private String name; | ||||
|     /** | ||||
|      * The UUID of the profile. Can be null. | ||||
|      */ | ||||
|     private UUID uuid; | ||||
|     /** | ||||
|      * The properties of the profile. Can be null. | ||||
|      */ | ||||
|     private Property[] properties; | ||||
|  | ||||
|     public Profile(@NonNull String name) | ||||
|     { | ||||
|         this( name, null, null ); | ||||
|     } | ||||
|  | ||||
|     public Profile(@NonNull UUID uuid) | ||||
|     { | ||||
|         this( null, uuid, null ); | ||||
|     } | ||||
|  | ||||
|     public Profile(@NonNull Property[] properties) | ||||
|     { | ||||
|         this( null, null, properties ); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,22 @@ | ||||
| package net.md_5.bungee.api.chat.player; | ||||
|  | ||||
| import lombok.AllArgsConstructor; | ||||
| import lombok.Data; | ||||
| import lombok.NonNull; | ||||
|  | ||||
| @Data | ||||
| @AllArgsConstructor | ||||
| public class Property | ||||
| { | ||||
|  | ||||
|     @NonNull | ||||
|     private String name; | ||||
|     @NonNull | ||||
|     private String value; | ||||
|     private String signature; | ||||
|  | ||||
|     public Property(@NonNull String name, @NonNull String value) | ||||
|     { | ||||
|         this( name, value, null ); | ||||
|     } | ||||
| } | ||||
| @@ -1,153 +0,0 @@ | ||||
| package net.md_5.bungee.chat; | ||||
|  | ||||
| import com.google.common.base.Preconditions; | ||||
| import com.google.gson.JsonDeserializationContext; | ||||
| import com.google.gson.JsonElement; | ||||
| import com.google.gson.JsonObject; | ||||
| import com.google.gson.JsonSerializationContext; | ||||
| import java.util.ArrayList; | ||||
| import java.util.Arrays; | ||||
| import java.util.Collections; | ||||
| import java.util.IdentityHashMap; | ||||
| import java.util.Locale; | ||||
| import net.md_5.bungee.api.chat.BaseComponent; | ||||
| 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.hover.content.Content; | ||||
|  | ||||
| public class BaseComponentSerializer | ||||
| { | ||||
|  | ||||
|     protected void deserialize(JsonObject object, BaseComponent component, JsonDeserializationContext context) | ||||
|     { | ||||
|         component.applyStyle( context.deserialize( object, ComponentStyle.class ) ); | ||||
|  | ||||
|         JsonElement insertion = object.get( "insertion" ); | ||||
|         if ( insertion != null ) | ||||
|         { | ||||
|             component.setInsertion( insertion.getAsString() ); | ||||
|         } | ||||
|  | ||||
|         //Events | ||||
|         JsonObject clickEvent = object.getAsJsonObject( "clickEvent" ); | ||||
|         if ( clickEvent != null ) | ||||
|         { | ||||
|             component.setClickEvent( new ClickEvent( | ||||
|                     ClickEvent.Action.valueOf( clickEvent.get( "action" ).getAsString().toUpperCase( Locale.ROOT ) ), | ||||
|                     ( clickEvent.has( "value" ) ) ? clickEvent.get( "value" ).getAsString() : "" ) ); | ||||
|         } | ||||
|         JsonObject hoverEventJson = object.getAsJsonObject( "hoverEvent" ); | ||||
|         if ( hoverEventJson != null ) | ||||
|         { | ||||
|             HoverEvent hoverEvent = null; | ||||
|             HoverEvent.Action action = HoverEvent.Action.valueOf( hoverEventJson.get( "action" ).getAsString().toUpperCase( Locale.ROOT ) ); | ||||
|  | ||||
|             JsonElement value = hoverEventJson.get( "value" ); | ||||
|             if ( value != null ) | ||||
|             { | ||||
|  | ||||
|                 // 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. | ||||
|                 BaseComponent[] components; | ||||
|                 if ( value.isJsonArray() ) | ||||
|                 { | ||||
|                     components = context.deserialize( value, BaseComponent[].class ); | ||||
|                 } else | ||||
|                 { | ||||
|                     components = new BaseComponent[] | ||||
|                     { | ||||
|                         context.deserialize( value, BaseComponent.class ) | ||||
|                     }; | ||||
|                 } | ||||
|                 hoverEvent = new HoverEvent( action, components ); | ||||
|             } else | ||||
|             { | ||||
|                 JsonElement contents = hoverEventJson.get( "contents" ); | ||||
|                 if ( contents != null ) | ||||
|                 { | ||||
|                     Content[] list; | ||||
|                     if ( contents.isJsonArray() ) | ||||
|                     { | ||||
|                         list = context.deserialize( contents, HoverEvent.getClass( action, true ) ); | ||||
|                     } else | ||||
|                     { | ||||
|                         list = new Content[] | ||||
|                         { | ||||
|                             context.deserialize( contents, HoverEvent.getClass( action, false ) ) | ||||
|                         }; | ||||
|                     } | ||||
|                     hoverEvent = new HoverEvent( action, new ArrayList<>( Arrays.asList( list ) ) ); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             if ( hoverEvent != null ) | ||||
|             { | ||||
|                 component.setHoverEvent( hoverEvent ); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         JsonElement extra = object.get( "extra" ); | ||||
|         if ( extra != null ) | ||||
|         { | ||||
|             component.setExtra( Arrays.asList( context.deserialize( extra, BaseComponent[].class ) ) ); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     protected void serialize(JsonObject object, BaseComponent component, JsonSerializationContext context) | ||||
|     { | ||||
|         boolean first = false; | ||||
|         if ( ComponentSerializer.serializedComponents.get() == null ) | ||||
|         { | ||||
|             first = true; | ||||
|             ComponentSerializer.serializedComponents.set( Collections.newSetFromMap( new IdentityHashMap<BaseComponent, Boolean>() ) ); | ||||
|         } | ||||
|         try | ||||
|         { | ||||
|             Preconditions.checkArgument( !ComponentSerializer.serializedComponents.get().contains( component ), "Component loop" ); | ||||
|             ComponentSerializer.serializedComponents.get().add( component ); | ||||
|  | ||||
|             ComponentStyleSerializer.serializeTo( component.getStyle(), object ); | ||||
|  | ||||
|             if ( component.getInsertion() != null ) | ||||
|             { | ||||
|                 object.addProperty( "insertion", component.getInsertion() ); | ||||
|             } | ||||
|  | ||||
|             //Events | ||||
|             if ( component.getClickEvent() != null ) | ||||
|             { | ||||
|                 JsonObject clickEvent = new JsonObject(); | ||||
|                 clickEvent.addProperty( "action", component.getClickEvent().getAction().toString().toLowerCase( Locale.ROOT ) ); | ||||
|                 clickEvent.addProperty( "value", component.getClickEvent().getValue() ); | ||||
|                 object.add( "clickEvent", clickEvent ); | ||||
|             } | ||||
|             if ( component.getHoverEvent() != null ) | ||||
|             { | ||||
|                 JsonObject hoverEvent = new JsonObject(); | ||||
|                 hoverEvent.addProperty( "action", component.getHoverEvent().getAction().toString().toLowerCase( Locale.ROOT ) ); | ||||
|                 if ( component.getHoverEvent().isLegacy() ) | ||||
|                 { | ||||
|                     hoverEvent.add( "value", context.serialize( component.getHoverEvent().getContents().get( 0 ) ) ); | ||||
|                 } else | ||||
|                 { | ||||
|                     hoverEvent.add( "contents", context.serialize( ( component.getHoverEvent().getContents().size() == 1 ) | ||||
|                             ? component.getHoverEvent().getContents().get( 0 ) : component.getHoverEvent().getContents() ) ); | ||||
|                 } | ||||
|                 object.add( "hoverEvent", hoverEvent ); | ||||
|             } | ||||
|  | ||||
|             if ( component.getExtra() != null ) | ||||
|             { | ||||
|                 object.add( "extra", context.serialize( component.getExtra() ) ); | ||||
|             } | ||||
|         } finally | ||||
|         { | ||||
|             ComponentSerializer.serializedComponents.get().remove( component ); | ||||
|             if ( first ) | ||||
|             { | ||||
|                 ComponentSerializer.serializedComponents.set( null ); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -4,15 +4,14 @@ | ||||
|     <modelVersion>4.0.0</modelVersion> | ||||
|  | ||||
|     <parent> | ||||
|         <groupId>net.md-5</groupId> | ||||
|         <groupId>fr.pandacube.bungeecord</groupId> | ||||
|         <artifactId>bungeecord-parent</artifactId> | ||||
|         <version>1.20-R0.3-SNAPSHOT</version> | ||||
|         <version>1.21-R0.5-SNAPSHOT</version> | ||||
|         <relativePath>../pom.xml</relativePath> | ||||
|     </parent> | ||||
|  | ||||
|     <groupId>net.md-5</groupId> | ||||
|     <artifactId>bungeecord-config</artifactId> | ||||
|     <version>1.20-R0.3-SNAPSHOT</version> | ||||
|     <version>1.21-R0.5-SNAPSHOT</version> | ||||
|     <packaging>jar</packaging> | ||||
|  | ||||
|     <name>BungeeCord-Config</name> | ||||
| @@ -22,7 +21,7 @@ | ||||
|         <dependency> | ||||
|             <groupId>com.google.code.gson</groupId> | ||||
|             <artifactId>gson</artifactId> | ||||
|             <version>2.10.1</version> | ||||
|             <version>2.11.0</version> | ||||
|             <scope>compile</scope> | ||||
|             <optional>true</optional> | ||||
|         </dependency> | ||||
|   | ||||
							
								
								
									
										28
									
								
								dialog/LICENSE
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								dialog/LICENSE
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | ||||
| BSD 3-Clause License | ||||
|  | ||||
| Copyright (c) 2025, SpigotMC Pty. Ltd. | ||||
|  | ||||
| Redistribution and use in source and binary forms, with or without | ||||
| modification, are permitted provided that the following conditions are met: | ||||
|  | ||||
| 1. Redistributions of source code must retain the above copyright notice, this | ||||
|    list of conditions and the following disclaimer. | ||||
|  | ||||
| 2. Redistributions in binary form must reproduce the above copyright notice, | ||||
|    this list of conditions and the following disclaimer in the documentation | ||||
|    and/or other materials provided with the distribution. | ||||
|  | ||||
| 3. Neither the name of the copyright holder nor the names of its | ||||
|    contributors may be used to endorse or promote products derived from | ||||
|    this software without specific prior written permission. | ||||
|  | ||||
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||||
| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||||
| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
| DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE | ||||
| FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||||
| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||||
| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | ||||
| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | ||||
| OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||||
| OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
							
								
								
									
										38
									
								
								dialog/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								dialog/README.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,38 @@ | ||||
| BungeeCord-Dialog | ||||
| ================= | ||||
|  | ||||
| Highly experimental API, subject to breakage. All contributions welcome, including major refactors/design changes. | ||||
|  | ||||
| Sample Plugin | ||||
| ------------- | ||||
|  | ||||
| ```java | ||||
|     private class TestCommand extends Command | ||||
|     { | ||||
|  | ||||
|         public TestCommand() | ||||
|         { | ||||
|             super( "btest" ); | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public void execute(CommandSender sender, String[] args) | ||||
|         { | ||||
|             ProxiedPlayer player = (ProxiedPlayer) sender; | ||||
|  | ||||
|             Dialog notice = new NoticeDialog( new DialogBase( new ComponentBuilder( "Hello" ).color( ChatColor.RED ).build() ) ); | ||||
|             player.showDialog( notice ); | ||||
|  | ||||
|             notice = new NoticeDialog( | ||||
|                     new DialogBase( new ComponentBuilder( "Hello" ).color( ChatColor.RED ).build() ) | ||||
|                             .inputs( | ||||
|                                     Arrays.asList( new TextInput( "first", new ComponentBuilder( "First" ).build() ), | ||||
|                                             new TextInput( "second", new ComponentBuilder( "Second" ).build() ) | ||||
|                                     ) | ||||
|                             ) ) | ||||
|                     .action( new ActionButton( new ComponentBuilder( "Submit Button" ).build(), new CustomClickAction( "customform" ) ) ); | ||||
|  | ||||
|             player.sendMessage( new ComponentBuilder( "click me" ).event( new ShowDialogClickEvent( notice ) ).build() ); | ||||
|         } | ||||
|     } | ||||
| ``` | ||||
							
								
								
									
										35
									
								
								dialog/pom.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								dialog/pom.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
|  | ||||
| <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>fr.pandacube.bungeecord</groupId> | ||||
|         <artifactId>bungeecord-parent</artifactId> | ||||
|         <version>1.21-R0.5-SNAPSHOT</version> | ||||
|         <relativePath>../pom.xml</relativePath> | ||||
|     </parent> | ||||
|  | ||||
|     <artifactId>bungeecord-dialog</artifactId> | ||||
|     <version>1.21-R0.5-SNAPSHOT</version> | ||||
|     <packaging>jar</packaging> | ||||
|  | ||||
|     <name>BungeeCord-Dialog</name> | ||||
|     <description>Minecraft dialog API intended for use with BungeeCord</description> | ||||
|     <licenses> | ||||
|         <license> | ||||
|             <name>BSD-3-Clause</name> | ||||
|             <url>https://github.com/SpigotMC/BungeeCord/blob/master/dialog/LICENSE</url> | ||||
|             <distribution>repo</distribution> | ||||
|         </license> | ||||
|     </licenses> | ||||
|  | ||||
|     <dependencies> | ||||
|         <dependency> | ||||
|             <groupId>fr.pandacube.bungeecord</groupId> | ||||
|             <artifactId>bungeecord-chat</artifactId> | ||||
|             <version>${project.version}</version> | ||||
|             <scope>compile</scope> | ||||
|         </dependency> | ||||
|     </dependencies> | ||||
| </project> | ||||
| @@ -0,0 +1,39 @@ | ||||
| package net.md_5.bungee.api.dialog; | ||||
|  | ||||
| import lombok.AllArgsConstructor; | ||||
| import lombok.Data; | ||||
| import lombok.EqualsAndHashCode; | ||||
| import lombok.NonNull; | ||||
| import lombok.ToString; | ||||
| import lombok.experimental.Accessors; | ||||
| import net.md_5.bungee.api.dialog.action.ActionButton; | ||||
|  | ||||
| /** | ||||
|  * Represents a simple dialog with text and two actions at the bottom (default: | ||||
|  * "yes", "no"). | ||||
|  */ | ||||
| @Data | ||||
| @ToString | ||||
| @EqualsAndHashCode | ||||
| @AllArgsConstructor | ||||
| @Accessors(fluent = true) | ||||
| public final class ConfirmationDialog implements Dialog | ||||
| { | ||||
|  | ||||
|     @NonNull | ||||
|     @Accessors(fluent = false) | ||||
|     private DialogBase base; | ||||
|     /** | ||||
|      * The "yes" click action / bottom (appears on the left). | ||||
|      */ | ||||
|     private ActionButton yes; | ||||
|     /** | ||||
|      * The "no" click action / bottom (appears on the right). | ||||
|      */ | ||||
|     private ActionButton no; | ||||
|  | ||||
|     public ConfirmationDialog(@NonNull DialogBase base) | ||||
|     { | ||||
|         this( base, null, null ); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										29
									
								
								dialog/src/main/java/net/md_5/bungee/api/dialog/Dialog.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								dialog/src/main/java/net/md_5/bungee/api/dialog/Dialog.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | ||||
| package net.md_5.bungee.api.dialog; | ||||
|  | ||||
| import org.jetbrains.annotations.ApiStatus; | ||||
|  | ||||
| /** | ||||
|  * Represents a dialog GUI. | ||||
|  */ | ||||
| public interface Dialog | ||||
| { | ||||
|  | ||||
|     /** | ||||
|      * Gets the dialog base which contains the dialog title and other options | ||||
|      * common to all types of dialogs. | ||||
|      * | ||||
|      * @return mutable reference to the dialog base | ||||
|      */ | ||||
|     DialogBase getBase(); | ||||
|  | ||||
|     /** | ||||
|      * Sets the dialog base. | ||||
|      * <br> | ||||
|      * For internal use only as this is mandatory and should be specified in the | ||||
|      * constructor. | ||||
|      * | ||||
|      * @param base the new dialog base | ||||
|      */ | ||||
|     @ApiStatus.Internal | ||||
|     void setBase(DialogBase base); | ||||
| } | ||||
| @@ -0,0 +1,84 @@ | ||||
| package net.md_5.bungee.api.dialog; | ||||
|  | ||||
| import com.google.gson.annotations.SerializedName; | ||||
| import java.util.List; | ||||
| import lombok.AllArgsConstructor; | ||||
| import lombok.Data; | ||||
| import lombok.NonNull; | ||||
| import lombok.experimental.Accessors; | ||||
| import net.md_5.bungee.api.chat.BaseComponent; | ||||
| import net.md_5.bungee.api.dialog.body.DialogBody; | ||||
| import net.md_5.bungee.api.dialog.input.DialogInput; | ||||
|  | ||||
| /** | ||||
|  * Represents the title and other options common to all dialogs. | ||||
|  */ | ||||
| @Data | ||||
| @AllArgsConstructor | ||||
| @Accessors(fluent = true) | ||||
| public final class DialogBase | ||||
| { | ||||
|  | ||||
|     /** | ||||
|      * The mandatory dialog title. | ||||
|      */ | ||||
|     @NonNull | ||||
|     private BaseComponent title; | ||||
|     /** | ||||
|      * The name which is used for any buttons leading to this dialog (eg from a | ||||
|      * {@link DialogListDialog}). Otherwise defaults to {@link #title}. | ||||
|      */ | ||||
|     @SerializedName("external_title") | ||||
|     private BaseComponent externalTitle; | ||||
|     /** | ||||
|      * The inputs to the dialog. | ||||
|      */ | ||||
|     private List<DialogInput> inputs; | ||||
|     /** | ||||
|      * The body elements which make up this dialog. | ||||
|      */ | ||||
|     private List<DialogBody> body; | ||||
|     /** | ||||
|      * Whether this dialog can be closed with the escape key (default: true). | ||||
|      */ | ||||
|     @SerializedName("can_close_with_escape") | ||||
|     private Boolean canCloseWithEscape; | ||||
|     /** | ||||
|      * Whether this dialog should pause the game in single-player mode (default: | ||||
|      * true). | ||||
|      */ | ||||
|     private Boolean pause; | ||||
|     /** | ||||
|      * Action to take after the a click or submit action is performed on the | ||||
|      * dialog (default: close). | ||||
|      */ | ||||
|     @SerializedName("after_action") | ||||
|     private AfterAction afterAction; | ||||
|  | ||||
|     public DialogBase(@NonNull BaseComponent title) | ||||
|     { | ||||
|         this( title, null, null, null, null, null, null ); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Types of action which may be taken after the dialog. | ||||
|      */ | ||||
|     public enum AfterAction | ||||
|     { | ||||
|         /** | ||||
|          * Close the dialog. | ||||
|          */ | ||||
|         @SerializedName("close") | ||||
|         CLOSE, | ||||
|         /** | ||||
|          * Do nothing. | ||||
|          */ | ||||
|         @SerializedName("none") | ||||
|         NONE, | ||||
|         /** | ||||
|          * Show a waiting for response screen. | ||||
|          */ | ||||
|         @SerializedName("wait_for_response") | ||||
|         WAIT_FOR_RESPONSE; | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,74 @@ | ||||
| package net.md_5.bungee.api.dialog; | ||||
|  | ||||
| import com.google.common.base.Preconditions; | ||||
| import com.google.gson.annotations.SerializedName; | ||||
| import java.util.Arrays; | ||||
| import java.util.List; | ||||
| import lombok.Data; | ||||
| import lombok.EqualsAndHashCode; | ||||
| import lombok.NonNull; | ||||
| import lombok.ToString; | ||||
| import lombok.experimental.Accessors; | ||||
| import net.md_5.bungee.api.dialog.action.ActionButton; | ||||
|  | ||||
| /** | ||||
|  * Represents a dialog which contains buttons that link to other dialogs. | ||||
|  */ | ||||
| @Data | ||||
| @ToString | ||||
| @EqualsAndHashCode | ||||
| @Accessors(fluent = true) | ||||
| public final class DialogListDialog implements Dialog | ||||
| { | ||||
|  | ||||
|     @NonNull | ||||
|     @Accessors(fluent = false) | ||||
|     private DialogBase base; | ||||
|     /** | ||||
|      * The child dialogs behind each button. | ||||
|      */ | ||||
|     private List<Dialog> dialogs; | ||||
|     /** | ||||
|      * The {@link ActionButton} activated when the dialog is exited. | ||||
|      */ | ||||
|     @SerializedName("exit_action") | ||||
|     private ActionButton exitAction; | ||||
|     /** | ||||
|      * The number of columns for the dialog buttons (default: 2). | ||||
|      */ | ||||
|     private Integer columns; | ||||
|     /** | ||||
|      * The width of the dialog buttons (default: 150, minimum: 1, maximum: | ||||
|      * 1024). | ||||
|      */ | ||||
|     @SerializedName("button_width") | ||||
|     private Integer buttonWidth; | ||||
|  | ||||
|     public DialogListDialog(@NonNull DialogBase base, Dialog... dialogs) | ||||
|     { | ||||
|         this( base, Arrays.asList( dialogs ), null, null, null ); | ||||
|     } | ||||
|  | ||||
|     public DialogListDialog(@NonNull DialogBase base, List<Dialog> dialogs, ActionButton exitAction, Integer columns, Integer buttonWidth) | ||||
|     { | ||||
|         this.base = base; | ||||
|         this.dialogs = dialogs; | ||||
|         this.exitAction = exitAction; | ||||
|         columns( columns ); | ||||
|         buttonWidth( buttonWidth ); | ||||
|     } | ||||
|  | ||||
|     public DialogListDialog columns(Integer columns) | ||||
|     { | ||||
|         Preconditions.checkArgument( columns == null || columns > 0, "At least one column is required" ); | ||||
|         this.columns = columns; | ||||
|         return this; | ||||
|     } | ||||
|  | ||||
|     public DialogListDialog buttonWidth(Integer buttonWidth) | ||||
|     { | ||||
|         Preconditions.checkArgument( buttonWidth == null || ( buttonWidth >= 1 && buttonWidth <= 1024 ), "buttonWidth must be between 1 and 1024" ); | ||||
|         this.buttonWidth = buttonWidth; | ||||
|         return this; | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,64 @@ | ||||
| package net.md_5.bungee.api.dialog; | ||||
|  | ||||
| import com.google.common.base.Preconditions; | ||||
| import com.google.gson.annotations.SerializedName; | ||||
| import java.util.Arrays; | ||||
| import java.util.List; | ||||
| import lombok.Data; | ||||
| import lombok.EqualsAndHashCode; | ||||
| import lombok.NonNull; | ||||
| import lombok.ToString; | ||||
| import lombok.experimental.Accessors; | ||||
| import net.md_5.bungee.api.dialog.action.ActionButton; | ||||
|  | ||||
| /** | ||||
|  * Represents a dialog with text a list of action buttons grouped into columns | ||||
|  * and scrollable if necessary. | ||||
|  */ | ||||
| @Data | ||||
| @ToString | ||||
| @EqualsAndHashCode | ||||
| @Accessors(fluent = true) | ||||
| public final class MultiActionDialog implements Dialog | ||||
| { | ||||
|  | ||||
|     @NonNull | ||||
|     @Accessors(fluent = false) | ||||
|     private DialogBase base; | ||||
|     /** | ||||
|      * The action buttons in the dialog. At least one must be provided. | ||||
|      */ | ||||
|     @NonNull | ||||
|     private List<ActionButton> actions; | ||||
|     /** | ||||
|      * The number of columns for the dialog buttons (default: 2). | ||||
|      */ | ||||
|     private Integer columns; | ||||
|     /** | ||||
|      * The {@link ActionButton} activated when the dialog is exited. | ||||
|      */ | ||||
|     @SerializedName("exit_action") | ||||
|     private ActionButton exitAction; | ||||
|  | ||||
|     public MultiActionDialog(@NonNull DialogBase base, @NonNull ActionButton... actions) | ||||
|     { | ||||
|         this( base, Arrays.asList( actions ), null, null ); | ||||
|     } | ||||
|  | ||||
|     public MultiActionDialog(@NonNull DialogBase base, @NonNull List<ActionButton> actions, Integer columns, ActionButton exitAction) | ||||
|     { | ||||
|         Preconditions.checkArgument( !actions.isEmpty(), "At least one action must be provided" ); | ||||
|  | ||||
|         this.base = base; | ||||
|         this.actions = actions; | ||||
|         columns( columns ); | ||||
|         this.exitAction = exitAction; | ||||
|     } | ||||
|  | ||||
|     public MultiActionDialog columns(Integer columns) | ||||
|     { | ||||
|         Preconditions.checkArgument( columns == null || columns > 0, "At least one column is required" ); | ||||
|         this.columns = columns; | ||||
|         return this; | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,35 @@ | ||||
| package net.md_5.bungee.api.dialog; | ||||
|  | ||||
| import lombok.AllArgsConstructor; | ||||
| import lombok.Data; | ||||
| import lombok.EqualsAndHashCode; | ||||
| import lombok.NonNull; | ||||
| import lombok.ToString; | ||||
| import lombok.experimental.Accessors; | ||||
| import net.md_5.bungee.api.dialog.action.ActionButton; | ||||
|  | ||||
| /** | ||||
|  * Represents a simple dialog with text and one action at the bottom (default: | ||||
|  * "OK"). | ||||
|  */ | ||||
| @Data | ||||
| @ToString | ||||
| @EqualsAndHashCode | ||||
| @AllArgsConstructor | ||||
| @Accessors(fluent = true) | ||||
| public final class NoticeDialog implements Dialog | ||||
| { | ||||
|  | ||||
|     @NonNull | ||||
|     @Accessors(fluent = false) | ||||
|     private DialogBase base; | ||||
|     /** | ||||
|      * The "OK" action button for the dialog. | ||||
|      */ | ||||
|     private ActionButton action; | ||||
|  | ||||
|     public NoticeDialog(DialogBase base) | ||||
|     { | ||||
|         this( base, null ); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,72 @@ | ||||
| package net.md_5.bungee.api.dialog; | ||||
|  | ||||
| import com.google.common.base.Preconditions; | ||||
| import com.google.gson.annotations.SerializedName; | ||||
| import lombok.Data; | ||||
| import lombok.EqualsAndHashCode; | ||||
| import lombok.NonNull; | ||||
| import lombok.ToString; | ||||
| import lombok.experimental.Accessors; | ||||
| import net.md_5.bungee.api.dialog.action.ActionButton; | ||||
|  | ||||
| /** | ||||
|  * Represents a dialog which shows the links configured/sent from the server. | ||||
|  */ | ||||
| @Data | ||||
| @ToString | ||||
| @EqualsAndHashCode | ||||
| @Accessors(fluent = true) | ||||
| public final class ServerLinksDialog implements Dialog | ||||
| { | ||||
|  | ||||
|     @NonNull | ||||
|     @Accessors(fluent = false) | ||||
|     private DialogBase base; | ||||
|     /** | ||||
|      * The optional {@link ActionButton} for this dialog. | ||||
|      */ | ||||
|     @SerializedName("action") | ||||
|     private ActionButton action; | ||||
|     /** | ||||
|      * The {@link ActionButton} activated when the dialog is exited. | ||||
|      */ | ||||
|     @SerializedName("exit_action") | ||||
|     private ActionButton exitAction; | ||||
|     /** | ||||
|      * The number of columns for the dialog buttons (default: 2). | ||||
|      */ | ||||
|     private Integer columns; | ||||
|     /** | ||||
|      * The width of the dialog buttons (default: 150, minimum: 1, maximum: | ||||
|      * 1024). | ||||
|      */ | ||||
|     @SerializedName("button_width") | ||||
|     private Integer buttonWidth; | ||||
|  | ||||
|     public ServerLinksDialog(@NonNull DialogBase base) | ||||
|     { | ||||
|         this( base, null, null, null ); | ||||
|     } | ||||
|  | ||||
|     public ServerLinksDialog(@NonNull DialogBase base, ActionButton action, Integer columns, Integer buttonWidth) | ||||
|     { | ||||
|         this.base = base; | ||||
|         this.action = action; | ||||
|         columns( columns ); | ||||
|         buttonWidth( buttonWidth ); | ||||
|     } | ||||
|  | ||||
|     public ServerLinksDialog columns(Integer columns) | ||||
|     { | ||||
|         Preconditions.checkArgument( columns == null || columns > 0, "At least one column is required" ); | ||||
|         this.columns = columns; | ||||
|         return this; | ||||
|     } | ||||
|  | ||||
|     public ServerLinksDialog buttonWidth(Integer buttonWidth) | ||||
|     { | ||||
|         Preconditions.checkArgument( buttonWidth == null || ( buttonWidth >= 1 && buttonWidth <= 1024 ), "buttonWidth must be between 1 and 1024" ); | ||||
|         this.buttonWidth = buttonWidth; | ||||
|         return this; | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,6 @@ | ||||
| package net.md_5.bungee.api.dialog.action; | ||||
|  | ||||
| public interface Action | ||||
| { | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,54 @@ | ||||
| package net.md_5.bungee.api.dialog.action; | ||||
|  | ||||
| import com.google.common.base.Preconditions; | ||||
| import lombok.Data; | ||||
| import lombok.NonNull; | ||||
| import lombok.experimental.Accessors; | ||||
| import net.md_5.bungee.api.chat.BaseComponent; | ||||
|  | ||||
| /** | ||||
|  * Represents a dialog action which will usually appear as a button. | ||||
|  */ | ||||
| @Data | ||||
| @Accessors(fluent = true) | ||||
| public class ActionButton | ||||
| { | ||||
|  | ||||
|     /** | ||||
|      * The text label of the button, mandatory. | ||||
|      */ | ||||
|     @NonNull | ||||
|     private BaseComponent label; | ||||
|     /** | ||||
|      * The hover tooltip of the button. | ||||
|      */ | ||||
|     private BaseComponent tooltip; | ||||
|     /** | ||||
|      * The width of the button (default: 150, minimum: 1, maximum: 1024). | ||||
|      */ | ||||
|     private Integer width; | ||||
|     /** | ||||
|      * The action to take. | ||||
|      */ | ||||
|     @NonNull | ||||
|     private Action action; | ||||
|  | ||||
|     public ActionButton(@NonNull BaseComponent label, BaseComponent tooltip, Integer width, @NonNull Action action) | ||||
|     { | ||||
|         this.label = label; | ||||
|         this.tooltip = tooltip; | ||||
|         setWidth( width ); | ||||
|         this.action = action; | ||||
|     } | ||||
|  | ||||
|     public ActionButton(@NonNull BaseComponent label, @NonNull Action action) | ||||
|     { | ||||
|         this( label, null, null, action ); | ||||
|     } | ||||
|  | ||||
|     public void setWidth(Integer width) | ||||
|     { | ||||
|         Preconditions.checkArgument( width == null || ( width >= 1 && width <= 1024 ), "width must be between 1 and 1024" ); | ||||
|         this.width = width; | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,27 @@ | ||||
| package net.md_5.bungee.api.dialog.action; | ||||
|  | ||||
| import com.google.gson.JsonElement; | ||||
| import lombok.Data; | ||||
| import lombok.NonNull; | ||||
| import lombok.ToString; | ||||
| import lombok.experimental.Accessors; | ||||
|  | ||||
| /** | ||||
|  * Submits the dialog with the given ID and values as a payload. | ||||
|  */ | ||||
| @Data | ||||
| @Accessors(fluent = true) | ||||
| @ToString(callSuper = true) | ||||
| public class CustomClickAction implements Action | ||||
| { | ||||
|  | ||||
|     /** | ||||
|      * The namespaced key of the submission. | ||||
|      */ | ||||
|     @NonNull | ||||
|     private String id; | ||||
|     /** | ||||
|      * Fields to be added to the submission payload. | ||||
|      */ | ||||
|     private JsonElement additions; | ||||
| } | ||||
| @@ -0,0 +1,25 @@ | ||||
| package net.md_5.bungee.api.dialog.action; | ||||
|  | ||||
| import lombok.Data; | ||||
| import lombok.NonNull; | ||||
| import lombok.ToString; | ||||
| import lombok.experimental.Accessors; | ||||
|  | ||||
| /** | ||||
|  * Executes a command. If the command requires a permission higher than 0, a | ||||
|  * confirmation dialog will be shown by the client. | ||||
|  */ | ||||
| @Data | ||||
| @Accessors(fluent = true) | ||||
| @ToString(callSuper = true) | ||||
| public class RunCommandAction implements Action | ||||
| { | ||||
|  | ||||
|     /** | ||||
|      * The template to be applied, where variables of the form | ||||
|      * <code>$(key)</code> will be replaced by their | ||||
|      * {@link net.md_5.bungee.api.dialog.input.DialogInput#key} value. | ||||
|      */ | ||||
|     @NonNull | ||||
|     private String template; | ||||
| } | ||||
| @@ -0,0 +1,20 @@ | ||||
| package net.md_5.bungee.api.dialog.action; | ||||
|  | ||||
| import lombok.Data; | ||||
| import lombok.NonNull; | ||||
| import lombok.ToString; | ||||
| import lombok.experimental.Accessors; | ||||
| import net.md_5.bungee.api.chat.ClickEvent; | ||||
|  | ||||
| /** | ||||
|  * Represents a static dialog action. | ||||
|  */ | ||||
| @Data | ||||
| @Accessors(fluent = true) | ||||
| @ToString(callSuper = true) | ||||
| public class StaticAction implements Action | ||||
| { | ||||
|  | ||||
|     @NonNull | ||||
|     private ClickEvent clickEvent; | ||||
| } | ||||
| @@ -0,0 +1,4 @@ | ||||
| /** | ||||
|  * Contains the different actions/buttons for a {@link net.md_5.bungee.api.dialog.Dialog}. | ||||
|  */ | ||||
| package net.md_5.bungee.api.dialog.action; | ||||
| @@ -0,0 +1,20 @@ | ||||
| package net.md_5.bungee.api.dialog.body; | ||||
|  | ||||
| import lombok.Data; | ||||
| import lombok.NonNull; | ||||
| import org.jetbrains.annotations.ApiStatus; | ||||
|  | ||||
| /** | ||||
|  * Represents the body content of a {@link net.md_5.bungee.api.dialog.Dialog}. | ||||
|  */ | ||||
| @Data | ||||
| public abstract class DialogBody | ||||
| { | ||||
|  | ||||
|     /** | ||||
|      * The internal body type. | ||||
|      */ | ||||
|     @NonNull | ||||
|     @ApiStatus.Internal | ||||
|     private final String type; | ||||
| } | ||||
| @@ -0,0 +1,49 @@ | ||||
| package net.md_5.bungee.api.dialog.body; | ||||
|  | ||||
| import com.google.common.base.Preconditions; | ||||
| import lombok.Data; | ||||
| import lombok.EqualsAndHashCode; | ||||
| import lombok.NonNull; | ||||
| import lombok.ToString; | ||||
| import lombok.experimental.Accessors; | ||||
| import net.md_5.bungee.api.chat.BaseComponent; | ||||
|  | ||||
| /** | ||||
|  * Represents a dialog body which consists of text constrained to a certain | ||||
|  * width. | ||||
|  */ | ||||
| @Data | ||||
| @Accessors(fluent = true) | ||||
| @ToString(callSuper = true) | ||||
| @EqualsAndHashCode(callSuper = true) | ||||
| public class PlainMessageBody extends DialogBody | ||||
| { | ||||
|  | ||||
|     /** | ||||
|      * The text body. | ||||
|      */ | ||||
|     @NonNull | ||||
|     private BaseComponent contents; | ||||
|     /** | ||||
|      * The maximum width (default: 200, minimum: 1, maximum: 1024). | ||||
|      */ | ||||
|     private Integer width; | ||||
|  | ||||
|     public PlainMessageBody(@NonNull BaseComponent contents) | ||||
|     { | ||||
|         this( contents, null ); | ||||
|     } | ||||
|  | ||||
|     public PlainMessageBody(@NonNull BaseComponent contents, Integer width) | ||||
|     { | ||||
|         super( "minecraft:plain_message" ); | ||||
|         this.contents = contents; | ||||
|         width( width ); | ||||
|     } | ||||
|  | ||||
|     public void width(Integer width) | ||||
|     { | ||||
|         Preconditions.checkArgument( width == null || ( width >= 1 && width <= 1024 ), "width must be between 1 and 1024" ); | ||||
|         this.width = width; | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,5 @@ | ||||
| /** | ||||
|  * Contains the different {@link net.md_5.bungee.api.dialog.Dialog} body content | ||||
|  * types. | ||||
|  */ | ||||
| package net.md_5.bungee.api.dialog.body; | ||||
| @@ -0,0 +1,42 @@ | ||||
| package net.md_5.bungee.api.dialog.chat; | ||||
|  | ||||
| import lombok.Data; | ||||
| import lombok.EqualsAndHashCode; | ||||
| import net.md_5.bungee.api.chat.ClickEvent; | ||||
| import net.md_5.bungee.api.dialog.Dialog; | ||||
|  | ||||
| /** | ||||
|  * Click event which displays either a pre-existing dialog by key or a custom | ||||
|  * dialog. | ||||
|  */ | ||||
| @Data | ||||
| @EqualsAndHashCode(callSuper = false) | ||||
| public class ShowDialogClickEvent extends ClickEvent | ||||
| { | ||||
|  | ||||
|     /** | ||||
|      * Key for a pre-existing dialog to show. | ||||
|      */ | ||||
|     private String reference; | ||||
|     /** | ||||
|      * Dialog to show. | ||||
|      */ | ||||
|     private Dialog dialog; | ||||
|  | ||||
|     public ShowDialogClickEvent(String reference) | ||||
|     { | ||||
|         this( reference, null ); | ||||
|     } | ||||
|  | ||||
|     public ShowDialogClickEvent(Dialog dialog) | ||||
|     { | ||||
|         this( null, dialog ); | ||||
|     } | ||||
|  | ||||
|     private ShowDialogClickEvent(String reference, Dialog dialog) | ||||
|     { | ||||
|         super( Action.SHOW_DIALOG, null ); | ||||
|         this.reference = reference; | ||||
|         this.dialog = dialog; | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,4 @@ | ||||
| /** | ||||
|  * Contains dialog extensions to the chat API. | ||||
|  */ | ||||
| package net.md_5.bungee.api.dialog.chat; | ||||
| @@ -0,0 +1,54 @@ | ||||
| package net.md_5.bungee.api.dialog.input; | ||||
|  | ||||
| import com.google.gson.annotations.SerializedName; | ||||
| import lombok.Data; | ||||
| import lombok.EqualsAndHashCode; | ||||
| import lombok.NonNull; | ||||
| import lombok.ToString; | ||||
| import lombok.experimental.Accessors; | ||||
| import net.md_5.bungee.api.chat.BaseComponent; | ||||
|  | ||||
| /** | ||||
|  * Represents a checkbox input control. | ||||
|  */ | ||||
| @Data | ||||
| @Accessors(fluent = true) | ||||
| @ToString(callSuper = true) | ||||
| @EqualsAndHashCode(callSuper = true) | ||||
| public class BooleanInput extends DialogInput | ||||
| { | ||||
|  | ||||
|     /** | ||||
|      * The input label. | ||||
|      */ | ||||
|     @NonNull | ||||
|     private BaseComponent label; | ||||
|     /** | ||||
|      * The initial value (default: false/unchecked). | ||||
|      */ | ||||
|     private Boolean initial; | ||||
|     /** | ||||
|      * The string value to be submitted when true/checked (default: "true"). | ||||
|      */ | ||||
|     @SerializedName("on_true") | ||||
|     private String onTrue; | ||||
|     /** | ||||
|      * The string value to be submitted when false/unchecked (default: "false"). | ||||
|      */ | ||||
|     @SerializedName("on_false") | ||||
|     private String onFalse; | ||||
|  | ||||
|     public BooleanInput(@NonNull String key, @NonNull BaseComponent label) | ||||
|     { | ||||
|         this( key, label, null, "true", "false" ); | ||||
|     } | ||||
|  | ||||
|     public BooleanInput(@NonNull String key, @NonNull BaseComponent label, Boolean initial, String onTrue, String onFalse) | ||||
|     { | ||||
|         super( "minecraft:boolean", key ); | ||||
|         this.label = label; | ||||
|         this.initial = initial; | ||||
|         this.onTrue = onTrue; | ||||
|         this.onFalse = onFalse; | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,29 @@ | ||||
| package net.md_5.bungee.api.dialog.input; | ||||
|  | ||||
| import lombok.Data; | ||||
| import lombok.NonNull; | ||||
| import lombok.experimental.Accessors; | ||||
| import org.jetbrains.annotations.ApiStatus; | ||||
|  | ||||
| /** | ||||
|  * Represents a type of input which may be displayed/submitted with a form | ||||
|  * dialog. | ||||
|  */ | ||||
| @Data | ||||
| @Accessors(fluent = true) | ||||
| public class DialogInput | ||||
| { | ||||
|  | ||||
|     /** | ||||
|      * The internal input type. | ||||
|      */ | ||||
|     @NonNull | ||||
|     @ApiStatus.Internal | ||||
|     private final String type; | ||||
|     /** | ||||
|      * The key corresponding to this input and associated with the value | ||||
|      * submitted. | ||||
|      */ | ||||
|     @NonNull | ||||
|     private final String key; | ||||
| } | ||||
| @@ -0,0 +1,39 @@ | ||||
| package net.md_5.bungee.api.dialog.input; | ||||
|  | ||||
| import lombok.AllArgsConstructor; | ||||
| import lombok.Data; | ||||
| import lombok.NonNull; | ||||
| import lombok.experimental.Accessors; | ||||
| import net.md_5.bungee.api.chat.BaseComponent; | ||||
|  | ||||
| /** | ||||
|  * Represents an option choice which may form part of a | ||||
|  * {@link SingleOptionInput}. | ||||
|  */ | ||||
| @Data | ||||
| @AllArgsConstructor | ||||
| @Accessors(fluent = true) | ||||
| public class InputOption | ||||
| { | ||||
|  | ||||
|     /** | ||||
|      * The string value associated with this option, to be submitted when | ||||
|      * selected. | ||||
|      */ | ||||
|     @NonNull | ||||
|     private String id; | ||||
|     /** | ||||
|      * The text to display for this option. | ||||
|      */ | ||||
|     private BaseComponent display; | ||||
|     /** | ||||
|      * Whether this option is the one initially selected. Only one option may | ||||
|      * have this value as true (default: first option). | ||||
|      */ | ||||
|     private Boolean initial; | ||||
|  | ||||
|     public InputOption(@NonNull String id) | ||||
|     { | ||||
|         this( id, null, null ); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,103 @@ | ||||
| package net.md_5.bungee.api.dialog.input; | ||||
|  | ||||
| import com.google.common.base.Preconditions; | ||||
| import lombok.Data; | ||||
| import lombok.EqualsAndHashCode; | ||||
| import lombok.NonNull; | ||||
| import lombok.ToString; | ||||
| import lombok.experimental.Accessors; | ||||
| import net.md_5.bungee.api.chat.BaseComponent; | ||||
|  | ||||
| /** | ||||
|  * Represents a number slider input. | ||||
|  */ | ||||
| @Data | ||||
| @Accessors(fluent = true) | ||||
| @ToString(callSuper = true) | ||||
| @EqualsAndHashCode(callSuper = true) | ||||
| public class NumberRangeInput extends DialogInput | ||||
| { | ||||
|  | ||||
|     /** | ||||
|      * The width of the input (default: 200, minimum: 1, maximum: 1024). | ||||
|      */ | ||||
|     private Integer width; | ||||
|     /** | ||||
|      * The label of the slider. | ||||
|      */ | ||||
|     @NonNull | ||||
|     private BaseComponent label; | ||||
|     /** | ||||
|      * A translate key used to display the label value (default: | ||||
|      * options.generic_value). | ||||
|      */ | ||||
|     private String labelFormat; | ||||
|     /** | ||||
|      * The start position of the slider (leftmost position). | ||||
|      */ | ||||
|     private float start; | ||||
|     /** | ||||
|      * The end position of the slider (rightmost position). | ||||
|      */ | ||||
|     private float end; | ||||
|     /** | ||||
|      * The steps in which the input will be increased or decreased, or null if | ||||
|      * no specific steps. | ||||
|      */ | ||||
|     private Float step; | ||||
|     /** | ||||
|      * The initial value of number input, or null to fall back to the middle. | ||||
|      */ | ||||
|     private Float initial; | ||||
|  | ||||
|     public NumberRangeInput(@NonNull String key, @NonNull BaseComponent label, float start, float end) | ||||
|     { | ||||
|         this( key, null, label, "options.generic_value", start, end, null, null ); | ||||
|     } | ||||
|  | ||||
|     public NumberRangeInput(@NonNull String key, @NonNull BaseComponent label, float start, float end, Float step) | ||||
|     { | ||||
|         this( key, null, label, "options.generic_value", start, end, step, null ); | ||||
|     } | ||||
|  | ||||
|     public NumberRangeInput(@NonNull String key, @NonNull BaseComponent label, float start, float end, Float step, Float initial) | ||||
|     { | ||||
|         this( key, null, label, "options.generic_value", start, end, step, initial ); | ||||
|     } | ||||
|  | ||||
|     public NumberRangeInput(@NonNull String key, Integer width, @NonNull BaseComponent label, String labelFormat, float start, float end, Float step, Float initial) | ||||
|     { | ||||
|         super( "minecraft:number_range", key ); | ||||
|         width( width ); | ||||
|         this.label = label; | ||||
|         this.labelFormat = labelFormat; | ||||
|         this.start = start; | ||||
|         this.end = end; | ||||
|         step( step ); | ||||
|         initial( initial ); | ||||
|     } | ||||
|  | ||||
|     public NumberRangeInput width(Integer width) | ||||
|     { | ||||
|         Preconditions.checkArgument( width == null || ( width >= 1 && width <= 1024 ), "with must be between 1 and 1024" ); | ||||
|         this.width = width; | ||||
|         return this; | ||||
|     } | ||||
|  | ||||
|     public NumberRangeInput step(Float step) | ||||
|     { | ||||
|         Preconditions.checkArgument( step == null || step > 0, "step must be null or greater than zero" ); | ||||
|         this.step = step; | ||||
|         return this; | ||||
|     } | ||||
|  | ||||
|     public NumberRangeInput initial(Float initial) | ||||
|     { | ||||
|         // we need to calculate if the initial value is between start and end, regardless of the order | ||||
|         float min = Math.min( start, end ); | ||||
|         float max = Math.max( start, end ); | ||||
|         Preconditions.checkArgument( initial == null || ( initial >= min && initial <= max ), "initial must be null or between start and end" ); | ||||
|         this.initial = initial; | ||||
|         return this; | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,66 @@ | ||||
| package net.md_5.bungee.api.dialog.input; | ||||
|  | ||||
| import com.google.common.base.Preconditions; | ||||
| import com.google.gson.annotations.SerializedName; | ||||
| import java.util.Arrays; | ||||
| import java.util.List; | ||||
| import lombok.Data; | ||||
| import lombok.EqualsAndHashCode; | ||||
| import lombok.NonNull; | ||||
| import lombok.ToString; | ||||
| import lombok.experimental.Accessors; | ||||
| import net.md_5.bungee.api.chat.BaseComponent; | ||||
|  | ||||
| /** | ||||
|  * Represents a single option (dropdown) input. | ||||
|  */ | ||||
| @Data | ||||
| @Accessors(fluent = true) | ||||
| @ToString(callSuper = true) | ||||
| @EqualsAndHashCode(callSuper = true) | ||||
| public class SingleOptionInput extends DialogInput | ||||
| { | ||||
|  | ||||
|     /** | ||||
|      * The width of the input (default: 200, minimum: 1, maximum: 1024). | ||||
|      */ | ||||
|     private Integer width; | ||||
|     /** | ||||
|      * The input label. | ||||
|      */ | ||||
|     @NonNull | ||||
|     private BaseComponent label; | ||||
|     /** | ||||
|      * Whether the label is visible (default: true). | ||||
|      */ | ||||
|     @SerializedName("label_visible") | ||||
|     private Boolean labelVisible; | ||||
|     /** | ||||
|      * The non-empty list of options to be selected from. | ||||
|      */ | ||||
|     @NonNull | ||||
|     private List<InputOption> options; | ||||
|  | ||||
|     public SingleOptionInput(@NonNull String key, @NonNull BaseComponent label, @NonNull InputOption... options) | ||||
|     { | ||||
|         this( key, null, label, null, Arrays.asList( options ) ); | ||||
|     } | ||||
|  | ||||
|     public SingleOptionInput(@NonNull String key, Integer width, @NonNull BaseComponent label, Boolean labelVisible, @NonNull List<InputOption> options) | ||||
|     { | ||||
|         super( "minecraft:single_option", key ); | ||||
|         Preconditions.checkArgument( !options.isEmpty(), "At least one option must be provided" ); | ||||
|  | ||||
|         width( width ); | ||||
|         this.label = label; | ||||
|         this.labelVisible = labelVisible; | ||||
|         this.options = options; | ||||
|     } | ||||
|  | ||||
|     public SingleOptionInput width(Integer width) | ||||
|     { | ||||
|         Preconditions.checkArgument( width == null || ( width >= 1 && width <= 1024 ), "width must be between 1 and 1024" ); | ||||
|         this.width = width; | ||||
|         return this; | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,110 @@ | ||||
| package net.md_5.bungee.api.dialog.input; | ||||
|  | ||||
| import com.google.common.base.Preconditions; | ||||
| import com.google.gson.annotations.SerializedName; | ||||
| import lombok.Data; | ||||
| import lombok.EqualsAndHashCode; | ||||
| import lombok.NoArgsConstructor; | ||||
| import lombok.NonNull; | ||||
| import lombok.ToString; | ||||
| import lombok.experimental.Accessors; | ||||
| import net.md_5.bungee.api.chat.BaseComponent; | ||||
|  | ||||
| /** | ||||
|  * Represents a textbox input. | ||||
|  */ | ||||
| @Data | ||||
| @Accessors(fluent = true) | ||||
| @ToString(callSuper = true) | ||||
| @EqualsAndHashCode(callSuper = true) | ||||
| public class TextInput extends DialogInput | ||||
| { | ||||
|  | ||||
|     /** | ||||
|      * The width of this text input (default: 200, minimum: 1, maximum: 1024). | ||||
|      */ | ||||
|     private Integer width; | ||||
|     /** | ||||
|      * The label of this text input. | ||||
|      */ | ||||
|     @NonNull | ||||
|     private BaseComponent label; | ||||
|     /** | ||||
|      * The visibility of this text input's label. | ||||
|      */ | ||||
|     @SerializedName("label_visible") | ||||
|     private Boolean labelVisible; | ||||
|     /** | ||||
|      * The initial value of this text input. | ||||
|      */ | ||||
|     private String initial; | ||||
|     /** | ||||
|      * The maximum length of the input (default: 32). | ||||
|      */ | ||||
|     @SerializedName("max_length") | ||||
|     private Integer maxLength; | ||||
|     /** | ||||
|      * If present, allows users to input multiple lines. | ||||
|      */ | ||||
|     private Multiline multiline; | ||||
|  | ||||
|     public TextInput(@NonNull String key, @NonNull BaseComponent label) | ||||
|     { | ||||
|         this( key, null, label, null, null, null, null ); | ||||
|     } | ||||
|  | ||||
|     public TextInput(@NonNull String key, Integer width, @NonNull BaseComponent label, Boolean labelVisible, String initial, Integer maxLength) | ||||
|     { | ||||
|         this( key, width, label, labelVisible, initial, maxLength, null ); | ||||
|     } | ||||
|  | ||||
|     public TextInput(@NonNull String key, Integer width, @NonNull BaseComponent label, Boolean labelVisible, String initial, Integer maxLength, Multiline multiline) | ||||
|     { | ||||
|         super( "minecraft:text", key ); | ||||
|         width( width ); | ||||
|         this.label = label; | ||||
|         this.labelVisible = labelVisible; | ||||
|         this.initial = initial; | ||||
|         this.maxLength = maxLength; | ||||
|         this.multiline = multiline; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Configuration data for a multiline input. | ||||
|      */ | ||||
|     @Data | ||||
|     @NoArgsConstructor | ||||
|     @Accessors(fluent = true) | ||||
|     public static class Multiline | ||||
|     { | ||||
|  | ||||
|         /** | ||||
|          * The maximum length of input, or null to disable any limits. | ||||
|          */ | ||||
|         @SerializedName("max_lines") | ||||
|         private Integer maxLines; | ||||
|         /** | ||||
|          * The height of this input (default: 32, minimum: 1, maximum: 512). | ||||
|          */ | ||||
|         private Integer height; | ||||
|  | ||||
|         public Multiline(Integer maxLines, Integer height) | ||||
|         { | ||||
|             height( height ).maxLines( maxLines ); | ||||
|         } | ||||
|  | ||||
|         public Multiline height(Integer height) | ||||
|         { | ||||
|             Preconditions.checkArgument( height == null || height >= 1 && height <= 512, "height must null or be between 1 and 512" ); | ||||
|             this.height = height; | ||||
|             return this; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public TextInput width(Integer width) | ||||
|     { | ||||
|         Preconditions.checkArgument( width == null || ( width >= 1 && width <= 1024 ), "width must be between 1 and 1024" ); | ||||
|         this.width = width; | ||||
|         return this; | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,4 @@ | ||||
| /** | ||||
|  * Represents the various input controls which may be present on form dialogs. | ||||
|  */ | ||||
| package net.md_5.bungee.api.dialog.input; | ||||
| @@ -0,0 +1,4 @@ | ||||
| /** | ||||
|  * Contains the core classes for the display of a {@link net.md_5.bungee.api.dialog.Dialog}. | ||||
|  */ | ||||
| package net.md_5.bungee.api.dialog; | ||||
| @@ -4,15 +4,14 @@ | ||||
|     <modelVersion>4.0.0</modelVersion> | ||||
|  | ||||
|     <parent> | ||||
|         <groupId>net.md-5</groupId> | ||||
|         <groupId>fr.pandacube.bungeecord</groupId> | ||||
|         <artifactId>bungeecord-parent</artifactId> | ||||
|         <version>1.20-R0.3-SNAPSHOT</version> | ||||
|         <version>1.21-R0.5-SNAPSHOT</version> | ||||
|         <relativePath>../pom.xml</relativePath> | ||||
|     </parent> | ||||
|  | ||||
|     <groupId>net.md-5</groupId> | ||||
|     <artifactId>bungeecord-event</artifactId> | ||||
|     <version>1.20-R0.3-SNAPSHOT</version> | ||||
|     <version>1.21-R0.5-SNAPSHOT</version> | ||||
|     <packaging>jar</packaging> | ||||
|  | ||||
|     <name>BungeeCord-Event</name> | ||||
|   | ||||
							
								
								
									
										13
									
								
								log/pom.xml
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								log/pom.xml
									
									
									
									
									
								
							| @@ -4,15 +4,14 @@ | ||||
|     <modelVersion>4.0.0</modelVersion> | ||||
|  | ||||
|     <parent> | ||||
|         <groupId>net.md-5</groupId> | ||||
|         <groupId>fr.pandacube.bungeecord</groupId> | ||||
|         <artifactId>bungeecord-parent</artifactId> | ||||
|         <version>1.20-R0.3-SNAPSHOT</version> | ||||
|         <version>1.21-R0.5-SNAPSHOT</version> | ||||
|         <relativePath>../pom.xml</relativePath> | ||||
|     </parent> | ||||
|  | ||||
|     <groupId>net.md-5</groupId> | ||||
|     <artifactId>bungeecord-log</artifactId> | ||||
|     <version>1.20-R0.3-SNAPSHOT</version> | ||||
|     <version>1.21-R0.5-SNAPSHOT</version> | ||||
|     <packaging>jar</packaging> | ||||
|  | ||||
|     <name>BungeeCord-Log</name> | ||||
| @@ -20,13 +19,13 @@ | ||||
|  | ||||
|     <dependencies> | ||||
|         <dependency> | ||||
|             <groupId>jline</groupId> | ||||
|             <groupId>org.jline</groupId> | ||||
|             <artifactId>jline</artifactId> | ||||
|             <version>2.12.1</version> | ||||
|             <version>3.30.4</version> | ||||
|             <scope>compile</scope> | ||||
|         </dependency> | ||||
|         <dependency> | ||||
|             <groupId>net.md-5</groupId> | ||||
|             <groupId>fr.pandacube.bungeecord</groupId> | ||||
|             <artifactId>bungeecord-chat</artifactId> | ||||
|             <version>${project.version}</version> | ||||
|             <scope>compile</scope> | ||||
|   | ||||
| @@ -1,26 +1,18 @@ | ||||
| package net.md_5.bungee.log; | ||||
|  | ||||
| import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; | ||||
| import java.io.IOException; | ||||
| import java.util.logging.FileHandler; | ||||
| import java.util.logging.Level; | ||||
| import java.util.logging.LogRecord; | ||||
| import java.util.logging.Logger; | ||||
| import jline.console.ConsoleReader; | ||||
| import org.jline.reader.LineReader; | ||||
|  | ||||
| public class BungeeLogger extends Logger | ||||
| { | ||||
|  | ||||
|     private final LogDispatcher dispatcher = new LogDispatcher( this ); | ||||
|  | ||||
|     // CHECKSTYLE:OFF | ||||
|     @SuppressWarnings( | ||||
|             { | ||||
|                 "CallToPrintStackTrace", "CallToThreadStartDuringObjectConstruction" | ||||
|             }) | ||||
|     // CHECKSTYLE:ON | ||||
|     @SuppressFBWarnings("SC_START_IN_CTOR") | ||||
|     public BungeeLogger(String loggerName, String filePattern, ConsoleReader reader) | ||||
|     public BungeeLogger(String loggerName, String filePattern, LineReader reader) | ||||
|     { | ||||
|         super( loggerName, null ); | ||||
|         setLevel( Level.ALL ); | ||||
|   | ||||
| @@ -1,15 +1,15 @@ | ||||
| package net.md_5.bungee.log; | ||||
|  | ||||
| import java.io.IOException; | ||||
| import java.util.logging.Handler; | ||||
| import java.util.logging.LogRecord; | ||||
| import java.util.regex.Pattern; | ||||
| import jline.console.ConsoleReader; | ||||
| import lombok.Data; | ||||
| import lombok.RequiredArgsConstructor; | ||||
| import net.md_5.bungee.api.ChatColor; | ||||
| import org.fusesource.jansi.Ansi; | ||||
| import org.fusesource.jansi.Ansi.Erase; | ||||
| import org.jline.jansi.Ansi; | ||||
| import org.jline.reader.LineReader; | ||||
|  | ||||
| @RequiredArgsConstructor | ||||
| public class ColouredWriter extends Handler | ||||
| { | ||||
|  | ||||
| @@ -52,12 +52,7 @@ public class ColouredWriter extends Handler | ||||
|         compile( ChatColor.RESET, Ansi.ansi().a( Ansi.Attribute.RESET ).toString() ), | ||||
|     }; | ||||
|     // | ||||
|     private final ConsoleReader console; | ||||
|  | ||||
|     public ColouredWriter(ConsoleReader console) | ||||
|     { | ||||
|         this.console = console; | ||||
|     } | ||||
|     private final LineReader console; | ||||
|  | ||||
|     public void print(String s) | ||||
|     { | ||||
| @@ -65,14 +60,7 @@ public class ColouredWriter extends Handler | ||||
|         { | ||||
|             s = replacement.pattern.matcher( s ).replaceAll( replacement.replacement ); | ||||
|         } | ||||
|         try | ||||
|         { | ||||
|             console.print( Ansi.ansi().eraseLine( Erase.ALL ).toString() + ConsoleReader.RESET_LINE + s + Ansi.ansi().reset().toString() ); | ||||
|             console.drawLine(); | ||||
|             console.flush(); | ||||
|         } catch ( IOException ex ) | ||||
|         { | ||||
|         } | ||||
|         console.printAbove( s + Ansi.ansi().reset().toString() ); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|   | ||||
| @@ -18,7 +18,6 @@ public class ConciseFormatter extends Formatter | ||||
|     private final boolean coloured; | ||||
|  | ||||
|     @Override | ||||
|     @SuppressWarnings("ThrowableResultIgnored") | ||||
|     public String format(LogRecord record) | ||||
|     { | ||||
|         StringBuilder formatted = new StringBuilder(); | ||||
|   | ||||
| @@ -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.3-SNAPSHOT</version> | ||||
|         <relativePath>../pom.xml</relativePath> | ||||
|     </parent> | ||||
|  | ||||
|     <groupId>net.md-5</groupId> | ||||
|     <artifactId>bungeecord-module-cmd-alert</artifactId> | ||||
|     <version>1.20-R0.3-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,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.3-SNAPSHOT</version> | ||||
|         <relativePath>../pom.xml</relativePath> | ||||
|     </parent> | ||||
|  | ||||
|     <groupId>net.md-5</groupId> | ||||
|     <artifactId>bungeecord-module-cmd-find</artifactId> | ||||
|     <version>1.20-R0.3-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,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.3-SNAPSHOT</version> | ||||
|         <relativePath>../pom.xml</relativePath> | ||||
|     </parent> | ||||
|  | ||||
|     <groupId>net.md-5</groupId> | ||||
|     <artifactId>bungeecord-module-cmd-kick</artifactId> | ||||
|     <version>1.20-R0.3-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.3-SNAPSHOT</version> | ||||
|         <relativePath>../pom.xml</relativePath> | ||||
|     </parent> | ||||
|  | ||||
|     <groupId>net.md-5</groupId> | ||||
|     <artifactId>bungeecord-module-cmd-list</artifactId> | ||||
|     <version>1.20-R0.3-SNAPSHOT</version> | ||||
|     <packaging>jar</packaging> | ||||
|  | ||||
|     <name>cmd_list</name> | ||||
|     <description>Provides the glist command</description> | ||||
| </project> | ||||
| @@ -1,79 +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.chat.BaseComponent; | ||||
| 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.hover.content.Text; | ||||
| 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" ); | ||||
|         boolean moduleLoaded = ProxyServer.getInstance().getPluginManager().getPlugin( "cmd_server" ) != null; | ||||
|  | ||||
|         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 ); | ||||
|  | ||||
|             BaseComponent baseComponent = new ComponentBuilder().appendLegacy( ProxyServer.getInstance().getTranslation( "command_list", server.getName(), players.size(), String.join( ChatColor.RESET + ", ", players ) ) ).build(); | ||||
|  | ||||
|             if ( moduleLoaded ) | ||||
|             { | ||||
|                 baseComponent.setHoverEvent( new HoverEvent( | ||||
|                         HoverEvent.Action.SHOW_TEXT, | ||||
|                         new Text( new ComponentBuilder().appendLegacy( ProxyServer.getInstance().getTranslation( "click_to_connect" ) ).create() ) ) | ||||
|                 ); | ||||
|                 baseComponent.setClickEvent( new ClickEvent( ClickEvent.Action.RUN_COMMAND, "/server " + server.getName() ) ); | ||||
|             } | ||||
|  | ||||
|             sender.sendMessage( baseComponent ); | ||||
|         } | ||||
|  | ||||
|         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.3-SNAPSHOT</version> | ||||
|         <relativePath>../pom.xml</relativePath> | ||||
|     </parent> | ||||
|  | ||||
|     <groupId>net.md-5</groupId> | ||||
|     <artifactId>bungeecord-module-cmd-send</artifactId> | ||||
|     <version>1.20-R0.3-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() ); | ||||
|     } | ||||
| } | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user