269 Commits

Author SHA1 Message Date
f948b287f5 new event TabCompleteRequestEvent and deprecate TabCompleteEvent 2024-02-17 18:30:11 +01:00
85d372ae7e Add CommandsDeclareEvent to declare commands with brigadier API 2024-02-17 18:30:11 +01:00
f38c4a6e94 Server branding now includes the backend server name 2024-02-17 18:30:11 +01:00
aefd61943b Multi-session with same Minecraft account with specific permission
Players with permission bungeecord.multiple_connect can have multiple connections with the same Minecraft account.
The UUID and player name is altered to avoid collision with other player:
UUID : xxxxxxxx-xxxx-VIxx-xxxx-xxxxxxxxxxxx
- The UUID version (V above) is now the provided version + 8 (for online player, it is 4, so it becomes C).
- The I digit will follow the index of the duplicated player : first duplicated player is 1, second one is 2.
- The name of the player will be the real player name, followed by the character "." (dot) followed by the duplication index.

Bedrock accounts connected using the Floodgate plugin will not be able to connect multiple times due to the risk of xUID collision.
2024-02-17 18:30:11 +01:00
f08fb3cdfe Change projet configuration and POM for Pandacube 2024-02-17 18:29:40 +01:00
c237bd3895 Remove modules and startup delay
We don’t need them for Pandacube
2024-02-17 13:40:26 +01:00
dependabot[bot]
3e9a7e45c4 #3616: Bump io.netty:netty-bom from 4.1.106.Final to 4.1.107.Final
Bumps [io.netty:netty-bom](https://github.com/netty/netty) from 4.1.106.Final to 4.1.107.Final.
- [Commits](https://github.com/netty/netty/compare/netty-4.1.106.Final...netty-4.1.107.Final)

---
updated-dependencies:
- dependency-name: io.netty:netty-bom
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-17 13:41:16 +11:00
dependabot[bot]
f6c5332c1a #3613: Bump org.junit.jupiter:junit-jupiter from 5.10.1 to 5.10.2
Bumps [org.junit.jupiter:junit-jupiter](https://github.com/junit-team/junit5) from 5.10.1 to 5.10.2.
- [Release notes](https://github.com/junit-team/junit5/releases)
- [Commits](https://github.com/junit-team/junit5/compare/r5.10.1...r5.10.2)

---
updated-dependencies:
- dependency-name: org.junit.jupiter:junit-jupiter
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-17 13:41:00 +11:00
md_5
d0fa62d424 Minecraft 24w06a support 2024-02-10 12:26:38 +11:00
md_5
464ed0184c Improve cookie support during login 2024-02-10 12:26:26 +11:00
md_5
eda268b481 Fix 24w05b spectate packet ID 2024-02-06 07:03:49 +11:00
md_5
3e1007527c #3612: Error when disconnecting player on PostLoginEvent 2024-02-04 11:47:30 +11:00
md_5
b52b14696c Add PendingConnection#isTransferred API method 2024-02-04 11:35:20 +11:00
md_5
94d5b0d03c Minecraft 24w05b support 2024-02-03 15:34:08 +11:00
Diogo Correia
c3f228f626 #3610, 3611: inverted isEmpty method on ComponentStyle 2024-02-02 11:16:46 +11:00
Outfluencer
02c5c1ee76 #3602: Minecraft 24w04a support 2024-01-30 07:25:22 +11:00
md_5
c69acf728c Add JetBrains java-annotations 2024-01-29 20:29:58 +11:00
md_5
a1cd694363 Bump version to 1.20-R0.3-SNAPSHOT 2024-01-20 08:41:57 +11:00
md_5
3e2bc8e2d7 Release 1.20-R0.2 2024-01-20 08:37:37 +11:00
dependabot[bot]
ad7163d2d6 #3600: Bump io.netty:netty-bom from 4.1.104.Final to 4.1.106.Final
Bumps [io.netty:netty-bom](https://github.com/netty/netty) from 4.1.104.Final to 4.1.106.Final.
- [Commits](https://github.com/netty/netty/compare/netty-4.1.104.Final...netty-4.1.106.Final)

---
updated-dependencies:
- dependency-name: io.netty:netty-bom
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-20 08:34:51 +11:00
Valentine
19918c694f #3594: Fix missing ComponentStyleSerializer 2024-01-09 16:09:55 +11:00
md_5
21c8f2815a Decode ComponentStyle over network as appropriate 2024-01-06 16:35:33 +11:00
Parker Hawke
737d545fb6 #3569: Separate component styling into a ComponentStyle class 2024-01-06 16:35:30 +11:00
dependabot[bot]
b23a51825e #3588: Bump org.apache.maven.plugins:maven-compiler-plugin
Bumps [org.apache.maven.plugins:maven-compiler-plugin](https://github.com/apache/maven-compiler-plugin) from 3.11.0 to 3.12.1.
- [Release notes](https://github.com/apache/maven-compiler-plugin/releases)
- [Commits](https://github.com/apache/maven-compiler-plugin/compare/maven-compiler-plugin-3.11.0...maven-compiler-plugin-3.12.1)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-compiler-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-26 08:47:34 +11:00
md_5
708c5b6254 #3585: Fix mistake converting certain NBT to JSON in previous commit 2023-12-22 22:06:23 +11:00
md_5
f5af11193c #3584: Handle conversion of mixed NBT lists to json 2023-12-22 18:01:30 +11:00
md_5
b711e4033f #3578: bungeecord-chat does not support array format UUIDs 2023-12-19 19:54:03 +11:00
Outfluencer
3deaaadc3a #3574: "VarInt too big" should be an OverflowPacketException 2023-12-16 11:29:03 +11:00
dependabot[bot]
51b9a6b0b8 #3577: Bump io.netty:netty-bom from 4.1.101.Final to 4.1.104.Final
Bumps [io.netty:netty-bom](https://github.com/netty/netty) from 4.1.101.Final to 4.1.104.Final.
- [Commits](https://github.com/netty/netty/compare/netty-4.1.101.Final...netty-4.1.104.Final)

---
updated-dependencies:
- dependency-name: io.netty:netty-bom
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-16 11:28:36 +11:00
dependabot[bot]
1a807731a5 #3567: Bump org.apache.maven.plugins:maven-javadoc-plugin from 3.6.2 to 3.6.3
Bumps [org.apache.maven.plugins:maven-javadoc-plugin](https://github.com/apache/maven-javadoc-plugin) from 3.6.2 to 3.6.3.
- [Release notes](https://github.com/apache/maven-javadoc-plugin/releases)
- [Commits](https://github.com/apache/maven-javadoc-plugin/compare/maven-javadoc-plugin-3.6.2...maven-javadoc-plugin-3.6.3)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-javadoc-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-10 11:00:38 +11:00
dependabot[bot]
772ad9951f #3566: Bump actions/setup-java from 3 to 4
Bumps [actions/setup-java](https://github.com/actions/setup-java) from 3 to 4.
- [Release notes](https://github.com/actions/setup-java/releases)
- [Commits](https://github.com/actions/setup-java/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/setup-java
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-10 11:00:24 +11:00
dependabot[bot]
2431c40a5c #3562: Bump io.netty:netty-bom from 4.1.100.Final to 4.1.101.Final
Bumps [io.netty:netty-bom](https://github.com/netty/netty) from 4.1.100.Final to 4.1.101.Final.
- [Commits](https://github.com/netty/netty/compare/netty-4.1.100.Final...netty-4.1.101.Final)

---
updated-dependencies:
- dependency-name: io.netty:netty-bom
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-10 11:00:05 +11:00
dependabot[bot]
8144ae8d7b #3555: Bump com.mysql:mysql-connector-j from 8.1.0 to 8.2.0
Bumps [com.mysql:mysql-connector-j](https://github.com/mysql/mysql-connector-j) from 8.1.0 to 8.2.0.
- [Changelog](https://github.com/mysql/mysql-connector-j/blob/release/8.x/CHANGES)
- [Commits](https://github.com/mysql/mysql-connector-j/compare/8.1.0...8.2.0)

---
updated-dependencies:
- dependency-name: com.mysql:mysql-connector-j
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-10 10:59:52 +11:00
md_5
0757c39a6f Attempt upgrade of resolver libraries 2023-12-10 10:56:39 +11:00
md_5
231024ba42 Relax chat parsing to treat bytes as booleans to allow formatting read from NBT 2023-12-06 21:55:56 +11:00
md_5
8ce7a7f8b6 Minecraft 1.20.3 support 2023-12-06 03:40:00 +11:00
md_5
e1462ccdd1 Minecraft 1.20.3-rc1 support 2023-12-04 19:02:45 +11:00
md_5
70f346c1dc Fix extra write in ScoreboardScore packet 2023-11-26 08:12:30 +11:00
md_5
197bf13a28 Minecraft 1.20.3-pre2 support 2023-11-25 17:02:40 +11:00
md_5
0925c06f9b #3563: Correct max string length for reading SystemChat packets 2023-11-13 20:09:48 +13:00
Parker Hawke
16298a75f2 #3558: Add Translatable interface for fluid creation of TranslatableComponents 2023-11-10 07:03:46 +11:00
md_5
39b10c0b16 Minecraft 23w45a support 2023-11-09 19:33:11 +11:00
dependabot[bot]
bd8d114992 #3561: Bump org.apache.maven.plugins:maven-javadoc-plugin from 3.6.0 to 3.6.2
Bumps [org.apache.maven.plugins:maven-javadoc-plugin](https://github.com/apache/maven-javadoc-plugin) from 3.6.0 to 3.6.2.
- [Release notes](https://github.com/apache/maven-javadoc-plugin/releases)
- [Commits](https://github.com/apache/maven-javadoc-plugin/compare/maven-javadoc-plugin-3.6.0...maven-javadoc-plugin-3.6.2)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-javadoc-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-07 20:17:54 +11:00
dependabot[bot]
30e12c6fe0 #3560: Bump org.junit.jupiter:junit-jupiter from 5.10.0 to 5.10.1
Bumps [org.junit.jupiter:junit-jupiter](https://github.com/junit-team/junit5) from 5.10.0 to 5.10.1.
- [Release notes](https://github.com/junit-team/junit5/releases)
- [Commits](https://github.com/junit-team/junit5/compare/r5.10.0...r5.10.1)

---
updated-dependencies:
- dependency-name: org.junit.jupiter:junit-jupiter
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-07 20:17:20 +11:00
md_5
bd009ca52d #3559: Fix serialisation of certain scoreboard packets < 1.13 2023-11-06 20:14:57 +11:00
md_5
65d8edf62d Minecraft 23w44a support 2023-11-06 20:14:55 +11:00
BoomEaro
f5157f12a4 #3438: Fix possible race condition in duplicate player check 2023-11-01 21:32:31 +11:00
BoomEaro
df20effacc #3557: Replace Guava Charsets with Java StandardCharsets 2023-10-31 21:49:17 +11:00
md_5
c92581d0dc #3556: Deserialize arrays to single components 2023-10-29 11:30:54 +11:00
Outfluencer
e442c3da5c #3546: Add string length checks to isValidName 2023-10-28 13:11:55 +11:00
dependabot[bot]
f903c54d55 #3554: Bump org.apache.maven.plugins:maven-checkstyle-plugin
Bumps [org.apache.maven.plugins:maven-checkstyle-plugin](https://github.com/apache/maven-checkstyle-plugin) from 3.3.0 to 3.3.1.
- [Commits](https://github.com/apache/maven-checkstyle-plugin/compare/maven-checkstyle-plugin-3.3.0...maven-checkstyle-plugin-3.3.1)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-checkstyle-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-28 13:06:40 +11:00
Parker Hawke
0d45378986 #3540: Add TextComponent#fromLegacy() as an array-free alternative to #fromLegacyText() 2023-10-28 13:04:18 +11:00
md_5
0f5f09b6c5 Minecraft 23w43b support 2023-10-28 12:57:19 +11:00
md_5
e5c80d0044 Fix code formatting 2023-10-28 12:57:16 +11:00
md_5
9cdb2ba3ea Deprecate exposed scoreboard API 2023-10-22 09:25:25 +11:00
dependabot[bot]
d0e5cf7ce5 #3549: Bump io.netty:netty-bom from 4.1.99.Final to 4.1.100.Final
Bumps [io.netty:netty-bom](https://github.com/netty/netty) from 4.1.99.Final to 4.1.100.Final.
- [Commits](https://github.com/netty/netty/compare/netty-4.1.99.Final...netty-4.1.100.Final)

---
updated-dependencies:
- dependency-name: io.netty:netty-bom
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-21 09:16:02 +11:00
md_5
c8568764f6 Fix writing non-compound root NBT tags 2023-10-14 16:38:11 +11:00
Outfluencer
a7dbbc2f0a #3544: Remove redundant super call in handle(FinishConfiguration) 2023-10-05 07:21:46 +11:00
Outfluencer
68b2df2b1e #3514: Add separator property to SelectorComponent 2023-10-05 07:21:13 +11:00
dependabot[bot]
1ef4d27dbe #3543: Bump io.netty:netty-bom from 4.1.97.Final to 4.1.99.Final
Bumps [io.netty:netty-bom](https://github.com/netty/netty) from 4.1.97.Final to 4.1.99.Final.
- [Commits](https://github.com/netty/netty/compare/netty-4.1.97.Final...netty-4.1.99.Final)

---
updated-dependencies:
- dependency-name: io.netty:netty-bom
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-29 07:50:39 +10:00
Outfluencer
94a1fb5117 #3535: Queue packets of Title api 2023-09-29 07:21:56 +10:00
md_5
78aef86a8f #3533: Don't put initial client in configure phase until server is ready 2023-09-29 06:50:28 +10:00
md_5
b34cfcde5a Simplify UpstreamBridge packet handling code 2023-09-28 06:55:00 +10:00
DartCZ
86e079a4b1 #3523, #3534: Fix kicking players with error 2023-09-28 06:55:00 +10:00
Outfluencer
1c42c34081 #3529: Use a synchronized list for /send command 2023-09-28 06:51:10 +10:00
dependabot[bot]
fed646d18b #3531: Bump org.apache.maven.plugins:maven-shade-plugin from 3.5.0 to 3.5.1
Bumps [org.apache.maven.plugins:maven-shade-plugin](https://github.com/apache/maven-shade-plugin) from 3.5.0 to 3.5.1.
- [Release notes](https://github.com/apache/maven-shade-plugin/releases)
- [Commits](https://github.com/apache/maven-shade-plugin/compare/maven-shade-plugin-3.5.0...maven-shade-plugin-3.5.1)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-shade-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-26 07:52:07 +10:00
md_5
653f1691d7 Print full stack trace for packet decoder errors 2023-09-26 06:40:02 +10:00
md_5
3cb7a12738 #3527: Switching between servers causes a decoding error 2023-09-26 06:35:48 +10:00
bob7l
f3397b3003 #3525, #3526: Set encode protocol to CONFIGURATION before connecting to a downstream server 2023-09-25 18:57:40 +10:00
md_5
497c6879e0 Add (hopefully temporary) queue for plugin messages to server 2023-09-24 06:50:46 +10:00
md_5
7b27dfaf5e #3522: Revert "#3518: Bump io.netty:netty-bom from 4.1.97.Final to 4.1.98.Final"
This reverts commit f486a251f3.
2023-09-24 06:25:28 +10:00
md_5
f9b75c4a3a Update tests to JUnit 5 2023-09-23 18:44:14 +10:00
md_5
0509303fd3 #3519: Queue configuration phase packets from API methods 2023-09-23 10:29:09 +10:00
dependabot[bot]
f486a251f3 #3518: Bump io.netty:netty-bom from 4.1.97.Final to 4.1.98.Final
Bumps [io.netty:netty-bom](https://github.com/netty/netty) from 4.1.97.Final to 4.1.98.Final.
- [Commits](https://github.com/netty/netty/compare/netty-4.1.97.Final...netty-4.1.98.Final)

---
updated-dependencies:
- dependency-name: io.netty:netty-bom
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-22 08:18:54 +10:00
md_5
5a1e342e0d Minecraft 1.20.2 support 2023-09-22 02:40:00 +10:00
md_5
d9bbdc3281 Add Java 21 compilation support 2023-09-20 18:06:33 +10:00
Parker Hawke
cfe00fa47c #3490: Add ComponentBuilder#build() and ComponentSerializer#deserialize()
Components traditionally use the extra data to represent components as a single BaseComponent object. While BaseComponent typically mirrors this behaviour, somewhere along the development of BungeeChat this practice was made unclear. Because ComponentBuilder#create() returns an array of BaseComponents, it has sort of been silently accepted that all components should be represented as arrays, which is incorrect. This heavily influenced the direction of Spigot's component API (with additions such as CommandSender#sendMessage(BaseComponent[])) which emphasizes this misconception of "all components are arrays".

Adding new methods to ComponentBuilder and ComponentSerializer should steer use of the BungeeChat API to be more oriented towards single component instances, not arrays.
2023-09-19 07:14:18 +10:00
md_5
d68ebd1eaf Minecraft 1.20.2-rc1 support 2023-09-17 08:10:42 +10:00
dependabot[bot]
a7cd79eb41 #3516: Bump org.apache.maven.plugins:maven-javadoc-plugin from 3.5.0 to 3.6.0
Bumps [org.apache.maven.plugins:maven-javadoc-plugin](https://github.com/apache/maven-javadoc-plugin) from 3.5.0 to 3.6.0.
- [Release notes](https://github.com/apache/maven-javadoc-plugin/releases)
- [Commits](https://github.com/apache/maven-javadoc-plugin/compare/maven-javadoc-plugin-3.5.0...maven-javadoc-plugin-3.6.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-javadoc-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-16 10:22:07 +10:00
Outfluencer
9e83ee6f0c #3508: Use same compression threshold checks as Vanilla 2023-09-12 20:29:01 +10:00
dependabot[bot]
7c81d91740 #3513: Bump org.apache.maven.plugins:maven-enforcer-plugin from 3.4.0 to 3.4.1
Bumps [org.apache.maven.plugins:maven-enforcer-plugin](https://github.com/apache/maven-enforcer) from 3.4.0 to 3.4.1.
- [Release notes](https://github.com/apache/maven-enforcer/releases)
- [Commits](https://github.com/apache/maven-enforcer/compare/enforcer-3.4.0...enforcer-3.4.1)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-enforcer-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-12 20:28:08 +10:00
md_5
5b126b7f4d Fix javadoc plugin version in non-dist builds 2023-09-10 11:41:56 +10:00
dependabot[bot]
9fe7d21f4b #3510: Bump actions/checkout from 3 to 4
Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-08 19:33:56 +10:00
dependabot[bot]
94ea0271ba #3505: Bump io.netty:netty-bom from 4.1.96.Final to 4.1.97.Final
Bumps [io.netty:netty-bom](https://github.com/netty/netty) from 4.1.96.Final to 4.1.97.Final.
- [Commits](https://github.com/netty/netty/compare/netty-4.1.96.Final...netty-4.1.97.Final)

---
updated-dependencies:
- dependency-name: io.netty:netty-bom
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-24 20:07:19 +10:00
dependabot[bot]
3af672d2f2 #3504: Bump org.apache.maven.plugins:maven-enforcer-plugin from 3.3.0 to 3.4.0
Bumps [org.apache.maven.plugins:maven-enforcer-plugin](https://github.com/apache/maven-enforcer) from 3.3.0 to 3.4.0.
- [Release notes](https://github.com/apache/maven-enforcer/releases)
- [Commits](https://github.com/apache/maven-enforcer/compare/enforcer-3.3.0...enforcer-3.4.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-enforcer-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-24 20:07:00 +10:00
md_5
0dd7b98428 Bump version to 1.20-R0.2-SNAPSHOT 2023-08-07 08:01:47 +10:00
md_5
a793692a2c Release 1.20-R0.1 2023-08-07 07:56:00 +10:00
dependabot[bot]
23fb838227 #3493: Bump io.netty:netty-bom from 4.1.95.Final to 4.1.96.Final
Bumps [io.netty:netty-bom](https://github.com/netty/netty) from 4.1.95.Final to 4.1.96.Final.
- [Commits](https://github.com/netty/netty/compare/netty-4.1.95.Final...netty-4.1.96.Final)

---
updated-dependencies:
- dependency-name: io.netty:netty-bom
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-02 20:01:19 +10:00
dependabot[bot]
2d6d89d668 #3492: Bump io.netty:netty-bom from 4.1.94.Final to 4.1.95.Final
Bumps [io.netty:netty-bom](https://github.com/netty/netty) from 4.1.94.Final to 4.1.95.Final.
- [Commits](https://github.com/netty/netty/compare/netty-4.1.94.Final...netty-4.1.95.Final)

---
updated-dependencies:
- dependency-name: io.netty:netty-bom
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-24 18:46:54 +10:00
BoomEaro
0199cb90ff #3489: Add command string length limit when decoding ClientCommand 2023-07-15 10:44:41 +10:00
dependabot[bot]
958cef5084 #3488: Bump scriptus from 0.4.1 to 0.5.0
Bumps [scriptus](https://github.com/SpigotMC/Scriptus) from 0.4.1 to 0.5.0.
- [Commits](https://github.com/SpigotMC/Scriptus/commits)

---
updated-dependencies:
- dependency-name: net.md-5:scriptus
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-15 10:29:22 +10:00
Outfluencer
9f5ace9025 #3418: Add tab completion for bungee command names in pre-1.13 versions 2023-07-05 19:58:23 +10:00
dependabot[bot]
3a6e2631bf #3479: Bump netty-bom from 4.1.93.Final to 4.1.94.Final
Bumps [netty-bom](https://github.com/netty/netty) from 4.1.93.Final to 4.1.94.Final.
- [Commits](https://github.com/netty/netty/compare/netty-4.1.93.Final...netty-4.1.94.Final)

---
updated-dependencies:
- dependency-name: io.netty:netty-bom
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-03 18:08:33 +10:00
md_5
c7adcf9fdf Disable maven enforcer for now 2023-06-18 20:55:47 +10:00
md_5
da3616e636 SPIGOT-7400: Downgrade maven-resolver due to issues resolving certain depends 2023-06-18 20:37:33 +10:00
dependabot[bot]
b371fe67a5 #3478: Bump maven-shade-plugin from 3.4.1 to 3.5.0
Bumps [maven-shade-plugin](https://github.com/apache/maven-shade-plugin) from 3.4.1 to 3.5.0.
- [Release notes](https://github.com/apache/maven-shade-plugin/releases)
- [Commits](https://github.com/apache/maven-shade-plugin/compare/maven-shade-plugin-3.4.1...maven-shade-plugin-3.5.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-shade-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-17 07:59:06 +10:00
Outfluencer
6324c7d527 #3401: Only synchronize necessary parts of the BungeeServerInfo#sendData method 2023-06-10 18:06:37 +10:00
Outfluencer
6263fe283b #3426: Made find command output hover and clickable 2023-06-10 18:03:02 +10:00
Ruan
9a7617f9b8 #3475: Add KickPlayerRaw channel 2023-06-10 18:01:01 +10:00
Janmm14
9a71358dfa #3439: Add GetPlayerServer bungee plugin message subchannel 2023-06-10 18:00:33 +10:00
Outfluencer
a96a2e80a1 #3437: Remove unused enum in ServerConnector and add color to exception message 2023-06-10 17:58:14 +10:00
md_5
68200133b6 Minecraft 1.20 support 2023-06-08 01:30:00 +10:00
dependabot[bot]
188d502c59 #3469: Bump netty-bom from 4.1.92.Final to 4.1.93.Final
Bumps [netty-bom](https://github.com/netty/netty) from 4.1.92.Final to 4.1.93.Final.
- [Commits](https://github.com/netty/netty/compare/netty-4.1.92.Final...netty-4.1.93.Final)

---
updated-dependencies:
- dependency-name: io.netty:netty-bom
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-05-26 18:45:35 +10:00
dependabot[bot]
84ac683c1d #3468: Bump lombok from 1.18.26 to 1.18.28
Bumps [lombok](https://github.com/projectlombok/lombok) from 1.18.26 to 1.18.28.
- [Release notes](https://github.com/projectlombok/lombok/releases)
- [Changelog](https://github.com/projectlombok/lombok/blob/master/doc/changelog.markdown)
- [Commits](https://github.com/projectlombok/lombok/compare/v1.18.26...v1.18.28)

---
updated-dependencies:
- dependency-name: org.projectlombok:lombok
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-05-26 18:45:21 +10:00
dependabot[bot]
b418c94215 #3467: Bump maven-source-plugin from 3.2.1 to 3.3.0
Bumps [maven-source-plugin](https://github.com/apache/maven-source-plugin) from 3.2.1 to 3.3.0.
- [Commits](https://github.com/apache/maven-source-plugin/compare/maven-source-plugin-3.2.1...maven-source-plugin-3.3.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-source-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-05-24 07:38:43 +10:00
dependabot[bot]
38e593a698 #3466: Bump maven-checkstyle-plugin from 3.2.2 to 3.3.0
Bumps [maven-checkstyle-plugin](https://github.com/apache/maven-checkstyle-plugin) from 3.2.2 to 3.3.0.
- [Commits](https://github.com/apache/maven-checkstyle-plugin/compare/maven-checkstyle-plugin-3.2.2...maven-checkstyle-plugin-3.3.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-checkstyle-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-05-24 07:38:27 +10:00
Janmm14
38028e8e90 #3455: Don't lock connections for offline uuid lookup when given uuid is not offline mode 2023-05-20 11:27:59 +10:00
md_5
3db27052a1 Bump maven-resolver dependencies 2023-05-20 11:13:38 +10:00
dependabot[bot]
e24f9223df #3464: Bump maven-gpg-plugin from 3.0.1 to 3.1.0
Bumps [maven-gpg-plugin](https://github.com/apache/maven-gpg-plugin) from 3.0.1 to 3.1.0.
- [Commits](https://github.com/apache/maven-gpg-plugin/compare/maven-gpg-plugin-3.0.1...maven-gpg-plugin-3.1.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-gpg-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-05-20 11:09:14 +10:00
dependabot[bot]
9e5ed82c99 #3461: Bump netty-bom from 4.1.91.Final to 4.1.92.Final
Bumps [netty-bom](https://github.com/netty/netty) from 4.1.91.Final to 4.1.92.Final.
- [Release notes](https://github.com/netty/netty/releases)
- [Commits](https://github.com/netty/netty/compare/netty-4.1.91.Final...netty-4.1.92.Final)

---
updated-dependencies:
- dependency-name: io.netty:netty-bom
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-30 12:43:52 +10:00
dependabot[bot]
606fa278c4 #3460: Bump maven-checkstyle-plugin from 3.2.1 to 3.2.2
Bumps [maven-checkstyle-plugin](https://github.com/apache/maven-checkstyle-plugin) from 3.2.1 to 3.2.2.
- [Release notes](https://github.com/apache/maven-checkstyle-plugin/releases)
- [Commits](https://github.com/apache/maven-checkstyle-plugin/compare/maven-checkstyle-plugin-3.2.1...maven-checkstyle-plugin-3.2.2)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-checkstyle-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-21 18:02:56 +10:00
md_5
7dd549ff1e Add maven-enforcer-plugin for dependency convergence 2023-04-20 07:41:22 +10:00
md_5
3c12b04c98 Update dependabot.yml 2023-04-20 07:35:29 +10:00
dependabot[bot]
5545850f9d #3459: Bump mysql-connector-j from 8.0.32 to 8.0.33
Bumps [mysql-connector-j](https://github.com/mysql/mysql-connector-j) from 8.0.32 to 8.0.33.
- [Release notes](https://github.com/mysql/mysql-connector-j/releases)
- [Changelog](https://github.com/mysql/mysql-connector-j/blob/release/8.0/CHANGES)
- [Commits](https://github.com/mysql/mysql-connector-j/compare/8.0.32...8.0.33)

---
updated-dependencies:
- dependency-name: com.mysql:mysql-connector-j
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-20 07:26:54 +10:00
dependabot[bot]
2f909b44d7 #3458: Bump maven-resolver-transport-http from 1.9.7 to 1.9.8
Bumps [maven-resolver-transport-http](https://github.com/apache/maven-resolver) from 1.9.7 to 1.9.8.
- [Release notes](https://github.com/apache/maven-resolver/releases)
- [Commits](https://github.com/apache/maven-resolver/compare/maven-resolver-1.9.7...maven-resolver-1.9.8)

---
updated-dependencies:
- dependency-name: org.apache.maven.resolver:maven-resolver-transport-http
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-20 07:26:41 +10:00
dependabot[bot]
ff155ebbb4 #3457: Bump maven-resolver-connector-basic from 1.9.7 to 1.9.8
Bumps [maven-resolver-connector-basic](https://github.com/apache/maven-resolver) from 1.9.7 to 1.9.8.
- [Release notes](https://github.com/apache/maven-resolver/releases)
- [Commits](https://github.com/apache/maven-resolver/compare/maven-resolver-1.9.7...maven-resolver-1.9.8)

---
updated-dependencies:
- dependency-name: org.apache.maven.resolver:maven-resolver-connector-basic
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-20 07:26:26 +10:00
md_5
a0a4fa0e56 Add profile for Java 20 compilation of bootstrap 2023-04-07 09:55:01 +10:00
dependabot[bot]
1b76a26691 #3456: Bump netty-bom from 4.1.90.Final to 4.1.91.Final
Bumps [netty-bom](https://github.com/netty/netty) from 4.1.90.Final to 4.1.91.Final.
- [Release notes](https://github.com/netty/netty/releases)
- [Commits](https://github.com/netty/netty/compare/netty-4.1.90.Final...netty-4.1.91.Final)

---
updated-dependencies:
- dependency-name: io.netty:netty-bom
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-07 09:01:03 +10:00
md_5
bd7bd2739a Update Github actions to ubuntu-22.04 2023-04-04 07:20:07 +10:00
md_5
a7ad407f4b Update dependencies 2023-04-02 14:08:27 +10:00
dependabot[bot]
931ff0fde6 #3452: Bump animal-sniffer-maven-plugin from 1.22 to 1.23
Bumps [animal-sniffer-maven-plugin](https://github.com/mojohaus/animal-sniffer) from 1.22 to 1.23.
- [Release notes](https://github.com/mojohaus/animal-sniffer/releases)
- [Commits](https://github.com/mojohaus/animal-sniffer/compare/animal-sniffer-parent-1.22...1.23)

---
updated-dependencies:
- dependency-name: org.codehaus.mojo:animal-sniffer-maven-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-02 12:59:50 +10:00
md_5
dfd847f705 Update native libraries 2023-03-25 11:14:25 +11:00
md_5
a1fee720b9 Deprecate string join 2023-03-25 11:00:30 +11:00
md_5
963854f8d5 Remove use of internal gson API 2023-03-25 11:00:30 +11:00
Janmm14
2ef5e7004b #3451: Improve length field prepending on bungee -> server connection
Use alternative implementation of Varint21LengthFieldPrepender on bungee -> server connection for improved speed - it uses separate buffer to prepend the length to avoid copying large data buffer.
Not applied bungee -> client because encrypting 1-5 bytes of length separately through expensive jni call could make it not worth (not measured).
2023-03-25 11:00:30 +11:00
Janmm14
2e6f0dd442 #3450: Use readRetainedSlice method instead of slice+retain+skip 2023-03-23 20:57:53 +11:00
Outfluencer
7790783949 #3436, #3441: Check if server icon image is null 2023-03-15 18:44:36 +11:00
md_5
f4534c8273 #3446: Fix < 1.19 support 2023-03-15 18:41:25 +11:00
md_5
76673f02a4 Apply dependabot configuration 2023-03-15 18:18:15 +11:00
md_5
b47ae0944c #3444: Use same duplicate player handling for online and offline modes 2023-03-15 07:41:50 +11:00
md_5
f9712cbc7c Minecraft 1.19.4 support 2023-03-15 03:30:00 +11:00
md_5
1b6d845530 Update lombok and maven shade 2023-02-11 10:26:59 +11:00
Outfluencer
19424aba9d #3430: Add new fallback field to TranslatableComponent 2023-01-28 11:32:59 +11:00
Outfluencer
71ac9b34fa #3425: Make ip command output clickable to copy ip 2023-01-28 11:19:45 +11:00
Achsion
7651d4a249 #3423: Remove empty servers from glist by default 2023-01-28 11:15:40 +11:00
md_5
f8e0bccdf0 Update README date 2023-01-01 11:17:02 +11:00
Outfluencer
a5b6eb6afa #3417: Support uppercase &h in Alert command 2022-12-23 10:54:57 +11:00
MrKeith
41471da9db #3405: Fix typo in ProxiedPlayer docs and add docs to ServerDisconnectEvent 2022-12-21 18:41:55 +11:00
md_5
e71767688d #3408: ConcurrentModificationException when player quits 2022-12-08 07:09:20 +11:00
md_5
5467e3a842 Minecraft 1.19.3 support 2022-12-08 03:00:00 +11:00
Ismael Hanbel
511017ab35 #3396: Update Netty version 2022-11-12 11:52:30 +11:00
floge07
c3e8cfac79 #3374, #3389: Improve log handling of normal java.util Logger usage by forwarding the LogRecords directly to the BungeeLogger instead of the fallback err stream. 2022-11-12 11:51:14 +11:00
rgnter
bf2b3c68f8 #3384: Update documentation of ProxyPingEvent 2022-11-12 11:43:29 +11:00
Outfluencer
68e74a8c03 #3378: Remove KickStringWriter from the pipeline after handshake arrives 2022-11-12 11:41:10 +11:00
Outfluencer
5b4a540440 #3361: Cache MessageFormats for translations 2022-11-12 11:39:31 +11:00
osfanbuff63
88da5c05c7 #3353: Update GitHub actions
Updates `actions/checkout` and `actions/setup-java` to v3.
2022-11-12 11:34:17 +11:00
md_5
2d369e8945 Update SnakeYAML version 2022-10-02 09:18:42 +11:00
md_5
02548c4b9b Update Netty/SnakeYAML version 2022-09-22 10:16:27 +10:00
Outfluencer
71990e3ccc #3387: Use the correct write method for ChatChain in ClientCommand 2022-08-27 07:40:18 +10:00
Outfluencer
5e7dcc48b9 #3382: Use the correct write method for ChatChain in ClientChat packet 2022-08-20 16:22:14 +10:00
Outfluencer
5cdba87b87 #3377: Add additional checks for protocol length limits 2022-08-16 19:26:33 +10:00
Outfluencer
696315615d #3366: Improve consistency and appearance of default translations 2022-08-14 11:34:00 +10:00
Outfluencer
dd3f820040 #3363, #3369: Implement new ServerData packet to stop MOTD data from servers 2022-08-14 11:32:35 +10:00
md_5
78ca16dfe3 Minecraft 1.19.1 support 2022-07-28 04:00:00 +10:00
Noah
adc32d5a5c #3367: Add linux aarch64 native epoll support 2022-07-23 18:53:52 +10:00
Outfluencer
12e4514813 #3355,#3357: Fix possible NPE's in LoginEvent & PreLoginEvent 2022-07-12 21:47:57 +10:00
Ivan Pekov
587fb37bdf #3192, #3210: Handle null ServerPing#getPlayers upon a legacy ping 2022-07-02 10:35:54 +10:00
Kevin Ludwig
d221e52929 #3241: Support ping passthrough for legacy pings 2022-07-02 10:27:36 +10:00
FlorianMichael
e151a6cf92 #3156: Add kick module 2022-07-02 10:11:09 +10:00
Outfluencer
9ced5ce131 #3287: Fix HttpHandler calls done method twice 2022-07-02 10:02:16 +10:00
tsuoihito
c8e876bfe2 #3342: Fix sanitized address being not IP but hostname after InetSocketAddress#getHostName() 2022-06-30 21:28:37 +10:00
Janmm14
2a716bbc7f #3344: Fix legacy chat conversion losing format reset information.
In legacy chat format, colors and reset do not retain any formatting.

In order to prevent this behaviour from creating unnecessary long json containing many redundant `formatting: false`, the original `fromLegacyText(...)` idea was to just override the color to white and handle the format reset just internally.

However eventual previous format rejection (aka reset) information was lost when appending multiple legacy format strings to a `ComponentBuilder`.

With this change we save the "reset wish" in the `BaseComponent` and update `ComponentBuilder`'s append function to not copy over formatting if the component has the reset flag set.
2022-06-30 21:22:16 +10:00
Janmm14
00590b6c0d #3343: Create GitHub issue templates 2022-06-30 21:18:12 +10:00
md_5
2ff4be7846 Update gson to 2.8.9 2022-06-28 21:40:53 +10:00
md_5
ff5727c5ef Revert broken chat PR and align with Spigot 2022-06-08 19:37:15 +10:00
Brokkonaut
e46bc343e4 #3319: Do not forward cancelled messages or handled commands 2022-06-08 17:44:08 +10:00
Lukas Alt
5972fd2353 #3318: Fixed system messages shown in action bar for MC 1.19 clients 2022-06-08 11:23:41 +10:00
bob7l
8c0e4b1d33 #3315: Further fix for offline mode support 2022-06-08 10:05:06 +10:00
md_5
a737a754d1 Downgrade dependency version 2022-06-08 09:01:05 +10:00
md_5
fc8685a042 #3311: Fix chat handling on older versions 2022-06-08 08:30:37 +10:00
md_5
cc4765b4fe #3313: Fix offline mode support 2022-06-08 08:22:46 +10:00
md_5
eccdf87f22 Minecraft 1.19 support 2022-06-08 02:00:00 +10:00
md_5
862bb2ac72 #3258: Only show detailed connect exception to admins 2022-04-09 08:59:01 +10:00
Outfluencer
34d416a4e8 #3261: Remove unused AttributeKeys
These attribute keys are not used so we can remove them
2022-03-19 10:05:23 +11:00
Outfluencer
410f64bc9f #3268: Correct plugin message size check 2022-03-19 10:04:45 +11:00
Outfluencer
978e68fc74 #3265: Print all thrown exception
DecoderExceptions that are not a CorruptedFrameException and dont have BadPacketException or OverflowPacketException as cause are not printed.
I also removed the ID message in BadPacketException because bad packet does not mean it has a invalid id the protocol version can also be not valid or the packet was not read to the end and more details are in the message of the exception
2022-03-19 10:04:40 +11:00
Outfluencer
a17d8f8a66 #3264: Negative packet ids are also outside of range 2022-03-09 11:21:07 +11:00
md_5
7e47490e70 Minecraft 1.18.2 support 2022-03-01 02:00:00 +11:00
nnnnt21
f4f94d3b56 #3256: Allow - and . in online mode as some accounts still have these usernames 2022-02-24 08:06:10 +11:00
md_5
eae9d45c8a Provide more information in connect errors 2022-02-06 08:44:55 +11:00
md_5
d2d157c1fe #3246: Fix commands not working due to MinecraftForge changes 2022-02-06 08:26:09 +11:00
Outfluencer
9c95d4ba43 #3226: Add console command name tab completion 2022-01-02 10:13:48 +11:00
md_5
6cbd7404f4 Fix checkstyle paren pad settings 2022-01-02 10:13:48 +11:00
md_5
ad8a8ef5a9 Increase per-listener event bus warning time 2022-01-01 09:22:26 +11:00
md_5
e6766a1ee2 Update README date 2022-01-01 08:50:50 +11:00
Janmm14
b4ccdaa51c #2715: Improve BadPacketException message in MinecraftDecoder 2021-12-19 09:54:37 +11:00
Janmm14
3a11656909 #3116: Do not fill in LogRecord caller data by default in slf4j wrapper 2021-12-19 09:53:13 +11:00
Janmm14
2479fab632 #3221: Use computeIfAbsent method in EventBus 2021-12-19 09:50:48 +11:00
md_5
51eb1ac623 Dependency upgrades 2021-12-18 12:18:21 +11:00
md_5
879f37f046 Upgrade to SnakeYAML 1.30 release 2021-12-18 11:36:05 +11:00
md_5
f2aadd6014 #3223: Only rewrite spectate packet if no IP forwarding 2021-12-13 08:25:54 +11:00
md_5
1ad81504ca Update native cipher 2021-12-10 15:54:39 +11:00
Janmm14
425ee4e142 #3215: Add time measurement per event listener method 2021-12-05 08:51:33 +11:00
Valtn
42d8300bb7 #3220: Fix server list info being cached permanently 2021-12-05 08:04:26 +11:00
md_5
a9d75c5255 Minecraft 1.18 support 2021-12-01 03:00:00 +11:00
md_5
98afd548d1 Minecraft 1.18-rc3 support 2021-11-27 08:00:00 +11:00
md_5
7fc256dba7 Minecraft 1.18-pre8 support 2021-11-25 08:00:00 +11:00
md_5
21b23624ad #3159: Account for the (broken) configuration when ip forward is enabled on bungee but not the server 2021-11-23 15:27:31 +11:00
md_5
1ace5c0c8b Trial snapshot SnakeYAML version 2021-11-23 08:30:38 +11:00
md_5
bee99beab1 Downgrade to Checkstyle 8.x as 9.x series has much larger memory usage 2021-11-22 15:27:24 +11:00
md_5
8b363d3d1f Minecraft 1.18-pre5 support 2021-11-22 09:00:00 +11:00
PSNRigner
c7b0c3cd48 #3207: Rework the plugin message relaying system to allow unregistering channels 2021-11-12 19:38:47 +11:00
md_5
c0c9b28582 Update snapshot support to 1.18-pre1 2021-11-12 19:37:57 +11:00
Frank van der Heijden
c3fffbc919 #3205: Don't forward tab completions if the root command is a bungee command 2021-11-04 18:45:11 +11:00
md_5
6613aaea95 Add test fix for library classes being visible to non-dependent plugins 2021-10-09 18:02:58 +11:00
riku6460
53ce6b93a2 #3200: Fix protocol for 21w40a 2021-10-09 18:00:36 +11:00
Janmm14
d8e293842f #2466: Use switch in "BungeeCord" plugin message handling 2021-10-09 09:25:29 +11:00
MrMicky
5cf869df1a #3198: Remove terminally deprecated SecurityManager
See https://openjdk.java.net/jeps/411
2021-10-09 09:25:29 +11:00
md_5
f26f7d8809 Add optional 1.18 (21w40a) snapshot protocol support
Accessible via the net.md_5.bungee.protocol.snapshot JVM property.
2021-10-09 09:25:28 +11:00
Outfluencer
c5a90475af #3195: Remove unused translations
Both translations are not used in BungeeCord or any modules.
2021-09-25 08:10:28 +10:00
Outfluencer
3008d7ef2f #3189: Improve username validation 2021-09-25 08:09:47 +10:00
Outfluencer
1823f86dbb #3190: Improve login protocol state machine
Prevents repetition of packets
2021-09-17 18:16:01 +10:00
Janmm14
06bf088d27 #3186: Replace String.format calls in exceptions with simple string concats 2021-09-17 18:14:21 +10:00
md_5
9953698a7c Add GitHub Java 17 build 2021-09-16 07:43:13 +10:00
md_5
bda1605627 Minor formatting fixes 2021-07-22 11:46:41 +10:00
Outfluencer
2e0e88db0d #3158: Remove redundant protocol version check in the TabCompleteResponse packet
No need for the second if in the read and write method use a else instead
2021-07-22 11:43:03 +10:00
Outfluencer
96482cc0cf #3157: Read only 20 chars for clients below 1.13 in PluginMessages
20 chars is the vanilla limit for all clients below 1.13. We should use this value.
2021-07-22 11:42:48 +10:00
Outfluencer
a283aaf724 #3153: Add color support to the end command 2021-07-18 10:22:17 +10:00
Adrian Antkowiak
5db276eb52 #3147: HAProxyMessage.sourceAddress() can be null
.sourceAddress() is null when send-proxy-v2 & check option is used
2021-07-11 09:06:51 +10:00
md_5
c866619f56 Minecraft 1.17.1 support 2021-07-07 00:00:00 +10:00
Outfluencer
b9da505efe #3142: Remove redundant name length check in InitialHandler
This check is not needed anymore as the player gets kicked while reading the LoginRequest packet if the name length is longer than 16
2021-07-04 09:40:47 +10:00
md_5
061a7c67bd Update checkstyle 2021-07-03 11:17:12 +10:00
Ivan Pekov
6f7331e852 #3138, 3140: Check for the new leak detector netty flag 2021-06-30 19:00:22 +10:00
md_5
1b489bcc11 Attempt to fix java 8 native crash 2021-06-26 11:39:53 +10:00
md_5
da27924a49 #3115, #3125: Update natives build script, switch to Cloudflare zlib 2021-06-26 11:31:05 +10:00
Outfluencer
15b39887c5 #3133: Directly disconnect on illegal chars 2021-06-26 10:09:17 +10:00
Janmm14
f9583a7652 #3129: Replace ConnectTimeoutException with a more user-friendly string. 2021-06-26 10:06:12 +10:00
Janmm14
cb738188de #3126: Use suppliers instead of reflection for native impl generation. 2021-06-26 10:01:30 +10:00
Outfluencer
a8b2f5268d #3123: Apply exact vanilla string length limits for tab completion 2021-06-20 08:51:55 +10:00
Outfluencer
ad50fc9ad3 #3111: Check chat for illegal chars & moved length check into the packet class 2021-06-15 09:07:20 +10:00
md_5
a25c2b325b Fix typo in previous commit 2021-06-13 11:26:18 +10:00
md_5
c57bf61114 #3113: Remove unnecessary slice in PacketDecompressor
Thanks @lokha for the profiling and suggestion.
2021-06-13 08:32:25 +10:00
md_5
b7935d4b14 Downgrade SnakeYAML due to issues with comments parsing 2021-06-11 21:13:42 +10:00
Janmm14
00982f3620 #3104: Use lambdas rather than reflection to create packets 2021-06-11 16:55:02 +10:00
Lukas Alt
088b2045d0 #3109: Made file log level configurable 2021-06-10 08:42:48 +10:00
Antoine L
633ff1cfc8 #3107: Fix action bar messages in 1.17 2021-06-09 18:58:20 +10:00
md_5
6cda6b6c10 Update SnakeYAML and Netty 2021-06-09 18:56:38 +10:00
md_5
90573625f1 Minecraft 1.17 support 2021-06-09 09:00:00 +10:00
Janmm14
d49e97c423 #3099: Improve toArray calls by using an empty array as parameter.
From Intellij IDEA inspections: Since late updates of OpenJDK 6 this call was intrinsified, making the performance of the empty array version the same and sometimes even better, compared to the pre-sized version.
2021-05-28 08:23:43 +10:00
md_5
39a80e414e #3093: Support names with '.', block names with ' ' 2021-05-26 10:31:37 +10:00
md_5
ab9153ddc3 Further increase length limit for TO_CLIENT chat packets 2021-05-26 10:31:26 +10:00
md_5
7ec1f487c1 Remove ipv6 scope from forwarded addresses
Affects forwarding when epoll enabled
2021-05-25 18:42:10 +10:00
md_5
c96628b72e #3094: Fix TO_CLIENT max Chat string length 2021-05-21 17:45:55 +10:00
md_5
e5ded9a2fb Apply stricter length limits to client strings
Also bump snapshot version and remove redundant file header
2021-05-21 08:16:55 +10:00
md_5
5823f47467 #3090: Register events in parent classes 2021-05-19 18:41:09 +10:00
Janmm14
a0b7f09252 #3087: Force-enable multi-release jar file support for JDK9+ via System property 2021-05-18 20:34:53 +10:00
md_5
b60a30c705 Move additional dependencies to runtime scope 2021-05-16 18:09:04 +10:00
md_5
4fc1a9e770 Dependency bump 2021-05-15 17:22:35 +10:00
md_5
f0908b663f Add optional 1.17 (21w19a) snapshot protocol support
Accessible via the net.md_5.bungee.protocol.snapshot JVM property.
2021-05-15 09:31:07 +10:00
md_5
5fa596fee9 #3084: (Regrettably) add a full SLF4J wrapper 2021-05-14 08:51:09 +10:00
md_5
ada1b95ffc Remove redundant entity rewriting code on > 1.16.2 2021-05-12 07:59:50 +10:00
Luck
72b3bdf676 #3077: Fix regression preventing child classloaders delegating to a PluginClassloader
Bug was introduced in 425dd45109
2021-05-01 08:32:51 +10:00
Janmm14
71d1246374 #3066: Put ReadTimeoutHandler after frame decoder.
This reduces the impact of attacks that send a large packet size first and then send data very slowly but frequently enough to not trigger a timeout (as the timeout handler was before the Varint21FrameDecoder). This causes connections to stay open for a long time without much effort from an attacker, while the packet never leaves the Varint21FrameDecpder stage of the netty pipeline (causing no additional checks to happen and no logs of the connection to be created).

This will not have an impact on bad connections as without recieving full packets the underlying spigot server would timeout instead.
2021-04-28 16:52:00 +10:00
_tomcraft
ac371bb596 #3073: Release HAProxyMessage after read 2021-04-28 08:07:17 +10:00
md_5
830ee8f27d #3061: Continue to fallback to underlying URLClassLoader 2021-04-10 07:30:17 +10:00
md_5
425dd45109 Override classloader close method for completeness 2021-04-09 15:38:21 +10:00
md_5
6a039de8db Add preview of automatic library support
Example plugin.yml usage:
```
    libraries:
      - com.squareup.okhttp3:okhttp:4.9.0
```

Libraries will only be accessible to plugins and their transitive depends, allowing for multiple versions of the same library to be used by different plugins.

This is a preview feature. Feedback is welcome so that it may be refined before being made widely available.
2021-04-09 13:13:55 +10:00
md_5
8d783aa172 #3058: Remove world limit 2021-04-06 08:18:58 +10:00
md_5
a4e5f5005b Add full support for building on JDK [15,) 2021-04-04 17:24:23 +10:00
Zach Levis
a7c6edeb63 #3041: Respond to login query requests in a way that matches the Vanilla client 2021-02-26 11:28:05 +11:00
Janmm14
4f23b49fef #3037: Update ProxiedPlayer#setDisplayName javadoc to current behaviour 2021-02-14 09:37:07 +11:00
md_5
cfcc8b1a6f Pin GitHub workflow build to ubuntu-20.04 2021-02-14 09:35:07 +11:00
md_5
ebec582ce2 Add full support for building on JDK [8, 14] 2021-02-14 09:29:55 +11:00
md_5
3d701fbe0e #3028: Add protocol level string length limits 2021-01-25 15:54:27 +11:00
md_5
e95da11115 Bump Netty/SnakeYAML/MySQL versions 2021-01-24 08:56:07 +11:00
md_5
9f6a798ea6 Bump version to 1.16-R0.5-SNAPSHOT 2021-01-15 10:19:24 +11:00
md_5
36c8df4d2f Release 1.16-R0.4 2021-01-15 09:49:36 +11:00
blablubbabc
baf2f60850 #3018: Serialize text component properties in the same order as Minecraft 2021-01-13 10:17:16 +11:00
md_5
9ac39005f8 Update README date 2021-01-12 09:06:25 +11:00
227 changed files with 9073 additions and 3610 deletions

63
.github/ISSUE_TEMPLATE/bug_report.yml vendored Normal file
View File

@@ -0,0 +1,63 @@
name: Bug inside BungeeCord
description: Create a bug report about a problem inside BungeeCord.
body:
- type: markdown
attributes:
value: |
#### Report a bug inside bungeecord
Issues happening with forks of BungeeCord should **not** be reported here.
- type: input
id: bungee-version
attributes:
label: Bungeecord version
description: The output of the /bungee command (or just the bungee build number) (execute in bungeecord console for easy text copy)
placeholder: e.g. git:BungeeCord-Bootstrap:1.xx-SNAPSHOT:xxxxxxx:xxxx
validations:
required: true
- type: input
id: server-version
attributes:
label: Server version
description: The output of the /version command (execute in server console for easy text copy)
placeholder: "e.g. git-Spigot-xxxxxxx-xxxxxxx (MC: 1.x.x)"
- type: input
id: client-version
attributes:
label: Client version
description: Minecraft Client Version
placeholder: e.g. 1.18.2
- type: textarea
id: bungee-plugins
attributes:
label: Bungeecord plugins
description: Please list all BungeeCord plugins you are using.
validations:
required: true
- type: textarea
id: the-bug
attributes:
label: The bug
description: Please describe the bug. Include **details** you find neccessary. If you just have a question, please ask it in [SpigotMC Forums](https://www.spigotmc.org) and not here.
validations:
required: true
- type: textarea
id: logs
attributes:
label: Log output (links)
description: Please put your log output inbetween three backticks (```` ``` ````). Upload your log files to [gist.github.com](https://gist.github.com) and put them in here.
placeholder: |
```
log output
```
- type: checkboxes
id: checkboxes
attributes:
label: Checking
options:
- label: I am using BungeeCord and **not a fork**. Issues with forks should not be reported here.
required: true
- label: I think this is **not** an issue with a bungeecord plugin.
required: true
- label: I have not read these checkboxes and therefore I just ticked them all.
- label: This is not a question or plugin creation help request.
required: true

14
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@@ -0,0 +1,14 @@
blank_issues_enabled: false
contact_links:
- name: Configuration help
url: https://www.spigotmc.org/forums/bungeecord-help.70/create-thread
about: Help for configuring bungeecord will only be answered in spigotmc.org forums.
- name: I have a problem with a bungee plugin
url: https://www.spigotmc.org/forums/bungeecord-plugin-help.71/create-thread
about: Help about plugins can be recieved in spigotmc.org forums.
- name: Questions and discussions
url: https://www.spigotmc.org/forums/bungeecord-discussion.21/create-thread
about: spigotmc.org forums are the best place to ask your questions regarding bungeecord.
- name: Plugin creation help
url: https://www.spigotmc.org/forums/bungeecord-plugin-development.23/create-thread
about: Plugin creation help for bungee plugins can be recieved in spigotmc.org forums.

View File

@@ -0,0 +1,36 @@
name: Feature request
description: Suggest a feature which bungeecord should include.
body:
- type: textarea
id: the-feature
attributes:
label: Feature description
description: Please describe your feature or improvement. Please include **details**.
validations:
required: true
- type: textarea
id: goal
attributes:
label: Goal of the feature
description: What is the goal of your feature?
validations:
required: true
- type: textarea
id: alternatives
attributes:
label: Unfitting alternatives
description: What alternatives have you considered and why are they not sufficient for your use case?
validations:
required: true
- type: checkboxes
id: checkboxes
attributes:
label: Checking
options:
- label: This is not a question or plugin creation help request.
required: true
- label: This is a **feature or improvement request**.
required: true
- label: I have not read these checkboxes and therefore I just ticked them all.
- label: I did not use this form to report a bug.
required: true

27
.github/dependabot.yml vendored Normal file
View File

@@ -0,0 +1,27 @@
version: 2
updates:
- package-ecosystem: "maven"
directory: "/"
schedule:
interval: "daily"
open-pull-requests-limit: 50
ignore:
# Synchronised with Minecraft
- dependency-name: "com.google.code.gson:gson"
# 9.x has performance issues (see, eg, checkstyle/checkstyle#10934) and 10.x is incompatible
- dependency-name: "com.puppycrawl.tools:checkstyle"
# Newer versions have issues, see #1909 and #2050
- dependency-name: "jline:jline"
# 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"
# Used with maven-resolver dependencies; 2.0 update breaks other providers
- dependency-name: "org.slf4j:slf4j-api"
update-types: ["version-update:semver-major"]
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"
open-pull-requests-limit: 50

View File

@@ -4,18 +4,20 @@ on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
strategy:
fail-fast: false
matrix:
java: [8, 11]
java: [8, 11, 17, 21]
name: Java ${{ matrix.java }}
steps:
- uses: actions/checkout@v2
- uses: actions/setup-java@v1
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
distribution: zulu
java-version: ${{ matrix.java }}
- run: java -version && mvn --version
- run: mvn --activate-profiles dist --no-transfer-progress package

6
.gitmodules vendored Normal file
View File

@@ -0,0 +1,6 @@
[submodule "native/mbedtls"]
path = native/mbedtls
url = https://github.com/ARMmbed/mbedtls.git
[submodule "native/zlib"]
path = native/zlib
url = https://github.com/cloudflare/zlib.git

View File

@@ -23,4 +23,4 @@ Binaries
--------
Precompiled binaries are available for end users on [Jenkins](https://www.spigotmc.org/go/bungeecord-dl).
(c) 2012-2020 SpigotMC Pty. Ltd.
(c) 2012-2023 SpigotMC Pty. Ltd.

View File

@@ -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.16-R0.4-SNAPSHOT</version>
<version>1.20-R0.3-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-api</artifactId>
<version>1.16-R0.4-SNAPSHOT</version>
<version>1.20-R0.3-SNAPSHOT</version>
<packaging>jar</packaging>
<name>BungeeCord-API</name>
@@ -20,25 +19,25 @@
<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-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>
@@ -46,13 +45,33 @@
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-transport-native-unix-common</artifactId>
<version>${netty.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-resolver-provider</artifactId>
<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.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.9.18</version>
<!-- not part of the API proper -->
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>1.26</version>
<version>2.2</version>
<scope>compile</scope>
</dependency>
</dependencies>

View File

@@ -7,6 +7,7 @@ import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Locale;
import java.util.UUID;
/**
@@ -68,6 +69,17 @@ public class Util
return String.format( "0x%02X", i );
}
/**
* Formats an char as a unicode value.
*
* @param c the character to format
* @return the unicode representation of the character
*/
public static String unicode(char c)
{
return "\\u" + String.format( "%04x", (int) c ).toUpperCase( Locale.ROOT );
}
/**
* Constructs a pretty one line version of a {@link Throwable}. Useful for
* debugging.
@@ -76,11 +88,24 @@ public class Util
* @return a string representing information about the {@link Throwable}
*/
public static String exception(Throwable t)
{
return exception( t, true );
}
/**
* Constructs a pretty one line version of a {@link Throwable}. Useful for
* debugging.
*
* @param t the {@link Throwable} to format.
* @param includeLineNumbers whether to include line numbers
* @return a string representing information about the {@link Throwable}
*/
public static String exception(Throwable t, boolean includeLineNumbers)
{
// TODO: We should use clear manually written exceptions
StackTraceElement[] trace = t.getStackTrace();
return t.getClass().getSimpleName() + " : " + t.getMessage()
+ ( ( trace.length > 0 ) ? " @ " + t.getStackTrace()[0].getClassName() + ":" + t.getStackTrace()[0].getLineNumber() : "" );
+ ( ( includeLineNumbers && trace.length > 0 ) ? " @ " + t.getStackTrace()[0].getClassName() + ":" + t.getStackTrace()[0].getLineNumber() : "" );
}
public static String csv(Iterable<?> objects)
@@ -88,6 +113,16 @@ public class Util
return format( objects, ", " );
}
/**
* Returns a string of objects, each separated by a separator.
*
* @param objects the objects to join
* @param separators the separator
* @return joined string
* @see String#join(java.lang.CharSequence, java.lang.Iterable)
* @deprecated use {@link String} join methods
*/
@Deprecated
public static String format(Iterable<?> objects, String separators)
{
return Joiner.on( separators ).join( objects );

View File

@@ -28,18 +28,13 @@ public abstract class AbstractReconnectHandler implements ReconnectHandler
public static ServerInfo getForcedHost(PendingConnection con)
{
if ( con.getVirtualHost() == null )
{
return null;
}
String forced = con.getListener().getForcedHosts().get( con.getVirtualHost().getHostString() );
String forced = ( con.getVirtualHost() == null ) ? null : con.getListener().getForcedHosts().get( con.getVirtualHost().getHostString() );
if ( forced == null && con.getListener().isForceDefault() )
{
forced = con.getListener().getDefaultServer();
}
return ProxyServer.getInstance().getServerInfo( forced );
return ( forced == null ) ? null : ProxyServer.getInstance().getServerInfo( forced );
}
protected abstract ServerInfo getStoredServer(ProxiedPlayer player);

View File

@@ -1,9 +1,10 @@
package net.md_5.bungee.api;
import com.google.common.base.Preconditions;
import com.google.common.io.BaseEncoding;
import com.google.gson.TypeAdapter;
import com.google.gson.internal.bind.TypeAdapters;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
@@ -26,13 +27,26 @@ public class Favicon
@Override
public void write(JsonWriter out, Favicon value) throws IOException
{
TypeAdapters.STRING.write( out, value == null ? null : value.getEncoded() );
if ( value == null )
{
out.nullValue();
} else
{
out.value( value.getEncoded() );
}
}
@Override
public Favicon read(JsonReader in) throws IOException
{
String enc = TypeAdapters.STRING.read( in );
JsonToken peek = in.peek();
if ( peek == JsonToken.NULL )
{
in.nextNull();
return null;
}
String enc = in.nextString();
return enc == null ? null : create( enc );
}
};
@@ -59,6 +73,7 @@ public class Favicon
*/
public static Favicon create(BufferedImage image)
{
Preconditions.checkArgument( image != null, "image is null" );
// check size
if ( image.getWidth() != 64 || image.getHeight() != 64 )
{

View File

@@ -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

View File

@@ -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,26 @@ 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);
}

View File

@@ -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;
@@ -13,9 +14,10 @@ import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.config.ServerInfo;
import net.md_5.bungee.api.event.ServerConnectEvent;
import net.md_5.bungee.api.score.Scoreboard;
import org.jetbrains.annotations.ApiStatus;
/**
* Represents a player who's connection is being connected to somewhere else,
* Represents a player whose connection is being connected to somewhere else,
* whether it be a remote or embedded server.
*/
public interface ProxiedPlayer extends Connection, CommandSender
@@ -57,8 +59,7 @@ public interface ProxiedPlayer extends Connection, CommandSender
String getDisplayName();
/**
* Sets this players display name to be used as their nametag and tab list
* name.
* Sets this player's display name to be used by proxy commands and plugins.
*
* @param name the name to set
*/
@@ -335,6 +336,50 @@ 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);
}

View File

@@ -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 ) );
}
}

View File

@@ -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 ) );
}
}

View File

@@ -8,7 +8,7 @@ import net.md_5.bungee.api.ServerPing;
import net.md_5.bungee.api.connection.PendingConnection;
/**
* Called when the proxy is pinged with packet 0xFE from the server list.
* Called when the proxy is queried for status from the server list.
*/
@Data
@ToString(callSuper = false)

View File

@@ -9,6 +9,13 @@ import net.md_5.bungee.api.config.ServerInfo;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.plugin.Event;
/**
* Called when the player is disconnected from a server, for example during
* server switching.
*
* If the player is kicked from a server, {@link ServerKickEvent} will be called
* instead.
*/
@Data
@AllArgsConstructor
@ToString(callSuper = false)

View File

@@ -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 ) );
}
}

View File

@@ -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)

View File

@@ -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;
}
}

View File

@@ -0,0 +1,123 @@
package net.md_5.bungee.api.plugin;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.maven.repository.internal.MavenRepositorySystemUtils;
import org.eclipse.aether.DefaultRepositorySystemSession;
import org.eclipse.aether.RepositorySystem;
import org.eclipse.aether.artifact.Artifact;
import org.eclipse.aether.artifact.DefaultArtifact;
import org.eclipse.aether.collection.CollectRequest;
import org.eclipse.aether.connector.basic.BasicRepositoryConnectorFactory;
import org.eclipse.aether.graph.Dependency;
import org.eclipse.aether.impl.DefaultServiceLocator;
import org.eclipse.aether.repository.LocalRepository;
import org.eclipse.aether.repository.RemoteRepository;
import org.eclipse.aether.repository.RepositoryPolicy;
import org.eclipse.aether.resolution.ArtifactResult;
import org.eclipse.aether.resolution.DependencyRequest;
import org.eclipse.aether.resolution.DependencyResolutionException;
import org.eclipse.aether.resolution.DependencyResult;
import org.eclipse.aether.spi.connector.RepositoryConnectorFactory;
import org.eclipse.aether.spi.connector.transport.TransporterFactory;
import org.eclipse.aether.transfer.AbstractTransferListener;
import org.eclipse.aether.transfer.TransferCancelledException;
import org.eclipse.aether.transfer.TransferEvent;
import org.eclipse.aether.transport.http.HttpTransporterFactory;
class LibraryLoader
{
private final Logger logger;
private final RepositorySystem repository;
private final DefaultRepositorySystemSession session;
private final List<RemoteRepository> repositories;
public LibraryLoader(Logger logger)
{
this.logger = logger;
DefaultServiceLocator locator = MavenRepositorySystemUtils.newServiceLocator();
locator.addService( RepositoryConnectorFactory.class, BasicRepositoryConnectorFactory.class );
locator.addService( TransporterFactory.class, HttpTransporterFactory.class );
this.repository = locator.getService( RepositorySystem.class );
this.session = MavenRepositorySystemUtils.newSession();
session.setChecksumPolicy( RepositoryPolicy.CHECKSUM_POLICY_FAIL );
session.setLocalRepositoryManager( repository.newLocalRepositoryManager( session, new LocalRepository( "libraries" ) ) );
session.setTransferListener( new AbstractTransferListener()
{
@Override
public void transferStarted(TransferEvent event) throws TransferCancelledException
{
logger.log( Level.INFO, "Downloading {0}", event.getResource().getRepositoryUrl() + event.getResource().getResourceName() );
}
} );
session.setReadOnly();
this.repositories = repository.newResolutionRepositories( session, Arrays.asList( new RemoteRepository.Builder( "central", "default", "https://repo.maven.apache.org/maven2" ).build() ) );
}
public ClassLoader createLoader(PluginDescription desc)
{
if ( desc.getLibraries().isEmpty() )
{
return null;
}
logger.log( Level.INFO, "[{0}] Loading {1} libraries... please wait", new Object[]
{
desc.getName(), desc.getLibraries().size()
} );
List<Dependency> dependencies = new ArrayList<>();
for ( String library : desc.getLibraries() )
{
Artifact artifact = new DefaultArtifact( library );
Dependency dependency = new Dependency( artifact, null );
dependencies.add( dependency );
}
DependencyResult result;
try
{
result = repository.resolveDependencies( session, new DependencyRequest( new CollectRequest( (Dependency) null, dependencies, repositories ), null ) );
} catch ( DependencyResolutionException ex )
{
throw new RuntimeException( "Error resolving libraries", ex );
}
List<URL> jarFiles = new ArrayList<>();
for ( ArtifactResult artifact : result.getArtifactResults() )
{
File file = artifact.getArtifact().getFile();
URL url;
try
{
url = file.toURI().toURL();
} catch ( MalformedURLException ex )
{
throw new AssertionError( ex );
}
jarFiles.add( url );
logger.log( Level.INFO, "[{0}] Loaded library {1}", new Object[]
{
desc.getName(), file
} );
}
URLClassLoader loader = new URLClassLoader( jarFiles.toArray( new URL[ 0 ] ) );
return loader;
}
}

View File

@@ -1,12 +1,23 @@
package net.md_5.bungee.api.plugin;
import com.google.common.base.Preconditions;
import com.google.common.io.ByteStreams;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLClassLoader;
import java.security.CodeSigner;
import java.security.CodeSource;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
import lombok.ToString;
import net.md_5.bungee.api.ProxyServer;
@ToString(of = "desc")
final class PluginClassloader extends URLClassLoader
{
@@ -14,6 +25,10 @@ final class PluginClassloader extends URLClassLoader
//
private final ProxyServer proxy;
private final PluginDescription desc;
private final JarFile jar;
private final Manifest manifest;
private final URL url;
private final ClassLoader libraryLoader;
//
private Plugin plugin;
@@ -22,11 +37,18 @@ final class PluginClassloader extends URLClassLoader
ClassLoader.registerAsParallelCapable();
}
public PluginClassloader(ProxyServer proxy, PluginDescription desc, URL[] urls)
public PluginClassloader(ProxyServer proxy, PluginDescription desc, File file, ClassLoader libraryLoader) throws IOException
{
super( urls );
super( new URL[]
{
file.toURI().toURL()
} );
this.proxy = proxy;
this.desc = desc;
this.jar = new JarFile( file );
this.manifest = jar.getManifest();
this.url = file.toURI().toURL();
this.libraryLoader = libraryLoader;
allLoaders.add( this );
}
@@ -34,17 +56,34 @@ final class PluginClassloader extends URLClassLoader
@Override
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException
{
return loadClass0( name, resolve, true );
return loadClass0( name, resolve, true, true );
}
private Class<?> loadClass0(String name, boolean resolve, boolean checkOther) throws ClassNotFoundException
private Class<?> loadClass0(String name, boolean resolve, boolean checkOther, boolean checkLibraries) throws ClassNotFoundException
{
try
{
return super.loadClass( name, resolve );
Class<?> result = super.loadClass( name, resolve );
// SPIGOT-6749: Library classes will appear in the above, but we don't want to return them to other plugins
if ( checkOther || result.getClassLoader() == this )
{
return result;
}
} catch ( ClassNotFoundException ex )
{
}
if ( checkLibraries && libraryLoader != null )
{
try
{
return libraryLoader.loadClass( name );
} catch ( ClassNotFoundException ex )
{
}
}
if ( checkOther )
{
for ( PluginClassloader loader : allLoaders )
@@ -53,16 +92,81 @@ final class PluginClassloader extends URLClassLoader
{
try
{
return loader.loadClass0( name, resolve, false );
return loader.loadClass0( name, resolve, false, proxy.getPluginManager().isTransitiveDepend( desc, loader.desc ) );
} catch ( ClassNotFoundException ex )
{
}
}
}
}
throw new ClassNotFoundException( name );
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException
{
String path = name.replace( '.', '/' ).concat( ".class" );
JarEntry entry = jar.getJarEntry( path );
if ( entry != null )
{
byte[] classBytes;
try ( InputStream is = jar.getInputStream( entry ) )
{
classBytes = ByteStreams.toByteArray( is );
} catch ( IOException ex )
{
throw new ClassNotFoundException( name, ex );
}
int dot = name.lastIndexOf( '.' );
if ( dot != -1 )
{
String pkgName = name.substring( 0, dot );
if ( getPackage( pkgName ) == null )
{
try
{
if ( manifest != null )
{
definePackage( pkgName, manifest, url );
} else
{
definePackage( pkgName, null, null, null, null, null, null, null );
}
} catch ( IllegalArgumentException ex )
{
if ( getPackage( pkgName ) == null )
{
throw new IllegalStateException( "Cannot find package " + pkgName );
}
}
}
}
CodeSigner[] signers = entry.getCodeSigners();
CodeSource source = new CodeSource( url, signers );
return defineClass( name, classBytes, 0, classBytes.length, source );
}
return super.findClass( name );
}
@Override
public void close() throws IOException
{
try
{
super.close();
} finally
{
jar.close();
}
}
void init(Plugin plugin)
{
Preconditions.checkArgument( plugin != null, "plugin" );

View File

@@ -2,6 +2,8 @@ package net.md_5.bungee.api.plugin;
import java.io.File;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import lombok.AllArgsConstructor;
import lombok.Data;
@@ -48,4 +50,8 @@ public class PluginDescription
* Optional description.
*/
private String description = null;
/**
* Optional libraries.
*/
private List<String> libraries = new LinkedList<>();
}

View File

@@ -4,10 +4,12 @@ import com.google.common.base.Preconditions;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import com.google.common.eventbus.Subscribe;
import com.google.common.graph.GraphBuilder;
import com.google.common.graph.Graphs;
import com.google.common.graph.MutableGraph;
import java.io.File;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Arrays;
import java.util.Collection;
@@ -31,6 +33,7 @@ import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.event.EventBus;
import net.md_5.bungee.event.EventHandler;
import org.yaml.snakeyaml.LoaderOptions;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.Constructor;
import org.yaml.snakeyaml.introspector.PropertyUtils;
@@ -49,6 +52,8 @@ public final class PluginManager
private final Yaml yaml;
private final EventBus eventBus;
private final Map<String, Plugin> plugins = new LinkedHashMap<>();
private final MutableGraph<String> dependencyGraph = GraphBuilder.directed().build();
private final LibraryLoader libraryLoader;
private final Map<String, Command> commandMap = new HashMap<>();
private Map<String, PluginDescription> toLoad = new HashMap<>();
private final Multimap<Plugin, Command> commandsByPlugin = ArrayListMultimap.create();
@@ -60,13 +65,24 @@ public final class PluginManager
this.proxy = proxy;
// Ignore unknown entries in the plugin descriptions
Constructor yamlConstructor = new Constructor();
Constructor yamlConstructor = new Constructor( new LoaderOptions() );
PropertyUtils propertyUtils = yamlConstructor.getPropertyUtils();
propertyUtils.setSkipMissingProperties( true );
yamlConstructor.setPropertyUtils( propertyUtils );
yaml = new Yaml( yamlConstructor );
eventBus = new EventBus( proxy.getLogger() );
LibraryLoader libraryLoader = null;
try
{
libraryLoader = new LibraryLoader( proxy.getLogger() );
} catch ( NoClassDefFoundError ex )
{
// Provided depends were not added back
proxy.getLogger().warning( "Could not initialize LibraryLoader (missing dependencies?)" );
}
this.libraryLoader = libraryLoader;
}
/**
@@ -309,6 +325,7 @@ public final class PluginManager
status = false;
}
dependencyGraph.putEdge( plugin.getName(), dependName );
if ( !status )
{
break;
@@ -320,10 +337,7 @@ public final class PluginManager
{
try
{
URLClassLoader loader = new PluginClassloader( proxy, plugin, new URL[]
{
plugin.getFile().toURI().toURL()
} );
URLClassLoader loader = new PluginClassloader( proxy, plugin, plugin.getFile(), ( libraryLoader != null ) ? libraryLoader.createLoader( plugin ) : null );
Class<?> main = loader.loadClass( plugin.getMain() );
Plugin clazz = (Plugin) main.getDeclaredConstructor().newInstance();
@@ -335,7 +349,7 @@ public final class PluginManager
} );
} catch ( Throwable t )
{
proxy.getLogger().log( Level.WARNING, "Error enabling plugin " + plugin.getName(), t );
proxy.getLogger().log( Level.WARNING, "Error loading plugin " + plugin.getName(), t );
}
}
@@ -463,4 +477,19 @@ public final class PluginManager
{
return Collections.unmodifiableCollection( commandMap.entrySet() );
}
boolean isTransitiveDepend(PluginDescription plugin, PluginDescription depend)
{
Preconditions.checkArgument( plugin != null, "plugin" );
Preconditions.checkArgument( depend != null, "depend" );
if ( dependencyGraph.nodes().contains( plugin.getName() ) )
{
if ( Graphs.reachableNodes( dependencyGraph, plugin.getName() ).contains( depend.getName() ) )
{
return true;
}
}
return false;
}
}

View File

@@ -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() );
}
}

View File

@@ -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 );

View File

@@ -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.contains( "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.contains( "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
}
}

View File

@@ -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 );
}
}
}

View File

@@ -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.16-R0.4-SNAPSHOT</version>
<version>1.20-R0.3-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-bootstrap</artifactId>
<version>1.16-R0.4-SNAPSHOT</version>
<version>1.20-R0.3-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,12 +33,12 @@
</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.2.0</version>
<version>3.3.0</version>
<configuration>
<archive>
<manifestEntries>
@@ -55,7 +52,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.3</version>
<version>3.5.1</version>
<executions>
<execution>
<phase>package</phase>
@@ -79,4 +76,34 @@
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>jdk-9-release</id>
<activation>
<jdk>[9,)</jdk>
</activation>
<properties>
<maven.compiler.release>6</maven.compiler.release>
</properties>
</profile>
<profile>
<id>jdk-12-release</id>
<activation>
<jdk>[12,)</jdk>
</activation>
<properties>
<maven.compiler.release>7</maven.compiler.release>
</properties>
</profile>
<profile>
<id>jdk-20-release</id>
<activation>
<jdk>[20,)</jdk>
</activation>
<properties>
<maven.compiler.release>8</maven.compiler.release>
</properties>
</profile>
</profiles>
</project>

View File

@@ -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.16-R0.4-SNAPSHOT</version>
<version>1.20-R0.3-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-chat</artifactId>
<version>1.16-R0.4-SNAPSHOT</version>
<version>1.20-R0.3-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.8.0</version>
<version>2.10.1</version>
<scope>compile</scope>
</dependency>
</dependencies>

View File

@@ -300,7 +300,7 @@ public final class ChatColor
@Deprecated
public static ChatColor[] values()
{
return BY_CHAR.values().toArray( new ChatColor[ BY_CHAR.values().size() ] );
return BY_CHAR.values().toArray( new ChatColor[ 0 ] );
}
/**

View File

@@ -20,38 +20,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
@@ -78,6 +50,12 @@ public abstract class BaseComponent
@Getter
private HoverEvent hoverEvent;
/**
* Whether this component rejects previous formatting
*/
@Getter
private transient boolean reset;
/**
* Default constructor.
*
@@ -147,31 +125,31 @@ 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.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() );
}
@@ -260,6 +238,29 @@ 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.
*
* @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}
@@ -269,7 +270,7 @@ public abstract class BaseComponent
*/
public ChatColor getColor()
{
if ( color == null )
if ( !style.hasColor() )
{
if ( parent == null )
{
@@ -277,7 +278,7 @@ public abstract class BaseComponent
}
return parent.getColor();
}
return color;
return style.getColor();
}
/**
@@ -288,7 +289,17 @@ public abstract class BaseComponent
*/
public ChatColor getColorRaw()
{
return color;
return style.getColor();
}
/**
* Set this component's font.
*
* @param font the font to set, or null to use the default
*/
public void setFont(String font)
{
this.style.setFont( font );
}
/**
@@ -299,7 +310,7 @@ public abstract class BaseComponent
*/
public String getFont()
{
if ( font == null )
if ( !style.hasFont() )
{
if ( parent == null )
{
@@ -307,7 +318,7 @@ public abstract class BaseComponent
}
return parent.getFont();
}
return font;
return style.getFont();
}
/**
@@ -318,7 +329,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 );
}
/**
@@ -330,11 +351,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();
}
/**
@@ -345,7 +366,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 );
}
/**
@@ -357,11 +388,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();
}
/**
@@ -372,7 +403,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 );
}
/**
@@ -384,11 +425,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();
}
/**
@@ -399,7 +440,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 );
}
/**
@@ -411,11 +463,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();
}
/**
@@ -426,7 +478,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 );
}
/**
@@ -438,11 +500,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();
}
/**
@@ -453,7 +515,48 @@ 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.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)
@@ -492,6 +595,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
*
@@ -499,10 +612,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;
}
/**

View File

@@ -57,7 +57,7 @@ public final class ComponentBuilder
*/
public ComponentBuilder(ComponentBuilder original)
{
this( original.parts.toArray( new BaseComponent[ original.parts.size() ] ) );
this( original.parts.toArray( new BaseComponent[ 0 ] ) );
}
/**
@@ -161,7 +161,7 @@ public final class ComponentBuilder
previous = dummy;
dummy = null;
}
if ( previous != null )
if ( previous != null && !component.isReset() )
{
component.copyFormatting( previous, retention, false );
}
@@ -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.
*
@@ -454,9 +493,32 @@ public final class ComponentBuilder
return this;
}
/**
* Returns the component built by this builder. If this builder is empty, an
* empty text component will be returned.
*
* @return the component
*/
public BaseComponent build()
{
TextComponent base = new TextComponent();
if ( !parts.isEmpty() )
{
List<BaseComponent> cloned = new ArrayList<>( parts );
cloned.replaceAll( BaseComponent::duplicate );
base.setExtra( cloned );
}
return base;
}
/**
* Returns the components needed to display the message created by this
* builder.git
* <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.
*
* @return the created components
*/

View File

@@ -0,0 +1,234 @@
package net.md_5.bungee.api.chat;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.Setter;
import net.md_5.bungee.api.ChatColor;
/**
* Represents a style that may be applied to a {@link BaseComponent}.
*/
@Setter
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode
public final class ComponentStyle implements Cloneable
{
/**
* The color of this style.
*/
private ChatColor color;
/**
* The font of this style.
*/
private String font;
/**
* Whether this style is bold.
*/
private Boolean bold;
/**
* Whether this style is italic.
*/
private Boolean italic;
/**
* Whether this style is underlined.
*/
private Boolean underlined;
/**
* Whether this style is strikethrough.
*/
private Boolean strikethrough;
/**
* Whether this style is obfuscated.
*/
private Boolean obfuscated;
/**
* Returns the color of this style. May return null.
*
* @return the color of this style, or null if default color
*/
public ChatColor getColor()
{
return color;
}
/**
* Returns whether or not this style has a color set.
*
* @return whether a color is set
*/
public boolean hasColor()
{
return ( color != null );
}
/**
* Returns the font of this style. May return null.
*
* @return the font of this style, or null if default font
*/
public String getFont()
{
return font;
}
/**
* Returns whether or not this style has a font set.
*
* @return whether a font is set
*/
public boolean hasFont()
{
return ( font != null );
}
/**
* Returns whether this style is bold.
*
* @return whether the style is bold
*/
public boolean isBold()
{
return ( bold != null ) && bold.booleanValue();
}
/**
* Returns whether this style is bold. May return null.
*
* @return whether the style is bold, or null if not set
*/
public Boolean isBoldRaw()
{
return bold;
}
/**
* Returns whether this style is italic. May return null.
*
* @return whether the style is italic
*/
public boolean isItalic()
{
return ( italic != null ) && italic.booleanValue();
}
/**
* Returns whether this style is italic. May return null.
*
* @return whether the style is italic, or null if not set
*/
public Boolean isItalicRaw()
{
return italic;
}
/**
* Returns whether this style is underlined.
*
* @return whether the style is underlined
*/
public boolean isUnderlined()
{
return ( underlined != null ) && underlined.booleanValue();
}
/**
* Returns whether this style is underlined. May return null.
*
* @return whether the style is underlined, or null if not set
*/
public Boolean isUnderlinedRaw()
{
return underlined;
}
/**
* Returns whether this style is strikethrough
*
* @return whether the style is strikethrough
*/
public boolean isStrikethrough()
{
return ( strikethrough != null ) && strikethrough.booleanValue();
}
/**
* Returns whether this style is strikethrough. May return null.
*
* @return whether the style is strikethrough, or null if not set
*/
public Boolean isStrikethroughRaw()
{
return strikethrough;
}
/**
* Returns whether this style is obfuscated.
*
* @return whether the style is obfuscated
*/
public boolean isObfuscated()
{
return ( obfuscated != null ) && obfuscated.booleanValue();
}
/**
* Returns whether this style is obfuscated. May return null.
*
* @return whether the style is obfuscated, or null if not set
*/
public Boolean isObfuscatedRaw()
{
return obfuscated;
}
/**
* Returns whether this style has no formatting explicitly set.
*
* @return true if no value is set, false if at least one is set
*/
public boolean isEmpty()
{
return color == null && font == null && bold == null
&& italic == null && underlined == null
&& strikethrough == null && obfuscated == null;
}
@Override
public ComponentStyle clone()
{
return new ComponentStyle( color, font, bold, italic, underlined, strikethrough, obfuscated );
}
/**
* Get a new {@link ComponentStyleBuilder}.
*
* @return the builder
*/
public static ComponentStyleBuilder builder()
{
return new ComponentStyleBuilder();
}
/**
* Get a new {@link ComponentStyleBuilder} with values initialized to the
* style values of the supplied {@link ComponentStyle}.
*
* @param other the component style whose values to copy into the builder
* @return the builder
*/
public static ComponentStyleBuilder builder(ComponentStyle other)
{
return new ComponentStyleBuilder()
.color( other.color )
.font( other.font )
.bold( other.bold )
.italic( other.italic )
.underlined( other.underlined )
.strikethrough( other.strikethrough )
.obfuscated( other.obfuscated );
}
}

View File

@@ -0,0 +1,126 @@
package net.md_5.bungee.api.chat;
import net.md_5.bungee.api.ChatColor;
/**
* <p>
* ComponentStyleBuilder simplifies creating component styles by allowing the
* use of a chainable builder.
* </p>
* <pre>
* ComponentStyle style = ComponentStyle.builder()
* .color(ChatColor.RED)
* .font("custom:font")
* .bold(true).italic(true).create();
*
* BaseComponent component = new ComponentBuilder("Hello world").style(style).create();
* // Or it can be used directly on a component
* TextComponent text = new TextComponent("Hello world");
* text.applyStyle(style);
* </pre>
*
* @see ComponentStyle#builder()
* @see ComponentStyle#builder(ComponentStyle)
*/
public final class ComponentStyleBuilder
{
private ChatColor color;
private String font;
private Boolean bold, italic, underlined, strikethrough, obfuscated;
/**
* Set the style color.
*
* @param color the color to set, or null to use the default
* @return this ComponentStyleBuilder for chaining
*/
public ComponentStyleBuilder color(ChatColor color)
{
this.color = color;
return this;
}
/**
* Set the style font.
*
* @param font the font key to set, or null to use the default
* @return this ComponentStyleBuilder for chaining
*/
public ComponentStyleBuilder font(String font)
{
this.font = font;
return this;
}
/**
* Set the style's bold property.
*
* @param bold the bold value to set, or null to use the default
* @return this ComponentStyleBuilder for chaining
*/
public ComponentStyleBuilder bold(Boolean bold)
{
this.bold = bold;
return this;
}
/**
* Set the style's italic property.
*
* @param italic the italic value to set, or null to use the default
* @return this ComponentStyleBuilder for chaining
*/
public ComponentStyleBuilder italic(Boolean italic)
{
this.italic = italic;
return this;
}
/**
* Set the style's underlined property.
*
* @param underlined the underlined value to set, or null to use the default
* @return this ComponentStyleBuilder for chaining
*/
public ComponentStyleBuilder underlined(Boolean underlined)
{
this.underlined = underlined;
return this;
}
/**
* Set the style's strikethrough property.
*
* @param strikethrough the strikethrough value to set, or null to use the
* default
* @return this ComponentStyleBuilder for chaining
*/
public ComponentStyleBuilder strikethrough(Boolean strikethrough)
{
this.strikethrough = strikethrough;
return this;
}
/**
* Set the style's obfuscated property.
*
* @param obfuscated the obfuscated value to set, or null to use the default
* @return this ComponentStyleBuilder for chaining
*/
public ComponentStyleBuilder obfuscated(Boolean obfuscated)
{
this.obfuscated = obfuscated;
return this;
}
/**
* Build the {@link ComponentStyle} using the values set in this builder.
*
* @return the created ComponentStyle
*/
public ComponentStyle build()
{
return new ComponentStyle( color, font, bold, italic, underlined, strikethrough, obfuscated );
}
}

View File

@@ -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

View File

@@ -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<BaseComponent>();
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 )
{
@@ -111,15 +158,15 @@ public final class TextComponent extends BaseComponent
} else if ( format == ChatColor.MAGIC )
{
component.setObfuscated( true );
} else if ( format == ChatColor.RESET )
{
format = defaultColor;
component = new TextComponent();
component.setColor( format );
} else
{
if ( format == ChatColor.RESET )
{
format = defaultColor;
}
component = new TextComponent();
component.setColor( format );
component.setReset( true );
}
continue;
}
@@ -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[ components.size() ] );
/**
* 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 );
}
/**
@@ -230,6 +297,6 @@ public final class TextComponent extends BaseComponent
@Override
public String toString()
{
return String.format( "TextComponent{text=%s, %s}", text, super.toString() );
return "TextComponent{text=" + text + ", " + super.toString() + '}';
}
}

View File

@@ -30,6 +30,10 @@ public final class TranslatableComponent extends BaseComponent
* The components to substitute into the translation
*/
private List<BaseComponent> with;
/**
* The fallback, if the translation is not found
*/
private String fallback;
/**
* Creates a translatable component from the original to clone it.
@@ -82,6 +86,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.
*
@@ -153,6 +172,11 @@ public final class TranslatableComponent extends BaseComponent
{
String trans = TranslationRegistry.INSTANCE.translate( translate );
if ( trans.equals( translate ) && fallback != null )
{
trans = fallback;
}
Matcher matcher = format.matcher( trans );
int position = 0;
int i = 0;

View File

@@ -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 );
}
}

View File

@@ -8,6 +8,7 @@ import com.google.gson.JsonParseException;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import java.lang.reflect.Type;
import java.util.UUID;
import net.md_5.bungee.api.chat.BaseComponent;
public class EntitySerializer implements JsonSerializer<Entity>, JsonDeserializer<Entity>
@@ -18,9 +19,19 @@ public class EntitySerializer implements JsonSerializer<Entity>, JsonDeserialize
{
JsonObject value = element.getAsJsonObject();
String idString;
JsonElement id = value.get( "id" );
if ( id.isJsonArray() )
{
idString = parseUUID( context.deserialize( id, int[].class ) ).toString();
} else
{
idString = id.getAsString();
}
return new Entity(
( value.has( "type" ) ) ? value.get( "type" ).getAsString() : null,
value.get( "id" ).getAsString(),
idString,
( value.has( "name" ) ) ? context.deserialize( value.get( "name" ), BaseComponent.class ) : null
);
}
@@ -37,4 +48,9 @@ public class EntitySerializer implements JsonSerializer<Entity>, JsonDeserialize
}
return object;
}
private static UUID parseUUID(int[] array)
{
return new UUID( (long) array[0] << 32 | (long) array[1] & 0XFFFFFFFFL, (long) array[2] << 32 | (long) array[3] & 0XFFFFFFFFL );
}
}

View File

@@ -23,6 +23,15 @@ public class Text extends Content
this.value = value;
}
public Text(BaseComponent value)
{
// For legacy serialization reasons, this has to be an array of components
this( new BaseComponent[]
{
value
} );
}
public Text(String value)
{
this.value = value;

View File

@@ -4,16 +4,15 @@ 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.ComponentStyle;
import net.md_5.bungee.api.chat.HoverEvent;
import net.md_5.bungee.api.chat.hover.content.Content;
@@ -22,42 +21,12 @@ public class BaseComponentSerializer
protected void deserialize(JsonObject object, BaseComponent component, JsonDeserializationContext context)
{
if ( object.has( "color" ) )
{
component.setColor( ChatColor.of( object.get( "color" ).getAsString() ) );
}
if ( object.has( "font" ) )
{
component.setFont( object.get( "font" ).getAsString() );
}
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() );
}
component.applyStyle( context.deserialize( object, ComponentStyle.class ) );
if ( object.has( "insertion" ) )
{
component.setInsertion( object.get( "insertion" ).getAsString() );
}
if ( object.has( "extra" ) )
{
component.setExtra( Arrays.asList( context.<BaseComponent[]>deserialize( object.get( "extra" ), BaseComponent[].class ) ) );
}
//Events
if ( object.has( "clickEvent" ) )
@@ -73,15 +42,9 @@ public class BaseComponentSerializer
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
if ( event.has( "value" ) )
{
JsonElement contents = event.get( "value" );
// 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.
@@ -97,8 +60,10 @@ public class BaseComponentSerializer
};
}
hoverEvent = new HoverEvent( action, components );
} catch ( JsonParseException ex )
} else if ( event.has( "contents" ) )
{
JsonElement contents = event.get( "contents" );
Content[] list;
if ( contents.isJsonArray() )
{
@@ -113,14 +78,16 @@ public class BaseComponentSerializer
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( "extra" ) )
{
component.setExtra( Arrays.asList( context.<BaseComponent[]>deserialize( object.get( "extra" ), BaseComponent[].class ) ) );
}
}
protected void serialize(JsonObject object, BaseComponent component, JsonSerializationContext context)
@@ -135,44 +102,14 @@ public class BaseComponentSerializer
{
Preconditions.checkArgument( !ComponentSerializer.serializedComponents.get().contains( component ), "Component loop" );
ComponentSerializer.serializedComponents.get().add( component );
if ( component.getColorRaw() != null )
{
object.addProperty( "color", component.getColorRaw().getName() );
}
if ( component.getFontRaw() != null )
{
object.addProperty( "font", component.getFontRaw() );
}
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() );
}
ComponentStyleSerializer.serializeTo( component.getStyle(), object );
if ( component.getInsertion() != null )
{
object.addProperty( "insertion", component.getInsertion() );
}
if ( component.getExtra() != null )
{
object.add( "extra", context.serialize( component.getExtra() ) );
}
//Events
if ( component.getClickEvent() != null )
{
@@ -195,6 +132,11 @@ public class BaseComponentSerializer
}
object.add( "hoverEvent", hoverEvent );
}
if ( component.getExtra() != null )
{
object.add( "extra", context.serialize( component.getExtra() ) );
}
} finally
{
ComponentSerializer.serializedComponents.get().remove( component );

View File

@@ -2,15 +2,18 @@ package net.md_5.bungee.chat;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
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 com.google.gson.JsonPrimitive;
import java.lang.reflect.Type;
import java.util.Set;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.chat.ComponentStyle;
import net.md_5.bungee.api.chat.ItemTag;
import net.md_5.bungee.api.chat.KeybindComponent;
import net.md_5.bungee.api.chat.ScoreComponent;
@@ -27,7 +30,6 @@ import net.md_5.bungee.api.chat.hover.content.TextSerializer;
public class ComponentSerializer implements JsonDeserializer<BaseComponent>
{
private static final JsonParser JSON_PARSER = new JsonParser();
private static final Gson gson = new GsonBuilder().
registerTypeAdapter( BaseComponent.class, new ComponentSerializer() ).
registerTypeAdapter( TextComponent.class, new TextComponentSerializer() ).
@@ -35,6 +37,7 @@ public class ComponentSerializer implements JsonDeserializer<BaseComponent>
registerTypeAdapter( KeybindComponent.class, new KeybindComponentSerializer() ).
registerTypeAdapter( ScoreComponent.class, new ScoreComponentSerializer() ).
registerTypeAdapter( SelectorComponent.class, new SelectorComponentSerializer() ).
registerTypeAdapter( ComponentStyle.class, new ComponentStyleSerializer() ).
registerTypeAdapter( Entity.class, new EntitySerializer() ).
registerTypeAdapter( Text.class, new TextSerializer() ).
registerTypeAdapter( Item.class, new ItemSerializer() ).
@@ -43,9 +46,26 @@ public class ComponentSerializer implements JsonDeserializer<BaseComponent>
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 = JSON_PARSER.parse( json );
JsonElement jsonElement = JsonParser.parseString( json );
if ( jsonElement.isJsonArray() )
{
@@ -59,6 +79,85 @@ public class ComponentSerializer implements JsonDeserializer<BaseComponent>
}
}
/**
* Deserialize a JSON-compliant String as a single component.
*
* @param json the component json to parse
* @return the deserialized component
* @throws IllegalArgumentException if anything other than a valid JSON
* component string is passed as input
*/
public static BaseComponent deserialize(String json)
{
JsonElement jsonElement = JsonParser.parseString( json );
return deserialize( jsonElement );
}
/**
* Deserialize a JSON element as a single component.
*
* @param jsonElement the component json to parse
* @return the deserialized component
* @throws IllegalArgumentException if anything other than a valid JSON
* component is passed as input
*/
public static BaseComponent deserialize(JsonElement jsonElement)
{
if ( jsonElement instanceof JsonPrimitive )
{
JsonPrimitive primitive = (JsonPrimitive) jsonElement;
if ( primitive.isString() )
{
return new TextComponent( primitive.getAsString() );
}
} else if ( jsonElement instanceof JsonArray )
{
BaseComponent[] array = gson.fromJson( jsonElement, BaseComponent[].class );
return TextComponent.fromArray( array );
}
return gson.fromJson( jsonElement, BaseComponent.class );
}
/**
* Deserialize a JSON-compliant String as a component style.
*
* @param json the component style json to parse
* @return the deserialized component style
* @throws IllegalArgumentException if anything other than a valid JSON
* component style string is passed as input
*/
public static ComponentStyle deserializeStyle(String json)
{
JsonElement jsonElement = JsonParser.parseString( json );
return deserializeStyle( jsonElement );
}
/**
* Deserialize a JSON element as a component style.
*
* @param jsonElement the component style json to parse
* @return the deserialized component style
* @throws IllegalArgumentException if anything other than a valid JSON
* component style is passed as input
*/
public static ComponentStyle deserializeStyle(JsonElement jsonElement)
{
return gson.fromJson( jsonElement, ComponentStyle.class );
}
public static JsonElement toJson(BaseComponent component)
{
return gson.toJsonTree( component );
}
public static JsonElement toJson(ComponentStyle style)
{
return gson.toJsonTree( style );
}
public static String toString(Object object)
{
return gson.toJson( object );
@@ -80,6 +179,11 @@ public class ComponentSerializer implements JsonDeserializer<BaseComponent>
}
}
public static String toString(ComponentStyle style)
{
return gson.toJson( style );
}
@Override
public BaseComponent deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException
{

View File

@@ -0,0 +1,118 @@
package net.md_5.bungee.chat;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import java.lang.reflect.Type;
import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.chat.ComponentStyle;
import net.md_5.bungee.api.chat.ComponentStyleBuilder;
public class ComponentStyleSerializer implements JsonSerializer<ComponentStyle>, JsonDeserializer<ComponentStyle>
{
private static boolean getAsBoolean(JsonElement el)
{
if ( el.isJsonPrimitive() )
{
JsonPrimitive primitive = (JsonPrimitive) el;
if ( primitive.isBoolean() )
{
return primitive.getAsBoolean();
}
if ( primitive.isNumber() )
{
Number number = primitive.getAsNumber();
if ( number instanceof Byte )
{
return number.byteValue() != 0;
}
}
}
return false;
}
static void serializeTo(ComponentStyle style, JsonObject object)
{
if ( style.isBoldRaw() != null )
{
object.addProperty( "bold", style.isBoldRaw() );
}
if ( style.isItalicRaw() != null )
{
object.addProperty( "italic", style.isItalicRaw() );
}
if ( style.isUnderlinedRaw() != null )
{
object.addProperty( "underlined", style.isUnderlinedRaw() );
}
if ( style.isStrikethroughRaw() != null )
{
object.addProperty( "strikethrough", style.isStrikethroughRaw() );
}
if ( style.isObfuscatedRaw() != null )
{
object.addProperty( "obfuscated", style.isObfuscatedRaw() );
}
if ( style.hasColor() )
{
object.addProperty( "color", style.getColor().getName() );
}
if ( style.hasFont() )
{
object.addProperty( "font", style.getFont() );
}
}
@Override
public ComponentStyle deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException
{
ComponentStyleBuilder builder = ComponentStyle.builder();
JsonObject object = json.getAsJsonObject();
if ( object.has( "bold" ) )
{
builder.bold( getAsBoolean( object.get( "bold" ) ) );
}
if ( object.has( "italic" ) )
{
builder.italic( getAsBoolean( object.get( "italic" ) ) );
}
if ( object.has( "underlined" ) )
{
builder.underlined( getAsBoolean( object.get( "underlined" ) ) );
}
if ( object.has( "strikethrough" ) )
{
builder.strikethrough( getAsBoolean( object.get( "strikethrough" ) ) );
}
if ( object.has( "obfuscated" ) )
{
builder.obfuscated( getAsBoolean( object.get( "obfuscated" ) ) );
}
if ( object.has( "color" ) )
{
builder.color( ChatColor.of( object.get( "color" ).getAsString() ) );
}
if ( object.has( "font" ) )
{
builder.font( object.get( "font" ).getAsString() );
}
return builder.build();
}
@Override
public JsonElement serialize(ComponentStyle src, Type typeOfSrc, JsonSerializationContext context)
{
JsonObject object = new JsonObject();
serializeTo( src, object );
return object;
}
}

View File

@@ -22,6 +22,12 @@ public class SelectorComponentSerializer extends BaseComponentSerializer impleme
throw new JsonParseException( "Could not parse JSON: missing 'selector' property" );
}
SelectorComponent component = new SelectorComponent( object.get( "selector" ).getAsString() );
if ( object.has( "separator" ) )
{
component.setSeparator( ComponentSerializer.deserialize( object.get( "separator" ).getAsString() ) );
}
deserialize( object, component, context );
return component;
}
@@ -32,6 +38,11 @@ public class SelectorComponentSerializer extends BaseComponentSerializer impleme
JsonObject object = new JsonObject();
serialize( object, component, context );
object.addProperty( "selector", component.getSelector() );
if ( component.getSeparator() != null )
{
object.addProperty( "separator", ComponentSerializer.toString( component.getSeparator() ) );
}
return object;
}
}

View File

@@ -8,8 +8,6 @@ import com.google.gson.JsonParseException;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import java.lang.reflect.Type;
import java.util.List;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.chat.TextComponent;
public class TextComponentSerializer extends BaseComponentSerializer implements JsonSerializer<TextComponent>, JsonDeserializer<TextComponent>
@@ -20,11 +18,10 @@ public class TextComponentSerializer extends BaseComponentSerializer implements
{
TextComponent component = new TextComponent();
JsonObject object = json.getAsJsonObject();
if ( !object.has( "text" ) )
if ( object.has( "text" ) )
{
throw new JsonParseException( "Could not parse JSON: missing 'text' property" );
}
component.setText( object.get( "text" ).getAsString() );
}
deserialize( object, component, context );
return component;
}
@@ -32,13 +29,9 @@ public class TextComponentSerializer extends BaseComponentSerializer implements
@Override
public JsonElement serialize(TextComponent src, Type typeOfSrc, JsonSerializationContext context)
{
List<BaseComponent> extra = src.getExtra();
JsonObject object = new JsonObject();
object.addProperty( "text", src.getText() );
if ( src.hasFormatting() || ( extra != null && !extra.isEmpty() ) )
{
serialize( object, src, context );
}
object.addProperty( "text", src.getText() );
return object;
}
}

View File

@@ -28,7 +28,11 @@ public class TranslatableComponentSerializer extends BaseComponentSerializer imp
component.setTranslate( object.get( "translate" ).getAsString() );
if ( object.has( "with" ) )
{
component.setWith( Arrays.asList( context.<BaseComponent[]>deserialize( object.get( "with" ), BaseComponent[].class ) ) );
component.setWith( Arrays.asList( context.deserialize( object.get( "with" ), BaseComponent[].class ) ) );
}
if ( object.has( "fallback" ) )
{
component.setFallback( object.get( "fallback" ).getAsString() );
}
return component;
}
@@ -43,6 +47,10 @@ public class TranslatableComponentSerializer extends BaseComponentSerializer imp
{
object.add( "with", context.serialize( src.getWith() ) );
}
if ( src.getFallback() != null )
{
object.addProperty( "fallback", src.getFallback() );
}
return object;
}
}

View File

@@ -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() )

View File

@@ -1,12 +1,17 @@
package net.md_5.bungee.api.chat;
import static org.junit.jupiter.api.Assertions.*;
import java.awt.Color;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.ObjIntConsumer;
import java.util.function.Supplier;
import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.chat.hover.content.Item;
import net.md_5.bungee.api.chat.hover.content.Entity;
import net.md_5.bungee.api.chat.hover.content.Text;
import net.md_5.bungee.chat.ComponentSerializer;
import org.junit.Assert;
import org.junit.Test;
import org.junit.jupiter.api.Test;
public class ComponentsTest
{
@@ -15,13 +20,27 @@ public class ComponentsTest
{
String json = ComponentSerializer.toString( components );
BaseComponent[] parsed = ComponentSerializer.parse( json );
Assert.assertEquals( TextComponent.toLegacyText( parsed ), TextComponent.toLegacyText( components ) );
assertEquals( TextComponent.toLegacyText( parsed ), TextComponent.toLegacyText( components ) );
}
public static void testDissembleReassemble(String json)
public static void testDissembleReassemble(BaseComponent component)
{
String json = ComponentSerializer.toString( component );
BaseComponent[] parsed = ComponentSerializer.parse( json );
assertEquals( TextComponent.toLegacyText( parsed ), TextComponent.toLegacyText( component ) );
}
public static void testAssembleDissemble(String json, boolean modern)
{
if ( modern )
{
BaseComponent deserialized = ComponentSerializer.deserialize( json );
assertEquals( json, ComponentSerializer.toString( deserialized ) );
} else
{
BaseComponent[] parsed = ComponentSerializer.parse( json );
Assert.assertEquals( json, ComponentSerializer.toString( parsed ) );
assertEquals( json, ComponentSerializer.toString( parsed ) );
}
}
@Test
@@ -41,16 +60,20 @@ public class ComponentsTest
{
textComponent
} );
json = "{\"text\":\"Test\",\"hoverEvent\":{\"action\":\"show_item\",\"value\":[{\"text\":\"{id:\\\"minecraft:netherrack\\\",Count:47b}\"}]}}";
testDissembleReassemble( json );
testDissembleReassemble( textComponent );
json = "{\"hoverEvent\":{\"action\":\"show_item\",\"value\":[{\"text\":\"{id:\\\"minecraft:netherrack\\\",Count:47b}\"}]},\"text\":\"Test\"}";
testAssembleDissemble( json, false );
testAssembleDissemble( json, true );
//////////
String hoverVal = "{\"text\":\"{id:\\\"minecraft:dirt\\\",Count:1b}\"}";
json = "{\"extra\":[{\"text\":\"[\"},{\"extra\":[{\"translate\":\"block.minecraft.dirt\"}],\"text\":\"\"},{\"text\":\"]\"}],\"hoverEvent\":{\"action\":\"show_item\",\"value\":[" + hoverVal + "]},\"text\":\"\"}";
components = ComponentSerializer.parse( json );
Text contentText = ( (Text) components[0].getHoverEvent().getContents().get( 0 ) );
Assert.assertEquals( hoverVal, ComponentSerializer.toString( (BaseComponent[]) contentText.getValue() ) );
assertEquals( hoverVal, ComponentSerializer.toString( (BaseComponent[]) contentText.getValue() ) );
testDissembleReassemble( components );
//////////
// TODO: now ambiguous since "text" to distinguish Text from Item is not required
/*
TextComponent component1 = new TextComponent( "HoverableText" );
String nbt = "{display:{Name:{text:Hello},Lore:[{text:Line_1},{text:Line_2}]},ench:[{id:49,lvl:5}],Unbreakable:1}}";
Item contentItem = new Item( "minecraft:wood", 1, ItemTag.ofNbt( nbt ) );
@@ -59,25 +82,53 @@ public class ComponentsTest
json = ComponentSerializer.toString( component1 );
components = ComponentSerializer.parse( json );
Item parsedContentItem = ( (Item) components[0].getHoverEvent().getContents().get( 0 ) );
Assert.assertEquals( contentItem, parsedContentItem );
Assert.assertEquals( contentItem.getCount(), parsedContentItem.getCount() );
Assert.assertEquals( contentItem.getId(), parsedContentItem.getId() );
Assert.assertEquals( nbt, parsedContentItem.getTag().getNbt() );
assertEquals( contentItem, parsedContentItem );
assertEquals( contentItem.getCount(), parsedContentItem.getCount() );
assertEquals( contentItem.getId(), parsedContentItem.getId() );
assertEquals( nbt, parsedContentItem.getTag().getNbt() );
*/
}
@Test
public void testEmptyComponentBuilder()
public void testArrayUUIDParse()
{
BaseComponent[] uuidComponent = ComponentSerializer.parse( "{\"translate\":\"multiplayer.player.joined\",\"with\":[{\"text\":\"Rexcantor64\",\"hoverEvent\":{\"contents\":{\"type\":\"minecraft:player\",\"id\":[1328556382,-2138814985,-1895806765,-1039963041],\"name\":\"Rexcantor64\"},\"action\":\"show_entity\"},\"insertion\":\"Rexcantor64\",\"clickEvent\":{\"action\":\"suggest_command\",\"value\":\"/tell Rexcantor64 \"}}],\"color\":\"yellow\"}" );
assertEquals( "4f30295e-8084-45f7-8f00-48d3c2036c5f", ( (Entity) ( (TranslatableComponent) uuidComponent[0] ).getWith().get( 0 ).getHoverEvent().getContents().get( 0 ) ).getId() );
testDissembleReassemble( uuidComponent );
}
@Test
public void testEmptyComponentBuilderCreate()
{
this.testEmptyComponentBuilder(
ComponentBuilder::create,
(components) -> assertEquals( components.length, 0 ),
(components, size) -> assertEquals( size, components.length )
);
}
@Test
public void testEmptyComponentBuilderBuild()
{
this.testEmptyComponentBuilder(
ComponentBuilder::build,
(component) -> assertNull( component.getExtra() ),
(component, size) -> assertEquals( component.getExtra().size(), size )
);
}
private <T> void testEmptyComponentBuilder(Function<ComponentBuilder, T> componentBuilder, Consumer<T> emptyAssertion, ObjIntConsumer<T> sizedAssertion)
{
ComponentBuilder builder = new ComponentBuilder();
BaseComponent[] parts = builder.create();
Assert.assertEquals( parts.length, 0 );
T component = componentBuilder.apply( builder );
emptyAssertion.accept( component );
for ( int i = 0; i < 3; i++ )
{
builder.append( "part:" + i );
parts = builder.create();
Assert.assertEquals( parts.length, i + 1 );
component = componentBuilder.apply( builder );
sizedAssertion.accept( component, i + 1 );
}
}
@@ -85,23 +136,23 @@ public class ComponentsTest
public void testDummyRetaining()
{
ComponentBuilder builder = new ComponentBuilder();
Assert.assertNotNull( builder.getCurrentComponent() );
assertNotNull( builder.getCurrentComponent() );
builder.color( ChatColor.GREEN );
builder.append( "test ", ComponentBuilder.FormatRetention.ALL );
Assert.assertEquals( builder.getCurrentComponent().getColor(), ChatColor.GREEN );
assertEquals( builder.getCurrentComponent().getColor(), ChatColor.GREEN );
}
@Test(expected = IndexOutOfBoundsException.class)
@Test
public void testComponentGettingExceptions()
{
ComponentBuilder builder = new ComponentBuilder();
builder.getComponent( -1 );
builder.getComponent( 0 );
builder.getComponent( 1 );
assertThrows( IndexOutOfBoundsException.class, () -> builder.getComponent( -1 ) );
assertThrows( IndexOutOfBoundsException.class, () -> builder.getComponent( 0 ) );
assertThrows( IndexOutOfBoundsException.class, () -> builder.getComponent( 1 ) );
BaseComponent component = new TextComponent( "Hello" );
builder.append( component );
Assert.assertEquals( builder.getComponent( 0 ), component );
builder.getComponent( 1 );
assertEquals( builder.getComponent( 0 ), component );
assertThrows( IndexOutOfBoundsException.class, () -> builder.getComponent( 1 ) );
}
@Test
@@ -110,33 +161,33 @@ public class ComponentsTest
ComponentBuilder builder = new ComponentBuilder();
TextComponent apple = new TextComponent( "apple" );
builder.append( apple );
Assert.assertEquals( builder.getCurrentComponent(), apple );
Assert.assertEquals( builder.getComponent( 0 ), apple );
assertEquals( builder.getCurrentComponent(), apple );
assertEquals( builder.getComponent( 0 ), apple );
TextComponent mango = new TextComponent( "mango" );
TextComponent orange = new TextComponent( "orange" );
builder.append( mango );
builder.append( orange );
builder.removeComponent( 1 ); // Removing mango
Assert.assertEquals( builder.getComponent( 0 ), apple );
Assert.assertEquals( builder.getComponent( 1 ), orange );
assertEquals( builder.getComponent( 0 ), apple );
assertEquals( builder.getComponent( 1 ), orange );
}
@Test
public void testToLegacyFromLegacy()
{
String text = "§a§lHello §f§kworld§7!";
Assert.assertEquals( text, TextComponent.toLegacyText( TextComponent.fromLegacyText( text ) ) );
assertEquals( text, TextComponent.toLegacyText( TextComponent.fromLegacyText( text ) ) );
}
@Test(expected = IndexOutOfBoundsException.class)
@Test
public void testComponentBuilderCursorInvalidPos()
{
ComponentBuilder builder = new ComponentBuilder();
builder.append( new TextComponent( "Apple, " ) );
builder.append( new TextComponent( "Orange, " ) );
builder.setCursor( -1 );
builder.setCursor( 2 );
assertThrows( IndexOutOfBoundsException.class, () -> builder.setCursor( -1 ) );
assertThrows( IndexOutOfBoundsException.class, () -> builder.setCursor( 2 ) );
}
@Test
@@ -144,24 +195,24 @@ public class ComponentsTest
{
TextComponent t1, t2, t3;
ComponentBuilder builder = new ComponentBuilder();
Assert.assertEquals( builder.getCursor(), -1 );
assertEquals( builder.getCursor(), -1 );
builder.append( t1 = new TextComponent( "Apple, " ) );
Assert.assertEquals( builder.getCursor(), 0 );
assertEquals( builder.getCursor(), 0 );
builder.append( t2 = new TextComponent( "Orange, " ) );
builder.append( t3 = new TextComponent( "Mango, " ) );
Assert.assertEquals( builder.getCursor(), 2 );
assertEquals( builder.getCursor(), 2 );
builder.setCursor( 0 );
Assert.assertEquals( builder.getCurrentComponent(), t1 );
assertEquals( builder.getCurrentComponent(), t1 );
// Test that appending new components updates the position to the new list size
// after having previously set it to 0 (first component)
builder.append( new TextComponent( "and Grapefruit" ) );
Assert.assertEquals( builder.getCursor(), 3 );
assertEquals( builder.getCursor(), 3 );
builder.setCursor( 0 );
builder.resetCursor();
Assert.assertEquals( builder.getCursor(), 3 );
assertEquals( builder.getCursor(), 3 );
}
@Test
@@ -170,7 +221,7 @@ public class ComponentsTest
String text = "§a§lHello §r§kworld§7!";
BaseComponent[] components = TextComponent.fromLegacyText( text );
BaseComponent[] builderComponents = new ComponentBuilder().append( components ).create();
Assert.assertArrayEquals( components, builderComponents );
assertArrayEquals( components, builderComponents );
}
/*
@@ -192,7 +243,7 @@ public class ComponentsTest
component.setHoverEvent( event );
String serialised = ComponentSerializer.toString( component );
BaseComponent[] deserialised = ComponentSerializer.parse( serialised );
Assert.assertEquals( TextComponent.toLegacyText( deserialised ), TextComponent.toLegacyText( component ) );
assertEquals( TextComponent.toLegacyText( deserialised ), TextComponent.toLegacyText( component ) );
}
*/
@@ -207,13 +258,13 @@ public class ComponentsTest
);
TextComponent component = new TextComponent( "test" );
component.setHoverEvent( hoverEvent );
Assert.assertEquals( component.getHoverEvent().getContents().size(), 1 );
Assert.assertTrue( component.getHoverEvent().getContents().get( 0 ) instanceof Text );
Assert.assertEquals( ( (Text) component.getHoverEvent().getContents().get( 0 ) ).getValue(), advancement );
assertEquals( component.getHoverEvent().getContents().size(), 1 );
assertTrue( component.getHoverEvent().getContents().get( 0 ) instanceof Text );
assertEquals( ( (Text) component.getHoverEvent().getContents().get( 0 ) ).getValue(), advancement );
}
@Test
public void testHoverEventContents()
public void testHoverEventContentsCreate()
{
// First do the text using the newer contents system
HoverEvent hoverEvent = new HoverEvent(
@@ -222,21 +273,53 @@ public class ComponentsTest
new Text( new ComponentBuilder( "Second" ).create() )
);
TextComponent component = new TextComponent( "Sample text" );
component.setHoverEvent( hoverEvent );
Assert.assertEquals( hoverEvent.getContents().size(), 2 );
Assert.assertFalse( hoverEvent.isLegacy() );
String serialized = ComponentSerializer.toString( component );
BaseComponent[] deserialized = ComponentSerializer.parse( serialized );
Assert.assertEquals( component.getHoverEvent(), deserialized[0].getHoverEvent() );
this.testHoverEventContents(
hoverEvent,
ComponentSerializer::parse,
(components) -> components[0].getHoverEvent(),
ComponentsTest::testDissembleReassemble // BaseComponent
);
// check the test still works with the value method
hoverEvent = new HoverEvent( HoverEvent.Action.SHOW_TEXT, new ComponentBuilder( "Sample text" ).create() );
Assert.assertEquals( hoverEvent.getContents().size(), 1 );
Assert.assertTrue( hoverEvent.isLegacy() );
serialized = ComponentSerializer.toString( component );
deserialized = ComponentSerializer.parse( serialized );
Assert.assertEquals( component.getHoverEvent(), deserialized[0].getHoverEvent() );
TextComponent component = new TextComponent( "Sample text" );
component.setHoverEvent( hoverEvent );
assertEquals( hoverEvent.getContents().size(), 1 );
assertTrue( hoverEvent.isLegacy() );
String serialized = ComponentSerializer.toString( component );
BaseComponent[] deserialized = ComponentSerializer.parse( serialized );
assertEquals( component.getHoverEvent(), deserialized[0].getHoverEvent() );
}
@Test
public void testHoverEventContentsBuild()
{
// First do the text using the newer contents system
HoverEvent hoverEvent = new HoverEvent(
HoverEvent.Action.SHOW_TEXT,
new Text( new ComponentBuilder( "First" ).build() ),
new Text( new ComponentBuilder( "Second" ).build() )
);
this.testHoverEventContents(
hoverEvent,
ComponentSerializer::deserialize,
BaseComponent::getHoverEvent,
ComponentsTest::testDissembleReassemble // BaseComponent
);
}
private <T> void testHoverEventContents(HoverEvent hoverEvent, Function<String, T> deserializer, Function<T, HoverEvent> hoverEventGetter, Consumer<T> dissembleReassembleTest)
{
TextComponent component = new TextComponent( "Sample text" );
component.setHoverEvent( hoverEvent );
assertEquals( hoverEvent.getContents().size(), 2 );
assertFalse( hoverEvent.isLegacy() );
String serialized = ComponentSerializer.toString( component );
T deserialized = deserializer.apply( serialized );
assertEquals( component.getHoverEvent(), hoverEventGetter.apply( deserialized ) );
// Test single content:
String json = "{\"italic\":true,\"color\":\"gray\",\"translate\":\"chat.type.admin\",\"with\":[{\"text\":\"@\"}"
@@ -248,37 +331,76 @@ public class ComponentsTest
+ "\"/tell Name \"},\"hoverEvent\":{\"action\":\"show_entity\",\"contents\":"
+ "{\"type\":\"minecraft:player\",\"id\":\"00000000-0000-0000-0000-00000000000000\",\"name\":"
+ "{\"text\":\"Name\"}}},\"text\":\"Name\"}]}]}";
testDissembleReassemble( ComponentSerializer.parse( json ) );
dissembleReassembleTest.accept( deserializer.apply( json ) );
}
@Test
public void testFormatRetentionCopyFormatting()
public void testFormatRetentionCopyFormattingCreate()
{
this.testFormatRetentionCopyFormatting( () -> new HoverEvent( HoverEvent.Action.SHOW_TEXT, new ComponentBuilder( "Test" ).create() ) );
}
@Test
public void testFormatRetentionCopyFormattingBuild()
{
this.testFormatRetentionCopyFormatting( () -> new HoverEvent( HoverEvent.Action.SHOW_TEXT, new Text( new ComponentBuilder( "Test" ).build() ) ) );
}
private void testFormatRetentionCopyFormatting(Supplier<HoverEvent> hoverEventSupplier)
{
TextComponent first = new TextComponent( "Hello" );
first.setBold( true );
first.setColor( ChatColor.RED );
first.setClickEvent( new ClickEvent( ClickEvent.Action.RUN_COMMAND, "test" ) );
first.setHoverEvent( new HoverEvent( HoverEvent.Action.SHOW_TEXT, new ComponentBuilder( "Test" ).create() ) );
first.setHoverEvent( hoverEventSupplier.get() );
TextComponent second = new TextComponent( " world" );
second.copyFormatting( first, ComponentBuilder.FormatRetention.ALL, true );
Assert.assertEquals( first.isBold(), second.isBold() );
Assert.assertEquals( first.getColor(), second.getColor() );
Assert.assertEquals( first.getClickEvent(), second.getClickEvent() );
Assert.assertEquals( first.getHoverEvent(), second.getHoverEvent() );
assertEquals( first.isBold(), second.isBold() );
assertEquals( first.getColor(), second.getColor() );
assertEquals( first.getClickEvent(), second.getClickEvent() );
assertEquals( first.getHoverEvent(), second.getHoverEvent() );
}
@Test
public void testBuilderClone()
public void testBuilderCloneCreate()
{
this.testBuilderClone( (builder) -> TextComponent.toLegacyText( builder.create() ) );
}
@Test
public void testBuilderCloneBuild()
{
this.testBuilderClone( (builder) -> TextComponent.toLegacyText( builder.build() ) );
}
private void testBuilderClone(Function<ComponentBuilder, String> legacyTextFunction)
{
ComponentBuilder builder = new ComponentBuilder( "Hello " ).color( ChatColor.RED ).append( "world" ).color( ChatColor.DARK_RED );
ComponentBuilder cloned = new ComponentBuilder( builder );
Assert.assertEquals( TextComponent.toLegacyText( builder.create() ), TextComponent.toLegacyText( cloned.create() ) );
assertEquals( legacyTextFunction.apply( builder ), legacyTextFunction.apply( cloned ) );
}
@Test
public void testBuilderAppendMixedComponents()
public void testBuilderAppendCreateMixedComponents()
{
this.testBuilderAppendMixedComponents(
ComponentBuilder::create,
(components, index) -> components[index]
);
}
@Test
public void testBuilderAppendBuildMixedComponents()
{
this.testBuilderAppendMixedComponents(
ComponentBuilder::build,
(component, index) -> component.getExtra().get( index )
);
}
private <T> void testBuilderAppendMixedComponents(Function<ComponentBuilder, T> componentBuilder, BiFunction<T, Integer, BaseComponent> extraGetter)
{
ComponentBuilder builder = new ComponentBuilder( "Hello " );
TextComponent textComponent = new TextComponent( "world " );
@@ -291,11 +413,11 @@ public class ComponentsTest
} );
ScoreComponent scoreComponent = new ScoreComponent( "myscore", "myobjective" );
builder.append( scoreComponent ); // non array based BaseComponent append
BaseComponent[] components = builder.create();
Assert.assertEquals( "Hello ", components[0].toPlainText() );
Assert.assertEquals( textComponent.toPlainText(), components[1].toPlainText() );
Assert.assertEquals( translatableComponent.toPlainText(), components[2].toPlainText() );
Assert.assertEquals( scoreComponent.toPlainText(), components[3].toPlainText() );
T component = componentBuilder.apply( builder );
assertEquals( "Hello ", extraGetter.apply( component, 0 ).toPlainText() );
assertEquals( textComponent.toPlainText(), extraGetter.apply( component, 1 ).toPlainText() );
assertEquals( translatableComponent.toPlainText(), extraGetter.apply( component, 2 ).toPlainText() );
assertEquals( scoreComponent.toPlainText(), extraGetter.apply( component, 3 ).toPlainText() );
}
@Test
@@ -305,36 +427,94 @@ public class ComponentsTest
String text = ComponentSerializer.toString( component );
BaseComponent[] reparsed = ComponentSerializer.parse( text );
Assert.assertArrayEquals( component, reparsed );
assertArrayEquals( component, reparsed );
}
@Test
public void testBuilderAppend()
public void testStyle()
{
ComponentStyle style = ComponentSerializer.deserializeStyle( "{\"color\":\"red\",\"font\":\"minecraft:example\",\"bold\":true,\"italic\":false,\"obfuscated\":true}" );
String text = ComponentSerializer.toString( style );
ComponentStyle reparsed = ComponentSerializer.deserializeStyle( text );
assertEquals( style, reparsed );
}
@Test
public void testBuilderAppendCreate()
{
this.testBuilderAppend(
() -> new HoverEvent( HoverEvent.Action.SHOW_TEXT, new ComponentBuilder( "Hello world" ).create() ),
ComponentBuilder::create,
(components, index) -> components[index],
BaseComponent::toPlainText,
ChatColor.YELLOW + "Hello " + ChatColor.GREEN + "world!",
BaseComponent::toLegacyText
);
}
@Test
public void testBuilderAppendBuild()
{
this.testBuilderAppend(
() -> new HoverEvent( HoverEvent.Action.SHOW_TEXT, new Text( new ComponentBuilder( "Hello world" ).build() ) ),
ComponentBuilder::build,
(component, index) -> component.getExtra().get( index ),
(component) -> BaseComponent.toPlainText( component ),
// An extra format code is appended to the beginning because there is an empty TextComponent at the start of every component
ChatColor.WHITE.toString() + ChatColor.YELLOW + "Hello " + ChatColor.GREEN + "world!",
(component) -> BaseComponent.toLegacyText( component )
);
}
private <T> void testBuilderAppend(Supplier<HoverEvent> hoverEventSupplier, Function<ComponentBuilder, T> componentBuilder, BiFunction<T, Integer, BaseComponent> extraGetter, Function<T, String> toPlainTextFunction, String expectedLegacyText, Function<T, String> toLegacyTextFunction)
{
ClickEvent clickEvent = new ClickEvent( ClickEvent.Action.RUN_COMMAND, "/help " );
HoverEvent hoverEvent = new HoverEvent( HoverEvent.Action.SHOW_TEXT, new ComponentBuilder( "Hello world" ).create() );
HoverEvent hoverEvent = hoverEventSupplier.get();
ComponentBuilder builder = new ComponentBuilder( "Hello " ).color( ChatColor.YELLOW );
builder.append( new ComponentBuilder( "world!" ).color( ChatColor.GREEN ).event( hoverEvent ).event( clickEvent ).create() );
builder.append( new ComponentBuilder( "world!" ).color( ChatColor.GREEN ).event( hoverEvent ).event( clickEvent ).create() ); // Intentionally using create() to append multiple individual components
BaseComponent[] components = builder.create();
T component = componentBuilder.apply( builder );
Assert.assertEquals( components[1].getHoverEvent(), hoverEvent );
Assert.assertEquals( components[1].getClickEvent(), clickEvent );
Assert.assertEquals( "Hello world!", BaseComponent.toPlainText( components ) );
Assert.assertEquals( ChatColor.YELLOW + "Hello " + ChatColor.GREEN + "world!", BaseComponent.toLegacyText( components ) );
assertEquals( extraGetter.apply( component, 1 ).getHoverEvent(), hoverEvent );
assertEquals( extraGetter.apply( component, 1 ).getClickEvent(), clickEvent );
assertEquals( "Hello world!", toPlainTextFunction.apply( component ) );
assertEquals( expectedLegacyText, toLegacyTextFunction.apply( component ) );
}
@Test
public void testBuilderAppendLegacy()
public void testBuilderAppendLegacyCreate()
{
this.testBuilderAppendLegacy(
ComponentBuilder::create,
BaseComponent::toPlainText,
ChatColor.YELLOW + "Hello " + ChatColor.GREEN + "world!",
BaseComponent::toLegacyText
);
}
@Test
public void testBuilderAppendLegacyBuild()
{
this.testBuilderAppendLegacy(
ComponentBuilder::build,
(component) -> BaseComponent.toPlainText( component ),
// An extra format code is appended to the beginning because there is an empty TextComponent at the start of every component
ChatColor.WHITE.toString() + ChatColor.YELLOW + "Hello " + ChatColor.GREEN + "world!",
(component) -> BaseComponent.toLegacyText( component )
);
}
private <T> void testBuilderAppendLegacy(Function<ComponentBuilder, T> componentBuilder, Function<T, String> toPlainTextFunction, String expectedLegacyString, Function<T, String> toLegacyTextFunction)
{
ComponentBuilder builder = new ComponentBuilder( "Hello " ).color( ChatColor.YELLOW );
builder.appendLegacy( "§aworld!" );
BaseComponent[] components = builder.create();
T component = componentBuilder.apply( builder );
Assert.assertEquals( "Hello world!", BaseComponent.toPlainText( components ) );
Assert.assertEquals( ChatColor.YELLOW + "Hello " + ChatColor.GREEN + "world!", BaseComponent.toLegacyText( components ) );
assertEquals( "Hello world!", toPlainTextFunction.apply( component ) );
assertEquals( expectedLegacyString, toLegacyTextFunction.apply( component ) );
}
@Test
@@ -343,8 +523,8 @@ public class ComponentsTest
TextComponent textComponent = new TextComponent( "Hello world" );
textComponent.setColor( ChatColor.RED );
Assert.assertEquals( "Hello world", textComponent.toPlainText() );
Assert.assertEquals( ChatColor.RED + "Hello world", textComponent.toLegacyText() );
assertEquals( "Hello world", textComponent.toPlainText() );
assertEquals( ChatColor.RED + "Hello world", textComponent.toLegacyText() );
}
@Test
@@ -352,25 +532,25 @@ public class ComponentsTest
{
BaseComponent[] test1 = TextComponent.fromLegacyText( ChatColor.AQUA + "Aqua " + ChatColor.RED + ChatColor.BOLD + "RedBold" );
Assert.assertEquals( "Aqua RedBold", BaseComponent.toPlainText( test1 ) );
Assert.assertEquals( ChatColor.AQUA + "Aqua " + ChatColor.RED + ChatColor.BOLD + "RedBold", BaseComponent.toLegacyText( test1 ) );
assertEquals( "Aqua RedBold", BaseComponent.toPlainText( test1 ) );
assertEquals( ChatColor.AQUA + "Aqua " + ChatColor.RED + ChatColor.BOLD + "RedBold", BaseComponent.toLegacyText( test1 ) );
BaseComponent[] test2 = TextComponent.fromLegacyText( "Text http://spigotmc.org " + ChatColor.GREEN + "google.com/test" );
Assert.assertEquals( "Text http://spigotmc.org google.com/test", BaseComponent.toPlainText( test2 ) );
assertEquals( "Text http://spigotmc.org google.com/test", BaseComponent.toPlainText( test2 ) );
//The extra ChatColor instances are sometimes inserted when not needed but it doesn't change the result
Assert.assertEquals( ChatColor.WHITE + "Text " + ChatColor.WHITE + "http://spigotmc.org" + ChatColor.WHITE
assertEquals( ChatColor.WHITE + "Text " + ChatColor.WHITE + "http://spigotmc.org" + ChatColor.WHITE
+ " " + ChatColor.GREEN + "google.com/test" + ChatColor.GREEN, BaseComponent.toLegacyText( test2 ) );
ClickEvent url1 = test2[1].getClickEvent();
Assert.assertNotNull( url1 );
Assert.assertTrue( url1.getAction() == ClickEvent.Action.OPEN_URL );
Assert.assertEquals( "http://spigotmc.org", url1.getValue() );
assertNotNull( url1 );
assertTrue( url1.getAction() == ClickEvent.Action.OPEN_URL );
assertEquals( "http://spigotmc.org", url1.getValue() );
ClickEvent url2 = test2[3].getClickEvent();
Assert.assertNotNull( url2 );
Assert.assertTrue( url2.getAction() == ClickEvent.Action.OPEN_URL );
Assert.assertEquals( "http://google.com/test", url2.getValue() );
assertNotNull( url2 );
assertTrue( url2.getAction() == ClickEvent.Action.OPEN_URL );
assertEquals( "http://google.com/test", url2.getValue() );
}
@Test
@@ -382,83 +562,138 @@ public class ComponentsTest
item, "5",
"thinkofdeath" );
Assert.assertEquals( "Given Golden Sword * 5 to thinkofdeath", translatableComponent.toPlainText() );
Assert.assertEquals( ChatColor.WHITE + "Given " + ChatColor.AQUA + "Golden Sword" + ChatColor.WHITE
assertEquals( "Given Golden Sword * 5 to thinkofdeath", translatableComponent.toPlainText() );
assertEquals( ChatColor.WHITE + "Given " + ChatColor.AQUA + "Golden Sword" + ChatColor.WHITE
+ " * " + ChatColor.WHITE + "5" + ChatColor.WHITE + " to " + ChatColor.WHITE + "thinkofdeath",
translatableComponent.toLegacyText() );
TranslatableComponent positional = new TranslatableComponent( "book.pageIndicator", "5", "50" );
Assert.assertEquals( "Page 5 of 50", positional.toPlainText() );
Assert.assertEquals( ChatColor.WHITE + "Page " + ChatColor.WHITE + "5" + ChatColor.WHITE + " of " + ChatColor.WHITE + "50", positional.toLegacyText() );
assertEquals( "Page 5 of 50", positional.toPlainText() );
assertEquals( ChatColor.WHITE + "Page " + ChatColor.WHITE + "5" + ChatColor.WHITE + " of " + ChatColor.WHITE + "50", positional.toLegacyText() );
TranslatableComponent one_four_two = new TranslatableComponent( "filled_map.buried_treasure" );
Assert.assertEquals( "Buried Treasure Map", one_four_two.toPlainText() );
assertEquals( "Buried Treasure Map", one_four_two.toPlainText() );
}
@Test
public void testBuilder()
public void testBuilderCreate()
{
BaseComponent[] components = new ComponentBuilder( "Hello " ).color( ChatColor.RED ).
this.testBuilder(
ComponentBuilder::create,
BaseComponent::toPlainText,
ChatColor.RED + "Hello " + ChatColor.BLUE + ChatColor.BOLD + "World" + ChatColor.YELLOW + ChatColor.BOLD + "!",
BaseComponent::toLegacyText
);
}
@Test
public void testBuilderBuild()
{
this.testBuilder(
ComponentBuilder::build,
(component) -> BaseComponent.toPlainText( component ),
// An extra format code is appended to the beginning because there is an empty TextComponent at the start of every component
ChatColor.WHITE.toString() + ChatColor.RED + "Hello " + ChatColor.BLUE + ChatColor.BOLD + "World" + ChatColor.YELLOW + ChatColor.BOLD + "!",
(component) -> BaseComponent.toLegacyText( component )
);
}
private <T> void testBuilder(Function<ComponentBuilder, T> componentBuilder, Function<T, String> toPlainTextFunction, String expectedLegacyString, Function<T, String> toLegacyTextFunction)
{
T component = componentBuilder.apply( new ComponentBuilder( "Hello " ).color( ChatColor.RED ).
append( "World" ).bold( true ).color( ChatColor.BLUE ).
append( "!" ).color( ChatColor.YELLOW ).create();
append( "!" ).color( ChatColor.YELLOW ) );
Assert.assertEquals( "Hello World!", BaseComponent.toPlainText( components ) );
Assert.assertEquals( ChatColor.RED + "Hello " + ChatColor.BLUE + ChatColor.BOLD
+ "World" + ChatColor.YELLOW + ChatColor.BOLD + "!", BaseComponent.toLegacyText( components ) );
assertEquals( "Hello World!", toPlainTextFunction.apply( component ) );
assertEquals( expectedLegacyString, toLegacyTextFunction.apply( component ) );
}
@Test
public void testBuilderReset()
public void testBuilderCreateReset()
{
BaseComponent[] components = new ComponentBuilder( "Hello " ).color( ChatColor.RED )
.append( "World" ).reset().create();
Assert.assertEquals( components[0].getColor(), ChatColor.RED );
Assert.assertEquals( components[1].getColor(), ChatColor.WHITE );
this.testBuilderReset(
ComponentBuilder::create,
(components, index) -> components[index]
);
}
@Test
public void testBuilderFormatRetention()
public void testBuilderBuildReset()
{
BaseComponent[] noneRetention = new ComponentBuilder( "Hello " ).color( ChatColor.RED )
.append( "World", ComponentBuilder.FormatRetention.NONE ).create();
this.testBuilderReset(
ComponentBuilder::build,
(component, index) -> component.getExtra().get( index )
);
}
Assert.assertEquals( noneRetention[0].getColor(), ChatColor.RED );
Assert.assertEquals( noneRetention[1].getColor(), ChatColor.WHITE );
private <T> void testBuilderReset(Function<ComponentBuilder, T> componentBuilder, BiFunction<T, Integer, BaseComponent> extraGetter)
{
T component = componentBuilder.apply( new ComponentBuilder( "Hello " ).color( ChatColor.RED )
.append( "World" ).reset() );
HoverEvent testEvent = new HoverEvent( HoverEvent.Action.SHOW_TEXT, new ComponentBuilder( "test" ).create() );
assertEquals( ChatColor.RED, extraGetter.apply( component, 0 ).getColor() );
assertEquals( ChatColor.WHITE, extraGetter.apply( component, 1 ).getColor() );
}
BaseComponent[] formattingRetention = new ComponentBuilder( "Hello " ).color( ChatColor.RED )
.event( testEvent ).append( "World", ComponentBuilder.FormatRetention.FORMATTING ).create();
@Test
public void testBuilderCreateFormatRetention()
{
this.testBuilderFormatRetention(
ComponentBuilder::create,
(components, index) -> components[index]
);
}
Assert.assertEquals( formattingRetention[0].getColor(), ChatColor.RED );
Assert.assertEquals( formattingRetention[0].getHoverEvent(), testEvent );
Assert.assertEquals( formattingRetention[1].getColor(), ChatColor.RED );
Assert.assertNull( formattingRetention[1].getHoverEvent() );
@Test
public void testBuilderBuildFormatRetention()
{
this.testBuilderFormatRetention(
ComponentBuilder::build,
(component, index) -> component.getExtra().get( index )
);
}
private <T> void testBuilderFormatRetention(Function<ComponentBuilder, T> componentBuilder, BiFunction<T, Integer, BaseComponent> extraGetter)
{
T noneRetention = componentBuilder.apply( new ComponentBuilder( "Hello " ).color( ChatColor.RED )
.append( "World", ComponentBuilder.FormatRetention.NONE ) );
assertEquals( ChatColor.RED, extraGetter.apply( noneRetention, 0 ).getColor() );
assertEquals( ChatColor.WHITE, extraGetter.apply( noneRetention, 1 ).getColor() );
HoverEvent testEvent = new HoverEvent( HoverEvent.Action.SHOW_TEXT, new Text( new ComponentBuilder( "test" ).build() ) );
T formattingRetention = componentBuilder.apply( new ComponentBuilder( "Hello " ).color( ChatColor.RED )
.event( testEvent ).append( "World", ComponentBuilder.FormatRetention.FORMATTING ) );
assertEquals( ChatColor.RED, extraGetter.apply( formattingRetention, 0 ).getColor() );
assertEquals( testEvent, extraGetter.apply( formattingRetention, 0 ).getHoverEvent() );
assertEquals( ChatColor.RED, extraGetter.apply( formattingRetention, 1 ).getColor() );
assertNull( extraGetter.apply( formattingRetention, 1 ).getHoverEvent() );
ClickEvent testClickEvent = new ClickEvent( ClickEvent.Action.OPEN_URL, "http://www.example.com" );
BaseComponent[] eventRetention = new ComponentBuilder( "Hello " ).color( ChatColor.RED )
.event( testEvent ).event( testClickEvent ).append( "World", ComponentBuilder.FormatRetention.EVENTS ).create();
T eventRetention = componentBuilder.apply( new ComponentBuilder( "Hello " ).color( ChatColor.RED )
.event( testEvent ).event( testClickEvent ).append( "World", ComponentBuilder.FormatRetention.EVENTS ) );
Assert.assertEquals( eventRetention[0].getColor(), ChatColor.RED );
Assert.assertEquals( eventRetention[0].getHoverEvent(), testEvent );
Assert.assertEquals( eventRetention[0].getClickEvent(), testClickEvent );
Assert.assertEquals( eventRetention[1].getColor(), ChatColor.WHITE );
Assert.assertEquals( eventRetention[1].getHoverEvent(), testEvent );
Assert.assertEquals( eventRetention[1].getClickEvent(), testClickEvent );
assertEquals( ChatColor.RED, extraGetter.apply( eventRetention, 0 ).getColor() );
assertEquals( testEvent, extraGetter.apply( eventRetention, 0 ).getHoverEvent() );
assertEquals( testClickEvent, extraGetter.apply( eventRetention, 0 ).getClickEvent() );
assertEquals( ChatColor.WHITE, extraGetter.apply( eventRetention, 1 ).getColor() );
assertEquals( testEvent, extraGetter.apply( eventRetention, 1 ).getHoverEvent() );
assertEquals( testClickEvent, extraGetter.apply( eventRetention, 1 ).getClickEvent() );
}
@Test(expected = IllegalArgumentException.class)
@Test
public void testLoopSimple()
{
TextComponent component = new TextComponent( "Testing" );
component.addExtra( component );
ComponentSerializer.toString( component );
assertThrows( IllegalArgumentException.class, () -> ComponentSerializer.toString( component ) );
}
@Test(expected = IllegalArgumentException.class)
@Test
public void testLoopComplex()
{
TextComponent a = new TextComponent( "A" );
@@ -469,7 +704,7 @@ public class ComponentsTest
a.addExtra( b );
b.addExtra( c );
c.addExtra( a );
ComponentSerializer.toString( a );
assertThrows( IllegalArgumentException.class, () -> ComponentSerializer.toString( a ) );
}
@Test
@@ -483,7 +718,7 @@ public class ComponentsTest
ComponentSerializer.toString( a );
}
@Test(expected = IllegalArgumentException.class)
@Test
public void testRepeatedError()
{
TextComponent a = new TextComponent( "A" );
@@ -495,7 +730,7 @@ public class ComponentsTest
a.addExtra( c );
c.addExtra( a );
a.addExtra( b );
ComponentSerializer.toString( a );
assertThrows( IllegalArgumentException.class, () -> ComponentSerializer.toString( a ) );
}
@Test
@@ -520,7 +755,7 @@ public class ComponentsTest
String emptyLegacyText = fromAndToLegacyText( "" );
// all invalid color codes and the trailing '§' should be ignored
Assert.assertEquals( emptyLegacyText, invalidColorCodesLegacyText );
assertEquals( emptyLegacyText, invalidColorCodesLegacyText );
}
@Test
@@ -529,12 +764,12 @@ public class ComponentsTest
String text = "§a";
BaseComponent[] converted = TextComponent.fromLegacyText( text );
Assert.assertEquals( ChatColor.GREEN, converted[0].getColor() );
assertEquals( ChatColor.GREEN, converted[0].getColor() );
String roundtripLegacyText = BaseComponent.toLegacyText( converted );
// color code should not be lost during conversion
Assert.assertEquals( text, roundtripLegacyText );
assertEquals( text, roundtripLegacyText );
}
@Test
@@ -546,7 +781,7 @@ public class ComponentsTest
TextComponent second = new TextComponent( "Hello, " );
second.addExtra( new TextComponent( "World!" ) );
Assert.assertEquals( first, second );
assertEquals( first, second );
}
@Test
@@ -558,7 +793,7 @@ public class ComponentsTest
TextComponent second = new TextComponent( "Hello, " );
second.addExtra( new TextComponent( "World!" ) );
Assert.assertNotEquals( first, second );
assertNotEquals( first, second );
}
@Test
@@ -569,10 +804,79 @@ public class ComponentsTest
BaseComponent[] reColored = TextComponent.fromLegacyText( legacy );
Assert.assertArrayEquals( hexColored, reColored );
assertArrayEquals( hexColored, reColored );
}
private String fromAndToLegacyText(String legacyText)
@Test
public void testLegacyResetInBuilderCreate()
{
this.testLegacyResetInBuilder(
ComponentBuilder::create,
ComponentSerializer::toString
);
}
@Test
public void testLegacyResetInBuilderBuild()
{
this.testLegacyResetInBuilder(
ComponentBuilder::build,
ComponentSerializer::toString
);
}
@Test
public void testHasFormatting()
{
BaseComponent component = new TextComponent();
assertFalse( component.hasFormatting() );
component.setBold( true );
assertTrue( component.hasFormatting() );
}
@Test
public void testStyleIsEmpty()
{
ComponentStyle style = ComponentStyle.builder().build();
assertTrue( style.isEmpty() );
style = ComponentStyle.builder()
.bold( true )
.build();
assertFalse( style.isEmpty() );
}
/*
* In legacy chat, colors and reset both reset all formatting.
* Make sure it works in combination with ComponentBuilder.
*/
private <T> void testLegacyResetInBuilder(Function<ComponentBuilder, T> componentBuilder, Function<T, String> componentSerializer)
{
ComponentBuilder builder = new ComponentBuilder();
BaseComponent[] a = TextComponent.fromLegacyText( "§4§n44444§rdd§6§l6666" );
String expected = "{\"extra\":[{\"underlined\":true,\"color\":\"dark_red\",\"text\":\"44444\"},{\"color\":"
+ "\"white\",\"text\":\"dd\"},{\"bold\":true,\"color\":\"gold\",\"text\":\"6666\"}],\"text\":\"\"}";
assertEquals( expected, ComponentSerializer.toString( a ) );
builder.append( a );
String test1 = componentSerializer.apply( componentBuilder.apply( builder ) );
assertEquals( expected, test1 );
BaseComponent[] b = TextComponent.fromLegacyText( "§rrrrr" );
builder.append( b );
String test2 = componentSerializer.apply( componentBuilder.apply( builder ) );
assertEquals(
"{\"extra\":[{\"underlined\":true,\"color\":\"dark_red\",\"text\":\"44444\"},"
+ "{\"color\":\"white\",\"text\":\"dd\"},{\"bold\":true,\"color\":\"gold\",\"text\":\"6666\"},"
+ "{\"color\":\"white\",\"text\":\"rrrr\"}],\"text\":\"\"}",
test2 );
}
private static String fromAndToLegacyText(String legacyText)
{
return BaseComponent.toLegacyText( TextComponent.fromLegacyText( legacyText ) );
}

View File

@@ -1,8 +1,8 @@
package net.md_5.bungee.api.chat;
import static org.junit.jupiter.api.Assertions.*;
import net.md_5.bungee.chat.ComponentSerializer;
import org.junit.Assert;
import org.junit.Test;
import org.junit.jupiter.api.Test;
public class TranslatableComponentTest
{
@@ -11,8 +11,8 @@ public class TranslatableComponentTest
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() );
assertEquals( "Test string with 2 placeholders: aoeu", testComponent.toPlainText() );
assertEquals( "§fTest string with §f2§f placeholders: §faoeu", testComponent.toLegacyText() );
}
@Test
@@ -22,7 +22,7 @@ public class TranslatableComponentTest
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 ) );
assertEquals( "Test string with a placeholder", TextComponent.toPlainText( baseComponents ) );
assertEquals( "§fTest string with §fa§f placeholder", TextComponent.toLegacyText( baseComponents ) );
}
}

View File

@@ -33,9 +33,9 @@
<!-- See http://checkstyle.sourceforge.net/config_filters.html -->
<module name="SuppressionCommentFilter"/>
<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"/>
@@ -54,11 +54,11 @@
<module name="OperatorWrap"/>
<module name="ParenPad">
<property name="option" value="nospace"/>
<property name="tokens" value="ANNOTATION, CTOR_DEF, METHOD_DEF"/>
<property name="tokens" value="ANNOTATION, CTOR_DEF, METHOD_DEF, LAMBDA"/>
</module>
<module name="ParenPad">
<property name="option" value="space"/>
<property name="tokens" value="ANNOTATION_FIELD_DEF, CTOR_CALL, DOT, ENUM_CONSTANT_DEF, EXPR, LITERAL_CATCH, LITERAL_DO, LITERAL_FOR, LITERAL_IF, LITERAL_NEW, LITERAL_SWITCH, LITERAL_SYNCHRONIZED, LITERAL_WHILE, METHOD_CALL, QUESTION, RESOURCE_SPECIFICATION, SUPER_CTOR_CALL, LAMBDA"/>
<property name="tokens" value="ANNOTATION_FIELD_DEF, CTOR_CALL, DOT, ENUM_CONSTANT_DEF, EXPR, LITERAL_CATCH, LITERAL_DO, LITERAL_FOR, LITERAL_IF, LITERAL_NEW, LITERAL_SWITCH, LITERAL_SYNCHRONIZED, LITERAL_WHILE, METHOD_CALL, QUESTION, RESOURCE_SPECIFICATION, SUPER_CTOR_CALL, RECORD_DEF"/>
</module>
<module name="SingleSpaceSeparator"/>
<module name="TypecastParenPad"/>
@@ -84,4 +84,6 @@
<module name="Indentation"/>
<module name="UpperEll"/>
</module>
<module name="SuppressWarningsFilter"/>
</module>

View File

@@ -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.16-R0.4-SNAPSHOT</version>
<version>1.20-R0.3-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-config</artifactId>
<version>1.16-R0.4-SNAPSHOT</version>
<version>1.20-R0.3-SNAPSHOT</version>
<packaging>jar</packaging>
<name>BungeeCord-Config</name>
@@ -22,14 +21,14 @@
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.0</version>
<version>2.10.1</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>1.26</version>
<version>2.2</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>

View File

@@ -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

View File

@@ -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,11 +8,13 @@ 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;
import lombok.NoArgsConstructor;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.LoaderOptions;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.Constructor;
import org.yaml.snakeyaml.nodes.Node;
@@ -29,7 +30,10 @@ public class YamlConfiguration extends ConfigurationProvider
@Override
protected Yaml initialValue()
{
Representer representer = new Representer()
DumperOptions options = new DumperOptions();
options.setDefaultFlowStyle( DumperOptions.FlowStyle.BLOCK );
Representer representer = new Representer( options )
{
{
representers.put( Configuration.class, new Represent()
@@ -43,17 +47,14 @@ public class YamlConfiguration extends ConfigurationProvider
}
};
DumperOptions options = new DumperOptions();
options.setDefaultFlowStyle( DumperOptions.FlowStyle.BLOCK );
return new Yaml( new Constructor(), representer, options );
return new Yaml( new Constructor( new LoaderOptions() ), representer, options );
}
};
@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 );
}

View File

@@ -1,30 +1,25 @@
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()
{
// CHECKSTYLE:OFF
return Arrays.asList( new Object[][]
{
public static Stream<Arguments> data()
{
return Stream.of(
Arguments.of(
// provider
YamlConfiguration.class,
// testDocument
@@ -73,8 +68,8 @@ public class CompoundConfigurationTest
+ "null:\n"
+ " null: object\n"
+ " object: null\n"
},
{
),
Arguments.of(
// provider
JsonConfiguration.class,
// testDocument
@@ -131,18 +126,13 @@ public class CompoundConfigurationTest
+ " \"object\": null\n"
+ " }\n"
+ "}"
)
);
}
} );
// CHECKSTYLE:ON
}
//
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 );
}
}

View File

@@ -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" ) );
}
}

View File

@@ -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.16-R0.4-SNAPSHOT</version>
<version>1.20-R0.3-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-event</artifactId>
<version>1.16-R0.4-SNAPSHOT</version>
<version>1.20-R0.3-SNAPSHOT</version>
<packaging>jar</packaging>
<name>BungeeCord-Event</name>

View File

@@ -1,5 +1,6 @@
package net.md_5.bungee.event;
import com.google.common.collect.ImmutableSet;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.MessageFormat;
@@ -41,6 +42,8 @@ public class EventBus
{
for ( EventHandlerMethod method : handlers )
{
long start = System.nanoTime();
try
{
method.invoke( event );
@@ -54,6 +57,15 @@ public class EventBus
{
logger.log( Level.WARNING, MessageFormat.format( "Error dispatching event {0} to listener {1}", event, method.getListener() ), ex.getCause() );
}
long elapsed = System.nanoTime() - start;
if ( elapsed > 50000000 )
{
logger.log( Level.WARNING, "Plugin listener {0} took {1}ms to process event {2}!", new Object[]
{
method.getListener().getClass().getName(), elapsed / 1000000, event
} );
}
}
}
}
@@ -61,7 +73,8 @@ public class EventBus
private Map<Class<?>, Map<Byte, Set<Method>>> findHandlers(Object listener)
{
Map<Class<?>, Map<Byte, Set<Method>>> handler = new HashMap<>();
for ( Method m : listener.getClass().getDeclaredMethods() )
Set<Method> methods = ImmutableSet.<Method>builder().add( listener.getClass().getMethods() ).add( listener.getClass().getDeclaredMethods() ).build();
for ( final Method m : methods )
{
EventHandler annotation = m.getAnnotation( EventHandler.class );
if ( annotation != null )
@@ -75,18 +88,8 @@ public class EventBus
} );
continue;
}
Map<Byte, Set<Method>> prioritiesMap = handler.get( params[0] );
if ( prioritiesMap == null )
{
prioritiesMap = new HashMap<>();
handler.put( params[0], prioritiesMap );
}
Set<Method> priority = prioritiesMap.get( annotation.priority() );
if ( priority == null )
{
priority = new HashSet<>();
prioritiesMap.put( annotation.priority(), priority );
}
Map<Byte, Set<Method>> prioritiesMap = handler.computeIfAbsent( params[0], k -> new HashMap<>() );
Set<Method> priority = prioritiesMap.computeIfAbsent( annotation.priority(), k -> new HashSet<>() );
priority.add( m );
}
}
@@ -101,22 +104,11 @@ public class EventBus
{
for ( Map.Entry<Class<?>, Map<Byte, Set<Method>>> e : handler.entrySet() )
{
Map<Byte, Map<Object, Method[]>> prioritiesMap = byListenerAndPriority.get( e.getKey() );
if ( prioritiesMap == null )
{
prioritiesMap = new HashMap<>();
byListenerAndPriority.put( e.getKey(), prioritiesMap );
}
Map<Byte, Map<Object, Method[]>> prioritiesMap = byListenerAndPriority.computeIfAbsent( e.getKey(), k -> new HashMap<>() );
for ( Map.Entry<Byte, Set<Method>> entry : e.getValue().entrySet() )
{
Map<Object, Method[]> currentPriorityMap = prioritiesMap.get( entry.getKey() );
if ( currentPriorityMap == null )
{
currentPriorityMap = new HashMap<>();
prioritiesMap.put( entry.getKey(), currentPriorityMap );
}
Method[] baked = new Method[ entry.getValue().size() ];
currentPriorityMap.put( listener, entry.getValue().toArray( baked ) );
Map<Object, Method[]> currentPriorityMap = prioritiesMap.computeIfAbsent( entry.getKey(), k -> new HashMap<>() );
currentPriorityMap.put( listener, entry.getValue().toArray( new Method[ 0 ] ) );
}
bakeHandlers( e.getKey() );
}
@@ -194,7 +186,7 @@ public class EventBus
}
}
} while ( value++ < Byte.MAX_VALUE );
byEventBaked.put( eventClass, handlersList.toArray( new EventHandlerMethod[ handlersList.size() ] ) );
byEventBaked.put( eventClass, handlersList.toArray( new EventHandlerMethod[ 0 ] ) );
} else
{
byEventBaked.remove( eventClass );

View File

@@ -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();
}

View File

@@ -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();
}
}

View File

@@ -0,0 +1,26 @@
package net.md_5.bungee.event;
import static org.junit.jupiter.api.Assertions.*;
import java.util.concurrent.CountDownLatch;
import org.junit.jupiter.api.Test;
public class SubclassTest extends EventBusTest
{
private final CountDownLatch latch = new CountDownLatch( 1 );
@Test
@Override
public void testNestedEvents()
{
super.testNestedEvents();
assertEquals( 0, latch.getCount() );
}
@EventHandler
protected void extraListener(FirstEvent event)
{
assertEquals( 1, latch.getCount() );
latch.countDown();
}
}

View File

@@ -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

View File

@@ -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.16-R0.4-SNAPSHOT</version>
<version>1.20-R0.3-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-log</artifactId>
<version>1.16-R0.4-SNAPSHOT</version>
<version>1.20-R0.3-SNAPSHOT</version>
<packaging>jar</packaging>
<name>BungeeCord-Log</name>
@@ -26,7 +25,7 @@
<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>

View File

@@ -13,19 +13,23 @@ 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)
{
super( loggerName, null );
setLevel( Level.ALL );
setUseParentHandlers( false );
try
{
FileHandler fileHandler = new FileHandler( filePattern, 1 << 24, 8, true );
fileHandler.setLevel( Level.parse( System.getProperty( "net.md_5.bungee.file-log-level", "INFO" ) ) );
fileHandler.setFormatter( new ConciseFormatter( false ) );
addHandler( fileHandler );

View File

@@ -0,0 +1,29 @@
package net.md_5.bungee.log;
import java.util.logging.Handler;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
public class LoggingForwardHandler extends Handler
{
private final Logger logger;
@Override
public void publish(LogRecord record)
{
logger.log( record );
}
@Override
public void flush()
{
}
@Override
public void close() throws SecurityException
{
}
}

View File

@@ -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 ) )
{

View File

@@ -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.16-R0.4-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-module-cmd-alert</artifactId>
<version>1.16-R0.4-SNAPSHOT</version>
<packaging>jar</packaging>
<name>cmd_alert</name>
<description>Provides the alert and alertraw commands</description>
</project>

View File

@@ -1,46 +0,0 @@
package net.md_5.bungee.module.cmd.alert;
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].startsWith( "&h" ) )
{
// Remove &h
args[0] = args[0].substring( 2, args[0].length() );
} 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 ) );
}
}
}

View File

@@ -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() ) );
}
}
}
}
}

View File

@@ -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() );
}
}

View File

@@ -1,5 +0,0 @@
name: ${project.name}
main: net.md_5.bungee.module.cmd.alert.PluginAlert
version: ${describe}
description: ${project.description}
author: ${module.author}

View File

@@ -1,31 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project-shared-configuration>
<!--
This file contains additional configuration written by modules in the NetBeans IDE.
The configuration is intended to be shared among all the users of project and
therefore it is assumed to be part of version control checkout.
Without this configuration present, some functionality in the IDE may be limited or fail altogether.
-->
<properties xmlns="http://www.netbeans.org/ns/maven-properties-data/1">
<!--
Properties that influence various parts of the IDE, especially code formatting and the like.
You can copy and paste the single properties, into the pom.xml file and the IDE will pick them up.
That way multiple projects can share the same settings (useful for formatting rules for example).
Any value defined here will override the pom.xml file value but is only applicable to the current project.
-->
<org-netbeans-modules-editor-indent.CodeStyle.usedProfile>project</org-netbeans-modules-editor-indent.CodeStyle.usedProfile>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>
</properties>
</project-shared-configuration>

View File

@@ -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.16-R0.4-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-module-cmd-find</artifactId>
<version>1.16-R0.4-SNAPSHOT</version>
<packaging>jar</packaging>
<name>cmd_find</name>
<description>Provides the find command</description>
</project>

View File

@@ -1,34 +0,0 @@
package net.md_5.bungee.module.cmd.find;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.command.PlayerCommand;
public class CommandFind extends PlayerCommand
{
public CommandFind()
{
super( "find", "bungeecord.command.find" );
}
@Override
public void execute(CommandSender sender, String[] args)
{
if ( args.length != 1 )
{
sender.sendMessage( ProxyServer.getInstance().getTranslation( "username_needed" ) );
} else
{
ProxiedPlayer player = ProxyServer.getInstance().getPlayer( args[0] );
if ( player == null || player.getServer() == null )
{
sender.sendMessage( ProxyServer.getInstance().getTranslation( "user_not_online" ) );
} else
{
sender.sendMessage( ProxyServer.getInstance().getTranslation( "user_online_at", player.getName(), player.getServer().getInfo().getName() ) );
}
}
}
}

View File

@@ -1,13 +0,0 @@
package net.md_5.bungee.module.cmd.find;
import net.md_5.bungee.api.plugin.Plugin;
public class PluginFind extends Plugin
{
@Override
public void onEnable()
{
getProxy().getPluginManager().registerCommand( this, new CommandFind() );
}
}

View File

@@ -1,5 +0,0 @@
name: ${project.name}
main: net.md_5.bungee.module.cmd.find.PluginFind
version: ${describe}
description: ${project.description}
author: ${module.author}

View File

@@ -1,31 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project-shared-configuration>
<!--
This file contains additional configuration written by modules in the NetBeans IDE.
The configuration is intended to be shared among all the users of project and
therefore it is assumed to be part of version control checkout.
Without this configuration present, some functionality in the IDE may be limited or fail altogether.
-->
<properties xmlns="http://www.netbeans.org/ns/maven-properties-data/1">
<!--
Properties that influence various parts of the IDE, especially code formatting and the like.
You can copy and paste the single properties, into the pom.xml file and the IDE will pick them up.
That way multiple projects can share the same settings (useful for formatting rules for example).
Any value defined here will override the pom.xml file value but is only applicable to the current project.
-->
<org-netbeans-modules-editor-indent.CodeStyle.usedProfile>project</org-netbeans-modules-editor-indent.CodeStyle.usedProfile>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>
</properties>
</project-shared-configuration>

View File

@@ -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.16-R0.4-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-module-cmd-list</artifactId>
<version>1.16-R0.4-SNAPSHOT</version>
<packaging>jar</packaging>
<name>cmd_list</name>
<description>Provides the glist command</description>
</project>

View File

@@ -1,47 +0,0 @@
package net.md_5.bungee.module.cmd.list;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import net.md_5.bungee.Util;
import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.config.ServerInfo;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.plugin.Command;
/**
* Command to list all players connected to the proxy.
*/
public class CommandList extends Command
{
public CommandList()
{
super( "glist", "bungeecord.command.list" );
}
@Override
public void execute(CommandSender sender, String[] args)
{
for ( ServerInfo server : ProxyServer.getInstance().getServers().values() )
{
if ( !server.canAccess( sender ) )
{
continue;
}
List<String> players = new ArrayList<>();
for ( ProxiedPlayer player : server.getPlayers() )
{
players.add( player.getDisplayName() );
}
Collections.sort( players, String.CASE_INSENSITIVE_ORDER );
sender.sendMessage( ProxyServer.getInstance().getTranslation( "command_list", server.getName(), server.getPlayers().size(), Util.format( players, ChatColor.RESET + ", " ) ) );
}
sender.sendMessage( ProxyServer.getInstance().getTranslation( "total_players", ProxyServer.getInstance().getOnlineCount() ) );
}
}

View File

@@ -1,13 +0,0 @@
package net.md_5.bungee.module.cmd.list;
import net.md_5.bungee.api.plugin.Plugin;
public class PluginList extends Plugin
{
@Override
public void onEnable()
{
getProxy().getPluginManager().registerCommand( this, new CommandList() );
}
}

View File

@@ -1,5 +0,0 @@
name: ${project.name}
main: net.md_5.bungee.module.cmd.list.PluginList
version: ${describe}
description: ${project.description}
author: ${module.author}

View File

@@ -1,31 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project-shared-configuration>
<!--
This file contains additional configuration written by modules in the NetBeans IDE.
The configuration is intended to be shared among all the users of project and
therefore it is assumed to be part of version control checkout.
Without this configuration present, some functionality in the IDE may be limited or fail altogether.
-->
<properties xmlns="http://www.netbeans.org/ns/maven-properties-data/1">
<!--
Properties that influence various parts of the IDE, especially code formatting and the like.
You can copy and paste the single properties, into the pom.xml file and the IDE will pick them up.
That way multiple projects can share the same settings (useful for formatting rules for example).
Any value defined here will override the pom.xml file value but is only applicable to the current project.
-->
<org-netbeans-modules-editor-indent.CodeStyle.usedProfile>project</org-netbeans-modules-editor-indent.CodeStyle.usedProfile>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>
</properties>
</project-shared-configuration>

View File

@@ -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.16-R0.4-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-module-cmd-send</artifactId>
<version>1.16-R0.4-SNAPSHOT</version>
<packaging>jar</packaging>
<name>cmd_send</name>
<description>Provides the gsend command</description>
</project>

View File

@@ -1,200 +0,0 @@
package net.md_5.bungee.module.cmd.send;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableSet;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import net.md_5.bungee.api.Callback;
import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.ServerConnectRequest;
import net.md_5.bungee.api.chat.ComponentBuilder;
import net.md_5.bungee.api.chat.HoverEvent;
import net.md_5.bungee.api.config.ServerInfo;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.event.ServerConnectEvent;
import net.md_5.bungee.api.plugin.Command;
import net.md_5.bungee.api.plugin.TabExecutor;
public class CommandSend extends Command implements TabExecutor
{
protected static class SendCallback
{
private final Map<ServerConnectRequest.Result, List<String>> results = new HashMap<>();
private final CommandSender sender;
private int count = 0;
public SendCallback(CommandSender sender)
{
this.sender = sender;
for ( ServerConnectRequest.Result result : ServerConnectRequest.Result.values() )
{
results.put( result, new ArrayList<String>() );
}
}
public void lastEntryDone()
{
sender.sendMessage( ChatColor.GREEN.toString() + ChatColor.BOLD + "Send Results:" );
for ( Map.Entry<ServerConnectRequest.Result, List<String>> entry : results.entrySet() )
{
ComponentBuilder builder = new ComponentBuilder( "" );
if ( !entry.getValue().isEmpty() )
{
builder.event( new HoverEvent( HoverEvent.Action.SHOW_TEXT,
new ComponentBuilder( Joiner.on( ", " ).join( entry.getValue() ) ).color( ChatColor.YELLOW ).create() ) );
}
builder.append( entry.getKey().name() + ": " ).color( ChatColor.GREEN );
builder.append( "" + entry.getValue().size() ).bold( true );
sender.sendMessage( builder.create() );
}
}
public static class Entry implements Callback<ServerConnectRequest.Result>
{
private final SendCallback callback;
private final ProxiedPlayer player;
private final ServerInfo target;
public Entry(SendCallback callback, ProxiedPlayer player, ServerInfo target)
{
this.callback = callback;
this.player = player;
this.target = target;
this.callback.count++;
}
@Override
public void done(ServerConnectRequest.Result result, Throwable error)
{
callback.results.get( result ).add( player.getName() );
if ( result == ServerConnectRequest.Result.SUCCESS )
{
player.sendMessage( ProxyServer.getInstance().getTranslation( "you_got_summoned", target.getName(), callback.sender.getName() ) );
}
if ( --callback.count == 0 )
{
callback.lastEntryDone();
}
}
}
}
public CommandSend()
{
super( "send", "bungeecord.command.send" );
}
@Override
public void execute(CommandSender sender, String[] args)
{
if ( args.length != 2 )
{
sender.sendMessage( ProxyServer.getInstance().getTranslation( "send_cmd_usage" ) );
return;
}
ServerInfo server = ProxyServer.getInstance().getServerInfo( args[1] );
if ( server == null )
{
sender.sendMessage( ProxyServer.getInstance().getTranslation( "no_server" ) );
return;
}
List<ProxiedPlayer> targets;
if ( args[0].equalsIgnoreCase( "all" ) )
{
targets = new ArrayList<>( ProxyServer.getInstance().getPlayers() );
} else if ( args[0].equalsIgnoreCase( "current" ) )
{
if ( !( sender instanceof ProxiedPlayer ) )
{
sender.sendMessage( ProxyServer.getInstance().getTranslation( "player_only" ) );
return;
}
ProxiedPlayer player = (ProxiedPlayer) sender;
targets = new ArrayList<>( player.getServer().getInfo().getPlayers() );
} else
{
// If we use a server name, send the entire server. This takes priority over players.
ServerInfo serverTarget = ProxyServer.getInstance().getServerInfo( args[0] );
if ( serverTarget != null )
{
targets = new ArrayList<>( serverTarget.getPlayers() );
} else
{
ProxiedPlayer player = ProxyServer.getInstance().getPlayer( args[0] );
if ( player == null )
{
sender.sendMessage( ProxyServer.getInstance().getTranslation( "user_not_online" ) );
return;
}
targets = Collections.singletonList( player );
}
}
final SendCallback callback = new SendCallback( sender );
for ( ProxiedPlayer player : targets )
{
ServerConnectRequest request = ServerConnectRequest.builder()
.target( server )
.reason( ServerConnectEvent.Reason.COMMAND )
.callback( new SendCallback.Entry( callback, player, server ) )
.build();
player.connect( request );
}
sender.sendMessage( ChatColor.DARK_GREEN + "Attempting to send " + targets.size() + " players to " + server.getName() );
}
@Override
public Iterable<String> onTabComplete(CommandSender sender, String[] args)
{
if ( args.length > 2 || args.length == 0 )
{
return ImmutableSet.of();
}
Set<String> matches = new HashSet<>();
if ( args.length == 1 )
{
String search = args[0].toLowerCase( Locale.ROOT );
for ( ProxiedPlayer player : ProxyServer.getInstance().getPlayers() )
{
if ( player.getName().toLowerCase( Locale.ROOT ).startsWith( search ) )
{
matches.add( player.getName() );
}
}
if ( "all".startsWith( search ) )
{
matches.add( "all" );
}
if ( "current".startsWith( search ) )
{
matches.add( "current" );
}
} else
{
String search = args[1].toLowerCase( Locale.ROOT );
for ( String server : ProxyServer.getInstance().getServers().keySet() )
{
if ( server.toLowerCase( Locale.ROOT ).startsWith( search ) )
{
matches.add( server );
}
}
}
return matches;
}
}

View File

@@ -1,13 +0,0 @@
package net.md_5.bungee.module.cmd.send;
import net.md_5.bungee.api.plugin.Plugin;
public class PluginSend extends Plugin
{
@Override
public void onEnable()
{
getProxy().getPluginManager().registerCommand( this, new CommandSend() );
}
}

View File

@@ -1,5 +0,0 @@
name: ${project.name}
main: net.md_5.bungee.module.cmd.send.PluginSend
version: ${describe}
description: ${project.description}
author: ${module.author}

View File

@@ -1,31 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project-shared-configuration>
<!--
This file contains additional configuration written by modules in the NetBeans IDE.
The configuration is intended to be shared among all the users of project and
therefore it is assumed to be part of version control checkout.
Without this configuration present, some functionality in the IDE may be limited or fail altogether.
-->
<properties xmlns="http://www.netbeans.org/ns/maven-properties-data/1">
<!--
Properties that influence various parts of the IDE, especially code formatting and the like.
You can copy and paste the single properties, into the pom.xml file and the IDE will pick them up.
That way multiple projects can share the same settings (useful for formatting rules for example).
Any value defined here will override the pom.xml file value but is only applicable to the current project.
-->
<org-netbeans-modules-editor-indent.CodeStyle.usedProfile>project</org-netbeans-modules-editor-indent.CodeStyle.usedProfile>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>
</properties>
</project-shared-configuration>

View File

@@ -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.16-R0.4-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-module-cmd-server</artifactId>
<version>1.16-R0.4-SNAPSHOT</version>
<packaging>jar</packaging>
<name>cmd_server</name>
<description>Provides the server command</description>
</project>

View File

@@ -1,104 +0,0 @@
package net.md_5.bungee.module.cmd.server;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import java.util.Collections;
import java.util.Locale;
import java.util.Map;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.chat.ClickEvent;
import net.md_5.bungee.api.chat.ComponentBuilder;
import net.md_5.bungee.api.chat.HoverEvent;
import net.md_5.bungee.api.chat.TextComponent;
import net.md_5.bungee.api.config.ServerInfo;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.event.ServerConnectEvent;
import net.md_5.bungee.api.plugin.Command;
import net.md_5.bungee.api.plugin.TabExecutor;
/**
* Command to list and switch a player between available servers.
*/
public class CommandServer extends Command implements TabExecutor
{
public CommandServer()
{
super( "server", "bungeecord.command.server" );
}
@Override
public void execute(CommandSender sender, String[] args)
{
Map<String, ServerInfo> servers = ProxyServer.getInstance().getServers();
if ( args.length == 0 )
{
if ( sender instanceof ProxiedPlayer )
{
sender.sendMessage( ProxyServer.getInstance().getTranslation( "current_server", ( (ProxiedPlayer) sender ).getServer().getInfo().getName() ) );
}
ComponentBuilder serverList = new ComponentBuilder().appendLegacy( ProxyServer.getInstance().getTranslation( "server_list" ) );
boolean first = true;
for ( ServerInfo server : servers.values() )
{
if ( server.canAccess( sender ) )
{
TextComponent serverTextComponent = new TextComponent( first ? server.getName() : ", " + server.getName() );
int count = server.getPlayers().size();
serverTextComponent.setHoverEvent( new HoverEvent(
HoverEvent.Action.SHOW_TEXT,
new ComponentBuilder( count + ( count == 1 ? " player" : " players" ) + "\n" ).appendLegacy( ProxyServer.getInstance().getTranslation( "click_to_connect" ) ).create() )
);
serverTextComponent.setClickEvent( new ClickEvent( ClickEvent.Action.RUN_COMMAND, "/server " + server.getName() ) );
serverList.append( serverTextComponent );
first = false;
}
}
sender.sendMessage( serverList.create() );
} else
{
if ( !( sender instanceof ProxiedPlayer ) )
{
return;
}
ProxiedPlayer player = (ProxiedPlayer) sender;
ServerInfo server = servers.get( args[0] );
if ( server == null )
{
player.sendMessage( ProxyServer.getInstance().getTranslation( "no_server" ) );
} else if ( !server.canAccess( player ) )
{
player.sendMessage( ProxyServer.getInstance().getTranslation( "no_server_permission" ) );
} else
{
player.connect( server, ServerConnectEvent.Reason.COMMAND );
}
}
}
@Override
public Iterable<String> onTabComplete(final CommandSender sender, final String[] args)
{
return ( args.length > 1 ) ? Collections.EMPTY_LIST : Iterables.transform( Iterables.filter( ProxyServer.getInstance().getServers().values(), new Predicate<ServerInfo>()
{
private final String lower = ( args.length == 0 ) ? "" : args[0].toLowerCase( Locale.ROOT );
@Override
public boolean apply(ServerInfo input)
{
return input.getName().toLowerCase( Locale.ROOT ).startsWith( lower ) && input.canAccess( sender );
}
} ), new Function<ServerInfo, String>()
{
@Override
public String apply(ServerInfo input)
{
return input.getName();
}
} );
}
}

View File

@@ -1,13 +0,0 @@
package net.md_5.bungee.module.cmd.server;
import net.md_5.bungee.api.plugin.Plugin;
public class PluginServer extends Plugin
{
@Override
public void onEnable()
{
getProxy().getPluginManager().registerCommand( this, new CommandServer() );
}
}

View File

@@ -1,5 +0,0 @@
name: ${project.name}
main: net.md_5.bungee.module.cmd.server.PluginServer
version: ${describe}
description: ${project.description}
author: ${module.author}

View File

@@ -1,54 +0,0 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-parent</artifactId>
<version>1.16-R0.4-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-module</artifactId>
<version>1.16-R0.4-SNAPSHOT</version>
<packaging>pom</packaging>
<name>BungeeCord Modules</name>
<description>Parent project for all BungeeCord modules.</description>
<modules>
<module>cmd-alert</module>
<module>cmd-find</module>
<module>cmd-list</module>
<module>cmd-send</module>
<module>cmd-server</module>
<module>reconnect-yaml</module>
</modules>
<properties>
<module.author>SpigotMC</module.author>
<maven.deploy.skip>true</maven.deploy.skip>
<maven.javadoc.skip>true</maven.javadoc.skip>
</properties>
<dependencies>
<dependency>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-api</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<finalName>${project.name}</finalName>
<resources>
<resource>
<filtering>true</filtering>
<directory>${basedir}/src/main/resources</directory>
</resource>
</resources>
</build>
</project>

View File

@@ -1,31 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project-shared-configuration>
<!--
This file contains additional configuration written by modules in the NetBeans IDE.
The configuration is intended to be shared among all the users of project and
therefore it is assumed to be part of version control checkout.
Without this configuration present, some functionality in the IDE may be limited or fail altogether.
-->
<properties xmlns="http://www.netbeans.org/ns/maven-properties-data/1">
<!--
Properties that influence various parts of the IDE, especially code formatting and the like.
You can copy and paste the single properties, into the pom.xml file and the IDE will pick them up.
That way multiple projects can share the same settings (useful for formatting rules for example).
Any value defined here will override the pom.xml file value but is only applicable to the current project.
-->
<org-netbeans-modules-editor-indent.CodeStyle.usedProfile>project</org-netbeans-modules-editor-indent.CodeStyle.usedProfile>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>
</properties>
</project-shared-configuration>

View File

@@ -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.16-R0.4-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-module-reconnect-yaml</artifactId>
<version>1.16-R0.4-SNAPSHOT</version>
<packaging>jar</packaging>
<name>reconnect_yaml</name>
<description>Provides reconnect location functionality in locations.yml</description>
</project>

View File

@@ -1,22 +0,0 @@
package net.md_5.bungee.module.reconnect.yaml;
import net.md_5.bungee.api.config.ListenerInfo;
import net.md_5.bungee.api.plugin.Plugin;
public class PluginYaml extends Plugin
{
@Override
public void onEnable()
{
// TODO: Abstract this for other reconnect modules
for ( ListenerInfo info : getProxy().getConfig().getListeners() )
{
if ( !info.isForceDefault() && getProxy().getReconnectHandler() == null )
{
getProxy().setReconnectHandler( new YamlReconnectHandler() );
break;
}
}
}
}

View File

@@ -1,115 +0,0 @@
package net.md_5.bungee.module.reconnect.yaml;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.logging.Level;
import net.md_5.bungee.api.AbstractReconnectHandler;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.config.ServerInfo;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.util.CaseInsensitiveMap;
import org.yaml.snakeyaml.Yaml;
public class YamlReconnectHandler extends AbstractReconnectHandler
{
private final Yaml yaml = new Yaml();
private final File file = new File( "locations.yml" );
private final ReadWriteLock lock = new ReentrantReadWriteLock();
/*========================================================================*/
private CaseInsensitiveMap<String> data;
@SuppressWarnings("unchecked")
public YamlReconnectHandler()
{
try
{
file.createNewFile();
try ( FileReader rd = new FileReader( file ) )
{
Map map = yaml.loadAs( rd, Map.class );
if ( map != null )
{
data = new CaseInsensitiveMap<>( map );
}
}
} catch ( Exception ex )
{
file.renameTo( new File( "locations.yml.old" ) );
ProxyServer.getInstance().getLogger().log( Level.WARNING, "Could not load reconnect locations, resetting them" );
}
if ( data == null )
{
data = new CaseInsensitiveMap<>();
}
}
@Override
protected ServerInfo getStoredServer(ProxiedPlayer player)
{
ServerInfo server = null;
lock.readLock().lock();
try
{
server = ProxyServer.getInstance().getServerInfo( data.get( key( player ) ) );
} finally
{
lock.readLock().unlock();
}
return server;
}
@Override
public void setServer(ProxiedPlayer player)
{
lock.writeLock().lock();
try
{
data.put( key( player ), ( player.getReconnectServer() != null ) ? player.getReconnectServer().getName() : player.getServer().getInfo().getName() );
} finally
{
lock.writeLock().unlock();
}
}
private String key(ProxiedPlayer player)
{
InetSocketAddress host = player.getPendingConnection().getVirtualHost();
return player.getName() + ";" + host.getHostString() + ":" + host.getPort();
}
@Override
public void save()
{
Map<String, String> copy = new HashMap<>();
lock.readLock().lock();
try
{
copy.putAll( data );
} finally
{
lock.readLock().unlock();
}
try ( FileWriter wr = new FileWriter( file ) )
{
yaml.dump( copy, wr );
} catch ( IOException ex )
{
ProxyServer.getInstance().getLogger().log( Level.WARNING, "Could not save reconnect locations", ex );
}
}
@Override
public void close()
{
}
}

View File

@@ -1,5 +0,0 @@
name: ${project.name}
main: net.md_5.bungee.module.reconnect.yaml.PluginYaml
version: ${describe}
description: ${project.description}
author: ${module.author}

View File

@@ -1,6 +1,14 @@
#!/bin/sh
CXX="g++ -shared -fPIC -O3 -Wall -Werror -I$JAVA_HOME/include/ -I$JAVA_HOME/include/linux/"
set -eu
$CXX src/main/c/NativeCipherImpl.cpp -o src/main/resources/native-cipher.so -lcrypto
$CXX src/main/c/NativeCompressImpl.cpp -o src/main/resources/native-compress.so -lz
echo "Compiling mbedtls"
(cd mbedtls && make no_test)
echo "Compiling zlib"
(cd zlib && CFLAGS=-fPIC ./configure --static && make)
CXX="g++ -shared -fPIC -Wl,--wrap=memcpy -O3 -Wall -Werror -I$JAVA_HOME/include/ -I$JAVA_HOME/include/linux/"
$CXX -Imbedtls/include src/main/c/NativeCipherImpl.cpp -o src/main/resources/native-cipher.so mbedtls/library/libmbedcrypto.a
$CXX -Izlib src/main/c/NativeCompressImpl.cpp -o src/main/resources/native-compress.so zlib/libz.a

1
native/mbedtls Submodule

Submodule native/mbedtls added at 8c89224991

Some files were not shown because too many files have changed in this diff Show More