mirror of
https://github.com/NEZNAMY/TAB.git
synced 2026-11-13 12:42:06 -05:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
622deb6fd7 | ||
|
|
7f41421d65 | ||
|
|
73e706465a | ||
|
|
a8c543ca9e | ||
|
|
9594ff452b | ||
|
|
d5c81298dd | ||
|
|
88faacb240 | ||
|
|
0d2a04b3a5 | ||
|
|
f8a90b28b5 | ||
|
|
a948febb18 | ||
|
|
8e33481b97 | ||
|
|
f54be214f9 | ||
|
|
d50b47acb5 | ||
|
|
31011c243a | ||
|
|
f4aa03f20d | ||
|
|
28aacaea45 | ||
|
|
d4fd9a2b78 | ||
|
|
663e0be357 | ||
|
|
14d29577c5 | ||
|
|
951f8072c1 | ||
|
|
05f042eda0 | ||
|
|
b00c2fbcb4 | ||
|
|
dde4866e50 | ||
|
|
9fa6b21c08 | ||
|
|
e95e6fc20c | ||
|
|
c7a3b00c3c | ||
|
|
74bc0e0cb7 | ||
|
|
6248008b4d | ||
|
|
2d91e165ce | ||
|
|
b1220550eb | ||
|
|
680ff3412f | ||
|
|
799f6b8215 | ||
|
|
1be224b7de | ||
|
|
a32adfbfc7 | ||
|
|
dda415351a | ||
|
|
685e4b9faa | ||
|
|
1f842563b3 | ||
|
|
f237b61065 |
No files matched your search
@@ -1 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="92" height="20" role="img" aria-label="Release: 5.2.0"><title>Release: 5.2.0</title><linearGradient id="s" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="r"><rect width="92" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#r)"><rect width="53" height="20" fill="#555"/><rect x="53" width="39" height="20" fill="#007ec6"/><rect width="92" height="20" fill="url(#s)"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><text aria-hidden="true" x="275" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="430">Release</text><text x="275" y="140" transform="scale(.1)" fill="#fff" textLength="430">Release</text><text aria-hidden="true" x="715" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="290">5.2.0</text><text x="715" y="140" transform="scale(.1)" fill="#fff" textLength="290">5.2.0</text></g></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="92" height="20" role="img" aria-label="Release: 5.2.1"><title>Release: 5.2.1</title><linearGradient id="s" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="r"><rect width="92" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#r)"><rect width="53" height="20" fill="#555"/><rect x="53" width="39" height="20" fill="#007ec6"/><rect width="92" height="20" fill="url(#s)"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><text aria-hidden="true" x="275" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="430">Release</text><text x="275" y="140" transform="scale(.1)" fill="#fff" textLength="430">Release</text><text aria-hidden="true" x="715" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="290">5.2.1</text><text x="715" y="140" transform="scale(.1)" fill="#fff" textLength="290">5.2.1</text></g></svg>
|
||||
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
@@ -274,7 +274,7 @@ if __name__ == "__main__":
|
||||
]
|
||||
)
|
||||
|
||||
release = "5.2.0"
|
||||
release = "5.2.1"
|
||||
download_image(f"https://img.shields.io/badge/Release-{release}-blue.svg", "Badge_Release.svg")
|
||||
|
||||
minecraft = "1.5 - 1.21.5".replace(" ", "%20").replace("-", "--")
|
||||
|
||||
@@ -70,7 +70,7 @@ TAB's shared module is compiled with Java 8. For the platforms themselves, TAB d
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
Modded platforms only support the latest MC version(s). For older MC versions try [modrinth](https://modrinth.com/plugin/tab-was-taken)'s version download filter. If you need a backport and no older version of TAB supports your desired server version, you'll need to edit it in the source code. Customers can ask for a backport on the customer discord.
|
||||
Modded platforms only support the latest MC version(s). For older MC versions try [modrinth](https://modrinth.com/plugin/tab-was-taken)'s version download filter.
|
||||
|
||||
<sup>1</sup> Latest only doesn't mean only the latest build will work,
|
||||
it means the plugin was made to be compatible with the latest version/build.
|
||||
|
||||
@@ -35,7 +35,7 @@ For Maven users, you can add the API dependency like this:
|
||||
<dependency>
|
||||
<groupId>com.github.NEZNAMY</groupId>
|
||||
<artifactId>TAB-API</artifactId>
|
||||
<version>5.2.0</version>
|
||||
<version>5.2.1</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
@@ -50,7 +50,7 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly 'com.github.NEZNAMY:TAB-API:5.2.0'
|
||||
compileOnly 'com.github.NEZNAMY:TAB-API:5.2.1'
|
||||
}
|
||||
```
|
||||
|
||||
@@ -61,7 +61,7 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly("com.github.NEZNAMY", "TAB-API", "5.2.0")
|
||||
compileOnly("com.github.NEZNAMY", "TAB-API", "5.2.1")
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -51,9 +51,10 @@ condition must contain the altered output.
|
||||
To see the exact output of a placeholder including color codes, use `/tab parse <player> <placeholder>`.
|
||||
|
||||
## Permission
|
||||
| Operation | Description | Example |
|
||||
|----------------------|------------------------|-------------------------------------------------------------------------------|
|
||||
| `permission:<value>` | Permission requirement | `permission:my.permission` will pass if player has `my.permission` permission |
|
||||
| Operation | Description | Example |
|
||||
|-----------------------|---------------------------------|----------------------------------------------------------------------------------------------|
|
||||
| `permission:<value>` | Permission requirement | `permission:my.permission` will pass if player has `my.permission` permission |
|
||||
| `!permission:<value>` | Negative permission requirement | `!permission:my.permission` will pass if player **does not have** `my.permission` permission |
|
||||
|
||||
# Multiple condition requirements
|
||||
Each condition has a `conditions` parameter, which a list of conditions. If you define more than 1 condition, you must specify the condition type.
|
||||
|
||||
@@ -11,15 +11,15 @@ This feature allows you to see players from other servers, instead of only seein
|
||||
If TAB is installed on a backend server, you'll need to set up [Multi server support](https://github.com/NEZNAMY/TAB/wiki/Feature-guide:-Multi-server-support) for proper linking of servers. On proxy installation, this is not required.
|
||||
|
||||
# Configuration
|
||||
| Option name | Default value | Description |
|
||||
|----------------------------------------|---------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| enabled | false | Enables / Disables the feature |
|
||||
| server-groups | *Map* | See [Grouping players only from certain servers](#grouping-players-only-from-certain-servers) |
|
||||
| spy-servers | *List* | See [Seeing all players on the network from some server](#seeing-all-players-on-the-network-from-some-server) |
|
||||
| display-others-as-spectators | false | When enabled, players on different servers will appear as having spectator gamemode in tablist. |
|
||||
| display-vanished-players-as-spectators | true | When enabled, vanished players will show as in spectator gamemode for those, who have permission to see vanished players (tab.seevanished) (others will obviously not see them at all). Vanished players will still see themselves in the gamemode they are actually in, since changing that would cause problems (client would think it's in spectator gamemode while it isn't). |
|
||||
| isolate-unlisted-servers | false | When enabled, servers not listed in any group will not share playerlist with any other server, instead of sharing it with other unlisted servers. |
|
||||
| update-latency | false | When **enabled**, plugin will send ping update to players on other servers, since backend servers only send ping updates of players on the same server. This is displayed as the green bar in tablist, unless altered by a mod / resource pack (?). <br /> <br />When **disabled**, ping of players on other servers will be set to 0 (5 bars). <br /> <br />Disabled by default, because it's not only not very useful, but also has a very high CPU usage to due spamming a large amount of packets (especially on large networks). |
|
||||
| Option name | Default value | Description |
|
||||
|----------------------------------------|---------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| enabled | false | Enables / Disables the feature |
|
||||
| server-groups | *Map* | See [Grouping players only from certain servers](#grouping-players-only-from-certain-servers) |
|
||||
| spy-servers | *List* | See [Seeing all players on the network from some server](#seeing-all-players-on-the-network-from-some-server) |
|
||||
| display-others-as-spectators | false | When enabled, players on different servers will appear as having spectator gamemode in tablist. |
|
||||
| display-vanished-players-as-spectators | true | When enabled, vanished players will show as in spectator gamemode for those, who have permission to see vanished players (tab.seevanished) (others will obviously not see them at all). Vanished players will still see themselves in the gamemode they are actually in, since changing that would cause problems (client would think it's in spectator gamemode while it isn't). |
|
||||
| isolate-unlisted-servers | false | When enabled, servers not listed in any group will not share playerlist with any other server, instead of sharing it with other unlisted servers. |
|
||||
| update-latency | false | When **enabled**, plugin will send ping update to players on other servers, since backend servers only send ping updates of players on the same server. This is displayed as the green bar in tablist, unless altered by a mod / resource pack (?). <br /> <br />When **disabled**, ping of players on other servers will be set to `0` (). <br /> <br />Disabled by default, because it's not only not very useful, but also has a very high CPU usage to due spamming a large amount of packets (especially on large networks). |
|
||||
|
||||
## Grouping players only from certain servers
|
||||
In case you want multiple servers to share playerlist,
|
||||
|
||||
@@ -157,12 +157,9 @@ To avoid it, make their names not match any online player and use holograms to d
|
||||
Since 1.9 teams affect tamed animals as well, displaying prefix/suffix on them as well and if nametags are set to be invisible, they will be completely invisible as well. If you want to avoid it, install [this plugin](https://www.spigotmc.org/resources/109466/).
|
||||
|
||||
## Additional note 3 - Changing name itself
|
||||
Teams do not allow to change the nametag name itself.
|
||||
Changing name is a complicated process which is slightly out of scope of the plugin as well,
|
||||
this is what nick plugins are about.
|
||||
On top of that, it's a pain
|
||||
requiring a ton of different packets which change their structure every version and with how many versions the plugin supports,
|
||||
it doesn't sound like fun doing.
|
||||
Teams do not allow to change the nametag name itself. The only way to achieve this goal is to send & modify packets to replace the player's actual profile name with a fake one. This is very complicated and can have a lot of side effects. This is out of scope of TAB and is in fact something nick plugins are trying to achieve. As such, **TAB does not offer this**.
|
||||
|
||||
Once you find a nick plugin that supports this, you will need to [make sure TAB properly detects this](https://github.com/NEZNAMY/TAB/wiki/How-to-display-name-from-nickname-plugins#proper-compatibility-with-plugins-that-change-profile-name) to make name-bound features (such as nametags) work properly for nicked players.
|
||||
|
||||
## Additional note 4 - F1 view
|
||||
Using teams causes player nametags to remain visible when using F1 view.
|
||||
|
||||
@@ -18,14 +18,14 @@ Since 1.20.3, it can display any text.
|
||||
This feature can be configured in **config.yml** under **playerlist-objective** section.
|
||||
|
||||
# Configuration
|
||||
| Option name | Default value | Description |
|
||||
|-------------------|--------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| enabled | true | Enables / Disables the feature |
|
||||
| value | "%ping%" | [1.20.2-] Defines value displayed. You can set this to any placeholder that outputs a number. Only visible on 1.20.2 and lower. <br/> **Note**: Even if you only support 1.20.3+, you still need to configure this value to properly evaluate to a number, because the value is still sent to the client (just not displayed). You can set it to `0` for simplicity. |
|
||||
| fancy-value | "&7Ping: %ping%" | [1.20.3+] Value to display for 1.20.3+ clients. Supports any text. |
|
||||
| title | "Java Edition is better" | Title to send. Only visible on Bedrock Edition. |
|
||||
| render-type | INTEGER | Render type of the value. Supported values are `INTEGER` and `HEARTS` |
|
||||
| disable-condition | %world%=disabledworld | A [condition](https://github.com/NEZNAMY/TAB/wiki/Feature-guide:-Conditional-placeholders) that must be met for disabling the feature for players. Set to empty for not disabling the feature ever. |
|
||||
| Option name | Default value | Description |
|
||||
|-------------------|-----------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| enabled | true | Enables / Disables the feature |
|
||||
| value | "%ping%" | [1.20.2-] Defines value displayed. You can set this to any placeholder that outputs a number. Only visible on 1.20.2 and lower. <br/> **Note**: Even if you only support 1.20.3+, you still need to configure this value to properly evaluate to a number, because the value is still sent to the client (just not displayed). You can set it to `0` for simplicity. |
|
||||
| fancy-value | "&7Ping: %ping%" | [1.20.3+] Value to display for 1.20.3+ clients. Supports any text. |
|
||||
| title | "TAB" | Title to send. Only visible on Bedrock Edition. |
|
||||
| render-type | INTEGER | Render type of the value. Supported values are `INTEGER` and `HEARTS` |
|
||||
| disable-condition | %world%=disabledworld | A [condition](https://github.com/NEZNAMY/TAB/wiki/Feature-guide:-Conditional-placeholders) that must be met for disabling the feature for players. Set to empty for not disabling the feature ever. |
|
||||
|
||||
# Limitations
|
||||
* [1.5 - 1.20.2] Only 2 display types are supported - yellow number and hearts.
|
||||
|
||||
@@ -4,4 +4,6 @@ A collection of things people have requested that I might look into implementing
|
||||
* `invisible-nametags` supporting conditions like `enable-collision` does
|
||||
* Relational placeholder support in sorting
|
||||
* Conditional header/footer
|
||||
* Relational conditions for layout player groups
|
||||
* Relational conditions for layout player groups
|
||||
* 1.21.2+ sorting support
|
||||
* disable-condition support in multi-server-support
|
||||
@@ -1,5 +1,5 @@
|
||||
# About the wiki
|
||||
The wiki explains the functionality of the plugin as of version **5.2.0**.
|
||||
The wiki explains the functionality of the plugin as of version **5.2.1**.
|
||||
If your config looks different or is missing some features, you are using an old version of the plugin.
|
||||
To get the latest version, check [releases](https://github.com/NEZNAMY/TAB/releases/).
|
||||
Wiki for older plugin versions is not available.
|
||||
|
||||
@@ -42,7 +42,13 @@ Most notably, it breaks all name-bound features,
|
||||
especially [nametags](https://github.com/NEZNAMY/TAB/wiki/Feature-guide:-Nametags) and [sorting](https://github.com/NEZNAMY/TAB/wiki/Feature-guide:-Sorting-players-in-tablist).
|
||||
For that reason, TAB must detect name change.
|
||||
This is done automatically on Bukkit, BungeeCord and Fabric.
|
||||
This detection is not available on Sponge and Velocity.
|
||||
**This detection is not available on Sponge and Velocity**.
|
||||
|
||||
> [!WARNING]
|
||||
> If you have TAB installed on backend server and a proxy plugin changes nickname, TAB is not able to detect this change, since the modified packets never actually go through the backend server where TAB is installed.
|
||||
|
||||
> [!TIP]
|
||||
> If automatic detection is not working for you (either you use TAB on Sponge / Velocity, or use proxy plugin for changing names while TAB is on backend), you can use [this API method](https://github.com/NEZNAMY/TAB/blob/master/api/src/main/java/me/neznamy/tab/api/TabPlayer.java#L88) to let TAB know player's name changed.
|
||||
|
||||
In order for TAB to properly detect name change, player UUID must remain the same,
|
||||
otherwise it's a random entry with a random uuid and random name, which TAB isn't able to match with actual players.
|
||||
|
||||
@@ -89,4 +89,4 @@ conditions:
|
||||
```
|
||||
Then, use this condition with `%condition:rgb%`.
|
||||
|
||||
This will not work in nametags and tablist formatting, because this would parse the condition for target player, not the viewer. To achieve this, you'll need a custom made [relational placeholder](https://github.com/NEZNAMY/TAB/wiki/Placeholders#relational-placeholders) that checks for viewer's version.
|
||||
This will not work in nametags and tablist formatting, because this would parse the condition for target player, not the viewer. To achieve this, you'll need a custom-made [relational placeholder](https://github.com/NEZNAMY/TAB/wiki/Placeholders#relational-placeholders) that checks for viewer's version.
|
||||
@@ -33,8 +33,7 @@ install [VelocityScoreboardAPI](https://github.com/NEZNAMY/VelocityScoreboardAPI
|
||||
> With proxy installation, use **/btab** command instead of **/tab**.
|
||||
|
||||
Advantages of proxy installation compared to installing on all backend servers instead:
|
||||
* Can use the [Global player list](https://github.com/NEZNAMY/TAB/wiki/Feature-guide:-Global-playerlist) and [Layout](https://github.com/NEZNAMY/TAB/wiki/Feature-guide:-Layout) can work with all players connected to the proxy
|
||||
* Can use new content for new clients even if a backend server version is old (1.16+ RGB codes, 1.20.3+ scoreboard features)
|
||||
* Can use the [Global player list](https://github.com/NEZNAMY/TAB/wiki/Feature-guide:-Global-playerlist) without requiring Redis set up and [Layout](https://github.com/NEZNAMY/TAB/wiki/Feature-guide:-Layout) can work with all players connected to the proxy
|
||||
* Avoid [header/footer](https://github.com/NEZNAMY/TAB/wiki/Feature-guide:-Header-&-Footer#additional-note-1---not-resetting-on-server-switch) and [bossbar](https://github.com/NEZNAMY/TAB/wiki/Feature-guide:-Bossbar#additional-note-2---not-hiding-on-server-switch) not disappearing on server switch
|
||||
* Configuration files in a single place for easier editing / no need to use MySQL for syncing data
|
||||
|
||||
|
||||
@@ -6,12 +6,10 @@ The usage can be checked at any time using [**/tab cpu**](https://github.com/NEZ
|
||||
* [#2 - [All platforms] Placeholder refresh intervals](#2---all-platforms-placeholder-refresh-intervals)
|
||||
* [#3 - [All platforms] Don't use RGB](#3---all-platforms-dont-use-rgb)
|
||||
* [#4 - [All platforms] Don't use animations](#4---all-platforms-dont-use-animations)
|
||||
* [#5 - [All platforms] Disable anti-override](#5---all-platforms-disable-anti-override)
|
||||
* [#6 - [All platforms] Disable tablist name formatting](#6---all-platforms-disable-tablist-name-formatting)
|
||||
* [#7 - [All platforms] Increase permission refresh interval](#7---all-platforms-increase-permission-refresh-interval)
|
||||
* [#8 - [BungeeCord / Velocity] Disable TAB expansion](#8---bungeecord--velocity-disable-tab-expansion)
|
||||
* [#9 - [BungeeCord / Velocity] Disable update-latency option in global playerlist](#9---bungeecord--velocity-disable-update-latency-option-in-global-playerlist)
|
||||
* [#10 - [BungeeCord] Disable ByteBuf deserialization](#10---bungeecord-disable-bytebuf-deserialization)
|
||||
* [#5 - [All platforms] Disable tablist name formatting](#5---all-platforms-disable-tablist-name-formatting)
|
||||
* [#6 - [All platforms] Increase permission refresh interval](#6---all-platforms-increase-permission-refresh-interval)
|
||||
* [#7 - [BungeeCord / Velocity] Disable TAB expansion](#7---bungeecord--velocity-disable-tab-expansion)
|
||||
* [#8 - [BungeeCord / Velocity] Disable update-latency option in global playerlist](#8---bungeecord--velocity-disable-update-latency-option-in-global-playerlist)
|
||||
|
||||
# #1 - [All platforms] Static text instead of placeholders
|
||||
Static text doesn't need to be refreshed periodically, resulting in better performance.
|
||||
@@ -56,27 +54,7 @@ This is because they work by spamming updates every time an animation switches t
|
||||
When animations are not used, no updates need to be sent (unless another placeholder changes value),
|
||||
not causing extra CPU usage.
|
||||
|
||||
# #5 - [All platforms] Disable anti-override
|
||||
By default, TAB prevents other plugins from overriding it.
|
||||
This is because many server owners are not competent enough to configure their plugins correctly,
|
||||
such as disabling CMI collision handling which breaks nametags or even disabling team handling in paper.
|
||||
This obviously causes higher CPU usage.
|
||||
TAB logs all override attempts of teams into [anti-override.log](https://github.com/NEZNAMY/TAB/wiki/Action-logging#anti-overridelog) file.
|
||||
If you didn't get the file, it looks like you configured your plugins correctly.
|
||||
In that case, you can disable anti-override for teams in TAB.
|
||||
```
|
||||
scoreboard-teams:
|
||||
anti-override: false
|
||||
```
|
||||
Tablist formatting is trickier, as override attempts are not logged because it would have a lot of false positives.
|
||||
You will need to try and see.
|
||||
|
||||
```
|
||||
tablist-name-formatting:
|
||||
anti-override: false
|
||||
```
|
||||
|
||||
# #6 - [All platforms] Disable tablist name formatting
|
||||
# #5 - [All platforms] Disable tablist name formatting
|
||||
As we already know from [Client-sided mechanics](https://github.com/NEZNAMY/TAB/wiki/Client%E2%80%90sided-mechanics#nametag-format-in-tablist) page,
|
||||
the nametag format appears in tablist if tablist name is not defined.
|
||||
You can take advantage of this to effectively disable one entire feature and its cpu usage,
|
||||
@@ -87,12 +65,11 @@ However, you can only do this if:
|
||||
|
||||
Whether you have another plugin attempting to handle them or not may not be easy to identify with a lot of plugins and not enough time spent configuring them. In that case, your best choice is to try it and see. If tablist names break, it means you have another plugin and cannot take advantage of this optimization option.
|
||||
|
||||
# #7 - [All platforms] Increase permission refresh interval
|
||||
# #6 - [All platforms] Increase permission refresh interval
|
||||
Plugin needs to constantly check permissions for:
|
||||
* Permission checks in conditions
|
||||
* Permission checks if sorting by permissions
|
||||
* Group retrieving from permission plugin (for sorting / per-group properties)
|
||||
* Prefix/suffix placeholders taking data from your permission plugin
|
||||
|
||||
default value
|
||||
```
|
||||
@@ -102,7 +79,7 @@ Refreshes them every second.
|
||||
If you don't need any permission/group changes to take effect within a second,
|
||||
you can increase this value for better performance.
|
||||
|
||||
# #8 - [BungeeCord / Velocity] Disable TAB expansion
|
||||
# #7 - [BungeeCord / Velocity] Disable TAB expansion
|
||||
To maximize the performance of TAB's response to PlaceholderAPI request,
|
||||
values are tracked in advance and then quickly returned.
|
||||
This process takes resources and is especially heavy on proxy installation,
|
||||
@@ -113,24 +90,5 @@ Disabling TAB's PlaceholderAPI expansion if you don't use it improves performanc
|
||||
placeholders:
|
||||
register-tab-expansion: false
|
||||
```
|
||||
# #9 - [BungeeCord / Velocity] Disable update-latency option in global playerlist
|
||||
When [Global playerlist](https://github.com/NEZNAMY/TAB/wiki/Feature-guide:-Global-playerlist) is enabled, you can enable / disable [update-latency](https://github.com/NEZNAMY/TAB/wiki/Feature-guide:-Global-playerlist#:~:text=other%20unlisted%20servers.-,update%2Dlatency,-false) option (open the link for detailed description of the option). Disabling this option massively improves performance.
|
||||
|
||||
# #10 - [BungeeCord] Disable ByteBuf deserialization
|
||||
In order for anti-override to work properly, some packets must be manually deserialized due to BungeeCord not doing it. If you don't need it, you can disable those functions, which will also disable the deserialization completely. To do so, you must disable 2 functions (only having 1 disabled is not enough):
|
||||
#1 - Anti-override for teams
|
||||
```
|
||||
scoreboard-teams:
|
||||
anti-override: false
|
||||
```
|
||||
Whether you need anti-override or not depends on the configuration of your plugins.
|
||||
The easiest way is to have it enabled and see if you get `anti-override.log` file in TAB folder.
|
||||
If you don't, you don't need it.
|
||||
If you do, you'll need to do some configuring.
|
||||
[Here](https://github.com/NEZNAMY/TAB/wiki/Feature-guide:-Sorting-players-in-tablist#additional-note-3---compatibility-issues-with-other-plugins)
|
||||
are a few examples of software and their team names, which you may find helpful.
|
||||
|
||||
#2 - Scoreboard detection of other plugins
|
||||
TAB checks for packets sent by other plugins, and if another plugin sends a scoreboard,
|
||||
TAB hides its own and resends it after the other plugin removes it.
|
||||
This check cannot be disabled if the scoreboard is enabled.
|
||||
# #8 - [BungeeCord / Velocity] Disable update-latency option in global playerlist
|
||||
When [Global playerlist](https://github.com/NEZNAMY/TAB/wiki/Feature-guide:-Global-playerlist) is enabled, you can enable / disable [update-latency](https://github.com/NEZNAMY/TAB/wiki/Feature-guide:-Global-playerlist#:~:text=other%20unlisted%20servers.-,update%2Dlatency,-false) option (open the link for detailed description of the option). Disabling this option massively improves performance.
|
||||
@@ -28,7 +28,7 @@ Basic placeholders provided by the plugin. Most of these placeholders were added
|
||||
|
||||
Placeholders must be refreshed.
|
||||
All internal placeholders have a manually defined refresh interval,
|
||||
which I found the most optimal. You can [override the refresh intervals](https://github.com/NEZNAMY/TAB/wiki/Optimizing-the-plugin#2---all-platforms-placeholder-refresh-intervals) if want to.
|
||||
which I found the most optimal. You can [override the refresh intervals](https://github.com/NEZNAMY/TAB/wiki/Optimizing-the-plugin#2---all-platforms-placeholder-refresh-intervals) if you want to.
|
||||
Time is in milliseconds.
|
||||
`-1` is used for placeholders which are in fact constants (such as %player%),
|
||||
or fire an event each time they change, which can be listened to (such as %world%) and value updated.
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
# About
|
||||
When TAB is installed on BungeeCord, the plugin has very limited access to information. It is unable to retrieve internal server data, as well as hook into backend plugins, because it's a different server.
|
||||
Bridge is a backend plugin that sends this data to the proxy, allowing TAB to work better when installed on BungeeCord.
|
||||
When TAB is installed on BungeeCord / Velocity, the plugin has very limited access to information. It is unable to retrieve internal server data, as well as hook into backend plugins, because it's a different server.
|
||||
Bridge is a backend plugin that sends this data to the proxy, allowing TAB to work better when installed on a proxy.
|
||||
You can download it from [GitHub](https://github.com/NEZNAMY/TAB-Bridge/releases) or [Spigot](https://www.spigotmc.org/resources/83966).
|
||||
|
||||
# Installation
|
||||
Installation is as simple as it can be.
|
||||
Put it into the plugins folder of your backend servers.
|
||||
Bridge is NOT a BungeeCord plugin!
|
||||
Bridge is NOT a proxy plugin!
|
||||
Bridge itself has no config file, as everything is configured in the main plugin.
|
||||
|
||||
# Features
|
||||
@@ -20,7 +20,7 @@ Bridge itself has no config file, as everything is configured in the main plugin
|
||||
* Forward player's gamemode for spectator fix feature to work
|
||||
|
||||
# Compatibility
|
||||
Just like with Minecraft, when there is a change in the communication protocol,
|
||||
Just like with Minecraft, when there is a change in the communication protocol between TAB <-> TAB-Bridge,
|
||||
older software will not be compatible with the new one.
|
||||
You should always be running the latest versions of both TAB and Bridge.
|
||||
|
||||
|
||||
+4
-2
@@ -4,7 +4,7 @@ plugins {
|
||||
|
||||
allprojects {
|
||||
group = "me.neznamy"
|
||||
version = "5.2.1"
|
||||
version = "5.2.2"
|
||||
description = "An all-in-one solution that works"
|
||||
|
||||
ext.set("id", "tab")
|
||||
@@ -15,7 +15,9 @@ allprojects {
|
||||
|
||||
val platforms = setOf(
|
||||
projects.bukkit,
|
||||
projects.bukkit.paper,
|
||||
projects.bukkit.paper1205,
|
||||
projects.bukkit.paper1212,
|
||||
projects.bukkit.paper1214,
|
||||
projects.bukkit.v18R3,
|
||||
projects.bukkit.v112R1,
|
||||
projects.bukkit.v116R3,
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
plugins {
|
||||
id("io.papermc.paperweight.userdev") version "2.0.0-beta.17"
|
||||
}
|
||||
|
||||
repositories {
|
||||
maven("https://jitpack.io") // YamlAssist
|
||||
maven("https://repo.opencollab.dev/maven-snapshots/")
|
||||
maven("https://repo.viaversion.com/")
|
||||
maven("https://oss.sonatype.org/content/repositories/snapshots")
|
||||
}
|
||||
|
||||
val version = "1.20.6-R0.1-SNAPSHOT" // 1.20.5 has a broken dependency, but there were no changes, so it's ok
|
||||
|
||||
dependencies {
|
||||
implementation(projects.bukkit)
|
||||
paperweight.paperDevBundle(version)
|
||||
compileOnly("io.papermc.paper:paper-api:${version}")
|
||||
}
|
||||
|
||||
tasks.compileJava {
|
||||
options.release.set(21)
|
||||
}
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
package me.neznamy.tab.platforms.paper_1_20_5;
|
||||
|
||||
import me.neznamy.chat.ChatModifier;
|
||||
import me.neznamy.tab.platforms.bukkit.provider.ComponentConverter;
|
||||
import net.minecraft.network.chat.*;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Component converter using direct mojang-mapped code.
|
||||
*/
|
||||
public class PaperComponentConverter extends ComponentConverter {
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public Object newTextComponent(@NotNull String text) {
|
||||
return Component.literal(text);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public Object newTranslatableComponent(@NotNull String key) {
|
||||
return Component.translatable(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public Object newKeybindComponent(@NotNull String keybind) {
|
||||
return Component.keybind(keybind);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyStyle(@NotNull Object nmsComponent, @NotNull ChatModifier modifier) {
|
||||
Style style = Style.EMPTY
|
||||
.withColor(modifier.getColor() == null ? null : TextColor.fromRgb(modifier.getColor().getRgb()))
|
||||
.withBold(modifier.getBold())
|
||||
.withItalic(modifier.getItalic())
|
||||
.withUnderlined(modifier.getUnderlined())
|
||||
.withStrikethrough(modifier.getStrikethrough())
|
||||
.withObfuscated(modifier.getObfuscated())
|
||||
.withFont(modifier.getFont() == null ? null : ResourceLocation.tryParse(modifier.getFont()));
|
||||
((MutableComponent)nmsComponent).setStyle(style);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSibling(@NotNull Object parent, @NotNull Object child) {
|
||||
((MutableComponent)parent).append((Component) child);
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
package me.neznamy.tab.platforms.paper;
|
||||
package me.neznamy.tab.platforms.paper_1_20_5;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
import lombok.Getter;
|
||||
@@ -15,7 +15,7 @@ import org.bukkit.craftbukkit.entity.CraftPlayer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Implementation provider using direct Mojang-mapped NMS code (1.20.5+).
|
||||
* Implementation provider using direct Mojang-mapped NMS code for versions 1.20.5 - 1.21.1.
|
||||
*/
|
||||
@Getter
|
||||
public class PaperImplementationProvider implements ImplementationProvider {
|
||||
+7
-9
@@ -1,4 +1,4 @@
|
||||
package me.neznamy.tab.platforms.paper;
|
||||
package me.neznamy.tab.platforms.paper_1_20_5;
|
||||
|
||||
import lombok.NonNull;
|
||||
import lombok.SneakyThrows;
|
||||
@@ -35,15 +35,13 @@ public class PaperPacketScoreboard extends SafeScoreboard<BukkitTabPlayer> {
|
||||
|
||||
@SneakyThrows
|
||||
public static void onPacketSend(@NonNull Object packet, @NonNull SafeScoreboard<BukkitTabPlayer> scoreboard) {
|
||||
if (scoreboard.isAntiOverrideScoreboard()) {
|
||||
if (packet instanceof ClientboundSetDisplayObjectivePacket display) {
|
||||
TAB.getInstance().getFeatureManager().onDisplayObjective(scoreboard.getPlayer(), display.getSlot().ordinal(), display.getObjectiveName());
|
||||
}
|
||||
if (packet instanceof ClientboundSetObjectivePacket objective) {
|
||||
TAB.getInstance().getFeatureManager().onObjective(scoreboard.getPlayer(), objective.getMethod(), objective.getObjectiveName());
|
||||
}
|
||||
if (packet instanceof ClientboundSetDisplayObjectivePacket display) {
|
||||
TAB.getInstance().getFeatureManager().onDisplayObjective(scoreboard.getPlayer(), display.getSlot().ordinal(), display.getObjectiveName());
|
||||
}
|
||||
if (scoreboard.isAntiOverrideTeams() && packet instanceof ClientboundSetPlayerTeamPacket team) {
|
||||
if (packet instanceof ClientboundSetObjectivePacket objective) {
|
||||
TAB.getInstance().getFeatureManager().onObjective(scoreboard.getPlayer(), objective.getMethod(), objective.getObjectiveName());
|
||||
}
|
||||
if (packet instanceof ClientboundSetPlayerTeamPacket team) {
|
||||
int action = getMethod(team);
|
||||
if (action == TeamAction.UPDATE) return;
|
||||
players.set(team, scoreboard.onTeamPacket(action, team.getName(), team.getPlayers() == null ? Collections.emptyList() : team.getPlayers()));
|
||||
+194
@@ -0,0 +1,194 @@
|
||||
package me.neznamy.tab.platforms.paper_1_20_5;
|
||||
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import com.mojang.authlib.properties.Property;
|
||||
import lombok.NonNull;
|
||||
import lombok.SneakyThrows;
|
||||
import me.neznamy.chat.component.TabComponent;
|
||||
import me.neznamy.tab.platforms.bukkit.BukkitTabPlayer;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.shared.platform.TabList;
|
||||
import me.neznamy.tab.shared.platform.decorators.TrackedTabList;
|
||||
import me.neznamy.tab.shared.util.ReflectionUtils;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.protocol.Packet;
|
||||
import net.minecraft.network.protocol.game.ClientboundPlayerInfoRemovePacket;
|
||||
import net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket;
|
||||
import net.minecraft.network.protocol.game.ClientboundTabListPacket;
|
||||
import net.minecraft.world.level.GameType;
|
||||
import org.bukkit.craftbukkit.entity.CraftPlayer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* TabList implementation using direct mojang-mapped code.
|
||||
*/
|
||||
public class PaperPacketTabList extends TrackedTabList<BukkitTabPlayer> {
|
||||
|
||||
private static final EnumSet<ClientboundPlayerInfoUpdatePacket.Action> addPlayer = EnumSet.allOf(ClientboundPlayerInfoUpdatePacket.Action.class);
|
||||
private static final EnumSet<ClientboundPlayerInfoUpdatePacket.Action> updateDisplayName = EnumSet.of(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_DISPLAY_NAME);
|
||||
private static final EnumSet<ClientboundPlayerInfoUpdatePacket.Action> updateLatency = EnumSet.of(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LATENCY);
|
||||
private static final EnumSet<ClientboundPlayerInfoUpdatePacket.Action> updateGameMode = EnumSet.of(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_GAME_MODE);
|
||||
private static final EnumSet<ClientboundPlayerInfoUpdatePacket.Action> updateListed = EnumSet.of(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LISTED);
|
||||
|
||||
private static final Field entries = ReflectionUtils.getOnlyField(ClientboundPlayerInfoUpdatePacket.class, List.class);
|
||||
|
||||
@SneakyThrows
|
||||
public static void onPacketSend(@NonNull Object packet, TrackedTabList<BukkitTabPlayer> tabList) {
|
||||
if (packet instanceof ClientboundPlayerInfoUpdatePacket info) {
|
||||
EnumSet<ClientboundPlayerInfoUpdatePacket.Action> actions = info.actions();
|
||||
List<ClientboundPlayerInfoUpdatePacket.Entry> updatedList = new ArrayList<>();
|
||||
boolean rewritePacket = false;
|
||||
for (ClientboundPlayerInfoUpdatePacket.Entry nmsData : info.entries()) {
|
||||
boolean rewriteEntry = false;
|
||||
Component displayName = nmsData.displayName();
|
||||
int latency = nmsData.latency();
|
||||
if (actions.contains(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_DISPLAY_NAME)) {
|
||||
TabComponent expectedDisplayName = tabList.getExpectedDisplayNames().get(nmsData.profileId());
|
||||
if (expectedDisplayName != null && expectedDisplayName.convert() != displayName) {
|
||||
displayName = expectedDisplayName.convert();
|
||||
rewriteEntry = rewritePacket = true;
|
||||
}
|
||||
}
|
||||
if (actions.contains(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LATENCY)) {
|
||||
int newLatency = TAB.getInstance().getFeatureManager().onLatencyChange(tabList.getPlayer(), nmsData.profileId(), latency);
|
||||
if (newLatency != latency) {
|
||||
latency = newLatency;
|
||||
rewriteEntry = rewritePacket = true;
|
||||
}
|
||||
}
|
||||
if (actions.contains(ClientboundPlayerInfoUpdatePacket.Action.ADD_PLAYER)) {
|
||||
TAB.getInstance().getFeatureManager().onEntryAdd(tabList.getPlayer(), nmsData.profileId(), nmsData.profile().getName());
|
||||
}
|
||||
updatedList.add(rewriteEntry ? new ClientboundPlayerInfoUpdatePacket.Entry(
|
||||
nmsData.profileId(), nmsData.profile(), nmsData.listed(), latency, nmsData.gameMode(), displayName,
|
||||
nmsData.chatSession()
|
||||
) : nmsData);
|
||||
}
|
||||
if (rewritePacket) entries.set(info, updatedList);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs new instance.
|
||||
*
|
||||
* @param player
|
||||
* Player this tablist will belong to
|
||||
*/
|
||||
public PaperPacketTabList(@NotNull BukkitTabPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeEntry(@NonNull UUID entry) {
|
||||
sendPacket(new ClientboundPlayerInfoRemovePacket(Collections.singletonList(entry)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateDisplayName0(@NonNull UUID entry, @Nullable TabComponent displayName) {
|
||||
sendPacket(updateDisplayName, entry, "", null, false, 0, 0, displayName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateLatency(@NonNull UUID entry, int latency) {
|
||||
sendPacket(updateLatency, entry, "", null, false, latency, 0, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateGameMode(@NonNull UUID entry, int gameMode) {
|
||||
sendPacket(updateGameMode, entry, "", null, false, 0, gameMode, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateListed(@NonNull UUID entry, boolean listed) {
|
||||
sendPacket(updateListed, entry, "", null, listed, 0, 0, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateListOrder(@NonNull UUID entry, int listOrder) {
|
||||
// Added in 1.21.2
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateHat(@NonNull UUID entry, boolean showHat) {
|
||||
// Added in 1.21.4
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addEntry0(@NonNull Entry entry) {
|
||||
sendPacket(addPlayer, entry.getUniqueId(), entry.getName(), entry.getSkin(), entry.isListed(), entry.getLatency(),
|
||||
entry.getGameMode(), entry.getDisplayName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPlayerListHeaderFooter(@NonNull TabComponent header, @NonNull TabComponent footer) {
|
||||
sendPacket(new ClientboundTabListPacket(header.convert(), footer.convert()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsEntry(@NonNull UUID entry) {
|
||||
return true; // TODO?
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Skin getSkin() {
|
||||
Collection<Property> properties = ((CraftPlayer)player.getPlayer()).getProfile().getProperties().get(TEXTURES_PROPERTY);
|
||||
if (properties.isEmpty()) return null; // Offline mode
|
||||
Property property = properties.iterator().next();
|
||||
return new Skin(property.value(), property.signature());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketSend(@NonNull Object packet) {
|
||||
onPacketSend(packet, this);
|
||||
}
|
||||
|
||||
private void sendPacket(@NonNull EnumSet<ClientboundPlayerInfoUpdatePacket.Action> action, @NonNull UUID id, @NonNull String name, @Nullable Skin skin,
|
||||
boolean listed, int latency, int gameMode, @Nullable TabComponent displayName) {
|
||||
ClientboundPlayerInfoUpdatePacket packet = new ClientboundPlayerInfoUpdatePacket(action, new ClientboundPlayerInfoUpdatePacket.Entry(
|
||||
id,
|
||||
action.contains(ClientboundPlayerInfoUpdatePacket.Action.ADD_PLAYER) ? createProfile(id, name, skin) : null,
|
||||
listed,
|
||||
latency,
|
||||
GameType.byId(gameMode),
|
||||
displayName == null ? null : displayName.convert(),
|
||||
null
|
||||
));
|
||||
sendPacket(packet);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates GameProfile from given parameters.
|
||||
*
|
||||
* @param id
|
||||
* Profile ID
|
||||
* @param name
|
||||
* Profile name
|
||||
* @param skin
|
||||
* Player skin
|
||||
* @return GameProfile from given parameters
|
||||
*/
|
||||
@NotNull
|
||||
private GameProfile createProfile(@NonNull UUID id, @NonNull String name, @Nullable Skin skin) {
|
||||
GameProfile profile = new GameProfile(id, name);
|
||||
if (skin != null) {
|
||||
profile.getProperties().put(TabList.TEXTURES_PROPERTY,
|
||||
new Property(TabList.TEXTURES_PROPERTY, skin.getValue(), skin.getSignature()));
|
||||
}
|
||||
return profile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the packet to the player.
|
||||
*
|
||||
* @param packet
|
||||
* Packet to send
|
||||
*/
|
||||
private void sendPacket(@NotNull Packet<?> packet) {
|
||||
((CraftPlayer)player.getPlayer()).getHandle().connection.send(packet);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
plugins {
|
||||
id("io.papermc.paperweight.userdev") version "2.0.0-beta.17"
|
||||
}
|
||||
|
||||
repositories {
|
||||
maven("https://jitpack.io") // YamlAssist
|
||||
maven("https://repo.opencollab.dev/maven-snapshots/")
|
||||
maven("https://repo.viaversion.com/")
|
||||
maven("https://oss.sonatype.org/content/repositories/snapshots")
|
||||
}
|
||||
|
||||
val version = "1.21.3-R0.1-SNAPSHOT" // 1.21.2 causes gradle error, but the versions are interchangeable
|
||||
|
||||
dependencies {
|
||||
implementation(projects.bukkit)
|
||||
paperweight.paperDevBundle(version)
|
||||
compileOnly("io.papermc.paper:paper-api:${version}")
|
||||
}
|
||||
|
||||
tasks.compileJava {
|
||||
options.release.set(21)
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
package me.neznamy.tab.platforms.paper_1_21_2;
|
||||
|
||||
import me.neznamy.chat.ChatModifier;
|
||||
import me.neznamy.tab.platforms.bukkit.provider.ComponentConverter;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.chat.MutableComponent;
|
||||
import net.minecraft.network.chat.Style;
|
||||
import net.minecraft.network.chat.TextColor;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Component converter using direct mojang-mapped code.
|
||||
*/
|
||||
public class PaperComponentConverter extends ComponentConverter {
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public Object newTextComponent(@NotNull String text) {
|
||||
return Component.literal(text);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public Object newTranslatableComponent(@NotNull String key) {
|
||||
return Component.translatable(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public Object newKeybindComponent(@NotNull String keybind) {
|
||||
return Component.keybind(keybind);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyStyle(@NotNull Object nmsComponent, @NotNull ChatModifier modifier) {
|
||||
Style style = Style.EMPTY
|
||||
.withColor(modifier.getColor() == null ? null : TextColor.fromRgb(modifier.getColor().getRgb()))
|
||||
.withBold(modifier.getBold())
|
||||
.withItalic(modifier.getItalic())
|
||||
.withUnderlined(modifier.getUnderlined())
|
||||
.withStrikethrough(modifier.getStrikethrough())
|
||||
.withObfuscated(modifier.getObfuscated())
|
||||
.withFont(modifier.getFont() == null ? null : ResourceLocation.tryParse(modifier.getFont()));
|
||||
((MutableComponent)nmsComponent).setStyle(style);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSibling(@NotNull Object parent, @NotNull Object child) {
|
||||
((MutableComponent)parent).append((Component) child);
|
||||
}
|
||||
}
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
package me.neznamy.tab.platforms.paper_1_21_2;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
import me.neznamy.tab.platforms.bukkit.BukkitTabPlayer;
|
||||
import me.neznamy.tab.platforms.bukkit.provider.ComponentConverter;
|
||||
import me.neznamy.tab.platforms.bukkit.provider.ImplementationProvider;
|
||||
import me.neznamy.tab.platforms.bukkit.provider.viaversion.ViaScoreboard;
|
||||
import me.neznamy.tab.platforms.bukkit.provider.viaversion.ViaTabList;
|
||||
import me.neznamy.tab.shared.platform.Scoreboard;
|
||||
import me.neznamy.tab.shared.platform.TabList;
|
||||
import me.neznamy.tab.shared.util.function.FunctionWithException;
|
||||
import org.bukkit.craftbukkit.entity.CraftPlayer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Implementation provider using direct Mojang-mapped NMS code for versions 1.21.2 - 1.21.3.
|
||||
*/
|
||||
@Getter
|
||||
public class PaperImplementationProvider implements ImplementationProvider {
|
||||
|
||||
@NotNull
|
||||
private final ComponentConverter componentConverter = new PaperComponentConverter();
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public Scoreboard newScoreboard(@NotNull BukkitTabPlayer player) {
|
||||
return new PaperPacketScoreboard(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketSend(@NonNull Object packet, @NonNull ViaScoreboard scoreboard) {
|
||||
PaperPacketScoreboard.onPacketSend(packet, scoreboard);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketSend(@NonNull Object packet, @NonNull ViaTabList tabList) {
|
||||
PaperPacketTabList.onPacketSend(packet, tabList);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public TabList newTabList(@NotNull BukkitTabPlayer player) {
|
||||
return new PaperPacketTabList(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public FunctionWithException<BukkitTabPlayer, Channel> getChannelFunction() {
|
||||
return player -> ((CraftPlayer)player.getPlayer()).getHandle().connection.connection.channel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPing(@NotNull BukkitTabPlayer player) {
|
||||
return player.getPlayer().getPing();
|
||||
}
|
||||
}
|
||||
+177
@@ -0,0 +1,177 @@
|
||||
package me.neznamy.tab.platforms.paper_1_21_2;
|
||||
|
||||
import lombok.NonNull;
|
||||
import lombok.SneakyThrows;
|
||||
import me.neznamy.tab.platforms.bukkit.BukkitTabPlayer;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.shared.platform.decorators.SafeScoreboard;
|
||||
import me.neznamy.tab.shared.util.ReflectionUtils;
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.network.chat.numbers.FixedFormat;
|
||||
import net.minecraft.network.protocol.Packet;
|
||||
import net.minecraft.network.protocol.game.*;
|
||||
import net.minecraft.world.scores.PlayerTeam;
|
||||
import net.minecraft.world.scores.Scoreboard;
|
||||
import net.minecraft.world.scores.criteria.ObjectiveCriteria;
|
||||
import net.minecraft.world.scores.criteria.ObjectiveCriteria.RenderType;
|
||||
import org.bukkit.craftbukkit.entity.CraftPlayer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Scoreboard implementation using direct mojang-mapped code.
|
||||
*/
|
||||
public class PaperPacketScoreboard extends SafeScoreboard<BukkitTabPlayer> {
|
||||
|
||||
private static final ChatFormatting[] formats = ChatFormatting.values();
|
||||
private static final net.minecraft.world.scores.Team.CollisionRule[] collisions = net.minecraft.world.scores.Team.CollisionRule.values();
|
||||
private static final net.minecraft.world.scores.Team.Visibility[] visibilities = net.minecraft.world.scores.Team.Visibility.values();
|
||||
private static final Scoreboard dummyScoreboard = new Scoreboard();
|
||||
private static final Field players = ReflectionUtils.getOnlyField(ClientboundSetPlayerTeamPacket.class, Collection.class);
|
||||
|
||||
@SneakyThrows
|
||||
public static void onPacketSend(@NonNull Object packet, @NonNull SafeScoreboard<BukkitTabPlayer> scoreboard) {
|
||||
if (packet instanceof ClientboundSetDisplayObjectivePacket display) {
|
||||
TAB.getInstance().getFeatureManager().onDisplayObjective(scoreboard.getPlayer(), display.getSlot().ordinal(), display.getObjectiveName());
|
||||
}
|
||||
if (packet instanceof ClientboundSetObjectivePacket objective) {
|
||||
TAB.getInstance().getFeatureManager().onObjective(scoreboard.getPlayer(), objective.getMethod(), objective.getObjectiveName());
|
||||
}
|
||||
if (packet instanceof ClientboundSetPlayerTeamPacket team) {
|
||||
int action = getMethod(team);
|
||||
if (action == TeamAction.UPDATE) return;
|
||||
players.set(team, scoreboard.onTeamPacket(action, team.getName(), team.getPlayers() == null ? Collections.emptyList() : team.getPlayers()));
|
||||
}
|
||||
}
|
||||
|
||||
private static int getMethod(@NonNull ClientboundSetPlayerTeamPacket team) {
|
||||
if (team.getTeamAction() == ClientboundSetPlayerTeamPacket.Action.ADD) {
|
||||
return 0;
|
||||
} else if (team.getTeamAction() == ClientboundSetPlayerTeamPacket.Action.REMOVE) {
|
||||
return 1;
|
||||
} else if (team.getPlayerAction() == ClientboundSetPlayerTeamPacket.Action.ADD) {
|
||||
return 3;
|
||||
} else if (team.getPlayerAction() == ClientboundSetPlayerTeamPacket.Action.REMOVE) {
|
||||
return 4;
|
||||
} else {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs new instance with given player.
|
||||
*
|
||||
* @param player
|
||||
* Player this scoreboard will belong to
|
||||
*/
|
||||
public PaperPacketScoreboard(@NotNull BukkitTabPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerObjective(@NonNull Objective objective) {
|
||||
net.minecraft.world.scores.Objective obj = new net.minecraft.world.scores.Objective(
|
||||
dummyScoreboard,
|
||||
objective.getName(),
|
||||
ObjectiveCriteria.DUMMY,
|
||||
objective.getTitle().convert(),
|
||||
RenderType.values()[objective.getHealthDisplay().ordinal()],
|
||||
false,
|
||||
objective.getNumberFormat() == null ? null : objective.getNumberFormat().toFixedFormat(FixedFormat::new)
|
||||
);
|
||||
objective.setPlatformObjective(obj);
|
||||
sendPacket(new ClientboundSetObjectivePacket(obj, ObjectiveAction.REGISTER));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDisplaySlot(@NonNull Objective objective) {
|
||||
sendPacket(new ClientboundSetDisplayObjectivePacket(
|
||||
net.minecraft.world.scores.DisplaySlot.values()[objective.getDisplaySlot().ordinal()],
|
||||
(net.minecraft.world.scores.Objective) objective.getPlatformObjective()
|
||||
));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterObjective(@NonNull Objective objective) {
|
||||
sendPacket(new ClientboundSetObjectivePacket((net.minecraft.world.scores.Objective) objective.getPlatformObjective(), ObjectiveAction.UNREGISTER));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateObjective(@NonNull Objective objective) {
|
||||
net.minecraft.world.scores.Objective obj = (net.minecraft.world.scores.Objective) objective.getPlatformObjective();
|
||||
obj.setDisplayName(objective.getTitle().convert());
|
||||
obj.setRenderType(RenderType.values()[objective.getHealthDisplay().ordinal()]);
|
||||
sendPacket(new ClientboundSetObjectivePacket(obj, ObjectiveAction.UPDATE));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setScore(@NonNull Score score) {
|
||||
sendPacket(new ClientboundSetScorePacket(
|
||||
score.getHolder(),
|
||||
score.getObjective().getName(),
|
||||
score.getValue(),
|
||||
Optional.ofNullable(score.getDisplayName() == null ? null : score.getDisplayName().convert()),
|
||||
Optional.ofNullable(score.getNumberFormat() == null ? null : score.getNumberFormat().toFixedFormat(FixedFormat::new))
|
||||
));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeScore(@NonNull Score score) {
|
||||
sendPacket(new ClientboundResetScorePacket(score.getHolder(), score.getObjective().getName()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public Object createTeam(@NonNull String name) {
|
||||
return new PlayerTeam(dummyScoreboard, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerTeam(@NonNull Team team) {
|
||||
updateTeamProperties(team);
|
||||
PlayerTeam t = (PlayerTeam) team.getPlatformTeam();
|
||||
t.getPlayers().addAll(team.getPlayers());
|
||||
sendPacket(ClientboundSetPlayerTeamPacket.createAddOrModifyPacket(t, true));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterTeam(@NonNull Team team) {
|
||||
sendPacket(ClientboundSetPlayerTeamPacket.createRemovePacket((PlayerTeam) team.getPlatformTeam()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateTeam(@NonNull Team team) {
|
||||
updateTeamProperties(team);
|
||||
sendPacket(ClientboundSetPlayerTeamPacket.createAddOrModifyPacket((PlayerTeam) team.getPlatformTeam(), false));
|
||||
}
|
||||
|
||||
private void updateTeamProperties(@NonNull Team team) {
|
||||
PlayerTeam t = (PlayerTeam) team.getPlatformTeam();
|
||||
t.setAllowFriendlyFire((team.getOptions() & 0x01) != 0);
|
||||
t.setSeeFriendlyInvisibles((team.getOptions() & 0x02) != 0);
|
||||
t.setColor(formats[team.getColor().getLegacyColor().ordinal()]);
|
||||
t.setCollisionRule(collisions[team.getCollision().ordinal()]);
|
||||
t.setNameTagVisibility(visibilities[team.getVisibility().ordinal()]);
|
||||
t.setPlayerPrefix(team.getPrefix().convert());
|
||||
t.setPlayerSuffix(team.getSuffix().convert());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketSend(@NonNull Object packet) {
|
||||
onPacketSend(packet, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the packet to the player.
|
||||
*
|
||||
* @param packet
|
||||
* Packet to send
|
||||
*/
|
||||
private void sendPacket(@NotNull Packet<?> packet) {
|
||||
((CraftPlayer)player.getPlayer()).getHandle().connection.sendPacket(packet);
|
||||
}
|
||||
}
|
||||
+196
@@ -0,0 +1,196 @@
|
||||
package me.neznamy.tab.platforms.paper_1_21_2;
|
||||
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import com.mojang.authlib.properties.Property;
|
||||
import lombok.NonNull;
|
||||
import lombok.SneakyThrows;
|
||||
import me.neznamy.chat.component.TabComponent;
|
||||
import me.neznamy.tab.platforms.bukkit.BukkitTabPlayer;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.shared.platform.TabList;
|
||||
import me.neznamy.tab.shared.platform.decorators.TrackedTabList;
|
||||
import me.neznamy.tab.shared.util.ReflectionUtils;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.protocol.Packet;
|
||||
import net.minecraft.network.protocol.game.ClientboundPlayerInfoRemovePacket;
|
||||
import net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket;
|
||||
import net.minecraft.network.protocol.game.ClientboundTabListPacket;
|
||||
import net.minecraft.world.level.GameType;
|
||||
import org.bukkit.craftbukkit.entity.CraftPlayer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* TabList implementation using direct mojang-mapped code.
|
||||
*/
|
||||
public class PaperPacketTabList extends TrackedTabList<BukkitTabPlayer> {
|
||||
|
||||
private static final EnumSet<ClientboundPlayerInfoUpdatePacket.Action> addPlayer = EnumSet.allOf(ClientboundPlayerInfoUpdatePacket.Action.class);
|
||||
private static final EnumSet<ClientboundPlayerInfoUpdatePacket.Action> updateDisplayName = EnumSet.of(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_DISPLAY_NAME);
|
||||
private static final EnumSet<ClientboundPlayerInfoUpdatePacket.Action> updateLatency = EnumSet.of(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LATENCY);
|
||||
private static final EnumSet<ClientboundPlayerInfoUpdatePacket.Action> updateGameMode = EnumSet.of(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_GAME_MODE);
|
||||
private static final EnumSet<ClientboundPlayerInfoUpdatePacket.Action> updateListed = EnumSet.of(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LISTED);
|
||||
private static final EnumSet<ClientboundPlayerInfoUpdatePacket.Action> updateListOrder = EnumSet.of(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LIST_ORDER);
|
||||
|
||||
private static final Field entries = ReflectionUtils.getOnlyField(ClientboundPlayerInfoUpdatePacket.class, List.class);
|
||||
|
||||
@SneakyThrows
|
||||
public static void onPacketSend(@NonNull Object packet, TrackedTabList<BukkitTabPlayer> tabList) {
|
||||
if (packet instanceof ClientboundPlayerInfoUpdatePacket info) {
|
||||
EnumSet<ClientboundPlayerInfoUpdatePacket.Action> actions = info.actions();
|
||||
List<ClientboundPlayerInfoUpdatePacket.Entry> updatedList = new ArrayList<>();
|
||||
boolean rewritePacket = false;
|
||||
for (ClientboundPlayerInfoUpdatePacket.Entry nmsData : info.entries()) {
|
||||
boolean rewriteEntry = false;
|
||||
Component displayName = nmsData.displayName();
|
||||
int latency = nmsData.latency();
|
||||
if (actions.contains(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_DISPLAY_NAME)) {
|
||||
TabComponent expectedDisplayName = tabList.getExpectedDisplayNames().get(nmsData.profileId());
|
||||
if (expectedDisplayName != null && expectedDisplayName.convert() != displayName) {
|
||||
displayName = expectedDisplayName.convert();
|
||||
rewriteEntry = rewritePacket = true;
|
||||
}
|
||||
}
|
||||
if (actions.contains(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LATENCY)) {
|
||||
int newLatency = TAB.getInstance().getFeatureManager().onLatencyChange(tabList.getPlayer(), nmsData.profileId(), latency);
|
||||
if (newLatency != latency) {
|
||||
latency = newLatency;
|
||||
rewriteEntry = rewritePacket = true;
|
||||
}
|
||||
}
|
||||
if (actions.contains(ClientboundPlayerInfoUpdatePacket.Action.ADD_PLAYER)) {
|
||||
TAB.getInstance().getFeatureManager().onEntryAdd(tabList.getPlayer(), nmsData.profileId(), nmsData.profile().getName());
|
||||
}
|
||||
updatedList.add(rewriteEntry ? new ClientboundPlayerInfoUpdatePacket.Entry(
|
||||
nmsData.profileId(), nmsData.profile(), nmsData.listed(), latency, nmsData.gameMode(), displayName,
|
||||
nmsData.listOrder(), nmsData.chatSession()
|
||||
) : nmsData);
|
||||
}
|
||||
if (rewritePacket) entries.set(info, updatedList);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs new instance.
|
||||
*
|
||||
* @param player
|
||||
* Player this tablist will belong to
|
||||
*/
|
||||
public PaperPacketTabList(@NotNull BukkitTabPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeEntry(@NonNull UUID entry) {
|
||||
sendPacket(new ClientboundPlayerInfoRemovePacket(Collections.singletonList(entry)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateDisplayName0(@NonNull UUID entry, @Nullable TabComponent displayName) {
|
||||
sendPacket(updateDisplayName, entry, "", null, false, 0, 0, displayName, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateLatency(@NonNull UUID entry, int latency) {
|
||||
sendPacket(updateLatency, entry, "", null, false, latency, 0, null, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateGameMode(@NonNull UUID entry, int gameMode) {
|
||||
sendPacket(updateGameMode, entry, "", null, false, 0, gameMode, null, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateListed(@NonNull UUID entry, boolean listed) {
|
||||
sendPacket(updateListed, entry, "", null, listed, 0, 0, null, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateListOrder(@NonNull UUID entry, int listOrder) {
|
||||
sendPacket(updateListOrder, entry, "", null, false, 0, 0, null, listOrder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateHat(@NonNull UUID entry, boolean showHat) {
|
||||
// Added in 1.21.4
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addEntry0(@NonNull Entry entry) {
|
||||
sendPacket(addPlayer, entry.getUniqueId(), entry.getName(), entry.getSkin(), entry.isListed(), entry.getLatency(),
|
||||
entry.getGameMode(), entry.getDisplayName(), entry.getListOrder());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPlayerListHeaderFooter(@NonNull TabComponent header, @NonNull TabComponent footer) {
|
||||
sendPacket(new ClientboundTabListPacket(header.convert(), footer.convert()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsEntry(@NonNull UUID entry) {
|
||||
return true; // TODO?
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Skin getSkin() {
|
||||
Collection<Property> properties = ((CraftPlayer)player.getPlayer()).getProfile().getProperties().get(TEXTURES_PROPERTY);
|
||||
if (properties.isEmpty()) return null; // Offline mode
|
||||
Property property = properties.iterator().next();
|
||||
return new Skin(property.value(), property.signature());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketSend(@NonNull Object packet) {
|
||||
onPacketSend(packet, this);
|
||||
}
|
||||
|
||||
private void sendPacket(@NonNull EnumSet<ClientboundPlayerInfoUpdatePacket.Action> action, @NonNull UUID id, @NonNull String name, @Nullable Skin skin,
|
||||
boolean listed, int latency, int gameMode, @Nullable TabComponent displayName, int listOrder) {
|
||||
ClientboundPlayerInfoUpdatePacket packet = new ClientboundPlayerInfoUpdatePacket(action, new ClientboundPlayerInfoUpdatePacket.Entry(
|
||||
id,
|
||||
action.contains(ClientboundPlayerInfoUpdatePacket.Action.ADD_PLAYER) ? createProfile(id, name, skin) : null,
|
||||
listed,
|
||||
latency,
|
||||
GameType.byId(gameMode),
|
||||
displayName == null ? null : displayName.convert(),
|
||||
listOrder,
|
||||
null
|
||||
));
|
||||
sendPacket(packet);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates GameProfile from given parameters.
|
||||
*
|
||||
* @param id
|
||||
* Profile ID
|
||||
* @param name
|
||||
* Profile name
|
||||
* @param skin
|
||||
* Player skin
|
||||
* @return GameProfile from given parameters
|
||||
*/
|
||||
@NotNull
|
||||
private GameProfile createProfile(@NonNull UUID id, @NonNull String name, @Nullable Skin skin) {
|
||||
GameProfile profile = new GameProfile(id, name);
|
||||
if (skin != null) {
|
||||
profile.getProperties().put(TabList.TEXTURES_PROPERTY,
|
||||
new Property(TabList.TEXTURES_PROPERTY, skin.getValue(), skin.getSignature()));
|
||||
}
|
||||
return profile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the packet to the player.
|
||||
*
|
||||
* @param packet
|
||||
* Packet to send
|
||||
*/
|
||||
private void sendPacket(@NotNull Packet<?> packet) {
|
||||
((CraftPlayer)player.getPlayer()).getHandle().connection.send(packet);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
plugins {
|
||||
id("io.papermc.paperweight.userdev") version "2.0.0-beta.16"
|
||||
id("io.papermc.paperweight.userdev") version "2.0.0-beta.17"
|
||||
}
|
||||
|
||||
repositories {
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package me.neznamy.tab.platforms.paper;
|
||||
package me.neznamy.tab.platforms.paper_1_21_4;
|
||||
|
||||
import me.neznamy.chat.ChatModifier;
|
||||
import me.neznamy.tab.platforms.bukkit.provider.ComponentConverter;
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
package me.neznamy.tab.platforms.paper_1_21_4;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
import me.neznamy.tab.platforms.bukkit.BukkitTabPlayer;
|
||||
import me.neznamy.tab.platforms.bukkit.provider.ComponentConverter;
|
||||
import me.neznamy.tab.platforms.bukkit.provider.ImplementationProvider;
|
||||
import me.neznamy.tab.platforms.bukkit.provider.viaversion.ViaScoreboard;
|
||||
import me.neznamy.tab.platforms.bukkit.provider.viaversion.ViaTabList;
|
||||
import me.neznamy.tab.shared.platform.Scoreboard;
|
||||
import me.neznamy.tab.shared.platform.TabList;
|
||||
import me.neznamy.tab.shared.util.function.FunctionWithException;
|
||||
import org.bukkit.craftbukkit.entity.CraftPlayer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Implementation provider using direct Mojang-mapped NMS code for versions 1.21.4 - 1.21.6.
|
||||
*/
|
||||
@Getter
|
||||
public class PaperImplementationProvider implements ImplementationProvider {
|
||||
|
||||
@NotNull
|
||||
private final ComponentConverter componentConverter = new PaperComponentConverter();
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public Scoreboard newScoreboard(@NotNull BukkitTabPlayer player) {
|
||||
return new PaperPacketScoreboard(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketSend(@NonNull Object packet, @NonNull ViaScoreboard scoreboard) {
|
||||
PaperPacketScoreboard.onPacketSend(packet, scoreboard);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketSend(@NonNull Object packet, @NonNull ViaTabList tabList) {
|
||||
PaperPacketTabList.onPacketSend(packet, tabList);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public TabList newTabList(@NotNull BukkitTabPlayer player) {
|
||||
return new PaperPacketTabList(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public FunctionWithException<BukkitTabPlayer, Channel> getChannelFunction() {
|
||||
return player -> ((CraftPlayer)player.getPlayer()).getHandle().connection.connection.channel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPing(@NotNull BukkitTabPlayer player) {
|
||||
return player.getPlayer().getPing();
|
||||
}
|
||||
}
|
||||
+177
@@ -0,0 +1,177 @@
|
||||
package me.neznamy.tab.platforms.paper_1_21_4;
|
||||
|
||||
import lombok.NonNull;
|
||||
import lombok.SneakyThrows;
|
||||
import me.neznamy.tab.platforms.bukkit.BukkitTabPlayer;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.shared.platform.decorators.SafeScoreboard;
|
||||
import me.neznamy.tab.shared.util.ReflectionUtils;
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.network.chat.numbers.FixedFormat;
|
||||
import net.minecraft.network.protocol.Packet;
|
||||
import net.minecraft.network.protocol.game.*;
|
||||
import net.minecraft.world.scores.PlayerTeam;
|
||||
import net.minecraft.world.scores.Scoreboard;
|
||||
import net.minecraft.world.scores.criteria.ObjectiveCriteria;
|
||||
import net.minecraft.world.scores.criteria.ObjectiveCriteria.RenderType;
|
||||
import org.bukkit.craftbukkit.entity.CraftPlayer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Scoreboard implementation using direct mojang-mapped code.
|
||||
*/
|
||||
public class PaperPacketScoreboard extends SafeScoreboard<BukkitTabPlayer> {
|
||||
|
||||
private static final ChatFormatting[] formats = ChatFormatting.values();
|
||||
private static final net.minecraft.world.scores.Team.CollisionRule[] collisions = net.minecraft.world.scores.Team.CollisionRule.values();
|
||||
private static final net.minecraft.world.scores.Team.Visibility[] visibilities = net.minecraft.world.scores.Team.Visibility.values();
|
||||
private static final Scoreboard dummyScoreboard = new Scoreboard();
|
||||
private static final Field players = ReflectionUtils.getOnlyField(ClientboundSetPlayerTeamPacket.class, Collection.class);
|
||||
|
||||
@SneakyThrows
|
||||
public static void onPacketSend(@NonNull Object packet, @NonNull SafeScoreboard<BukkitTabPlayer> scoreboard) {
|
||||
if (packet instanceof ClientboundSetDisplayObjectivePacket display) {
|
||||
TAB.getInstance().getFeatureManager().onDisplayObjective(scoreboard.getPlayer(), display.getSlot().ordinal(), display.getObjectiveName());
|
||||
}
|
||||
if (packet instanceof ClientboundSetObjectivePacket objective) {
|
||||
TAB.getInstance().getFeatureManager().onObjective(scoreboard.getPlayer(), objective.getMethod(), objective.getObjectiveName());
|
||||
}
|
||||
if (packet instanceof ClientboundSetPlayerTeamPacket team) {
|
||||
int action = getMethod(team);
|
||||
if (action == TeamAction.UPDATE) return;
|
||||
players.set(team, scoreboard.onTeamPacket(action, team.getName(), team.getPlayers() == null ? Collections.emptyList() : team.getPlayers()));
|
||||
}
|
||||
}
|
||||
|
||||
private static int getMethod(@NonNull ClientboundSetPlayerTeamPacket team) {
|
||||
if (team.getTeamAction() == ClientboundSetPlayerTeamPacket.Action.ADD) {
|
||||
return 0;
|
||||
} else if (team.getTeamAction() == ClientboundSetPlayerTeamPacket.Action.REMOVE) {
|
||||
return 1;
|
||||
} else if (team.getPlayerAction() == ClientboundSetPlayerTeamPacket.Action.ADD) {
|
||||
return 3;
|
||||
} else if (team.getPlayerAction() == ClientboundSetPlayerTeamPacket.Action.REMOVE) {
|
||||
return 4;
|
||||
} else {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs new instance with given player.
|
||||
*
|
||||
* @param player
|
||||
* Player this scoreboard will belong to
|
||||
*/
|
||||
public PaperPacketScoreboard(@NotNull BukkitTabPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerObjective(@NonNull Objective objective) {
|
||||
net.minecraft.world.scores.Objective obj = new net.minecraft.world.scores.Objective(
|
||||
dummyScoreboard,
|
||||
objective.getName(),
|
||||
ObjectiveCriteria.DUMMY,
|
||||
objective.getTitle().convert(),
|
||||
RenderType.values()[objective.getHealthDisplay().ordinal()],
|
||||
false,
|
||||
objective.getNumberFormat() == null ? null : objective.getNumberFormat().toFixedFormat(FixedFormat::new)
|
||||
);
|
||||
objective.setPlatformObjective(obj);
|
||||
sendPacket(new ClientboundSetObjectivePacket(obj, ObjectiveAction.REGISTER));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDisplaySlot(@NonNull Objective objective) {
|
||||
sendPacket(new ClientboundSetDisplayObjectivePacket(
|
||||
net.minecraft.world.scores.DisplaySlot.values()[objective.getDisplaySlot().ordinal()],
|
||||
(net.minecraft.world.scores.Objective) objective.getPlatformObjective()
|
||||
));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterObjective(@NonNull Objective objective) {
|
||||
sendPacket(new ClientboundSetObjectivePacket((net.minecraft.world.scores.Objective) objective.getPlatformObjective(), ObjectiveAction.UNREGISTER));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateObjective(@NonNull Objective objective) {
|
||||
net.minecraft.world.scores.Objective obj = (net.minecraft.world.scores.Objective) objective.getPlatformObjective();
|
||||
obj.setDisplayName(objective.getTitle().convert());
|
||||
obj.setRenderType(RenderType.values()[objective.getHealthDisplay().ordinal()]);
|
||||
sendPacket(new ClientboundSetObjectivePacket(obj, ObjectiveAction.UPDATE));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setScore(@NonNull Score score) {
|
||||
sendPacket(new ClientboundSetScorePacket(
|
||||
score.getHolder(),
|
||||
score.getObjective().getName(),
|
||||
score.getValue(),
|
||||
Optional.ofNullable(score.getDisplayName() == null ? null : score.getDisplayName().convert()),
|
||||
Optional.ofNullable(score.getNumberFormat() == null ? null : score.getNumberFormat().toFixedFormat(FixedFormat::new))
|
||||
));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeScore(@NonNull Score score) {
|
||||
sendPacket(new ClientboundResetScorePacket(score.getHolder(), score.getObjective().getName()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public Object createTeam(@NonNull String name) {
|
||||
return new PlayerTeam(dummyScoreboard, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerTeam(@NonNull Team team) {
|
||||
updateTeamProperties(team);
|
||||
PlayerTeam t = (PlayerTeam) team.getPlatformTeam();
|
||||
t.getPlayers().addAll(team.getPlayers());
|
||||
sendPacket(ClientboundSetPlayerTeamPacket.createAddOrModifyPacket(t, true));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterTeam(@NonNull Team team) {
|
||||
sendPacket(ClientboundSetPlayerTeamPacket.createRemovePacket((PlayerTeam) team.getPlatformTeam()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateTeam(@NonNull Team team) {
|
||||
updateTeamProperties(team);
|
||||
sendPacket(ClientboundSetPlayerTeamPacket.createAddOrModifyPacket((PlayerTeam) team.getPlatformTeam(), false));
|
||||
}
|
||||
|
||||
private void updateTeamProperties(@NonNull Team team) {
|
||||
PlayerTeam t = (PlayerTeam) team.getPlatformTeam();
|
||||
t.setAllowFriendlyFire((team.getOptions() & 0x01) != 0);
|
||||
t.setSeeFriendlyInvisibles((team.getOptions() & 0x02) != 0);
|
||||
t.setColor(formats[team.getColor().getLegacyColor().ordinal()]);
|
||||
t.setCollisionRule(collisions[team.getCollision().ordinal()]);
|
||||
t.setNameTagVisibility(visibilities[team.getVisibility().ordinal()]);
|
||||
t.setPlayerPrefix(team.getPrefix().convert());
|
||||
t.setPlayerSuffix(team.getSuffix().convert());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketSend(@NonNull Object packet) {
|
||||
onPacketSend(packet, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the packet to the player.
|
||||
*
|
||||
* @param packet
|
||||
* Packet to send
|
||||
*/
|
||||
private void sendPacket(@NotNull Packet<?> packet) {
|
||||
((CraftPlayer)player.getPlayer()).getHandle().connection.sendPacket(packet);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package me.neznamy.tab.platforms.paper;
|
||||
package me.neznamy.tab.platforms.paper_1_21_4;
|
||||
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import com.mojang.authlib.properties.Property;
|
||||
@@ -118,16 +118,19 @@ public class BukkitPlatform implements BackendPlatform {
|
||||
@NotNull
|
||||
@SneakyThrows
|
||||
private ImplementationProvider findImplementationProvider() {
|
||||
if (ReflectionUtils.classExists("org.bukkit.craftbukkit.CraftServer") &&
|
||||
(serverVersion == ProtocolVersion.V1_21_4 || serverVersion == ProtocolVersion.V1_21_5)) {
|
||||
return (ImplementationProvider) Class.forName("me.neznamy.tab.platforms.paper.PaperImplementationProvider").getConstructor().newInstance();
|
||||
// Check for mojang-mapped paper (1.20.5+)
|
||||
String paperModule = getPaperModule();
|
||||
if (paperModule != null) {
|
||||
return (ImplementationProvider) Class.forName("me.neznamy.tab.platforms.paper_" + paperModule + ".PaperImplementationProvider").getConstructor().newInstance();
|
||||
}
|
||||
|
||||
// Check for direct NMS on some supported versions
|
||||
String serverPackage = BukkitReflection.getServerVersion().getServerPackage();
|
||||
if (Arrays.asList("v1_8_R3", "v1_12_R1", "v1_16_R3", "v1_17_R1", "v1_18_R2", "v1_19_R1").contains(serverPackage) && serverVersion != ProtocolVersion.V1_19) {
|
||||
return (ImplementationProvider) Class.forName("me.neznamy.tab.platforms.bukkit." + serverPackage + ".NMSImplementationProvider").getConstructor().newInstance();
|
||||
}
|
||||
|
||||
// Try reflection
|
||||
try {
|
||||
return new ReflectionImplementationProvider();
|
||||
} catch (Throwable e) {
|
||||
@@ -158,12 +161,40 @@ public class BukkitPlatform implements BackendPlatform {
|
||||
}
|
||||
Bukkit.getConsoleSender().sendMessage("§c[TAB] Please use " +
|
||||
"a plugin version with full support for your server version for optimal experience. This plugin version " +
|
||||
"has full support for 1.8.8, 1.12.x, 1.16.5, 1.17.x, 1.18.2 and 1.19.1 - 1.21.5.");
|
||||
"has full support for 1.8.8, 1.12.x, 1.16.5, 1.17.x, 1.18.2 and 1.19.1 - 1.21.6.");
|
||||
}
|
||||
return new BukkitImplementationProvider();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns name of the paper module that can be used on this server.
|
||||
* If this server is not using paper or no module is available for any other reason,
|
||||
* {@code null} is returned.
|
||||
*
|
||||
* @return Name of the available paper module or {@code null} if not available
|
||||
*/
|
||||
@Nullable
|
||||
private String getPaperModule() {
|
||||
if (!ReflectionUtils.classExists("org.bukkit.craftbukkit.CraftServer")) return null;
|
||||
switch (serverVersion) {
|
||||
case V1_20_5:
|
||||
case V1_20_6:
|
||||
case V1_21:
|
||||
case V1_21_1:
|
||||
return "1_20_5";
|
||||
case V1_21_2:
|
||||
case V1_21_3:
|
||||
return "1_21_2";
|
||||
case V1_21_4:
|
||||
case V1_21_5:
|
||||
case V1_21_6:
|
||||
return "1_21_4";
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadPlayers() {
|
||||
for (Player p : getOnlinePlayers()) {
|
||||
@@ -246,7 +277,9 @@ public class BukkitPlatform implements BackendPlatform {
|
||||
Bukkit.getScheduler().runTask(plugin, () -> {
|
||||
long time = System.nanoTime();
|
||||
ppl[0].updateValue(p, placeholderAPI ? PlaceholderAPI.setPlaceholders((Player) p.getPlayer(), syncedPlaceholder) : identifier);
|
||||
TAB.getInstance().getCPUManager().addPlaceholderTime(identifier, System.nanoTime() - time);
|
||||
long totalTime = System.nanoTime()-time;
|
||||
TAB.getInstance().getCPUManager().addPlaceholderTime(identifier, totalTime);
|
||||
TAB.getInstance().getCpu().addTime(TAB.getInstance().getPlaceholderManager().getFeatureName(), TabConstants.CpuUsageCategory.PLACEHOLDER_REQUEST, totalTime);
|
||||
});
|
||||
return null;
|
||||
});
|
||||
@@ -281,7 +314,7 @@ public class BukkitPlatform implements BackendPlatform {
|
||||
command.setExecutor(cmd);
|
||||
command.setTabCompleter(cmd);
|
||||
} else {
|
||||
logWarn(SimpleTextComponent.text("Failed to register command, is it defined in plugin.yml?"));
|
||||
logWarn(TabComponent.legacyText("Failed to register command, is it defined in plugin.yml?"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
package me.neznamy.tab.platforms.bukkit.platform;
|
||||
|
||||
import lombok.NonNull;
|
||||
import lombok.SneakyThrows;
|
||||
import me.clip.placeholderapi.PlaceholderAPI;
|
||||
import me.neznamy.tab.platforms.bukkit.features.PerWorldPlayerList;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.shared.TabConstants;
|
||||
import me.neznamy.chat.component.SimpleTextComponent;
|
||||
import me.neznamy.tab.shared.cpu.TimedCaughtTask;
|
||||
import me.neznamy.tab.shared.placeholders.types.PlayerPlaceholderImpl;
|
||||
import me.neznamy.tab.shared.platform.TabPlayer;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.player.PlayerChangedWorldEvent;
|
||||
@@ -16,7 +17,10 @@ import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.DecimalFormatSymbols;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* Platform override for Folia.
|
||||
@@ -37,10 +41,6 @@ public class FoliaPlatform extends BukkitPlatform {
|
||||
public void loadPlayers() {
|
||||
super.loadPlayers();
|
||||
|
||||
// Values are never updated in the API, warn users
|
||||
logWarn(SimpleTextComponent.text("Folia never updates MSPT and TPS values in the API, making " +
|
||||
"%mspt% and %tps% return the default values (0 and 20)."));
|
||||
|
||||
// Folia never calls PlayerChangedWorldEvent, this is a workaround
|
||||
TAB.getInstance().getCpu().getProcessingThread().repeatTask(new TimedCaughtTask(TAB.getInstance().getCpu(), () -> {
|
||||
for (TabPlayer player : TAB.getInstance().getOnlinePlayers()) {
|
||||
@@ -56,6 +56,17 @@ public class FoliaPlatform extends BukkitPlatform {
|
||||
}, "Folia compatibility", "Refreshing world"), 100);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerPlaceholders() {
|
||||
super.registerPlaceholders();
|
||||
DecimalFormat decimal2;
|
||||
DecimalFormatSymbols symbols = new DecimalFormatSymbols();
|
||||
symbols.setDecimalSeparator('.');
|
||||
decimal2 = new DecimalFormat("#.##", symbols);
|
||||
registerInternalSyncPlaceholder(TabConstants.Placeholder.MSPT, 1000, p -> decimal2.format(Bukkit.getAverageTickTime()));
|
||||
registerInternalSyncPlaceholder(TabConstants.Placeholder.TPS, 1000, p -> decimal2.format(Math.min(20, Bukkit.getTPS()[0])));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerSyncPlaceholder(@NotNull String identifier) {
|
||||
String syncedPlaceholder = "%" + identifier.substring(6);
|
||||
@@ -64,13 +75,42 @@ public class FoliaPlatform extends BukkitPlatform {
|
||||
runSync((Entity) p.getPlayer(), () -> {
|
||||
long time = System.nanoTime();
|
||||
String output = isPlaceholderAPI() ? PlaceholderAPI.setPlaceholders((Player) p.getPlayer(), syncedPlaceholder) : identifier;
|
||||
TAB.getInstance().getCPUManager().addPlaceholderTime(identifier, System.nanoTime()-time);
|
||||
long totalTime = System.nanoTime()-time;
|
||||
TAB.getInstance().getCPUManager().addPlaceholderTime(identifier, totalTime);
|
||||
TAB.getInstance().getCpu().addTime(TAB.getInstance().getPlaceholderManager().getFeatureName(), TabConstants.CpuUsageCategory.PLACEHOLDER_REQUEST, totalTime);
|
||||
TAB.getInstance().getCPUManager().runTask(() -> ppl[0].updateValue(p, output)); // To ensure player is loaded
|
||||
});
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
private void registerInternalSyncPlaceholder(@NonNull String identifier, int refresh, @NonNull Function<TabPlayer, String> function) {
|
||||
PlayerPlaceholderImpl[] ppl = new PlayerPlaceholderImpl[1];
|
||||
ppl[0] = TAB.getInstance().getPlaceholderManager().registerInternalPlayerPlaceholder(identifier, refresh, p -> {
|
||||
runSync((Entity) p.getPlayer(), () -> {
|
||||
long time = System.nanoTime();
|
||||
String output = function.apply((TabPlayer) p);
|
||||
long totalTime = System.nanoTime()-time;
|
||||
TAB.getInstance().getCPUManager().addPlaceholderTime(identifier, totalTime);
|
||||
TAB.getInstance().getCpu().addTime(TAB.getInstance().getPlaceholderManager().getFeatureName(), TabConstants.CpuUsageCategory.PLACEHOLDER_REQUEST, totalTime);
|
||||
TAB.getInstance().getCPUManager().runTask(() -> ppl[0].updateValue(p, output)); // To ensure player is loaded
|
||||
});
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Overriding the method to fix initial error caused by ServerPlaceholder implementation trying to
|
||||
* retrieve the value in constructor, but folia does not support that. Overriding this function to avoid the
|
||||
* MSPT function being called in the wrong thread.
|
||||
*
|
||||
* @return -1
|
||||
*/
|
||||
@Override
|
||||
public double getMSPT() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs task using player's entity scheduler. It's using reflection, because
|
||||
* Folia uses Java 17 while TAB maintains Java 8 compatibility for compatibility
|
||||
|
||||
+8
-10
@@ -138,17 +138,15 @@ public class PacketScoreboard extends SafeScoreboard<BukkitTabPlayer> {
|
||||
|
||||
@SneakyThrows
|
||||
public static void onPacketSend(@NonNull Object packet, @NonNull SafeScoreboard<BukkitTabPlayer> scoreboard) {
|
||||
if (scoreboard.isAntiOverrideScoreboard()) {
|
||||
if (DisplayObjectiveClass.isInstance(packet)) {
|
||||
TAB.getInstance().getFeatureManager().onDisplayObjective(scoreboard.getPlayer(), packetToSlot.apply(packet),
|
||||
(String) DisplayObjective_OBJECTIVE_NAME.get(packet));
|
||||
}
|
||||
if (ObjectivePacketClass.isInstance(packet)) {
|
||||
TAB.getInstance().getFeatureManager().onObjective(scoreboard.getPlayer(),
|
||||
Objective_METHOD.getInt(packet), (String) Objective_OBJECTIVE_NAME.get(packet));
|
||||
}
|
||||
if (DisplayObjectiveClass.isInstance(packet)) {
|
||||
TAB.getInstance().getFeatureManager().onDisplayObjective(scoreboard.getPlayer(), packetToSlot.apply(packet),
|
||||
(String) DisplayObjective_OBJECTIVE_NAME.get(packet));
|
||||
}
|
||||
if (scoreboard.isAntiOverrideTeams()) teamPacketData.onPacketSend(scoreboard.getPlayer(), packet);
|
||||
if (ObjectivePacketClass.isInstance(packet)) {
|
||||
TAB.getInstance().getFeatureManager().onObjective(scoreboard.getPlayer(),
|
||||
Objective_METHOD.getInt(packet), (String) Objective_OBJECTIVE_NAME.get(packet));
|
||||
}
|
||||
teamPacketData.onPacketSend(scoreboard.getPlayer(), packet);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@ public class PacketSender {
|
||||
Class<?> EntityPlayer = BukkitReflection.getClass("server.level.ServerPlayer", "server.level.EntityPlayer");
|
||||
Class<?> PlayerConnection = BukkitReflection.getClass("server.network.ServerGamePacketListenerImpl", "server.network.PlayerConnection");
|
||||
Field PLAYER_CONNECTION = ReflectionUtils.getOnlyField(EntityPlayer, PlayerConnection);
|
||||
Method sendPacket = ReflectionUtils.getMethods(PlayerConnection, void.class, Packet).get(0);
|
||||
Method sendPacket = ReflectionUtils.getPublicMethods(PlayerConnection, void.class, Packet).get(0);
|
||||
send = (player, packet) -> {
|
||||
if (player.connection == null) player.connection = PLAYER_CONNECTION.get(player.getHandle());
|
||||
sendPacket.invoke(player.connection, packet);
|
||||
|
||||
+1
-2
@@ -8,7 +8,6 @@ import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
|
||||
import com.viaversion.viaversion.api.protocol.packet.State;
|
||||
import com.viaversion.viaversion.api.type.Types;
|
||||
import lombok.NonNull;
|
||||
import me.neznamy.chat.component.SimpleTextComponent;
|
||||
import me.neznamy.chat.component.TabComponent;
|
||||
import me.neznamy.tab.platforms.bukkit.BukkitTabPlayer;
|
||||
import me.neznamy.tab.platforms.bukkit.platform.BukkitPlatform;
|
||||
@@ -144,7 +143,7 @@ public abstract class ViaScoreboard extends SafeScoreboard<BukkitTabPlayer> {
|
||||
case TeamAction.CREATE:
|
||||
case TeamAction.UPDATE:
|
||||
// Team display name
|
||||
writeComponent(packet, SimpleTextComponent.text(team.getName()));
|
||||
writeComponent(packet, TabComponent.legacyText(team.getName()));
|
||||
// Friendly flags
|
||||
packet.write(Types.BYTE, (byte) team.getOptions());
|
||||
// Name tag visibility
|
||||
|
||||
+8
-10
@@ -37,17 +37,15 @@ public class NMSPacketScoreboard extends SafeScoreboard<BukkitTabPlayer> {
|
||||
@SneakyThrows
|
||||
@SuppressWarnings("unchecked")
|
||||
public static void onPacketSend(@NonNull Object packet, @NonNull SafeScoreboard<BukkitTabPlayer> scoreboard) {
|
||||
if (scoreboard.isAntiOverrideScoreboard()) {
|
||||
if (packet instanceof PacketPlayOutScoreboardDisplayObjective) {
|
||||
TAB.getInstance().getFeatureManager().onDisplayObjective(scoreboard.getPlayer(), DisplayObjective_POSITION.getInt(packet),
|
||||
(String) DisplayObjective_OBJECTIVE_NAME.get(packet));
|
||||
}
|
||||
if (packet instanceof PacketPlayOutScoreboardObjective) {
|
||||
TAB.getInstance().getFeatureManager().onObjective(scoreboard.getPlayer(),
|
||||
Objective_METHOD.getInt(packet), (String) Objective_OBJECTIVE_NAME.get(packet));
|
||||
}
|
||||
if (packet instanceof PacketPlayOutScoreboardDisplayObjective) {
|
||||
TAB.getInstance().getFeatureManager().onDisplayObjective(scoreboard.getPlayer(), DisplayObjective_POSITION.getInt(packet),
|
||||
(String) DisplayObjective_OBJECTIVE_NAME.get(packet));
|
||||
}
|
||||
if (scoreboard.isAntiOverrideTeams() && packet instanceof PacketPlayOutScoreboardTeam) {
|
||||
if (packet instanceof PacketPlayOutScoreboardObjective) {
|
||||
TAB.getInstance().getFeatureManager().onObjective(scoreboard.getPlayer(),
|
||||
Objective_METHOD.getInt(packet), (String) Objective_OBJECTIVE_NAME.get(packet));
|
||||
}
|
||||
if (packet instanceof PacketPlayOutScoreboardTeam) {
|
||||
int action = TeamPacket_ACTION.getInt(packet);
|
||||
if (action == TeamAction.UPDATE) return;
|
||||
Collection<String> players = (Collection<String>) TeamPacket_PLAYERS.get(packet);
|
||||
|
||||
+8
-10
@@ -36,17 +36,15 @@ public class NMSPacketScoreboard extends SafeScoreboard<BukkitTabPlayer> {
|
||||
@SneakyThrows
|
||||
@SuppressWarnings("unchecked")
|
||||
public static void onPacketSend(@NonNull Object packet, @NonNull SafeScoreboard<BukkitTabPlayer> scoreboard) {
|
||||
if (scoreboard.isAntiOverrideScoreboard()) {
|
||||
if (packet instanceof PacketPlayOutScoreboardDisplayObjective) {
|
||||
TAB.getInstance().getFeatureManager().onDisplayObjective(scoreboard.getPlayer(), DisplayObjective_POSITION.getInt(packet),
|
||||
(String) DisplayObjective_OBJECTIVE_NAME.get(packet));
|
||||
}
|
||||
if (packet instanceof PacketPlayOutScoreboardObjective) {
|
||||
TAB.getInstance().getFeatureManager().onObjective(scoreboard.getPlayer(),
|
||||
Objective_METHOD.getInt(packet), (String) Objective_OBJECTIVE_NAME.get(packet));
|
||||
}
|
||||
if (packet instanceof PacketPlayOutScoreboardDisplayObjective) {
|
||||
TAB.getInstance().getFeatureManager().onDisplayObjective(scoreboard.getPlayer(), DisplayObjective_POSITION.getInt(packet),
|
||||
(String) DisplayObjective_OBJECTIVE_NAME.get(packet));
|
||||
}
|
||||
if (scoreboard.isAntiOverrideTeams() && packet instanceof PacketPlayOutScoreboardTeam) {
|
||||
if (packet instanceof PacketPlayOutScoreboardObjective) {
|
||||
TAB.getInstance().getFeatureManager().onObjective(scoreboard.getPlayer(),
|
||||
Objective_METHOD.getInt(packet), (String) Objective_OBJECTIVE_NAME.get(packet));
|
||||
}
|
||||
if (packet instanceof PacketPlayOutScoreboardTeam) {
|
||||
int action = TeamPacket_ACTION.getInt(packet);
|
||||
if (action == TeamAction.UPDATE) return;
|
||||
Collection<String> players = (Collection<String>) TeamPacket_PLAYERS.get(packet);
|
||||
|
||||
+14
-16
@@ -39,23 +39,21 @@ public class NMSPacketScoreboard extends SafeScoreboard<BukkitTabPlayer> {
|
||||
@SneakyThrows
|
||||
@SuppressWarnings("unchecked")
|
||||
public static void onPacketSend(@NonNull Object packet, @NonNull SafeScoreboard<BukkitTabPlayer> scoreboard) {
|
||||
if (scoreboard.isAntiOverrideScoreboard()) {
|
||||
if (packet instanceof PacketPlayOutScoreboardDisplayObjective) {
|
||||
TAB.getInstance().getFeatureManager().onDisplayObjective(
|
||||
scoreboard.getPlayer(),
|
||||
((PacketPlayOutScoreboardDisplayObjective)packet).b(),
|
||||
((PacketPlayOutScoreboardDisplayObjective)packet).c()
|
||||
);
|
||||
}
|
||||
if (packet instanceof PacketPlayOutScoreboardObjective) {
|
||||
TAB.getInstance().getFeatureManager().onObjective(
|
||||
scoreboard.getPlayer(),
|
||||
((PacketPlayOutScoreboardObjective)packet).d(),
|
||||
((PacketPlayOutScoreboardObjective)packet).b()
|
||||
);
|
||||
}
|
||||
if (packet instanceof PacketPlayOutScoreboardDisplayObjective) {
|
||||
TAB.getInstance().getFeatureManager().onDisplayObjective(
|
||||
scoreboard.getPlayer(),
|
||||
((PacketPlayOutScoreboardDisplayObjective)packet).b(),
|
||||
((PacketPlayOutScoreboardDisplayObjective)packet).c()
|
||||
);
|
||||
}
|
||||
if (scoreboard.isAntiOverrideTeams() && packet instanceof PacketPlayOutScoreboardTeam) {
|
||||
if (packet instanceof PacketPlayOutScoreboardObjective) {
|
||||
TAB.getInstance().getFeatureManager().onObjective(
|
||||
scoreboard.getPlayer(),
|
||||
((PacketPlayOutScoreboardObjective)packet).d(),
|
||||
((PacketPlayOutScoreboardObjective)packet).b()
|
||||
);
|
||||
}
|
||||
if (packet instanceof PacketPlayOutScoreboardTeam) {
|
||||
int action = getMethod((PacketPlayOutScoreboardTeam) packet);
|
||||
if (action == TeamAction.UPDATE) return;
|
||||
Collection<String> players = (Collection<String>) TeamPacket_PLAYERS.get(packet);
|
||||
|
||||
+14
-16
@@ -40,23 +40,21 @@ public class NMSPacketScoreboard extends SafeScoreboard<BukkitTabPlayer> {
|
||||
@SneakyThrows
|
||||
@SuppressWarnings("unchecked")
|
||||
public static void onPacketSend(@NonNull Object packet, @NonNull SafeScoreboard<BukkitTabPlayer> scoreboard) {
|
||||
if (scoreboard.isAntiOverrideScoreboard()) {
|
||||
if (packet instanceof PacketPlayOutScoreboardDisplayObjective) {
|
||||
TAB.getInstance().getFeatureManager().onDisplayObjective(
|
||||
scoreboard.getPlayer(),
|
||||
((PacketPlayOutScoreboardDisplayObjective)packet).b(),
|
||||
((PacketPlayOutScoreboardDisplayObjective)packet).c()
|
||||
);
|
||||
}
|
||||
if (packet instanceof PacketPlayOutScoreboardObjective) {
|
||||
TAB.getInstance().getFeatureManager().onObjective(
|
||||
scoreboard.getPlayer(),
|
||||
((PacketPlayOutScoreboardObjective)packet).d(),
|
||||
((PacketPlayOutScoreboardObjective)packet).b()
|
||||
);
|
||||
}
|
||||
if (packet instanceof PacketPlayOutScoreboardDisplayObjective) {
|
||||
TAB.getInstance().getFeatureManager().onDisplayObjective(
|
||||
scoreboard.getPlayer(),
|
||||
((PacketPlayOutScoreboardDisplayObjective)packet).b(),
|
||||
((PacketPlayOutScoreboardDisplayObjective)packet).c()
|
||||
);
|
||||
}
|
||||
if (scoreboard.isAntiOverrideTeams() && packet instanceof PacketPlayOutScoreboardTeam) {
|
||||
if (packet instanceof PacketPlayOutScoreboardObjective) {
|
||||
TAB.getInstance().getFeatureManager().onObjective(
|
||||
scoreboard.getPlayer(),
|
||||
((PacketPlayOutScoreboardObjective)packet).d(),
|
||||
((PacketPlayOutScoreboardObjective)packet).b()
|
||||
);
|
||||
}
|
||||
if (packet instanceof PacketPlayOutScoreboardTeam) {
|
||||
int action = getMethod((PacketPlayOutScoreboardTeam) packet);
|
||||
if (action == TeamAction.UPDATE) return;
|
||||
Collection<String> players = (Collection<String>) TeamPacket_PLAYERS.get(packet);
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@ import org.bukkit.craftbukkit.v1_19_R1.entity.CraftPlayer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Implementation provider using direct NMS code for 1.19 - 1.19.2.
|
||||
* Implementation provider using direct NMS code for 1.19.1 - 1.19.2.
|
||||
*/
|
||||
@Getter
|
||||
public class NMSImplementationProvider implements ImplementationProvider {
|
||||
|
||||
+14
-16
@@ -40,23 +40,21 @@ public class NMSPacketScoreboard extends SafeScoreboard<BukkitTabPlayer> {
|
||||
@SneakyThrows
|
||||
@SuppressWarnings("unchecked")
|
||||
public static void onPacketSend(@NonNull Object packet, @NonNull SafeScoreboard<BukkitTabPlayer> scoreboard) {
|
||||
if (scoreboard.isAntiOverrideScoreboard()) {
|
||||
if (packet instanceof PacketPlayOutScoreboardDisplayObjective) {
|
||||
TAB.getInstance().getFeatureManager().onDisplayObjective(
|
||||
scoreboard.getPlayer(),
|
||||
((PacketPlayOutScoreboardDisplayObjective)packet).b(),
|
||||
((PacketPlayOutScoreboardDisplayObjective)packet).c()
|
||||
);
|
||||
}
|
||||
if (packet instanceof PacketPlayOutScoreboardObjective) {
|
||||
TAB.getInstance().getFeatureManager().onObjective(
|
||||
scoreboard.getPlayer(),
|
||||
((PacketPlayOutScoreboardObjective)packet).d(),
|
||||
((PacketPlayOutScoreboardObjective)packet).b()
|
||||
);
|
||||
}
|
||||
if (packet instanceof PacketPlayOutScoreboardDisplayObjective) {
|
||||
TAB.getInstance().getFeatureManager().onDisplayObjective(
|
||||
scoreboard.getPlayer(),
|
||||
((PacketPlayOutScoreboardDisplayObjective)packet).b(),
|
||||
((PacketPlayOutScoreboardDisplayObjective)packet).c()
|
||||
);
|
||||
}
|
||||
if (scoreboard.isAntiOverrideTeams() && packet instanceof PacketPlayOutScoreboardTeam) {
|
||||
if (packet instanceof PacketPlayOutScoreboardObjective) {
|
||||
TAB.getInstance().getFeatureManager().onObjective(
|
||||
scoreboard.getPlayer(),
|
||||
((PacketPlayOutScoreboardObjective)packet).d(),
|
||||
((PacketPlayOutScoreboardObjective)packet).b()
|
||||
);
|
||||
}
|
||||
if (packet instanceof PacketPlayOutScoreboardTeam) {
|
||||
int action = getMethod((PacketPlayOutScoreboardTeam) packet);
|
||||
if (action == TeamAction.UPDATE) return;
|
||||
Collection<String> players = (Collection<String>) TeamPacket_PLAYERS.get(packet);
|
||||
|
||||
+8
-10
@@ -36,17 +36,15 @@ public class NMSPacketScoreboard extends SafeScoreboard<BukkitTabPlayer> {
|
||||
@SneakyThrows
|
||||
@SuppressWarnings("unchecked")
|
||||
public static void onPacketSend(@NonNull Object packet, @NonNull SafeScoreboard<BukkitTabPlayer> scoreboard) {
|
||||
if (scoreboard.isAntiOverrideScoreboard()) {
|
||||
if (packet instanceof PacketPlayOutScoreboardDisplayObjective) {
|
||||
TAB.getInstance().getFeatureManager().onDisplayObjective(scoreboard.getPlayer(), DisplayObjective_POSITION.getInt(packet),
|
||||
(String) DisplayObjective_OBJECTIVE_NAME.get(packet));
|
||||
}
|
||||
if (packet instanceof PacketPlayOutScoreboardObjective) {
|
||||
TAB.getInstance().getFeatureManager().onObjective(scoreboard.getPlayer(),
|
||||
Objective_METHOD.getInt(packet), (String) Objective_OBJECTIVE_NAME.get(packet));
|
||||
}
|
||||
if (packet instanceof PacketPlayOutScoreboardDisplayObjective) {
|
||||
TAB.getInstance().getFeatureManager().onDisplayObjective(scoreboard.getPlayer(), DisplayObjective_POSITION.getInt(packet),
|
||||
(String) DisplayObjective_OBJECTIVE_NAME.get(packet));
|
||||
}
|
||||
if (scoreboard.isAntiOverrideTeams() && packet instanceof PacketPlayOutScoreboardTeam) {
|
||||
if (packet instanceof PacketPlayOutScoreboardObjective) {
|
||||
TAB.getInstance().getFeatureManager().onObjective(scoreboard.getPlayer(),
|
||||
Objective_METHOD.getInt(packet), (String) Objective_OBJECTIVE_NAME.get(packet));
|
||||
}
|
||||
if (packet instanceof PacketPlayOutScoreboardTeam) {
|
||||
int action = TeamPacket_ACTION.getInt(packet);
|
||||
if (action == TeamAction.UPDATE) return;
|
||||
Collection<String> players = (Collection<String>) TeamPacket_PLAYERS.get(packet);
|
||||
|
||||
+10
-13
@@ -2,11 +2,10 @@ package me.neznamy.tab.platforms.bungeecord;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import lombok.NonNull;
|
||||
import me.neznamy.chat.component.TabComponent;
|
||||
import me.neznamy.tab.shared.Limitations;
|
||||
import me.neznamy.tab.shared.ProtocolVersion;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.chat.component.SimpleTextComponent;
|
||||
import me.neznamy.chat.component.TabComponent;
|
||||
import me.neznamy.tab.shared.platform.decorators.SafeScoreboard;
|
||||
import net.md_5.bungee.api.chat.BaseComponent;
|
||||
import net.md_5.bungee.protocol.Either;
|
||||
@@ -117,7 +116,7 @@ public class BungeeScoreboard extends SafeScoreboard<BungeeTabPlayer> {
|
||||
player.sendPacket(new net.md_5.bungee.protocol.packet.Team(
|
||||
team.getName(),
|
||||
action,
|
||||
either(SimpleTextComponent.text(team.getName()), Limitations.TEAM_PREFIX_SUFFIX_PRE_1_13),
|
||||
either(TabComponent.legacyText(team.getName()), Limitations.TEAM_PREFIX_SUFFIX_PRE_1_13),
|
||||
either(team.getPrefix(), Limitations.TEAM_PREFIX_SUFFIX_PRE_1_13),
|
||||
either(team.getSuffix(), Limitations.TEAM_PREFIX_SUFFIX_PRE_1_13),
|
||||
net.md_5.bungee.protocol.packet.Team.NameTagVisibility.valueOf(team.getVisibility().name()),
|
||||
@@ -130,17 +129,15 @@ public class BungeeScoreboard extends SafeScoreboard<BungeeTabPlayer> {
|
||||
|
||||
@Override
|
||||
public void onPacketSend(@NonNull Object packet) {
|
||||
if (isAntiOverrideScoreboard()) {
|
||||
if (packet instanceof ScoreboardDisplay) {
|
||||
ScoreboardDisplay display = (ScoreboardDisplay) packet;
|
||||
TAB.getInstance().getFeatureManager().onDisplayObjective(player, display.getPosition(), display.getName());
|
||||
}
|
||||
if (packet instanceof ScoreboardObjective) {
|
||||
ScoreboardObjective objective = (ScoreboardObjective) packet;
|
||||
TAB.getInstance().getFeatureManager().onObjective(player, objective.getAction(), objective.getName());
|
||||
}
|
||||
if (packet instanceof ScoreboardDisplay) {
|
||||
ScoreboardDisplay display = (ScoreboardDisplay) packet;
|
||||
TAB.getInstance().getFeatureManager().onDisplayObjective(player, display.getPosition(), display.getName());
|
||||
}
|
||||
if (isAntiOverrideTeams() && packet instanceof net.md_5.bungee.protocol.packet.Team) {
|
||||
if (packet instanceof ScoreboardObjective) {
|
||||
ScoreboardObjective objective = (ScoreboardObjective) packet;
|
||||
TAB.getInstance().getFeatureManager().onObjective(player, objective.getAction(), objective.getName());
|
||||
}
|
||||
if (packet instanceof net.md_5.bungee.protocol.packet.Team) {
|
||||
net.md_5.bungee.protocol.packet.Team team = (net.md_5.bungee.protocol.packet.Team) packet;
|
||||
if (team.getMode() == TeamAction.UPDATE) return;
|
||||
List<String> players = team.getPlayers() == null ? Collections.emptyList() : Lists.newArrayList(team.getPlayers());
|
||||
|
||||
+2
-2
@@ -1,9 +1,9 @@
|
||||
package me.neznamy.tab.platforms.bungeecord.hook;
|
||||
|
||||
import de.myzelyam.api.vanish.BungeeVanishAPI;
|
||||
import me.neznamy.chat.component.TabComponent;
|
||||
import me.neznamy.tab.api.TabPlayer;
|
||||
import me.neznamy.tab.platforms.bungeecord.BungeeTabPlayer;
|
||||
import me.neznamy.chat.component.SimpleTextComponent;
|
||||
import me.neznamy.tab.shared.hook.PremiumVanishHook;
|
||||
import me.neznamy.tab.shared.platform.Platform;
|
||||
import me.neznamy.tab.shared.util.ReflectionUtils;
|
||||
@@ -29,7 +29,7 @@ public class BungeePremiumVanishHook extends PremiumVanishHook {
|
||||
canSeeEnabled = true;
|
||||
} else {
|
||||
canSeeEnabled = false;
|
||||
platform.logWarn(SimpleTextComponent.text("Detected an outdated version of " +
|
||||
platform.logWarn(TabComponent.legacyText("Detected an outdated version of " +
|
||||
"PremiumVanish with limited API. Vanish compatibility " +
|
||||
"may not work as expected. Update PremiumVanish to version 2.7.11+ for optimal experience."));
|
||||
}
|
||||
|
||||
+1
-1
@@ -28,7 +28,7 @@ public class BungeePipelineInjector extends NettyPipelineInjector {
|
||||
public BungeePipelineInjector() {
|
||||
super("inbound-boss");
|
||||
Config config = TAB.getInstance().getConfiguration().getConfig();
|
||||
byteBufDeserialization = (config.getTeams() != null && config.getTeams().isAntiOverride()) || config.getScoreboard() != null;
|
||||
byteBufDeserialization = (config.getTeams() != null) || config.getScoreboard() != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package me.neznamy.chat.component;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -8,7 +9,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
* A component of "keybind" type that contains bound key.
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
@AllArgsConstructor(access = AccessLevel.PACKAGE)
|
||||
public class KeybindComponent extends TabComponent {
|
||||
|
||||
@NotNull
|
||||
|
||||
+2
-19
@@ -1,6 +1,5 @@
|
||||
package me.neznamy.chat.component;
|
||||
|
||||
import lombok.NonNull;
|
||||
import me.neznamy.chat.TextColor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -9,31 +8,15 @@ import org.jetbrains.annotations.Nullable;
|
||||
* An implementation that only uses the "text" field with legacy colors in it, without using
|
||||
* any component style or extra.
|
||||
*/
|
||||
public class SimpleTextComponent extends TextComponent {
|
||||
public class LegacyTextComponent extends TextComponent {
|
||||
|
||||
/** Empty component to avoid recreating one over and over */
|
||||
public static final SimpleTextComponent EMPTY = new SimpleTextComponent("");
|
||||
|
||||
/**
|
||||
* Creates a new instance with given text.
|
||||
*
|
||||
* @param text
|
||||
* Component text, including color codes
|
||||
* @return Component with given text
|
||||
*/
|
||||
@NotNull
|
||||
public static SimpleTextComponent text(@NonNull String text) {
|
||||
if (text.isEmpty()) return EMPTY;
|
||||
return new SimpleTextComponent(text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs new instance with given text.
|
||||
*
|
||||
* @param text
|
||||
* Component text
|
||||
*/
|
||||
private SimpleTextComponent(@NotNull String text) {
|
||||
protected LegacyTextComponent(@NotNull String text) {
|
||||
super(text);
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.viaversion.nbt.tag.Tag;
|
||||
import com.viaversion.viaversion.libs.gson.JsonElement;
|
||||
import com.viaversion.viaversion.util.ComponentUtil;
|
||||
import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
import lombok.Setter;
|
||||
import lombok.SneakyThrows;
|
||||
import me.neznamy.chat.ChatModifier;
|
||||
@@ -17,7 +18,9 @@ import net.kyori.adventure.text.Component;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
@@ -27,6 +30,9 @@ import java.util.regex.Pattern;
|
||||
*/
|
||||
public abstract class TabComponent {
|
||||
|
||||
/** Empty component to avoid recreating one over and over */
|
||||
public static final LegacyTextComponent EMPTY_LEGACY_TEXT = new LegacyTextComponent("");
|
||||
|
||||
/** Function for converting this class into platform's actual component */
|
||||
@Nullable
|
||||
public static Function<TabComponent, Object> CONVERT_FUNCTION;
|
||||
@@ -422,4 +428,48 @@ public abstract class TabComponent {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an empty component of "text" type.
|
||||
* This is used to avoid creating new empty components over and over.
|
||||
*
|
||||
* @return Empty legacy text component
|
||||
*/
|
||||
public static TabComponent empty() {
|
||||
return EMPTY_LEGACY_TEXT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new component of "text" type with given legacy text.
|
||||
*
|
||||
* @param text
|
||||
* Text to use in the component
|
||||
* @return New legacy text component with given text
|
||||
*/
|
||||
public static LegacyTextComponent legacyText(@NonNull String text) {
|
||||
if (text.isEmpty()) return EMPTY_LEGACY_TEXT;
|
||||
return new LegacyTextComponent(text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new component of "translatable" type with given key.
|
||||
*
|
||||
* @param key
|
||||
* Translatable to use in the component
|
||||
* @return New translatable component with given key
|
||||
*/
|
||||
public static TranslatableComponent translatable(@NonNull String key) {
|
||||
return new TranslatableComponent(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new component of "keybind" type with given key.
|
||||
*
|
||||
* @param keybind
|
||||
* Key to use in the component
|
||||
* @return New keybind text component with given key
|
||||
*/
|
||||
public static KeybindComponent keybind(@NonNull String keybind) {
|
||||
return new KeybindComponent(keybind);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package me.neznamy.chat.component;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -8,7 +9,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
* A component of "translate" type that contains key to translate.
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
@AllArgsConstructor(access = AccessLevel.PACKAGE)
|
||||
public class TranslatableComponent extends TabComponent {
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -97,9 +97,9 @@ public class AdventureHook {
|
||||
if (component instanceof net.kyori.adventure.text.TextComponent) {
|
||||
tabComponent = new TextComponent(((net.kyori.adventure.text.TextComponent) component).content());
|
||||
} else if (component instanceof net.kyori.adventure.text.TranslatableComponent) {
|
||||
tabComponent = new TranslatableComponent(((net.kyori.adventure.text.TranslatableComponent) component).key());
|
||||
tabComponent = TabComponent.translatable(((net.kyori.adventure.text.TranslatableComponent) component).key());
|
||||
} else if (component instanceof net.kyori.adventure.text.KeybindComponent) {
|
||||
tabComponent = new KeybindComponent(((net.kyori.adventure.text.KeybindComponent) component).keybind());
|
||||
tabComponent = TabComponent.keybind(((net.kyori.adventure.text.KeybindComponent) component).keybind());
|
||||
} else {
|
||||
throw new UnsupportedOperationException(component.getClass().getName() + " component type is not supported");
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import com.viaversion.viaversion.libs.gson.JsonObject;
|
||||
import com.viaversion.viaversion.util.ComponentUtil;
|
||||
import me.neznamy.chat.ChatModifier;
|
||||
import me.neznamy.chat.component.KeybindComponent;
|
||||
import me.neznamy.chat.component.SimpleTextComponent;
|
||||
import me.neznamy.chat.component.LegacyTextComponent;
|
||||
import me.neznamy.chat.component.TabComponent;
|
||||
import me.neznamy.chat.component.TextComponent;
|
||||
import me.neznamy.chat.component.TranslatableComponent;
|
||||
@@ -18,7 +18,7 @@ public class ViaVersionHook {
|
||||
|
||||
@NotNull
|
||||
public static JsonElement convert(@NotNull TabComponent component) {
|
||||
if (component instanceof SimpleTextComponent) {
|
||||
if (component instanceof LegacyTextComponent) {
|
||||
return ComponentUtil.legacyToJson(component.toLegacyText());
|
||||
}
|
||||
|
||||
|
||||
@@ -11,11 +11,11 @@ repositories {
|
||||
maven("https://maven.nucleoid.xyz/")
|
||||
}
|
||||
|
||||
val minecraftVersion = "1.21.5"
|
||||
val minecraftVersion = "1.21.6"
|
||||
|
||||
// Fabric API versions for each Minecraft version for easier backporting
|
||||
val fabricApiVersions = mapOf(
|
||||
"25w21a" to "0.119.10+1.21.6",
|
||||
"1.21.6" to "0.125.1+1.21.6",
|
||||
"1.21.5" to "0.119.9+1.21.5",
|
||||
"1.21.4" to "0.119.2+1.21.4",
|
||||
"1.21.3" to "0.114.0+1.21.3",
|
||||
|
||||
@@ -106,7 +106,7 @@ public record FabricPlatform(MinecraftServer server) implements BackendPlatform
|
||||
@Override
|
||||
@NotNull
|
||||
public String getServerVersionInfo() {
|
||||
return "[Fabric] " + SharedConstants.getCurrentVersion().getName();
|
||||
return "[Fabric] " + SharedConstants.getCurrentVersion().name();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -128,15 +128,13 @@ public class FabricScoreboard extends SafeScoreboard<FabricTabPlayer> {
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public void onPacketSend(@NonNull Object packet) {
|
||||
if (isAntiOverrideScoreboard()) {
|
||||
if (packet instanceof ClientboundSetDisplayObjectivePacket display) {
|
||||
TAB.getInstance().getFeatureManager().onDisplayObjective(player, display.getSlot().ordinal(), display.getObjectiveName());
|
||||
}
|
||||
if (packet instanceof ClientboundSetObjectivePacket objective) {
|
||||
TAB.getInstance().getFeatureManager().onObjective(player, objective.getMethod(), objective.getObjectiveName());
|
||||
}
|
||||
if (packet instanceof ClientboundSetDisplayObjectivePacket display) {
|
||||
TAB.getInstance().getFeatureManager().onDisplayObjective(player, display.getSlot().ordinal(), display.getObjectiveName());
|
||||
}
|
||||
if (isAntiOverrideTeams() && packet instanceof ClientboundSetPlayerTeamPacket team) {
|
||||
if (packet instanceof ClientboundSetObjectivePacket objective) {
|
||||
TAB.getInstance().getFeatureManager().onObjective(player, objective.getMethod(), objective.getObjectiveName());
|
||||
}
|
||||
if (packet instanceof ClientboundSetPlayerTeamPacket team) {
|
||||
int method = getMethod(team);
|
||||
if (method == TeamAction.UPDATE) return;
|
||||
team.getPlayers();
|
||||
|
||||
@@ -14,8 +14,7 @@
|
||||
"fabric-api-base": "*",
|
||||
"java": ">=17",
|
||||
"minecraft": [
|
||||
"1.21.4",
|
||||
"1.21.5"
|
||||
"1.21.6"
|
||||
]
|
||||
},
|
||||
"recommends": {
|
||||
|
||||
@@ -12,10 +12,11 @@ repositories {
|
||||
maven("https://maven.neoforged.net/releases")
|
||||
}
|
||||
|
||||
val minecraftVersion = "1.21.5"
|
||||
val minecraftVersion = "1.21.6"
|
||||
|
||||
// Forge API versions for each Minecraft version for easier backporting
|
||||
val forgeApiVersions = mapOf(
|
||||
"1.21.6" to "1.21.6-56.0.0",
|
||||
"1.21.5" to "1.21.5-55.0.3",
|
||||
"1.21.4" to "1.21.4-54.1.3",
|
||||
"1.21.3" to "1.21.3-53.1.0",
|
||||
|
||||
@@ -4,9 +4,7 @@ import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.shared.platform.EventListener;
|
||||
import me.neznamy.tab.shared.platform.TabPlayer;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.event.entity.player.PlayerEvent;
|
||||
import net.minecraftforge.eventbus.api.IEventBus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
@@ -18,15 +16,14 @@ public class ForgeEventListener implements EventListener<ServerPlayer> {
|
||||
* Registers all event listeners.
|
||||
*/
|
||||
public void register() {
|
||||
IEventBus eventBus = MinecraftForge.EVENT_BUS;
|
||||
eventBus.addListener((PlayerEvent.PlayerLoggedInEvent event) -> join((ServerPlayer) event.getEntity()));
|
||||
eventBus.addListener((PlayerEvent.PlayerLoggedOutEvent event) -> quit(event.getEntity().getUUID()));
|
||||
eventBus.addListener((PlayerEvent.PlayerRespawnEvent event) -> {
|
||||
PlayerEvent.PlayerLoggedInEvent.BUS.addListener(event -> join((ServerPlayer) event.getEntity()));
|
||||
PlayerEvent.PlayerLoggedOutEvent.BUS.addListener(event -> quit(event.getEntity().getUUID()));
|
||||
PlayerEvent.PlayerRespawnEvent.BUS.addListener(event -> {
|
||||
ServerPlayer player = (ServerPlayer) event.getEntity();
|
||||
replacePlayer(player.getUUID(), player);
|
||||
worldChange(player.getUUID(), ForgeTAB.getLevelName(player.level()));
|
||||
});
|
||||
eventBus.addListener((PlayerEvent.PlayerChangedDimensionEvent event) -> worldChange(event.getEntity().getUUID(), ForgeTAB.getLevelName(event.getEntity().level())));
|
||||
PlayerEvent.PlayerChangedDimensionEvent.BUS.addListener(event -> worldChange(event.getEntity().getUUID(), ForgeTAB.getLevelName(event.getEntity().level())));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -81,7 +81,7 @@ public record ForgePlatform(MinecraftServer server) implements BackendPlatform {
|
||||
@Override
|
||||
@NotNull
|
||||
public String getServerVersionInfo() {
|
||||
return "[Forge] " + SharedConstants.getCurrentVersion().getName();
|
||||
return "[Forge] " + SharedConstants.getCurrentVersion().name();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -128,15 +128,13 @@ public class ForgeScoreboard extends SafeScoreboard<ForgeTabPlayer> {
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public void onPacketSend(@NonNull Object packet) {
|
||||
if (isAntiOverrideScoreboard()) {
|
||||
if (packet instanceof ClientboundSetDisplayObjectivePacket display) {
|
||||
TAB.getInstance().getFeatureManager().onDisplayObjective(player, display.getSlot().ordinal(), display.getObjectiveName());
|
||||
}
|
||||
if (packet instanceof ClientboundSetObjectivePacket objective) {
|
||||
TAB.getInstance().getFeatureManager().onObjective(player, objective.getMethod(), objective.getObjectiveName());
|
||||
}
|
||||
if (packet instanceof ClientboundSetDisplayObjectivePacket display) {
|
||||
TAB.getInstance().getFeatureManager().onDisplayObjective(player, display.getSlot().ordinal(), display.getObjectiveName());
|
||||
}
|
||||
if (isAntiOverrideTeams() && packet instanceof ClientboundSetPlayerTeamPacket team) {
|
||||
if (packet instanceof ClientboundSetObjectivePacket objective) {
|
||||
TAB.getInstance().getFeatureManager().onObjective(player, objective.getMethod(), objective.getObjectiveName());
|
||||
}
|
||||
if (packet instanceof ClientboundSetPlayerTeamPacket team) {
|
||||
int method = getMethod(team);
|
||||
if (method == TeamAction.UPDATE) return;
|
||||
players.set(team, onTeamPacket(method, team.getName(), team.getPlayers()));
|
||||
|
||||
@@ -5,23 +5,23 @@ import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.storage.ServerLevelData;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.event.RegisterCommandsEvent;
|
||||
import net.minecraftforge.event.server.ServerStartingEvent;
|
||||
import net.minecraftforge.event.server.ServerStoppingEvent;
|
||||
import net.minecraftforge.eventbus.api.IEventBus;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Main class for Forge TAB implementation.
|
||||
*/
|
||||
@OnlyIn(Dist.DEDICATED_SERVER)
|
||||
@Mod(value = "tab")
|
||||
@Mod("tab")
|
||||
public class ForgeTAB {
|
||||
|
||||
public ForgeTAB() {
|
||||
IEventBus EVENT_BUS = MinecraftForge.EVENT_BUS;
|
||||
EVENT_BUS.addListener((RegisterCommandsEvent event) -> new ForgeTabCommand().onRegisterCommands(event.getDispatcher()));
|
||||
EVENT_BUS.addListener((ServerStartingEvent event) -> TAB.create(new ForgePlatform(event.getServer())));
|
||||
EVENT_BUS.addListener((ServerStoppingEvent event) -> TAB.getInstance().unload());
|
||||
RegisterCommandsEvent.BUS.addListener(event -> new ForgeTabCommand().onRegisterCommands(event.getDispatcher()));
|
||||
ServerStartingEvent.BUS.addListener(event -> TAB.create(new ForgePlatform(event.getServer())));
|
||||
ServerStoppingEvent.BUS.addListener(event -> TAB.getInstance().unload());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -22,6 +22,6 @@ side = "SERVER"
|
||||
[[dependencies.tab]]
|
||||
modId = "minecraft"
|
||||
mandatory = true
|
||||
versionRange = "[1.21.4],[1.21.5]"
|
||||
versionRange = "[1.21.6]"
|
||||
ordering = "NONE"
|
||||
side = "SERVER"
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.2-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
||||
@@ -6,7 +6,9 @@ plugins {
|
||||
|
||||
val platforms = setOf(
|
||||
rootProject.projects.bukkit,
|
||||
rootProject.projects.bukkit.paper,
|
||||
rootProject.projects.bukkit.paper1205,
|
||||
rootProject.projects.bukkit.paper1212,
|
||||
rootProject.projects.bukkit.paper1214,
|
||||
rootProject.projects.bukkit.v18R3,
|
||||
rootProject.projects.bukkit.v112R1,
|
||||
rootProject.projects.bukkit.v116R3,
|
||||
|
||||
@@ -12,21 +12,22 @@ repositories {
|
||||
maven("https://maven.neoforged.net/releases")
|
||||
}
|
||||
|
||||
val minecraftVersion = "1.21.5"
|
||||
val minecraftVersion = "1.21.6"
|
||||
|
||||
// NeoForge API versions for each Minecraft version for easier backporting
|
||||
val neoforgeApiVersions = mapOf(
|
||||
"1.21.5" to "21.5.26-beta",
|
||||
"1.21.4" to "21.4.124",
|
||||
"1.21.3" to "21.3.66",
|
||||
"1.21.6" to "21.6.5-beta",
|
||||
"1.21.5" to "21.5.77",
|
||||
"1.21.4" to "21.4.138",
|
||||
"1.21.3" to "21.3.77",
|
||||
"1.21.2" to "21.2.1-beta",
|
||||
"1.21.1" to "21.1.144",
|
||||
"1.21.1" to "21.1.180",
|
||||
"1.21" to "21.0.167",
|
||||
"1.20.6" to "20.6.125",
|
||||
"1.20.6" to "20.6.135",
|
||||
"1.20.5" to "20.5.21-beta",
|
||||
"1.20.4" to "20.4.239",
|
||||
"1.20.4" to "20.4.248",
|
||||
"1.20.3" to "20.3.8-beta",
|
||||
"1.20.2" to "20.2.88"
|
||||
"1.20.2" to "20.2.93"
|
||||
)
|
||||
|
||||
dependencies {
|
||||
|
||||
@@ -81,7 +81,7 @@ public record NeoForgePlatform(MinecraftServer server) implements BackendPlatfor
|
||||
@Override
|
||||
@NotNull
|
||||
public String getServerVersionInfo() {
|
||||
return "[NeoForge] " + SharedConstants.getCurrentVersion().getName();
|
||||
return "[NeoForge] " + SharedConstants.getCurrentVersion().name();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -128,15 +128,13 @@ public class NeoForgeScoreboard extends SafeScoreboard<NeoForgeTabPlayer> {
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public void onPacketSend(@NonNull Object packet) {
|
||||
if (isAntiOverrideScoreboard()) {
|
||||
if (packet instanceof ClientboundSetDisplayObjectivePacket display) {
|
||||
TAB.getInstance().getFeatureManager().onDisplayObjective(player, display.getSlot().ordinal(), display.getObjectiveName());
|
||||
}
|
||||
if (packet instanceof ClientboundSetObjectivePacket objective) {
|
||||
TAB.getInstance().getFeatureManager().onObjective(player, objective.getMethod(), objective.getObjectiveName());
|
||||
}
|
||||
if (packet instanceof ClientboundSetDisplayObjectivePacket display) {
|
||||
TAB.getInstance().getFeatureManager().onDisplayObjective(player, display.getSlot().ordinal(), display.getObjectiveName());
|
||||
}
|
||||
if (isAntiOverrideTeams() && packet instanceof ClientboundSetPlayerTeamPacket team) {
|
||||
if (packet instanceof ClientboundSetObjectivePacket objective) {
|
||||
TAB.getInstance().getFeatureManager().onObjective(player, objective.getMethod(), objective.getObjectiveName());
|
||||
}
|
||||
if (packet instanceof ClientboundSetPlayerTeamPacket team) {
|
||||
int method = getMethod(team);
|
||||
if (method == TeamAction.UPDATE) return;
|
||||
players.set(team, onTeamPacket(method, team.getName(), team.getPlayers()));
|
||||
|
||||
@@ -21,6 +21,6 @@ side = "SERVER"
|
||||
[[dependencies.tab]]
|
||||
modId = "minecraft"
|
||||
type = "required"
|
||||
versionRange = "[1.21.4],[1.21.5]"
|
||||
versionRange = "[1.21.6]"
|
||||
ordering = "NONE"
|
||||
side = "SERVER"
|
||||
+3
-1
@@ -32,7 +32,9 @@ include(":api")
|
||||
include(":shared")
|
||||
include(":velocity")
|
||||
include(":bukkit")
|
||||
include(":bukkit:paper")
|
||||
include(":bukkit:paper_1_20_5")
|
||||
include(":bukkit:paper_1_21_2")
|
||||
include(":bukkit:paper_1_21_4")
|
||||
include(":bukkit:v1_8_R3")
|
||||
include(":bukkit:v1_12_R1")
|
||||
include(":bukkit:v1_16_R3")
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package me.neznamy.tab.shared;
|
||||
|
||||
import lombok.Getter;
|
||||
import me.neznamy.chat.component.TabComponent;
|
||||
import me.neznamy.tab.api.event.TabEvent;
|
||||
import me.neznamy.chat.component.SimpleTextComponent;
|
||||
import me.neznamy.tab.shared.platform.TabPlayer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -117,13 +117,13 @@ public class ErrorManager {
|
||||
if (file.length() < TabConstants.MAX_LOG_SIZE)
|
||||
buf.write(dateFormat.format(new Date()) + "[TAB v" + TabConstants.PLUGIN_VERSION + "] " + message + System.lineSeparator());
|
||||
if (intoConsoleToo || TAB.getInstance().getConfiguration().getConfig().isDebugMode())
|
||||
TAB.getInstance().getPlatform().logWarn(SimpleTextComponent.text(message));
|
||||
TAB.getInstance().getPlatform().logWarn(TabComponent.legacyText(message));
|
||||
}
|
||||
for (String line : error) {
|
||||
if (file.length() < TabConstants.MAX_LOG_SIZE)
|
||||
buf.write(dateFormat.format(new Date()) + line + System.lineSeparator());
|
||||
if (intoConsoleToo || TAB.getInstance().getConfiguration().getConfig().isDebugMode())
|
||||
TAB.getInstance().getPlatform().logWarn(SimpleTextComponent.text(line));
|
||||
TAB.getInstance().getPlatform().logWarn(TabComponent.legacyText(line));
|
||||
}
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
@@ -133,7 +133,7 @@ public class ErrorManager {
|
||||
lines.add("Original error: " + message);
|
||||
lines.addAll(error);
|
||||
for (String line : lines) {
|
||||
TAB.getInstance().getPlatform().logWarn(SimpleTextComponent.text(line));
|
||||
TAB.getInstance().getPlatform().logWarn(TabComponent.legacyText(line));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,9 +63,7 @@ public class FeatureManager {
|
||||
public void load() {
|
||||
for (TabFeature f : values) {
|
||||
if (!(f instanceof Loadable)) continue;
|
||||
long time = System.currentTimeMillis();
|
||||
((Loadable) f).load();
|
||||
TAB.getInstance().debug("Feature " + f.getClass().getSimpleName() + " processed load in " + (System.currentTimeMillis()-time) + "ms");
|
||||
}
|
||||
if (TAB.getInstance().getConfiguration().getUsers() instanceof MySQLUserConfiguration) {
|
||||
MySQLUserConfiguration users = (MySQLUserConfiguration) TAB.getInstance().getConfiguration().getUsers();
|
||||
@@ -84,9 +82,7 @@ public class FeatureManager {
|
||||
((CustomThreaded) f).getCustomThread().shutdown();
|
||||
}
|
||||
if (f instanceof UnLoadable) {
|
||||
long time = System.currentTimeMillis();
|
||||
((UnLoadable) f).unload();
|
||||
TAB.getInstance().debug("Feature " + f.getClass().getSimpleName() + " processed unload in " + (System.currentTimeMillis()-time) + "ms");
|
||||
}
|
||||
}
|
||||
for (TabFeature f : values) {
|
||||
@@ -165,10 +161,31 @@ public class FeatureManager {
|
||||
}
|
||||
}
|
||||
TAB.getInstance().removePlayer(disconnectedPlayer);
|
||||
for (TabPlayer all : TAB.getInstance().getOnlinePlayers()) {
|
||||
((TrackedTabList<?>)all.getTabList()).getExpectedDisplayNames().remove(disconnectedPlayer.getTablistId());
|
||||
}
|
||||
removeExpectedDisplayName(disconnectedPlayer.getTablistId());
|
||||
TAB.getInstance().debug("Player quit of " + disconnectedPlayer.getName() + " processed in " + (System.currentTimeMillis()-millis) + "ms");
|
||||
|
||||
ProxySupport proxy = getFeature(TabConstants.Feature.PROXY_SUPPORT);
|
||||
if (proxy != null) {
|
||||
ProxyPlayer proxyPlayer = proxy.getProxyPlayers().get(disconnectedPlayer.getUniqueId());
|
||||
if (proxyPlayer != null && proxyPlayer.getConnectionState() == ProxyPlayer.ConnectionState.QUEUED) {
|
||||
onJoin(proxyPlayer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void removeExpectedDisplayName(@NotNull UUID id) {
|
||||
ProxySupport proxy = getFeature(TabConstants.Feature.PROXY_SUPPORT);
|
||||
if (proxy != null) {
|
||||
ProxyPlayer proxyPlayer = proxy.getProxyPlayers().get(id);
|
||||
if (proxyPlayer != null) return; // Proxy player is already connected, do not remove anymore
|
||||
}
|
||||
|
||||
if (TAB.getInstance().getPlayer(id) != null) return; // Real player connected in the meantime, do not remove anymore
|
||||
|
||||
// Player is actually not online anymore, remove to avoid memory leak
|
||||
for (TabPlayer all : TAB.getInstance().getOnlinePlayers()) {
|
||||
((TrackedTabList<?>)all.getTabList()).getExpectedDisplayNames().remove(id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -182,11 +199,7 @@ public class FeatureManager {
|
||||
TAB.getInstance().addPlayer(connectedPlayer);
|
||||
for (TabFeature f : values) {
|
||||
if (!(f instanceof JoinListener)) continue;
|
||||
TimedCaughtTask task = new TimedCaughtTask(TAB.getInstance().getCpu(), () -> {
|
||||
long time = System.nanoTime();
|
||||
((JoinListener) f).onJoin(connectedPlayer);
|
||||
TAB.getInstance().debug("Feature " + f.getClass().getSimpleName() + " processed player join in " + (System.nanoTime()-time)/1000000 + "ms");
|
||||
}, f.getFeatureName(), CpuUsageCategory.PLAYER_JOIN);
|
||||
TimedCaughtTask task = new TimedCaughtTask(TAB.getInstance().getCpu(), () -> ((JoinListener) f).onJoin(connectedPlayer), f.getFeatureName(), CpuUsageCategory.PLAYER_JOIN);
|
||||
if (f instanceof CustomThreaded) {
|
||||
((CustomThreaded) f).getCustomThread().execute(task);
|
||||
} else {
|
||||
@@ -426,16 +439,25 @@ public class FeatureManager {
|
||||
* Player who joined
|
||||
*/
|
||||
public void onJoin(@NotNull ProxyPlayer connectedPlayer) {
|
||||
for (TabFeature f : values) {
|
||||
if (!(f instanceof ProxyFeature)) continue;
|
||||
TimedCaughtTask task = new TimedCaughtTask(TAB.getInstance().getCpu(),
|
||||
() -> ((ProxyFeature) f).onJoin(connectedPlayer), f.getFeatureName(), CpuUsageCategory.PLAYER_JOIN);
|
||||
if (f instanceof CustomThreaded) {
|
||||
((CustomThreaded) f).getCustomThread().execute(task);
|
||||
} else {
|
||||
task.run();
|
||||
// Delay to let server remove the player from tablist, and then we can potentially add the player back
|
||||
// No delay could cause the server to send tablist remove packet of real player AFTER we sent add, removing the player
|
||||
TAB.getInstance().getCpu().getProcessingThread().executeLater(new TimedCaughtTask(TAB.getInstance().getCpu(), () -> {
|
||||
if (connectedPlayer.getConnectionState() == ProxyPlayer.ConnectionState.DISCONNECTED) return; // Player immediately disconnected in the meantime
|
||||
connectedPlayer.setConnectionState(ProxyPlayer.ConnectionState.CONNECTED);
|
||||
for (TabFeature f : values) {
|
||||
if (!(f instanceof ProxyFeature)) continue;
|
||||
TimedCaughtTask task = new TimedCaughtTask(TAB.getInstance().getCpu(),
|
||||
() -> ((ProxyFeature) f).onJoin(connectedPlayer), f.getFeatureName(), CpuUsageCategory.PLAYER_JOIN);
|
||||
if (f instanceof CustomThreaded) {
|
||||
((CustomThreaded) f).getCustomThread().execute(task);
|
||||
} else {
|
||||
task.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (connectedPlayer.isVanished()) {
|
||||
onVanishStatusChange(connectedPlayer);
|
||||
}
|
||||
}, getFeature(TabConstants.Feature.PROXY_SUPPORT).getFeatureName(), CpuUsageCategory.PLAYER_JOIN), 200);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -464,6 +486,7 @@ public class FeatureManager {
|
||||
* Player who left
|
||||
*/
|
||||
public void onQuit(@NotNull ProxyPlayer disconnectedPlayer) {
|
||||
disconnectedPlayer.setConnectionState(ProxyPlayer.ConnectionState.DISCONNECTED);
|
||||
for (TabFeature f : values) {
|
||||
if (!(f instanceof ProxyFeature)) continue;
|
||||
TimedCaughtTask task = new TimedCaughtTask(TAB.getInstance().getCpu(),
|
||||
@@ -474,9 +497,7 @@ public class FeatureManager {
|
||||
task.run();
|
||||
}
|
||||
}
|
||||
for (TabPlayer all : TAB.getInstance().getOnlinePlayers()) {
|
||||
((TrackedTabList<?>)all.getTabList()).getExpectedDisplayNames().remove(disconnectedPlayer.getUniqueId());
|
||||
}
|
||||
removeExpectedDisplayName(disconnectedPlayer.getTablistId());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -11,6 +11,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
public enum ProtocolVersion {
|
||||
|
||||
UNKNOWN,
|
||||
V1_21_6 (771),
|
||||
V1_21_5 (770),
|
||||
V1_21_4 (769),
|
||||
V1_21_3 (768),
|
||||
|
||||
@@ -222,7 +222,9 @@ public class TabConstants {
|
||||
public static final String STAFF_ONLINE = "%staffonline%";
|
||||
public static final String NON_STAFF_ONLINE = "%nonstaffonline%";
|
||||
public static final String LUCKPERMS_PREFIX = "%luckperms-prefix%";
|
||||
public static final String LUCKPERMS_PREFIXES = "%luckperms-prefixes%";
|
||||
public static final String LUCKPERMS_SUFFIX = "%luckperms-suffix%";
|
||||
public static final String LUCKPERMS_SUFFIXES = "%luckperms-suffixes%";
|
||||
public static final String LUCKPERMS_WEIGHT = "%luckperms-weight%";
|
||||
public static final String GAMEMODE = "%gamemode%";
|
||||
public static final String BEDROCK = "%bedrock%";
|
||||
|
||||
@@ -108,7 +108,6 @@ public class Converter {
|
||||
private void convertTeamOptions(@NonNull ConfigurationFile oldConfig, @NonNull ConfigurationFile newConfig, @Nullable ConfigurationFile premiumConfig) {
|
||||
newConfig.set("scoreboard-teams.enabled", oldConfig.getBoolean("change-nametag-prefix-suffix", true));
|
||||
newConfig.set("scoreboard-teams.invisible-nametags", oldConfig.getBoolean("invisible-nametags", false));
|
||||
newConfig.set("scoreboard-teams.anti-override", oldConfig.getBoolean("anti-override.scoreboard-teams", true));
|
||||
newConfig.set("scoreboard-teams.enable-collision", oldConfig.getBoolean("enable-collision", true));
|
||||
newConfig.set("scoreboard-teams.disable-in-worlds", oldConfig.getStringList("disable-features-in-worlds.nametag", Collections.singletonList("disabledworld")));
|
||||
if (TAB.getInstance().getPlatform().isProxy()) {
|
||||
@@ -152,7 +151,6 @@ public class Converter {
|
||||
|
||||
private void convertTabListFormatting(@NonNull ConfigurationFile oldConfig, @NonNull ConfigurationFile newConfig) {
|
||||
newConfig.set("tablist-name-formatting.enabled", oldConfig.getBoolean("change-tablist-prefix-suffix", true));
|
||||
newConfig.set("tablist-name-formatting.anti-override", oldConfig.getBoolean("anti-override.tablist-names", true));
|
||||
newConfig.set("tablist-name-formatting.disable-in-worlds", oldConfig.getStringList("disable-features-in-worlds.tablist-names", Collections.singletonList("disabledworld")));
|
||||
if (TAB.getInstance().getPlatform().isProxy())
|
||||
newConfig.set("tablist-name-formatting.disable-in-servers", oldConfig.getStringList("disable-features-in-servers.tablist-names", Collections.singletonList("disabledserver")));
|
||||
@@ -520,4 +518,19 @@ public class Converter {
|
||||
config.setIfMissing("playerlist-objective.title", "TAB");
|
||||
config.setIfMissing("playerlist-objective.render-type", Arrays.asList("%health%", "%player_health%", "%player_health_rounded%").contains(config.getString("playerlist-objective.value", "")) ? "HEARTS" : "INTEGER");
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts config from 5.2.1 to 5.2.2.
|
||||
* This update:
|
||||
* - Removes anti-override settings from scoreboard-teams and tablist-name-formatting
|
||||
*
|
||||
* @param config
|
||||
* Config file
|
||||
*/
|
||||
public void convert521to522(@NonNull ConfigurationFile config) {
|
||||
if (config.removeOption("scoreboard-teams.anti-override")) {
|
||||
TAB.getInstance().getPlatform().logInfo(new TextComponent("Performing configuration conversion from 5.2.1 to 5.2.2", TextColor.YELLOW));
|
||||
}
|
||||
config.removeOption("tablist-name-formatting.anti-override");
|
||||
}
|
||||
}
|
||||
@@ -183,7 +183,7 @@ public interface PropertyConfiguration {
|
||||
*/
|
||||
default void checkProperty(@NonNull String source, @NonNull String type, @NonNull String name, @NonNull String property,
|
||||
@Nullable String server, @Nullable String world, boolean startupWarn) {
|
||||
if (VALID_PROPERTIES.contains(property)) return;
|
||||
if (VALID_PROPERTIES.contains(property.toLowerCase(Locale.US))) return;
|
||||
StringBuilder msg = new StringBuilder(String.format("[%s] Unknown property \"%s\" defined for %s \"%s\"", source, property, type, name));
|
||||
if (world != null) msg.append(" in world \"").append(world).append("\"");
|
||||
if (server != null) msg.append(" in server \"").append(server).append("\"");
|
||||
|
||||
@@ -6,10 +6,7 @@ import me.neznamy.tab.shared.TAB;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -22,7 +19,7 @@ public class ConfigurationSection {
|
||||
|
||||
public void checkForUnknownKey(@NonNull List<String> validProperties) {
|
||||
for (Object mapKey : map.keySet()) {
|
||||
if (!validProperties.contains(mapKey.toString())) {
|
||||
if (!validProperties.contains(mapKey.toString().toLowerCase(Locale.US))) {
|
||||
startupWarn(String.format("Configuration section \"%s\" has unknown key \"%s\". Valid keys: %s", section, mapKey, validProperties));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ package me.neznamy.tab.shared.config.file;
|
||||
|
||||
import lombok.NonNull;
|
||||
import me.neznamy.chat.TextColor;
|
||||
import me.neznamy.chat.component.SimpleTextComponent;
|
||||
import me.neznamy.chat.component.TabComponent;
|
||||
import me.neznamy.chat.component.TextComponent;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.yamlassist.YamlAssist;
|
||||
@@ -55,7 +55,7 @@ public class YamlConfigurationFile extends ConfigurationFile {
|
||||
if (input != null) input.close();
|
||||
TAB tab = TAB.getInstance();
|
||||
tab.setBrokenFile(destination.getName());
|
||||
tab.getPlatform().logWarn(SimpleTextComponent.text("File " + destination + " has broken syntax."));
|
||||
tab.getPlatform().logWarn(TabComponent.legacyText("File " + destination + " has broken syntax."));
|
||||
tab.getPlatform().logInfo(new TextComponent("Error message from yaml parser: " + e.getMessage(), TextColor.GOLD));
|
||||
List<String> suggestions = YamlAssist.getSuggestions(file);
|
||||
if (!suggestions.isEmpty()) {
|
||||
@@ -77,7 +77,7 @@ public class YamlConfigurationFile extends ConfigurationFile {
|
||||
new Yaml(options).dump(values, writer);
|
||||
writer.close();
|
||||
} catch (IOException e) {
|
||||
TAB.getInstance().getPlatform().logWarn(SimpleTextComponent.text(String.format(
|
||||
TAB.getInstance().getPlatform().logWarn(TabComponent.legacyText(String.format(
|
||||
"Failed to save yaml file %s: %s: %s",
|
||||
file.getPath(), e.getClass().getName(), e.getMessage()
|
||||
)));
|
||||
|
||||
@@ -80,6 +80,7 @@ public class Config {
|
||||
converter.convert419to500(config);
|
||||
converter.convert501to502(config);
|
||||
converter.convert507to510(config);
|
||||
converter.convert521to522(config);
|
||||
|
||||
conditions = ConditionsSection.fromSection(config.getConfigurationSection("conditions"));
|
||||
refresh = PlaceholderRefreshConfiguration.fromSection(config.getConfigurationSection("placeholder-refresh-intervals"));
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package me.neznamy.tab.shared.config.helper;
|
||||
|
||||
import lombok.NonNull;
|
||||
import me.neznamy.chat.component.SimpleTextComponent;
|
||||
import me.neznamy.chat.component.TabComponent;
|
||||
import me.neznamy.tab.api.bossbar.BossBar;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.shared.features.sorting.types.SortingType;
|
||||
@@ -91,8 +91,12 @@ public class RuntimeErrorPrinter {
|
||||
// Placeholders are not initialized, because bridge did not respond yet (typically on join)
|
||||
if (target instanceof ProxyTabPlayer && !((ProxyTabPlayer)target).isBridgeConnected()) return;
|
||||
|
||||
error(String.format("Belowname value is configured to show \"%s\", but returned \"%s\" for player %s, which cannot be evaluated to a number.",
|
||||
configuredValue, output, target.getName()));
|
||||
String msg = String.format("Belowname value is configured to show \"%s\", but returned \"%s\" for player %s, which cannot be evaluated to a number.",
|
||||
configuredValue, output, target.getName());
|
||||
if (output.contains("%")) {
|
||||
msg += " Did you perhaps forget to download a PlaceholderAPI expansion?";
|
||||
}
|
||||
error(msg);
|
||||
}
|
||||
|
||||
public void floatInBelowName(@NonNull TabPlayer target, @NonNull String configuredValue, @NonNull String output) {
|
||||
@@ -108,8 +112,12 @@ public class RuntimeErrorPrinter {
|
||||
// Placeholders are not initialized, because bridge did not respond yet (typically on join)
|
||||
if (target instanceof ProxyTabPlayer && !((ProxyTabPlayer)target).isBridgeConnected()) return;
|
||||
|
||||
error(String.format("Playerlist objective value is configured to show \"%s\", but returned \"%s\" for player %s, which cannot be evaluated to a number.",
|
||||
configuredValue, output, target.getName()));
|
||||
String msg = String.format("Playerlist objective value is configured to show \"%s\", but returned \"%s\" for player %s, which cannot be evaluated to a number.",
|
||||
configuredValue, output, target.getName());
|
||||
if (output.contains("%")) {
|
||||
msg += " Did you perhaps forget to download a PlaceholderAPI expansion?";
|
||||
}
|
||||
error(msg);
|
||||
}
|
||||
|
||||
public void floatInPlayerlistObjective(@NonNull TabPlayer target, @NonNull String configuredValue, @NonNull String output) {
|
||||
@@ -198,6 +206,6 @@ public class RuntimeErrorPrinter {
|
||||
* Message to log
|
||||
*/
|
||||
public void error(@NonNull String message) {
|
||||
TAB.getInstance().getPlatform().logWarn(SimpleTextComponent.text(message.replace('§', '&')));
|
||||
TAB.getInstance().getPlatform().logWarn(TabComponent.legacyText(message.replace('§', '&')));
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
package me.neznamy.tab.shared.config.helper;
|
||||
|
||||
import lombok.NonNull;
|
||||
import me.neznamy.chat.component.SimpleTextComponent;
|
||||
import me.neznamy.chat.component.TabComponent;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.shared.features.sorting.types.SortingType;
|
||||
|
||||
@@ -43,8 +43,8 @@ public class StartupWarnPrinter {
|
||||
startupWarn("Line \"" + line + "\" in condition " + conditionName + " is not a valid condition pattern.");
|
||||
}
|
||||
|
||||
public void incompleteSortingLine(@NonNull String configuredLine) {
|
||||
startupWarn("Sorting line \"" + configuredLine + "\" is incomplete.");
|
||||
public void invalidSortingLine(@NonNull String configuredLine, @NonNull String message) {
|
||||
startupWarn("Sorting line \"" + configuredLine + "\" is invalid: " + message);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -56,13 +56,13 @@ public class StartupWarnPrinter {
|
||||
public void startupWarn(@NonNull String... messages) {
|
||||
warnCount++;
|
||||
for (String message : messages) {
|
||||
TAB.getInstance().getPlatform().logWarn(SimpleTextComponent.text(message));
|
||||
TAB.getInstance().getPlatform().logWarn(TabComponent.legacyText(message));
|
||||
}
|
||||
}
|
||||
|
||||
public void startupWarn(@NonNull File file, @NonNull String message) {
|
||||
warnCount++;
|
||||
TAB.getInstance().getPlatform().logWarn(SimpleTextComponent.text("[" + file.getName() + "] " + message));
|
||||
TAB.getInstance().getPlatform().logWarn(TabComponent.legacyText("[" + file.getName() + "] " + message));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -70,7 +70,7 @@ public class StartupWarnPrinter {
|
||||
*/
|
||||
public void printWarnCount() {
|
||||
if (warnCount == 0) return;
|
||||
TAB.getInstance().getPlatform().logWarn(SimpleTextComponent.text("Found a total of " + warnCount + " issues."));
|
||||
TAB.getInstance().getPlatform().logWarn(TabComponent.legacyText("Found a total of " + warnCount + " issues."));
|
||||
// Reset after printing to prevent count going up on each reload
|
||||
warnCount = 0;
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ public class NickCompatibility extends TabFeature implements EntryAddListener {
|
||||
if (proxyPlayer == null) return;
|
||||
if (!proxyPlayer.getNickname().equals(name)) {
|
||||
proxyPlayer.setNickname(name);
|
||||
TAB.getInstance().debug("Processing name change of proxy player " + proxyPlayer.getName() + " to " + name);
|
||||
TAB.getInstance().debug("[Proxy Support] Processing name change of proxy player " + proxyPlayer.getName() + " to " + name);
|
||||
processNameChange(proxyPlayer);
|
||||
}
|
||||
}
|
||||
@@ -94,11 +94,11 @@ public class NickCompatibility extends TabFeature implements EntryAddListener {
|
||||
String teamName = player.getTeamName();
|
||||
for (TabPlayer viewer : nameTags.getOnlinePlayers().getPlayers()) {
|
||||
viewer.getScoreboard().unregisterTeam(teamName);
|
||||
TabComponent prefix = nameTags.getCache().get(player.getTagPrefix());
|
||||
TabComponent prefix = player.getTagPrefix();
|
||||
viewer.getScoreboard().registerTeam(
|
||||
teamName,
|
||||
prefix,
|
||||
nameTags.getCache().get(player.getTagSuffix()),
|
||||
player.getTagSuffix(),
|
||||
player.getNameVisibility(),
|
||||
Scoreboard.CollisionRule.ALWAYS,
|
||||
Collections.singletonList(player.getNickname()),
|
||||
|
||||
@@ -35,10 +35,10 @@ public class SpectatorFix extends TabFeature implements JoinListener, GameModeLi
|
||||
for (TabPlayer target : TAB.getInstance().getOnlinePlayers()) {
|
||||
if (viewer == target) continue;
|
||||
if (target.getGamemode() == 3 && !viewer.hasPermission(TabConstants.Permission.SPECTATOR_BYPASS)) {
|
||||
viewer.getTabList().updateGameMode(target.getTablistId(), realGameMode ? target.getGamemode() : 0);
|
||||
viewer.getTabList().updateGameMode(target, realGameMode ? target.getGamemode() : 0);
|
||||
}
|
||||
if (mutually && viewer.getGamemode() == 3 && !target.hasPermission(TabConstants.Permission.SPECTATOR_BYPASS)) {
|
||||
target.getTabList().updateGameMode(viewer.getTablistId(), realGameMode ? viewer.getGamemode() : 0);
|
||||
target.getTabList().updateGameMode(viewer, realGameMode ? viewer.getGamemode() : 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -49,7 +49,7 @@ public class SpectatorFix extends TabFeature implements JoinListener, GameModeLi
|
||||
for (TabPlayer viewer : TAB.getInstance().getOnlinePlayers()) {
|
||||
if (viewer.hasPermission(TabConstants.Permission.SPECTATOR_BYPASS)) continue;
|
||||
if (player != viewer && player.server.equals(viewer.server)) {
|
||||
viewer.getTabList().updateGameMode(player.getTablistId(), 0);
|
||||
viewer.getTabList().updateGameMode(player, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -90,7 +90,7 @@ public class SpectatorFix extends TabFeature implements JoinListener, GameModeLi
|
||||
if (changed.getGamemode() != 3) return;
|
||||
for (TabPlayer viewer : TAB.getInstance().getOnlinePlayers()) {
|
||||
if (viewer == changed || viewer.hasPermission(TabConstants.Permission.SPECTATOR_BYPASS)) continue;
|
||||
viewer.getTabList().updateGameMode(changed.getTablistId(), 0);
|
||||
viewer.getTabList().updateGameMode(changed, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,7 +99,7 @@ public class SpectatorFix extends TabFeature implements JoinListener, GameModeLi
|
||||
if (player.isVanished() || player.getGamemode() != 3) return;
|
||||
for (TabPlayer viewer : TAB.getInstance().getOnlinePlayers()) {
|
||||
if (viewer == player || viewer.hasPermission(TabConstants.Permission.SPECTATOR_BYPASS)) continue;
|
||||
viewer.getTabList().updateGameMode(player.getTablistId(), 0);
|
||||
viewer.getTabList().updateGameMode(player, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ public class BelowName extends RefreshableFeature implements JoinListener, QuitL
|
||||
TAB.getInstance().getFeatureManager().registerFeature(TabConstants.Feature.BELOW_NAME + "-Condition", disableChecker);
|
||||
TAB.getInstance().getFeatureManager().registerFeature(TabConstants.Feature.BELOW_NAME_TEXT, textRefresher);
|
||||
if (proxy != null) {
|
||||
proxy.registerMessage("belowname", BelowNameUpdateProxyPlayer.class, () -> new BelowNameUpdateProxyPlayer(this));
|
||||
proxy.registerMessage(BelowNameUpdateProxyPlayer.class, in -> new BelowNameUpdateProxyPlayer(in, this));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -292,6 +292,25 @@ public class BelowName extends RefreshableFeature implements JoinListener, QuitL
|
||||
onlinePlayers.removePlayer(disconnectedPlayer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onJoin(@NotNull ProxyPlayer player) {
|
||||
updatePlayer(player);
|
||||
}
|
||||
|
||||
public void updatePlayer(@NotNull ProxyPlayer player) {
|
||||
if (player.getBelowNameFancy() == null) return; // Player not loaded yet
|
||||
for (TabPlayer viewer : onlinePlayers.getPlayers()) {
|
||||
if (viewer.belowNameData.disabled.get()) continue;
|
||||
viewer.getScoreboard().setScore(
|
||||
OBJECTIVE_NAME,
|
||||
player.getNickname(),
|
||||
player.getBelowNameNumber(),
|
||||
null, // Unused by this objective slot
|
||||
player.getBelowNameFancy()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------
|
||||
// ProxySupport
|
||||
// ------------------
|
||||
|
||||
+3
-1
@@ -39,7 +39,9 @@ public class BelowNameConfiguration {
|
||||
String title = section.getString("title", "Health");
|
||||
if (title.contains("%") && !title.contains("%animation") && !title.contains("%condition")) {
|
||||
section.startupWarn("Belowname title is set to \"" + title + "\", however, the feature cannot display different title on different players " +
|
||||
"due to a minecraft limitation. Placeholders will be parsed for viewing player.");
|
||||
"due to a minecraft limitation. Placeholders will be parsed for viewing player. To display per-player placeholders correctly, " +
|
||||
"move them to fancy-value and only keep static text in title (this only works on 1.20.3+, on older versions you will need to " +
|
||||
"use \"value\", which only supports numbers).");
|
||||
}
|
||||
|
||||
// Check "value" for empty value
|
||||
|
||||
+27
-29
@@ -3,13 +3,12 @@ package me.neznamy.tab.shared.features.belowname;
|
||||
import com.google.common.io.ByteArrayDataInput;
|
||||
import com.google.common.io.ByteArrayDataOutput;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import lombok.ToString;
|
||||
import me.neznamy.tab.shared.cpu.ThreadExecutor;
|
||||
import me.neznamy.tab.shared.features.proxy.ProxyPlayer;
|
||||
import me.neznamy.tab.shared.features.proxy.ProxySupport;
|
||||
import me.neznamy.tab.shared.features.proxy.QueuedData;
|
||||
import me.neznamy.tab.shared.features.proxy.message.ProxyMessage;
|
||||
import me.neznamy.tab.shared.platform.TabPlayer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.UUID;
|
||||
@@ -17,16 +16,29 @@ import java.util.UUID;
|
||||
/**
|
||||
* Proxy message to update belowname data of a player.
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@ToString
|
||||
public class BelowNameUpdateProxyPlayer extends ProxyMessage {
|
||||
|
||||
@NotNull
|
||||
private final BelowName feature;
|
||||
@NotNull private final BelowName feature;
|
||||
@NotNull private final UUID playerId;
|
||||
private final int value;
|
||||
@NotNull private final String fancyValue;
|
||||
|
||||
private UUID playerId;
|
||||
private int value;
|
||||
private String fancyValue;
|
||||
/**
|
||||
* Creates new instance and reads data from byte input.
|
||||
*
|
||||
* @param in
|
||||
* Input stream to read from
|
||||
* @param feature
|
||||
* Feature instance to use for processing
|
||||
*/
|
||||
public BelowNameUpdateProxyPlayer(@NotNull ByteArrayDataInput in, @NotNull BelowName feature) {
|
||||
this.feature = feature;
|
||||
playerId = readUUID(in);
|
||||
value = in.readInt();
|
||||
fancyValue = in.readUTF();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public ThreadExecutor getCustomThread() {
|
||||
@@ -40,34 +52,20 @@ public class BelowNameUpdateProxyPlayer extends ProxyMessage {
|
||||
out.writeUTF(fancyValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(@NotNull ByteArrayDataInput in) {
|
||||
playerId = readUUID(in);
|
||||
value = in.readInt();
|
||||
fancyValue = in.readUTF();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(@NotNull ProxySupport proxySupport) {
|
||||
ProxyPlayer target = proxySupport.getProxyPlayers().get(playerId);
|
||||
if (target == null) {
|
||||
TAB.getInstance().getErrorManager().printError("Unable to process Belowname objective update of proxy player " + playerId + ", because no such player exists", null);
|
||||
unknownPlayer(playerId.toString(), "belowname objective update");
|
||||
QueuedData data = proxySupport.getQueuedData().computeIfAbsent(playerId, k -> new QueuedData());
|
||||
data.setBelowNameNumber(value);
|
||||
data.setBelowNameFancy(feature.getCache().get(fancyValue));
|
||||
return;
|
||||
}
|
||||
if (target.getBelowNameFancy() == null) {
|
||||
TAB.getInstance().debug("Processing belowname objective join of proxy player " + target.getName());
|
||||
}
|
||||
target.setBelowNameNumber(value);
|
||||
target.setBelowNameFancy(feature.getCache().get(fancyValue));
|
||||
for (TabPlayer viewer : feature.getOnlinePlayers().getPlayers()) {
|
||||
if (viewer.belowNameData.disabled.get()) continue;
|
||||
viewer.getScoreboard().setScore(
|
||||
BelowName.OBJECTIVE_NAME,
|
||||
target.getNickname(),
|
||||
target.getBelowNameNumber(),
|
||||
null, // Unused by this objective slot
|
||||
target.getBelowNameFancy()
|
||||
);
|
||||
if (target.getConnectionState() == ProxyPlayer.ConnectionState.CONNECTED) {
|
||||
feature.updatePlayer(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
+10
-10
@@ -17,9 +17,7 @@ import me.neznamy.tab.shared.util.PerformanceUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Feature handler for global PlayerList feature.
|
||||
@@ -249,7 +247,7 @@ public class GlobalPlayerList extends RefreshableFeature implements JoinListener
|
||||
public void onGameModeChange(@NotNull TabPlayer player) {
|
||||
for (TabPlayer viewer : onlinePlayers.getPlayers()) {
|
||||
if (!player.server.equals(viewer.server)) {
|
||||
viewer.getTabList().updateGameMode(player.getTablistId(), configuration.isOthersAsSpectators() ? 3 : player.getGamemode());
|
||||
viewer.getTabList().updateGameMode(player, configuration.isOthersAsSpectators() ? 3 : player.getGamemode());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -284,7 +282,7 @@ public class GlobalPlayerList extends RefreshableFeature implements JoinListener
|
||||
//player ping changed, must manually update latency for players on other servers
|
||||
for (TabPlayer viewer : onlinePlayers.getPlayers()) {
|
||||
if (viewer.globalPlayerListData.serverGroup == refreshed.globalPlayerListData.serverGroup && !refreshed.server.equals(viewer.server)) {
|
||||
viewer.getTabList().updateLatency(refreshed.getTablistId(), refreshed.getPing());
|
||||
viewer.getTabList().updateLatency(refreshed, refreshed.getPing());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -292,7 +290,7 @@ public class GlobalPlayerList extends RefreshableFeature implements JoinListener
|
||||
private boolean shouldSee(@NotNull TabPlayer viewer, @NotNull ProxyPlayer target) {
|
||||
if (target.isVanished() && !viewer.hasPermission(TabConstants.Permission.SEE_VANISHED)) return false;
|
||||
// Do not show duplicate player that will be removed in a sec
|
||||
if (TAB.getInstance().isPlayerConnected(target.getUniqueId())) return false;
|
||||
if (TAB.getInstance().isPlayerConnected(target.getTablistId())) return false;
|
||||
if (viewer.globalPlayerListData.onSpyServer) return true;
|
||||
return viewer.globalPlayerListData.serverGroup == target.serverGroup;
|
||||
}
|
||||
@@ -319,16 +317,18 @@ public class GlobalPlayerList extends RefreshableFeature implements JoinListener
|
||||
if (shouldSee(viewer, player)) {
|
||||
viewer.getTabList().addEntry(player.asEntry());
|
||||
} else {
|
||||
viewer.getTabList().removeEntry(player.getUniqueId());
|
||||
viewer.getTabList().removeEntry(player.getTablistId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onQuit(@NotNull ProxyPlayer player) {
|
||||
TabPlayer connected = TAB.getInstance().getPlayer(player.getUniqueId());
|
||||
for (TabPlayer viewer : onlinePlayers.getPlayers()) {
|
||||
if (!player.server.equals(viewer.server)) {
|
||||
viewer.getTabList().removeEntry(player.getUniqueId());
|
||||
// Make sure to not remove player if they are connected already and added into tablist by the server
|
||||
if (!player.server.equals(viewer.server) && (connected == null || !shouldSee(viewer, connected))) {
|
||||
viewer.getTabList().removeEntry(player.getTablistId());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -338,7 +338,7 @@ public class GlobalPlayerList extends RefreshableFeature implements JoinListener
|
||||
if (player.isVanished()) {
|
||||
for (TabPlayer all : onlinePlayers.getPlayers()) {
|
||||
if (!shouldSee(all, player)) {
|
||||
all.getTabList().removeEntry(player.getUniqueId());
|
||||
all.getTabList().removeEntry(player.getTablistId());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package me.neznamy.tab.shared.features.header;
|
||||
|
||||
import lombok.Getter;
|
||||
import me.neznamy.chat.component.TabComponent;
|
||||
import me.neznamy.tab.api.tablist.HeaderFooterManager;
|
||||
import me.neznamy.tab.shared.Property;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.shared.TabConstants;
|
||||
import me.neznamy.chat.component.SimpleTextComponent;
|
||||
import me.neznamy.tab.shared.cpu.ThreadExecutor;
|
||||
import me.neznamy.tab.shared.features.header.HeaderFooterConfiguration.HeaderFooterPair;
|
||||
import me.neznamy.tab.shared.features.types.*;
|
||||
@@ -124,7 +124,7 @@ public class HeaderFooter extends RefreshableFeature implements HeaderFooterMana
|
||||
*/
|
||||
public void onDisableConditionChange(TabPlayer p, boolean disabledNow) {
|
||||
if (disabledNow) {
|
||||
p.getTabList().setPlayerListHeaderFooter(SimpleTextComponent.EMPTY, SimpleTextComponent.EMPTY);
|
||||
p.getTabList().setPlayerListHeaderFooter(TabComponent.empty(), TabComponent.empty());
|
||||
} else {
|
||||
sendHeaderFooter(p, p.headerFooterData.header.get(), p.headerFooterData.footer.get());
|
||||
}
|
||||
|
||||
+1
-3
@@ -68,9 +68,7 @@ public abstract class NettyPipelineInjector extends PipelineInjector {
|
||||
if (player.getVersion().getMinorVersion() >= 8) {
|
||||
((TrackedTabList<?>)player.getTabList()).onPacketSend(packet);
|
||||
}
|
||||
if (((SafeScoreboard<?>)player.getScoreboard()).isAntiOverrideTeams() || ((SafeScoreboard<?>)player.getScoreboard()).isAntiOverrideScoreboard()) {
|
||||
((SafeScoreboard<?>)player.getScoreboard()).onPacketSend(packet);
|
||||
}
|
||||
((SafeScoreboard<?>)player.getScoreboard()).onPacketSend(packet);
|
||||
} catch (Throwable e) {
|
||||
TAB.getInstance().getErrorManager().printError("An error occurred when reading packets", e);
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ public class LayoutManagerImpl extends RefreshableFeature implements LayoutManag
|
||||
// Unformat original entries for players who can see a layout to avoid spaces due to unparsed placeholders and such
|
||||
if (highest == null) return;
|
||||
for (TabPlayer all : TAB.getInstance().getOnlinePlayers()) {
|
||||
p.getTabList().updateDisplayName(all.getTablistId(), null);
|
||||
p.getTabList().updateDisplayName(all, null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package me.neznamy.tab.shared.features.layout;
|
||||
|
||||
import lombok.Getter;
|
||||
import me.neznamy.chat.component.SimpleTextComponent;
|
||||
import me.neznamy.chat.component.TabComponent;
|
||||
import me.neznamy.tab.shared.features.layout.LayoutConfiguration.LayoutDefinition.GroupPattern;
|
||||
import me.neznamy.tab.shared.placeholders.conditions.Condition;
|
||||
import me.neznamy.tab.shared.platform.TabList;
|
||||
@@ -55,7 +55,7 @@ public class LayoutView {
|
||||
true,
|
||||
manager.getConfiguration().getEmptySlotPing(),
|
||||
0,
|
||||
SimpleTextComponent.EMPTY,
|
||||
TabComponent.empty(),
|
||||
Integer.MAX_VALUE - manager.getConfiguration().getDirection().translateSlot(slot),
|
||||
true
|
||||
));
|
||||
|
||||
@@ -2,7 +2,7 @@ package me.neznamy.tab.shared.features.layout;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import me.neznamy.chat.component.SimpleTextComponent;
|
||||
import me.neznamy.chat.component.TabComponent;
|
||||
import me.neznamy.tab.shared.features.playerlist.PlayerList;
|
||||
import me.neznamy.tab.shared.platform.TabList;
|
||||
import me.neznamy.tab.shared.platform.TabPlayer;
|
||||
@@ -44,7 +44,7 @@ public class PlayerSlot {
|
||||
true,
|
||||
layout.getManager().getPingSpoof() != null ? layout.getManager().getPingSpoof().getConfiguration().getValue() : player.getPing(),
|
||||
0,
|
||||
playerList == null || player.tablistData.disabled.get() ? SimpleTextComponent.text(player.getName()) : playerList.getTabFormat(player, viewer),
|
||||
playerList == null || player.tablistData.disabled.get() ? TabComponent.legacyText(player.getName()) : playerList.getTabFormat(player, viewer),
|
||||
Integer.MAX_VALUE - layout.getManager().getConfiguration().getDirection().translateSlot(slot),
|
||||
true
|
||||
);
|
||||
@@ -56,7 +56,7 @@ public class PlayerSlot {
|
||||
true,
|
||||
layout.getManager().getConfiguration().getEmptySlotPing(),
|
||||
0,
|
||||
SimpleTextComponent.text(text),
|
||||
TabComponent.legacyText(text),
|
||||
Integer.MAX_VALUE - layout.getManager().getConfiguration().getDirection().translateSlot(slot),
|
||||
true
|
||||
);
|
||||
|
||||
@@ -13,6 +13,7 @@ import me.neznamy.tab.shared.features.proxy.ProxyPlayer;
|
||||
import me.neznamy.tab.shared.features.proxy.ProxySupport;
|
||||
import me.neznamy.tab.shared.features.types.*;
|
||||
import me.neznamy.tab.shared.placeholders.conditions.Condition;
|
||||
import me.neznamy.tab.shared.platform.Scoreboard;
|
||||
import me.neznamy.tab.shared.platform.Scoreboard.CollisionRule;
|
||||
import me.neznamy.tab.shared.platform.Scoreboard.NameVisibility;
|
||||
import me.neznamy.tab.shared.platform.TabPlayer;
|
||||
@@ -51,7 +52,7 @@ public class NameTag extends RefreshableFeature implements NameTagManager, JoinL
|
||||
TAB.getInstance().getFeatureManager().registerFeature(TabConstants.Feature.NAME_TAGS + "-Condition", disableChecker);
|
||||
TAB.getInstance().getFeatureManager().registerFeature(TabConstants.Feature.NAME_TAGS_VISIBILITY, new VisibilityRefresher(this));
|
||||
if (proxy != null) {
|
||||
proxy.registerMessage("teams", NameTagUpdateProxyPlayer.class, () -> new NameTagUpdateProxyPlayer(this));
|
||||
proxy.registerMessage(NameTagUpdateProxyPlayer.class, in -> new NameTagUpdateProxyPlayer(in, this));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,7 +62,6 @@ public class NameTag extends RefreshableFeature implements NameTagManager, JoinL
|
||||
TAB.getInstance().getFeatureManager().registerFeature(TabConstants.Feature.NAME_TAGS_COLLISION, collisionManager);
|
||||
collisionManager.load();
|
||||
for (TabPlayer all : onlinePlayers.getPlayers()) {
|
||||
((SafeScoreboard<?>)all.getScoreboard()).setAntiOverrideTeams(configuration.isAntiOverride());
|
||||
loadProperties(all);
|
||||
if (configuration.isInvisibleNameTags()) {
|
||||
all.teamData.hideNametag(NameTagInvisibilityReason.MEETING_CONFIGURED_CONDITION);
|
||||
@@ -73,7 +73,6 @@ public class NameTag extends RefreshableFeature implements NameTagManager, JoinL
|
||||
}
|
||||
TAB.getInstance().getPlaceholderManager().getTabExpansion().setNameTagVisibility(all, true);
|
||||
if (proxy != null) {
|
||||
TAB.getInstance().debug("Sending nametag join (on load) of proxy player " + all.getName());
|
||||
proxy.sendMessage(new NameTagUpdateProxyPlayer(
|
||||
this,
|
||||
all.getTablistId(),
|
||||
@@ -125,7 +124,6 @@ public class NameTag extends RefreshableFeature implements NameTagManager, JoinL
|
||||
@Override
|
||||
public void onJoin(@NotNull TabPlayer connectedPlayer) {
|
||||
onlinePlayers.addPlayer(connectedPlayer);
|
||||
((SafeScoreboard<?>)connectedPlayer.getScoreboard()).setAntiOverrideTeams(configuration.isAntiOverride());
|
||||
loadProperties(connectedPlayer);
|
||||
if (configuration.isInvisibleNameTags()) {
|
||||
connectedPlayer.teamData.hideNametag(NameTagInvisibilityReason.MEETING_CONFIGURED_CONDITION);
|
||||
@@ -144,6 +142,15 @@ public class NameTag extends RefreshableFeature implements NameTagManager, JoinL
|
||||
}
|
||||
}
|
||||
TAB.getInstance().getPlaceholderManager().getTabExpansion().setNameTagVisibility(connectedPlayer, true);
|
||||
if (proxy != null) {
|
||||
ProxyPlayer proxyPlayer = proxy.getProxyPlayers().get(connectedPlayer.getUniqueId());
|
||||
if (proxyPlayer != null && proxyPlayer.getTeamName() != null) {
|
||||
for (TabPlayer viewer : onlinePlayers.getPlayers()) {
|
||||
((SafeScoreboard<?>)viewer.getScoreboard()).unregisterTeamSafe(proxyPlayer.getTeamName());
|
||||
}
|
||||
proxyPlayer.setTeamName(null);
|
||||
}
|
||||
}
|
||||
if (disableChecker.isDisableConditionMet(connectedPlayer)) {
|
||||
connectedPlayer.teamData.disabled.set(true);
|
||||
return;
|
||||
@@ -151,20 +158,18 @@ public class NameTag extends RefreshableFeature implements NameTagManager, JoinL
|
||||
registerTeam(connectedPlayer);
|
||||
if (proxy != null) {
|
||||
for (ProxyPlayer proxied : proxy.getProxyPlayers().values()) {
|
||||
if (proxied.getTagPrefix() == null) continue; // This proxy player is not loaded yet
|
||||
TabComponent prefix = cache.get(proxied.getTagPrefix());
|
||||
if (proxied.getTeamName() == null) continue; // This proxy player is not loaded yet
|
||||
connectedPlayer.getScoreboard().registerTeam(
|
||||
proxied.getTeamName(),
|
||||
prefix,
|
||||
cache.get(proxied.getTagSuffix()),
|
||||
proxied.getTagPrefix(),
|
||||
proxied.getTagSuffix(),
|
||||
proxied.getNameVisibility(),
|
||||
CollisionRule.ALWAYS,
|
||||
Collections.singletonList(proxied.getNickname()),
|
||||
2,
|
||||
prefix.getLastColor()
|
||||
proxied.getTagPrefix().getLastColor()
|
||||
);
|
||||
}
|
||||
TAB.getInstance().debug("Sending nametag join of proxy player " + connectedPlayer.getName());
|
||||
proxy.sendMessage(new NameTagUpdateProxyPlayer(
|
||||
this,
|
||||
connectedPlayer.getTablistId(),
|
||||
@@ -268,7 +273,6 @@ public class NameTag extends RefreshableFeature implements NameTagManager, JoinL
|
||||
);
|
||||
}
|
||||
if (proxy != null) {
|
||||
TAB.getInstance().debug("Sending nametag update (prefix / suffix) of proxy player " + player.getName());
|
||||
proxy.sendMessage(new NameTagUpdateProxyPlayer(
|
||||
this,
|
||||
player.getTablistId(),
|
||||
@@ -319,7 +323,6 @@ public class NameTag extends RefreshableFeature implements NameTagManager, JoinL
|
||||
);
|
||||
}
|
||||
if (proxy != null) {
|
||||
TAB.getInstance().debug("Sending nametag update (visibility) of proxy player " + player.getName());
|
||||
proxy.sendMessage(new NameTagUpdateProxyPlayer(
|
||||
this,
|
||||
player.getTablistId(),
|
||||
@@ -405,7 +408,6 @@ public class NameTag extends RefreshableFeature implements NameTagManager, JoinL
|
||||
}
|
||||
player.teamData.teamName = newTeamName;
|
||||
if (proxy != null) {
|
||||
TAB.getInstance().debug("Sending nametag update (team name) of proxy player " + player.getName());
|
||||
proxy.sendMessage(new NameTagUpdateProxyPlayer(
|
||||
this,
|
||||
player.getTablistId(),
|
||||
@@ -424,7 +426,6 @@ public class NameTag extends RefreshableFeature implements NameTagManager, JoinL
|
||||
|
||||
@Override
|
||||
public void onProxyLoadRequest() {
|
||||
TAB.getInstance().debug("Sending nametag load of all proxy players as requested by another proxy");
|
||||
for (TabPlayer all : onlinePlayers.getPlayers()) {
|
||||
proxy.sendMessage(new NameTagUpdateProxyPlayer(
|
||||
this,
|
||||
@@ -440,7 +441,7 @@ public class NameTag extends RefreshableFeature implements NameTagManager, JoinL
|
||||
@Override
|
||||
public void onQuit(@NotNull ProxyPlayer player) {
|
||||
if (player.getTeamName() == null) {
|
||||
TAB.getInstance().getErrorManager().printError("Unable to unregister team of proxy player " + player.getName() + " on quit, because team is null", null);
|
||||
// One of the two options is being forcibly unregistered when real player joined
|
||||
return;
|
||||
}
|
||||
for (TabPlayer viewer : onlinePlayers.getPlayers()) {
|
||||
@@ -448,6 +449,23 @@ public class NameTag extends RefreshableFeature implements NameTagManager, JoinL
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onJoin(@NotNull ProxyPlayer player) {
|
||||
if (player.getTeamName() == null) return; // Player not loaded yet
|
||||
for (TabPlayer viewer : onlinePlayers.getPlayers()) {
|
||||
viewer.getScoreboard().registerTeam(
|
||||
player.getTeamName(),
|
||||
player.getTagPrefix(),
|
||||
player.getTagSuffix(),
|
||||
player.getNameVisibility(),
|
||||
Scoreboard.CollisionRule.ALWAYS,
|
||||
Collections.singletonList(player.getNickname()),
|
||||
2,
|
||||
player.getTagPrefix().getLastColor()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public void hideNameTag(@NonNull TabPlayer player, @NonNull NameTagInvisibilityReason reason, @NonNull String cpuReason,
|
||||
boolean sendMessage) {
|
||||
ensureActive();
|
||||
|
||||
+63
-53
@@ -3,16 +3,17 @@ package me.neznamy.tab.shared.features.nametags;
|
||||
import com.google.common.io.ByteArrayDataInput;
|
||||
import com.google.common.io.ByteArrayDataOutput;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import me.neznamy.chat.component.TabComponent;
|
||||
import lombok.ToString;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.shared.cpu.ThreadExecutor;
|
||||
import me.neznamy.tab.shared.features.proxy.ProxyPlayer;
|
||||
import me.neznamy.tab.shared.features.proxy.ProxySupport;
|
||||
import me.neznamy.tab.shared.features.proxy.QueuedData;
|
||||
import me.neznamy.tab.shared.features.proxy.message.ProxyMessage;
|
||||
import me.neznamy.tab.shared.platform.Scoreboard;
|
||||
import me.neznamy.tab.shared.platform.TabPlayer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.UUID;
|
||||
@@ -20,16 +21,33 @@ import java.util.UUID;
|
||||
/**
|
||||
* Proxy message to update team data of a player.
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@ToString
|
||||
public class NameTagUpdateProxyPlayer extends ProxyMessage {
|
||||
|
||||
@NotNull private final NameTag feature;
|
||||
private UUID playerId;
|
||||
private String teamName;
|
||||
private String prefix;
|
||||
private String suffix;
|
||||
private Scoreboard.NameVisibility nameVisibility;
|
||||
@NotNull private final UUID playerId;
|
||||
@NotNull private final String teamName;
|
||||
@NotNull private final String prefix;
|
||||
@NotNull private final String suffix;
|
||||
@NotNull private final Scoreboard.NameVisibility nameVisibility;
|
||||
|
||||
/**
|
||||
* Creates new instance and reads data from byte input.
|
||||
*
|
||||
* @param in
|
||||
* Input stream to read from
|
||||
* @param feature
|
||||
* Feature instance to use for processing
|
||||
*/
|
||||
public NameTagUpdateProxyPlayer(@NotNull ByteArrayDataInput in, @NotNull NameTag feature) {
|
||||
this.feature = feature;
|
||||
playerId = readUUID(in);
|
||||
teamName = in.readUTF();
|
||||
prefix = in.readUTF();
|
||||
suffix = in.readUTF();
|
||||
nameVisibility = Scoreboard.NameVisibility.getByName(in.readUTF());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public ThreadExecutor getCustomThread() {
|
||||
@@ -45,66 +63,58 @@ public class NameTagUpdateProxyPlayer extends ProxyMessage {
|
||||
out.writeUTF(nameVisibility.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(@NotNull ByteArrayDataInput in) {
|
||||
playerId = readUUID(in);
|
||||
teamName = in.readUTF();
|
||||
prefix = in.readUTF();
|
||||
suffix = in.readUTF();
|
||||
nameVisibility = Scoreboard.NameVisibility.getByName(in.readUTF());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(@NotNull ProxySupport proxySupport) {
|
||||
ProxyPlayer target = proxySupport.getProxyPlayers().get(playerId);
|
||||
if (target == null) {
|
||||
TAB.getInstance().getErrorManager().printError("[Proxy Support] Unable to process nametag update of proxy player " + playerId + ", because no such player exists", null);
|
||||
return;
|
||||
}
|
||||
TAB.getInstance().debug("[Proxy Support] Processing nametag update of proxy player " + target.getName());
|
||||
// Nametag is already being processed by connected player
|
||||
if (TAB.getInstance().isPlayerConnected(target.getUniqueId())) {
|
||||
TAB.getInstance().debug("The player " + target.getName() + " is already connected");
|
||||
unknownPlayer(playerId.toString(), "nametag update update");
|
||||
QueuedData data = proxySupport.getQueuedData().computeIfAbsent(playerId, k -> new QueuedData());
|
||||
data.setTeamName(checkTeamName(null, teamName.substring(0, teamName.length()-1)));
|
||||
data.setTagPrefix(feature.getCache().get(prefix));
|
||||
data.setTagSuffix(feature.getCache().get(suffix));
|
||||
data.setNameVisibility(nameVisibility);
|
||||
return;
|
||||
}
|
||||
String oldTeamName = target.getTeamName();
|
||||
String newTeamName = checkTeamName(target, teamName.substring(0, teamName.length()-1));
|
||||
target.setTeamName(newTeamName);
|
||||
target.setTagPrefix(prefix);
|
||||
target.setTagSuffix(suffix);
|
||||
target.setTagPrefix(feature.getCache().get(prefix));
|
||||
target.setTagSuffix(feature.getCache().get(suffix));
|
||||
target.setNameVisibility(nameVisibility);
|
||||
TabComponent prefixComponent = feature.getCache().get(prefix);
|
||||
if (!newTeamName.equals(oldTeamName)) {
|
||||
for (TabPlayer viewer : feature.getOnlinePlayers().getPlayers()) {
|
||||
if (oldTeamName != null) viewer.getScoreboard().unregisterTeam(oldTeamName);
|
||||
viewer.getScoreboard().registerTeam(
|
||||
newTeamName,
|
||||
prefixComponent,
|
||||
feature.getCache().get(suffix),
|
||||
nameVisibility,
|
||||
Scoreboard.CollisionRule.ALWAYS,
|
||||
Collections.singletonList(target.getNickname()),
|
||||
2,
|
||||
prefixComponent.getLastColor()
|
||||
);
|
||||
}
|
||||
} else {
|
||||
for (TabPlayer viewer : feature.getOnlinePlayers().getPlayers()) {
|
||||
viewer.getScoreboard().updateTeam(
|
||||
oldTeamName,
|
||||
prefixComponent,
|
||||
feature.getCache().get(suffix),
|
||||
nameVisibility,
|
||||
Scoreboard.CollisionRule.ALWAYS,
|
||||
2,
|
||||
prefixComponent.getLastColor()
|
||||
);
|
||||
|
||||
if (target.getConnectionState() == ProxyPlayer.ConnectionState.CONNECTED) {
|
||||
if (!newTeamName.equals(oldTeamName)) {
|
||||
for (TabPlayer viewer : feature.getOnlinePlayers().getPlayers()) {
|
||||
if (oldTeamName != null) viewer.getScoreboard().unregisterTeam(oldTeamName);
|
||||
viewer.getScoreboard().registerTeam(
|
||||
newTeamName,
|
||||
target.getTagPrefix(),
|
||||
target.getTagSuffix(),
|
||||
nameVisibility,
|
||||
Scoreboard.CollisionRule.ALWAYS,
|
||||
Collections.singletonList(target.getNickname()),
|
||||
2,
|
||||
target.getTagPrefix().getLastColor()
|
||||
);
|
||||
}
|
||||
} else {
|
||||
for (TabPlayer viewer : feature.getOnlinePlayers().getPlayers()) {
|
||||
viewer.getScoreboard().updateTeam(
|
||||
oldTeamName,
|
||||
target.getTagPrefix(),
|
||||
target.getTagSuffix(),
|
||||
nameVisibility,
|
||||
Scoreboard.CollisionRule.ALWAYS,
|
||||
2,
|
||||
target.getTagPrefix().getLastColor()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private String checkTeamName(@NotNull ProxyPlayer player, @NotNull String currentName15) {
|
||||
private String checkTeamName(@Nullable ProxyPlayer player, @NotNull String currentName15) {
|
||||
char id = 'A';
|
||||
while (true) {
|
||||
String potentialTeamName = currentName15 + id;
|
||||
|
||||
@@ -16,7 +16,6 @@ public class TeamConfiguration {
|
||||
|
||||
@NotNull private final String enableCollision;
|
||||
private final boolean invisibleNameTags;
|
||||
private final boolean antiOverride;
|
||||
private final boolean canSeeFriendlyInvisibles;
|
||||
@NotNull private final String disableCondition;
|
||||
|
||||
@@ -31,19 +30,12 @@ public class TeamConfiguration {
|
||||
@NotNull
|
||||
public static TeamConfiguration fromSection(@NotNull ConfigurationSection section) {
|
||||
// Check keys
|
||||
section.checkForUnknownKey(Arrays.asList("enabled", "enable-collision", "invisible-nametags", "anti-override", "sorting-types",
|
||||
section.checkForUnknownKey(Arrays.asList("enabled", "enable-collision", "invisible-nametags", "sorting-types",
|
||||
"case-sensitive-sorting", "can-see-friendly-invisibles", "disable-condition"));
|
||||
|
||||
// Check anti-override
|
||||
boolean antiOverride = section.getBoolean("anti-override", true);
|
||||
if (!antiOverride) {
|
||||
section.startupWarn("anti-override for scoreboard-teams is disabled in config. This is usually a mistake. If you notice the feature randomly breaking, enable it back.");
|
||||
}
|
||||
|
||||
return new TeamConfiguration(
|
||||
section.getObject("enable-collision", "true").toString(),
|
||||
section.getBoolean("invisible-nametags", false),
|
||||
antiOverride,
|
||||
section.getBoolean("can-see-friendly-invisibles", false),
|
||||
section.getString("disable-condition", "%world%=disabledworld")
|
||||
);
|
||||
|
||||
@@ -43,15 +43,15 @@ public class PingSpoof extends TabFeature implements JoinListener, LatencyListen
|
||||
@Override
|
||||
public void onJoin(@NotNull TabPlayer connectedPlayer) {
|
||||
for (TabPlayer all : TAB.getInstance().getOnlinePlayers()) {
|
||||
connectedPlayer.getTabList().updateLatency(all.getTablistId(), configuration.getValue());
|
||||
all.getTabList().updateLatency(connectedPlayer.getTablistId(), configuration.getValue());
|
||||
connectedPlayer.getTabList().updateLatency(all, configuration.getValue());
|
||||
all.getTabList().updateLatency(connectedPlayer, configuration.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
private void updateAll(boolean realPing) {
|
||||
for (TabPlayer viewer : TAB.getInstance().getOnlinePlayers()) {
|
||||
for (TabPlayer target : TAB.getInstance().getOnlinePlayers()) {
|
||||
viewer.getTabList().updateLatency(target.getTablistId(), realPing ? target.getPing() : configuration.getValue());
|
||||
viewer.getTabList().updateLatency(target, realPing ? target.getPing() : configuration.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package me.neznamy.tab.shared.features.playerlist;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
import me.neznamy.chat.component.SimpleTextComponent;
|
||||
import me.neznamy.chat.component.TabComponent;
|
||||
import me.neznamy.tab.api.tablist.TabListFormatManager;
|
||||
import me.neznamy.tab.shared.Property;
|
||||
@@ -46,16 +45,13 @@ public class PlayerList extends RefreshableFeature implements TabListFormatManag
|
||||
this.configuration = configuration;
|
||||
disableChecker = new DisableChecker(this, Condition.getCondition(configuration.getDisableCondition()), this::onDisableConditionChange, p -> p.tablistData.disabled);
|
||||
TAB.getInstance().getFeatureManager().registerFeature(TabConstants.Feature.PLAYER_LIST + "-Condition", disableChecker);
|
||||
if (configuration.isAntiOverride()) {
|
||||
TAB.getInstance().getCpu().getTablistEntryCheckThread().repeatTask(new TimedCaughtTask(TAB.getInstance().getCpu(), () -> {
|
||||
for (TabPlayer p : TAB.getInstance().getOnlinePlayers()) {
|
||||
((TrackedTabList<?>)p.getTabList()).checkDisplayNames();
|
||||
}
|
||||
}, getFeatureName(), CpuUsageCategory.ANTI_OVERRIDE_TABLIST_PERIODIC), 500
|
||||
);
|
||||
}
|
||||
TAB.getInstance().getCpu().getTablistEntryCheckThread().repeatTask(new TimedCaughtTask(TAB.getInstance().getCpu(), () -> {
|
||||
for (TabPlayer p : TAB.getInstance().getOnlinePlayers()) {
|
||||
((TrackedTabList<?>)p.getTabList()).checkDisplayNames();
|
||||
}
|
||||
}, getFeatureName(), CpuUsageCategory.ANTI_OVERRIDE_TABLIST_PERIODIC), 500);
|
||||
if (proxy != null) {
|
||||
proxy.registerMessage("tabformat", PlayerListUpdateProxyPlayer.class, () -> new PlayerListUpdateProxyPlayer(this));
|
||||
proxy.registerMessage(PlayerListUpdateProxyPlayer.class, in -> new PlayerListUpdateProxyPlayer(in, this));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,10 +115,10 @@ public class PlayerList extends RefreshableFeature implements TabListFormatManag
|
||||
*/
|
||||
public void updatePlayer(@NotNull TabPlayer player, boolean format) {
|
||||
for (TabPlayer viewer : TAB.getInstance().getOnlinePlayers()) {
|
||||
//if (!viewer.getTabList().containsEntry(player.getTablistId())) continue;
|
||||
if (!viewer.canSee(player)) continue;
|
||||
UUID tablistId = getTablistUUID(player, viewer);
|
||||
viewer.getTabList().updateDisplayName(tablistId, format ? getTabFormat(player, viewer) :
|
||||
tablistId.getMostSignificantBits() == 0 ? SimpleTextComponent.text(player.getName()) : null);
|
||||
tablistId.getMostSignificantBits() == 0 ? TabComponent.legacyText(player.getName()) : null);
|
||||
}
|
||||
if (proxy != null) proxy.sendMessage(new PlayerListUpdateProxyPlayer(this, player.getUniqueId(), player.getName(), player.tablistData.prefix.get() +
|
||||
player.tablistData.name.get() + player.tablistData.suffix.get()));
|
||||
@@ -150,11 +146,7 @@ public class PlayerList extends RefreshableFeature implements TabListFormatManag
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
if (proxy != null) {
|
||||
TAB.getInstance().debug("[Proxy Support] Sending tablist update of all players on load");
|
||||
}
|
||||
for (TabPlayer all : TAB.getInstance().getOnlinePlayers()) {
|
||||
((TrackedTabList<?>)all.getTabList()).setAntiOverride(configuration.isAntiOverride());
|
||||
loadProperties(all);
|
||||
if (disableChecker.isDisableConditionMet(all)) {
|
||||
all.tablistData.disabled.set(true);
|
||||
@@ -166,7 +158,7 @@ public class PlayerList extends RefreshableFeature implements TabListFormatManag
|
||||
for (TabPlayer viewer : TAB.getInstance().getOnlinePlayers()) {
|
||||
for (TabPlayer target : TAB.getInstance().getOnlinePlayers()) {
|
||||
if (target.tablistData.disabled.get()) continue;
|
||||
//if (!viewer.getTabList().containsEntry(target.getTablistId())) continue;
|
||||
if (!viewer.canSee(target)) continue;
|
||||
viewer.getTabList().updateDisplayName(getTablistUUID(target, viewer), getTabFormat(target, viewer));
|
||||
}
|
||||
}
|
||||
@@ -177,7 +169,7 @@ public class PlayerList extends RefreshableFeature implements TabListFormatManag
|
||||
for (TabPlayer viewer : TAB.getInstance().getOnlinePlayers()) {
|
||||
for (TabPlayer target : TAB.getInstance().getOnlinePlayers()) {
|
||||
if (target.tablistData.disabled.get()) continue;
|
||||
//if (!viewer.getTabList().containsEntry(target.getTablistId())) continue;
|
||||
if (!viewer.canSee(target)) continue;
|
||||
viewer.getTabList().updateDisplayName(getTablistUUID(target, target), null);
|
||||
}
|
||||
}
|
||||
@@ -189,18 +181,14 @@ public class PlayerList extends RefreshableFeature implements TabListFormatManag
|
||||
if (TAB.getInstance().getFeatureManager().isFeatureEnabled(TabConstants.Feature.PIPELINE_INJECTION)) return;
|
||||
TAB.getInstance().getCpu().getProcessingThread().executeLater(new TimedCaughtTask(TAB.getInstance().getCpu(), () -> {
|
||||
for (TabPlayer all : TAB.getInstance().getOnlinePlayers()) {
|
||||
if (!all.tablistData.disabled.get()
|
||||
//&& p.getTabList().containsEntry(all.getTablistId())
|
||||
)
|
||||
if (!all.tablistData.disabled.get() && p.canSee(all))
|
||||
p.getTabList().updateDisplayName(getTablistUUID(all, p), getTabFormat(all, p));
|
||||
if (all != p && !p.tablistData.disabled.get()
|
||||
//&& all.getTabList().containsEntry(p.getTablistId())
|
||||
)
|
||||
if (all != p && !p.tablistData.disabled.get() && all.canSee(p))
|
||||
all.getTabList().updateDisplayName(getTablistUUID(p, all), getTabFormat(p, all));
|
||||
}
|
||||
if (proxy != null) {
|
||||
for (ProxyPlayer proxied : proxy.getProxyPlayers().values()) {
|
||||
p.getTabList().updateDisplayName(proxied.getUniqueId(), proxied.getTabFormat());
|
||||
p.getTabList().updateDisplayName(proxied.getTablistId(), proxied.getTabFormat());
|
||||
}
|
||||
}
|
||||
}, getFeatureName(), CpuUsageCategory.PLAYER_JOIN), 300);
|
||||
@@ -257,7 +245,6 @@ public class PlayerList extends RefreshableFeature implements TabListFormatManag
|
||||
|
||||
@Override
|
||||
public void onJoin(@NotNull TabPlayer connectedPlayer) {
|
||||
((TrackedTabList<?>)connectedPlayer.getTabList()).setAntiOverride(configuration.isAntiOverride());
|
||||
loadProperties(connectedPlayer);
|
||||
if (disableChecker.isDisableConditionMet(connectedPlayer)) {
|
||||
connectedPlayer.tablistData.disabled.set(true);
|
||||
@@ -268,16 +255,17 @@ public class PlayerList extends RefreshableFeature implements TabListFormatManag
|
||||
for (TabPlayer all : TAB.getInstance().getOnlinePlayers()) {
|
||||
if (all == connectedPlayer) continue; // Already updated above
|
||||
if (all.tablistData.disabled.get()) continue;
|
||||
if (!connectedPlayer.canSee(all)) continue;
|
||||
connectedPlayer.getTabList().updateDisplayName(getTablistUUID(all, connectedPlayer), getTabFormat(all, connectedPlayer));
|
||||
}
|
||||
if (proxy != null) {
|
||||
for (ProxyPlayer proxied : proxy.getProxyPlayers().values()) {
|
||||
connectedPlayer.getTabList().updateDisplayName(proxied.getUniqueId(), proxied.getTabFormat());
|
||||
connectedPlayer.getTabList().updateDisplayName(proxied.getTablistId(), proxied.getTabFormat());
|
||||
}
|
||||
}
|
||||
};
|
||||
//add packet might be sent after tab's refresh packet, resending again when anti-override is disabled
|
||||
if (!configuration.isAntiOverride() || !TAB.getInstance().getFeatureManager().isFeatureEnabled(TabConstants.Feature.PIPELINE_INJECTION)) {
|
||||
if (!TAB.getInstance().getFeatureManager().isFeatureEnabled(TabConstants.Feature.PIPELINE_INJECTION)) {
|
||||
TAB.getInstance().getCpu().getProcessingThread().executeLater(new TimedCaughtTask(TAB.getInstance().getCpu(),
|
||||
r, getFeatureName(), CpuUsageCategory.PLAYER_JOIN), 300);
|
||||
} else {
|
||||
@@ -289,7 +277,7 @@ public class PlayerList extends RefreshableFeature implements TabListFormatManag
|
||||
public void onVanishStatusChange(@NotNull TabPlayer player) {
|
||||
if (player.isVanished() || player.tablistData.disabled.get()) return;
|
||||
for (TabPlayer viewer : TAB.getInstance().getOnlinePlayers()) {
|
||||
//if (!viewer.getTabList().containsEntry(player.getTablistId())) continue;
|
||||
if (!viewer.canSee(player)) continue;
|
||||
viewer.getTabList().updateDisplayName(player.getTablistId(), getTabFormat(player, viewer));
|
||||
}
|
||||
}
|
||||
@@ -373,7 +361,6 @@ public class PlayerList extends RefreshableFeature implements TabListFormatManag
|
||||
|
||||
@Override
|
||||
public void onProxyLoadRequest() {
|
||||
TAB.getInstance().debug("[Proxy Support] Sending tablist update of all players as requested by another proxy");
|
||||
for (TabPlayer all : TAB.getInstance().getOnlinePlayers()) {
|
||||
proxy.sendMessage(new PlayerListUpdateProxyPlayer(this, all.getTablistId(), all.getName(), all.tablistData.prefix.get() + all.tablistData.name.get() + all.tablistData.suffix.get()));
|
||||
}
|
||||
@@ -381,9 +368,19 @@ public class PlayerList extends RefreshableFeature implements TabListFormatManag
|
||||
|
||||
@Override
|
||||
public void onVanishStatusChange(@NotNull ProxyPlayer player) {
|
||||
updatePlayer(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onJoin(@NotNull ProxyPlayer player) {
|
||||
updatePlayer(player);
|
||||
}
|
||||
|
||||
public void updatePlayer(@NotNull ProxyPlayer player) {
|
||||
if (player.isVanished()) return;
|
||||
if (player.getTabFormat() == null) return; // Player not loaded yet
|
||||
for (TabPlayer viewer : TAB.getInstance().getOnlinePlayers()) {
|
||||
viewer.getTabList().updateDisplayName(player.getUniqueId(), player.getTabFormat());
|
||||
viewer.getTabList().updateDisplayName(player.getTablistId(), player.getTabFormat());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+29
-22
@@ -3,12 +3,11 @@ package me.neznamy.tab.shared.features.playerlist;
|
||||
import com.google.common.io.ByteArrayDataInput;
|
||||
import com.google.common.io.ByteArrayDataOutput;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import lombok.ToString;
|
||||
import me.neznamy.tab.shared.features.proxy.ProxyPlayer;
|
||||
import me.neznamy.tab.shared.features.proxy.ProxySupport;
|
||||
import me.neznamy.tab.shared.features.proxy.QueuedData;
|
||||
import me.neznamy.tab.shared.features.proxy.message.ProxyMessage;
|
||||
import me.neznamy.tab.shared.platform.TabPlayer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.UUID;
|
||||
@@ -16,41 +15,49 @@ import java.util.UUID;
|
||||
/**
|
||||
* Proxy message to update tablist format of a player.
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@ToString
|
||||
public class PlayerListUpdateProxyPlayer extends ProxyMessage {
|
||||
|
||||
private final PlayerList feature;
|
||||
private UUID playerId;
|
||||
private String player;
|
||||
private String format;
|
||||
@NotNull private final PlayerList feature;
|
||||
@NotNull private final UUID playerId;
|
||||
@NotNull private final String player;
|
||||
@NotNull private final String format;
|
||||
|
||||
@Override
|
||||
public void write(@NotNull ByteArrayDataOutput out) {
|
||||
TAB.getInstance().debug("[Proxy Support] Sending proxy message to update tablist format of player " + player + " to " + format);
|
||||
writeUUID(out, playerId);
|
||||
out.writeUTF(player);
|
||||
out.writeUTF(format);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(@NotNull ByteArrayDataInput in) {
|
||||
/**
|
||||
* Creates new instance and reads data from byte input.
|
||||
*
|
||||
* @param in
|
||||
* Input stream to read from
|
||||
* @param feature
|
||||
* Feature instance to use for processing
|
||||
*/
|
||||
public PlayerListUpdateProxyPlayer(@NotNull ByteArrayDataInput in, @NotNull PlayerList feature) {
|
||||
this.feature = feature;
|
||||
playerId = readUUID(in);
|
||||
player = in.readUTF();
|
||||
format = in.readUTF();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(@NotNull ByteArrayDataOutput out) {
|
||||
writeUUID(out, playerId);
|
||||
out.writeUTF(player);
|
||||
out.writeUTF(format);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(@NotNull ProxySupport proxySupport) {
|
||||
ProxyPlayer target = proxySupport.getProxyPlayers().get(playerId);
|
||||
if (target == null) {
|
||||
TAB.getInstance().getErrorManager().printError("[Proxy Support] Unable to process tablist format update of proxy player " + player + ", because no such player exists", null);
|
||||
unknownPlayer(playerId.toString(), "tablist format update");
|
||||
QueuedData data = proxySupport.getQueuedData().computeIfAbsent(playerId, k -> new QueuedData());
|
||||
data.setTabFormat(feature.getCache().get(format));
|
||||
return;
|
||||
}
|
||||
TAB.getInstance().debug("[Proxy Support] Processing tablist formatting update of proxy player " + player + " to " + format);
|
||||
target.setTabFormat(feature.getCache().get(format));
|
||||
for (TabPlayer viewer : TAB.getInstance().getOnlinePlayers()) {
|
||||
viewer.getTabList().updateDisplayName(target.getUniqueId(), target.getTabFormat());
|
||||
if (target.getConnectionState() == ProxyPlayer.ConnectionState.CONNECTED) {
|
||||
feature.updatePlayer(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
-12
@@ -2,7 +2,6 @@ package me.neznamy.tab.shared.features.playerlist;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.shared.config.file.ConfigurationSection;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@@ -15,7 +14,6 @@ import java.util.Arrays;
|
||||
@RequiredArgsConstructor
|
||||
public class TablistFormattingConfiguration {
|
||||
|
||||
private final boolean antiOverride;
|
||||
@NotNull private final String disableCondition;
|
||||
|
||||
/**
|
||||
@@ -29,15 +27,8 @@ public class TablistFormattingConfiguration {
|
||||
@NotNull
|
||||
public static TablistFormattingConfiguration fromSection(@NotNull ConfigurationSection section) {
|
||||
// Check keys
|
||||
section.checkForUnknownKey(Arrays.asList("enabled", "anti-override", "disable-condition"));
|
||||
|
||||
// Check anti-override
|
||||
boolean antiOverride = section.getBoolean("anti-override", true);
|
||||
if (!antiOverride) {
|
||||
TAB.getInstance().getConfigHelper().startup().startupWarn("anti-override for tablist-name-formatting is disabled in config. " +
|
||||
"This is usually a mistake. If you notice the feature randomly breaking, enable it back.");
|
||||
}
|
||||
|
||||
return new TablistFormattingConfiguration(antiOverride, section.getString("disable-condition", "%world%=disabledworld"));
|
||||
section.checkForUnknownKey(Arrays.asList("enabled", "disable-condition"));
|
||||
|
||||
return new TablistFormattingConfiguration(section.getString("disable-condition", "%world%=disabledworld"));
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
package me.neznamy.tab.shared.features.playerlistobjective;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import me.neznamy.chat.component.SimpleTextComponent;
|
||||
import me.neznamy.chat.component.TabComponent;
|
||||
import me.neznamy.tab.shared.cpu.ThreadExecutor;
|
||||
import me.neznamy.tab.shared.features.types.CustomThreaded;
|
||||
import me.neznamy.tab.shared.features.types.RefreshableFeature;
|
||||
@@ -36,7 +36,7 @@ public class PlayerlistObjectiveTitleRefresher extends RefreshableFeature implem
|
||||
YellowNumber.OBJECTIVE_NAME,
|
||||
feature.getCache().get(refreshed.playerlistObjectiveData.title.updateAndGet()),
|
||||
feature.getConfiguration().getHealthDisplay(),
|
||||
SimpleTextComponent.EMPTY
|
||||
TabComponent.empty()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Loaded 100 of 125 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user