Compare commits
270 Commits
5a1e342e0d
...
for-pandac
Author | SHA1 | Date | |
---|---|---|---|
3aab2fa1e1 | |||
8be54e72ed | |||
3e1e95ff49 | |||
b5794d87d9 | |||
dc8d29a05b | |||
43dab76bd5 | |||
![]() |
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 | ||
![]() |
df413f62db | ||
![]() |
8a88ce464e | ||
![]() |
006a14a75c | ||
![]() |
07df657f3c | ||
![]() |
b8b373a53e | ||
![]() |
e7e0b97cff | ||
![]() |
52ab21b1ff | ||
![]() |
8e8a635361 | ||
![]() |
18eae8a1a6 | ||
![]() |
6e1751733f | ||
![]() |
6335af840b | ||
![]() |
336333acb1 | ||
![]() |
d110f6629b | ||
![]() |
6f70b15e2e | ||
![]() |
b30499e2b6 | ||
![]() |
5079181c28 | ||
![]() |
ee02d98cb2 | ||
![]() |
c7ff3b8a14 | ||
![]() |
de60af0d7b | ||
![]() |
a9218a7aa7 | ||
![]() |
67c65e0464 | ||
![]() |
1be25b6c74 | ||
![]() |
8525b44961 | ||
![]() |
1fca510a08 | ||
![]() |
3384185285 | ||
![]() |
3075d2c19d | ||
![]() |
bc528d5d98 | ||
![]() |
25cf8d682b | ||
![]() |
17e23d5c3f | ||
![]() |
d6c5197cb9 | ||
![]() |
dd96f0f878 | ||
![]() |
8a9501ffe4 | ||
![]() |
5e25c63c5a | ||
![]() |
bd963501ec | ||
![]() |
da795a7094 | ||
![]() |
84d0ea73fa | ||
![]() |
0851e39197 | ||
![]() |
86e6fdf8a2 | ||
![]() |
6ab0f5eba7 | ||
![]() |
f224787222 | ||
![]() |
82684c7b6b | ||
![]() |
c2f73d32b8 | ||
![]() |
e642b9dde1 | ||
![]() |
db623d10c5 | ||
![]() |
61bb9f5b93 | ||
![]() |
9551b45328 | ||
![]() |
dc680b87eb | ||
![]() |
156eda78c6 | ||
![]() |
31be68af51 | ||
![]() |
ffa011c7b1 | ||
![]() |
22536c11bd | ||
![]() |
2394e204fa | ||
![]() |
1b88a84710 | ||
![]() |
7606d4437b | ||
![]() |
3e9a7e45c4 | ||
![]() |
f6c5332c1a | ||
![]() |
d0fa62d424 | ||
![]() |
464ed0184c | ||
![]() |
eda268b481 | ||
![]() |
3e1007527c | ||
![]() |
b52b14696c | ||
![]() |
94d5b0d03c | ||
![]() |
c3f228f626 | ||
![]() |
02c5c1ee76 | ||
![]() |
c69acf728c | ||
![]() |
a1cd694363 | ||
![]() |
3e2bc8e2d7 | ||
![]() |
ad7163d2d6 | ||
![]() |
19918c694f | ||
![]() |
21c8f2815a | ||
![]() |
737d545fb6 | ||
![]() |
b23a51825e | ||
![]() |
708c5b6254 | ||
![]() |
f5af11193c | ||
![]() |
b711e4033f | ||
![]() |
3deaaadc3a | ||
![]() |
51b9a6b0b8 | ||
![]() |
1a807731a5 | ||
![]() |
772ad9951f | ||
![]() |
2431c40a5c | ||
![]() |
8144ae8d7b | ||
![]() |
0757c39a6f | ||
![]() |
231024ba42 | ||
![]() |
8ce7a7f8b6 | ||
![]() |
e1462ccdd1 | ||
![]() |
70f346c1dc | ||
![]() |
197bf13a28 | ||
![]() |
0925c06f9b | ||
![]() |
16298a75f2 | ||
![]() |
39b10c0b16 | ||
![]() |
bd8d114992 | ||
![]() |
30e12c6fe0 | ||
![]() |
bd009ca52d | ||
![]() |
65d8edf62d | ||
![]() |
f5157f12a4 | ||
![]() |
df20effacc | ||
![]() |
c92581d0dc | ||
![]() |
e442c3da5c | ||
![]() |
f903c54d55 | ||
![]() |
0d45378986 | ||
![]() |
0f5f09b6c5 | ||
![]() |
e5c80d0044 | ||
![]() |
9cdb2ba3ea | ||
![]() |
d0e5cf7ce5 | ||
![]() |
c8568764f6 | ||
![]() |
a7dbbc2f0a | ||
![]() |
68b2df2b1e | ||
![]() |
1ef4d27dbe | ||
![]() |
94a1fb5117 | ||
![]() |
78aef86a8f | ||
![]() |
b34cfcde5a | ||
![]() |
86e079a4b1 | ||
![]() |
1c42c34081 | ||
![]() |
fed646d18b | ||
![]() |
653f1691d7 | ||
![]() |
3cb7a12738 | ||
![]() |
f3397b3003 | ||
![]() |
497c6879e0 | ||
![]() |
7b27dfaf5e | ||
![]() |
f9b75c4a3a | ||
![]() |
0509303fd3 | ||
![]() |
f486a251f3 |
3
.github/dependabot.yml
vendored
3
.github/dependabot.yml
vendored
@@ -13,10 +13,9 @@ updates:
|
||||
- dependency-name: "com.puppycrawl.tools:checkstyle"
|
||||
# Newer versions have issues, see #1909 and #2050
|
||||
- dependency-name: "jline:jline"
|
||||
# Later versions of these Maven dependencies are incompatible and require careful management - see SPIGOT-7400
|
||||
# Needs to be synchronised with maven-resolver-provider dependencies
|
||||
- dependency-name: "org.apache.maven.resolver:maven-resolver-connector-basic"
|
||||
- dependency-name: "org.apache.maven.resolver:maven-resolver-transport-http"
|
||||
- dependency-name: "org.apache.maven:maven-resolver-provider"
|
||||
# Used with maven-resolver dependencies; 2.0 update breaks other providers
|
||||
- dependency-name: "org.slf4j:slf4j-api"
|
||||
update-types: ["version-update:semver-major"]
|
||||
|
6
.github/workflows/maven.yml
vendored
6
.github/workflows/maven.yml
vendored
@@ -4,18 +4,18 @@ on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
java: [8, 11, 17, 21]
|
||||
java: [8, 11, 17, 21, 25-ea]
|
||||
|
||||
name: Java ${{ matrix.java }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-java@v3
|
||||
- uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: zulu
|
||||
java-version: ${{ matrix.java }}
|
||||
|
@@ -23,4 +23,4 @@ Binaries
|
||||
--------
|
||||
Precompiled binaries are available for end users on [Jenkins](https://www.spigotmc.org/go/bungeecord-dl).
|
||||
|
||||
(c) 2012-2023 SpigotMC Pty. Ltd.
|
||||
(c) 2012-2025 SpigotMC Pty. Ltd.
|
||||
|
27
api/pom.xml
27
api/pom.xml
@@ -4,15 +4,14 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>net.md-5</groupId>
|
||||
<groupId>fr.pandacube.bungeecord</groupId>
|
||||
<artifactId>bungeecord-parent</artifactId>
|
||||
<version>1.20-R0.2-SNAPSHOT</version>
|
||||
<version>1.21-R0.4-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-api</artifactId>
|
||||
<version>1.20-R0.2-SNAPSHOT</version>
|
||||
<version>1.21-R0.4-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>BungeeCord-API</name>
|
||||
@@ -20,25 +19,31 @@
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>net.md-5</groupId>
|
||||
<groupId>fr.pandacube.bungeecord</groupId>
|
||||
<artifactId>bungeecord-chat</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.md-5</groupId>
|
||||
<groupId>fr.pandacube.bungeecord</groupId>
|
||||
<artifactId>bungeecord-config</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.md-5</groupId>
|
||||
<groupId>fr.pandacube.bungeecord</groupId>
|
||||
<artifactId>bungeecord-dialog</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>fr.pandacube.bungeecord</groupId>
|
||||
<artifactId>bungeecord-event</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.md-5</groupId>
|
||||
<groupId>fr.pandacube.bungeecord</groupId>
|
||||
<artifactId>bungeecord-protocol</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
@@ -51,21 +56,21 @@
|
||||
<dependency>
|
||||
<groupId>org.apache.maven</groupId>
|
||||
<artifactId>maven-resolver-provider</artifactId>
|
||||
<version>3.8.5</version>
|
||||
<version>3.9.6</version>
|
||||
<!-- not part of the API proper -->
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven.resolver</groupId>
|
||||
<artifactId>maven-resolver-connector-basic</artifactId>
|
||||
<version>1.7.3</version>
|
||||
<version>1.9.18</version>
|
||||
<!-- not part of the API proper -->
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven.resolver</groupId>
|
||||
<artifactId>maven-resolver-transport-http</artifactId>
|
||||
<version>1.7.3</version>
|
||||
<version>1.9.18</version>
|
||||
<!-- not part of the API proper -->
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
@@ -16,6 +16,7 @@ import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.plugin.Plugin;
|
||||
import net.md_5.bungee.api.plugin.PluginManager;
|
||||
import net.md_5.bungee.api.scheduler.TaskScheduler;
|
||||
import net.md_5.bungee.protocol.channel.BungeeChannelInitializer;
|
||||
|
||||
public abstract class ProxyServer
|
||||
{
|
||||
@@ -311,4 +312,56 @@ public abstract class ProxyServer
|
||||
*/
|
||||
public abstract Title createTitle();
|
||||
|
||||
/**
|
||||
* Get the unsafe methods of this class.
|
||||
*
|
||||
* @return the unsafe method interface
|
||||
*/
|
||||
public abstract Unsafe unsafe();
|
||||
|
||||
public interface Unsafe
|
||||
{
|
||||
|
||||
/**
|
||||
* Gets the frontend channel initializer
|
||||
*
|
||||
* @return the frontend channel initializer
|
||||
*/
|
||||
BungeeChannelInitializer getFrontendChannelInitializer();
|
||||
|
||||
/**
|
||||
* Set the frontend channel initializer of this proxy
|
||||
*
|
||||
* @param channelInitializer the frontend channelInitializer to set
|
||||
*/
|
||||
void setFrontendChannelInitializer(BungeeChannelInitializer channelInitializer);
|
||||
|
||||
/**
|
||||
* Gets the backend channel initializer
|
||||
*
|
||||
* @return the backend channel initializer
|
||||
*/
|
||||
BungeeChannelInitializer getBackendChannelInitializer();
|
||||
|
||||
/**
|
||||
* Set the backend channel initializer of this proxy
|
||||
*
|
||||
* @param channelInitializer the backend channelInitializer to set
|
||||
*/
|
||||
void setBackendChannelInitializer(BungeeChannelInitializer channelInitializer);
|
||||
|
||||
/**
|
||||
* Gets the server info channel initializer
|
||||
*
|
||||
* @return the server info channel initializer
|
||||
*/
|
||||
BungeeChannelInitializer getServerInfoChannelInitializer();
|
||||
|
||||
/**
|
||||
* Set the server info channel initializer of this proxy
|
||||
*
|
||||
* @param channelInitializer the server info channelInitializer to set
|
||||
*/
|
||||
void setServerInfoChannelInitializer(BungeeChannelInitializer channelInitializer);
|
||||
}
|
||||
}
|
||||
|
@@ -105,13 +105,13 @@ public class ServerPing
|
||||
@Deprecated
|
||||
public ServerPing(Protocol version, Players players, String description, String favicon)
|
||||
{
|
||||
this( version, players, new TextComponent( TextComponent.fromLegacyText( description ) ), favicon == null ? null : Favicon.create( favicon ) );
|
||||
this( version, players, TextComponent.fromLegacy( description ), favicon == null ? null : Favicon.create( favicon ) );
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public ServerPing(Protocol version, Players players, String description, Favicon favicon)
|
||||
{
|
||||
this( version, players, new TextComponent( TextComponent.fromLegacyText( description ) ), favicon );
|
||||
this( version, players, TextComponent.fromLegacy( description ), favicon );
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@@ -139,7 +139,7 @@ public class ServerPing
|
||||
@Deprecated
|
||||
public void setDescription(String description)
|
||||
{
|
||||
this.description = new TextComponent( TextComponent.fromLegacyText( description ) );
|
||||
this.description = TextComponent.fromLegacy( description );
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
|
@@ -84,5 +84,15 @@ public interface Connection
|
||||
* @param packet the packet to send
|
||||
*/
|
||||
void sendPacket(DefinedPacket packet);
|
||||
|
||||
/**
|
||||
* Queue a packet to this connection.
|
||||
* If the packet is not registered for the connections current encoder protocol, it will be queued until it is,
|
||||
* otherwise it will be sent immediately.
|
||||
*
|
||||
* @param packet the packet to be queued
|
||||
* @throws UnsupportedOperationException if used for a PendingConnection
|
||||
*/
|
||||
void sendPacketQueued(DefinedPacket packet);
|
||||
}
|
||||
}
|
||||
|
@@ -2,7 +2,9 @@ package net.md_5.bungee.api.connection;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import net.md_5.bungee.api.config.ListenerInfo;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
/**
|
||||
* Represents a user attempting to log into the proxy.
|
||||
@@ -89,4 +91,40 @@ public interface PendingConnection extends Connection
|
||||
* @return Whether the client is using a legacy client.
|
||||
*/
|
||||
boolean isLegacy();
|
||||
|
||||
/**
|
||||
* Gets if this connection has been transferred from another server.
|
||||
*
|
||||
* @return true if the connection has been transferred
|
||||
*/
|
||||
@ApiStatus.Experimental
|
||||
boolean isTransferred();
|
||||
|
||||
/**
|
||||
* Retrieves a cookie from this pending connection.
|
||||
*
|
||||
* @param cookie the resource location of the cookie, for example
|
||||
* "bungeecord:my_cookie"
|
||||
* @return a {@link CompletableFuture} that will be completed when the
|
||||
* Cookie response is received. If the cookie is not set in the client, the
|
||||
* {@link CompletableFuture} will complete with a null value
|
||||
* @throws IllegalStateException if the player's version is not at least
|
||||
* 1.20.5
|
||||
*/
|
||||
@ApiStatus.Experimental
|
||||
CompletableFuture<byte[]> retrieveCookie(String cookie);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
@@ -3,6 +3,7 @@ package net.md_5.bungee.api.connection;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import net.md_5.bungee.api.Callback;
|
||||
import net.md_5.bungee.api.ChatMessageType;
|
||||
import net.md_5.bungee.api.CommandSender;
|
||||
@@ -11,8 +12,10 @@ import net.md_5.bungee.api.SkinConfiguration;
|
||||
import net.md_5.bungee.api.Title;
|
||||
import net.md_5.bungee.api.chat.BaseComponent;
|
||||
import net.md_5.bungee.api.config.ServerInfo;
|
||||
import net.md_5.bungee.api.dialog.Dialog;
|
||||
import net.md_5.bungee.api.event.ServerConnectEvent;
|
||||
import net.md_5.bungee.api.score.Scoreboard;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
/**
|
||||
* Represents a player whose connection is being connected to somewhere else,
|
||||
@@ -334,6 +337,77 @@ public interface ProxiedPlayer extends Connection, CommandSender
|
||||
* Get the {@link Scoreboard} that belongs to this player.
|
||||
*
|
||||
* @return this player's {@link Scoreboard}
|
||||
* @deprecated for internal use only, setters will not have the expected
|
||||
* effect, will not update client state, and may corrupt proxy state
|
||||
*/
|
||||
@Deprecated
|
||||
Scoreboard getScoreboard();
|
||||
|
||||
/**
|
||||
* Retrieves a cookie from this player.
|
||||
*
|
||||
* @param cookie the resource location of the cookie, for example
|
||||
* "bungeecord:my_cookie"
|
||||
* @return a {@link CompletableFuture} that will be completed when the
|
||||
* Cookie response is received. If the cookie is not set in the client, the
|
||||
* {@link CompletableFuture} will complete with a null value
|
||||
* @throws IllegalStateException if the player's version is not at least
|
||||
* 1.20.5
|
||||
*/
|
||||
@ApiStatus.Experimental
|
||||
CompletableFuture<byte[]> retrieveCookie(String cookie);
|
||||
|
||||
/**
|
||||
* Stores a cookie in this player's client.
|
||||
*
|
||||
* @param cookie the resource location of the cookie, for example
|
||||
* "bungeecord:my_cookie"
|
||||
* @param data the data to store in the cookie
|
||||
* @throws IllegalStateException if the player's version is not at least
|
||||
* 1.20.5
|
||||
*/
|
||||
@ApiStatus.Experimental
|
||||
void storeCookie(String cookie, byte[] data);
|
||||
|
||||
/**
|
||||
* Requests this player to connect to a different server specified by host
|
||||
* and port.
|
||||
*
|
||||
* This is a client-side transfer - host and port should not specify a
|
||||
* BungeeCord backend server.
|
||||
*
|
||||
* @param host the host of the server to transfer to
|
||||
* @param port the port of the server to transfer to
|
||||
* @throws IllegalStateException if the players version is not at least
|
||||
* 1.20.5
|
||||
*/
|
||||
@ApiStatus.Experimental
|
||||
void transfer(String host, int port);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
@@ -1,9 +1,7 @@
|
||||
package net.md_5.bungee.api.event;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
import net.md_5.bungee.api.Callback;
|
||||
import net.md_5.bungee.api.chat.BaseComponent;
|
||||
@@ -27,8 +25,7 @@ public class LoginEvent extends AsyncEvent<LoginEvent> implements Cancellable
|
||||
/**
|
||||
* Message to use when kicking if this event is canceled.
|
||||
*/
|
||||
@Setter(AccessLevel.NONE)
|
||||
private BaseComponent[] cancelReasonComponents;
|
||||
private BaseComponent reason;
|
||||
/**
|
||||
* Connection attempting to login.
|
||||
*/
|
||||
@@ -42,28 +39,44 @@ public class LoginEvent extends AsyncEvent<LoginEvent> implements Cancellable
|
||||
|
||||
/**
|
||||
* @return reason to be displayed
|
||||
* @deprecated Use component methods instead.
|
||||
* @deprecated use component methods instead
|
||||
*/
|
||||
@Deprecated
|
||||
public String getCancelReason()
|
||||
{
|
||||
return BaseComponent.toLegacyText( getCancelReasonComponents() );
|
||||
return TextComponent.toLegacyText( getReason() );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param cancelReason reason to be displayed
|
||||
* @deprecated Use
|
||||
* {@link #setCancelReason(net.md_5.bungee.api.chat.BaseComponent...)}
|
||||
* instead.
|
||||
* @deprecated use component methods instead
|
||||
*/
|
||||
@Deprecated
|
||||
public void setCancelReason(String cancelReason)
|
||||
{
|
||||
setCancelReason( TextComponent.fromLegacyText( cancelReason ) );
|
||||
setReason( TextComponent.fromLegacy( cancelReason ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return reason to be displayed
|
||||
* @deprecated use single component methods instead
|
||||
*/
|
||||
@Deprecated
|
||||
public BaseComponent[] getCancelReasonComponents()
|
||||
{
|
||||
return new BaseComponent[]
|
||||
{
|
||||
getReason()
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param cancelReason reason to be displayed
|
||||
* @deprecated use single component methods instead
|
||||
*/
|
||||
@Deprecated
|
||||
public void setCancelReason(BaseComponent... cancelReason)
|
||||
{
|
||||
this.cancelReasonComponents = cancelReason;
|
||||
setReason( TextComponent.fromArray( cancelReason ) );
|
||||
}
|
||||
}
|
||||
|
@@ -3,8 +3,9 @@ package net.md_5.bungee.api.event;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
import net.md_5.bungee.api.Callback;
|
||||
import net.md_5.bungee.api.config.ServerInfo;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.plugin.Event;
|
||||
|
||||
/**
|
||||
* Event called as soon as a connection has a {@link ProxiedPlayer} and is ready
|
||||
@@ -13,11 +14,22 @@ import net.md_5.bungee.api.plugin.Event;
|
||||
@Data
|
||||
@ToString(callSuper = false)
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class PostLoginEvent extends Event
|
||||
public class PostLoginEvent extends AsyncEvent<PostLoginEvent>
|
||||
{
|
||||
|
||||
/**
|
||||
* The player involved with this event.
|
||||
*/
|
||||
private final ProxiedPlayer player;
|
||||
/**
|
||||
* The server to which the player will initially be connected.
|
||||
*/
|
||||
private ServerInfo target;
|
||||
|
||||
public PostLoginEvent(ProxiedPlayer player, ServerInfo target, Callback<PostLoginEvent> done)
|
||||
{
|
||||
super( done );
|
||||
this.player = player;
|
||||
this.target = target;
|
||||
}
|
||||
}
|
||||
|
@@ -1,9 +1,7 @@
|
||||
package net.md_5.bungee.api.event;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
import net.md_5.bungee.api.Callback;
|
||||
import net.md_5.bungee.api.chat.BaseComponent;
|
||||
@@ -32,8 +30,7 @@ public class PreLoginEvent extends AsyncEvent<PreLoginEvent> implements Cancella
|
||||
/**
|
||||
* Message to use when kicking if this event is canceled.
|
||||
*/
|
||||
@Setter(AccessLevel.NONE)
|
||||
private BaseComponent[] cancelReasonComponents;
|
||||
private BaseComponent reason;
|
||||
/**
|
||||
* Connection attempting to login.
|
||||
*/
|
||||
@@ -47,28 +44,44 @@ public class PreLoginEvent extends AsyncEvent<PreLoginEvent> implements Cancella
|
||||
|
||||
/**
|
||||
* @return reason to be displayed
|
||||
* @deprecated Use component methods instead.
|
||||
* @deprecated use component methods instead
|
||||
*/
|
||||
@Deprecated
|
||||
public String getCancelReason()
|
||||
{
|
||||
return BaseComponent.toLegacyText( getCancelReasonComponents() );
|
||||
return BaseComponent.toLegacyText( getReason() );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param cancelReason reason to be displayed
|
||||
* @deprecated Use
|
||||
* {@link #setCancelReason(net.md_5.bungee.api.chat.BaseComponent...)}
|
||||
* instead.
|
||||
* @deprecated Use component methods instead
|
||||
*/
|
||||
@Deprecated
|
||||
public void setCancelReason(String cancelReason)
|
||||
{
|
||||
setCancelReason( TextComponent.fromLegacyText( cancelReason ) );
|
||||
setReason( TextComponent.fromLegacy( cancelReason ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return reason to be displayed
|
||||
* @deprecated use single component methods instead
|
||||
*/
|
||||
@Deprecated
|
||||
public BaseComponent[] getCancelReasonComponents()
|
||||
{
|
||||
return new BaseComponent[]
|
||||
{
|
||||
getReason()
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param cancelReason reason to be displayed
|
||||
* @deprecated use single component methods instead
|
||||
*/
|
||||
@Deprecated
|
||||
public void setCancelReason(BaseComponent... cancelReason)
|
||||
{
|
||||
this.cancelReasonComponents = cancelReason;
|
||||
setReason( TextComponent.fromArray( cancelReason ) );
|
||||
}
|
||||
}
|
||||
|
@@ -3,6 +3,7 @@ package net.md_5.bungee.api.event;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
import net.md_5.bungee.api.CommandSender;
|
||||
import net.md_5.bungee.api.plugin.Event;
|
||||
|
||||
@@ -10,6 +11,7 @@ import net.md_5.bungee.api.plugin.Event;
|
||||
* Called when somebody reloads BungeeCord
|
||||
*/
|
||||
@Getter
|
||||
@ToString(callSuper = false)
|
||||
@AllArgsConstructor
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class ProxyReloadEvent extends Event
|
||||
|
@@ -35,7 +35,7 @@ public class ServerKickEvent extends Event implements Cancellable
|
||||
/**
|
||||
* Kick reason.
|
||||
*/
|
||||
private BaseComponent[] kickReasonComponent;
|
||||
private BaseComponent reason;
|
||||
/**
|
||||
* Server to send player to if this event is cancelled.
|
||||
*/
|
||||
@@ -63,24 +63,61 @@ public class ServerKickEvent extends Event implements Cancellable
|
||||
this( player, player.getServer().getInfo(), kickReasonComponent, cancelServer, state );
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public ServerKickEvent(ProxiedPlayer player, ServerInfo kickedFrom, BaseComponent[] kickReasonComponent, ServerInfo cancelServer, State state)
|
||||
{
|
||||
this( player, kickedFrom, TextComponent.fromArray( kickReasonComponent ), cancelServer, state );
|
||||
}
|
||||
|
||||
public ServerKickEvent(ProxiedPlayer player, ServerInfo kickedFrom, BaseComponent reason, ServerInfo cancelServer, State state)
|
||||
{
|
||||
this.player = player;
|
||||
this.kickedFrom = kickedFrom;
|
||||
this.kickReasonComponent = kickReasonComponent;
|
||||
this.reason = reason;
|
||||
this.cancelServer = cancelServer;
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the kick reason
|
||||
* @deprecated use component methods instead
|
||||
*/
|
||||
@Deprecated
|
||||
public String getKickReason()
|
||||
{
|
||||
return BaseComponent.toLegacyText( kickReasonComponent );
|
||||
return BaseComponent.toLegacyText( getReason() );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param reason the kick reason
|
||||
* @deprecated use component methods instead
|
||||
*/
|
||||
@Deprecated
|
||||
public void setKickReason(String reason)
|
||||
{
|
||||
kickReasonComponent = TextComponent.fromLegacyText( reason );
|
||||
this.setReason( TextComponent.fromLegacy( reason ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the kick reason
|
||||
* @deprecated use single component methods instead
|
||||
*/
|
||||
@Deprecated
|
||||
public BaseComponent[] getKickReasonComponent()
|
||||
{
|
||||
return new BaseComponent[]
|
||||
{
|
||||
getReason()
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param kickReasonComponent the kick reason
|
||||
* @deprecated use single component methods instead
|
||||
*/
|
||||
@Deprecated
|
||||
public void setKickReasonComponent(BaseComponent[] kickReasonComponent)
|
||||
{
|
||||
this.setReason( TextComponent.fromArray( kickReasonComponent ) );
|
||||
}
|
||||
}
|
||||
|
@@ -9,7 +9,9 @@ import net.md_5.bungee.api.plugin.Cancellable;
|
||||
|
||||
/**
|
||||
* Event called when a player uses tab completion.
|
||||
* @deprecated please use {@link TabCompleteRequestEvent} to support 1.13+ suggestions.
|
||||
*/
|
||||
@Deprecated
|
||||
@Data
|
||||
@ToString(callSuper = true)
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
|
@@ -0,0 +1,85 @@
|
||||
package net.md_5.bungee.api.event;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.mojang.brigadier.context.StringRange;
|
||||
import com.mojang.brigadier.suggestion.Suggestions;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
import net.md_5.bungee.api.connection.Connection;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.plugin.Cancellable;
|
||||
import net.md_5.bungee.protocol.ProtocolConstants;
|
||||
|
||||
/**
|
||||
* Event called when a player uses tab completion.
|
||||
*/
|
||||
@Data
|
||||
@ToString(callSuper = true)
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class TabCompleteRequestEvent extends TargetedEvent implements Cancellable
|
||||
{
|
||||
|
||||
/**
|
||||
* Cancelled state.
|
||||
*/
|
||||
private boolean cancelled;
|
||||
/**
|
||||
* The message the player has already entered.
|
||||
*/
|
||||
private final String cursor;
|
||||
/**
|
||||
* Range corresponding to the last word of {@link #getCursor()}.
|
||||
* If you want your suggestions to be compatible with 1.12 and older
|
||||
* clients, you need to {@link #setSuggestions(Suggestions)} with
|
||||
* a range equals to this one.
|
||||
* For 1.13 and newer clients, any other range that cover any part of
|
||||
* {@link #getCursor()} is fine.<br>
|
||||
* To check if the client supports custom ranges, use
|
||||
* {@link #supportsCustomRange()}.
|
||||
*/
|
||||
private final StringRange legacyCompatibleRange;
|
||||
/**
|
||||
* The suggestions that will be sent to the client. If this list is empty,
|
||||
* the request will be forwarded to the server.
|
||||
*/
|
||||
private Suggestions suggestions;
|
||||
|
||||
public TabCompleteRequestEvent(Connection sender, Connection receiver, String cursor, StringRange legacyCompatibleRange, Suggestions suggestions)
|
||||
{
|
||||
super( sender, receiver );
|
||||
this.cursor = cursor;
|
||||
this.legacyCompatibleRange = legacyCompatibleRange;
|
||||
this.suggestions = suggestions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the suggestions that will be sent to the client.
|
||||
* If this list is empty, the request will be forwarded to the server.
|
||||
* @param suggestions the new Suggestions. Cannot be null.
|
||||
* @throws IllegalArgumentException if the client is on 1.12 or lower and
|
||||
* {@code suggestions.getRange()} is not equals to {@link #legacyCompatibleRange}.
|
||||
*/
|
||||
public void setSuggestions(Suggestions suggestions)
|
||||
{
|
||||
Preconditions.checkNotNull( suggestions );
|
||||
Preconditions.checkArgument( supportsCustomRange() || legacyCompatibleRange.equals( suggestions.getRange() ),
|
||||
"Clients on 1.12 or lower versions don't support the provided range for tab-completion: " + suggestions.getRange()
|
||||
+ ". Please use TabCompleteRequestEvent.getLegacyCompatibleRange() for legacy clients." );
|
||||
this.suggestions = suggestions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenient method to tell if the client supports custom range for
|
||||
* suggestions.
|
||||
* If the client is on 1.13 or above, this methods returns true, and any
|
||||
* range can be used for {@link #setSuggestions(Suggestions)}. Otherwise,
|
||||
* it returns false and the defined range must be equals to
|
||||
* {@link #legacyCompatibleRange}.
|
||||
* @return true if the client is on 1.13 or newer version, false otherwise.
|
||||
*/
|
||||
public boolean supportsCustomRange()
|
||||
{
|
||||
return ( (ProxiedPlayer) getSender() ).getPendingConnection().getVersion() >= ProtocolConstants.MINECRAFT_1_13;
|
||||
}
|
||||
}
|
@@ -35,6 +35,7 @@ import org.eclipse.aether.transport.http.HttpTransporterFactory;
|
||||
class LibraryLoader
|
||||
{
|
||||
|
||||
private static final String REPOSITORY_PROPERTY = "net.md_5.bungee.api.plugin.centralURL";
|
||||
private final Logger logger;
|
||||
private final RepositorySystem repository;
|
||||
private final DefaultRepositorySystemSession session;
|
||||
@@ -61,9 +62,14 @@ class LibraryLoader
|
||||
logger.log( Level.INFO, "Downloading {0}", event.getResource().getRepositoryUrl() + event.getResource().getResourceName() );
|
||||
}
|
||||
} );
|
||||
|
||||
// SPIGOT-7638: Add system properties,
|
||||
// since JdkVersionProfileActivator needs 'java.version' when a profile has the 'jdk' element
|
||||
// otherwise it will silently fail and not resolves the dependencies in the affected pom.
|
||||
session.setSystemProperties( System.getProperties() );
|
||||
session.setReadOnly();
|
||||
|
||||
this.repositories = repository.newResolutionRepositories( session, Arrays.asList( new RemoteRepository.Builder( "central", "default", "https://repo.maven.apache.org/maven2" ).build() ) );
|
||||
this.repositories = repository.newResolutionRepositories( session, Arrays.asList( new RemoteRepository.Builder( "central", "default", System.getProperty( REPOSITORY_PROPERTY, "https://repo.maven.apache.org/maven2" ) ).build() ) );
|
||||
}
|
||||
|
||||
public ClassLoader createLoader(PluginDescription desc)
|
||||
|
@@ -23,6 +23,10 @@ import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.Stack;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.logging.Level;
|
||||
@@ -59,6 +63,9 @@ public final class PluginManager
|
||||
private final Multimap<Plugin, Command> commandsByPlugin = ArrayListMultimap.create();
|
||||
private final Multimap<Plugin, Listener> listenersByPlugin = ArrayListMultimap.create();
|
||||
|
||||
private final ReadWriteLock commandsLock = new ReentrantReadWriteLock();
|
||||
private final Lock listenersLock = new ReentrantLock();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public PluginManager(ProxyServer proxy)
|
||||
{
|
||||
@@ -93,12 +100,19 @@ public final class PluginManager
|
||||
*/
|
||||
public void registerCommand(Plugin plugin, Command command)
|
||||
{
|
||||
commandMap.put( command.getName().toLowerCase( Locale.ROOT ), command );
|
||||
for ( String alias : command.getAliases() )
|
||||
commandsLock.writeLock().lock();
|
||||
try
|
||||
{
|
||||
commandMap.put( alias.toLowerCase( Locale.ROOT ), command );
|
||||
commandMap.put( command.getName().toLowerCase( Locale.ROOT ), command );
|
||||
for ( String alias : command.getAliases() )
|
||||
{
|
||||
commandMap.put( alias.toLowerCase( Locale.ROOT ), command );
|
||||
}
|
||||
commandsByPlugin.put( plugin, command );
|
||||
} finally
|
||||
{
|
||||
commandsLock.writeLock().unlock();
|
||||
}
|
||||
commandsByPlugin.put( plugin, command );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -108,8 +122,15 @@ public final class PluginManager
|
||||
*/
|
||||
public void unregisterCommand(Command command)
|
||||
{
|
||||
while ( commandMap.values().remove( command ) );
|
||||
commandsByPlugin.values().remove( command );
|
||||
commandsLock.writeLock().lock();
|
||||
try
|
||||
{
|
||||
while ( commandMap.values().remove( command ) );
|
||||
commandsByPlugin.values().remove( command );
|
||||
} finally
|
||||
{
|
||||
commandsLock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -119,11 +140,18 @@ public final class PluginManager
|
||||
*/
|
||||
public void unregisterCommands(Plugin plugin)
|
||||
{
|
||||
for ( Iterator<Command> it = commandsByPlugin.get( plugin ).iterator(); it.hasNext(); )
|
||||
commandsLock.writeLock().lock();
|
||||
try
|
||||
{
|
||||
Command command = it.next();
|
||||
while ( commandMap.values().remove( command ) );
|
||||
it.remove();
|
||||
for ( Iterator<Command> it = commandsByPlugin.get( plugin ).iterator(); it.hasNext(); )
|
||||
{
|
||||
Command command = it.next();
|
||||
while ( commandMap.values().remove( command ) );
|
||||
it.remove();
|
||||
}
|
||||
} finally
|
||||
{
|
||||
commandsLock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,7 +165,14 @@ public final class PluginManager
|
||||
return null;
|
||||
}
|
||||
|
||||
return commandMap.get( commandLower );
|
||||
commandsLock.readLock().lock();
|
||||
try
|
||||
{
|
||||
return commandMap.get( commandLower );
|
||||
} finally
|
||||
{
|
||||
commandsLock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -434,13 +469,20 @@ public final class PluginManager
|
||||
*/
|
||||
public void registerListener(Plugin plugin, Listener listener)
|
||||
{
|
||||
for ( Method method : listener.getClass().getDeclaredMethods() )
|
||||
listenersLock.lock();
|
||||
try
|
||||
{
|
||||
Preconditions.checkArgument( !method.isAnnotationPresent( Subscribe.class ),
|
||||
for ( Method method : listener.getClass().getDeclaredMethods() )
|
||||
{
|
||||
Preconditions.checkArgument( !method.isAnnotationPresent( Subscribe.class ),
|
||||
"Listener %s has registered using deprecated subscribe annotation! Please update to @EventHandler.", listener );
|
||||
}
|
||||
eventBus.register( listener );
|
||||
listenersByPlugin.put( plugin, listener );
|
||||
} finally
|
||||
{
|
||||
listenersLock.unlock();
|
||||
}
|
||||
eventBus.register( listener );
|
||||
listenersByPlugin.put( plugin, listener );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -450,8 +492,15 @@ public final class PluginManager
|
||||
*/
|
||||
public void unregisterListener(Listener listener)
|
||||
{
|
||||
eventBus.unregister( listener );
|
||||
listenersByPlugin.values().remove( listener );
|
||||
listenersLock.lock();
|
||||
try
|
||||
{
|
||||
eventBus.unregister( listener );
|
||||
listenersByPlugin.values().remove( listener );
|
||||
} finally
|
||||
{
|
||||
listenersLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -461,10 +510,17 @@ public final class PluginManager
|
||||
*/
|
||||
public void unregisterListeners(Plugin plugin)
|
||||
{
|
||||
for ( Iterator<Listener> it = listenersByPlugin.get( plugin ).iterator(); it.hasNext(); )
|
||||
listenersLock.lock();
|
||||
try
|
||||
{
|
||||
eventBus.unregister( it.next() );
|
||||
it.remove();
|
||||
for ( Iterator<Listener> it = listenersByPlugin.get( plugin ).iterator(); it.hasNext(); )
|
||||
{
|
||||
eventBus.unregister( it.next() );
|
||||
it.remove();
|
||||
}
|
||||
} finally
|
||||
{
|
||||
listenersLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -475,7 +531,14 @@ public final class PluginManager
|
||||
*/
|
||||
public Collection<Map.Entry<String, Command>> getCommands()
|
||||
{
|
||||
return Collections.unmodifiableCollection( commandMap.entrySet() );
|
||||
commandsLock.readLock().lock();
|
||||
try
|
||||
{
|
||||
return Collections.unmodifiableCollection( commandMap.entrySet() );
|
||||
} finally
|
||||
{
|
||||
commandsLock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
boolean isTransitiveDepend(PluginDescription plugin, PluginDescription depend)
|
||||
|
@@ -1,22 +1,37 @@
|
||||
package net.md_5.bungee.util;
|
||||
|
||||
import gnu.trove.strategy.HashingStrategy;
|
||||
import it.unimi.dsi.fastutil.Hash;
|
||||
import java.util.Locale;
|
||||
|
||||
class CaseInsensitiveHashingStrategy implements HashingStrategy
|
||||
class CaseInsensitiveHashingStrategy implements Hash.Strategy<String>
|
||||
{
|
||||
|
||||
static final CaseInsensitiveHashingStrategy INSTANCE = new CaseInsensitiveHashingStrategy();
|
||||
|
||||
@Override
|
||||
public int computeHashCode(Object object)
|
||||
public int hashCode(String object)
|
||||
{
|
||||
return ( (String) object ).toLowerCase( Locale.ROOT ).hashCode();
|
||||
if ( object == null )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return object.toLowerCase( Locale.ROOT ).hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o1, Object o2)
|
||||
public boolean equals(String o1, String o2)
|
||||
{
|
||||
return o1.equals( o2 ) || ( o1 instanceof String && o2 instanceof String && ( (String) o1 ).toLowerCase( Locale.ROOT ).equals( ( (String) o2 ).toLowerCase( Locale.ROOT ) ) );
|
||||
if ( o1 == o2 )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( o1 == null || o2 == null )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return o1.equals( o2 ) || o1.toLowerCase( Locale.ROOT ).equals( o2.toLowerCase( Locale.ROOT ) );
|
||||
}
|
||||
}
|
||||
|
@@ -1,9 +1,9 @@
|
||||
package net.md_5.bungee.util;
|
||||
|
||||
import gnu.trove.map.hash.TCustomHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenCustomHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class CaseInsensitiveMap<V> extends TCustomHashMap<String, V>
|
||||
public class CaseInsensitiveMap<V> extends Object2ObjectOpenCustomHashMap<String, V>
|
||||
{
|
||||
|
||||
public CaseInsensitiveMap()
|
||||
@@ -13,6 +13,6 @@ public class CaseInsensitiveMap<V> extends TCustomHashMap<String, V>
|
||||
|
||||
public CaseInsensitiveMap(Map<? extends String, ? extends V> map)
|
||||
{
|
||||
super( CaseInsensitiveHashingStrategy.INSTANCE, map );
|
||||
super( map, CaseInsensitiveHashingStrategy.INSTANCE );
|
||||
}
|
||||
}
|
||||
|
@@ -1,9 +1,9 @@
|
||||
package net.md_5.bungee.util;
|
||||
|
||||
import gnu.trove.set.hash.TCustomHashSet;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectOpenCustomHashSet;
|
||||
import java.util.Collection;
|
||||
|
||||
public class CaseInsensitiveSet extends TCustomHashSet<String>
|
||||
public class CaseInsensitiveSet extends ObjectOpenCustomHashSet<String>
|
||||
{
|
||||
|
||||
public CaseInsensitiveSet()
|
||||
@@ -13,6 +13,6 @@ public class CaseInsensitiveSet extends TCustomHashSet<String>
|
||||
|
||||
public CaseInsensitiveSet(Collection<? extends String> collection)
|
||||
{
|
||||
super( CaseInsensitiveHashingStrategy.INSTANCE, collection );
|
||||
super( collection, CaseInsensitiveHashingStrategy.INSTANCE );
|
||||
}
|
||||
}
|
||||
|
@@ -1,12 +1,13 @@
|
||||
package net.md_5.bungee.api;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
import java.util.Collection;
|
||||
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 org.junit.Test;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class ServerConnectRequestTest
|
||||
{
|
||||
@@ -78,15 +79,15 @@ public class ServerConnectRequestTest
|
||||
}
|
||||
};
|
||||
|
||||
@Test(expected = NullPointerException.class)
|
||||
@Test
|
||||
public void testNullTarget()
|
||||
{
|
||||
ServerConnectRequest.builder().target( null ).reason( ServerConnectEvent.Reason.JOIN_PROXY ).build();
|
||||
assertThrows( NullPointerException.class, () -> ServerConnectRequest.builder().target( null ).reason( ServerConnectEvent.Reason.JOIN_PROXY ).build() );
|
||||
}
|
||||
|
||||
@Test(expected = NullPointerException.class)
|
||||
@Test
|
||||
public void testNullReason()
|
||||
{
|
||||
ServerConnectRequest.builder().target( DUMMY_INFO ).reason( null ).build();
|
||||
assertThrows( NullPointerException.class, () -> ServerConnectRequest.builder().target( DUMMY_INFO ).reason( null ).build() );
|
||||
}
|
||||
}
|
||||
|
@@ -1,63 +1,38 @@
|
||||
package net.md_5.bungee.util;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import io.netty.channel.unix.DomainSocketAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.stream.Stream;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import net.md_5.bungee.Util;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.junit.runners.Parameterized.Parameters;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@RunWith(Parameterized.class)
|
||||
public class AddressParseTest
|
||||
{
|
||||
|
||||
@Parameters
|
||||
public static Collection<Object[]> data()
|
||||
public static Stream<Arguments> data()
|
||||
{
|
||||
return Arrays.asList( new Object[][]
|
||||
{
|
||||
{
|
||||
"127.0.0.1", "127.0.0.1", Util.DEFAULT_PORT
|
||||
},
|
||||
{
|
||||
"127.0.0.1:1337", "127.0.0.1", 1337
|
||||
},
|
||||
{
|
||||
"[::1]", "0:0:0:0:0:0:0:1", Util.DEFAULT_PORT
|
||||
},
|
||||
{
|
||||
"[0:0:0:0::1]", "0:0:0:0:0:0:0:1", Util.DEFAULT_PORT
|
||||
},
|
||||
{
|
||||
"[0:0:0:0:0:0:0:1]", "0:0:0:0:0:0:0:1", Util.DEFAULT_PORT
|
||||
},
|
||||
{
|
||||
"[::1]:1337", "0:0:0:0:0:0:0:1", 1337
|
||||
},
|
||||
{
|
||||
"[0:0:0:0::1]:1337", "0:0:0:0:0:0:0:1", 1337
|
||||
},
|
||||
{
|
||||
"[0:0:0:0:0:0:0:1]:1337", "0:0:0:0:0:0:0:1", 1337
|
||||
},
|
||||
{
|
||||
"unix:///var/run/bungee.sock", "/var/run/bungee.sock", -1
|
||||
}
|
||||
} );
|
||||
return Stream.of(
|
||||
Arguments.of( "127.0.0.1", "127.0.0.1", Util.DEFAULT_PORT ),
|
||||
Arguments.of( "127.0.0.1:1337", "127.0.0.1", 1337 ),
|
||||
Arguments.of( "[::1]", "0:0:0:0:0:0:0:1", Util.DEFAULT_PORT ),
|
||||
Arguments.of( "[0:0:0:0::1]", "0:0:0:0:0:0:0:1", Util.DEFAULT_PORT ),
|
||||
Arguments.of( "[0:0:0:0:0:0:0:1]", "0:0:0:0:0:0:0:1", Util.DEFAULT_PORT ),
|
||||
Arguments.of( "[::1]:1337", "0:0:0:0:0:0:0:1", 1337 ),
|
||||
Arguments.of( "[0:0:0:0::1]:1337", "0:0:0:0:0:0:0:1", 1337 ),
|
||||
Arguments.of( "[0:0:0:0:0:0:0:1]:1337", "0:0:0:0:0:0:0:1", 1337 ),
|
||||
Arguments.of( "unix:///var/run/bungee.sock", "/var/run/bungee.sock", -1 )
|
||||
);
|
||||
}
|
||||
private final String line;
|
||||
private final String host;
|
||||
private final int port;
|
||||
|
||||
@Test
|
||||
public void test()
|
||||
@ParameterizedTest
|
||||
@MethodSource("data")
|
||||
public void test(String line, String host, int port)
|
||||
{
|
||||
SocketAddress parsed = Util.getAddr( line );
|
||||
|
||||
@@ -65,14 +40,14 @@ public class AddressParseTest
|
||||
{
|
||||
InetSocketAddress tcp = (InetSocketAddress) parsed;
|
||||
|
||||
Assert.assertEquals( host, tcp.getHostString() );
|
||||
Assert.assertEquals( port, tcp.getPort() );
|
||||
assertEquals( host, tcp.getHostString() );
|
||||
assertEquals( port, tcp.getPort() );
|
||||
} else if ( parsed instanceof DomainSocketAddress )
|
||||
{
|
||||
DomainSocketAddress unix = (DomainSocketAddress) parsed;
|
||||
|
||||
Assert.assertEquals( host, unix.path() );
|
||||
Assert.assertEquals( -1, port );
|
||||
assertEquals( host, unix.path() );
|
||||
assertEquals( -1, port );
|
||||
} else
|
||||
{
|
||||
throw new AssertionError( "Unknown socket " + parsed );
|
||||
|
@@ -1,7 +1,7 @@
|
||||
package net.md_5.bungee.util;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class CaseInsensitiveTest
|
||||
{
|
||||
@@ -13,12 +13,12 @@ public class CaseInsensitiveTest
|
||||
CaseInsensitiveMap<Object> map = new CaseInsensitiveMap<>();
|
||||
|
||||
map.put( "FOO", obj );
|
||||
Assert.assertTrue( map.contains( "foo" ) ); // Assert that contains is case insensitive
|
||||
Assert.assertTrue( map.entrySet().iterator().next().getKey().equals( "FOO" ) ); // Assert that case is preserved
|
||||
assertTrue( map.containsKey( "foo" ) ); // Assert that contains is case insensitive
|
||||
assertTrue( map.entrySet().iterator().next().getKey().equals( "FOO" ) ); // Assert that case is preserved
|
||||
|
||||
// Assert that remove is case insensitive
|
||||
map.remove( "FoO" );
|
||||
Assert.assertFalse( map.contains( "foo" ) );
|
||||
assertFalse( map.containsKey( "foo" ) );
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -27,8 +27,8 @@ public class CaseInsensitiveTest
|
||||
CaseInsensitiveSet set = new CaseInsensitiveSet();
|
||||
|
||||
set.add( "FOO" );
|
||||
Assert.assertTrue( set.contains( "foo" ) ); // Assert that contains is case insensitive
|
||||
assertTrue( set.contains( "foo" ) ); // Assert that contains is case insensitive
|
||||
set.remove( "FoO" );
|
||||
Assert.assertFalse( set.contains( "foo" ) ); // Assert that remove is case insensitive
|
||||
assertFalse( set.contains( "foo" ) ); // Assert that remove is case insensitive
|
||||
}
|
||||
}
|
||||
|
@@ -1,9 +1,9 @@
|
||||
package net.md_5.bungee.util;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import java.util.UUID;
|
||||
import net.md_5.bungee.Util;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class UUIDTest
|
||||
{
|
||||
@@ -13,7 +13,7 @@ public class UUIDTest
|
||||
{
|
||||
UUID uuid = UUID.fromString( "af74a02d-19cb-445b-b07f-6866a861f783" );
|
||||
UUID uuid1 = Util.getUUID( "af74a02d19cb445bb07f6866a861f783" );
|
||||
Assert.assertEquals( uuid, uuid1 );
|
||||
assertEquals( uuid, uuid1 );
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -23,7 +23,7 @@ public class UUIDTest
|
||||
{
|
||||
UUID expected = UUID.randomUUID();
|
||||
UUID actual = Util.getUUID( expected.toString().replace( "-", "" ) );
|
||||
Assert.assertEquals( "Could not parse UUID " + expected, expected, actual );
|
||||
assertEquals( expected, actual, "Could not parse UUID " + expected );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -4,15 +4,14 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>net.md-5</groupId>
|
||||
<groupId>fr.pandacube.bungeecord</groupId>
|
||||
<artifactId>bungeecord-parent</artifactId>
|
||||
<version>1.20-R0.2-SNAPSHOT</version>
|
||||
<version>1.21-R0.4-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-bootstrap</artifactId>
|
||||
<version>1.20-R0.2-SNAPSHOT</version>
|
||||
<version>1.21-R0.4-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>BungeeCord-Bootstrap</name>
|
||||
@@ -21,14 +20,12 @@
|
||||
<properties>
|
||||
<maven.deploy.skip>true</maven.deploy.skip>
|
||||
<maven.javadoc.skip>true</maven.javadoc.skip>
|
||||
<maven.compiler.source>1.6</maven.compiler.source>
|
||||
<maven.compiler.target>1.6</maven.compiler.target>
|
||||
<maven.build.timestamp.format>yyyyMMdd</maven.build.timestamp.format>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>net.md-5</groupId>
|
||||
<groupId>fr.pandacube.bungeecord</groupId>
|
||||
<artifactId>bungeecord-proxy</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
@@ -36,18 +33,19 @@
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<finalName>BungeeCord</finalName>
|
||||
<finalName>BungeeCord-${project.version}-${build.number}</finalName>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>3.3.0</version>
|
||||
<version>3.4.1</version>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifestEntries>
|
||||
<Main-Class>net.md_5.bungee.Bootstrap</Main-Class>
|
||||
<Implementation-Version>${describe}</Implementation-Version>
|
||||
<Specification-Version>${maven.build.timestamp}</Specification-Version>
|
||||
<Enable-Native-Access>ALL-UNNAMED</Enable-Native-Access>
|
||||
</manifestEntries>
|
||||
</archive>
|
||||
</configuration>
|
||||
@@ -55,7 +53,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>3.5.0</version>
|
||||
<version>3.5.3</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
|
@@ -4,15 +4,14 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>net.md-5</groupId>
|
||||
<groupId>fr.pandacube.bungeecord</groupId>
|
||||
<artifactId>bungeecord-parent</artifactId>
|
||||
<version>1.20-R0.2-SNAPSHOT</version>
|
||||
<version>1.21-R0.4-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-chat</artifactId>
|
||||
<version>1.20-R0.2-SNAPSHOT</version>
|
||||
<version>1.21-R0.4-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>BungeeCord-Chat</name>
|
||||
@@ -22,7 +21,7 @@
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
<version>2.10.1</version>
|
||||
<version>2.11.0</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
@@ -244,7 +244,7 @@ public final class ChatColor
|
||||
public static ChatColor of(String string)
|
||||
{
|
||||
Preconditions.checkArgument( string != null, "string cannot be null" );
|
||||
if ( string.startsWith( "#" ) && string.length() == 7 )
|
||||
if ( string.length() == 7 && string.charAt( 0 ) == '#' )
|
||||
{
|
||||
int rgb;
|
||||
try
|
||||
|
@@ -1,8 +1,10 @@
|
||||
package net.md_5.bungee.api.chat;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
@@ -20,38 +22,10 @@ public abstract class BaseComponent
|
||||
BaseComponent parent;
|
||||
|
||||
/**
|
||||
* The color of this component and any child components (unless overridden)
|
||||
* The component's style.
|
||||
*/
|
||||
private ChatColor color;
|
||||
/**
|
||||
* The font of this component and any child components (unless overridden)
|
||||
*/
|
||||
private String font;
|
||||
/**
|
||||
* Whether this component and any child components (unless overridden) is
|
||||
* bold
|
||||
*/
|
||||
private Boolean bold;
|
||||
/**
|
||||
* Whether this component and any child components (unless overridden) is
|
||||
* italic
|
||||
*/
|
||||
private Boolean italic;
|
||||
/**
|
||||
* Whether this component and any child components (unless overridden) is
|
||||
* underlined
|
||||
*/
|
||||
private Boolean underlined;
|
||||
/**
|
||||
* Whether this component and any child components (unless overridden) is
|
||||
* strikethrough
|
||||
*/
|
||||
private Boolean strikethrough;
|
||||
/**
|
||||
* Whether this component and any child components (unless overridden) is
|
||||
* obfuscated
|
||||
*/
|
||||
private Boolean obfuscated;
|
||||
@Getter
|
||||
private ComponentStyle style = new ComponentStyle();
|
||||
/**
|
||||
* The text to insert into the chat when this component (and child
|
||||
* components) are clicked while pressing the shift key
|
||||
@@ -153,31 +127,35 @@ public abstract class BaseComponent
|
||||
}
|
||||
if ( retention == FormatRetention.FORMATTING || retention == FormatRetention.ALL )
|
||||
{
|
||||
if ( replace || color == null )
|
||||
if ( replace || !style.hasColor() )
|
||||
{
|
||||
setColor( component.getColorRaw() );
|
||||
}
|
||||
if ( replace || font == null )
|
||||
if ( replace || !style.hasShadowColor() )
|
||||
{
|
||||
setShadowColor( component.getShadowColorRaw() );
|
||||
}
|
||||
if ( replace || !style.hasFont() )
|
||||
{
|
||||
setFont( component.getFontRaw() );
|
||||
}
|
||||
if ( replace || bold == null )
|
||||
if ( replace || style.isBoldRaw() == null )
|
||||
{
|
||||
setBold( component.isBoldRaw() );
|
||||
}
|
||||
if ( replace || italic == null )
|
||||
if ( replace || style.isItalicRaw() == null )
|
||||
{
|
||||
setItalic( component.isItalicRaw() );
|
||||
}
|
||||
if ( replace || underlined == null )
|
||||
if ( replace || style.isUnderlinedRaw() == null )
|
||||
{
|
||||
setUnderlined( component.isUnderlinedRaw() );
|
||||
}
|
||||
if ( replace || strikethrough == null )
|
||||
if ( replace || style.isStrikethroughRaw() == null )
|
||||
{
|
||||
setStrikethrough( component.isStrikethroughRaw() );
|
||||
}
|
||||
if ( replace || obfuscated == null )
|
||||
if ( replace || style.isObfuscatedRaw() == null )
|
||||
{
|
||||
setObfuscated( component.isObfuscatedRaw() );
|
||||
}
|
||||
@@ -203,6 +181,7 @@ public abstract class BaseComponent
|
||||
if ( retention == FormatRetention.EVENTS || retention == FormatRetention.NONE )
|
||||
{
|
||||
setColor( null );
|
||||
setShadowColor( null );
|
||||
setBold( null );
|
||||
setItalic( null );
|
||||
setUnderlined( null );
|
||||
@@ -266,6 +245,32 @@ public abstract class BaseComponent
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link ComponentStyle} for this component.
|
||||
* <p>
|
||||
* Unlike {@link #applyStyle(ComponentStyle)}, this method will overwrite
|
||||
* all style values on this component.
|
||||
*
|
||||
* @param style the style to set, or null to set all style values to default
|
||||
*/
|
||||
public void setStyle(ComponentStyle style)
|
||||
{
|
||||
this.style = ( style != null ) ? style.clone() : new ComponentStyle();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this component's color.
|
||||
* <p>
|
||||
* <b>Warning: This should be a color, not formatting code (ie,
|
||||
* {@link ChatColor#color} should not be null).</b>
|
||||
*
|
||||
* @param color the component color, or null to use the default
|
||||
*/
|
||||
public void setColor(ChatColor color)
|
||||
{
|
||||
this.style.setColor( color );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the color of this component. This uses the parent's color if this
|
||||
* component doesn't have one. {@link net.md_5.bungee.api.ChatColor#WHITE}
|
||||
@@ -275,7 +280,7 @@ public abstract class BaseComponent
|
||||
*/
|
||||
public ChatColor getColor()
|
||||
{
|
||||
if ( color == null )
|
||||
if ( !style.hasColor() )
|
||||
{
|
||||
if ( parent == null )
|
||||
{
|
||||
@@ -283,7 +288,7 @@ public abstract class BaseComponent
|
||||
}
|
||||
return parent.getColor();
|
||||
}
|
||||
return color;
|
||||
return style.getColor();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -294,7 +299,57 @@ public abstract class BaseComponent
|
||||
*/
|
||||
public ChatColor getColorRaw()
|
||||
{
|
||||
return color;
|
||||
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.
|
||||
*
|
||||
* @param font the font to set, or null to use the default
|
||||
*/
|
||||
public void setFont(String font)
|
||||
{
|
||||
this.style.setFont( font );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -305,7 +360,7 @@ public abstract class BaseComponent
|
||||
*/
|
||||
public String getFont()
|
||||
{
|
||||
if ( font == null )
|
||||
if ( !style.hasFont() )
|
||||
{
|
||||
if ( parent == null )
|
||||
{
|
||||
@@ -313,7 +368,7 @@ public abstract class BaseComponent
|
||||
}
|
||||
return parent.getFont();
|
||||
}
|
||||
return font;
|
||||
return style.getFont();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -324,7 +379,17 @@ public abstract class BaseComponent
|
||||
*/
|
||||
public String getFontRaw()
|
||||
{
|
||||
return font;
|
||||
return style.getFont();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether or not this component is bold.
|
||||
*
|
||||
* @param bold the new bold state, or null to use the default
|
||||
*/
|
||||
public void setBold(Boolean bold)
|
||||
{
|
||||
this.style.setBold( bold );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -336,11 +401,11 @@ public abstract class BaseComponent
|
||||
*/
|
||||
public boolean isBold()
|
||||
{
|
||||
if ( bold == null )
|
||||
if ( style.isBoldRaw() == null )
|
||||
{
|
||||
return parent != null && parent.isBold();
|
||||
}
|
||||
return bold;
|
||||
return style.isBold();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -351,7 +416,17 @@ public abstract class BaseComponent
|
||||
*/
|
||||
public Boolean isBoldRaw()
|
||||
{
|
||||
return bold;
|
||||
return style.isBoldRaw();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether or not this component is italic.
|
||||
*
|
||||
* @param italic the new italic state, or null to use the default
|
||||
*/
|
||||
public void setItalic(Boolean italic)
|
||||
{
|
||||
this.style.setItalic( italic );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -363,11 +438,11 @@ public abstract class BaseComponent
|
||||
*/
|
||||
public boolean isItalic()
|
||||
{
|
||||
if ( italic == null )
|
||||
if ( style.isItalicRaw() == null )
|
||||
{
|
||||
return parent != null && parent.isItalic();
|
||||
}
|
||||
return italic;
|
||||
return style.isItalic();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -378,7 +453,17 @@ public abstract class BaseComponent
|
||||
*/
|
||||
public Boolean isItalicRaw()
|
||||
{
|
||||
return italic;
|
||||
return style.isItalicRaw();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether or not this component is underlined.
|
||||
*
|
||||
* @param underlined the new underlined state, or null to use the default
|
||||
*/
|
||||
public void setUnderlined(Boolean underlined)
|
||||
{
|
||||
this.style.setUnderlined( underlined );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -390,11 +475,11 @@ public abstract class BaseComponent
|
||||
*/
|
||||
public boolean isUnderlined()
|
||||
{
|
||||
if ( underlined == null )
|
||||
if ( style.isUnderlinedRaw() == null )
|
||||
{
|
||||
return parent != null && parent.isUnderlined();
|
||||
}
|
||||
return underlined;
|
||||
return style.isUnderlined();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -405,7 +490,18 @@ public abstract class BaseComponent
|
||||
*/
|
||||
public Boolean isUnderlinedRaw()
|
||||
{
|
||||
return underlined;
|
||||
return style.isUnderlinedRaw();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether or not this component is strikethrough.
|
||||
*
|
||||
* @param strikethrough the new strikethrough state, or null to use the
|
||||
* default
|
||||
*/
|
||||
public void setStrikethrough(Boolean strikethrough)
|
||||
{
|
||||
this.style.setStrikethrough( strikethrough );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -417,11 +513,11 @@ public abstract class BaseComponent
|
||||
*/
|
||||
public boolean isStrikethrough()
|
||||
{
|
||||
if ( strikethrough == null )
|
||||
if ( style.isStrikethroughRaw() == null )
|
||||
{
|
||||
return parent != null && parent.isStrikethrough();
|
||||
}
|
||||
return strikethrough;
|
||||
return style.isStrikethrough();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -432,7 +528,17 @@ public abstract class BaseComponent
|
||||
*/
|
||||
public Boolean isStrikethroughRaw()
|
||||
{
|
||||
return strikethrough;
|
||||
return style.isStrikethroughRaw();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether or not this component is obfuscated.
|
||||
*
|
||||
* @param obfuscated the new obfuscated state, or null to use the default
|
||||
*/
|
||||
public void setObfuscated(Boolean obfuscated)
|
||||
{
|
||||
this.style.setObfuscated( obfuscated );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -444,11 +550,11 @@ public abstract class BaseComponent
|
||||
*/
|
||||
public boolean isObfuscated()
|
||||
{
|
||||
if ( obfuscated == null )
|
||||
if ( style.isObfuscatedRaw() == null )
|
||||
{
|
||||
return parent != null && parent.isObfuscated();
|
||||
}
|
||||
return obfuscated;
|
||||
return style.isObfuscated();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -459,7 +565,52 @@ public abstract class BaseComponent
|
||||
*/
|
||||
public Boolean isObfuscatedRaw()
|
||||
{
|
||||
return obfuscated;
|
||||
return style.isObfuscatedRaw();
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the style from the given {@link ComponentStyle} to this component.
|
||||
* <p>
|
||||
* Any style values that have been explicitly set in the style will be
|
||||
* applied to this component. If a value is not set in the style, it will
|
||||
* not override the style set in this component.
|
||||
*
|
||||
* @param style the style to apply
|
||||
*/
|
||||
public void applyStyle(ComponentStyle style)
|
||||
{
|
||||
if ( style.hasColor() )
|
||||
{
|
||||
setColor( style.getColor() );
|
||||
}
|
||||
if ( style.hasShadowColor() )
|
||||
{
|
||||
setShadowColor( style.getShadowColor() );
|
||||
}
|
||||
if ( style.hasFont() )
|
||||
{
|
||||
setFont( style.getFont() );
|
||||
}
|
||||
if ( style.isBoldRaw() != null )
|
||||
{
|
||||
setBold( style.isBoldRaw() );
|
||||
}
|
||||
if ( style.isItalicRaw() != null )
|
||||
{
|
||||
setItalic( style.isItalicRaw() );
|
||||
}
|
||||
if ( style.isUnderlinedRaw() != null )
|
||||
{
|
||||
setUnderlined( style.isUnderlinedRaw() );
|
||||
}
|
||||
if ( style.isStrikethroughRaw() != null )
|
||||
{
|
||||
setStrikethrough( style.isStrikethroughRaw() );
|
||||
}
|
||||
if ( style.isObfuscatedRaw() != null )
|
||||
{
|
||||
setObfuscated( style.isObfuscatedRaw() );
|
||||
}
|
||||
}
|
||||
|
||||
public void setExtra(List<BaseComponent> components)
|
||||
@@ -498,6 +649,16 @@ public abstract class BaseComponent
|
||||
extra.add( component );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the component has any styling applied to it.
|
||||
*
|
||||
* @return Whether any styling is applied
|
||||
*/
|
||||
public boolean hasStyle()
|
||||
{
|
||||
return !style.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the component has any formatting or events applied to it
|
||||
*
|
||||
@@ -505,10 +666,8 @@ public abstract class BaseComponent
|
||||
*/
|
||||
public boolean hasFormatting()
|
||||
{
|
||||
return color != null || font != null || bold != null
|
||||
|| italic != null || underlined != null
|
||||
|| strikethrough != null || obfuscated != null
|
||||
|| insertion != null || hoverEvent != null || clickEvent != null;
|
||||
return hasStyle() || insertion != null
|
||||
|| hoverEvent != null || clickEvent != null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -519,11 +678,11 @@ public abstract class BaseComponent
|
||||
public String toPlainText()
|
||||
{
|
||||
StringBuilder builder = new StringBuilder();
|
||||
toPlainText( builder );
|
||||
toPlainText( new LimitedStringVisitor( builder, Short.MAX_VALUE ) );
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
void toPlainText(StringBuilder builder)
|
||||
void toPlainText(StringVisitor builder)
|
||||
{
|
||||
if ( extra != null )
|
||||
{
|
||||
@@ -543,11 +702,11 @@ public abstract class BaseComponent
|
||||
public String toLegacyText()
|
||||
{
|
||||
StringBuilder builder = new StringBuilder();
|
||||
toLegacyText( builder );
|
||||
toLegacyText( new LimitedStringVisitor( builder, Short.MAX_VALUE ) );
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
void toLegacyText(StringBuilder builder)
|
||||
void toLegacyText(StringVisitor builder)
|
||||
{
|
||||
if ( extra != null )
|
||||
{
|
||||
@@ -558,7 +717,7 @@ public abstract class BaseComponent
|
||||
}
|
||||
}
|
||||
|
||||
void addFormat(StringBuilder builder)
|
||||
void addFormat(StringVisitor builder)
|
||||
{
|
||||
builder.append( getColor() );
|
||||
if ( isBold() )
|
||||
@@ -582,4 +741,35 @@ public abstract class BaseComponent
|
||||
builder.append( ChatColor.MAGIC );
|
||||
}
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
protected static interface StringVisitor
|
||||
{
|
||||
|
||||
void append(String s);
|
||||
|
||||
default void append(Object obj)
|
||||
{
|
||||
append( String.valueOf( obj ) );
|
||||
}
|
||||
}
|
||||
|
||||
@Data
|
||||
protected static class LimitedStringVisitor implements StringVisitor
|
||||
{
|
||||
|
||||
private final StringBuilder builder;
|
||||
private final int maxLength;
|
||||
|
||||
@Override
|
||||
public void append(String s)
|
||||
{
|
||||
if ( builder.length() >= maxLength )
|
||||
{
|
||||
throw new IllegalArgumentException( "String exceeded maximum length " + maxLength );
|
||||
}
|
||||
|
||||
builder.append( s );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -4,12 +4,14 @@ import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.ToString;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
@Getter
|
||||
@ToString
|
||||
@EqualsAndHashCode
|
||||
@RequiredArgsConstructor
|
||||
public final class ClickEvent
|
||||
@ApiStatus.NonExtendable
|
||||
public class ClickEvent
|
||||
{
|
||||
|
||||
/**
|
||||
@@ -52,11 +54,19 @@ public final class ClickEvent
|
||||
* {@link net.md_5.bungee.api.chat.ClickEvent#value} in a book.
|
||||
*/
|
||||
CHANGE_PAGE,
|
||||
/**
|
||||
* Must use subclass ShowDialogClickEvent.
|
||||
*/
|
||||
SHOW_DIALOG,
|
||||
/**
|
||||
* Copy the string given by
|
||||
* {@link net.md_5.bungee.api.chat.ClickEvent#value} into the player's
|
||||
* clipboard.
|
||||
*/
|
||||
COPY_TO_CLIPBOARD
|
||||
COPY_TO_CLIPBOARD,
|
||||
/**
|
||||
* Must use subclass {@link ClickEventCustom}.
|
||||
*/
|
||||
CUSTOM,
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,30 @@
|
||||
package net.md_5.bungee.api.chat;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
/**
|
||||
* Click event which sends a custom payload to the server.
|
||||
*/
|
||||
@Data
|
||||
@ToString(callSuper = true)
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ClickEventCustom extends ClickEvent
|
||||
{
|
||||
|
||||
/**
|
||||
* The custom payload.
|
||||
*/
|
||||
private final String payload;
|
||||
|
||||
/**
|
||||
* @param id identifier for the event (lower case, no special characters)
|
||||
* @param payload custom payload
|
||||
*/
|
||||
public ClickEventCustom(String id, String payload)
|
||||
{
|
||||
super( ClickEvent.Action.CUSTOM, id );
|
||||
this.payload = payload;
|
||||
}
|
||||
}
|
@@ -204,6 +204,33 @@ public final class ComponentBuilder
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the {@link TranslationProvider} object to the builder and makes
|
||||
* the last element the current target for formatting. The components will
|
||||
* have all the formatting from previous part.
|
||||
*
|
||||
* @param translatable the translatable object to append
|
||||
* @return this ComponentBuilder for chaining
|
||||
*/
|
||||
public ComponentBuilder append(TranslationProvider translatable)
|
||||
{
|
||||
return append( translatable, FormatRetention.ALL );
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the {@link TranslationProvider} object to the builder and makes
|
||||
* the last element the current target for formatting. You can specify the
|
||||
* amount of formatting retained from previous part.
|
||||
*
|
||||
* @param translatable the translatable object to append
|
||||
* @param retention the formatting to retain
|
||||
* @return this ComponentBuilder for chaining
|
||||
*/
|
||||
public ComponentBuilder append(TranslationProvider translatable, FormatRetention retention)
|
||||
{
|
||||
return append( translatable.asTranslatableComponent(), retention );
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the text to the builder and makes it the current target for
|
||||
* formatting. The text will have all the formatting from previous part.
|
||||
@@ -396,6 +423,18 @@ public final class ComponentBuilder
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the provided {@link ComponentStyle} to the current part.
|
||||
*
|
||||
* @param style the style to apply
|
||||
* @return this ComponentBuilder for chaining
|
||||
*/
|
||||
public ComponentBuilder style(ComponentStyle style)
|
||||
{
|
||||
getCurrentComponent().applyStyle( style );
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the insertion text for the current part.
|
||||
*
|
||||
@@ -455,8 +494,8 @@ public final class ComponentBuilder
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the component built by this builder. If this builder is
|
||||
* empty, an empty text component will be returned.
|
||||
* Returns the component built by this builder. If this builder is empty, an
|
||||
* empty text component will be returned.
|
||||
*
|
||||
* @return the component
|
||||
*/
|
||||
@@ -478,8 +517,8 @@ public final class ComponentBuilder
|
||||
* <p>
|
||||
* <strong>NOTE:</strong> {@link #build()} is preferred as it will
|
||||
* consolidate all components into a single BaseComponent with extra
|
||||
* contents as opposed to an array of components which is non-standard
|
||||
* and may result in unexpected behavior.
|
||||
* contents as opposed to an array of components which is non-standard and
|
||||
* may result in unexpected behavior.
|
||||
*
|
||||
* @return the created components
|
||||
*/
|
||||
|
263
chat/src/main/java/net/md_5/bungee/api/chat/ComponentStyle.java
Normal file
263
chat/src/main/java/net/md_5/bungee/api/chat/ComponentStyle.java
Normal file
@@ -0,0 +1,263 @@
|
||||
package net.md_5.bungee.api.chat;
|
||||
|
||||
import java.awt.Color;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
|
||||
/**
|
||||
* Represents a style that may be applied to a {@link BaseComponent}.
|
||||
*/
|
||||
@Setter
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@EqualsAndHashCode
|
||||
public final class ComponentStyle implements Cloneable
|
||||
{
|
||||
|
||||
/**
|
||||
* The color of this style.
|
||||
* <p>
|
||||
* <b>Warning: This should be a color, not formatting code (ie,
|
||||
* {@link ChatColor#color} should not be null).</b>
|
||||
*/
|
||||
private ChatColor color;
|
||||
/**
|
||||
* The shadow color of this style.
|
||||
*/
|
||||
private Color shadowColor;
|
||||
/**
|
||||
* The font of this style.
|
||||
*/
|
||||
private String font;
|
||||
/**
|
||||
* Whether this style is bold.
|
||||
*/
|
||||
private Boolean bold;
|
||||
/**
|
||||
* Whether this style is italic.
|
||||
*/
|
||||
private Boolean italic;
|
||||
/**
|
||||
* Whether this style is underlined.
|
||||
*/
|
||||
private Boolean underlined;
|
||||
/**
|
||||
* Whether this style is strikethrough.
|
||||
*/
|
||||
private Boolean strikethrough;
|
||||
/**
|
||||
* Whether this style is obfuscated.
|
||||
*/
|
||||
private Boolean obfuscated;
|
||||
|
||||
/**
|
||||
* Returns the color of this style. May return null.
|
||||
*
|
||||
* @return the color of this style, or null if default color
|
||||
*/
|
||||
public ChatColor getColor()
|
||||
{
|
||||
return color;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not this style has a color set.
|
||||
*
|
||||
* @return whether a color is set
|
||||
*/
|
||||
public boolean hasColor()
|
||||
{
|
||||
return ( color != null );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the 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.
|
||||
*
|
||||
* @return the font of this style, or null if default font
|
||||
*/
|
||||
public String getFont()
|
||||
{
|
||||
return font;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not this style has a font set.
|
||||
*
|
||||
* @return whether a font is set
|
||||
*/
|
||||
public boolean hasFont()
|
||||
{
|
||||
return ( font != null );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this style is bold.
|
||||
*
|
||||
* @return whether the style is bold
|
||||
*/
|
||||
public boolean isBold()
|
||||
{
|
||||
return ( bold != null ) && bold.booleanValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this style is bold. May return null.
|
||||
*
|
||||
* @return whether the style is bold, or null if not set
|
||||
*/
|
||||
public Boolean isBoldRaw()
|
||||
{
|
||||
return bold;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this style is italic. May return null.
|
||||
*
|
||||
* @return whether the style is italic
|
||||
*/
|
||||
public boolean isItalic()
|
||||
{
|
||||
return ( italic != null ) && italic.booleanValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this style is italic. May return null.
|
||||
*
|
||||
* @return whether the style is italic, or null if not set
|
||||
*/
|
||||
public Boolean isItalicRaw()
|
||||
{
|
||||
return italic;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this style is underlined.
|
||||
*
|
||||
* @return whether the style is underlined
|
||||
*/
|
||||
public boolean isUnderlined()
|
||||
{
|
||||
return ( underlined != null ) && underlined.booleanValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this style is underlined. May return null.
|
||||
*
|
||||
* @return whether the style is underlined, or null if not set
|
||||
*/
|
||||
public Boolean isUnderlinedRaw()
|
||||
{
|
||||
return underlined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this style is strikethrough
|
||||
*
|
||||
* @return whether the style is strikethrough
|
||||
*/
|
||||
public boolean isStrikethrough()
|
||||
{
|
||||
return ( strikethrough != null ) && strikethrough.booleanValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this style is strikethrough. May return null.
|
||||
*
|
||||
* @return whether the style is strikethrough, or null if not set
|
||||
*/
|
||||
public Boolean isStrikethroughRaw()
|
||||
{
|
||||
return strikethrough;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this style is obfuscated.
|
||||
*
|
||||
* @return whether the style is obfuscated
|
||||
*/
|
||||
public boolean isObfuscated()
|
||||
{
|
||||
return ( obfuscated != null ) && obfuscated.booleanValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this style is obfuscated. May return null.
|
||||
*
|
||||
* @return whether the style is obfuscated, or null if not set
|
||||
*/
|
||||
public Boolean isObfuscatedRaw()
|
||||
{
|
||||
return obfuscated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this style has no formatting explicitly set.
|
||||
*
|
||||
* @return true if no value is set, false if at least one is set
|
||||
*/
|
||||
public boolean isEmpty()
|
||||
{
|
||||
return color == null && shadowColor == null && font == null && bold == null
|
||||
&& italic == null && underlined == null
|
||||
&& strikethrough == null && obfuscated == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ComponentStyle clone()
|
||||
{
|
||||
return new ComponentStyle( color, shadowColor, font, bold, italic, underlined, strikethrough, obfuscated );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a new {@link ComponentStyleBuilder}.
|
||||
*
|
||||
* @return the builder
|
||||
*/
|
||||
public static ComponentStyleBuilder builder()
|
||||
{
|
||||
return new ComponentStyleBuilder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a new {@link ComponentStyleBuilder} with values initialized to the
|
||||
* style values of the supplied {@link ComponentStyle}.
|
||||
*
|
||||
* @param other the component style whose values to copy into the builder
|
||||
* @return the builder
|
||||
*/
|
||||
public static ComponentStyleBuilder builder(ComponentStyle other)
|
||||
{
|
||||
return new ComponentStyleBuilder()
|
||||
.color( other.color )
|
||||
.shadowColor( other.shadowColor )
|
||||
.font( other.font )
|
||||
.bold( other.bold )
|
||||
.italic( other.italic )
|
||||
.underlined( other.underlined )
|
||||
.strikethrough( other.strikethrough )
|
||||
.obfuscated( other.obfuscated );
|
||||
}
|
||||
}
|
@@ -0,0 +1,140 @@
|
||||
package net.md_5.bungee.api.chat;
|
||||
|
||||
import java.awt.Color;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* ComponentStyleBuilder simplifies creating component styles by allowing the
|
||||
* use of a chainable builder.
|
||||
* </p>
|
||||
* <pre>
|
||||
* ComponentStyle style = ComponentStyle.builder()
|
||||
* .color(ChatColor.RED)
|
||||
* .font("custom:font")
|
||||
* .bold(true).italic(true).create();
|
||||
*
|
||||
* BaseComponent component = new ComponentBuilder("Hello world").style(style).create();
|
||||
* // Or it can be used directly on a component
|
||||
* TextComponent text = new TextComponent("Hello world");
|
||||
* text.applyStyle(style);
|
||||
* </pre>
|
||||
*
|
||||
* @see ComponentStyle#builder()
|
||||
* @see ComponentStyle#builder(ComponentStyle)
|
||||
*/
|
||||
public final class ComponentStyleBuilder
|
||||
{
|
||||
|
||||
private ChatColor color;
|
||||
private Color shadowColor;
|
||||
private String font;
|
||||
private Boolean bold, italic, underlined, strikethrough, obfuscated;
|
||||
|
||||
/**
|
||||
* Set the style color.
|
||||
*
|
||||
* @param color the color to set, or null to use the default
|
||||
* @return this ComponentStyleBuilder for chaining
|
||||
*/
|
||||
public ComponentStyleBuilder color(ChatColor color)
|
||||
{
|
||||
this.color = color;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the style 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.
|
||||
*
|
||||
* @param font the font key to set, or null to use the default
|
||||
* @return this ComponentStyleBuilder for chaining
|
||||
*/
|
||||
public ComponentStyleBuilder font(String font)
|
||||
{
|
||||
this.font = font;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the style's bold property.
|
||||
*
|
||||
* @param bold the bold value to set, or null to use the default
|
||||
* @return this ComponentStyleBuilder for chaining
|
||||
*/
|
||||
public ComponentStyleBuilder bold(Boolean bold)
|
||||
{
|
||||
this.bold = bold;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the style's italic property.
|
||||
*
|
||||
* @param italic the italic value to set, or null to use the default
|
||||
* @return this ComponentStyleBuilder for chaining
|
||||
*/
|
||||
public ComponentStyleBuilder italic(Boolean italic)
|
||||
{
|
||||
this.italic = italic;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the style's underlined property.
|
||||
*
|
||||
* @param underlined the underlined value to set, or null to use the default
|
||||
* @return this ComponentStyleBuilder for chaining
|
||||
*/
|
||||
public ComponentStyleBuilder underlined(Boolean underlined)
|
||||
{
|
||||
this.underlined = underlined;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the style's strikethrough property.
|
||||
*
|
||||
* @param strikethrough the strikethrough value to set, or null to use the
|
||||
* default
|
||||
* @return this ComponentStyleBuilder for chaining
|
||||
*/
|
||||
public ComponentStyleBuilder strikethrough(Boolean strikethrough)
|
||||
{
|
||||
this.strikethrough = strikethrough;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the style's obfuscated property.
|
||||
*
|
||||
* @param obfuscated the obfuscated value to set, or null to use the default
|
||||
* @return this ComponentStyleBuilder for chaining
|
||||
*/
|
||||
public ComponentStyleBuilder obfuscated(Boolean obfuscated)
|
||||
{
|
||||
this.obfuscated = obfuscated;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the {@link ComponentStyle} using the values set in this builder.
|
||||
*
|
||||
* @return the created ComponentStyle
|
||||
*/
|
||||
public ComponentStyle build()
|
||||
{
|
||||
return new ComponentStyle( color, shadowColor, font, bold, italic, underlined, strikethrough, obfuscated );
|
||||
}
|
||||
}
|
@@ -13,7 +13,7 @@ import net.md_5.bungee.api.chat.hover.content.Content;
|
||||
import net.md_5.bungee.api.chat.hover.content.Entity;
|
||||
import net.md_5.bungee.api.chat.hover.content.Item;
|
||||
import net.md_5.bungee.api.chat.hover.content.Text;
|
||||
import net.md_5.bungee.chat.ComponentSerializer;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
@Getter
|
||||
@ToString
|
||||
@@ -34,6 +34,7 @@ public final class HoverEvent
|
||||
* Returns whether this hover event is prior to 1.16
|
||||
*/
|
||||
@Setter
|
||||
@ApiStatus.Internal
|
||||
private boolean legacy = false;
|
||||
|
||||
/**
|
||||
@@ -71,22 +72,6 @@ public final class HoverEvent
|
||||
this.legacy = true;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public BaseComponent[] getValue()
|
||||
{
|
||||
Content content = contents.get( 0 );
|
||||
if ( content instanceof Text && ( (Text) content ).getValue() instanceof BaseComponent[] )
|
||||
{
|
||||
return (BaseComponent[]) ( (Text) content ).getValue();
|
||||
}
|
||||
|
||||
TextComponent component = new TextComponent( ComponentSerializer.toString( content ) );
|
||||
return new BaseComponent[]
|
||||
{
|
||||
component
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a content to this hover event.
|
||||
*
|
||||
|
@@ -43,7 +43,7 @@ public final class ItemTag
|
||||
private final int level;
|
||||
private final int id;
|
||||
}
|
||||
*/
|
||||
*/
|
||||
|
||||
private ItemTag(String nbt)
|
||||
{
|
||||
|
@@ -50,14 +50,14 @@ public final class KeybindComponent extends BaseComponent
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void toPlainText(StringBuilder builder)
|
||||
protected void toPlainText(StringVisitor builder)
|
||||
{
|
||||
builder.append( getKeybind() );
|
||||
super.toPlainText( builder );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void toLegacyText(StringBuilder builder)
|
||||
protected void toLegacyText(StringVisitor builder)
|
||||
{
|
||||
addFormat( builder );
|
||||
builder.append( getKeybind() );
|
||||
|
@@ -85,14 +85,14 @@ public final class ScoreComponent extends BaseComponent
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void toPlainText(StringBuilder builder)
|
||||
protected void toPlainText(StringVisitor builder)
|
||||
{
|
||||
builder.append( this.value );
|
||||
super.toPlainText( builder );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void toLegacyText(StringBuilder builder)
|
||||
protected void toLegacyText(StringVisitor builder)
|
||||
{
|
||||
addFormat( builder );
|
||||
builder.append( this.value );
|
||||
|
@@ -33,6 +33,13 @@ public final class SelectorComponent extends BaseComponent
|
||||
*/
|
||||
private String selector;
|
||||
|
||||
/**
|
||||
* The separator of multiple selected entities.
|
||||
* <br>
|
||||
* The default is {@code {"color": "gray", "text": ", "}}.
|
||||
*/
|
||||
private BaseComponent separator;
|
||||
|
||||
/**
|
||||
* Creates a selector component from the original to clone it.
|
||||
*
|
||||
@@ -42,6 +49,17 @@ public final class SelectorComponent extends BaseComponent
|
||||
{
|
||||
super( original );
|
||||
setSelector( original.getSelector() );
|
||||
setSeparator( original.getSeparator() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a selector component from the selector
|
||||
*
|
||||
* @param selector the selector as a String
|
||||
*/
|
||||
public SelectorComponent(String selector)
|
||||
{
|
||||
setSelector( selector );
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -51,14 +69,14 @@ public final class SelectorComponent extends BaseComponent
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void toPlainText(StringBuilder builder)
|
||||
protected void toPlainText(StringVisitor builder)
|
||||
{
|
||||
builder.append( this.selector );
|
||||
super.toPlainText( builder );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void toLegacyText(StringBuilder builder)
|
||||
protected void toLegacyText(StringVisitor builder)
|
||||
{
|
||||
addFormat( builder );
|
||||
builder.append( this.selector );
|
||||
|
@@ -2,6 +2,7 @@ package net.md_5.bungee.api.chat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import lombok.AllArgsConstructor;
|
||||
@@ -27,6 +28,41 @@ public final class TextComponent extends BaseComponent
|
||||
* @param message the text to convert
|
||||
* @return the components needed to print the message to the client
|
||||
*/
|
||||
public static BaseComponent fromLegacy(String message)
|
||||
{
|
||||
return fromLegacy( message, ChatColor.WHITE );
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the old formatting system that used
|
||||
* {@link net.md_5.bungee.api.ChatColor#COLOR_CHAR} into the new json based
|
||||
* system.
|
||||
*
|
||||
* @param message the text to convert
|
||||
* @param defaultColor color to use when no formatting is to be applied
|
||||
* (i.e. after ChatColor.RESET).
|
||||
* @return the components needed to print the message to the client
|
||||
*/
|
||||
public static BaseComponent fromLegacy(String message, ChatColor defaultColor)
|
||||
{
|
||||
ComponentBuilder componentBuilder = new ComponentBuilder();
|
||||
populateComponentStructure( message, defaultColor, componentBuilder::append );
|
||||
return componentBuilder.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the old formatting system that used
|
||||
* {@link net.md_5.bungee.api.ChatColor#COLOR_CHAR} into the new json based
|
||||
* system.
|
||||
*
|
||||
* @param message the text to convert
|
||||
* @return the components needed to print the message to the client
|
||||
* @deprecated {@link #fromLegacy(String)} is preferred as it will
|
||||
* consolidate all components into a single BaseComponent with extra
|
||||
* contents as opposed to an array of components which is non-standard and
|
||||
* may result in unexpected behavior.
|
||||
*/
|
||||
@Deprecated
|
||||
public static BaseComponent[] fromLegacyText(String message)
|
||||
{
|
||||
return fromLegacyText( message, ChatColor.WHITE );
|
||||
@@ -41,10 +77,21 @@ public final class TextComponent extends BaseComponent
|
||||
* @param defaultColor color to use when no formatting is to be applied
|
||||
* (i.e. after ChatColor.RESET).
|
||||
* @return the components needed to print the message to the client
|
||||
* @deprecated {@link #fromLegacy(String, ChatColor)} is preferred as it
|
||||
* will consolidate all components into a single BaseComponent with extra
|
||||
* contents as opposed to an array of components which is non-standard and
|
||||
* may result in unexpected behavior.
|
||||
*/
|
||||
@Deprecated
|
||||
public static BaseComponent[] fromLegacyText(String message, ChatColor defaultColor)
|
||||
{
|
||||
ArrayList<BaseComponent> components = new ArrayList<>();
|
||||
populateComponentStructure( message, defaultColor, components::add );
|
||||
return components.toArray( new BaseComponent[ 0 ] );
|
||||
}
|
||||
|
||||
private static void populateComponentStructure(String message, ChatColor defaultColor, Consumer<BaseComponent> appender)
|
||||
{
|
||||
StringBuilder builder = new StringBuilder();
|
||||
TextComponent component = new TextComponent();
|
||||
Matcher matcher = url.matcher( message );
|
||||
@@ -94,7 +141,7 @@ public final class TextComponent extends BaseComponent
|
||||
component = new TextComponent( old );
|
||||
old.setText( builder.toString() );
|
||||
builder = new StringBuilder();
|
||||
components.add( old );
|
||||
appender.accept( old );
|
||||
}
|
||||
if ( format == ChatColor.BOLD )
|
||||
{
|
||||
@@ -137,7 +184,7 @@ public final class TextComponent extends BaseComponent
|
||||
component = new TextComponent( old );
|
||||
old.setText( builder.toString() );
|
||||
builder = new StringBuilder();
|
||||
components.add( old );
|
||||
appender.accept( old );
|
||||
}
|
||||
|
||||
TextComponent old = component;
|
||||
@@ -146,7 +193,7 @@ public final class TextComponent extends BaseComponent
|
||||
component.setText( urlString );
|
||||
component.setClickEvent( new ClickEvent( ClickEvent.Action.OPEN_URL,
|
||||
urlString.startsWith( "http" ) ? urlString : "http://" + urlString ) );
|
||||
components.add( component );
|
||||
appender.accept( component );
|
||||
i += pos - i - 1;
|
||||
component = old;
|
||||
continue;
|
||||
@@ -155,9 +202,29 @@ public final class TextComponent extends BaseComponent
|
||||
}
|
||||
|
||||
component.setText( builder.toString() );
|
||||
components.add( component );
|
||||
appender.accept( component );
|
||||
}
|
||||
|
||||
return components.toArray( new BaseComponent[ 0 ] );
|
||||
/**
|
||||
* Internal compatibility method to transform an array of components to a
|
||||
* single component.
|
||||
*
|
||||
* @param components array
|
||||
* @return single component
|
||||
*/
|
||||
public static BaseComponent fromArray(BaseComponent... components)
|
||||
{
|
||||
if ( components == null )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if ( components.length == 1 )
|
||||
{
|
||||
return components[0];
|
||||
}
|
||||
|
||||
return new TextComponent( components );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -213,14 +280,14 @@ public final class TextComponent extends BaseComponent
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void toPlainText(StringBuilder builder)
|
||||
protected void toPlainText(StringVisitor builder)
|
||||
{
|
||||
builder.append( text );
|
||||
super.toPlainText( builder );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void toLegacyText(StringBuilder builder)
|
||||
protected void toLegacyText(StringVisitor builder)
|
||||
{
|
||||
addFormat( builder );
|
||||
builder.append( text );
|
||||
|
@@ -19,7 +19,7 @@ import net.md_5.bungee.chat.TranslationRegistry;
|
||||
public final class TranslatableComponent extends BaseComponent
|
||||
{
|
||||
|
||||
private final Pattern format = Pattern.compile( "%(?:(\\d+)\\$)?([A-Za-z%]|$)" );
|
||||
private static final Pattern FORMAT = Pattern.compile( "%(?:(\\d+)\\$)?([A-Za-z%]|$)" );
|
||||
|
||||
/**
|
||||
* The key into the Minecraft locale files to use for the translation. The
|
||||
@@ -44,10 +44,11 @@ public final class TranslatableComponent extends BaseComponent
|
||||
{
|
||||
super( original );
|
||||
setTranslate( original.getTranslate() );
|
||||
setFallback( original.getFallback() );
|
||||
|
||||
if ( original.getWith() != null )
|
||||
{
|
||||
List<BaseComponent> temp = new ArrayList<BaseComponent>();
|
||||
List<BaseComponent> temp = new ArrayList<>();
|
||||
for ( BaseComponent baseComponent : original.getWith() )
|
||||
{
|
||||
temp.add( baseComponent.duplicate() );
|
||||
@@ -86,6 +87,21 @@ public final class TranslatableComponent extends BaseComponent
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a translatable component with the passed substitutions
|
||||
*
|
||||
* @param translatable the translatable object
|
||||
* @param with the {@link java.lang.String}s and
|
||||
* {@link net.md_5.bungee.api.chat.BaseComponent}s to use into the
|
||||
* translation
|
||||
* @see #translate
|
||||
* @see #setWith(java.util.List)
|
||||
*/
|
||||
public TranslatableComponent(TranslationProvider translatable, Object... with)
|
||||
{
|
||||
this( translatable.getTranslationKey(), with );
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a duplicate of this TranslatableComponent.
|
||||
*
|
||||
@@ -140,20 +156,20 @@ public final class TranslatableComponent extends BaseComponent
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void toPlainText(StringBuilder builder)
|
||||
protected void toPlainText(StringVisitor builder)
|
||||
{
|
||||
convert( builder, false );
|
||||
super.toPlainText( builder );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void toLegacyText(StringBuilder builder)
|
||||
protected void toLegacyText(StringVisitor builder)
|
||||
{
|
||||
convert( builder, true );
|
||||
super.toLegacyText( builder );
|
||||
}
|
||||
|
||||
private void convert(StringBuilder builder, boolean applyFormat)
|
||||
private void convert(StringVisitor builder, boolean applyFormat)
|
||||
{
|
||||
String trans = TranslationRegistry.INSTANCE.translate( translate );
|
||||
|
||||
@@ -162,7 +178,7 @@ public final class TranslatableComponent extends BaseComponent
|
||||
trans = fallback;
|
||||
}
|
||||
|
||||
Matcher matcher = format.matcher( trans );
|
||||
Matcher matcher = FORMAT.matcher( trans );
|
||||
int position = 0;
|
||||
int i = 0;
|
||||
while ( matcher.find( position ) )
|
||||
|
@@ -0,0 +1,38 @@
|
||||
package net.md_5.bungee.api.chat;
|
||||
|
||||
/**
|
||||
* An object capable of being translated by the client in a
|
||||
* {@link TranslatableComponent}.
|
||||
*/
|
||||
public interface TranslationProvider
|
||||
{
|
||||
|
||||
/**
|
||||
* Get the translation key.
|
||||
*
|
||||
* @return the translation key
|
||||
*/
|
||||
String getTranslationKey();
|
||||
|
||||
/**
|
||||
* Get this translatable object as a {@link TranslatableComponent}.
|
||||
*
|
||||
* @return the translatable component
|
||||
*/
|
||||
default TranslatableComponent asTranslatableComponent()
|
||||
{
|
||||
return asTranslatableComponent( (Object[]) null );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this translatable object as a {@link TranslatableComponent}.
|
||||
*
|
||||
* @param with the {@link String Strings} and
|
||||
* {@link BaseComponent BaseComponents} to use in the translation
|
||||
* @return the translatable component
|
||||
*/
|
||||
default TranslatableComponent asTranslatableComponent(Object... with)
|
||||
{
|
||||
return new TranslatableComponent( this, with );
|
||||
}
|
||||
}
|
@@ -1,40 +0,0 @@
|
||||
package net.md_5.bungee.api.chat.hover.content;
|
||||
|
||||
import com.google.gson.JsonDeserializationContext;
|
||||
import com.google.gson.JsonDeserializer;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.JsonSerializationContext;
|
||||
import com.google.gson.JsonSerializer;
|
||||
import java.lang.reflect.Type;
|
||||
import net.md_5.bungee.api.chat.BaseComponent;
|
||||
|
||||
public class EntitySerializer implements JsonSerializer<Entity>, JsonDeserializer<Entity>
|
||||
{
|
||||
|
||||
@Override
|
||||
public Entity deserialize(JsonElement element, Type type, JsonDeserializationContext context) throws JsonParseException
|
||||
{
|
||||
JsonObject value = element.getAsJsonObject();
|
||||
|
||||
return new Entity(
|
||||
( value.has( "type" ) ) ? value.get( "type" ).getAsString() : null,
|
||||
value.get( "id" ).getAsString(),
|
||||
( value.has( "name" ) ) ? context.deserialize( value.get( "name" ), BaseComponent.class ) : null
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement serialize(Entity content, Type type, JsonSerializationContext context)
|
||||
{
|
||||
JsonObject object = new JsonObject();
|
||||
object.addProperty( "type", ( content.getType() != null ) ? content.getType() : "minecraft:pig" );
|
||||
object.addProperty( "id", content.getId() );
|
||||
if ( content.getName() != null )
|
||||
{
|
||||
object.add( "name", context.serialize( content.getName() ) );
|
||||
}
|
||||
return object;
|
||||
}
|
||||
}
|
@@ -26,7 +26,10 @@ public class Text extends Content
|
||||
public Text(BaseComponent value)
|
||||
{
|
||||
// For legacy serialization reasons, this has to be an array of components
|
||||
this( new BaseComponent[]{value} );
|
||||
this( new BaseComponent[]
|
||||
{
|
||||
value
|
||||
} );
|
||||
}
|
||||
|
||||
public Text(String value)
|
||||
|
@@ -1,208 +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.JsonParseException;
|
||||
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.ChatColor;
|
||||
import net.md_5.bungee.api.chat.BaseComponent;
|
||||
import net.md_5.bungee.api.chat.ClickEvent;
|
||||
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)
|
||||
{
|
||||
if ( object.has( "bold" ) )
|
||||
{
|
||||
component.setBold( object.get( "bold" ).getAsBoolean() );
|
||||
}
|
||||
if ( object.has( "italic" ) )
|
||||
{
|
||||
component.setItalic( object.get( "italic" ).getAsBoolean() );
|
||||
}
|
||||
if ( object.has( "underlined" ) )
|
||||
{
|
||||
component.setUnderlined( object.get( "underlined" ).getAsBoolean() );
|
||||
}
|
||||
if ( object.has( "strikethrough" ) )
|
||||
{
|
||||
component.setStrikethrough( object.get( "strikethrough" ).getAsBoolean() );
|
||||
}
|
||||
if ( object.has( "obfuscated" ) )
|
||||
{
|
||||
component.setObfuscated( object.get( "obfuscated" ).getAsBoolean() );
|
||||
}
|
||||
if ( object.has( "color" ) )
|
||||
{
|
||||
component.setColor( ChatColor.of( object.get( "color" ).getAsString() ) );
|
||||
}
|
||||
if ( object.has( "insertion" ) )
|
||||
{
|
||||
component.setInsertion( object.get( "insertion" ).getAsString() );
|
||||
}
|
||||
|
||||
//Events
|
||||
if ( object.has( "clickEvent" ) )
|
||||
{
|
||||
JsonObject event = object.getAsJsonObject( "clickEvent" );
|
||||
component.setClickEvent( new ClickEvent(
|
||||
ClickEvent.Action.valueOf( event.get( "action" ).getAsString().toUpperCase( Locale.ROOT ) ),
|
||||
( event.has( "value" ) ) ? event.get( "value" ).getAsString() : "" ) );
|
||||
}
|
||||
if ( object.has( "hoverEvent" ) )
|
||||
{
|
||||
JsonObject event = object.getAsJsonObject( "hoverEvent" );
|
||||
HoverEvent hoverEvent = null;
|
||||
HoverEvent.Action action = HoverEvent.Action.valueOf( event.get( "action" ).getAsString().toUpperCase( Locale.ROOT ) );
|
||||
|
||||
for ( String type : Arrays.asList( "value", "contents" ) )
|
||||
{
|
||||
if ( !event.has( type ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
JsonElement contents = event.get( type );
|
||||
try
|
||||
{
|
||||
|
||||
// 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 ( contents.isJsonArray() )
|
||||
{
|
||||
components = context.deserialize( contents, BaseComponent[].class );
|
||||
} else
|
||||
{
|
||||
components = new BaseComponent[]
|
||||
{
|
||||
context.deserialize( contents, BaseComponent.class )
|
||||
};
|
||||
}
|
||||
hoverEvent = new HoverEvent( action, components );
|
||||
} catch ( JsonParseException ex )
|
||||
{
|
||||
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 ) ) );
|
||||
}
|
||||
|
||||
// stop the loop as soon as either one is found
|
||||
break;
|
||||
}
|
||||
if ( hoverEvent != null )
|
||||
{
|
||||
component.setHoverEvent( hoverEvent );
|
||||
}
|
||||
}
|
||||
|
||||
if ( object.has( "font" ) )
|
||||
{
|
||||
component.setFont( object.get( "font" ).getAsString() );
|
||||
}
|
||||
if ( object.has( "extra" ) )
|
||||
{
|
||||
component.setExtra( Arrays.asList( context.<BaseComponent[]>deserialize( object.get( "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 );
|
||||
if ( component.isBoldRaw() != null )
|
||||
{
|
||||
object.addProperty( "bold", component.isBoldRaw() );
|
||||
}
|
||||
if ( component.isItalicRaw() != null )
|
||||
{
|
||||
object.addProperty( "italic", component.isItalicRaw() );
|
||||
}
|
||||
if ( component.isUnderlinedRaw() != null )
|
||||
{
|
||||
object.addProperty( "underlined", component.isUnderlinedRaw() );
|
||||
}
|
||||
if ( component.isStrikethroughRaw() != null )
|
||||
{
|
||||
object.addProperty( "strikethrough", component.isStrikethroughRaw() );
|
||||
}
|
||||
if ( component.isObfuscatedRaw() != null )
|
||||
{
|
||||
object.addProperty( "obfuscated", component.isObfuscatedRaw() );
|
||||
}
|
||||
if ( component.getColorRaw() != null )
|
||||
{
|
||||
object.addProperty( "color", component.getColorRaw().getName() );
|
||||
}
|
||||
if ( component.getInsertion() != null )
|
||||
{
|
||||
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.getFontRaw() != null )
|
||||
{
|
||||
object.addProperty( "font", component.getFontRaw() );
|
||||
}
|
||||
if ( component.getExtra() != null )
|
||||
{
|
||||
object.add( "extra", context.serialize( component.getExtra() ) );
|
||||
}
|
||||
} finally
|
||||
{
|
||||
ComponentSerializer.serializedComponents.get().remove( component );
|
||||
if ( first )
|
||||
{
|
||||
ComponentSerializer.serializedComponents.set( null );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,144 +0,0 @@
|
||||
package net.md_5.bungee.chat;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonDeserializationContext;
|
||||
import com.google.gson.JsonDeserializer;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.JsonParser;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Set;
|
||||
import net.md_5.bungee.api.chat.BaseComponent;
|
||||
import net.md_5.bungee.api.chat.ItemTag;
|
||||
import net.md_5.bungee.api.chat.KeybindComponent;
|
||||
import net.md_5.bungee.api.chat.ScoreComponent;
|
||||
import net.md_5.bungee.api.chat.SelectorComponent;
|
||||
import net.md_5.bungee.api.chat.TextComponent;
|
||||
import net.md_5.bungee.api.chat.TranslatableComponent;
|
||||
import net.md_5.bungee.api.chat.hover.content.Entity;
|
||||
import net.md_5.bungee.api.chat.hover.content.EntitySerializer;
|
||||
import net.md_5.bungee.api.chat.hover.content.Item;
|
||||
import net.md_5.bungee.api.chat.hover.content.ItemSerializer;
|
||||
import net.md_5.bungee.api.chat.hover.content.Text;
|
||||
import net.md_5.bungee.api.chat.hover.content.TextSerializer;
|
||||
|
||||
public class ComponentSerializer implements JsonDeserializer<BaseComponent>
|
||||
{
|
||||
|
||||
private static final Gson gson = new GsonBuilder().
|
||||
registerTypeAdapter( BaseComponent.class, new ComponentSerializer() ).
|
||||
registerTypeAdapter( TextComponent.class, new TextComponentSerializer() ).
|
||||
registerTypeAdapter( TranslatableComponent.class, new TranslatableComponentSerializer() ).
|
||||
registerTypeAdapter( KeybindComponent.class, new KeybindComponentSerializer() ).
|
||||
registerTypeAdapter( ScoreComponent.class, new ScoreComponentSerializer() ).
|
||||
registerTypeAdapter( SelectorComponent.class, new SelectorComponentSerializer() ).
|
||||
registerTypeAdapter( Entity.class, new EntitySerializer() ).
|
||||
registerTypeAdapter( Text.class, new TextSerializer() ).
|
||||
registerTypeAdapter( Item.class, new ItemSerializer() ).
|
||||
registerTypeAdapter( ItemTag.class, new ItemTag.Serializer() ).
|
||||
create();
|
||||
|
||||
public static final ThreadLocal<Set<BaseComponent>> serializedComponents = new ThreadLocal<Set<BaseComponent>>();
|
||||
|
||||
/**
|
||||
* Parse a JSON-compliant String as an array of base components. The input
|
||||
* can be one of either an array of components, or a single component object.
|
||||
* If the input is an array, each component will be parsed individually and
|
||||
* returned in the order that they were parsed. If the input is a single
|
||||
* component object, a single-valued array with the component will be returned.
|
||||
* <p>
|
||||
* <strong>NOTE:</strong> {@link #deserialize(String)} is preferred as it will
|
||||
* parse only one component as opposed to an array of components which is non-
|
||||
* standard behavior. This method is still appropriate for parsing multiple
|
||||
* components at once, although such use case is rarely (if at all) exhibited
|
||||
* in vanilla Minecraft.
|
||||
*
|
||||
* @param json the component json to parse
|
||||
* @return an array of all parsed components
|
||||
*/
|
||||
public static BaseComponent[] parse(String json)
|
||||
{
|
||||
JsonElement jsonElement = JsonParser.parseString( json );
|
||||
|
||||
if ( jsonElement.isJsonArray() )
|
||||
{
|
||||
return gson.fromJson( jsonElement, BaseComponent[].class );
|
||||
} else
|
||||
{
|
||||
return new BaseComponent[]
|
||||
{
|
||||
gson.fromJson( jsonElement, BaseComponent.class )
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserialize a JSON-compliant String as a single component. The input is
|
||||
* expected to be a JSON object that represents only one component.
|
||||
*
|
||||
* @param json the component json to parse
|
||||
* @return the deserialized component
|
||||
* @throws IllegalArgumentException if anything other than a JSON object is
|
||||
* passed as input
|
||||
*/
|
||||
public static BaseComponent deserialize(String json)
|
||||
{
|
||||
JsonElement jsonElement = JsonParser.parseString( json );
|
||||
if ( !jsonElement.isJsonObject() )
|
||||
{
|
||||
throw new IllegalArgumentException( "Malformatted JSON. Expected object, got array for input \"" + json + "\"." );
|
||||
}
|
||||
|
||||
return gson.fromJson( jsonElement, BaseComponent.class );
|
||||
}
|
||||
|
||||
public static String toString(Object object)
|
||||
{
|
||||
return gson.toJson( object );
|
||||
}
|
||||
|
||||
public static String toString(BaseComponent component)
|
||||
{
|
||||
return gson.toJson( component );
|
||||
}
|
||||
|
||||
public static String toString(BaseComponent... components)
|
||||
{
|
||||
if ( components.length == 1 )
|
||||
{
|
||||
return gson.toJson( components[0] );
|
||||
} else
|
||||
{
|
||||
return gson.toJson( new TextComponent( components ) );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseComponent deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException
|
||||
{
|
||||
if ( json.isJsonPrimitive() )
|
||||
{
|
||||
return new TextComponent( json.getAsString() );
|
||||
}
|
||||
JsonObject object = json.getAsJsonObject();
|
||||
if ( object.has( "translate" ) )
|
||||
{
|
||||
return context.deserialize( json, TranslatableComponent.class );
|
||||
}
|
||||
if ( object.has( "keybind" ) )
|
||||
{
|
||||
return context.deserialize( json, KeybindComponent.class );
|
||||
}
|
||||
if ( object.has( "score" ) )
|
||||
{
|
||||
return context.deserialize( json, ScoreComponent.class );
|
||||
}
|
||||
if ( object.has( "selector" ) )
|
||||
{
|
||||
return context.deserialize( json, SelectorComponent.class );
|
||||
}
|
||||
return context.deserialize( json, TextComponent.class );
|
||||
}
|
||||
}
|
@@ -1,11 +1,11 @@
|
||||
package net.md_5.bungee.chat;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
@@ -102,7 +102,7 @@ public final class TranslationRegistry
|
||||
|
||||
public JsonProvider(String resourcePath) throws IOException
|
||||
{
|
||||
try ( InputStreamReader rd = new InputStreamReader( JsonProvider.class.getResourceAsStream( resourcePath ), Charsets.UTF_8 ) )
|
||||
try ( InputStreamReader rd = new InputStreamReader( JsonProvider.class.getResourceAsStream( resourcePath ), StandardCharsets.UTF_8 ) )
|
||||
{
|
||||
JsonObject obj = new Gson().fromJson( rd, JsonObject.class );
|
||||
for ( Map.Entry<String, JsonElement> entries : obj.entrySet() )
|
||||
|
@@ -1,28 +0,0 @@
|
||||
package net.md_5.bungee.api.chat;
|
||||
|
||||
import net.md_5.bungee.chat.ComponentSerializer;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class TranslatableComponentTest
|
||||
{
|
||||
|
||||
@Test
|
||||
public void testMissingPlaceholdersAdded()
|
||||
{
|
||||
TranslatableComponent testComponent = new TranslatableComponent( "Test string with %s placeholders: %s", 2, "aoeu" );
|
||||
Assert.assertEquals( "Test string with 2 placeholders: aoeu", testComponent.toPlainText() );
|
||||
Assert.assertEquals( "§fTest string with §f2§f placeholders: §faoeu", testComponent.toLegacyText() );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJsonSerialisation()
|
||||
{
|
||||
TranslatableComponent testComponent = new TranslatableComponent( "Test string with %s placeholder", "a" );
|
||||
String jsonString = ComponentSerializer.toString( testComponent );
|
||||
BaseComponent[] baseComponents = ComponentSerializer.parse( jsonString );
|
||||
|
||||
Assert.assertEquals( "Test string with a placeholder", TextComponent.toPlainText( baseComponents ) );
|
||||
Assert.assertEquals( "§fTest string with §fa§f placeholder", TextComponent.toLegacyText( baseComponents ) );
|
||||
}
|
||||
}
|
@@ -36,7 +36,6 @@
|
||||
<module name="SuppressWarningsHolder"/>
|
||||
|
||||
<!-- See http://checkstyle.sourceforge.net/config_imports.html -->
|
||||
<module name="AvoidStarImport"/>
|
||||
<module name="ImportOrder">
|
||||
<property name="option" value="above"/>
|
||||
<property name="ordered" value="true"/>
|
||||
|
@@ -4,15 +4,14 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>net.md-5</groupId>
|
||||
<groupId>fr.pandacube.bungeecord</groupId>
|
||||
<artifactId>bungeecord-parent</artifactId>
|
||||
<version>1.20-R0.2-SNAPSHOT</version>
|
||||
<version>1.21-R0.4-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-config</artifactId>
|
||||
<version>1.20-R0.2-SNAPSHOT</version>
|
||||
<version>1.21-R0.4-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>BungeeCord-Config</name>
|
||||
@@ -22,7 +21,7 @@
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
<version>2.10.1</version>
|
||||
<version>2.11.0</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
@@ -1,6 +1,5 @@
|
||||
package net.md_5.bungee.config;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonElement;
|
||||
@@ -16,6 +15,7 @@ import java.io.OutputStreamWriter;
|
||||
import java.io.Reader;
|
||||
import java.io.Writer;
|
||||
import java.lang.reflect.Type;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import lombok.AccessLevel;
|
||||
@@ -37,7 +37,7 @@ public class JsonConfiguration extends ConfigurationProvider
|
||||
@Override
|
||||
public void save(Configuration config, File file) throws IOException
|
||||
{
|
||||
try ( Writer writer = new OutputStreamWriter( new FileOutputStream( file ), Charsets.UTF_8 ) )
|
||||
try ( Writer writer = new OutputStreamWriter( new FileOutputStream( file ), StandardCharsets.UTF_8 ) )
|
||||
{
|
||||
save( config, writer );
|
||||
}
|
||||
@@ -91,7 +91,7 @@ public class JsonConfiguration extends ConfigurationProvider
|
||||
@Override
|
||||
public Configuration load(InputStream is, Configuration defaults)
|
||||
{
|
||||
return load( new InputStreamReader( is, Charsets.UTF_8 ), defaults );
|
||||
return load( new InputStreamReader( is, StandardCharsets.UTF_8 ), defaults );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -1,6 +1,5 @@
|
||||
package net.md_5.bungee.config;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
@@ -9,6 +8,7 @@ import java.io.InputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.Reader;
|
||||
import java.io.Writer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import lombok.AccessLevel;
|
||||
@@ -54,7 +54,7 @@ public class YamlConfiguration extends ConfigurationProvider
|
||||
@Override
|
||||
public void save(Configuration config, File file) throws IOException
|
||||
{
|
||||
try ( Writer writer = new OutputStreamWriter( new FileOutputStream( file ), Charsets.UTF_8 ) )
|
||||
try ( Writer writer = new OutputStreamWriter( new FileOutputStream( file ), StandardCharsets.UTF_8 ) )
|
||||
{
|
||||
save( config, writer );
|
||||
}
|
||||
|
@@ -1,148 +1,138 @@
|
||||
package net.md_5.bungee.config;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import java.io.StringReader;
|
||||
import java.io.StringWriter;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Stream;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.junit.runners.Parameterized.Parameters;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@RunWith(Parameterized.class)
|
||||
public class CompoundConfigurationTest
|
||||
{
|
||||
|
||||
@Parameters(name = "{0}")
|
||||
public static Iterable<Object[]> data()
|
||||
public static Stream<Arguments> data()
|
||||
{
|
||||
// CHECKSTYLE:OFF
|
||||
return Arrays.asList( new Object[][]
|
||||
{
|
||||
{
|
||||
// provider
|
||||
YamlConfiguration.class,
|
||||
// testDocument
|
||||
""
|
||||
+ "receipt: Oz-Ware Purchase Invoice\n"
|
||||
+ "date: 2012-08-06\n"
|
||||
+ "customer:\n"
|
||||
+ " given: Dorothy\n"
|
||||
+ " family: Gale\n"
|
||||
+ "\n"
|
||||
+ "items:\n"
|
||||
+ " - part_no: A4786\n"
|
||||
+ " descrip: Water Bucket (Filled)\n"
|
||||
+ " price: 1.47\n"
|
||||
+ " quantity: 4\n"
|
||||
+ "\n"
|
||||
+ " - part_no: E1628\n"
|
||||
+ " descrip: High Heeled \"Ruby\" Slippers\n"
|
||||
+ " size: 8\n"
|
||||
+ " price: 100.27\n"
|
||||
+ " quantity: 1\n"
|
||||
+ "\n"
|
||||
+ "bill-to: &id001\n"
|
||||
+ " street: |\n"
|
||||
+ " 123 Tornado Alley\n"
|
||||
+ " Suite 16\n"
|
||||
+ " city: East Centerville\n"
|
||||
+ " state: KS\n"
|
||||
+ "\n"
|
||||
+ "ship-to: *id001\n"
|
||||
+ "\n"
|
||||
+ "specialDelivery: >\n"
|
||||
+ " Follow the Yellow Brick\n"
|
||||
+ " Road to the Emerald City.\n"
|
||||
+ " Pay no attention to the\n"
|
||||
+ " man behind the curtain.",
|
||||
// numberTest
|
||||
""
|
||||
+ "someKey:\n"
|
||||
+ " 1: 1\n"
|
||||
+ " 2: 2\n"
|
||||
+ " 3: 3\n"
|
||||
+ " 4: 4",
|
||||
// nullTest
|
||||
""
|
||||
+ "null:\n"
|
||||
+ " null: object\n"
|
||||
+ " object: null\n"
|
||||
},
|
||||
{
|
||||
// provider
|
||||
JsonConfiguration.class,
|
||||
// testDocument
|
||||
""
|
||||
+ "{\n"
|
||||
+ " \"customer\": {\n"
|
||||
+ " \"given\": \"Dorothy\", \n"
|
||||
+ " \"family\": \"Gale\"\n"
|
||||
+ " }, \n"
|
||||
+ " \"ship-to\": {\n"
|
||||
+ " \"city\": \"East Centerville\", \n"
|
||||
+ " \"state\": \"KS\", \n"
|
||||
+ " \"street\": \"123 Tornado Alley\\nSuite 16\\n\"\n"
|
||||
+ " }, \n"
|
||||
+ " \"bill-to\": {\n"
|
||||
+ " \"city\": \"East Centerville\", \n"
|
||||
+ " \"state\": \"KS\", \n"
|
||||
+ " \"street\": \"123 Tornado Alley\\nSuite 16\\n\"\n"
|
||||
+ " }, \n"
|
||||
+ " \"date\": \"2012-08-06\", \n"
|
||||
+ " \"items\": [\n"
|
||||
+ " {\n"
|
||||
+ " \"part_no\": \"A4786\", \n"
|
||||
+ " \"price\": 1.47, \n"
|
||||
+ " \"descrip\": \"Water Bucket (Filled)\", \n"
|
||||
+ " \"quantity\": 4\n"
|
||||
+ " }, \n"
|
||||
+ " {\n"
|
||||
+ " \"part_no\": \"E1628\", \n"
|
||||
+ " \"descrip\": \"High Heeled \\\"Ruby\\\" Slippers\", \n"
|
||||
+ " \"price\": 100.27, \n"
|
||||
+ " \"quantity\": 1, \n"
|
||||
+ " \"size\": 8\n"
|
||||
+ " }\n"
|
||||
+ " ], \n"
|
||||
+ " \"receipt\": \"Oz-Ware Purchase Invoice\", \n"
|
||||
+ " \"specialDelivery\": \"Follow the Yellow Brick Road to the Emerald City. Pay no attention to the man behind the curtain.\"\n"
|
||||
+ "}",
|
||||
// numberTest
|
||||
""
|
||||
+ "{\n"
|
||||
+ " \"someKey\": {\n"
|
||||
+ " \"1\": 1, \n"
|
||||
+ " \"2\": 2, \n"
|
||||
+ " \"3\": 3, \n"
|
||||
+ " \"4\": 4\n"
|
||||
+ " }\n"
|
||||
+ "}",
|
||||
// nullTest
|
||||
""
|
||||
+ "{\n"
|
||||
+ " \"null\": {\n"
|
||||
+ " \"null\": \"object\", \n"
|
||||
+ " \"object\": null\n"
|
||||
+ " }\n"
|
||||
+ "}"
|
||||
}
|
||||
} );
|
||||
// CHECKSTYLE:ON
|
||||
return Stream.of(
|
||||
Arguments.of(
|
||||
// provider
|
||||
YamlConfiguration.class,
|
||||
// testDocument
|
||||
""
|
||||
+ "receipt: Oz-Ware Purchase Invoice\n"
|
||||
+ "date: 2012-08-06\n"
|
||||
+ "customer:\n"
|
||||
+ " given: Dorothy\n"
|
||||
+ " family: Gale\n"
|
||||
+ "\n"
|
||||
+ "items:\n"
|
||||
+ " - part_no: A4786\n"
|
||||
+ " descrip: Water Bucket (Filled)\n"
|
||||
+ " price: 1.47\n"
|
||||
+ " quantity: 4\n"
|
||||
+ "\n"
|
||||
+ " - part_no: E1628\n"
|
||||
+ " descrip: High Heeled \"Ruby\" Slippers\n"
|
||||
+ " size: 8\n"
|
||||
+ " price: 100.27\n"
|
||||
+ " quantity: 1\n"
|
||||
+ "\n"
|
||||
+ "bill-to: &id001\n"
|
||||
+ " street: |\n"
|
||||
+ " 123 Tornado Alley\n"
|
||||
+ " Suite 16\n"
|
||||
+ " city: East Centerville\n"
|
||||
+ " state: KS\n"
|
||||
+ "\n"
|
||||
+ "ship-to: *id001\n"
|
||||
+ "\n"
|
||||
+ "specialDelivery: >\n"
|
||||
+ " Follow the Yellow Brick\n"
|
||||
+ " Road to the Emerald City.\n"
|
||||
+ " Pay no attention to the\n"
|
||||
+ " man behind the curtain.",
|
||||
// numberTest
|
||||
""
|
||||
+ "someKey:\n"
|
||||
+ " 1: 1\n"
|
||||
+ " 2: 2\n"
|
||||
+ " 3: 3\n"
|
||||
+ " 4: 4",
|
||||
// nullTest
|
||||
""
|
||||
+ "null:\n"
|
||||
+ " null: object\n"
|
||||
+ " object: null\n"
|
||||
),
|
||||
Arguments.of(
|
||||
// provider
|
||||
JsonConfiguration.class,
|
||||
// testDocument
|
||||
""
|
||||
+ "{\n"
|
||||
+ " \"customer\": {\n"
|
||||
+ " \"given\": \"Dorothy\", \n"
|
||||
+ " \"family\": \"Gale\"\n"
|
||||
+ " }, \n"
|
||||
+ " \"ship-to\": {\n"
|
||||
+ " \"city\": \"East Centerville\", \n"
|
||||
+ " \"state\": \"KS\", \n"
|
||||
+ " \"street\": \"123 Tornado Alley\\nSuite 16\\n\"\n"
|
||||
+ " }, \n"
|
||||
+ " \"bill-to\": {\n"
|
||||
+ " \"city\": \"East Centerville\", \n"
|
||||
+ " \"state\": \"KS\", \n"
|
||||
+ " \"street\": \"123 Tornado Alley\\nSuite 16\\n\"\n"
|
||||
+ " }, \n"
|
||||
+ " \"date\": \"2012-08-06\", \n"
|
||||
+ " \"items\": [\n"
|
||||
+ " {\n"
|
||||
+ " \"part_no\": \"A4786\", \n"
|
||||
+ " \"price\": 1.47, \n"
|
||||
+ " \"descrip\": \"Water Bucket (Filled)\", \n"
|
||||
+ " \"quantity\": 4\n"
|
||||
+ " }, \n"
|
||||
+ " {\n"
|
||||
+ " \"part_no\": \"E1628\", \n"
|
||||
+ " \"descrip\": \"High Heeled \\\"Ruby\\\" Slippers\", \n"
|
||||
+ " \"price\": 100.27, \n"
|
||||
+ " \"quantity\": 1, \n"
|
||||
+ " \"size\": 8\n"
|
||||
+ " }\n"
|
||||
+ " ], \n"
|
||||
+ " \"receipt\": \"Oz-Ware Purchase Invoice\", \n"
|
||||
+ " \"specialDelivery\": \"Follow the Yellow Brick Road to the Emerald City. Pay no attention to the man behind the curtain.\"\n"
|
||||
+ "}",
|
||||
// numberTest
|
||||
""
|
||||
+ "{\n"
|
||||
+ " \"someKey\": {\n"
|
||||
+ " \"1\": 1, \n"
|
||||
+ " \"2\": 2, \n"
|
||||
+ " \"3\": 3, \n"
|
||||
+ " \"4\": 4\n"
|
||||
+ " }\n"
|
||||
+ "}",
|
||||
// nullTest
|
||||
""
|
||||
+ "{\n"
|
||||
+ " \"null\": {\n"
|
||||
+ " \"null\": \"object\", \n"
|
||||
+ " \"object\": null\n"
|
||||
+ " }\n"
|
||||
+ "}"
|
||||
)
|
||||
);
|
||||
}
|
||||
//
|
||||
private final Class<? extends ConfigurationProvider> provider;
|
||||
private final String testDocument;
|
||||
private final String numberTest;
|
||||
private final String nullTest;
|
||||
|
||||
@Test
|
||||
public void testConfig() throws Exception
|
||||
@ParameterizedTest
|
||||
@MethodSource("data")
|
||||
public void testConfig(Class<? extends ConfigurationProvider> provider, String testDocument, String numberTest, String nullTest) throws Exception
|
||||
{
|
||||
Configuration conf = ConfigurationProvider.getProvider( provider ).load( testDocument );
|
||||
testSection( conf );
|
||||
@@ -151,7 +141,7 @@ public class CompoundConfigurationTest
|
||||
ConfigurationProvider.getProvider( provider ).save( conf, sw );
|
||||
|
||||
// Check nulls were saved, see #1094
|
||||
Assert.assertFalse( "Config contains null", sw.toString().contains( "null" ) );
|
||||
assertFalse( sw.toString().contains( "null" ), "Config contains null" );
|
||||
|
||||
conf = ConfigurationProvider.getProvider( provider ).load( new StringReader( sw.toString() ) );
|
||||
conf.set( "receipt", "Oz-Ware Purchase Invoice" ); // Add it back
|
||||
@@ -160,37 +150,38 @@ public class CompoundConfigurationTest
|
||||
|
||||
private void testSection(Configuration conf)
|
||||
{
|
||||
Assert.assertEquals( "receipt", "Oz-Ware Purchase Invoice", conf.getString( "receipt" ) );
|
||||
// Assert.assertEquals( "date", "2012-08-06", conf.get( "date" ).toString() );
|
||||
assertEquals( "Oz-Ware Purchase Invoice", conf.getString( "receipt" ), "receipt" );
|
||||
// assertEquals( "2012-08-06", conf.get( "date" ).toString(), "date" );
|
||||
|
||||
Configuration customer = conf.getSection( "customer" );
|
||||
Assert.assertEquals( "customer.given", "Dorothy", customer.getString( "given" ) );
|
||||
Assert.assertEquals( "customer.given", "Dorothy", conf.getString( "customer.given" ) );
|
||||
assertEquals( "Dorothy", customer.getString( "given" ), "customer.given" );
|
||||
assertEquals( "Dorothy", conf.getString( "customer.given" ), "customer.given" );
|
||||
|
||||
List items = conf.getList( "items" );
|
||||
Map item = (Map) items.get( 0 );
|
||||
Assert.assertEquals( "items[0].part_no", "A4786", item.get( "part_no" ) );
|
||||
assertEquals( "A4786", item.get( "part_no" ), "items[0].part_no" );
|
||||
|
||||
conf.set( "receipt", null );
|
||||
Assert.assertEquals( null, conf.get( "receipt" ) );
|
||||
Assert.assertEquals( "foo", conf.get( "receipt", "foo" ) );
|
||||
assertEquals( null, conf.get( "receipt" ) );
|
||||
assertEquals( "foo", conf.get( "receipt", "foo" ) );
|
||||
|
||||
Configuration newSection = conf.getSection( "new.section" );
|
||||
newSection.set( "value", "foo" );
|
||||
Assert.assertEquals( "foo", conf.get( "new.section.value" ) );
|
||||
assertEquals( "foo", conf.get( "new.section.value" ) );
|
||||
|
||||
conf.set( "other.new.section", "bar" );
|
||||
Assert.assertEquals( "bar", conf.get( "other.new.section" ) );
|
||||
assertEquals( "bar", conf.get( "other.new.section" ) );
|
||||
|
||||
Assert.assertTrue( conf.contains( "customer.given" ) );
|
||||
Assert.assertTrue( customer.contains( "given" ) );
|
||||
assertTrue( conf.contains( "customer.given" ) );
|
||||
assertTrue( customer.contains( "given" ) );
|
||||
|
||||
Assert.assertFalse( conf.contains( "customer.foo" ) );
|
||||
Assert.assertFalse( customer.contains( "foo" ) );
|
||||
assertFalse( conf.contains( "customer.foo" ) );
|
||||
assertFalse( customer.contains( "foo" ) );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNumberedKeys()
|
||||
@ParameterizedTest
|
||||
@MethodSource("data")
|
||||
public void testNumberedKeys(Class<? extends ConfigurationProvider> provider, String testDocument, String numberTest, String nullTest)
|
||||
{
|
||||
Configuration conf = ConfigurationProvider.getProvider( provider ).load( numberTest );
|
||||
|
||||
@@ -201,29 +192,31 @@ public class CompoundConfigurationTest
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNull()
|
||||
@ParameterizedTest
|
||||
@MethodSource("data")
|
||||
public void testNull(Class<? extends ConfigurationProvider> provider, String testDocument, String numberTest, String nullTest)
|
||||
{
|
||||
Configuration conf = ConfigurationProvider.getProvider( provider ).load( nullTest );
|
||||
|
||||
Assert.assertEquals( "object", conf.get( "null.null" ) );
|
||||
Assert.assertEquals( "object", conf.getSection( "null" ).get( "null" ) );
|
||||
assertEquals( "object", conf.get( "null.null" ) );
|
||||
assertEquals( "object", conf.getSection( "null" ).get( "null" ) );
|
||||
|
||||
Assert.assertEquals( null, conf.get( "null.object" ) );
|
||||
Assert.assertEquals( "", conf.getString( "null.object" ) );
|
||||
assertEquals( null, conf.get( "null.object" ) );
|
||||
assertEquals( "", conf.getString( "null.object" ) );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapAddition()
|
||||
@ParameterizedTest
|
||||
@MethodSource("data")
|
||||
public void testMapAddition(Class<? extends ConfigurationProvider> provider, String testDocument, String numberTest, String nullTest)
|
||||
{
|
||||
Configuration conf = ConfigurationProvider.getProvider( provider ).load( testDocument );
|
||||
|
||||
conf.set( "addition", Collections.singletonMap( "foo", "bar" ) );
|
||||
|
||||
// Order matters
|
||||
Assert.assertEquals( "bar", conf.getSection( "addition" ).getString( "foo" ) );
|
||||
Assert.assertEquals( "bar", conf.getString( "addition.foo" ) );
|
||||
assertEquals( "bar", conf.getSection( "addition" ).getString( "foo" ) );
|
||||
assertEquals( "bar", conf.getString( "addition.foo" ) );
|
||||
|
||||
Assert.assertTrue( conf.get( "addition" ) instanceof Configuration );
|
||||
assertTrue( conf.get( "addition" ) instanceof Configuration );
|
||||
}
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
package net.md_5.bungee.config;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class DefaultConfigurationTest
|
||||
{
|
||||
@@ -16,8 +16,8 @@ public class DefaultConfigurationTest
|
||||
|
||||
Configuration actualConfig = new Configuration( defaultConfig );
|
||||
|
||||
Assert.assertEquals( 10, actualConfig.getInt( "setting" ) );
|
||||
Assert.assertEquals( 11, actualConfig.getInt( "nested.setting" ) );
|
||||
Assert.assertEquals( 12, actualConfig.getInt( "double.nested.setting" ) );
|
||||
assertEquals( 10, actualConfig.getInt( "setting" ) );
|
||||
assertEquals( 11, actualConfig.getInt( "nested.setting" ) );
|
||||
assertEquals( 12, actualConfig.getInt( "double.nested.setting" ) );
|
||||
}
|
||||
}
|
||||
|
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.4-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>bungeecord-dialog</artifactId>
|
||||
<version>1.21-R0.4-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,73 @@
|
||||
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,71 @@
|
||||
package net.md_5.bungee.api.dialog;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NonNull;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Accessors;
|
||||
import net.md_5.bungee.api.dialog.action.ActionButton;
|
||||
|
||||
/**
|
||||
* Represents a dialog which shows the links configured/sent from the server.
|
||||
*/
|
||||
@Data
|
||||
@ToString
|
||||
@EqualsAndHashCode
|
||||
@Accessors(fluent = true)
|
||||
public final class ServerLinksDialog implements Dialog
|
||||
{
|
||||
|
||||
@NonNull
|
||||
@Accessors(fluent = false)
|
||||
private DialogBase base;
|
||||
/**
|
||||
* The optional {@link ActionButton} for this dialog.
|
||||
*/
|
||||
@SerializedName("action")
|
||||
private ActionButton action;
|
||||
/**
|
||||
* The {@link ActionButton} activated when the dialog is exited.
|
||||
*/
|
||||
@SerializedName("exit_action")
|
||||
private ActionButton exitAction;
|
||||
/**
|
||||
* The number of columns for the dialog buttons (default: 2).
|
||||
*/
|
||||
private Integer columns;
|
||||
/**
|
||||
* The width of the dialog buttons (default: 150, minimum: 1, maximum: 1024).
|
||||
*/
|
||||
@SerializedName("button_width")
|
||||
private Integer buttonWidth;
|
||||
|
||||
public ServerLinksDialog(@NonNull DialogBase base)
|
||||
{
|
||||
this( base, null, null, null );
|
||||
}
|
||||
|
||||
public ServerLinksDialog(@NonNull DialogBase base, ActionButton action, Integer columns, Integer buttonWidth)
|
||||
{
|
||||
this.base = base;
|
||||
this.action = action;
|
||||
columns( columns );
|
||||
buttonWidth( buttonWidth );
|
||||
}
|
||||
|
||||
public ServerLinksDialog columns(Integer columns)
|
||||
{
|
||||
Preconditions.checkArgument( columns == null || columns > 0, "At least one column is required" );
|
||||
this.columns = columns;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ServerLinksDialog buttonWidth(Integer buttonWidth)
|
||||
{
|
||||
Preconditions.checkArgument( buttonWidth == null || ( buttonWidth >= 1 && buttonWidth <= 1024 ), "buttonWidth must be between 1 and 1024" );
|
||||
this.buttonWidth = buttonWidth;
|
||||
return this;
|
||||
}
|
||||
}
|
@@ -0,0 +1,6 @@
|
||||
package net.md_5.bungee.api.dialog.action;
|
||||
|
||||
public interface Action
|
||||
{
|
||||
|
||||
}
|
@@ -0,0 +1,54 @@
|
||||
package net.md_5.bungee.api.dialog.action;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import lombok.Data;
|
||||
import lombok.NonNull;
|
||||
import lombok.experimental.Accessors;
|
||||
import net.md_5.bungee.api.chat.BaseComponent;
|
||||
|
||||
/**
|
||||
* Represents a dialog action which will usually appear as a button.
|
||||
*/
|
||||
@Data
|
||||
@Accessors(fluent = true)
|
||||
public class ActionButton
|
||||
{
|
||||
|
||||
/**
|
||||
* The text label of the button, mandatory.
|
||||
*/
|
||||
@NonNull
|
||||
private BaseComponent label;
|
||||
/**
|
||||
* The hover tooltip of the button.
|
||||
*/
|
||||
private BaseComponent tooltip;
|
||||
/**
|
||||
* The width of the button (default: 150, minimum: 1, maximum: 1024).
|
||||
*/
|
||||
private Integer width;
|
||||
/**
|
||||
* The action to take.
|
||||
*/
|
||||
@NonNull
|
||||
private Action action;
|
||||
|
||||
public ActionButton(@NonNull BaseComponent label, BaseComponent tooltip, Integer width, @NonNull Action action)
|
||||
{
|
||||
this.label = label;
|
||||
this.tooltip = tooltip;
|
||||
setWidth( width );
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
public ActionButton(@NonNull BaseComponent label, @NonNull Action action)
|
||||
{
|
||||
this( label, null, null, action );
|
||||
}
|
||||
|
||||
public void setWidth(Integer width)
|
||||
{
|
||||
Preconditions.checkArgument( width == null || ( width >= 1 && width <= 1024 ), "width must be between 1 and 1024" );
|
||||
this.width = width;
|
||||
}
|
||||
}
|
@@ -0,0 +1,27 @@
|
||||
package net.md_5.bungee.api.dialog.action;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import lombok.Data;
|
||||
import lombok.NonNull;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* Submits the dialog with the given ID and values as a payload.
|
||||
*/
|
||||
@Data
|
||||
@Accessors(fluent = true)
|
||||
@ToString(callSuper = true)
|
||||
public class CustomClickAction implements Action
|
||||
{
|
||||
|
||||
/**
|
||||
* The namespaced key of the submission.
|
||||
*/
|
||||
@NonNull
|
||||
private String id;
|
||||
/**
|
||||
* Fields to be added to the submission payload.
|
||||
*/
|
||||
private JsonElement additions;
|
||||
}
|
@@ -0,0 +1,25 @@
|
||||
package net.md_5.bungee.api.dialog.action;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.NonNull;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* Executes a command. If the command requires a permission
|
||||
* higher than 0, a confirmation dialog will be shown by the client.
|
||||
*/
|
||||
@Data
|
||||
@Accessors(fluent = true)
|
||||
@ToString(callSuper = true)
|
||||
public class RunCommandAction implements Action
|
||||
{
|
||||
|
||||
/**
|
||||
* The template to be applied, where variables of the form
|
||||
* <code>$(key)</code> will be replaced by their
|
||||
* {@link net.md_5.bungee.api.dialog.input.DialogInput#key} value.
|
||||
*/
|
||||
@NonNull
|
||||
private String template;
|
||||
}
|
@@ -0,0 +1,20 @@
|
||||
package net.md_5.bungee.api.dialog.action;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.NonNull;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Accessors;
|
||||
import net.md_5.bungee.api.chat.ClickEvent;
|
||||
|
||||
/**
|
||||
* Represents a static dialog action.
|
||||
*/
|
||||
@Data
|
||||
@Accessors(fluent = true)
|
||||
@ToString(callSuper = true)
|
||||
public class StaticAction implements Action
|
||||
{
|
||||
|
||||
@NonNull
|
||||
private ClickEvent clickEvent;
|
||||
}
|
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Contains the different actions/buttons for a {@link net.md_5.bungee.api.dialog.Dialog}.
|
||||
*/
|
||||
package net.md_5.bungee.api.dialog.action;
|
@@ -0,0 +1,20 @@
|
||||
package net.md_5.bungee.api.dialog.body;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.NonNull;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
/**
|
||||
* Represents the body content of a {@link net.md_5.bungee.api.dialog.Dialog}.
|
||||
*/
|
||||
@Data
|
||||
public abstract class DialogBody
|
||||
{
|
||||
|
||||
/**
|
||||
* The internal body type.
|
||||
*/
|
||||
@NonNull
|
||||
@ApiStatus.Internal
|
||||
private final String type;
|
||||
}
|
@@ -0,0 +1,49 @@
|
||||
package net.md_5.bungee.api.dialog.body;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NonNull;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Accessors;
|
||||
import net.md_5.bungee.api.chat.BaseComponent;
|
||||
|
||||
/**
|
||||
* Represents a dialog body which consists of text constrained to a certain
|
||||
* width.
|
||||
*/
|
||||
@Data
|
||||
@Accessors(fluent = true)
|
||||
@ToString(callSuper = true)
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class PlainMessageBody extends DialogBody
|
||||
{
|
||||
|
||||
/**
|
||||
* The text body.
|
||||
*/
|
||||
@NonNull
|
||||
private BaseComponent contents;
|
||||
/**
|
||||
* The maximum width (default: 200, minimum: 1, maximum: 1024).
|
||||
*/
|
||||
private Integer width;
|
||||
|
||||
public PlainMessageBody(@NonNull BaseComponent contents)
|
||||
{
|
||||
this( contents, null );
|
||||
}
|
||||
|
||||
public PlainMessageBody(@NonNull BaseComponent contents, Integer width)
|
||||
{
|
||||
super( "minecraft:plain_message" );
|
||||
this.contents = contents;
|
||||
width( width );
|
||||
}
|
||||
|
||||
public void width(Integer width)
|
||||
{
|
||||
Preconditions.checkArgument( width == null || ( width >= 1 && width <= 1024 ), "width must be between 1 and 1024" );
|
||||
this.width = width;
|
||||
}
|
||||
}
|
@@ -0,0 +1,5 @@
|
||||
/**
|
||||
* Contains the different {@link net.md_5.bungee.api.dialog.Dialog} body content
|
||||
* types.
|
||||
*/
|
||||
package net.md_5.bungee.api.dialog.body;
|
@@ -0,0 +1,42 @@
|
||||
package net.md_5.bungee.api.dialog.chat;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import net.md_5.bungee.api.chat.ClickEvent;
|
||||
import net.md_5.bungee.api.dialog.Dialog;
|
||||
|
||||
/**
|
||||
* Click event which displays either a pre-existing dialog by key or a custom
|
||||
* dialog.
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class ShowDialogClickEvent extends ClickEvent
|
||||
{
|
||||
|
||||
/**
|
||||
* Key for a pre-existing dialog to show.
|
||||
*/
|
||||
private String reference;
|
||||
/**
|
||||
* Dialog to show.
|
||||
*/
|
||||
private Dialog dialog;
|
||||
|
||||
public ShowDialogClickEvent(String reference)
|
||||
{
|
||||
this( reference, null );
|
||||
}
|
||||
|
||||
public ShowDialogClickEvent(Dialog dialog)
|
||||
{
|
||||
this( null, dialog );
|
||||
}
|
||||
|
||||
private ShowDialogClickEvent(String reference, Dialog dialog)
|
||||
{
|
||||
super( Action.SHOW_DIALOG, null );
|
||||
this.reference = reference;
|
||||
this.dialog = dialog;
|
||||
}
|
||||
}
|
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Contains dialog extensions to the chat API.
|
||||
*/
|
||||
package net.md_5.bungee.api.dialog.chat;
|
@@ -0,0 +1,54 @@
|
||||
package net.md_5.bungee.api.dialog.input;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NonNull;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Accessors;
|
||||
import net.md_5.bungee.api.chat.BaseComponent;
|
||||
|
||||
/**
|
||||
* Represents a checkbox input control.
|
||||
*/
|
||||
@Data
|
||||
@Accessors(fluent = true)
|
||||
@ToString(callSuper = true)
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class BooleanInput extends DialogInput
|
||||
{
|
||||
|
||||
/**
|
||||
* The input label.
|
||||
*/
|
||||
@NonNull
|
||||
private BaseComponent label;
|
||||
/**
|
||||
* The initial value (default: false/unchecked).
|
||||
*/
|
||||
private Boolean initial;
|
||||
/**
|
||||
* The string value to be submitted when true/checked (default: "true").
|
||||
*/
|
||||
@SerializedName("on_true")
|
||||
private String onTrue;
|
||||
/**
|
||||
* The string value to be submitted when false/unchecked (default: "false").
|
||||
*/
|
||||
@SerializedName("on_false")
|
||||
private String onFalse;
|
||||
|
||||
public BooleanInput(@NonNull String key, @NonNull BaseComponent label)
|
||||
{
|
||||
this( key, label, null, "true", "false" );
|
||||
}
|
||||
|
||||
public BooleanInput(@NonNull String key, @NonNull BaseComponent label, Boolean initial, String onTrue, String onFalse)
|
||||
{
|
||||
super( "minecraft:boolean", key );
|
||||
this.label = label;
|
||||
this.initial = initial;
|
||||
this.onTrue = onTrue;
|
||||
this.onFalse = onFalse;
|
||||
}
|
||||
}
|
@@ -0,0 +1,29 @@
|
||||
package net.md_5.bungee.api.dialog.input;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.NonNull;
|
||||
import lombok.experimental.Accessors;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
/**
|
||||
* Represents a type of input which may be displayed/submitted with a form
|
||||
* dialog.
|
||||
*/
|
||||
@Data
|
||||
@Accessors(fluent = true)
|
||||
public class DialogInput
|
||||
{
|
||||
|
||||
/**
|
||||
* The internal input type.
|
||||
*/
|
||||
@NonNull
|
||||
@ApiStatus.Internal
|
||||
private final String type;
|
||||
/**
|
||||
* The key corresponding to this input and associated with the value
|
||||
* submitted.
|
||||
*/
|
||||
@NonNull
|
||||
private final String key;
|
||||
}
|
@@ -0,0 +1,39 @@
|
||||
package net.md_5.bungee.api.dialog.input;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NonNull;
|
||||
import lombok.experimental.Accessors;
|
||||
import net.md_5.bungee.api.chat.BaseComponent;
|
||||
|
||||
/**
|
||||
* Represents an option choice which may form part of a
|
||||
* {@link SingleOptionInput}.
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@Accessors(fluent = true)
|
||||
public class InputOption
|
||||
{
|
||||
|
||||
/**
|
||||
* The string value associated with this option, to be submitted when
|
||||
* selected.
|
||||
*/
|
||||
@NonNull
|
||||
private String id;
|
||||
/**
|
||||
* The text to display for this option.
|
||||
*/
|
||||
private BaseComponent display;
|
||||
/**
|
||||
* Whether this option is the one initially selected. Only one option may
|
||||
* have this value as true (default: first option).
|
||||
*/
|
||||
private Boolean initial;
|
||||
|
||||
public InputOption(@NonNull String id)
|
||||
{
|
||||
this( id, null, null );
|
||||
}
|
||||
}
|
@@ -0,0 +1,103 @@
|
||||
package net.md_5.bungee.api.dialog.input;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NonNull;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Accessors;
|
||||
import net.md_5.bungee.api.chat.BaseComponent;
|
||||
|
||||
/**
|
||||
* Represents a number slider input.
|
||||
*/
|
||||
@Data
|
||||
@Accessors(fluent = true)
|
||||
@ToString(callSuper = true)
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class NumberRangeInput extends DialogInput
|
||||
{
|
||||
|
||||
/**
|
||||
* The width of the input (default: 200, minimum: 1, maximum: 1024).
|
||||
*/
|
||||
private Integer width;
|
||||
/**
|
||||
* The label of the slider.
|
||||
*/
|
||||
@NonNull
|
||||
private BaseComponent label;
|
||||
/**
|
||||
* A translate key used to display the label value (default:
|
||||
* options.generic_value).
|
||||
*/
|
||||
private String labelFormat;
|
||||
/**
|
||||
* The start position of the slider (leftmost position).
|
||||
*/
|
||||
private float start;
|
||||
/**
|
||||
* The end position of the slider (rightmost position).
|
||||
*/
|
||||
private float end;
|
||||
/**
|
||||
* The steps in which the input will be increased or decreased, or null if
|
||||
* no specific steps.
|
||||
*/
|
||||
private Float step;
|
||||
/**
|
||||
* The initial value of number input, or null to fall back to the middle.
|
||||
*/
|
||||
private Float initial;
|
||||
|
||||
public NumberRangeInput(@NonNull String key, @NonNull BaseComponent label, float start, float end)
|
||||
{
|
||||
this( key, null, label, "options.generic_value", start, end, null, null );
|
||||
}
|
||||
|
||||
public NumberRangeInput(@NonNull String key, @NonNull BaseComponent label, float start, float end, Float step)
|
||||
{
|
||||
this( key, null, label, "options.generic_value", start, end, step, null );
|
||||
}
|
||||
|
||||
public NumberRangeInput(@NonNull String key, @NonNull BaseComponent label, float start, float end, Float step, Float initial)
|
||||
{
|
||||
this( key, null, label, "options.generic_value", start, end, step, initial );
|
||||
}
|
||||
|
||||
public NumberRangeInput(@NonNull String key, Integer width, @NonNull BaseComponent label, String labelFormat, float start, float end, Float step, Float initial)
|
||||
{
|
||||
super( "minecraft:number_range", key );
|
||||
width( width );
|
||||
this.label = label;
|
||||
this.labelFormat = labelFormat;
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
step( step );
|
||||
initial( initial );
|
||||
}
|
||||
|
||||
public NumberRangeInput width(Integer width)
|
||||
{
|
||||
Preconditions.checkArgument( width == null || ( width >= 1 && width <= 1024 ), "with must be between 1 and 1024" );
|
||||
this.width = width;
|
||||
return this;
|
||||
}
|
||||
|
||||
public NumberRangeInput step(Float step)
|
||||
{
|
||||
Preconditions.checkArgument( step == null || step > 0, "step must be null or greater than zero" );
|
||||
this.step = step;
|
||||
return this;
|
||||
}
|
||||
|
||||
public NumberRangeInput initial(Float initial)
|
||||
{
|
||||
// we need to calculate if the initial value is between start and end, regardless of the order
|
||||
float min = Math.min( start, end );
|
||||
float max = Math.max( start, end );
|
||||
Preconditions.checkArgument( initial == null || ( initial >= min && initial <= max ), "initial must be null or between start and end" );
|
||||
this.initial = initial;
|
||||
return this;
|
||||
}
|
||||
}
|
@@ -0,0 +1,66 @@
|
||||
package net.md_5.bungee.api.dialog.input;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NonNull;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Accessors;
|
||||
import net.md_5.bungee.api.chat.BaseComponent;
|
||||
|
||||
/**
|
||||
* Represents a single option (dropdown) input.
|
||||
*/
|
||||
@Data
|
||||
@Accessors(fluent = true)
|
||||
@ToString(callSuper = true)
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class SingleOptionInput extends DialogInput
|
||||
{
|
||||
|
||||
/**
|
||||
* The width of the input (default: 200, minimum: 1, maximum: 1024).
|
||||
*/
|
||||
private Integer width;
|
||||
/**
|
||||
* The input label.
|
||||
*/
|
||||
@NonNull
|
||||
private BaseComponent label;
|
||||
/**
|
||||
* Whether the label is visible (default: true).
|
||||
*/
|
||||
@SerializedName("label_visible")
|
||||
private Boolean labelVisible;
|
||||
/**
|
||||
* The non-empty list of options to be selected from.
|
||||
*/
|
||||
@NonNull
|
||||
private List<InputOption> options;
|
||||
|
||||
public SingleOptionInput(@NonNull String key, @NonNull BaseComponent label, @NonNull InputOption... options)
|
||||
{
|
||||
this( key, null, label, null, Arrays.asList( options ) );
|
||||
}
|
||||
|
||||
public SingleOptionInput(@NonNull String key, Integer width, @NonNull BaseComponent label, Boolean labelVisible, @NonNull List<InputOption> options)
|
||||
{
|
||||
super( "minecraft:single_option", key );
|
||||
Preconditions.checkArgument( !options.isEmpty(), "At least one option must be provided" );
|
||||
|
||||
width( width );
|
||||
this.label = label;
|
||||
this.labelVisible = labelVisible;
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
public SingleOptionInput width(Integer width)
|
||||
{
|
||||
Preconditions.checkArgument( width == null || ( width >= 1 && width <= 1024 ), "width must be between 1 and 1024" );
|
||||
this.width = width;
|
||||
return this;
|
||||
}
|
||||
}
|
@@ -0,0 +1,110 @@
|
||||
package net.md_5.bungee.api.dialog.input;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.NonNull;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Accessors;
|
||||
import net.md_5.bungee.api.chat.BaseComponent;
|
||||
|
||||
/**
|
||||
* Represents a textbox input.
|
||||
*/
|
||||
@Data
|
||||
@Accessors(fluent = true)
|
||||
@ToString(callSuper = true)
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class TextInput extends DialogInput
|
||||
{
|
||||
|
||||
/**
|
||||
* The width of this text input (default: 200, minimum: 1, maximum: 1024).
|
||||
*/
|
||||
private Integer width;
|
||||
/**
|
||||
* The label of this text input.
|
||||
*/
|
||||
@NonNull
|
||||
private BaseComponent label;
|
||||
/**
|
||||
* The visibility of this text input's label.
|
||||
*/
|
||||
@SerializedName("label_visible")
|
||||
private Boolean labelVisible;
|
||||
/**
|
||||
* The initial value of this text input.
|
||||
*/
|
||||
private String initial;
|
||||
/**
|
||||
* The maximum length of the input (default: 32).
|
||||
*/
|
||||
@SerializedName("max_length")
|
||||
private Integer maxLength;
|
||||
/**
|
||||
* If present, allows users to input multiple lines.
|
||||
*/
|
||||
private Multiline multiline;
|
||||
|
||||
public TextInput(@NonNull String key, @NonNull BaseComponent label)
|
||||
{
|
||||
this( key, null, label, null, null, null, null );
|
||||
}
|
||||
|
||||
public TextInput(@NonNull String key, Integer width, @NonNull BaseComponent label, Boolean labelVisible, String initial, Integer maxLength)
|
||||
{
|
||||
this( key, width, label, labelVisible, initial, maxLength, null );
|
||||
}
|
||||
|
||||
public TextInput(@NonNull String key, Integer width, @NonNull BaseComponent label, Boolean labelVisible, String initial, Integer maxLength, Multiline multiline)
|
||||
{
|
||||
super( "minecraft:text", key );
|
||||
width( width );
|
||||
this.label = label;
|
||||
this.labelVisible = labelVisible;
|
||||
this.initial = initial;
|
||||
this.maxLength = maxLength;
|
||||
this.multiline = multiline;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configuration data for a multiline input.
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@Accessors(fluent = true)
|
||||
public static class Multiline
|
||||
{
|
||||
|
||||
/**
|
||||
* The maximum length of input, or null to disable any limits.
|
||||
*/
|
||||
@SerializedName("max_lines")
|
||||
private Integer maxLines;
|
||||
/**
|
||||
* The height of this input (default: 32, minimum: 1, maximum: 512).
|
||||
*/
|
||||
private Integer height;
|
||||
|
||||
public Multiline(Integer maxLines, Integer height)
|
||||
{
|
||||
height( height ).maxLines( maxLines );
|
||||
}
|
||||
|
||||
public Multiline height(Integer height)
|
||||
{
|
||||
Preconditions.checkArgument( height == null || height >= 1 && height <= 512, "height must null or be between 1 and 512" );
|
||||
this.height = height;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
public TextInput width(Integer width)
|
||||
{
|
||||
Preconditions.checkArgument( width == null || ( width >= 1 && width <= 1024 ), "width must be between 1 and 1024" );
|
||||
this.width = width;
|
||||
return this;
|
||||
}
|
||||
}
|
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Represents the various input controls which may be present on form dialogs.
|
||||
*/
|
||||
package net.md_5.bungee.api.dialog.input;
|
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Contains the core classes for the display of a {@link net.md_5.bungee.api.dialog.Dialog}.
|
||||
*/
|
||||
package net.md_5.bungee.api.dialog;
|
@@ -4,15 +4,14 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>net.md-5</groupId>
|
||||
<groupId>fr.pandacube.bungeecord</groupId>
|
||||
<artifactId>bungeecord-parent</artifactId>
|
||||
<version>1.20-R0.2-SNAPSHOT</version>
|
||||
<version>1.21-R0.4-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-event</artifactId>
|
||||
<version>1.20-R0.2-SNAPSHOT</version>
|
||||
<version>1.21-R0.4-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>BungeeCord-Event</name>
|
||||
|
@@ -1,8 +1,8 @@
|
||||
package net.md_5.bungee.event;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class EventBusTest
|
||||
{
|
||||
@@ -15,14 +15,14 @@ public class EventBusTest
|
||||
{
|
||||
bus.register( this );
|
||||
bus.post( new FirstEvent() );
|
||||
Assert.assertEquals( 0, latch.getCount() );
|
||||
assertEquals( 0, latch.getCount() );
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void firstListener(FirstEvent event)
|
||||
{
|
||||
bus.post( new SecondEvent() );
|
||||
Assert.assertEquals( 1, latch.getCount() );
|
||||
assertEquals( 1, latch.getCount() );
|
||||
latch.countDown();
|
||||
}
|
||||
|
||||
|
@@ -1,8 +1,8 @@
|
||||
package net.md_5.bungee.event;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class EventPriorityTest
|
||||
{
|
||||
@@ -16,41 +16,41 @@ public class EventPriorityTest
|
||||
bus.register( this );
|
||||
bus.register( new EventPriorityListenerPartner() );
|
||||
bus.post( new PriorityTestEvent() );
|
||||
Assert.assertEquals( 0, latch.getCount() );
|
||||
assertEquals( 0, latch.getCount() );
|
||||
}
|
||||
|
||||
@EventHandler(priority = Byte.MIN_VALUE)
|
||||
public void onMinPriority(PriorityTestEvent event)
|
||||
{
|
||||
Assert.assertEquals( 7, latch.getCount() );
|
||||
assertEquals( 7, latch.getCount() );
|
||||
latch.countDown();
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onLowestPriority(PriorityTestEvent event)
|
||||
{
|
||||
Assert.assertEquals( 6, latch.getCount() );
|
||||
assertEquals( 6, latch.getCount() );
|
||||
latch.countDown();
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onNormalPriority(PriorityTestEvent event)
|
||||
{
|
||||
Assert.assertEquals( 4, latch.getCount() );
|
||||
assertEquals( 4, latch.getCount() );
|
||||
latch.countDown();
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onHighestPriority(PriorityTestEvent event)
|
||||
{
|
||||
Assert.assertEquals( 2, latch.getCount() );
|
||||
assertEquals( 2, latch.getCount() );
|
||||
latch.countDown();
|
||||
}
|
||||
|
||||
@EventHandler(priority = Byte.MAX_VALUE)
|
||||
public void onMaxPriority(PriorityTestEvent event)
|
||||
{
|
||||
Assert.assertEquals( 1, latch.getCount() );
|
||||
assertEquals( 1, latch.getCount() );
|
||||
latch.countDown();
|
||||
}
|
||||
|
||||
@@ -64,14 +64,14 @@ public class EventPriorityTest
|
||||
@EventHandler(priority = EventPriority.HIGH)
|
||||
public void onHighPriority(PriorityTestEvent event)
|
||||
{
|
||||
Assert.assertEquals( 3, latch.getCount() );
|
||||
assertEquals( 3, latch.getCount() );
|
||||
latch.countDown();
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOW)
|
||||
public void onLowPriority(PriorityTestEvent event)
|
||||
{
|
||||
Assert.assertEquals( 5, latch.getCount() );
|
||||
assertEquals( 5, latch.getCount() );
|
||||
latch.countDown();
|
||||
}
|
||||
}
|
||||
|
@@ -1,8 +1,8 @@
|
||||
package net.md_5.bungee.event;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class SubclassTest extends EventBusTest
|
||||
{
|
||||
@@ -14,13 +14,13 @@ public class SubclassTest extends EventBusTest
|
||||
public void testNestedEvents()
|
||||
{
|
||||
super.testNestedEvents();
|
||||
Assert.assertEquals( 0, latch.getCount() );
|
||||
assertEquals( 0, latch.getCount() );
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
protected void extraListener(FirstEvent event)
|
||||
{
|
||||
Assert.assertEquals( 1, latch.getCount() );
|
||||
assertEquals( 1, latch.getCount() );
|
||||
latch.countDown();
|
||||
}
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
package net.md_5.bungee.event;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class UnregisteringListenerTest
|
||||
{
|
||||
@@ -19,7 +19,7 @@ public class UnregisteringListenerTest
|
||||
@EventHandler
|
||||
public void onEvent(TestEvent evt)
|
||||
{
|
||||
Assert.fail( "Event listener wasn't unregistered" );
|
||||
fail( "Event listener wasn't unregistered" );
|
||||
}
|
||||
|
||||
public static class TestEvent
|
||||
|
13
log/pom.xml
13
log/pom.xml
@@ -4,15 +4,14 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>net.md-5</groupId>
|
||||
<groupId>fr.pandacube.bungeecord</groupId>
|
||||
<artifactId>bungeecord-parent</artifactId>
|
||||
<version>1.20-R0.2-SNAPSHOT</version>
|
||||
<version>1.21-R0.4-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-log</artifactId>
|
||||
<version>1.20-R0.2-SNAPSHOT</version>
|
||||
<version>1.21-R0.4-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>BungeeCord-Log</name>
|
||||
@@ -20,13 +19,13 @@
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>jline</groupId>
|
||||
<groupId>org.jline</groupId>
|
||||
<artifactId>jline</artifactId>
|
||||
<version>2.12.1</version>
|
||||
<version>3.30.4</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.md-5</groupId>
|
||||
<groupId>fr.pandacube.bungeecord</groupId>
|
||||
<artifactId>bungeecord-chat</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
|
@@ -1,26 +1,18 @@
|
||||
package net.md_5.bungee.log;
|
||||
|
||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||
import java.io.IOException;
|
||||
import java.util.logging.FileHandler;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.LogRecord;
|
||||
import java.util.logging.Logger;
|
||||
import jline.console.ConsoleReader;
|
||||
import org.jline.reader.LineReader;
|
||||
|
||||
public class BungeeLogger extends Logger
|
||||
{
|
||||
|
||||
private final LogDispatcher dispatcher = new LogDispatcher( this );
|
||||
|
||||
// CHECKSTYLE:OFF
|
||||
@SuppressWarnings(
|
||||
{
|
||||
"CallToPrintStackTrace", "CallToThreadStartDuringObjectConstruction"
|
||||
})
|
||||
// CHECKSTYLE:ON
|
||||
@SuppressFBWarnings("SC_START_IN_CTOR")
|
||||
public BungeeLogger(String loggerName, String filePattern, ConsoleReader reader)
|
||||
public BungeeLogger(String loggerName, String filePattern, LineReader reader)
|
||||
{
|
||||
super( loggerName, null );
|
||||
setLevel( Level.ALL );
|
||||
|
@@ -1,15 +1,15 @@
|
||||
package net.md_5.bungee.log;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.logging.Handler;
|
||||
import java.util.logging.LogRecord;
|
||||
import java.util.regex.Pattern;
|
||||
import jline.console.ConsoleReader;
|
||||
import lombok.Data;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import org.fusesource.jansi.Ansi;
|
||||
import org.fusesource.jansi.Ansi.Erase;
|
||||
import org.jline.jansi.Ansi;
|
||||
import org.jline.reader.LineReader;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class ColouredWriter extends Handler
|
||||
{
|
||||
|
||||
@@ -52,12 +52,7 @@ public class ColouredWriter extends Handler
|
||||
compile( ChatColor.RESET, Ansi.ansi().a( Ansi.Attribute.RESET ).toString() ),
|
||||
};
|
||||
//
|
||||
private final ConsoleReader console;
|
||||
|
||||
public ColouredWriter(ConsoleReader console)
|
||||
{
|
||||
this.console = console;
|
||||
}
|
||||
private final LineReader console;
|
||||
|
||||
public void print(String s)
|
||||
{
|
||||
@@ -65,14 +60,7 @@ public class ColouredWriter extends Handler
|
||||
{
|
||||
s = replacement.pattern.matcher( s ).replaceAll( replacement.replacement );
|
||||
}
|
||||
try
|
||||
{
|
||||
console.print( Ansi.ansi().eraseLine( Erase.ALL ).toString() + ConsoleReader.RESET_LINE + s + Ansi.ansi().reset().toString() );
|
||||
console.drawLine();
|
||||
console.flush();
|
||||
} catch ( IOException ex )
|
||||
{
|
||||
}
|
||||
console.printAbove( s + Ansi.ansi().reset().toString() );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -18,7 +18,6 @@ public class ConciseFormatter extends Formatter
|
||||
private final boolean coloured;
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("ThrowableResultIgnored")
|
||||
public String format(LogRecord record)
|
||||
{
|
||||
StringBuilder formatted = new StringBuilder();
|
||||
|
@@ -1,8 +1,8 @@
|
||||
package net.md_5.bungee.log;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@@ -19,7 +19,7 @@ public class LoggingOutputStream extends ByteArrayOutputStream
|
||||
@Override
|
||||
public void flush() throws IOException
|
||||
{
|
||||
String contents = toString( Charsets.UTF_8.name() );
|
||||
String contents = toString( StandardCharsets.UTF_8.name() );
|
||||
super.reset();
|
||||
if ( !contents.isEmpty() && !contents.equals( separator ) )
|
||||
{
|
||||
|
@@ -1,20 +0,0 @@
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-module</artifactId>
|
||||
<version>1.20-R0.2-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-module-cmd-alert</artifactId>
|
||||
<version>1.20-R0.2-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>cmd_alert</name>
|
||||
<description>Provides the alert and alertraw commands</description>
|
||||
</project>
|
@@ -1,47 +0,0 @@
|
||||
package net.md_5.bungee.module.cmd.alert;
|
||||
|
||||
import java.util.Locale;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import net.md_5.bungee.api.CommandSender;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
import net.md_5.bungee.api.chat.TextComponent;
|
||||
import net.md_5.bungee.api.plugin.Command;
|
||||
|
||||
public class CommandAlert extends Command
|
||||
{
|
||||
|
||||
public CommandAlert()
|
||||
{
|
||||
super( "alert", "bungeecord.command.alert" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(CommandSender sender, String[] args)
|
||||
{
|
||||
if ( args.length == 0 )
|
||||
{
|
||||
sender.sendMessage( ProxyServer.getInstance().getTranslation( "message_needed" ) );
|
||||
} else
|
||||
{
|
||||
StringBuilder builder = new StringBuilder();
|
||||
if ( args[0].toLowerCase( Locale.ROOT ).startsWith( "&h" ) )
|
||||
{
|
||||
// Remove &h
|
||||
args[0] = args[0].substring( 2 );
|
||||
} else
|
||||
{
|
||||
builder.append( ProxyServer.getInstance().getTranslation( "alert" ) );
|
||||
}
|
||||
|
||||
for ( String s : args )
|
||||
{
|
||||
builder.append( ChatColor.translateAlternateColorCodes( '&', s ) );
|
||||
builder.append( " " );
|
||||
}
|
||||
|
||||
String message = builder.substring( 0, builder.length() - 1 );
|
||||
|
||||
ProxyServer.getInstance().broadcast( TextComponent.fromLegacyText( 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() );
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user