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: | jobs: | ||||||
|   build: |   build: | ||||||
|     runs-on: ubuntu-22.04 |     runs-on: ubuntu-24.04 | ||||||
|  |  | ||||||
|     strategy: |     strategy: | ||||||
|       fail-fast: false |       fail-fast: false | ||||||
|       matrix: |       matrix: | ||||||
|         java: [8, 11, 17, 21] |         java: [8, 11, 17, 21, 25] | ||||||
|  |  | ||||||
|     name: Java ${{ matrix.java }} |     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). | 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> |     <modelVersion>4.0.0</modelVersion> | ||||||
|  |  | ||||||
|     <parent> |     <parent> | ||||||
|         <groupId>net.md-5</groupId> |         <groupId>fr.pandacube.bungeecord</groupId> | ||||||
|         <artifactId>bungeecord-parent</artifactId> |         <artifactId>bungeecord-parent</artifactId> | ||||||
|         <version>1.20-R0.3-SNAPSHOT</version> |         <version>1.21-R0.5-SNAPSHOT</version> | ||||||
|         <relativePath>../pom.xml</relativePath> |         <relativePath>../pom.xml</relativePath> | ||||||
|     </parent> |     </parent> | ||||||
|  |  | ||||||
|     <groupId>net.md-5</groupId> |  | ||||||
|     <artifactId>bungeecord-api</artifactId> |     <artifactId>bungeecord-api</artifactId> | ||||||
|     <version>1.20-R0.3-SNAPSHOT</version> |     <version>1.21-R0.5-SNAPSHOT</version> | ||||||
|     <packaging>jar</packaging> |     <packaging>jar</packaging> | ||||||
|  |  | ||||||
|     <name>BungeeCord-API</name> |     <name>BungeeCord-API</name> | ||||||
| @@ -20,25 +19,31 @@ | |||||||
|  |  | ||||||
|     <dependencies> |     <dependencies> | ||||||
|         <dependency> |         <dependency> | ||||||
|             <groupId>net.md-5</groupId> |             <groupId>fr.pandacube.bungeecord</groupId> | ||||||
|             <artifactId>bungeecord-chat</artifactId> |             <artifactId>bungeecord-chat</artifactId> | ||||||
|             <version>${project.version}</version> |             <version>${project.version}</version> | ||||||
|             <scope>compile</scope> |             <scope>compile</scope> | ||||||
|         </dependency> |         </dependency> | ||||||
|         <dependency> |         <dependency> | ||||||
|             <groupId>net.md-5</groupId> |             <groupId>fr.pandacube.bungeecord</groupId> | ||||||
|             <artifactId>bungeecord-config</artifactId> |             <artifactId>bungeecord-config</artifactId> | ||||||
|             <version>${project.version}</version> |             <version>${project.version}</version> | ||||||
|             <scope>compile</scope> |             <scope>compile</scope> | ||||||
|         </dependency> |         </dependency> | ||||||
|         <dependency> |         <dependency> | ||||||
|             <groupId>net.md-5</groupId> |             <groupId>fr.pandacube.bungeecord</groupId> | ||||||
|  |             <artifactId>bungeecord-dialog</artifactId> | ||||||
|  |             <version>${project.version}</version> | ||||||
|  |             <scope>compile</scope> | ||||||
|  |         </dependency> | ||||||
|  |         <dependency> | ||||||
|  |             <groupId>fr.pandacube.bungeecord</groupId> | ||||||
|             <artifactId>bungeecord-event</artifactId> |             <artifactId>bungeecord-event</artifactId> | ||||||
|             <version>${project.version}</version> |             <version>${project.version}</version> | ||||||
|             <scope>compile</scope> |             <scope>compile</scope> | ||||||
|         </dependency> |         </dependency> | ||||||
|         <dependency> |         <dependency> | ||||||
|             <groupId>net.md-5</groupId> |             <groupId>fr.pandacube.bungeecord</groupId> | ||||||
|             <artifactId>bungeecord-protocol</artifactId> |             <artifactId>bungeecord-protocol</artifactId> | ||||||
|             <version>${project.version}</version> |             <version>${project.version}</version> | ||||||
|             <scope>compile</scope> |             <scope>compile</scope> | ||||||
| @@ -69,6 +74,12 @@ | |||||||
|             <!-- not part of the API proper --> |             <!-- not part of the API proper --> | ||||||
|             <scope>provided</scope> |             <scope>provided</scope> | ||||||
|         </dependency> |         </dependency> | ||||||
|  |         <dependency> | ||||||
|  |             <groupId>org.ow2.asm</groupId> | ||||||
|  |             <artifactId>asm-commons</artifactId> | ||||||
|  |             <version>9.8</version> | ||||||
|  |             <scope>compile</scope> | ||||||
|  |         </dependency> | ||||||
|         <dependency> |         <dependency> | ||||||
|             <groupId>org.yaml</groupId> |             <groupId>org.yaml</groupId> | ||||||
|             <artifactId>snakeyaml</artifactId> |             <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.Plugin; | ||||||
| import net.md_5.bungee.api.plugin.PluginManager; | import net.md_5.bungee.api.plugin.PluginManager; | ||||||
| import net.md_5.bungee.api.scheduler.TaskScheduler; | import net.md_5.bungee.api.scheduler.TaskScheduler; | ||||||
|  | import net.md_5.bungee.protocol.channel.BungeeChannelInitializer; | ||||||
|  |  | ||||||
| public abstract class ProxyServer | public abstract class ProxyServer | ||||||
| { | { | ||||||
| @@ -311,4 +312,56 @@ public abstract class ProxyServer | |||||||
|      */ |      */ | ||||||
|     public abstract Title createTitle(); |     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 |          * @param packet the packet to send | ||||||
|          */ |          */ | ||||||
|         void sendPacket(DefinedPacket packet); |         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 |     @ApiStatus.Experimental | ||||||
|     CompletableFuture<byte[]> retrieveCookie(String cookie); |     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; | package net.md_5.bungee.api.connection; | ||||||
|  |  | ||||||
|  | import java.util.List; | ||||||
| import java.util.Locale; | import java.util.Locale; | ||||||
| import java.util.Map; | import java.util.Map; | ||||||
| import java.util.UUID; | 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.ChatMessageType; | ||||||
| import net.md_5.bungee.api.CommandSender; | import net.md_5.bungee.api.CommandSender; | ||||||
| import net.md_5.bungee.api.ServerConnectRequest; | 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.SkinConfiguration; | ||||||
| import net.md_5.bungee.api.Title; | import net.md_5.bungee.api.Title; | ||||||
| import net.md_5.bungee.api.chat.BaseComponent; | import net.md_5.bungee.api.chat.BaseComponent; | ||||||
| import net.md_5.bungee.api.config.ServerInfo; | 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.event.ServerConnectEvent; | ||||||
| import net.md_5.bungee.api.score.Scoreboard; | import net.md_5.bungee.api.score.Scoreboard; | ||||||
| import org.jetbrains.annotations.ApiStatus; | import org.jetbrains.annotations.ApiStatus; | ||||||
| @@ -382,4 +385,44 @@ public interface ProxiedPlayer extends Connection, CommandSender | |||||||
|      */ |      */ | ||||||
|     @ApiStatus.Experimental |     @ApiStatus.Experimental | ||||||
|     void transfer(String host, int port); |     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.AllArgsConstructor; | ||||||
| import lombok.EqualsAndHashCode; | import lombok.EqualsAndHashCode; | ||||||
| import lombok.Getter; | import lombok.Getter; | ||||||
|  | import lombok.ToString; | ||||||
| import net.md_5.bungee.api.CommandSender; | import net.md_5.bungee.api.CommandSender; | ||||||
| import net.md_5.bungee.api.plugin.Event; | 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 |  * Called when somebody reloads BungeeCord | ||||||
|  */ |  */ | ||||||
| @Getter | @Getter | ||||||
|  | @ToString(callSuper = false) | ||||||
| @AllArgsConstructor | @AllArgsConstructor | ||||||
| @EqualsAndHashCode(callSuper = false) | @EqualsAndHashCode(callSuper = false) | ||||||
| public class ProxyReloadEvent extends Event | 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. |  * Event called when a player uses tab completion. | ||||||
|  |  * @deprecated please use {@link TabCompleteRequestEvent} to support 1.13+ suggestions. | ||||||
|  */ |  */ | ||||||
|  | @Deprecated | ||||||
| @Data | @Data | ||||||
| @ToString(callSuper = true) | @ToString(callSuper = true) | ||||||
| @EqualsAndHashCode(callSuper = true) | @EqualsAndHashCode(callSuper = true) | ||||||
|   | |||||||
| @@ -0,0 +1,85 @@ | |||||||
|  | package net.md_5.bungee.api.event; | ||||||
|  |  | ||||||
|  | import com.google.common.base.Preconditions; | ||||||
|  | import com.mojang.brigadier.context.StringRange; | ||||||
|  | import com.mojang.brigadier.suggestion.Suggestions; | ||||||
|  | import lombok.Data; | ||||||
|  | import lombok.EqualsAndHashCode; | ||||||
|  | import lombok.ToString; | ||||||
|  | import net.md_5.bungee.api.connection.Connection; | ||||||
|  | import net.md_5.bungee.api.connection.ProxiedPlayer; | ||||||
|  | import net.md_5.bungee.api.plugin.Cancellable; | ||||||
|  | import net.md_5.bungee.protocol.ProtocolConstants; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Event called when a player uses tab completion. | ||||||
|  |  */ | ||||||
|  | @Data | ||||||
|  | @ToString(callSuper = true) | ||||||
|  | @EqualsAndHashCode(callSuper = true) | ||||||
|  | public class TabCompleteRequestEvent extends TargetedEvent implements Cancellable | ||||||
|  | { | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Cancelled state. | ||||||
|  |      */ | ||||||
|  |     private boolean cancelled; | ||||||
|  |     /** | ||||||
|  |      * The message the player has already entered. | ||||||
|  |      */ | ||||||
|  |     private final String cursor; | ||||||
|  |     /** | ||||||
|  |      * Range corresponding to the last word of {@link #getCursor()}. | ||||||
|  |      * If you want your suggestions to be compatible with 1.12 and older | ||||||
|  |      * clients, you need to {@link #setSuggestions(Suggestions)} with | ||||||
|  |      * a range equals to this one. | ||||||
|  |      * For 1.13 and newer clients, any other range that cover any part of | ||||||
|  |      * {@link #getCursor()} is fine.<br> | ||||||
|  |      * To check if the client supports custom ranges, use | ||||||
|  |      * {@link #supportsCustomRange()}. | ||||||
|  |      */ | ||||||
|  |     private final StringRange legacyCompatibleRange; | ||||||
|  |     /** | ||||||
|  |      * The suggestions that will be sent to the client. If this list is empty, | ||||||
|  |      * the request will be forwarded to the server. | ||||||
|  |      */ | ||||||
|  |     private Suggestions suggestions; | ||||||
|  |  | ||||||
|  |     public TabCompleteRequestEvent(Connection sender, Connection receiver, String cursor, StringRange legacyCompatibleRange, Suggestions suggestions) | ||||||
|  |     { | ||||||
|  |         super( sender, receiver ); | ||||||
|  |         this.cursor = cursor; | ||||||
|  |         this.legacyCompatibleRange = legacyCompatibleRange; | ||||||
|  |         this.suggestions = suggestions; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Sets the suggestions that will be sent to the client. | ||||||
|  |      * If this list is empty, the request will be forwarded to the server. | ||||||
|  |      * @param suggestions the new Suggestions. Cannot be null. | ||||||
|  |      * @throws IllegalArgumentException if the client is on 1.12 or lower and | ||||||
|  |      * {@code suggestions.getRange()} is not equals to {@link #legacyCompatibleRange}. | ||||||
|  |      */ | ||||||
|  |     public void setSuggestions(Suggestions suggestions) | ||||||
|  |     { | ||||||
|  |         Preconditions.checkNotNull( suggestions ); | ||||||
|  |         Preconditions.checkArgument( supportsCustomRange() || legacyCompatibleRange.equals( suggestions.getRange() ), | ||||||
|  |                 "Clients on 1.12 or lower versions don't support the provided range for tab-completion: " + suggestions.getRange() | ||||||
|  |                 + ". Please use TabCompleteRequestEvent.getLegacyCompatibleRange() for legacy clients." ); | ||||||
|  |         this.suggestions = suggestions; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Convenient method to tell if the client supports custom range for | ||||||
|  |      * suggestions. | ||||||
|  |      * If the client is on 1.13 or above, this methods returns true, and any | ||||||
|  |      * range can be used for {@link #setSuggestions(Suggestions)}. Otherwise, | ||||||
|  |      * it returns false and the defined range must be equals to | ||||||
|  |      * {@link #legacyCompatibleRange}. | ||||||
|  |      * @return true if the client is on 1.13 or newer version, false otherwise. | ||||||
|  |      */ | ||||||
|  |     public boolean supportsCustomRange() | ||||||
|  |     { | ||||||
|  |         return ( (ProxiedPlayer) getSender() ).getPendingConnection().getVersion() >= ProtocolConstants.MINECRAFT_1_13; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -35,6 +35,7 @@ import org.eclipse.aether.transport.http.HttpTransporterFactory; | |||||||
| class LibraryLoader | class LibraryLoader | ||||||
| { | { | ||||||
|  |  | ||||||
|  |     private static final String REPOSITORY_PROPERTY = "net.md_5.bungee.api.plugin.centralURL"; | ||||||
|     private final Logger logger; |     private final Logger logger; | ||||||
|     private final RepositorySystem repository; |     private final RepositorySystem repository; | ||||||
|     private final DefaultRepositorySystemSession session; |     private final DefaultRepositorySystemSession session; | ||||||
| @@ -68,7 +69,7 @@ class LibraryLoader | |||||||
|         session.setSystemProperties( System.getProperties() ); |         session.setSystemProperties( System.getProperties() ); | ||||||
|         session.setReadOnly(); |         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) |     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.ProxyServer; | ||||||
| import net.md_5.bungee.api.config.ConfigurationAdapter; | import net.md_5.bungee.api.config.ConfigurationAdapter; | ||||||
| import net.md_5.bungee.api.scheduler.GroupedThreadFactory; | 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 |  * Represents any Plugin that may be loaded at runtime to enhance existing | ||||||
| @@ -108,7 +109,14 @@ public class Plugin | |||||||
|     // |     // | ||||||
|     private ExecutorService service; |     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 |     @Deprecated | ||||||
|  |     @ApiStatus.Internal | ||||||
|     public ExecutorService getExecutorService() |     public ExecutorService getExecutorService() | ||||||
|     { |     { | ||||||
|         if ( service == null ) |         if ( service == null ) | ||||||
|   | |||||||
| @@ -1,6 +1,7 @@ | |||||||
| package net.md_5.bungee.api.plugin; | package net.md_5.bungee.api.plugin; | ||||||
|  |  | ||||||
| import com.google.common.base.Preconditions; | import com.google.common.base.Preconditions; | ||||||
|  | import com.google.common.collect.ImmutableMap; | ||||||
| import com.google.common.io.ByteStreams; | import com.google.common.io.ByteStreams; | ||||||
| import java.io.File; | import java.io.File; | ||||||
| import java.io.IOException; | import java.io.IOException; | ||||||
| @@ -9,13 +10,20 @@ import java.net.URL; | |||||||
| import java.net.URLClassLoader; | import java.net.URLClassLoader; | ||||||
| import java.security.CodeSigner; | import java.security.CodeSigner; | ||||||
| import java.security.CodeSource; | import java.security.CodeSource; | ||||||
|  | import java.util.Map; | ||||||
| import java.util.Set; | import java.util.Set; | ||||||
| import java.util.concurrent.CopyOnWriteArraySet; | import java.util.concurrent.CopyOnWriteArraySet; | ||||||
| import java.util.jar.JarEntry; | import java.util.jar.JarEntry; | ||||||
| import java.util.jar.JarFile; | import java.util.jar.JarFile; | ||||||
| import java.util.jar.Manifest; | import java.util.jar.Manifest; | ||||||
|  | import java.util.logging.Level; | ||||||
|  | import java.util.logging.Logger; | ||||||
| import lombok.ToString; | import lombok.ToString; | ||||||
| import net.md_5.bungee.api.ProxyServer; | 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") | @ToString(of = "desc") | ||||||
| final class PluginClassloader extends URLClassLoader | final class PluginClassloader extends URLClassLoader | ||||||
| @@ -121,6 +129,15 @@ final class PluginClassloader extends URLClassLoader | |||||||
|                 throw new ClassNotFoundException( name, ex ); |                 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( '.' ); |             int dot = name.lastIndexOf( '.' ); | ||||||
|             if ( dot != -1 ) |             if ( dot != -1 ) | ||||||
|             { |             { | ||||||
| @@ -155,6 +172,27 @@ final class PluginClassloader extends URLClassLoader | |||||||
|         return super.findClass( name ); |         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 |     @Override | ||||||
|     public void close() throws IOException |     public void close() throws IOException | ||||||
|     { |     { | ||||||
|   | |||||||
| @@ -23,9 +23,14 @@ import java.util.Locale; | |||||||
| import java.util.Map; | import java.util.Map; | ||||||
| import java.util.Set; | import java.util.Set; | ||||||
| import java.util.Stack; | 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.JarEntry; | ||||||
| import java.util.jar.JarFile; | import java.util.jar.JarFile; | ||||||
| import java.util.logging.Level; | import java.util.logging.Level; | ||||||
|  | import lombok.Locked; | ||||||
| import lombok.RequiredArgsConstructor; | import lombok.RequiredArgsConstructor; | ||||||
| import net.md_5.bungee.api.ChatColor; | import net.md_5.bungee.api.ChatColor; | ||||||
| import net.md_5.bungee.api.CommandSender; | 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, Command> commandsByPlugin = ArrayListMultimap.create(); | ||||||
|     private final Multimap<Plugin, Listener> listenersByPlugin = ArrayListMultimap.create(); |     private final Multimap<Plugin, Listener> listenersByPlugin = ArrayListMultimap.create(); | ||||||
|  |  | ||||||
|  |     private final ReadWriteLock commandsLock = new ReentrantReadWriteLock(); | ||||||
|  |     private final Lock listenersLock = new ReentrantLock(); | ||||||
|  |  | ||||||
|     @SuppressWarnings("unchecked") |     @SuppressWarnings("unchecked") | ||||||
|     public PluginManager(ProxyServer proxy) |     public PluginManager(ProxyServer proxy) | ||||||
|     { |     { | ||||||
| @@ -91,6 +99,7 @@ public final class PluginManager | |||||||
|      * @param plugin the plugin owning this command |      * @param plugin the plugin owning this command | ||||||
|      * @param command the command to register |      * @param command the command to register | ||||||
|      */ |      */ | ||||||
|  |     @Locked.Write("commandsLock") | ||||||
|     public void registerCommand(Plugin plugin, Command command) |     public void registerCommand(Plugin plugin, Command command) | ||||||
|     { |     { | ||||||
|         commandMap.put( command.getName().toLowerCase( Locale.ROOT ), command ); |         commandMap.put( command.getName().toLowerCase( Locale.ROOT ), command ); | ||||||
| @@ -106,6 +115,7 @@ public final class PluginManager | |||||||
|      * |      * | ||||||
|      * @param command the command to unregister |      * @param command the command to unregister | ||||||
|      */ |      */ | ||||||
|  |     @Locked.Write("commandsLock") | ||||||
|     public void unregisterCommand(Command command) |     public void unregisterCommand(Command command) | ||||||
|     { |     { | ||||||
|         while ( commandMap.values().remove( command ) ); |         while ( commandMap.values().remove( command ) ); | ||||||
| @@ -117,6 +127,7 @@ public final class PluginManager | |||||||
|      * |      * | ||||||
|      * @param plugin the plugin to register the commands of |      * @param plugin the plugin to register the commands of | ||||||
|      */ |      */ | ||||||
|  |     @Locked.Write("commandsLock") | ||||||
|     public void unregisterCommands(Plugin plugin) |     public void unregisterCommands(Plugin plugin) | ||||||
|     { |     { | ||||||
|         for ( Iterator<Command> it = commandsByPlugin.get( plugin ).iterator(); it.hasNext(); ) |         for ( Iterator<Command> it = commandsByPlugin.get( plugin ).iterator(); it.hasNext(); ) | ||||||
| @@ -137,7 +148,14 @@ public final class PluginManager | |||||||
|             return null; |             return null; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         commandsLock.readLock().lock(); | ||||||
|  |         try | ||||||
|  |         { | ||||||
|             return commandMap.get( commandLower ); |             return commandMap.get( commandLower ); | ||||||
|  |         } finally | ||||||
|  |         { | ||||||
|  |             commandsLock.readLock().unlock(); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
| @@ -432,12 +450,12 @@ public final class PluginManager | |||||||
|      * @param plugin the owning plugin |      * @param plugin the owning plugin | ||||||
|      * @param listener the listener to register events for |      * @param listener the listener to register events for | ||||||
|      */ |      */ | ||||||
|  |     @Locked("listenersLock") | ||||||
|     public void registerListener(Plugin plugin, Listener listener) |     public void registerListener(Plugin plugin, Listener listener) | ||||||
|     { |     { | ||||||
|         for ( Method method : listener.getClass().getDeclaredMethods() ) |         for ( Method method : listener.getClass().getDeclaredMethods() ) | ||||||
|         { |         { | ||||||
|             Preconditions.checkArgument( !method.isAnnotationPresent( Subscribe.class ), |             Preconditions.checkArgument( !method.isAnnotationPresent( Subscribe.class ), "Listener %s has registered using deprecated subscribe annotation! Please update to @EventHandler.", listener ); | ||||||
|                     "Listener %s has registered using deprecated subscribe annotation! Please update to @EventHandler.", listener ); |  | ||||||
|         } |         } | ||||||
|         eventBus.register( listener ); |         eventBus.register( listener ); | ||||||
|         listenersByPlugin.put( plugin, listener ); |         listenersByPlugin.put( plugin, listener ); | ||||||
| @@ -448,6 +466,7 @@ public final class PluginManager | |||||||
|      * |      * | ||||||
|      * @param listener the listener to unregister |      * @param listener the listener to unregister | ||||||
|      */ |      */ | ||||||
|  |     @Locked("listenersLock") | ||||||
|     public void unregisterListener(Listener listener) |     public void unregisterListener(Listener listener) | ||||||
|     { |     { | ||||||
|         eventBus.unregister( listener ); |         eventBus.unregister( listener ); | ||||||
| @@ -459,6 +478,7 @@ public final class PluginManager | |||||||
|      * |      * | ||||||
|      * @param plugin target plugin |      * @param plugin target plugin | ||||||
|      */ |      */ | ||||||
|  |     @Locked("listenersLock") | ||||||
|     public void unregisterListeners(Plugin plugin) |     public void unregisterListeners(Plugin plugin) | ||||||
|     { |     { | ||||||
|         for ( Iterator<Listener> it = listenersByPlugin.get( plugin ).iterator(); it.hasNext(); ) |         for ( Iterator<Listener> it = listenersByPlugin.get( plugin ).iterator(); it.hasNext(); ) | ||||||
| @@ -473,6 +493,7 @@ public final class PluginManager | |||||||
|      * |      * | ||||||
|      * @return commands |      * @return commands | ||||||
|      */ |      */ | ||||||
|  |     @Locked.Read("commandsLock") | ||||||
|     public Collection<Map.Entry<String, Command>> getCommands() |     public Collection<Map.Entry<String, Command>> getCommands() | ||||||
|     { |     { | ||||||
|         return Collections.unmodifiableCollection( commandMap.entrySet() ); |         return Collections.unmodifiableCollection( commandMap.entrySet() ); | ||||||
|   | |||||||
| @@ -1,22 +1,37 @@ | |||||||
| package net.md_5.bungee.util; | package net.md_5.bungee.util; | ||||||
|  |  | ||||||
| import gnu.trove.strategy.HashingStrategy; | import it.unimi.dsi.fastutil.Hash; | ||||||
| import java.util.Locale; | import java.util.Locale; | ||||||
|  |  | ||||||
| class CaseInsensitiveHashingStrategy implements HashingStrategy | class CaseInsensitiveHashingStrategy implements Hash.Strategy<String> | ||||||
| { | { | ||||||
|  |  | ||||||
|     static final CaseInsensitiveHashingStrategy INSTANCE = new CaseInsensitiveHashingStrategy(); |     static final CaseInsensitiveHashingStrategy INSTANCE = new CaseInsensitiveHashingStrategy(); | ||||||
|  |  | ||||||
|     @Override |     @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 |     @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; | package net.md_5.bungee.util; | ||||||
|  |  | ||||||
| import gnu.trove.map.hash.TCustomHashMap; | import it.unimi.dsi.fastutil.objects.Object2ObjectOpenCustomHashMap; | ||||||
| import java.util.Map; | import java.util.Map; | ||||||
|  |  | ||||||
| public class CaseInsensitiveMap<V> extends TCustomHashMap<String, V> | public class CaseInsensitiveMap<V> extends Object2ObjectOpenCustomHashMap<String, V> | ||||||
| { | { | ||||||
|  |  | ||||||
|     public CaseInsensitiveMap() |     public CaseInsensitiveMap() | ||||||
| @@ -13,6 +13,6 @@ public class CaseInsensitiveMap<V> extends TCustomHashMap<String, V> | |||||||
|  |  | ||||||
|     public CaseInsensitiveMap(Map<? extends String, ? extends V> map) |     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; | package net.md_5.bungee.util; | ||||||
|  |  | ||||||
| import gnu.trove.set.hash.TCustomHashSet; | import it.unimi.dsi.fastutil.objects.ObjectOpenCustomHashSet; | ||||||
| import java.util.Collection; | import java.util.Collection; | ||||||
|  |  | ||||||
| public class CaseInsensitiveSet extends TCustomHashSet<String> | public class CaseInsensitiveSet extends ObjectOpenCustomHashSet<String> | ||||||
| { | { | ||||||
|  |  | ||||||
|     public CaseInsensitiveSet() |     public CaseInsensitiveSet() | ||||||
| @@ -13,6 +13,6 @@ public class CaseInsensitiveSet extends TCustomHashSet<String> | |||||||
|  |  | ||||||
|     public CaseInsensitiveSet(Collection<? extends String> collection) |     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<>(); |         CaseInsensitiveMap<Object> map = new CaseInsensitiveMap<>(); | ||||||
|  |  | ||||||
|         map.put( "FOO", obj ); |         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 |         assertTrue( map.entrySet().iterator().next().getKey().equals( "FOO" ) ); // Assert that case is preserved | ||||||
|  |  | ||||||
|         // Assert that remove is case insensitive |         // Assert that remove is case insensitive | ||||||
|         map.remove( "FoO" ); |         map.remove( "FoO" ); | ||||||
|         assertFalse( map.contains( "foo" ) ); |         assertFalse( map.containsKey( "foo" ) ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Test |     @Test | ||||||
|   | |||||||
| @@ -4,31 +4,29 @@ | |||||||
|     <modelVersion>4.0.0</modelVersion> |     <modelVersion>4.0.0</modelVersion> | ||||||
|  |  | ||||||
|     <parent> |     <parent> | ||||||
|         <groupId>net.md-5</groupId> |         <groupId>fr.pandacube.bungeecord</groupId> | ||||||
|         <artifactId>bungeecord-parent</artifactId> |         <artifactId>bungeecord-parent</artifactId> | ||||||
|         <version>1.20-R0.3-SNAPSHOT</version> |         <version>1.21-R0.5-SNAPSHOT</version> | ||||||
|         <relativePath>../pom.xml</relativePath> |         <relativePath>../pom.xml</relativePath> | ||||||
|     </parent> |     </parent> | ||||||
|  |  | ||||||
|     <groupId>net.md-5</groupId> |  | ||||||
|     <artifactId>bungeecord-bootstrap</artifactId> |     <artifactId>bungeecord-bootstrap</artifactId> | ||||||
|     <version>1.20-R0.3-SNAPSHOT</version> |     <version>1.21-R0.5-SNAPSHOT</version> | ||||||
|     <packaging>jar</packaging> |     <packaging>jar</packaging> | ||||||
|  |  | ||||||
|     <name>BungeeCord-Bootstrap</name> |     <name>BungeeCord-Bootstrap</name> | ||||||
|     <description>Java 1.6 loader for BungeeCord</description> |     <description>Java 1.6 loader for BungeeCord</description> | ||||||
|  |  | ||||||
|     <properties> |     <properties> | ||||||
|  |         <skipPublishing>true</skipPublishing> | ||||||
|         <maven.deploy.skip>true</maven.deploy.skip> |         <maven.deploy.skip>true</maven.deploy.skip> | ||||||
|         <maven.javadoc.skip>true</maven.javadoc.skip> |         <maven.javadoc.skip>true</maven.javadoc.skip> | ||||||
|         <maven.compiler.source>1.6</maven.compiler.source> |  | ||||||
|         <maven.compiler.target>1.6</maven.compiler.target> |  | ||||||
|         <maven.build.timestamp.format>yyyyMMdd</maven.build.timestamp.format> |         <maven.build.timestamp.format>yyyyMMdd</maven.build.timestamp.format> | ||||||
|     </properties> |     </properties> | ||||||
|  |  | ||||||
|     <dependencies> |     <dependencies> | ||||||
|         <dependency> |         <dependency> | ||||||
|             <groupId>net.md-5</groupId> |             <groupId>fr.pandacube.bungeecord</groupId> | ||||||
|             <artifactId>bungeecord-proxy</artifactId> |             <artifactId>bungeecord-proxy</artifactId> | ||||||
|             <version>${project.version}</version> |             <version>${project.version}</version> | ||||||
|             <scope>compile</scope> |             <scope>compile</scope> | ||||||
| @@ -36,7 +34,7 @@ | |||||||
|     </dependencies> |     </dependencies> | ||||||
|  |  | ||||||
|     <build> |     <build> | ||||||
|         <finalName>BungeeCord</finalName> |         <finalName>BungeeCord-${project.version}-${build.number}</finalName> | ||||||
|         <plugins> |         <plugins> | ||||||
|             <plugin> |             <plugin> | ||||||
|                 <groupId>org.apache.maven.plugins</groupId> |                 <groupId>org.apache.maven.plugins</groupId> | ||||||
| @@ -48,6 +46,7 @@ | |||||||
|                             <Main-Class>net.md_5.bungee.Bootstrap</Main-Class>  |                             <Main-Class>net.md_5.bungee.Bootstrap</Main-Class>  | ||||||
|                             <Implementation-Version>${describe}</Implementation-Version> |                             <Implementation-Version>${describe}</Implementation-Version> | ||||||
|                             <Specification-Version>${maven.build.timestamp}</Specification-Version> |                             <Specification-Version>${maven.build.timestamp}</Specification-Version> | ||||||
|  |                             <Enable-Native-Access>ALL-UNNAMED</Enable-Native-Access> | ||||||
|                         </manifestEntries> |                         </manifestEntries> | ||||||
|                     </archive> |                     </archive> | ||||||
|                 </configuration> |                 </configuration> | ||||||
|   | |||||||
| @@ -4,15 +4,14 @@ | |||||||
|     <modelVersion>4.0.0</modelVersion> |     <modelVersion>4.0.0</modelVersion> | ||||||
|  |  | ||||||
|     <parent> |     <parent> | ||||||
|         <groupId>net.md-5</groupId> |         <groupId>fr.pandacube.bungeecord</groupId> | ||||||
|         <artifactId>bungeecord-parent</artifactId> |         <artifactId>bungeecord-parent</artifactId> | ||||||
|         <version>1.20-R0.3-SNAPSHOT</version> |         <version>1.21-R0.5-SNAPSHOT</version> | ||||||
|         <relativePath>../pom.xml</relativePath> |         <relativePath>../pom.xml</relativePath> | ||||||
|     </parent> |     </parent> | ||||||
|  |  | ||||||
|     <groupId>net.md-5</groupId> |  | ||||||
|     <artifactId>bungeecord-chat</artifactId> |     <artifactId>bungeecord-chat</artifactId> | ||||||
|     <version>1.20-R0.3-SNAPSHOT</version> |     <version>1.21-R0.5-SNAPSHOT</version> | ||||||
|     <packaging>jar</packaging> |     <packaging>jar</packaging> | ||||||
|  |  | ||||||
|     <name>BungeeCord-Chat</name> |     <name>BungeeCord-Chat</name> | ||||||
| @@ -22,7 +21,7 @@ | |||||||
|         <dependency> |         <dependency> | ||||||
|             <groupId>com.google.code.gson</groupId> |             <groupId>com.google.code.gson</groupId> | ||||||
|             <artifactId>gson</artifactId> |             <artifactId>gson</artifactId> | ||||||
|             <version>2.10.1</version> |             <version>2.11.0</version> | ||||||
|             <scope>compile</scope> |             <scope>compile</scope> | ||||||
|         </dependency> |         </dependency> | ||||||
|     </dependencies> |     </dependencies> | ||||||
|   | |||||||
| @@ -1,8 +1,10 @@ | |||||||
| package net.md_5.bungee.api.chat; | package net.md_5.bungee.api.chat; | ||||||
|  |  | ||||||
|  | import java.awt.Color; | ||||||
| import java.util.ArrayList; | import java.util.ArrayList; | ||||||
| import java.util.List; | import java.util.List; | ||||||
| import lombok.AccessLevel; | import lombok.AccessLevel; | ||||||
|  | import lombok.Data; | ||||||
| import lombok.EqualsAndHashCode; | import lombok.EqualsAndHashCode; | ||||||
| import lombok.Getter; | import lombok.Getter; | ||||||
| import lombok.Setter; | import lombok.Setter; | ||||||
| @@ -129,6 +131,10 @@ public abstract class BaseComponent | |||||||
|             { |             { | ||||||
|                 setColor( component.getColorRaw() ); |                 setColor( component.getColorRaw() ); | ||||||
|             } |             } | ||||||
|  |             if ( replace || !style.hasShadowColor() ) | ||||||
|  |             { | ||||||
|  |                 setShadowColor( component.getShadowColorRaw() ); | ||||||
|  |             } | ||||||
|             if ( replace || !style.hasFont() ) |             if ( replace || !style.hasFont() ) | ||||||
|             { |             { | ||||||
|                 setFont( component.getFontRaw() ); |                 setFont( component.getFontRaw() ); | ||||||
| @@ -175,6 +181,7 @@ public abstract class BaseComponent | |||||||
|         if ( retention == FormatRetention.EVENTS || retention == FormatRetention.NONE ) |         if ( retention == FormatRetention.EVENTS || retention == FormatRetention.NONE ) | ||||||
|         { |         { | ||||||
|             setColor( null ); |             setColor( null ); | ||||||
|  |             setShadowColor( null ); | ||||||
|             setBold( null ); |             setBold( null ); | ||||||
|             setItalic( null ); |             setItalic( null ); | ||||||
|             setUnderlined( null ); |             setUnderlined( null ); | ||||||
| @@ -295,6 +302,47 @@ public abstract class BaseComponent | |||||||
|         return style.getColor(); |         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. |      * Set this component's font. | ||||||
|      * |      * | ||||||
| @@ -536,6 +584,10 @@ public abstract class BaseComponent | |||||||
|         { |         { | ||||||
|             setColor( style.getColor() ); |             setColor( style.getColor() ); | ||||||
|         } |         } | ||||||
|  |         if ( style.hasShadowColor() ) | ||||||
|  |         { | ||||||
|  |             setShadowColor( style.getShadowColor() ); | ||||||
|  |         } | ||||||
|         if ( style.hasFont() ) |         if ( style.hasFont() ) | ||||||
|         { |         { | ||||||
|             setFont( style.getFont() ); |             setFont( style.getFont() ); | ||||||
| @@ -627,11 +679,11 @@ public abstract class BaseComponent | |||||||
|     public String toPlainText() |     public String toPlainText() | ||||||
|     { |     { | ||||||
|         StringBuilder builder = new StringBuilder(); |         StringBuilder builder = new StringBuilder(); | ||||||
|         toPlainText( builder ); |         toPlainText( new LimitedStringVisitor( builder, Short.MAX_VALUE ) ); | ||||||
|         return builder.toString(); |         return builder.toString(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     void toPlainText(StringBuilder builder) |     void toPlainText(StringVisitor builder) | ||||||
|     { |     { | ||||||
|         if ( extra != null ) |         if ( extra != null ) | ||||||
|         { |         { | ||||||
| @@ -651,11 +703,11 @@ public abstract class BaseComponent | |||||||
|     public String toLegacyText() |     public String toLegacyText() | ||||||
|     { |     { | ||||||
|         StringBuilder builder = new StringBuilder(); |         StringBuilder builder = new StringBuilder(); | ||||||
|         toLegacyText( builder ); |         toLegacyText( new LimitedStringVisitor( builder, Short.MAX_VALUE ) ); | ||||||
|         return builder.toString(); |         return builder.toString(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     void toLegacyText(StringBuilder builder) |     void toLegacyText(StringVisitor builder) | ||||||
|     { |     { | ||||||
|         if ( extra != null ) |         if ( extra != null ) | ||||||
|         { |         { | ||||||
| @@ -666,7 +718,7 @@ public abstract class BaseComponent | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     void addFormat(StringBuilder builder) |     void addFormat(StringVisitor builder) | ||||||
|     { |     { | ||||||
|         builder.append( getColor() ); |         builder.append( getColor() ); | ||||||
|         if ( isBold() ) |         if ( isBold() ) | ||||||
| @@ -690,4 +742,35 @@ public abstract class BaseComponent | |||||||
|             builder.append( ChatColor.MAGIC ); |             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.Getter; | ||||||
| import lombok.RequiredArgsConstructor; | import lombok.RequiredArgsConstructor; | ||||||
| import lombok.ToString; | import lombok.ToString; | ||||||
|  | import org.jetbrains.annotations.ApiStatus; | ||||||
|  |  | ||||||
| @Getter | @Getter | ||||||
| @ToString | @ToString | ||||||
| @EqualsAndHashCode | @EqualsAndHashCode | ||||||
| @RequiredArgsConstructor | @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. |          * {@link net.md_5.bungee.api.chat.ClickEvent#value} in a book. | ||||||
|          */ |          */ | ||||||
|         CHANGE_PAGE, |         CHANGE_PAGE, | ||||||
|  |         /** | ||||||
|  |          * Must use subclass ShowDialogClickEvent. | ||||||
|  |          */ | ||||||
|  |         SHOW_DIALOG, | ||||||
|         /** |         /** | ||||||
|          * Copy the string given by |          * Copy the string given by | ||||||
|          * {@link net.md_5.bungee.api.chat.ClickEvent#value} into the player's |          * {@link net.md_5.bungee.api.chat.ClickEvent#value} into the player's | ||||||
|          * clipboard. |          * 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; | package net.md_5.bungee.api.chat; | ||||||
|  |  | ||||||
| import com.google.common.base.Preconditions; | import com.google.common.base.Preconditions; | ||||||
|  | import java.awt.Color; | ||||||
| import java.util.ArrayList; | import java.util.ArrayList; | ||||||
| import java.util.List; | import java.util.List; | ||||||
| import lombok.Getter; | import lombok.Getter; | ||||||
| @@ -351,6 +352,19 @@ public final class ComponentBuilder | |||||||
|         return this; |         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. |      * Sets the font of the current part. | ||||||
|      * |      * | ||||||
|   | |||||||
| @@ -1,5 +1,6 @@ | |||||||
| package net.md_5.bungee.api.chat; | package net.md_5.bungee.api.chat; | ||||||
|  |  | ||||||
|  | import java.awt.Color; | ||||||
| import lombok.AllArgsConstructor; | import lombok.AllArgsConstructor; | ||||||
| import lombok.EqualsAndHashCode; | import lombok.EqualsAndHashCode; | ||||||
| import lombok.NoArgsConstructor; | import lombok.NoArgsConstructor; | ||||||
| @@ -23,6 +24,10 @@ public final class ComponentStyle implements Cloneable | |||||||
|      * {@link ChatColor#color} should not be null).</b> |      * {@link ChatColor#color} should not be null).</b> | ||||||
|      */ |      */ | ||||||
|     private ChatColor color; |     private ChatColor color; | ||||||
|  |     /** | ||||||
|  |      * The shadow color of this style. | ||||||
|  |      */ | ||||||
|  |     private Color shadowColor; | ||||||
|     /** |     /** | ||||||
|      * The font of this style. |      * The font of this style. | ||||||
|      */ |      */ | ||||||
| @@ -68,6 +73,26 @@ public final class ComponentStyle implements Cloneable | |||||||
|         return ( color != null ); |         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. |      * Returns the font of this style. May return null. | ||||||
|      * |      * | ||||||
| @@ -195,7 +220,7 @@ public final class ComponentStyle implements Cloneable | |||||||
|      */ |      */ | ||||||
|     public boolean isEmpty() |     public boolean isEmpty() | ||||||
|     { |     { | ||||||
|         return color == null && font == null && bold == null |         return color == null && shadowColor == null && font == null && bold == null | ||||||
|                 && italic == null && underlined == null |                 && italic == null && underlined == null | ||||||
|                 && strikethrough == null && obfuscated == null; |                 && strikethrough == null && obfuscated == null; | ||||||
|     } |     } | ||||||
| @@ -203,7 +228,7 @@ public final class ComponentStyle implements Cloneable | |||||||
|     @Override |     @Override | ||||||
|     public ComponentStyle clone() |     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() |         return new ComponentStyleBuilder() | ||||||
|                 .color( other.color ) |                 .color( other.color ) | ||||||
|  |                 .shadowColor( other.shadowColor ) | ||||||
|                 .font( other.font ) |                 .font( other.font ) | ||||||
|                 .bold( other.bold ) |                 .bold( other.bold ) | ||||||
|                 .italic( other.italic ) |                 .italic( other.italic ) | ||||||
|   | |||||||
| @@ -1,5 +1,6 @@ | |||||||
| package net.md_5.bungee.api.chat; | package net.md_5.bungee.api.chat; | ||||||
|  |  | ||||||
|  | import java.awt.Color; | ||||||
| import net.md_5.bungee.api.ChatColor; | import net.md_5.bungee.api.ChatColor; | ||||||
|  |  | ||||||
| /** | /** | ||||||
| @@ -26,6 +27,7 @@ public final class ComponentStyleBuilder | |||||||
| { | { | ||||||
|  |  | ||||||
|     private ChatColor color; |     private ChatColor color; | ||||||
|  |     private Color shadowColor; | ||||||
|     private String font; |     private String font; | ||||||
|     private Boolean bold, italic, underlined, strikethrough, obfuscated; |     private Boolean bold, italic, underlined, strikethrough, obfuscated; | ||||||
|  |  | ||||||
| @@ -41,6 +43,18 @@ public final class ComponentStyleBuilder | |||||||
|         return this; |         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. |      * Set the style font. | ||||||
|      * |      * | ||||||
| @@ -121,6 +135,6 @@ public final class ComponentStyleBuilder | |||||||
|      */ |      */ | ||||||
|     public ComponentStyle build() |     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.Entity; | ||||||
| import net.md_5.bungee.api.chat.hover.content.Item; | 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.api.chat.hover.content.Text; | ||||||
| import net.md_5.bungee.chat.ComponentSerializer; | import org.jetbrains.annotations.ApiStatus; | ||||||
|  |  | ||||||
| @Getter | @Getter | ||||||
| @ToString | @ToString | ||||||
| @@ -34,6 +34,7 @@ public final class HoverEvent | |||||||
|      * Returns whether this hover event is prior to 1.16 |      * Returns whether this hover event is prior to 1.16 | ||||||
|      */ |      */ | ||||||
|     @Setter |     @Setter | ||||||
|  |     @ApiStatus.Internal | ||||||
|     private boolean legacy = false; |     private boolean legacy = false; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
| @@ -71,22 +72,6 @@ public final class HoverEvent | |||||||
|         this.legacy = true; |         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. |      * Adds a content to this hover event. | ||||||
|      * |      * | ||||||
|   | |||||||
| @@ -50,14 +50,14 @@ public final class KeybindComponent extends BaseComponent | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     protected void toPlainText(StringBuilder builder) |     protected void toPlainText(StringVisitor builder) | ||||||
|     { |     { | ||||||
|         builder.append( getKeybind() ); |         builder.append( getKeybind() ); | ||||||
|         super.toPlainText( builder ); |         super.toPlainText( builder ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     protected void toLegacyText(StringBuilder builder) |     protected void toLegacyText(StringVisitor builder) | ||||||
|     { |     { | ||||||
|         addFormat( builder ); |         addFormat( builder ); | ||||||
|         builder.append( getKeybind() ); |         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 |     @Override | ||||||
|     protected void toPlainText(StringBuilder builder) |     protected void toPlainText(StringVisitor builder) | ||||||
|     { |     { | ||||||
|         builder.append( this.value ); |         builder.append( this.value ); | ||||||
|         super.toPlainText( builder ); |         super.toPlainText( builder ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     protected void toLegacyText(StringBuilder builder) |     protected void toLegacyText(StringVisitor builder) | ||||||
|     { |     { | ||||||
|         addFormat( builder ); |         addFormat( builder ); | ||||||
|         builder.append( this.value ); |         builder.append( this.value ); | ||||||
|   | |||||||
| @@ -69,14 +69,14 @@ public final class SelectorComponent extends BaseComponent | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     protected void toPlainText(StringBuilder builder) |     protected void toPlainText(StringVisitor builder) | ||||||
|     { |     { | ||||||
|         builder.append( this.selector ); |         builder.append( this.selector ); | ||||||
|         super.toPlainText( builder ); |         super.toPlainText( builder ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     protected void toLegacyText(StringBuilder builder) |     protected void toLegacyText(StringVisitor builder) | ||||||
|     { |     { | ||||||
|         addFormat( builder ); |         addFormat( builder ); | ||||||
|         builder.append( this.selector ); |         builder.append( this.selector ); | ||||||
|   | |||||||
| @@ -170,7 +170,7 @@ public final class TextComponent extends BaseComponent | |||||||
|                 } |                 } | ||||||
|                 continue; |                 continue; | ||||||
|             } |             } | ||||||
|             int pos = message.indexOf( ' ', i ); |             int pos = indexOfSpecial( message, i ); | ||||||
|             if ( pos == -1 ) |             if ( pos == -1 ) | ||||||
|             { |             { | ||||||
|                 pos = message.length(); |                 pos = message.length(); | ||||||
| @@ -205,6 +205,20 @@ public final class TextComponent extends BaseComponent | |||||||
|         appender.accept( component ); |         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 |      * Internal compatibility method to transform an array of components to a | ||||||
|      * single component. |      * single component. | ||||||
| @@ -280,14 +294,14 @@ public final class TextComponent extends BaseComponent | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     protected void toPlainText(StringBuilder builder) |     protected void toPlainText(StringVisitor builder) | ||||||
|     { |     { | ||||||
|         builder.append( text ); |         builder.append( text ); | ||||||
|         super.toPlainText( builder ); |         super.toPlainText( builder ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     protected void toLegacyText(StringBuilder builder) |     protected void toLegacyText(StringVisitor builder) | ||||||
|     { |     { | ||||||
|         addFormat( builder ); |         addFormat( builder ); | ||||||
|         builder.append( text ); |         builder.append( text ); | ||||||
|   | |||||||
| @@ -156,20 +156,20 @@ public final class TranslatableComponent extends BaseComponent | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     protected void toPlainText(StringBuilder builder) |     protected void toPlainText(StringVisitor builder) | ||||||
|     { |     { | ||||||
|         convert( builder, false ); |         convert( builder, false ); | ||||||
|         super.toPlainText( builder ); |         super.toPlainText( builder ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     protected void toLegacyText(StringBuilder builder) |     protected void toLegacyText(StringVisitor builder) | ||||||
|     { |     { | ||||||
|         convert( builder, true ); |         convert( builder, true ); | ||||||
|         super.toLegacyText( builder ); |         super.toLegacyText( builder ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     private void convert(StringBuilder builder, boolean applyFormat) |     private void convert(StringVisitor builder, boolean applyFormat) | ||||||
|     { |     { | ||||||
|         String trans = TranslationRegistry.INSTANCE.translate( translate ); |         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> |     <modelVersion>4.0.0</modelVersion> | ||||||
|  |  | ||||||
|     <parent> |     <parent> | ||||||
|         <groupId>net.md-5</groupId> |         <groupId>fr.pandacube.bungeecord</groupId> | ||||||
|         <artifactId>bungeecord-parent</artifactId> |         <artifactId>bungeecord-parent</artifactId> | ||||||
|         <version>1.20-R0.3-SNAPSHOT</version> |         <version>1.21-R0.5-SNAPSHOT</version> | ||||||
|         <relativePath>../pom.xml</relativePath> |         <relativePath>../pom.xml</relativePath> | ||||||
|     </parent> |     </parent> | ||||||
|  |  | ||||||
|     <groupId>net.md-5</groupId> |  | ||||||
|     <artifactId>bungeecord-config</artifactId> |     <artifactId>bungeecord-config</artifactId> | ||||||
|     <version>1.20-R0.3-SNAPSHOT</version> |     <version>1.21-R0.5-SNAPSHOT</version> | ||||||
|     <packaging>jar</packaging> |     <packaging>jar</packaging> | ||||||
|  |  | ||||||
|     <name>BungeeCord-Config</name> |     <name>BungeeCord-Config</name> | ||||||
| @@ -22,7 +21,7 @@ | |||||||
|         <dependency> |         <dependency> | ||||||
|             <groupId>com.google.code.gson</groupId> |             <groupId>com.google.code.gson</groupId> | ||||||
|             <artifactId>gson</artifactId> |             <artifactId>gson</artifactId> | ||||||
|             <version>2.10.1</version> |             <version>2.11.0</version> | ||||||
|             <scope>compile</scope> |             <scope>compile</scope> | ||||||
|             <optional>true</optional> |             <optional>true</optional> | ||||||
|         </dependency> |         </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> |     <modelVersion>4.0.0</modelVersion> | ||||||
|  |  | ||||||
|     <parent> |     <parent> | ||||||
|         <groupId>net.md-5</groupId> |         <groupId>fr.pandacube.bungeecord</groupId> | ||||||
|         <artifactId>bungeecord-parent</artifactId> |         <artifactId>bungeecord-parent</artifactId> | ||||||
|         <version>1.20-R0.3-SNAPSHOT</version> |         <version>1.21-R0.5-SNAPSHOT</version> | ||||||
|         <relativePath>../pom.xml</relativePath> |         <relativePath>../pom.xml</relativePath> | ||||||
|     </parent> |     </parent> | ||||||
|  |  | ||||||
|     <groupId>net.md-5</groupId> |  | ||||||
|     <artifactId>bungeecord-event</artifactId> |     <artifactId>bungeecord-event</artifactId> | ||||||
|     <version>1.20-R0.3-SNAPSHOT</version> |     <version>1.21-R0.5-SNAPSHOT</version> | ||||||
|     <packaging>jar</packaging> |     <packaging>jar</packaging> | ||||||
|  |  | ||||||
|     <name>BungeeCord-Event</name> |     <name>BungeeCord-Event</name> | ||||||
|   | |||||||
							
								
								
									
										13
									
								
								log/pom.xml
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								log/pom.xml
									
									
									
									
									
								
							| @@ -4,15 +4,14 @@ | |||||||
|     <modelVersion>4.0.0</modelVersion> |     <modelVersion>4.0.0</modelVersion> | ||||||
|  |  | ||||||
|     <parent> |     <parent> | ||||||
|         <groupId>net.md-5</groupId> |         <groupId>fr.pandacube.bungeecord</groupId> | ||||||
|         <artifactId>bungeecord-parent</artifactId> |         <artifactId>bungeecord-parent</artifactId> | ||||||
|         <version>1.20-R0.3-SNAPSHOT</version> |         <version>1.21-R0.5-SNAPSHOT</version> | ||||||
|         <relativePath>../pom.xml</relativePath> |         <relativePath>../pom.xml</relativePath> | ||||||
|     </parent> |     </parent> | ||||||
|  |  | ||||||
|     <groupId>net.md-5</groupId> |  | ||||||
|     <artifactId>bungeecord-log</artifactId> |     <artifactId>bungeecord-log</artifactId> | ||||||
|     <version>1.20-R0.3-SNAPSHOT</version> |     <version>1.21-R0.5-SNAPSHOT</version> | ||||||
|     <packaging>jar</packaging> |     <packaging>jar</packaging> | ||||||
|  |  | ||||||
|     <name>BungeeCord-Log</name> |     <name>BungeeCord-Log</name> | ||||||
| @@ -20,13 +19,13 @@ | |||||||
|  |  | ||||||
|     <dependencies> |     <dependencies> | ||||||
|         <dependency> |         <dependency> | ||||||
|             <groupId>jline</groupId> |             <groupId>org.jline</groupId> | ||||||
|             <artifactId>jline</artifactId> |             <artifactId>jline</artifactId> | ||||||
|             <version>2.12.1</version> |             <version>3.30.4</version> | ||||||
|             <scope>compile</scope> |             <scope>compile</scope> | ||||||
|         </dependency> |         </dependency> | ||||||
|         <dependency> |         <dependency> | ||||||
|             <groupId>net.md-5</groupId> |             <groupId>fr.pandacube.bungeecord</groupId> | ||||||
|             <artifactId>bungeecord-chat</artifactId> |             <artifactId>bungeecord-chat</artifactId> | ||||||
|             <version>${project.version}</version> |             <version>${project.version}</version> | ||||||
|             <scope>compile</scope> |             <scope>compile</scope> | ||||||
|   | |||||||
| @@ -1,26 +1,18 @@ | |||||||
| package net.md_5.bungee.log; | package net.md_5.bungee.log; | ||||||
|  |  | ||||||
| import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; |  | ||||||
| import java.io.IOException; | import java.io.IOException; | ||||||
| import java.util.logging.FileHandler; | import java.util.logging.FileHandler; | ||||||
| import java.util.logging.Level; | import java.util.logging.Level; | ||||||
| import java.util.logging.LogRecord; | import java.util.logging.LogRecord; | ||||||
| import java.util.logging.Logger; | import java.util.logging.Logger; | ||||||
| import jline.console.ConsoleReader; | import org.jline.reader.LineReader; | ||||||
|  |  | ||||||
| public class BungeeLogger extends Logger | public class BungeeLogger extends Logger | ||||||
| { | { | ||||||
|  |  | ||||||
|     private final LogDispatcher dispatcher = new LogDispatcher( this ); |     private final LogDispatcher dispatcher = new LogDispatcher( this ); | ||||||
|  |  | ||||||
|     // CHECKSTYLE:OFF |     public BungeeLogger(String loggerName, String filePattern, LineReader reader) | ||||||
|     @SuppressWarnings( |  | ||||||
|             { |  | ||||||
|                 "CallToPrintStackTrace", "CallToThreadStartDuringObjectConstruction" |  | ||||||
|             }) |  | ||||||
|     // CHECKSTYLE:ON |  | ||||||
|     @SuppressFBWarnings("SC_START_IN_CTOR") |  | ||||||
|     public BungeeLogger(String loggerName, String filePattern, ConsoleReader reader) |  | ||||||
|     { |     { | ||||||
|         super( loggerName, null ); |         super( loggerName, null ); | ||||||
|         setLevel( Level.ALL ); |         setLevel( Level.ALL ); | ||||||
|   | |||||||
| @@ -1,15 +1,15 @@ | |||||||
| package net.md_5.bungee.log; | package net.md_5.bungee.log; | ||||||
|  |  | ||||||
| import java.io.IOException; |  | ||||||
| import java.util.logging.Handler; | import java.util.logging.Handler; | ||||||
| import java.util.logging.LogRecord; | import java.util.logging.LogRecord; | ||||||
| import java.util.regex.Pattern; | import java.util.regex.Pattern; | ||||||
| import jline.console.ConsoleReader; |  | ||||||
| import lombok.Data; | import lombok.Data; | ||||||
|  | import lombok.RequiredArgsConstructor; | ||||||
| import net.md_5.bungee.api.ChatColor; | import net.md_5.bungee.api.ChatColor; | ||||||
| import org.fusesource.jansi.Ansi; | import org.jline.jansi.Ansi; | ||||||
| import org.fusesource.jansi.Ansi.Erase; | import org.jline.reader.LineReader; | ||||||
|  |  | ||||||
|  | @RequiredArgsConstructor | ||||||
| public class ColouredWriter extends Handler | public class ColouredWriter extends Handler | ||||||
| { | { | ||||||
|  |  | ||||||
| @@ -52,12 +52,7 @@ public class ColouredWriter extends Handler | |||||||
|         compile( ChatColor.RESET, Ansi.ansi().a( Ansi.Attribute.RESET ).toString() ), |         compile( ChatColor.RESET, Ansi.ansi().a( Ansi.Attribute.RESET ).toString() ), | ||||||
|     }; |     }; | ||||||
|     // |     // | ||||||
|     private final ConsoleReader console; |     private final LineReader console; | ||||||
|  |  | ||||||
|     public ColouredWriter(ConsoleReader console) |  | ||||||
|     { |  | ||||||
|         this.console = console; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public void print(String s) |     public void print(String s) | ||||||
|     { |     { | ||||||
| @@ -65,14 +60,7 @@ public class ColouredWriter extends Handler | |||||||
|         { |         { | ||||||
|             s = replacement.pattern.matcher( s ).replaceAll( replacement.replacement ); |             s = replacement.pattern.matcher( s ).replaceAll( replacement.replacement ); | ||||||
|         } |         } | ||||||
|         try |         console.printAbove( s + Ansi.ansi().reset().toString() ); | ||||||
|         { |  | ||||||
|             console.print( Ansi.ansi().eraseLine( Erase.ALL ).toString() + ConsoleReader.RESET_LINE + s + Ansi.ansi().reset().toString() ); |  | ||||||
|             console.drawLine(); |  | ||||||
|             console.flush(); |  | ||||||
|         } catch ( IOException ex ) |  | ||||||
|         { |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|   | |||||||
| @@ -18,7 +18,6 @@ public class ConciseFormatter extends Formatter | |||||||
|     private final boolean coloured; |     private final boolean coloured; | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     @SuppressWarnings("ThrowableResultIgnored") |  | ||||||
|     public String format(LogRecord record) |     public String format(LogRecord record) | ||||||
|     { |     { | ||||||
|         StringBuilder formatted = new StringBuilder(); |         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