Compare commits

...
77 Commits
Author SHA1 Message Date
NEZNAMY 900ae83028 3.0.1 2021-12-11 12:11:58 +01:00
NEZNAMY 2c09db25b7 Merge pull request #432 from LeonMangler/patch-1
Load TAB after PremiumVanish
2021-12-11 12:10:26 +01:00
NEZNAMY 004e53fa29 Merge pull request #437 from Tanguygab/master
fix NPE when executing scoreboard cmd from console
2021-12-11 12:10:01 +01:00
NEZNAMY e285b143d5 3.0.0-pre3 2021-12-11 00:15:44 +01:00
NEZNAMY f78eb0ffed add API to change group temporarily 2021-12-11 00:14:13 +01:00
NEZNAMY 4d761e1d6e allow decimals in sorting by placeholder 2021-12-11 00:04:20 +01:00
NEZNAMY 4a8c975319 fix startup on bungeecord when assigning groups by permissions AND using bukkit permission manager 2021-12-10 23:45:55 +01:00
NEZNAMY fe56b7ed2d add LP group event listener as well & fix refreshing when assigning by permissions 2021-12-10 23:21:40 +01:00
NEZNAMY 5a74654807 fix scoreboard being enabled by default when converting config 2021-12-10 22:16:08 +01:00
NEZNAMY 533ce4a529 remove unused import 2021-12-10 20:55:19 +01:00
Tanguygab 4ea3780114 fix NPE when executing cmd from console 2021-12-10 19:36:45 +01:00
NEZNAMY 0d229ee26c do not send objective changes before they are registered 2021-12-10 18:25:56 +01:00
NEZNAMY 29079ecad5 add 1.18.1 to recognized versions 2021-12-10 16:01:21 +01:00
NEZNAMY ea88401a58 fix NPE when placeholder returns null 2021-12-10 15:25:17 +01:00
NEZNAMY 298cef4d1f fix startup error if replacement value is null 2021-12-10 15:24:45 +01:00
NEZNAMY a51e9495de add player load status checks to other placeholder types as well 2021-12-10 15:12:43 +01:00
NEZNAMY eead8ca1e2 attempt to avoid rare concurrent modification 2021-12-10 15:11:39 +01:00
NEZNAMY a30712bc38 unregister on bungeecord as well to avoid issues with new bukkit-focused check 2021-12-10 14:56:06 +01:00
NEZNAMY 07b443fb21 actually fixed the error 2021-12-10 14:54:23 +01:00
NEZNAMY 61d927305c add very likely useless check to try to prevent errors 2021-12-10 13:24:29 +01:00
NEZNAMY 8f21c2f27d fix mohist (again) 2021-12-09 22:34:20 +01:00
NEZNAMY 9fcf76e0c4 3.0.1-pre2 2021-12-09 14:53:16 +01:00
NEZNAMY 773afe2fb5 fix _DEFAULT_ not being used when using MySQL (#433) 2021-12-09 14:05:28 +01:00
NEZNAMY 83ce5bd476 Drop <#RRGGBB> format due to conflict with the gradient pattern starting the same way (#430) 2021-12-09 13:50:04 +01:00
NEZNAMY 75a341c240 fix placeholder refreshing being broken for time travelers 2021-12-09 13:44:51 +01:00
NEZNAMY 921a793b5c return identifier instead of null for sync placeholders before initialized 2021-12-09 13:05:31 +01:00
NEZNAMY c1b92868cd fix world forwarding on bungeecord 2021-12-08 20:39:51 +01:00
NEZNAMY 94d19d728d fix condition refresh when only trigger placeholders are used inside 2021-12-08 20:38:39 +01:00
NEZNAMY 8ef518f7e2 add null check for tablist properties when refreshing 2021-12-08 19:11:43 +01:00
NEZNAMY 79fd1148a9 add back animation format converting from 2.8.10 -> 2.9.0 2021-12-08 18:51:00 +01:00
NEZNAMY 313ba8d765 attempt to fix error caused by concurrent access 2021-12-08 18:43:22 +01:00
NEZNAMY c12c422357 fix NPE when editing unknown bossbar 2021-12-08 18:37:56 +01:00
NEZNAMY b14c97d18a add try/catch for ConcurrentModificationException 2021-12-08 18:34:39 +01:00
NEZNAMY 2fe345cb65 add back "barcolors" animation since it's used in default config 2021-12-08 18:11:03 +01:00
NEZNAMY 96ff81370c fix animations lagging when using nested animations 2021-12-08 18:09:48 +01:00
Leon Mangler c4a1f41673 Load TAB after PremiumVanish
When BungeeTabPlayer#isVanished uses PV's API, PV needs to actually be enabled, not just loaded. A soft-dependency should ensure that PV is fully enabled before TAB's onEnable() uses the API.
2021-12-08 17:37:13 +01:00
NEZNAMY ca4c8ccb20 Merge branch 'master' of https://github.com/NEZNAMY/TAB 2021-12-08 15:57:51 +01:00
Callum Seabrook 7471006f8a Updated to Krypton 0.58 2021-12-07 18:14:23 +00:00
NEZNAMY 896c709824 fix small memory leak 2021-12-04 22:41:55 +01:00
NEZNAMY 473a37cb6a fix NPE 2021-12-04 22:29:10 +01:00
NEZNAMY 9e84d96051 Add back %essentialsnick% for all the crybabies we get in #community-support who didn't even bother reading changelog of a major plugin update which is supposed to hint big changes were made and the changelog should be read. 2021-12-04 20:56:30 +01:00
NEZNAMY 019466d84d remove unused code 2021-12-04 19:27:02 +01:00
NEZNAMY c222061529 slightly optimize width calculation & partially avoid #347 2021-12-04 19:15:36 +01:00
NEZNAMY acdd99404c use different functions for file operations 2021-12-04 19:08:58 +01:00
NEZNAMY 799381bff3 properly convert objects to string 2021-12-04 19:02:11 +01:00
NEZNAMY b3654977ca cast to long 2021-12-04 18:59:03 +01:00
NEZNAMY b67d1928b5 add "final" modifier 2021-12-04 18:58:00 +01:00
NEZNAMY 052748d2b9 simplify 2021-12-04 18:47:18 +01:00
NEZNAMY e265187ff8 call function instead of duplicating code 2021-12-04 18:10:44 +01:00
NEZNAMY c622a95550 use fixed interval to avoid startup error 2021-12-04 17:09:40 +01:00
NEZNAMY 94d71a245b Merge branch 'master' of https://github.com/NEZNAMY/TAB 2021-12-04 13:28:23 +01:00
NEZNAMY a9403269be add LP softdepend on bungeecord 2021-12-04 13:26:16 +01:00
Callum Seabrook dfe6768eb5 Moved YamlAssist to Krypton repository version 2021-12-04 12:19:55 +00:00
Callum Seabrook d88bf65806 Setup publishing for all but the JAR module 2021-12-04 12:05:35 +00:00
NEZNAMY 30929062d6 what happened here 2021-12-04 12:20:56 +01:00
NEZNAMY 747e3d692d clear registered teams on login packet 2021-12-04 12:16:07 +01:00
Callum Seabrook 1d3ecbb7ed Somehow forgot that display name is now nullable 2021-12-04 10:28:25 +00:00
Callum Seabrook 39b88b0dd5 Updated Krypton to 0.57 2021-12-04 10:24:18 +00:00
NEZNAMY d13d3eb055 bridge placeholders will return identifier until they are initialized instead of null 2021-12-03 16:21:04 +01:00
NEZNAMY f8f72b9074 rgb support for remaining players text as well 2021-12-03 15:47:51 +01:00
NEZNAMY a9d0b0a0ae 3.0.1-pre1 2021-12-03 15:38:46 +01:00
NEZNAMY 37bd624537 double-fix for bungeecord bug kick 2021-12-03 15:37:23 +01:00
NEZNAMY e19f4ed771 reorder bungee.yml to match PluginDescription.java order 2021-12-03 12:11:27 +01:00
NEZNAMY c828fa8d52 Merge remote-tracking branch 'origin/master' 2021-12-03 12:00:36 +01:00
NEZNAMY 9e080a5f5c add argument check 2021-12-03 12:00:20 +01:00
NEZNAMY 7d7d4c05ab remove debug message 2021-12-03 11:59:34 +01:00
NEZNAMY d4c7044708 add proper color support to layout more players text 2021-12-02 20:36:38 +01:00
Callum Seabrook 52dd8c7c8b Added run folder to gitignore for test servers 2021-12-02 18:49:11 +00:00
NEZNAMY 398ac8b6cf register invalid relational placeholders on proxy correctly, so it doesn't throw errors 2021-12-02 18:12:53 +01:00
NEZNAMY 911792b214 Merge branch 'master' of https://github.com/NEZNAMY/TAB 2021-12-02 13:50:21 +01:00
Callum Seabrook 8e54989502 Setup new publish repository for API 2021-12-02 12:49:11 +00:00
NEZNAMY 4f16579063 support mineskin by uuid 2021-12-02 11:01:19 +01:00
NEZNAMY e1f1698413 fix startup on mohist 1.12.2 2021-12-02 10:09:25 +01:00
NEZNAMY 5eb999b98a fixed typos, capital letters, more docs 2021-12-01 15:52:18 +01:00
NEZNAMY 5e7af835d8 %online% cannot be trigger due to vanish checks 2021-12-01 10:12:05 +01:00
NEZNAMY f19f2c5a20 add conversion for multiple groups with same sorting priority 2021-12-01 08:57:24 +01:00
NEZNAMY ff2aceb781 fix placeholder in default layout.yml 2021-12-01 08:50:37 +01:00
199 changed files with 1887 additions and 1748 deletions

No files matched your search

+1
View File
@@ -35,6 +35,7 @@ hs_err_pid*
# other
.gitattributes
*.iml
run/
# Gradle
.gradle/
+1 -1
View File
@@ -9,7 +9,7 @@ Once the plugin compiles, you can grab the jar from `jar/build/libs/` folder.
# Links
See [releases](https://github.com/NEZNAMY/TAB/releases) for precompiled jar.
Has the plugin helped you in any way and you wish to support the development?
Has the plugin helped you in any way, and you wish to support the development?
You can purchase the plugin on [MC-Market](https://www.mc-market.org/resources/20631/), [Polymart](https://polymart.org/resource/484) or just [send a donation](https://paypal.me/neznamy1).
Supporters have access to high-quality [discord support](https://discord.gg/EaSvdk6).
-4
View File
@@ -1,7 +1,3 @@
plugins {
id("tab.publishing")
}
dependencies {
compileOnlyApi(libs.netty)
api(libs.jsonSimple) {
@@ -6,77 +6,77 @@ public interface ArmorStand {
* Returns true if offset is static, false if not
* @return true if static, false if dynamic
*/
public boolean hasStaticOffset();
boolean hasStaticOffset();
/**
* Changes offset of the armor stand
* @param offset - new offset
*/
public void setOffset(double offset);
void setOffset(double offset);
/**
* Returns offset of the armor stand
* @return offset from base
*/
public double getOffset();
double getOffset();
/**
* Returns property for armor stand's name
* @return property for armor stand's name
*/
public Property getProperty();
Property getProperty();
/**
* Teleports armor stand to owner's current location for everyone in range
*/
public void teleport();
void teleport();
/**
* Teleports armor stand to owner's current location for specified player
* @param viewer - player to send packet to
*/
public void teleport(TabPlayer viewer);
void teleport(TabPlayer viewer);
/**
* Changes sneaking flag and sends packets to everyone in range
* @param sneaking
* @param sneaking
* new sneaking status
*/
public void sneak(boolean sneaking);
void sneak(boolean sneaking);
/**
* Despawns armor stand for everyone
* DeSpawns armor stand for everyone
*/
public void destroy();
void destroy();
/**
* Despawns armor stand for specified player
* DeSpawns armor stand for specified player
* @param viewer - player to send packet to
*/
public void destroy(TabPlayer viewer);
void destroy(TabPlayer viewer);
/**
* Updates armor stand's name if needed
*/
public void refresh();
void refresh();
/**
* Updates visibility if needed
* @param force - if refresh should be forced
*/
public void updateVisibility(boolean force);
void updateVisibility(boolean force);
/**
* Returns entity ID of this armor stand
* @return entity ID of this armor stand
*/
public int getEntityId();
int getEntityId();
/**
* Spawns armor stand for specified player
* @param viewer - player to spawn for
* @param addToRegistered - if player should be added to players in range
*/
public void spawn(TabPlayer viewer);
void spawn(TabPlayer viewer);
public void respawn(TabPlayer viewer);
void respawn(TabPlayer viewer);
}
@@ -3,19 +3,19 @@ package me.neznamy.tab.api;
public interface FeatureManager {
/**
* Registers a feature, which will start recieiving events
* Registers a feature, which will start receiving events
*
* @param featureName - name of feature
* @param featureHandler - the handler
* @param name - name of feature
* @param feature - the handler
*/
public void registerFeature(String name, TabFeature feature);
void registerFeature(String name, TabFeature feature);
/**
* Unregisters feature making it no longer receive events. This does not run unload method nor cancel
* tasks created by the feature
* @param name - feature name defined in registerFeature
*/
public void unregisterFeature(String name);
void unregisterFeature(String name);
/**
* Returns whether a feature with said name is registered or not
@@ -23,13 +23,13 @@ public interface FeatureManager {
* @param name - name of feature defined in registerFeature method
* @return true if feature exists, false if not
*/
public boolean isFeatureEnabled(String name);
boolean isFeatureEnabled(String name);
/**
* Returns feature handler by it's name
* Returns feature handler by its name
*
* @param name - name of feature defined in registerFeature method
* @return the feature or null if feature does not exist
*/
public TabFeature getFeature(String name);
TabFeature getFeature(String name);
}
@@ -2,15 +2,15 @@ package me.neznamy.tab.api;
public interface HeaderFooterManager {
public void setHeader(TabPlayer player, String header);
void setHeader(TabPlayer player, String header);
public void setFooter(TabPlayer player, String footer);
void setFooter(TabPlayer player, String footer);
public void setHeaderAndFooter(TabPlayer player, String header, String footer);
void setHeaderAndFooter(TabPlayer player, String header, String footer);
public void resetHeader(TabPlayer player);
void resetHeader(TabPlayer player);
public void resetFooter(TabPlayer player);
void resetFooter(TabPlayer player);
public void resetHeaderAndFooter(TabPlayer player);
void resetHeaderAndFooter(TabPlayer player);
}
@@ -4,57 +4,57 @@ public interface Property {
/**
* Changes raw value to new one
* @param newValue - new value to be used
* @param rawValue - new value to be used
*/
public void changeRawValue(String rawValue);
void changeRawValue(String rawValue);
/**
* Returns original raw value ignoring API calls
* @return original raw value
*/
public String getOriginalRawValue();
String getOriginalRawValue();
/**
* Temporarily overrides current raw value with an API call
* @param temporaryValue - temporary value to be assigned
*/
public void setTemporaryValue(String temporaryValue);
void setTemporaryValue(String temporaryValue);
/**
* Returns current temporary value
* @return temporary value or null if not set
*/
public String getTemporaryValue();
String getTemporaryValue();
/**
* Returns temporary value (via API) if present, raw value otherwise
* @return current raw value
*/
public String getCurrentRawValue();
String getCurrentRawValue();
/**
* Returns last known value
* @return last known value
*/
public String get();
String get();
/**
* Replaces all placeholders in current raw value, colorizes it, removes remove-strings and returns whether value changed or not
* @return if updating changed value or not
*/
public boolean update();
boolean update();
/**
* Replaces all placeholders in current raw value, colorizes it, removes remove-strings and returns it.
* Equal to calling update() and then get().
* @return updated value
*/
public String updateAndGet();
String updateAndGet();
/**
* Returns value for defined viewer by applying relational placeholders to last known value
* @param viewer - the viewer
* @return format for the viewer
*/
public String getFormat(TabPlayer viewer);
String getFormat(TabPlayer viewer);
}
@@ -2,9 +2,9 @@ package me.neznamy.tab.api;
public interface PropertyConfiguration {
public void setProperty(String name, String property, String server, String world, String value);
void setProperty(String name, String property, String server, String world, String value);
public String[] getProperty(String name, String property, String server, String world);
String[] getProperty(String name, String property, String server, String world);
public void remove(String name);
void remove(String name);
}
@@ -5,8 +5,9 @@ package me.neznamy.tab.api;
*/
public enum ProtocolVersion {
UNKNOWN (999, "Unknown"),
PROXY (999, "Proxy"),
UNKNOWN ("Unknown"),
PROXY ("Proxy"),
V1_18_1 (757),
V1_18 (757),
V1_17_1 (756),
V1_17 (755),
@@ -72,25 +73,24 @@ public enum ProtocolVersion {
* Constructs new instance with given network id
* @param networkId - network id of this version
*/
private ProtocolVersion(int networkId){
ProtocolVersion(int networkId){
this.networkId = networkId;
this.minorVersion = Integer.parseInt(toString().split("_")[1]);
this.friendlyName = toString().substring(1).replace("_", ".");
}
/**
* Constructs new instance with given network id and friendly name
* @param networkId - network id of this version
* Constructs new instance with given friendly name
* @param friendlyName - friendly name to display
*/
private ProtocolVersion(int networkId, String friendlyName){
this.networkId = networkId;
this.minorVersion = 17;
ProtocolVersion(String friendlyName){
this.networkId = 999;
this.minorVersion = 18;
this.friendlyName = friendlyName;
}
/**
* Returns the vesion's network id
* Returns the version's network id
* @return version's network id
*/
public int getNetworkId() {
@@ -99,7 +99,7 @@ public enum ProtocolVersion {
/**
* Returns user-friendly name of the version (such as 1.16.2 instead of V1_16_2)
* @return
* @return user-friendly name of the version
*/
public String getFriendlyName() {
return friendlyName;
@@ -45,8 +45,8 @@ public abstract class TabAPI {
public abstract TabPlayer[] getOnlinePlayers();
/**
* Return bossbar manager instance if the feature is enabled. Returns null otherwise.
* @return bossbar manager
* Return BossBar manager instance if the feature is enabled. Returns null otherwise.
* @return BossBar manager
*/
public abstract BossBarManager getBossBarManager();
@@ -132,14 +132,13 @@ public abstract class TabFeature {
* Processes the packet send and returns true if packet should be cancelled
* @param receiver - player receiving packet
* @param packet - received packet
* @return true if packet should be cancelled, false if not
*/
public boolean onDisplayObjective(TabPlayer receiver, PacketPlayOutScoreboardDisplayObjective packet) {
return false;
public void onDisplayObjective(TabPlayer receiver, PacketPlayOutScoreboardDisplayObjective packet) {
//empty by default
}
/**
* Processes login packet, only available on bungeecord
* Processes login packet, only available on BungeeCord
* @param packetReceiver - player receiving client reset packet
*/
public void onLoginPacket(TabPlayer packetReceiver) {
@@ -158,7 +157,7 @@ public abstract class TabFeature {
/**
* Processes the packet send and possibly modifies it
* @param receiver - player receiving packet
* @param packet - received packet
* @param info - received packet
*/
public void onPlayerInfo(TabPlayer receiver, PacketPlayOutPlayerInfo info) {
//empty by default
@@ -169,7 +168,8 @@ public abstract class TabFeature {
* @param sender - packet sender
* @param packet - packet received
* @return true if false should be cancelled, false if not
* @throws ReflectiveOperationException
* @throws ReflectiveOperationException
* if thrown by reflective operation
*/
public boolean onPacketReceive(TabPlayer sender, Object packet) throws ReflectiveOperationException {
return false;
@@ -179,7 +179,8 @@ public abstract class TabFeature {
* Processes raw packet sent to client
* @param receiver - packet receiver
* @param packet - the packet
* @throws ReflectiveOperationException
* @throws ReflectiveOperationException
* if thrown by reflective operation
*/
public void onPacketSend(TabPlayer receiver, Object packet) throws ReflectiveOperationException {
//empty by default
@@ -251,8 +252,8 @@ public abstract class TabFeature {
disabledPlayers.add(p);
}
public boolean removeDisabledPlayer(TabPlayer p) {
return disabledPlayers.remove(p);
public void removeDisabledPlayer(TabPlayer p) {
disabledPlayers.remove(p);
}
public String getRefreshDisplayName() {
@@ -14,63 +14,63 @@ public interface TabPlayer {
/**
* Refreshes all visuals on the player
*/
public void forceRefresh();
void forceRefresh();
/**
* Returns player's name
* @return Player's name
*/
public String getName();
String getName();
/**
* Returns player's UUID
* @return Player's UUID
*/
public UUID getUniqueId();
UUID getUniqueId();
/**
* Returns player's uuid used in tablist. This may only be different than real uuid if
* Returns player's uuid used in TabList. This may only be different from real uuid if
* TAB is installed on velocity with some specific velocity setup
* @return player's uuid in tablist
* @return player's uuid in TabList
*/
public UUID getTablistUUID();
UUID getTablistUUID();
/**
* Returns player's protocol version
* @return player's protocol version
*/
public ProtocolVersion getVersion();
ProtocolVersion getVersion();
/**
* Returns platform-specific entity
* @return an instance of bukkit/bungee player depending on platform
*/
public Object getPlayer();
Object getPlayer();
/**
* Returns player's current world name (on bungeecord this requires bridge installed)
* @return name of world where player is currently in, null on bungeecord if bridge is not installed
* Returns player's current world name (on BungeeCord this requires bridge installed)
* @return name of world where player is currently in, null on BungeeCord if bridge is not installed
*/
public String getWorld();
String getWorld();
/**
* Returns player's current server name on bungeecord (on bukkit this returns null)
* Returns player's current server name on BungeeCord (on bukkit this returns null)
* @return name of server where player is currently in, null on bukkit
*/
public String getServer();
String getServer();
/**
* Performs platform-specific API call to check for permission and returns the result
* @param permission - the permission to check for
* @return - true if has, false if not
* @return - true if player has permission, false if not
*/
public boolean hasPermission(String permission);
boolean hasPermission(String permission);
/**
* Sends the player a custom universal packet
* @param packet - packet to send
*/
public void sendCustomPacket(TabPacket packet);
void sendCustomPacket(TabPacket packet);
/**
* Sends the player a custom universal packet and adds that packet into counter that
@@ -78,7 +78,7 @@ public interface TabPlayer {
* @param packet - packet to send
* @param feature - feature to increment sent packet counter of
*/
public void sendCustomPacket(TabPacket packet, TabFeature feature);
void sendCustomPacket(TabPacket packet, TabFeature feature);
/**
* Sends the player a custom universal packet and adds that packet into counter that
@@ -86,13 +86,13 @@ public interface TabPlayer {
* @param packet - packet to send
* @param feature - feature to increment sent packet counter of
*/
public void sendCustomPacket(TabPacket packet, String feature);
void sendCustomPacket(TabPacket packet, String feature);
/**
* Sends the player a platform-specific packet
* @param packet - an instance of packet depending on platform
*/
public void sendPacket(Object packet);
void sendPacket(Object packet);
/**
* Sends the player a platform-specific packet and adds that packet into counter that
@@ -100,7 +100,7 @@ public interface TabPlayer {
* @param packet - an instance of packet depending on platform
* @param feature - feature to increment sent packet counter of
*/
public void sendPacket(Object packet, TabFeature feature);
void sendPacket(Object packet, TabFeature feature);
/**
* Sends the player a platform-specific packet and adds that packet into counter that
@@ -108,84 +108,84 @@ public interface TabPlayer {
* @param packet - an instance of packet depending on platform
* @param feature - feature to increment sent packet counter of
*/
public void sendPacket(Object packet, String feature);
void sendPacket(Object packet, String feature);
/**
* Returns player's property by name
* @param name - name of property
* @return the property or null if not found
*/
public Property getProperty(String name);
Property getProperty(String name);
/**
* Sends a message to the player
* @param message - message to be sent
* @param translateColors - whether colors should be translated or not
*/
public void sendMessage(String message, boolean translateColors);
void sendMessage(String message, boolean translateColors);
/**
* Sends specified component as a chat message
* @param message - message to send
*/
public void sendMessage(IChatBaseComponent message);
void sendMessage(IChatBaseComponent message);
/**
* Returns player's primary permission group
* @return player's group depending on configuration
*/
public String getGroup();
String getGroup();
/**
* Toggles armor stands preview mode for the player
*/
public void toggleNametagPreview();
void toggleNametagPreview();
/**
* Returns whether player is previewing nametag or not
* Returns whether player is previewing NameTag or not
* @return true if previewing, false if not
*/
public boolean isPreviewingNametag();
boolean isPreviewingNametag();
/**
* Returns player's channel or null if server is 1.7 or older
* @return player's channel
*/
public Channel getChannel();
Channel getChannel();
/**
* Returns player's ping calculated by server
* @return player's ping
*/
public int getPing();
int getPing();
/**
* Returns player's platform-specific skin data
* @return player's skin
*/
public Object getSkin();
Object getSkin();
/**
* Returns true once the player is successfully loaded (onJoin method ran through all methods)
* @return true if player is fully loaded, false otherwise
*/
public boolean isLoaded();
boolean isLoaded();
/**
* Sets property with specified name to new value. If property did no exist before, it is
* created and true is returned. If it existed, it is overridden and true is returned. False is returned othewise.
* Sets property with specified name to new value. If property did not exist before, it is
* created and true is returned. If it existed, it is overridden and true is returned. False is returned otherwise.
* @param feature - feature using this property to get placeholders registered
* @param identifier - property name
* @param rawValue - new raw value
* @return true if value changed / did not exist, false if value did not change
*/
public boolean setProperty(TabFeature feature, String identifier, String rawValue);
boolean setProperty(TabFeature feature, String identifier, String rawValue);
/**
* Loads property from config using standard property loading algorithm
* @param property - property name to load
*/
public void loadPropertyFromConfig(TabFeature feature, String property);
void loadPropertyFromConfig(TabFeature feature, String property);
/**
* Loads property from config using standard property loading algorithm. If the property is
@@ -193,64 +193,69 @@ public interface TabPlayer {
* @param property - property name to load
* @param ifNotSet - value to use if property is not defined in config
*/
public void loadPropertyFromConfig(TabFeature feature, String property, String ifNotSet);
void loadPropertyFromConfig(TabFeature feature, String property, String ifNotSet);
/**
* Returns name of player's scoreboard team or null if nametag feature is disabled
* Returns name of player's scoreboard team or null if NameTag feature is disabled
* @return name of player's team
*/
public String getTeamName();
String getTeamName();
/**
* Returns user-friendly explanation of team name
* @return explanation behind team name
*/
public String getTeamNameNote();
String getTeamNameNote();
/**
* Returns true if player is disguised using iDisguide or LibsDisguises on bukkit, LibsDisguises
* only on bungeecord via bukkit bridge
* Returns true if player is disguised using LibsDisguises
* @return true if player is disguised, false if not
*/
public boolean isDisguised();
boolean isDisguised();
/**
* Returns true if player has invisiblity potion, false if not. For bukkit, API is used, for bungeecord
* Returns true if player has invisibility potion, false if not. For bukkit, API is used, for BungeeCord
* bukkit bridge is used
* @return true if has invisiblity potion, false if not
* @return true if player has invisibility potion, false if not
*/
public boolean hasInvisibilityPotion();
boolean hasInvisibilityPotion();
/**
* Currently only PV hook on bungeecord for global playerlist function. Looking to expand this
* Currently only PV hook on BungeeCord for global PlayerList function. Looking to expand this
* in the future
* @return true if vanished with PV on bungeecord
* @return true if vanished with PV on BungeeCord
*/
public boolean isVanished();
boolean isVanished();
/**
* Returns true if player is online according to server
* @return true if online, false if not
*/
public boolean isOnline();
boolean isOnline();
/**
* Returns player's armor stand manager if unlimited nametag mode is enabled, null if disabled
* Returns player's armor stand manager if unlimited GameMode mode is enabled, null if disabled
* @return player's armor stand manager
*/
public ArmorStandManager getArmorStandManager();
ArmorStandManager getArmorStandManager();
/**
* Sets player's armor stands manager to new instance
* @param armorStandManager - new instance
*/
public void setArmorStandManager(ArmorStandManager armorStandManager);
void setArmorStandManager(ArmorStandManager armorStandManager);
/**
* Returns gamemode of the player (0 for survival, 1 creative, 2 adventure, 3 spectator)
* @return gamemode of the player
* Returns GameMode of the player (0 for survival, 1 creative, 2 adventure, 3 spectator)
* @return GameMode of the player
*/
public int getGamemode();
int getGamemode();
public boolean isBedrockPlayer();
boolean isBedrockPlayer();
void setTemporaryGroup(String group);
boolean hasTemporaryGroup();
void resetTemporaryGroup();
}
@@ -2,28 +2,28 @@ package me.neznamy.tab.api;
public interface TablistFormatManager {
public void setPrefix(TabPlayer player, String prefix);
void setPrefix(TabPlayer player, String prefix);
public void setName(TabPlayer player, String customname);
void setName(TabPlayer player, String customName);
public void setSuffix(TabPlayer player, String suffix);
void setSuffix(TabPlayer player, String suffix);
public void resetPrefix(TabPlayer player);
void resetPrefix(TabPlayer player);
public void resetName(TabPlayer player);
void resetName(TabPlayer player);
public void resetSuffix(TabPlayer player);
void resetSuffix(TabPlayer player);
public String getCustomPrefix(TabPlayer player);
String getCustomPrefix(TabPlayer player);
public String getCustomName(TabPlayer player);
String getCustomName(TabPlayer player);
public String getCustomSuffix(TabPlayer player);
String getCustomSuffix(TabPlayer player);
public String getOriginalPrefix(TabPlayer player);
String getOriginalPrefix(TabPlayer player);
public String getOriginalName(TabPlayer player);
String getOriginalName(TabPlayer player);
public String getOriginalSuffix(TabPlayer player);
String getOriginalSuffix(TabPlayer player);
}
@@ -1,7 +1,7 @@
package me.neznamy.tab.api.bossbar;
/**
* An enum representing all available bossbar colors.
* An enum representing all available BossBar colors.
* Calling ordinal() will return color's network ID.
*/
public enum BarColor {
@@ -12,5 +12,5 @@ public enum BarColor {
GREEN,
YELLOW,
PURPLE,
WHITE;
WHITE
}
@@ -1,7 +1,7 @@
package me.neznamy.tab.api.bossbar;
/**
* An enum representing all available bossbar styles.
* An enum representing all available BossBar styles.
* Calling ordinal() will return style's network ID.
* Style names are equal to NMS names.
*/
@@ -14,7 +14,7 @@ public enum BarStyle {
NOTCHED_20("SEGMENTED_20");
/** Style's name used in Bukkit API */
private String bukkitName;
private final String bukkitName;
/**
* Initializes enum constant with given bukkit name
@@ -22,7 +22,7 @@ public enum BarStyle {
* @param bukkitName
* Name of color to be returned in {@code getBukkitName()}
*/
private BarStyle(String bukkitName){
BarStyle(String bukkitName){
this.bukkitName = bukkitName;
}
@@ -6,36 +6,36 @@ import java.util.UUID;
import me.neznamy.tab.api.TabPlayer;
/**
* An interface representing a bossbar line.
* An interface representing a BossBar line.
* <p>
* For clients 1.8 and lower it uses wither, which only allows 1 bar
* to be displayed at a time. Entity packets are not available on bungeecord,
* to be displayed at a time. Entity packets are not available on BungeeCord,
* where nothing will be displayed for these players.
* <p>
* For 1.9+ it uses the new bossbar feature, allowing configurable styles
* For 1.9+ it uses the new BossBar feature, allowing configurable styles
* and colors, as well as display several bars at once. Limit of maximum
* displayed bossbars depends on client resolution and GUI scale, up to
* 9 concurrent bossbars displayed at once.
* displayed BossBars depends on client resolution and GUI scale, up to
* 9 concurrent BossBars displayed at once.
*/
public interface BossBar {
/**
* Returns name of this bossbar. If it was defined in config, returns
* Returns name of this BossBar. If it was defined in config, returns
* the name specified in config. If it was made using the API, returns
* randomly generated ID given to this bossbar when creating.
* @return name of bossbar
* randomly generated ID given to this BossBar when creating.
* @return name of BossBar
*/
public String getName();
String getName();
/**
* Returns randomly generated uuid of this bossbar used internally to match
* the bossbar in client with packets or with Bukkit API bossbar instances.
* @return uuid of this bossbar
* Returns randomly generated uuid of this BossBar used internally to match
* the BossBar in client with packets or with Bukkit API BossBar instances.
* @return uuid of this BossBar
*/
public UUID getUniqueId();
UUID getUniqueId();
/**
* Changes bossbar title to specified string, supporting placeholders.
* Changes BossBar title to specified string, supporting placeholders.
* <p>
* If title contains new placeholders not used before, they are registered using
* standard registration logic and refreshed periodically. No need to call
@@ -44,12 +44,12 @@ public interface BossBar {
* If specified title is equal to the current one, nothing happens.
*
* @param title
* New title to display in this bossbar
* New title to display in this BossBar
*/
public void setTitle(String title);
void setTitle(String title);
/**
* Changes bossbar progress to specified string, supporting placeholders.
* Changes BossBar progress to specified string, supporting placeholders.
* The string must be a string version of a float value, or a placeholder that
* outputs a float value with range 0-100.
* <p>
@@ -60,21 +60,21 @@ public interface BossBar {
* If specified progress is equal to the current one, nothing happens.
*
* @param progress
* New progress to use in this bossbar
* New progress to use in this BossBar
*/
public void setProgress(String progress);
void setProgress(String progress);
/**
* Changes bossbar progress to specified value ranging from 0 to 100.
* Changes BossBar progress to specified value ranging from 0 to 100.
* <p>
* If specified progress is equal to the current one, nothing happens.
* @param progress
* New progress to use in this bossbar
* New progress to use in this BossBar
*/
public void setProgress(float progress);
void setProgress(float progress);
/**
* Changes bossbar color to specified string, supporting placeholders.
* Changes BossBar color to specified string, supporting placeholders.
* The string must be a string version of one of the supported values,
* or a placeholder that outputs one of them.
* <p>
@@ -85,22 +85,22 @@ public interface BossBar {
* If specified color is equal to the current one, nothing happens.
*
* @param color
* New color to use in this bossbar
* New color to use in this BossBar
*/
public void setColor(String color);
void setColor(String color);
/**
* Changes bossbar color to specified enum constant.
* Changes BossBar color to specified enum constant.
* <p>
* If specified color is equal to the current one, nothing happens.
*
* @param color
* New color to use in this bossbar
* New color to use in this BossBar
*/
public void setColor(BarColor color);
void setColor(BarColor color);
/**
* Changes bossbar style to specified string, supporting placeholders.
* Changes BossBar style to specified string, supporting placeholders.
* The string must be a string version of one of the supported values,
* or a placeholder that outputs one of them.
* <p>
@@ -111,75 +111,75 @@ public interface BossBar {
* If specified style is equal to the current one, nothing happens.
*
* @param style
* New style to use in this bossbar
* New style to use in this BossBar
*/
public void setStyle(String style);
void setStyle(String style);
/**
* Changes bossbar style to specified enum constant.
* Changes BossBar style to specified enum constant.
* <p>
* If specified style is equal to the current one, nothing happens.
*
* @param style
* New style to use in this bossbar
* New style to use in this BossBar
*/
public void setStyle(BarStyle style);
void setStyle(BarStyle style);
/**
* Returns current title of the bossbar in raw format. If it contains placeholders,
* Returns current title of the BossBar in raw format. If it contains placeholders,
* their raw identifiers are used in the result.
* @return title of the bossbar
* @return title of the BossBar
*/
public String getTitle();
String getTitle();
/**
* Returns progress of the bossbar as a string, which is either entered string
* Returns progress of the BossBar as a string, which is either entered string
* containing placeholders or entered number converted to string
* @return entered progress as a string
*/
public String getProgress();
String getProgress();
/**
* Returns color of the bossbar as a string, which is either entered string
* Returns color of the BossBar as a string, which is either entered string
* containing placeholders or entered enum value converted to string
* @return entered color as a string
*/
public String getColor();
String getColor();
/**
* Returns style of the bossbar as a string, which is either entered string
* Returns style of the BossBar as a string, which is either entered string
* containing placeholders or entered enum value converted to string
* @return entered style as a string
*/
public String getStyle();
String getStyle();
/**
* Registers this bossbar to specified player.
* Registers this BossBar to specified player.
* <p>
* If the player already sees this bossbar, nothing happens.
* If the player already sees this BossBar, nothing happens.
*
* @param player
* Player to register this bossbar to
* Player to register this BossBar to
*/
public void addPlayer(TabPlayer player);
void addPlayer(TabPlayer player);
/**
* Unregisters this bossbar from specified player.
* Unregisters this BossBar from specified player.
* <p>
* If the player does not see this bossbar, nothing happens.
* If the player does not see this BossBar, nothing happens.
*
* @param player
* Player to unregister this bossbar from
* Player to unregister this BossBar from
*/
public void removePlayer(TabPlayer player);
void removePlayer(TabPlayer player);
/**
* Returns list of players who can see this bossbar.
* Returns list of players who can see this BossBar.
* <p>
* The returned list can only be used to read. Writing
* will not work properly. For adding/removing playes see {@link #addPlayer(TabPlayer)}
* will not work properly. For adding/removing players see {@link #addPlayer(TabPlayer)}
* and {@link #removePlayer(TabPlayer)}.
* @return List of players seeing this bossbar
* @return List of players seeing this BossBar
*/
public List<TabPlayer> getPlayers();
List<TabPlayer> getPlayers();
}
@@ -7,17 +7,17 @@ import java.util.UUID;
import me.neznamy.tab.api.TabPlayer;
/**
* An interface allowing work with bossbars such as creating, sending
* An interface allowing work with BossBars such as creating, sending
* and toggling.
* <p>
* Instance can be obtained using {@link me.neznamy.tab.api.TabAPI#getBossBarManager()}.
* This requires the bossbar feature to be enabled in config, otherwise the method will
* This requires the BossBar feature to be enabled in config, otherwise the method will
* return null.
*/
public interface BossBarManager {
/**
* Creates bossbar with specified parameters and registers it to bossbar manager,
* Creates BossBar with specified parameters and registers it to BossBar manager,
* allowing to retrieve it later.
*
* @param title
@@ -31,12 +31,12 @@ public interface BossBarManager {
*
* @param style
* Style to use
* @return The newly created bossbar
* @return The newly created BossBar
*/
public BossBar createBossBar(String title, float progress, BarColor color, BarStyle style);
BossBar createBossBar(String title, float progress, BarColor color, BarStyle style);
/**
* Creates bossbar with specified parameters and registers it to bossbar manager,
* Creates BossBar with specified parameters and registers it to BossBar manager,
* allowing to retrieve it later.
*
* @param title
@@ -53,58 +53,58 @@ public interface BossBarManager {
* @param style
* Style to use. Must be a string version of one of enum constants, or
* a placeholder that returns one of them
* @return The newly created bossbar
* @return The newly created BossBar
*/
public BossBar createBossBar(String title, String progress, String color, String style);
BossBar createBossBar(String title, String progress, String color, String style);
/**
* Returns registered bossbar with given name. For bossbars from config it is the name
* they were created with, for API bossbars their randomly generated name, which can be
* Returns registered BossBar with given name. For BossBars from config it is the name
* they were created with, for API BossBars their randomly generated name, which can be
* retrieved using {@link me.neznamy.tab.api.bossbar.BossBar#getName()}.
* Returns null if no such bossbar exists.
* Returns null if no such BossBar exists.
*
* @param name
* Name of registered bossbar
* @return bossbar with specified name
* Name of registered BossBar
* @return BossBar with specified name
*/
public BossBar getBossBar(String name);
BossBar getBossBar(String name);
/**
* Returns registered bossbar with specified UUID. This UUID is randomly generated when
* bossbar is created and used in packets / to match which the one from Bukkit API.
* Returns null if no such bossbar exists.
* Returns registered BossBar with specified UUID. This UUID is randomly generated when
* BossBar is created and used in packets / to match which the one from Bukkit API.
* Returns null if no such BossBar exists.
*
* @param id
* UUID to return bossbar by
* @return bossbar with specified uuid
* UUID to return BossBar by
* @return BossBar with specified uuid
*/
public BossBar getBossBar(UUID id);
BossBar getBossBar(UUID id);
/**
* Returns a map of all registered bossbars. This includes both bossbars from config
* Returns a map of all registered BossBars. This includes both BossBars from config
* and those registered via API.
* <p>
* Map key is bossbar's name available in {@link me.neznamy.tab.api.bossbar.BossBar#getName()},
* map value is the bossbar interface.
* @return all registered bossbars
* Map key is BossBar's name available in {@link me.neznamy.tab.api.bossbar.BossBar#getName()},
* map value is the BossBar interface.
* @return all registered BossBars
*/
public Map<String, BossBar> getRegisteredBossBars();
Map<String, BossBar> getRegisteredBossBars();
/**
* Toggles bossbar for this player and sends toggle message if {@code sendToggleMessage} is true.
* Toggles BossBar for this player and sends toggle message if {@code sendToggleMessage} is true.
*
* @param player
* Player to toggle bossbar for
* Player to toggle BossBar for
*
* @param sendToggleMessage
* {@code true} if toggle message should be sent, {@code false} if not
* @see #hasBossBarVisible(TabPlayer)
* @see #setBossBarVisible(TabPlayer, boolean, boolean)
*/
public void toggleBossBar(TabPlayer player, boolean sendToggleMessage);
void toggleBossBar(TabPlayer player, boolean sendToggleMessage);
/**
* Returns true if player can see bossbars, false if toggled via command or API.
* Returns true if player can see BossBars, false if toggled via command or API.
*
* @param player
* Player to check toggle status of
@@ -112,56 +112,56 @@ public interface BossBarManager {
* @see #toggleBossBar(TabPlayer, boolean)
* @see #setBossBarVisible(TabPlayer, boolean, boolean)
*/
public boolean hasBossBarVisible(TabPlayer player);
boolean hasBossBarVisible(TabPlayer player);
/**
* Sets bossbar visibility of player to set value. If value did not change, nothing happens.
* Sets BossBar visibility of player to set value. If value did not change, nothing happens.
* If visibility changed, toggle message is sent if {@code sendToggleMessage} is {@code true}.
*
* @param player
* Player to set bossbar visibility of
* Player to set BossBar visibility of
* @param visible
* {@code true} if bossbar should be visible, {@code false} if not
* {@code true} if BossBar should be visible, {@code false} if not
* @param sendToggleMessage
* {@code true} if toggle message should be sent if value changed, {@code false} if not
* @see #toggleBossBar(TabPlayer, boolean)
* @see #hasBossBarVisible(TabPlayer)
*/
public void setBossBarVisible(TabPlayer player, boolean visible, boolean sendToggleMessage);
void setBossBarVisible(TabPlayer player, boolean visible, boolean sendToggleMessage);
/**
* Temporarily displays registered bossbar to player for specified amount of time in milliseconds.
* Temporarily displays registered BossBar to player for specified amount of time in milliseconds.
* @param player
* Player to show bossbar to
* @param bossbar
* Name of registered bossbar to show
* Player to show BossBar to
* @param bossBar
* Name of registered BossBar to show
* @param duration
* In milliseconds for how long should bossbar be displayed
* In milliseconds for how long should BossBar be displayed
* @throws IllegalArgumentException
* if no bossbar with specified name exists
* if no BossBar with specified name exists
* @see #announceBossBar(String, int)
* @see #getAnnouncedBossBars()
*/
public void sendBossBarTemporarily(TabPlayer player, String bossbar, int duration);
void sendBossBarTemporarily(TabPlayer player, String bossBar, int duration);
/**
* Temporarily displays registered bossbar to all players for specified amount of time in milliseconds.
* @param bossbar
* Name of registered bossbar to show
* Temporarily displays registered BossBar to all players for specified amount of time in milliseconds.
* @param bossBar
* Name of registered BossBar to show
* @param duration
* In milliseconds for how long should bossbar be displayed
* In milliseconds for how long should BossBar be displayed
* @throws IllegalArgumentException
* if no bossbar with specified name exists
* if no BossBar with specified name exists
* @see #sendBossBarTemporarily(TabPlayer, String, int)
* @see #getAnnouncedBossBars()
*/
public void announceBossBar(String bossbar, int duration);
void announceBossBar(String bossBar, int duration);
/**
* Returns list of bossbars which are currently being announced.
* @return list of currently active bossbar announcements
* Returns list of BossBars which are currently being announced.
* @return list of currently active BossBar announcements
* @see #sendBossBarTemporarily(TabPlayer, String, int)
* @see #announceBossBar(String, int)
*/
public List<BossBar> getAnnouncedBossBars();
List<BossBar> getAnnouncedBossBars();
}
@@ -1,31 +1,50 @@
package me.neznamy.tab.api.chat;
import me.neznamy.tab.api.util.Preconditions;
/**
* Class for click event action in chat component
*/
public class ChatClickable {
private EnumClickAction action;
private String value;
/** Click action */
private final EnumClickAction action;
/** Click value */
private final String value;
/**
* Constructs new instance with given action and value.
* @param action
* click event action
* @param value
* click event value
* @throws IllegalArgumentException
* if {@code action} is null or {@code value} is null
*/
public ChatClickable(EnumClickAction action, String value) {
Preconditions.checkNotNull(action, "hover action cannot be null");
Preconditions.checkNotNull(value, "hover value cannot be null");
this.action = action;
this.value = value;
}
/**
* Returns click action defined in constructor
* @return click action
*/
public EnumClickAction getAction() {
return action;
}
public void setAction(EnumClickAction action) {
this.action = action;
}
/**
* Returns click action defined in constructor
* @return click action
*/
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
/**
* Enum for all possible click actions
*/
@@ -35,6 +54,6 @@ public class ChatClickable {
RUN_COMMAND,
CHANGE_PAGE, //since 1.8
SUGGEST_COMMAND,
COPY_TO_CLIPBOARD; //since 1.15
COPY_TO_CLIPBOARD //since 1.15
}
}
@@ -1,31 +1,50 @@
package me.neznamy.tab.api.chat;
import me.neznamy.tab.api.util.Preconditions;
/**
* Class for hover event action in chat component
*/
public class ChatHoverable {
private EnumHoverAction action;
private IChatBaseComponent value;
/** Hover action */
private final EnumHoverAction action;
/** Hover value */
private final IChatBaseComponent value;
/**
* Constructs new instance with given action and value.
* @param action
* hover event action
* @param value
* hover event value
* @throws IllegalArgumentException
* if {@code action} is null or {@code value} is null
*/
public ChatHoverable(EnumHoverAction action, IChatBaseComponent value) {
Preconditions.checkNotNull(action, "hover action cannot be null");
Preconditions.checkNotNull(value, "hover value cannot be null");
this.action = action;
this.value = value;
}
/**
* Returns hover action defined in constructor
* @return hover action
*/
public EnumHoverAction getAction() {
return action;
}
public void setAction(EnumHoverAction action) {
this.action = action;
}
/**
* Returns hover value defined in constructor
* @return hover value
*/
public IChatBaseComponent getValue() {
return value;
}
public void setValue(IChatBaseComponent value) {
this.value = value;
}
/**
* Enum for all possible hover actions
*/
@@ -33,6 +52,6 @@ public class ChatHoverable {
SHOW_TEXT,
SHOW_ITEM,
SHOW_ENTITY;
SHOW_ENTITY
}
}
}
@@ -39,6 +39,7 @@ public class ChatModifier {
this.clickEvent = modifier.clickEvent == null ? null : new ChatClickable(modifier.clickEvent.getAction(), modifier.clickEvent.getValue());
this.hoverEvent = modifier.hoverEvent == null ? null : new ChatHoverable(modifier.hoverEvent.getAction(), modifier.hoverEvent.getValue());
this.font = modifier.font;
this.targetVersion = modifier.targetVersion;
}
public TextColor getColor() {
@@ -156,7 +157,6 @@ public class ChatModifier {
/**
* Sets click action to RUN_COMMAND and command to given value
* @param command - command to perform, might be without / to send a chat message
* @return self
*/
public void onClickRunCommand(String command) {
clickEvent = new ChatClickable(EnumClickAction.RUN_COMMAND, command);
@@ -172,11 +172,11 @@ public class ChatModifier {
/**
* Sets click action to CHANGE_PAGE and page id to given value
* @param newpage - id of new page
* @param newPage - id of new page
*/
public void onClickChangePage(int newpage) {
public void onClickChangePage(int newPage) {
if (TabAPI.getInstance().getServerVersion().getMinorVersion() < 8) throw new UnsupportedOperationException("change_page click action is not supported on <1.8");
clickEvent = new ChatClickable(EnumClickAction.CHANGE_PAGE, String.valueOf(newpage));
clickEvent = new ChatClickable(EnumClickAction.CHANGE_PAGE, String.valueOf(newPage));
}
public void onClick(EnumClickAction action, String value) {
@@ -3,81 +3,80 @@ package me.neznamy.tab.api.chat;
import me.neznamy.tab.api.chat.rgb.RGBUtils;
/**
* A class representing the n.m.s.EnumChatFormat class to make work with it much easier
* An enum containing all possible legacy color codes and magic codes. Also contains handy color-related methods.
*/
public enum EnumChatFormat {
BLACK(0, '0', "000000"),
DARK_BLUE(1, '1', "0000AA"),
DARK_GREEN(2, '2', "00AA00"),
DARK_AQUA(3, '3', "00AAAA"),
DARK_RED(4, '4', "AA0000"),
DARK_PURPLE(5, '5', "AA00AA"),
GOLD(6, '6', "FFAA00"),
GRAY(7, '7', "AAAAAA"),
DARK_GRAY(8, '8', "555555"),
BLUE(9, '9', "5555FF"),
GREEN(10, 'a', "55FF55"),
AQUA(11, 'b', "55FFFF"),
RED(12, 'c', "FF5555"),
LIGHT_PURPLE(13, 'd', "FF55FF"),
YELLOW(14, 'e', "FFFF55"),
WHITE(15, 'f', "FFFFFF"),
OBFUSCATED(16, 'k'),
BOLD(17, 'l'),
STRIKETHROUGH(18, 'm'),
UNDERLINE(19, 'n'),
ITALIC(20, 'o'),
RESET(21, 'r');
BLACK('0', "000000"),
DARK_BLUE('1', "0000AA"),
DARK_GREEN('2', "00AA00"),
DARK_AQUA('3', "00AAAA"),
DARK_RED('4', "AA0000"),
DARK_PURPLE('5', "AA00AA"),
GOLD('6', "FFAA00"),
GRAY('7', "AAAAAA"),
DARK_GRAY('8', "555555"),
BLUE('9', "5555FF"),
GREEN('a', "55FF55"),
AQUA('b', "55FFFF"),
RED('c', "FF5555"),
LIGHT_PURPLE('d', "FF55FF"),
YELLOW('e', "FFFF55"),
WHITE('f', "FFFFFF"),
OBFUSCATED('k'),
BOLD('l'),
STRIKETHROUGH('m'),
UNDERLINE('n'),
ITALIC('o'),
RESET('r');
/** The symbol minecraft uses to colorize text */
public static final char COLOR_CHAR = 0x00a7;
/** The color symbol in form of a string */
public static final String COLOR_STRING = String.valueOf(COLOR_CHAR);
//network id of the color
private final int networkId;
//characer representing the color
/** Character representing the color or magic code */
private final char character;
//red value of this color
private final int red;
/** Red value of this constant, 0 for magic codes */
private final short red;
/** Green value of this constant, 0 for magic codes */
private final short green;
/** Blue value of this constant, 0 for magic codes */
private final short blue;
//green value of this color
private final int green;
//blue value of this color
private final int blue;
//hex code as string
/** Color as 6-digit hex code, null for magic codes */
private final String hexCode;
//color char followed by color's character
/** Color symbol followed by constant's character */
private final String chatFormat;
/**
* Constructs new instance with given parameters
* @param networkId - network id of the color
* @param character - character representing the color
* @param hexColor - hex code of the color
* Constructs new color instance with given character and hex code
* @param character
* character which the color goes by
* @param hexCode
* 6-digit hex code of the color
*/
private EnumChatFormat(int networkId, char character, String hexCode) {
this.networkId = networkId;
EnumChatFormat(char character, String hexCode) {
this.character = character;
this.chatFormat = String.valueOf(COLOR_CHAR) + character;
this.hexCode = hexCode;
int hexColor = Integer.parseInt(hexCode, 16);
red = (hexColor >> 16) & 0xFF;
green = (hexColor >> 8) & 0xFF;
blue = hexColor & 0xFF;
red = (short) ((hexColor >> 16) & 0xFF);
green = (short) ((hexColor >> 8) & 0xFF);
blue = (short) (hexColor & 0xFF);
}
/**
* Constructs new instance with given parameters
* @param networkId - network id of the color
* @param character - character representing the color
* Constructs new magic code instance with given character
* @param character
* character representing the magic code
*/
private EnumChatFormat(int networkId, char character) {
this.networkId = networkId;
EnumChatFormat(char character) {
this.character = character;
this.chatFormat = String.valueOf(COLOR_CHAR) + character;
red = 0;
@@ -85,43 +84,36 @@ public enum EnumChatFormat {
blue = 0;
hexCode = null;
}
/**
* Returns network id of this color
* @return network if of this color
* Returns red value of this color code
* @return red value
*/
public int getNetworkId() {
return networkId;
}
/**
* Returns red value of this color
* @return red value
*/
public int getRed() {
public short getRed() {
return red;
}
/**
* Returns green value of this color
* @return green value
* Returns green value of this color code
* @return green value
*/
public int getGreen() {
public short getGreen() {
return green;
}
/**
* Returns blue value of this color
* @return blue value
* Returns blue value of this color code
* @return blue value
*/
public int getBlue() {
public short getBlue() {
return blue;
}
/**
* Returns enum value based on inserted color or null if character is not valid
* @param c - color code character (0-9, a-f, k-o, r)
* @return instance from the character
* Returns enum value based on provided character or null if character is not valid
* @param c
* color code character (0-9, a-f, k-o, r)
* @return instance from the character or null if character is not valid
*/
public static EnumChatFormat getByChar(char c) {
for (EnumChatFormat format : values()) {
@@ -131,13 +123,15 @@ public enum EnumChatFormat {
}
/**
* Returns enum value of last colors used in given string
* @param string - string to check last colors of
* @return last used color code in given string
* Returns enum value of last colors used in given string.
* If it's null, empty or does not contain color codes, WHITE is returned.
* @param string
* string to check last colors of
* @return last used color code in given string or WHITE if nothing is found
*/
public static EnumChatFormat lastColorsOf(String string) {
if (string == null || string.length() == 0) return EnumChatFormat.WHITE;
String legacyText = RGBUtils.getInstance().convertRGBtoLegacy(string); //translating RGB into legacy for nametags
String legacyText = RGBUtils.getInstance().convertRGBtoLegacy(string);
String last = getLastColors(legacyText);
if (last.length() > 0) {
char c = last.toCharArray()[1];
@@ -173,11 +167,14 @@ public enum EnumChatFormat {
}
/**
* Returns enum value with exact red, green and blue values or null if no match
* @param red - exact red value
* @param green - exact green value
* @param blue - exact blue value
* @return enum value or null if no such combination exists
* Returns enum value with exact red, green and blue values or null if no match was found
* @param red
* exact red value
* @param green
* exact green value
* @param blue
* exact blue value
* @return enum value or null if no such combination exists
*/
public static EnumChatFormat fromRGBExact(int red, int green, int blue){
for (EnumChatFormat format : values()) {
@@ -185,8 +182,14 @@ public enum EnumChatFormat {
}
return null;
}
//code taken from bukkit, so it can work on bungee too
/**
* Color translation method taken from bukkit, which converts '&' symbol into
* the actual color character if followed by a valid color character.
* @param textToTranslate
* text to replace color symbol in
* @return colorized string from provided text
*/
public static String color(String textToTranslate){
if (textToTranslate == null) return null;
if (!textToTranslate.contains("&")) return textToTranslate;
@@ -199,13 +202,25 @@ public enum EnumChatFormat {
}
return new String(b);
}
/**
* Turns back the color symbol into '&' symbol in provided text.
* @param text
* text to revert colors in
* @return reverted text
*/
public static String decolor(String text) {
if (text == null) return null;
if (!text.contains(COLOR_STRING)) return text;
return text.replace(COLOR_CHAR, '&');
}
//code taken from bukkit, so it can work on bungee too
/**
* Code taken from bukkit, which returns last color codes used in provided text.
* @param input
* text to get last colors from
* @return last colors used in provided text or empty string if nothing was found
*/
public static String getLastColors(String input) {
StringBuilder result = new StringBuilder();
int length = input.length();
@@ -136,7 +136,7 @@ public class IChatBaseComponent {
JSONObject jsonObject = (JSONObject) new JSONParser().parse(json);
IChatBaseComponent component;
if (jsonObject.containsKey("type")) {
return new ChatComponentEntity((String) jsonObject.get("type"), UUID.fromString((String) jsonObject.get("id")), IChatBaseComponent.deserialize(((JSONObject) jsonObject.get("name")).toString()).toFlatText());
return new ChatComponentEntity((String) jsonObject.get("type"), UUID.fromString((String) jsonObject.get("id")), IChatBaseComponent.deserialize(jsonObject.get("name").toString()).toFlatText());
}
component = new IChatBaseComponent();
component.setText((String) jsonObject.get("text"));
@@ -338,7 +338,7 @@ public class IChatBaseComponent {
}
/**
* Converts this component into a simple text with legacy colors (closest match if color is set to RGB)
* Converts this component into a simple text with legacy colors (the closest match if color is set to RGB)
* @return The simple text format
*/
public String toLegacyText() {
@@ -349,7 +349,7 @@ public class IChatBaseComponent {
/**
* Appends text to string builder, might also add color and magic codes if different
* than previous component in chain
* from previous component in chain
* @param builder - builder to append text to
* @param previousFormatting - colors and magic codes in previous component
* @return New formatting, might be identical to previous one
@@ -407,7 +407,7 @@ public class IChatBaseComponent {
*/
public String toFlatText() {
StringBuilder builder = new StringBuilder();
if (modifier.getColor() != null) builder.append("#" + modifier.getColor().getHexCode());
if (modifier.getColor() != null) builder.append("#").append(modifier.getColor().getHexCode());
builder.append(modifier.getMagicCodes());
if (text != null) builder.append(text);
for (IChatBaseComponent child : getExtra()) {
@@ -1,25 +1,42 @@
package me.neznamy.tab.api.chat;
import me.neznamy.tab.api.util.Preconditions;
/**
* A class used to represent any combination of RGB colors
* A class representing a component color, which can be either RGB or legacy code.
*/
public class TextColor {
//rgb values, only initializing when they are actually requested
private int red = -1;
private int green = -1;
private int blue = -1;
/**
* RGB values from 0 to 255.
* They are only initialized if they are actually used to avoid
* unnecessary memory allocations with string operations.
*/
private short red = -1;
private short green = -1;
private short blue = -1;
//closest legacy color
/** Closest legacy color to this color object. */
private EnumChatFormat legacyColor;
//6-digit combination of hexadecimal numbers
/** HEX code of this color as a 6-digit hexadecimal string without "#" prefix. */
private String hexCode;
//true if legacy color was forced via constructor, false if automatically
/**
* Boolean value whether the legacy color was forced with constructor or should be
* automatically assigned as closest color.
* This value is used in gradients when converting text for legacy players. */
private boolean legacyColorForced;
/**
* Constructs new instance as a clone of the provided color.
* @param color
* color to create a clone of
* @throws IllegalArgumentException
* if color is {@code null}
*/
public TextColor(TextColor color) {
Preconditions.checkNotNull(color, "color cannot be null");
red = color.red;
green = color.green;
blue = color.blue;
@@ -29,29 +46,43 @@ public class TextColor {
}
/**
* Constructs new instance based on hex code as string
* @param hexCode - a 6-digit combination of hex numbers
* Constructs new instance from provided 6-digit hex code string
* @param hexCode
* a 6-digit combination of hex numbers as a string
* @throws IllegalArgumentException
* if hexCode is {@code null}
*/
public TextColor(String hexCode) {
Preconditions.checkNotNull(hexCode, "hex code cannot be null");
this.hexCode = hexCode;
}
/**
* Constructs new instance from given 6-digit hex code and legacy color
* @param hexCode - 6-digit hex code
* @param legacyColor color to use for legacy clients
* Constructs new instance from provided 6-digit hex code and forced legacy color
* @param hexCode
* 6-digit combination of hex numbers as a string
* @param legacyColor
* color to use for legacy clients instead of using the closest legacy color
* @throws IllegalArgumentException
* if {@code hexCode} is {@code null} or {@code legacyColor} is {@code null}
*/
public TextColor(String hexCode, EnumChatFormat legacyColor) {
Preconditions.checkNotNull(hexCode, "hex code cannot be null");
Preconditions.checkNotNull(legacyColor, "legacy color cannot be null");
this.hexCode = hexCode;
this.legacyColorForced = true;
this.legacyColor = legacyColor;
}
/**
* Constructs new instance with given parameter
* @param legacyColor - legacy color
* Constructs new instance from provided legacy color
* @param legacyColor
* legacy color to construct the instance from
* @throws IllegalArgumentException
* if {@code legacyColor} is {@code null}
*/
public TextColor(EnumChatFormat legacyColor) {
Preconditions.checkNotNull(legacyColor, "legacy color cannot be null");
this.red = legacyColor.getRed();
this.green = legacyColor.getGreen();
this.blue = legacyColor.getBlue();
@@ -59,31 +90,36 @@ public class TextColor {
}
/**
* Constructs new instance with given parameters
* @param red - red value
* @param green - green value
* @param blue - blue value
* Constructs new instance with red, green and blue values
* @param red
* red value
* @param green
* green value
* @param blue
* blue value
* @throws IllegalArgumentException
* if {@code red}, {@code green} or {@code blue} is out of range ({@code 0-255})
*/
public TextColor(int red, int green, int blue) {
this.red = red;
this.green = green;
this.blue = blue;
Preconditions.checkRange(red, 0, 255);
Preconditions.checkRange(green, 0, 255);
Preconditions.checkRange(blue, 0, 255);
this.red = (short) red;
this.green = (short) green;
this.blue = (short) blue;
}
/**
* Gets closest legacy color based on rgb values
* Loads the closest legacy color based currently provided values
*/
private EnumChatFormat getClosestColor(int red, int green, int blue) {
private EnumChatFormat loadClosestColor() {
double minMaxDist = 9999;
double maxDist;
EnumChatFormat closestColor = EnumChatFormat.WHITE;
for (EnumChatFormat color : EnumChatFormat.values()) {
int rDiff = color.getRed() - red;
int gDiff = color.getGreen() - green;
int bDiff = color.getBlue() - blue;
if (rDiff < 0) rDiff = -rDiff;
if (gDiff < 0) gDiff = -gDiff;
if (bDiff < 0) bDiff = -bDiff;
int rDiff = Math.abs(color.getRed() - getRed());
int gDiff = Math.abs(color.getGreen() - getGreen());
int bDiff = Math.abs(color.getBlue() - getBlue());
maxDist = rDiff;
if (gDiff > maxDist) maxDist = gDiff;
if (bDiff > maxDist) maxDist = bDiff;
@@ -96,61 +132,58 @@ public class TextColor {
}
/**
* Returns amount of red
* @return amount of red
* Returns {@code red} value
* @return red value
*/
public int getRed() {
if (red == -1) {
int hexColor = Integer.parseInt(hexCode, 16);
red = (hexColor >> 16) & 0xFF;
green = (hexColor >> 8) & 0xFF;
blue = hexColor & 0xFF;
}
if (red == -1) loadColors();
return red;
}
/**
* Returns amount of green
* @return amount of green
* Returns {@code green} value
* @return green value
*/
public int getGreen() {
if (green == -1) {
int hexColor = Integer.parseInt(hexCode, 16);
red = (hexColor >> 16) & 0xFF;
green = (hexColor >> 8) & 0xFF;
blue = hexColor & 0xFF;
}
if (green == -1) loadColors();
return green;
}
/**
* Returns amount of blue
* @return amount of blue
* Returns {@code blue} value
* @return blue value
*/
public int getBlue() {
if (blue == -1) {
int hexColor = Integer.parseInt(hexCode, 16);
red = (hexColor >> 16) & 0xFF;
green = (hexColor >> 8) & 0xFF;
blue = hexColor & 0xFF;
}
if (blue == -1) loadColors();
return blue;
}
/**
* Loads red, green and blue values based on current hex code string
*/
private void loadColors(){
int hexColor = Integer.parseInt(hexCode, 16);
red = (short) ((hexColor >> 16) & 0xFF);
green = (short) ((hexColor >> 8) & 0xFF);
blue = (short) (hexColor & 0xFF);
}
/**
* Returns defined legacy color
* @return defined legacy color
* Returns the closest legacy color of this color object.
* If the color was defined in constructor, it's returned.
* Otherwise, the closest color is calculated the then returned.
* @return closest legacy color
*/
public EnumChatFormat getLegacyColor() {
if (legacyColor == null) {
legacyColor = getClosestColor(getRed(), getGreen(), getBlue());
legacyColor = loadClosestColor();
}
return legacyColor;
}
/**
* Returns hex code of this color
* @return hex code of this color
* Returns the rgb combination as a 6-digit hex code string
* @return the rgb combination as a 6-digit hex code string
*/
public String getHexCode() {
if (hexCode == null) {
@@ -160,8 +193,9 @@ public class TextColor {
}
/**
* Converts the color into a valid color value used in color field in chat component
* @return the color converted into string acceptable by client
* Converts the color into a valid color value used in color field in chat component.
* That is either 6-digit hex code prefixed with '#', or lowercase legacy color.
* @return the color serialized for use in chat component
*/
public String toString() {
EnumChatFormat legacyEquivalent = EnumChatFormat.fromRGBExact(getRed(), getGreen(), getBlue());
@@ -170,21 +204,24 @@ public class TextColor {
return legacyEquivalent.toString().toLowerCase();
}
return "#" + getHexCode();
}
/**
* Returns true if legacy color was forced with a constructor, false if automatically
* @return true if forced, false if not
* Returns true if legacy color was forced with a constructor, false if not
* @return true if forced, false if not
*/
public boolean isLegacyColorForced() {
return legacyColorForced;
}
/**
* Reads the string and turns into text color. String is either #RRGGBB or a lowercased legacy color
* @param string - string from color field in chat component
* @return An instance from specified string
* Reads the string as it appears in chat component and turns it into the color object.
* If the entered string is null, returns null.
* If it's prefixed with '#', it's considered as a hex code.
* Otherwise, it is considered being a lowercase legacy color.
* @param string
* string from color field in chat component
* @return An instance from specified string or null if string is null
*/
public static TextColor fromString(String string) {
if (string == null) return null;
@@ -4,12 +4,10 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
import me.neznamy.tab.api.chat.EnumChatFormat;
import me.neznamy.tab.api.chat.IChatBaseComponent;
import me.neznamy.tab.api.chat.TextColor;
import me.neznamy.tab.api.chat.rgb.format.BukkitFormat;
import me.neznamy.tab.api.chat.rgb.format.CMIFormat;
import me.neznamy.tab.api.chat.rgb.format.HtmlFormat;
import me.neznamy.tab.api.chat.rgb.format.HtmlFormat2;
import me.neznamy.tab.api.chat.rgb.format.RGBFormatter;
import me.neznamy.tab.api.chat.rgb.format.UnnamedFormat1;
import me.neznamy.tab.api.chat.rgb.gradient.CMIGradient;
@@ -22,26 +20,30 @@ import me.neznamy.tab.api.chat.rgb.gradient.KyoriGradient;
*/
public class RGBUtils {
//instance of class
private final static RGBUtils instance = new RGBUtils();
/** Instance of the class */
private static final RGBUtils instance = new RGBUtils();
//rgb formatters
/** Registered RGB formatters */
private final RGBFormatter[] formats;
//gradient patterns
/** Registered gradient patterns */
private final GradientPattern[] gradients;
//TAB's RGB format
/** TAB's RGB pattern, used to convert text to bukkit format for boss bar */
private final Pattern tabPattern = Pattern.compile("#[0-9a-fA-F]{6}");
/** RGB pattern for legacy codes */
private final Pattern tabPatternLegacy = Pattern.compile("#[0-9a-fA-F]{6}\\|.");
/**
* Constructs new instance and loads all RGB patterns and gradients
*/
public RGBUtils() {
formats = new RGBFormatter[] {
new BukkitFormat(),
new CMIFormat(),
new UnnamedFormat1(),
new HtmlFormat(),
new HtmlFormat2()
new HtmlFormat()
};
gradients = new GradientPattern[] {
//{#RRGGBB>}text{#RRGGBB<}
@@ -60,16 +62,22 @@ public class RGBUtils {
/**
* Returns instance of this class
* @return instance
* @return instance
*/
public static RGBUtils getInstance() {
return instance;
}
/**
* Applies all RGB formats and gradients to text and returns it
* @param text - original text
* @return text where everything is converted to #RRGGBB
* Applies all RGB formats and gradients to text and returns it.
* This method is called on every property initialization to convert formats
* once instead of on every refresh, if possible. Because of that, parameter
* {@code ignorePlaceholders} exists to not break raw placeholder identifiers
* @param text
* original text
* @param ignorePlaceholders
* whether placeholders should be ignored or not
* @return text where everything is converted to #RRGGBB
*/
public String applyFormats(String text, boolean ignorePlaceholders) {
String replaced = text;
@@ -81,8 +89,18 @@ public class RGBUtils {
}
return replaced;
}
/**
* Converts TAB's RGB format (#RRGGBB) into bukkit one (&x&r&r&g&g&b&b)
* for modern clients (1.16+), for legacy clients it will use the closest color.
* @param text
* text to convert
* @param rgbClient
* whether client accepts RGB or not
* @return converted text
*/
public String convertToBukkitFormat(String text, boolean rgbClient) {
if (text == null) return null;
if (!text.contains("#")) return text; //no rgb codes
if (rgbClient) {
//converting random formats to TAB one
@@ -90,21 +108,22 @@ public class RGBUtils {
for (Pattern p : new Pattern[]{tabPatternLegacy, tabPattern}) {
Matcher m = p.matcher(replaced);
while (m.find()) {
String hexcode = m.group();
String fixed = "&x&" + hexcode.charAt(1) + "&" + hexcode.charAt(2) + "&" + hexcode.charAt(3) + "&" + hexcode.charAt(4) + "&" + hexcode.charAt(5) + "&" + hexcode.charAt(6);
replaced = replaced.replace(hexcode, EnumChatFormat.color(fixed));
String hexCode = m.group();
String fixed = "&x&" + hexCode.charAt(1) + "&" + hexCode.charAt(2) + "&" + hexCode.charAt(3) + "&" + hexCode.charAt(4) + "&" + hexCode.charAt(5) + "&" + hexCode.charAt(6);
replaced = replaced.replace(hexCode, EnumChatFormat.color(fixed));
}
}
return replaced;
} else {
return IChatBaseComponent.fromColoredText(text).toLegacyText();
return convertRGBtoLegacy(text);
}
}
/**
* Converts all hex codes in given string to legacy codes
* @param text - text to translate
* @return - translated text
* @param text
* text to convert
* @return translated text
*/
public String convertRGBtoLegacy(String text) {
if (text == null) return null;
@@ -132,7 +151,14 @@ public class RGBUtils {
}
return sb.toString();
}
/**
* Returns true if entered string is a valid 6-digit combination of
* hexadecimal numbers, false if not
* @param string
* string to check
* @return {@code true} if valid, {@code false} if not
*/
public boolean isHexCode(String string) {
if (string.length() != 6) return false;
for (int i=0; i<6; i++) {
@@ -144,9 +170,11 @@ public class RGBUtils {
/**
* Returns true if text contains legacy color request at defined RGB index start
* @param text - text to check
* @param i - current index start
* @return true if legacy color is defined, false if not
* @param text
* text to check
* @param i
* current index start
* @return {@code true} if legacy color is defined and valid, {@code false} otherwise
*/
private static boolean containsLegacyCode(String text, int i) {
if (text.length() - i < 9 || text.charAt(i+7) != '|') return false;
@@ -18,9 +18,9 @@ public class BukkitFormat implements RGBFormatter {
String replaced = text;
Matcher m = pattern.matcher(replaced);
while (m.find()) {
String hexcode = m.group();
String fixed = new String(new char[] {'#', hexcode.charAt(3), hexcode.charAt(5), hexcode.charAt(7), hexcode.charAt(9), hexcode.charAt(11), hexcode.charAt(13)});
replaced = replaced.replace(hexcode, fixed);
String hexCode = m.group();
String fixed = new String(new char[] {'#', hexCode.charAt(3), hexCode.charAt(5), hexCode.charAt(7), hexCode.charAt(9), hexCode.charAt(11), hexCode.charAt(13)});
replaced = replaced.replace(hexCode, fixed);
}
return replaced;
}
@@ -16,9 +16,9 @@ public class CMIFormat implements RGBFormatter {
String replaced = text;
Matcher m = pattern.matcher(replaced);
while (m.find()) {
String hexcode = m.group();
String fixed = hexcode.substring(2, 8);
replaced = replaced.replace(hexcode, "#" + fixed);
String hexCode = m.group();
String fixed = hexCode.substring(2, 8);
replaced = replaced.replace(hexCode, "#" + fixed);
}
return replaced;
}
@@ -16,9 +16,9 @@ public class HtmlFormat implements RGBFormatter {
Matcher m = pattern.matcher(text);
String replaced = text;
while (m.find()) {
String hexcode = m.group();
String fixed = hexcode.substring(2, 8);
replaced = replaced.replace(hexcode, "#" + fixed);
String hexCode = m.group();
String fixed = hexCode.substring(2, 8);
replaced = replaced.replace(hexCode, "#" + fixed);
}
return replaced;
}
@@ -1,25 +0,0 @@
package me.neznamy.tab.api.chat.rgb.format;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Formatter for <#RRGGBB>
*/
public class HtmlFormat2 implements RGBFormatter {
private final Pattern pattern = Pattern.compile("<#[0-9a-fA-F]{6}>");
@Override
public String reformat(String text) {
if (!text.contains("<#")) return text;
Matcher m = pattern.matcher(text);
String replaced = text;
while (m.find()) {
String hexcode = m.group();
String fixed = hexcode.substring(2, 8);
replaced = replaced.replace(hexcode, "#" + fixed);
}
return replaced;
}
}
@@ -10,5 +10,5 @@ public interface RGBFormatter {
* @param text - text to format
* @return reformatted text
*/
public String reformat(String text);
String reformat(String text);
}
@@ -13,7 +13,7 @@ public interface GradientPattern {
* @param text - text to be reformatted
* @return reformatted text
*/
public String applyPattern(String text, boolean ignorePlaceholders);
String applyPattern(String text, boolean ignorePlaceholders);
/**
* Returns gradient text based on start color, text and end color
@@ -22,18 +22,18 @@ public interface GradientPattern {
* @param end - end color
* @return reformatted text
*/
public default String asGradient(TextColor start, String text, TextColor end) {
default String asGradient(TextColor start, String text, TextColor end) {
//lazy support for magic codes in gradients
String magicCodes = EnumChatFormat.getLastColors(text);
String decolorized = text.substring(magicCodes.length());
String deColorized = text.substring(magicCodes.length());
StringBuilder sb = new StringBuilder();
int length = decolorized.length();
int length = deColorized.length();
if (length == 1) {
sb.append("#");
sb.append(new TextColor(start.getRed(), start.getGreen(), start.getBlue()).getHexCode());
if (start.isLegacyColorForced()) sb.append("|" + start.getLegacyColor().getCharacter());
if (start.isLegacyColorForced()) sb.append("|").append(start.getLegacyColor().getCharacter());
sb.append(magicCodes);
sb.append(decolorized);
sb.append(deColorized);
return sb.toString();
}
for (int i=0; i<length; i++) {
@@ -42,9 +42,9 @@ public interface GradientPattern {
int blue = (int) (start.getBlue() + (float)(end.getBlue() - start.getBlue())/(length-1)*i);
sb.append("#");
sb.append(new TextColor(red, green, blue).getHexCode());
if (start.isLegacyColorForced()) sb.append("|" + start.getLegacyColor().getCharacter());
if (start.isLegacyColorForced()) sb.append("|").append(start.getLegacyColor().getCharacter());
sb.append(magicCodes);
sb.append(decolorized.charAt(i));
sb.append(deColorized.charAt(i));
}
return sb.toString();
}
@@ -52,22 +52,18 @@ public abstract class ConfigurationFile {
if (destination == null) throw new IllegalArgumentException("Destination cannot be null");
this.file = destination;
if (file.getParentFile() != null) file.getParentFile().mkdirs();
if (!file.exists()) {
if (source == null) throw new IllegalStateException("File does not exist and source is null");
if (!file.exists() && source == null) throw new IllegalStateException("File does not exist and source is null");
if (file.createNewFile()) {
// Files.copy(source, file.toPath());
//avoiding MalformedInputException thrown on fabric due to file not having UTF8 encoding by default
//also automatically using the encoding so users don't have to worry about it anymore
file.createNewFile();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(source, StandardCharsets.UTF_8));
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8))){
String line;
while ((line = reader.readLine()) != null) {
writer.write(line + "\n");
}
reader.close();
writer.close();
}
}
detectHeader();
}
@@ -155,8 +151,8 @@ public abstract class ConfigurationFile {
* @param map
* map to get value from
* @param key
* case insensitive key name
* @return map value from case insensitive key
* case-insensitive key name
* @return map value from case-insensitive key
*/
private Object getIgnoreCase(Map<Object, Object> map, String key) {
for (Entry<Object, Object> entry : map.entrySet()) {
@@ -360,11 +356,11 @@ public abstract class ConfigurationFile {
private Map<String, Object> set(Map<String, Object> map, String path, Object value) {
if (path.contains(".")) {
String keyWord = getRealKey(map, path.split("\\.")[0]);
Object submap = map.get(keyWord);
if (!(submap instanceof Map)) {
submap = new LinkedHashMap<>();
Object subMap = map.get(keyWord);
if (!(subMap instanceof Map)) {
subMap = new LinkedHashMap<>();
}
map.put(keyWord, set((Map<String, Object>) submap, path.substring(keyWord.length()+1, path.length()), value));
map.put(keyWord, set((Map<String, Object>) subMap, path.substring(keyWord.length()+1), value));
} else {
if (value == null) {
map.remove(getRealKey(map, path));
@@ -386,20 +382,19 @@ public abstract class ConfigurationFile {
* @return The real key name
*/
private String getRealKey(Map<?, ?> map, String key) {
for (Object mapkey : map.keySet()) {
if (mapkey.toString().equalsIgnoreCase(key)) return mapkey.toString();
for (Object mapKey : map.keySet()) {
if (mapKey.toString().equalsIgnoreCase(key)) return mapKey.toString();
}
return key;
}
/**
* Detects header of a file (first lines of file starting with #).
*
* @return list of comment lines on top
*
* @throws IOException
* if I/O operation fails
*/
private List<String> detectHeader() throws IOException {
private void detectHeader() throws IOException {
header = new ArrayList<>();
for (String line : Files.readAllLines(file.toPath())) {
if (line.startsWith("#")) {
@@ -408,7 +403,6 @@ public abstract class ConfigurationFile {
break;
}
}
return header;
}
/**
@@ -10,7 +10,6 @@ import java.io.Writer;
import java.nio.charset.StandardCharsets;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml;
@@ -27,9 +26,6 @@ public class YamlConfigurationFile extends ConfigurationFile {
/** SnakeYAML instance */
private static final Yaml yaml;
/**
* Initializes SnakeYAML instance with BLOCK flowstyle dumper option
*/
static {
DumperOptions options = new DumperOptions();
options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
@@ -53,13 +49,12 @@ public class YamlConfigurationFile extends ConfigurationFile {
* @throws IOException
* if I/O operation with the file unexpectedly fails
*/
@SuppressWarnings("unchecked")
public YamlConfigurationFile(InputStream source, File destination) throws YAMLException, IOException {
super(source, destination);
FileInputStream input = null;
try {
input = new FileInputStream(file);
values = (Map<String, Object>) yaml.load(input);
values = yaml.load(input);
if (values == null) values = new LinkedHashMap<>();
input.close();
} catch (YAMLException e) {
@@ -2,15 +2,15 @@ package me.neznamy.tab.api.placeholder;
public interface Placeholder {
public int getRefresh();
int getRefresh();
public String getIdentifier();
String getIdentifier();
public boolean isTriggerMode();
boolean isTriggerMode();
public void enableTriggerMode();
void enableTriggerMode();
public void enableTriggerMode(Runnable onActivation, Runnable onDisable);
void enableTriggerMode(Runnable onActivation, Runnable onDisable);
public void unload();
void unload();
}
@@ -13,24 +13,24 @@ public interface PlaceholderManager {
/**
* Registers a server placeholder (placeholder with same output for all players)
*/
public ServerPlaceholder registerServerPlaceholder(String identifier, int refresh, Supplier<Object> supplier);
ServerPlaceholder registerServerPlaceholder(String identifier, int refresh, Supplier<Object> supplier);
/**
* Registers a player placeholder (placeholder with player-specific output)
*/
public PlayerPlaceholder registerPlayerPlaceholder(String identifier, int refresh, Function<TabPlayer, Object> function);
PlayerPlaceholder registerPlayerPlaceholder(String identifier, int refresh, Function<TabPlayer, Object> function);
/**
* Registers a relational placeholder (different output for each player pair)
*/
public RelationalPlaceholder registerRelationalPlaceholder(String identifier, int refresh, BiFunction<TabPlayer, TabPlayer, Object> function);
RelationalPlaceholder registerRelationalPlaceholder(String identifier, int refresh, BiFunction<TabPlayer, TabPlayer, Object> function);
/**
* Detects placeholders in text using %% pattern and returns list of all detected identifiers
* @param text - text to detect placeholders in
* @return list of detected identifiers
*/
public List<String> detectPlaceholders(String text);
List<String> detectPlaceholders(String text);
/**
* Adds placeholder to list of used placeholders and assigns this feature as using it,
@@ -38,7 +38,7 @@ public interface PlaceholderManager {
* @param identifier - placeholder identifier
* @param feature - feature using the placeholder
*/
public void addUsedPlaceholder(String identifier, TabFeature feature);
void addUsedPlaceholder(String identifier, TabFeature feature);
public String findReplacement(String placeholder, String output);
String findReplacement(String placeholder, String output);
}
@@ -4,7 +4,7 @@ import me.neznamy.tab.api.TabPlayer;
public interface PlayerPlaceholder extends Placeholder {
public void updateValue(TabPlayer player, Object value);
void updateValue(TabPlayer player, Object value);
public Object request(TabPlayer p);
Object request(TabPlayer p);
}
@@ -4,7 +4,7 @@ import me.neznamy.tab.api.TabPlayer;
public interface RelationalPlaceholder extends Placeholder {
public void updateValue(TabPlayer viewer, TabPlayer target, Object value);
void updateValue(TabPlayer viewer, TabPlayer target, Object value);
public Object request(TabPlayer viewer, TabPlayer target);
Object request(TabPlayer viewer, TabPlayer target);
}
@@ -2,7 +2,7 @@ package me.neznamy.tab.api.placeholder;
public interface ServerPlaceholder extends Placeholder {
public void updateValue(Object value);
void updateValue(Object value);
public Object request();
Object request();
}
@@ -10,7 +10,7 @@ import me.neznamy.tab.api.chat.rgb.RGBUtils;
import me.neznamy.tab.api.util.BiFunctionWithException;
/**
* An interface represending a platform-specific packet builder
* An interface representing a platform-specific packet builder
*/
public abstract class PacketBuilder {
@@ -180,7 +180,7 @@ public abstract class PacketBuilder {
/**
* If {@code clientVersion} is >= 1.13, creates a component from given text and returns
* it as a serialized component, which bungeecord uses.
* it as a serialized component, which BungeeCord uses.
* <p>
* If {@code clientVersion} is < 1.12, the text is cut to {@code length} characters if
* needed and returned.
@@ -202,13 +202,13 @@ public abstract class PacketBuilder {
/**
* Converts platform-specific instance of player info packet into
* {@link me.neznamy.tab.api.protocol.PacketPlayOutPlayerInfo} object.
* {@link PacketPlayOutPlayerInfo} object.
*
* @param packet
* platform-specific info packet
* @param clientVersion
* Version of client receiving the packet
* @return The packet converted into {@link me.neznamy.tab.api.protocol.PacketPlayOutPlayerInfo}
* @return The packet converted into {@link PacketPlayOutPlayerInfo}
* @throws ReflectiveOperationException
* if thrown by reflective operation
*/
@@ -216,29 +216,25 @@ public abstract class PacketBuilder {
/**
* Converts platform-specific instance of objective packet into
* {@link me.neznamy.tab.api.protocol.PacketPlayOutScoreboardObjective} object.
* {@link PacketPlayOutScoreboardObjective} object.
*
* @param packet
* platform-specific objective packet
* @param clientVersion
* Version of client receiving the packet
* @return The packet converted into {@link me.neznamy.tab.api.protocol.PacketPlayOutScoreboardObjective}
* @return The packet converted into {@link PacketPlayOutScoreboardObjective}
* @throws ReflectiveOperationException
* if thrown by reflective operation
*/
public abstract PacketPlayOutScoreboardObjective readObjective(Object packet, ProtocolVersion clientVersion) throws ReflectiveOperationException;
public abstract PacketPlayOutScoreboardObjective readObjective(Object packet) throws ReflectiveOperationException;
/**
* Converts platform-specific instance of display objective packet into
* {@link me.neznamy.tab.api.protocol.PacketPlayOutScoreboardDisplayObjective} object.
* {@link PacketPlayOutScoreboardDisplayObjective} object.
*
* @param packet
* platform-specific display objective packet
* @param clientVersion
* Version of client receiving the packet
* @return The packet converted into {@link me.neznamy.tab.api.protocol.PacketPlayOutScoreboardDisplayObjective}
* @return The packet converted into {@link PacketPlayOutScoreboardDisplayObjective}
* @throws ReflectiveOperationException
* if thrown by reflective operation
*/
public abstract PacketPlayOutScoreboardDisplayObjective readDisplayObjective(Object packet, ProtocolVersion clientVersion) throws ReflectiveOperationException;
public abstract PacketPlayOutScoreboardDisplayObjective readDisplayObjective(Object packet) throws ReflectiveOperationException;
}
@@ -10,22 +10,22 @@ import me.neznamy.tab.api.bossbar.BarStyle;
*/
public class PacketPlayOutBoss implements TabPacket {
/** UUID of the bossbar */
private UUID id;
/** UUID of the BossBar */
private final UUID id;
/** Action of this packet */
private Action operation;
private final Action operation;
/** Bossbar title */
/** BossBar title */
private String name;
/** Bossbar progress (0-1)*/
/** BossBar progress (0-1)*/
private float pct;
/** Bossbar color */
/** BossBar color */
private BarColor color;
/** Bossbar style */
/** BossBar style */
private BarStyle overlay;
/** Darken screen flag */
@@ -42,15 +42,15 @@ public class PacketPlayOutBoss implements TabPacket {
* {@link me.neznamy.tab.api.protocol.PacketPlayOutBoss.Action}.ADD action
*
* @param id
* bossbar uuid
* BossBar uuid
* @param name
* bossbar title
* BossBar title
* @param pct
* bossbar progress
* BossBar progress
* @param color
* bossbar color
* BossBar color
* @param overlay
* bossbar style
* BossBar style
*/
public PacketPlayOutBoss(UUID id, String name, float pct, BarColor color, BarStyle overlay) {
this.operation = Action.ADD;
@@ -66,7 +66,7 @@ public class PacketPlayOutBoss implements TabPacket {
* {@link me.neznamy.tab.api.protocol.PacketPlayOutBoss.Action}.REMOVE action
*
* @param id
* bossbar uuid
* BossBar uuid
*/
public PacketPlayOutBoss(UUID id) {
this.operation = Action.REMOVE;
@@ -78,9 +78,9 @@ public class PacketPlayOutBoss implements TabPacket {
* {@link me.neznamy.tab.api.protocol.PacketPlayOutBoss.Action}.UPDATE_PCT action
*
* @param id
* bossbar uuid
* BossBar uuid
* @param pct
* bossbar progress
* BossBar progress
*/
public PacketPlayOutBoss(UUID id, float pct) {
this.operation = Action.UPDATE_PCT;
@@ -93,9 +93,9 @@ public class PacketPlayOutBoss implements TabPacket {
* {@link me.neznamy.tab.api.protocol.PacketPlayOutBoss.Action}.UPDATE_NAME action
*
* @param id
* bossbar uuid
* BossBar uuid
* @param name
* bossbar title
* BossBar title
*/
public PacketPlayOutBoss(UUID id, String name) {
this.operation = Action.UPDATE_NAME;
@@ -108,11 +108,11 @@ public class PacketPlayOutBoss implements TabPacket {
* {@link me.neznamy.tab.api.protocol.PacketPlayOutBoss.Action}.UPDATE_STYLE action
*
* @param id
* bossbar uuid
* @param name
* bossbar color
* BossBar uuid
* @param color
* BossBar color
* @param overlay
* bossbar style
* BossBar style
*/
public PacketPlayOutBoss(UUID id, BarColor color, BarStyle overlay) {
this.operation = Action.UPDATE_STYLE;
@@ -171,7 +171,7 @@ public class PacketPlayOutBoss implements TabPacket {
}
/**
* Returns {@link #style}
* Returns {@link #overlay}
* @return style
*/
public BarStyle getOverlay() {
@@ -275,6 +275,6 @@ public class PacketPlayOutBoss implements TabPacket {
UPDATE_PCT,
UPDATE_NAME,
UPDATE_STYLE,
UPDATE_PROPERTIES;
UPDATE_PROPERTIES
}
}
@@ -55,6 +55,6 @@ public class PacketPlayOutChat implements TabPacket {
CHAT,
SYSTEM,
GAME_INFO;
GAME_INFO
}
}
@@ -12,7 +12,7 @@ import me.neznamy.tab.api.chat.IChatBaseComponent;
public class PacketPlayOutPlayerInfo implements TabPacket {
/** Packet action */
private EnumPlayerInfoAction action;
private final EnumPlayerInfoAction action;
/** List of affected entries */
private final List<PlayerInfoData> entries;
@@ -72,12 +72,12 @@ public class PacketPlayOutPlayerInfo implements TabPacket {
/** Latency */
private int latency;
/** Gamemode */
private EnumGamemode gameMode = EnumGamemode.SURVIVAL; //protocollib causes NPE even when action does not use gamemode
/** GameMode */
private EnumGamemode gameMode = EnumGamemode.SURVIVAL; //ProtocolLib causes NPE even when action does not use GameMode
/**
* Display name displayed in tablist. Using {@code null} results in no display name
* and scoreboard team prefix/suffix being visible in tablist instead.
* Display name displayed in TabList. Using {@code null} results in no display name
* and scoreboard team prefix/suffix being visible in TabList instead.
*/
private IChatBaseComponent displayName;
@@ -103,7 +103,7 @@ public class PacketPlayOutPlayerInfo implements TabPacket {
* @param latency
* Player's ping
* @param gameMode
* Player's gamemode
* Player's GameMode
* @param displayName
* Player's display name
*/
@@ -123,7 +123,7 @@ public class PacketPlayOutPlayerInfo implements TabPacket {
* @param uniqueId
* Player's uuid
* @param gameMode
* Player's gamemode
* Player's GameMode
*/
public PlayerInfoData(UUID uniqueId, EnumGamemode gameMode) {
this.uniqueId = uniqueId;
@@ -254,7 +254,7 @@ public class PacketPlayOutPlayerInfo implements TabPacket {
/**
* Sets {@link #gameMode} to specified value
* @param gameMode
* Gamemode to use
* GameMode to use
*/
public void setGameMode(EnumGamemode gameMode) {
this.gameMode = gameMode;
@@ -288,11 +288,11 @@ public class PacketPlayOutPlayerInfo implements TabPacket {
UPDATE_GAME_MODE,
UPDATE_LATENCY,
UPDATE_DISPLAY_NAME,
REMOVE_PLAYER;
REMOVE_PLAYER
}
/**
* An enum representing gamemode
* An enum representing GameMode
*/
public enum EnumGamemode {
@@ -300,6 +300,6 @@ public class PacketPlayOutPlayerInfo implements TabPacket {
SURVIVAL,
CREATIVE,
ADVENTURE,
SPECTATOR;
SPECTATOR
}
}
@@ -7,10 +7,10 @@ import me.neznamy.tab.api.chat.IChatBaseComponent;
*/
public class PacketPlayOutPlayerListHeaderFooter implements TabPacket {
/** Tablist header */
/** TabList header */
private final IChatBaseComponent header;
/** Tablist footer */
/** TabList footer */
private final IChatBaseComponent footer;
/**
@@ -18,9 +18,9 @@ public class PacketPlayOutPlayerListHeaderFooter implements TabPacket {
* using {@link IChatBaseComponent#optimizedComponent(String)} method.
*
* @param header
* Tablist header
* TabList header
* @param footer
* Tablist footer
* TabList footer
*/
public PacketPlayOutPlayerListHeaderFooter(String header, String footer) {
this.header = IChatBaseComponent.optimizedComponent(header);
@@ -31,9 +31,9 @@ public class PacketPlayOutPlayerListHeaderFooter implements TabPacket {
* Constructs new instance with given parameters.
*
* @param header
* Tablist header
* TabList header
* @param footer
* Tablist footer
* TabList footer
*/
public PacketPlayOutPlayerListHeaderFooter(IChatBaseComponent header, IChatBaseComponent footer) {
this.header = header;
@@ -7,9 +7,9 @@ public class PacketPlayOutScoreboardDisplayObjective implements TabPacket {
/**
* Display slot.
* 0 = playerlist,
* 1 = sidebar,
* 2 = belowname.
* 0 = PlayerList,
* 1 = SideBar,
* 2 = BelowName.
*/
private final int slot;
@@ -11,7 +11,7 @@ public class PacketPlayOutScoreboardObjective implements TabPacket {
/** Display name */
private final String displayName;
/** Display type, only takes effect in playertlist */
/** Display type, only takes effect in PlayerList */
private final EnumScoreboardHealthDisplay renderType;
/**
@@ -100,10 +100,10 @@ public class PacketPlayOutScoreboardObjective implements TabPacket {
/**
* An enum representing available display types.
* They only take effect in playerlist position.
* They only take effect in PlayerList position.
*/
public enum EnumScoreboardHealthDisplay {
INTEGER, HEARTS;
INTEGER, HEARTS
}
}
@@ -84,6 +84,6 @@ public class PacketPlayOutScoreboardScore implements TabPacket {
public enum Action {
CHANGE,
REMOVE;
REMOVE
}
}
@@ -12,12 +12,12 @@ public class PacketPlayOutScoreboardTeam implements TabPacket {
/**
* Up to 16 characters long team name.
* It is used to sort players alphabetically in tablist by team names.
* Teamless players appear on top, sorted by usernames.
* It is used to sort players alphabetically in TabList by team names.
* Team-less players appear on top, sorted by usernames.
* Players with teams are below them, players of the same team are
* sorted alphabetically by usernames.
*/
private String name;
private final String name;
/** Team prefix, limited to 16 characters, on <1.13 */
private String playerPrefix;
@@ -26,10 +26,10 @@ public class PacketPlayOutScoreboardTeam implements TabPacket {
private String playerSuffix;
/**
* Nametag visibility rule since 1.8. Possible options are:
* NameTag visibility rule since 1.8. Possible options are:
* {@code always}, {@code hideForOtherTeams}, {@code hideForOwnTeam}, {@code never}
*/
private String nametagVisibility;
private String nameTagVisibility;
/**
* Collision rule added in 1.9. Possible options are:
@@ -44,7 +44,7 @@ public class PacketPlayOutScoreboardTeam implements TabPacket {
private EnumChatFormat color;
/**
* Affected entities. For players it is their name, for other entities their UUID
* Affected entities. For players, it is their name, for other entities their UUID
* Player name length is limited to 16 characters for <1.8, 40 characters since 1.8.
* Entity UUID option was added in 1.8.
*/
@@ -58,7 +58,7 @@ public class PacketPlayOutScoreboardTeam implements TabPacket {
* 3 = add entries,
* 4 = remove entries
*/
private int method;
private final int method;
/**
* Bit mask.
@@ -96,7 +96,7 @@ public class PacketPlayOutScoreboardTeam implements TabPacket {
* @param suffix
* Suffix of players in team
* @param visibility
* Nametag visibility rule
* NameTag visibility rule
* @param collision
* Collision rule
* @param players
@@ -110,7 +110,7 @@ public class PacketPlayOutScoreboardTeam implements TabPacket {
this(0, team);
this.playerPrefix = prefix;
this.playerSuffix = suffix;
this.nametagVisibility = visibility;
this.nameTagVisibility = visibility;
this.collisionRule = collision;
this.players = players;
this.options = options;
@@ -138,7 +138,7 @@ public class PacketPlayOutScoreboardTeam implements TabPacket {
* @param suffix
* Suffix of players in team
* @param visibility
* Nametag visibility rule
* NameTag visibility rule
* @param collision
* Collision rule
* @param options
@@ -150,7 +150,7 @@ public class PacketPlayOutScoreboardTeam implements TabPacket {
this(2, team);
this.playerPrefix = prefix;
this.playerSuffix = suffix;
this.nametagVisibility = visibility;
this.nameTagVisibility = visibility;
this.collisionRule = collision;
this.options = options;
}
@@ -175,9 +175,9 @@ public class PacketPlayOutScoreboardTeam implements TabPacket {
@Override
public String toString() {
return String.format("PacketPlayOutScoreboardTeam{name=%s,playerPrefix=%s,playerSuffix=%s,nametagVisibility=%s,"
return String.format("PacketPlayOutScoreboardTeam{name=%s,playerPrefix=%s,playerSuffix=%s,nameTagVisibility=%s,"
+ "collisionRule=%s,color=%s,players=%s,method=%s,options=%s}",
name, playerPrefix, playerSuffix, nametagVisibility, collisionRule, color, players, method, options);
name, playerPrefix, playerSuffix, nameTagVisibility, collisionRule, color, players, method, options);
}
/**
@@ -205,11 +205,11 @@ public class PacketPlayOutScoreboardTeam implements TabPacket {
}
/**
* Returns {@link #nametagVisibility}
* @return nametagVisibility
* Returns {@link #nameTagVisibility}
* @return nameTagVisibility
*/
public String getNametagVisibility() {
return nametagVisibility;
public String getNameTagVisibility() {
return nameTagVisibility;
}
/**
@@ -12,5 +12,5 @@ public interface TabPacket {
* Returns user-friendly string representation of the packet
* @return user-friendly string representation of the packet
*/
public String toString();
String toString();
}
@@ -9,11 +9,11 @@ public interface Line {
/**
* Returns configured raw text of this line. Placeholders
* remain unparsed.
* remain in raw format.
*
* @return raw text of this line
*/
public String getText();
String getText();
/**
* Changes text to new value. Supports placeholders, which are
@@ -25,5 +25,5 @@ public interface Line {
* @param text
* Raw text to display in the line
*/
public void setText(String text);
void setText(String text);
}
@@ -3,7 +3,7 @@ package me.neznamy.tab.api.scoreboard;
import java.util.List;
/**
* An interface allowing to work with scoreboard, such as adding plyaers,
* An interface allowing to work with scoreboard, such as adding players,
* removing players and changing lines. New instance can be created using
* {@link ScoreboardManager#createScoreboard(String, String, List)},
* for scoreboards from config {@link ScoreboardManager#getRegisteredScoreboards()}.
@@ -17,16 +17,16 @@ public interface Scoreboard {
*
* @return custom name of this scoreboard
*/
public String getName();
String getName();
/**
* Returns raw title of this scoreboard. Placeholders stay in their
* raw, unparsed format.
* raw format.
*
* @return scoreboard title
* @see #setTitle(String)
*/
public String getTitle();
String getTitle();
/**
* Sets title to specified value. Placeholders are refreshed automatically
@@ -43,7 +43,7 @@ public interface Scoreboard {
* New title to use with placeholder support
* @see #getTitle()
*/
public void setTitle(String title);
void setTitle(String title);
/**
* Returns list of lines in this scoreboard in the order they appear
@@ -54,7 +54,7 @@ public interface Scoreboard {
* @see #addLine(String)
* @see #removeLine(int)
*/
public List<Line> getLines();
List<Line> getLines();
/**
* Adds line with specified text on the bottom of scoreboard. Supports
@@ -65,7 +65,7 @@ public interface Scoreboard {
* @see #getLines()
* @see #removeLine(int)
*/
public void addLine(String text);
void addLine(String text);
/**
* Removes line with specified index. Index starts at {@code 0} and ends at
@@ -78,12 +78,10 @@ public interface Scoreboard {
* @see #getLines()
* @see #addLine(String)
*/
public void removeLine(int index);
void removeLine(int index);
/**
* Unregisters this scoreboard from all players who can see it.
* Calling this method is equal to iterating over {@link #getPlayers()}
* and calling {@link #removePlayer(TabPlayer)} on each player.
*/
public void unregister();
void unregister();
}
@@ -23,7 +23,7 @@ public interface ScoreboardManager {
* Scoreboard {@code title} is limited to 32 characters on <1.13. If needed,
* it will be cut to 32 character for those players (after replacing
* placeholders). RGB is supported using any of the supported formats.
* Placholders are supported.
* Placeholders are supported.
* <p>
* {@code lines} will display in the same order as contained in the list.
* Client can only see up to 15 lines at a time, however you can define
@@ -39,7 +39,7 @@ public interface ScoreboardManager {
* @throws NullPointerException
* if {@code name} or {@code lines} is {@code null}
*/
public Scoreboard createScoreboard(String name, String title, List<String> lines);
Scoreboard createScoreboard(String name, String title, List<String> lines);
/**
* Returns map of registered scoreboards via config and API.
@@ -49,7 +49,7 @@ public interface ScoreboardManager {
*
* @return map of registered scoreboards
*/
public Map<String, Scoreboard> getRegisteredScoreboards();
Map<String, Scoreboard> getRegisteredScoreboards();
/**
* Displays scoreboard to defined player. This will disable all display
@@ -66,7 +66,7 @@ public interface ScoreboardManager {
* @see #hasCustomScoreboard(TabPlayer)
* @see #resetScoreboard(TabPlayer)
*/
public void showScoreboard(TabPlayer player, Scoreboard scoreboard);
void showScoreboard(TabPlayer player, Scoreboard scoreboard);
/**
* Returns {@code true} if player has custom scoreboard set using
@@ -79,7 +79,7 @@ public interface ScoreboardManager {
* @see #showScoreboard(TabPlayer, Scoreboard)
* @see #resetScoreboard(TabPlayer)
*/
public boolean hasCustomScoreboard(TabPlayer player);
boolean hasCustomScoreboard(TabPlayer player);
/**
* Hides custom scoreboard sent using {@link #showScoreboard(TabPlayer, Scoreboard)}
@@ -91,7 +91,7 @@ public interface ScoreboardManager {
* @see #showScoreboard(TabPlayer, Scoreboard)
* @see #hasCustomScoreboard(TabPlayer)
*/
public void resetScoreboard(TabPlayer player);
void resetScoreboard(TabPlayer player);
/**
* Returns {@code true} if player has scoreboard enabled, {@code false}
@@ -105,7 +105,7 @@ public interface ScoreboardManager {
* @see #setScoreboardVisible(TabPlayer, boolean, boolean)
* @see #toggleScoreboard(TabPlayer, boolean)
*/
public boolean hasScoreboardVisible(TabPlayer player);
boolean hasScoreboardVisible(TabPlayer player);
/**
* Sets scoreboard visibility of player to defined value. If visibility status
@@ -122,7 +122,7 @@ public interface ScoreboardManager {
* @see #toggleScoreboard(TabPlayer, boolean)
* @see #hasScoreboardVisible(TabPlayer)
*/
public void setScoreboardVisible(TabPlayer player, boolean visible, boolean sendToggleMessage);
void setScoreboardVisible(TabPlayer player, boolean visible, boolean sendToggleMessage);
/**
* Toggles scoreboard for specified player. If player had scoreboard visible,
@@ -136,7 +136,7 @@ public interface ScoreboardManager {
* @see #hasScoreboardVisible(TabPlayer)
* @see #setScoreboardVisible(TabPlayer, boolean, boolean)
*/
public void toggleScoreboard(TabPlayer player, boolean sendToggleMessage);
void toggleScoreboard(TabPlayer player, boolean sendToggleMessage);
/**
* Temporarily displays scoreboard to all players for specified amount of
@@ -151,5 +151,5 @@ public interface ScoreboardManager {
* if no scoreboard was found with such name or {@code duration}
* is < 0.
*/
public void announceScoreboard(String scoreboard, int duration);
void announceScoreboard(String scoreboard, int duration);
}
@@ -13,14 +13,14 @@ public interface ThreadManager {
* @param type - usage type to add cpu usage to
* @param task - the task
*/
public Future<Void> runMeasuredTask(String errorDescription, TabFeature feature, String type, Runnable task);
Future<Void> runMeasuredTask(String errorDescription, TabFeature feature, String type, Runnable task);
/**
* Runs task in a new thread
* @param errorDescription - description to use if this task throws an error
* @param task - the task
*/
public Future<Void> runTask(String errorDescription, Runnable task);
Future<Void> runTask(String errorDescription, Runnable task);
/**
* Starts a new task with defined repeat interval that measures cpu usage
@@ -30,7 +30,7 @@ public interface ThreadManager {
* @param type - usage type to add cpu usage to
* @param task - the task
*/
public RepeatingTask startRepeatingMeasuredTask(int intervalMilliseconds, String errorDescription, TabFeature feature, String type, Runnable task);
RepeatingTask startRepeatingMeasuredTask(int intervalMilliseconds, String errorDescription, TabFeature feature, String type, Runnable task);
/**
* Runs task with a delay and measures how long it took to process
@@ -40,7 +40,7 @@ public interface ThreadManager {
* @param type - usage type to add cpu usage to
* @param task - the task
*/
public Future<Void> runTaskLater(int delayMilliseconds, String errorDescription, TabFeature feature, String type, Runnable task);
Future<Void> runTaskLater(int delayMilliseconds, String errorDescription, TabFeature feature, String type, Runnable task);
/**
* Runs task with a delay and measures how long it took to process
@@ -50,7 +50,7 @@ public interface ThreadManager {
* @param type - usage type to add cpu usage to
* @param task - the task
*/
public Future<Void> runTaskLater(int delayMilliseconds, String errorDescription, String feature, String type, Runnable task);
Future<Void> runTaskLater(int delayMilliseconds, String errorDescription, String feature, String type, Runnable task);
public Future<Void> runTaskLater(int delayMilliseconds, String errorDescription, Runnable task);
Future<Void> runTaskLater(int delayMilliseconds, String errorDescription, Runnable task);
}
@@ -5,109 +5,109 @@ import me.neznamy.tab.api.TabPlayer;
public interface TeamManager {
/**
* Makes player's nametag globally invisible
* @see showNametag
* @see hasHiddenNametag
* Makes player's NameTag globally invisible
* @see #showNametag(TabPlayer)
* @see #hasHiddenNametag(TabPlayer)
*/
public void hideNametag(TabPlayer player);
void hideNametag(TabPlayer player);
/**
* Hides player's nametag for specified player until it's shown again
* @param viewer - player to hide nametag for
* Hides player's NameTag for specified player until it's shown again
* @param viewer - player to hide NameTag for
*/
public void hideNametag(TabPlayer player, TabPlayer viewer);
void hideNametag(TabPlayer player, TabPlayer viewer);
/**
* Makes player's nametag visible again
* @see hideNametag
* @see hasHiddenNametag
* Makes player's NameTag visible again
* @see #hideNametag(TabPlayer)
* @see #hasHiddenNametag(TabPlayer)
*/
public void showNametag(TabPlayer player);
void showNametag(TabPlayer player);
/**
* Shows player's nametag for specified viewer if it was hidden before
* @param viewer - player to show nametag back for
* Shows player's NameTag for specified viewer if it was hidden before
* @param viewer - player to show NameTag back for
*/
public void showNametag(TabPlayer player, TabPlayer viewer);
void showNametag(TabPlayer player, TabPlayer viewer);
/**
* Return whether player has hidden nametag or not
* @return Whether player has hidden nametag or not
* @see hideNametag
* @see showNametag
* Return whether player has hidden NameTag or not
* @return Whether player has hidden NameTag or not
* @see #hideNametag(TabPlayer)
* @see #showNametag(TabPlayer)
*/
public boolean hasHiddenNametag(TabPlayer player);
boolean hasHiddenNametag(TabPlayer player);
/**
* Returns true if nametag is hidden for specified viewer, false if not
* Returns true if NameTag is hidden for specified viewer, false if not
* @param viewer - player to check visibility status for
* @return true if hidden, false if not
*/
public boolean hasHiddenNametag(TabPlayer player, TabPlayer viewer);
boolean hasHiddenNametag(TabPlayer player, TabPlayer viewer);
/**
* Unregisters player's team and no longer handles it, as well as disables anti-override for teams.
* This can be resumed using resumeTeamHandling(). If team handling was paused already, nothing happens.
*/
public void pauseTeamHandling(TabPlayer player);
void pauseTeamHandling(TabPlayer player);
/**
* Resumes team handling if it was before paused using pauseTeamHandling(), if not, nothing happens
*/
public void resumeTeamHandling(TabPlayer player);
void resumeTeamHandling(TabPlayer player);
/**
* Returns true if team handling is paused for this player using pauseTeamHandling(), false if not or
* Returns true if team handling is paused for this player using pauseTeamHandling(), false if not, or
* it was resumed already using resumeTeamHandling
* @return true if paused, false if not
*/
public boolean hasTeamHandlingPaused(TabPlayer player);
boolean hasTeamHandlingPaused(TabPlayer player);
/**
* Forces new team name for the player until this method is called again with null argument and
* performs all actions to change player's team name
* @param teamName - forced team name
*/
public void forceTeamName(TabPlayer player, String teamName);
void forceTeamName(TabPlayer player, String teamName);
/**
* Returns forced team name of player or null if not forced
* @return forced team name of player or null if not forced
*/
public String getForcedTeamName(TabPlayer player);
String getForcedTeamName(TabPlayer player);
/**
* Forces collision rule for the player. Setting it to null will remove forced value
* @param collision - forced collision rule
*/
public void setCollisionRule(TabPlayer player, Boolean collision);
void setCollisionRule(TabPlayer player, Boolean collision);
/**
* Returns forced collision rule or null if collision is not forced using setCollisionRule
* @return forced value or null if not forced
*/
public Boolean getCollisionRule(TabPlayer player);
Boolean getCollisionRule(TabPlayer player);
/**
* Sends update team properties packet of player's team to everyone
* Sends update team's properties packet of player's team to everyone
* @param player - player to update team data of
*/
public void updateTeamData(TabPlayer player);
void updateTeamData(TabPlayer player);
public void setPrefix(TabPlayer player, String prefix);
void setPrefix(TabPlayer player, String prefix);
public void setSuffix(TabPlayer player, String suffix);
void setSuffix(TabPlayer player, String suffix);
public void resetPrefix(TabPlayer player);
void resetPrefix(TabPlayer player);
public void resetSuffix(TabPlayer player);
void resetSuffix(TabPlayer player);
public String getCustomPrefix(TabPlayer player);
String getCustomPrefix(TabPlayer player);
public String getCustomSuffix(TabPlayer player);
String getCustomSuffix(TabPlayer player);
public String getOriginalPrefix(TabPlayer player);
String getOriginalPrefix(TabPlayer player);
public String getOriginalSuffix(TabPlayer player);
String getOriginalSuffix(TabPlayer player);
}
@@ -6,27 +6,27 @@ import me.neznamy.tab.api.TabPlayer;
public interface UnlimitedNametagManager extends TeamManager {
public void disableArmorStands(TabPlayer player);
void disableArmorStands(TabPlayer player);
public void enableArmorStands(TabPlayer player);
void enableArmorStands(TabPlayer player);
public boolean hasDisabledArmorStands(TabPlayer player);
boolean hasDisabledArmorStands(TabPlayer player);
public void setName(TabPlayer player, String customname);
void setName(TabPlayer player, String customName);
public void setLine(TabPlayer player, String line, String value);
void setLine(TabPlayer player, String line, String value);
public void resetName(TabPlayer player);
void resetName(TabPlayer player);
public void resetLine(TabPlayer player, String line);
void resetLine(TabPlayer player, String line);
public String getCustomName(TabPlayer player);
String getCustomName(TabPlayer player);
public String getCustomLineValue(TabPlayer player, String line);
String getCustomLineValue(TabPlayer player, String line);
public String getOriginalName(TabPlayer player);
String getOriginalName(TabPlayer player);
public String getOriginalLineValue(TabPlayer player, String line);
String getOriginalLineValue(TabPlayer player, String line);
public List<String> getDefinedLines();
List<String> getDefinedLines();
}
@@ -0,0 +1,13 @@
package me.neznamy.tab.api.util;
public class Preconditions {
public static void checkNotNull(Object obj, String exceptionMessage){
if (obj == null) throw new IllegalArgumentException(exceptionMessage);
}
public static void checkRange(Number number, Number min, Number max){
if (number.doubleValue() < min.doubleValue() || number.doubleValue() > max.doubleValue())
throw new IllegalArgumentException("Number index out of range (" + min + " - " + max + ")");
}
}
@@ -1,5 +1,5 @@
plugins {
id("tab.base-conventions")
id("tab.standard-conventions")
id("com.github.johnrengelman.shadow")
}
@@ -1,18 +0,0 @@
plugins {
id("tab.base-conventions")
`maven-publish`
}
java {
withSourcesJar()
withJavadocJar()
}
publishing {
publications.create<MavenPublication>("mavenJava") {
groupId = rootProject.group as String
artifactId = project.name
version = rootProject.version as String
from(components["java"])
}
}
@@ -0,0 +1,31 @@
import gradle.kotlin.dsl.accessors._4cbb0020bd75d48acc42cabded5fdbb7.publishing
import org.gradle.api.artifacts.repositories.PasswordCredentials
import org.gradle.api.publish.maven.MavenPublication
import org.gradle.kotlin.dsl.get
import org.gradle.kotlin.dsl.repositories
plugins {
id("tab.base-conventions")
`maven-publish`
}
java {
withSourcesJar()
withJavadocJar()
}
publishing {
repositories {
maven {
name = "krypton"
url = uri("https://repo.kryptonmc.org/releases")
credentials(PasswordCredentials::class)
}
}
publications.create<MavenPublication>("mavenJava") {
groupId = rootProject.group as String
artifactId = "tab-${project.name}"
version = rootProject.version as String
from(components["java"])
}
}
+6
View File
@@ -15,9 +15,15 @@ val platforms = setOf(
projects.velocity
).map { it.dependencyProject }
val special = setOf(
projects.api,
projects.shared
).map { it.dependencyProject }
subprojects {
when (this) {
in platforms -> plugins.apply("tab.platform-conventions")
in special -> plugins.apply("tab.standard-conventions")
else -> plugins.apply("tab.base-conventions")
}
}
@@ -36,7 +36,6 @@ import me.neznamy.tab.api.protocol.PacketPlayOutPlayerInfo.PlayerInfoData;
import me.neznamy.tab.api.protocol.PacketPlayOutPlayerListHeaderFooter;
import me.neznamy.tab.api.protocol.PacketPlayOutScoreboardDisplayObjective;
import me.neznamy.tab.api.protocol.PacketPlayOutScoreboardObjective;
import me.neznamy.tab.api.protocol.PacketPlayOutScoreboardObjective.EnumScoreboardHealthDisplay;
import me.neznamy.tab.api.protocol.PacketPlayOutScoreboardScore;
import me.neznamy.tab.api.protocol.PacketPlayOutScoreboardTeam;
import me.neznamy.tab.platforms.bukkit.nms.NMSStorage;
@@ -95,7 +94,7 @@ public class BukkitPacketBuilder extends PacketBuilder {
@Override
public Object build(PacketPlayOutBoss packet, ProtocolVersion clientVersion) throws ReflectiveOperationException {
if (nms.getMinorVersion() >= 9 || clientVersion.getMinorVersion() >= 9) {
//1.9+ server or client, handled by bukkit api or viaversion
//1.9+ server or client, handled by bukkit api or ViaVersion
return packet;
}
//<1.9 client and server
@@ -209,9 +208,9 @@ public class BukkitPacketBuilder extends PacketBuilder {
nms.ScoreboardTeam_setAllowFriendlyFire.invoke(team, (packet.getOptions() & 0x1) > 0);
nms.ScoreboardTeam_setCanSeeFriendlyInvisibles.invoke(team, (packet.getOptions() & 0x2) > 0);
if (nms.getMinorVersion() >= 13) {
team = createTeamModern(packet, clientVersion, team, prefix, suffix);
createTeamModern(packet, clientVersion, team, prefix, suffix);
} else {
team = createTeamLegacy(packet, team, prefix, suffix);
createTeamLegacy(packet, team, prefix, suffix);
}
if (nms.getMinorVersion() >= 17) {
switch (packet.getMethod()) {
@@ -234,9 +233,9 @@ public class BukkitPacketBuilder extends PacketBuilder {
/**
* Builds entity destroy packet with given parameter
* @param id - entity id to destroy
* @return destroy packet
* @throws ReflectiveOperationException
* @throws ReflectiveOperationException
* if thrown by reflective operation
*/
public Object build(PacketPlayOutEntityDestroy packet) throws ReflectiveOperationException {
try {
@@ -253,13 +252,10 @@ public class BukkitPacketBuilder extends PacketBuilder {
/**
* Builds entity spawn packet with given parameters
* @param entityId - entity id
* @param uuid - entity uuid
* @param entityType - entity type
* @param loc - location to spawn at
* @param dataWatcher - datawatcher
*
* @return entity spawn packet
* @throws ReflectiveOperationException
* @throws ReflectiveOperationException
* if thrown by reflective operation
*/
public Object build(PacketPlayOutSpawnEntityLiving packet) throws ReflectiveOperationException {
Object nmsPacket;
@@ -290,10 +286,9 @@ public class BukkitPacketBuilder extends PacketBuilder {
/**
* Builds entity teleport packet with given parameters
* @param entityId - entity id
* @param location - location to teleport to
* @return entity teleport packet
* @throws ReflectiveOperationException
* @throws ReflectiveOperationException
* if thrown by reflective operation
*/
public Object build(PacketPlayOutEntityTeleport packet) throws ReflectiveOperationException {
Object nmsPacket;
@@ -317,22 +312,20 @@ public class BukkitPacketBuilder extends PacketBuilder {
return nmsPacket;
}
private Object createTeamModern(PacketPlayOutScoreboardTeam packet, ProtocolVersion clientVersion, Object team, String prefix, String suffix) throws ReflectiveOperationException {
private void createTeamModern(PacketPlayOutScoreboardTeam packet, ProtocolVersion clientVersion, Object team, String prefix, String suffix) throws ReflectiveOperationException {
if (prefix != null) nms.ScoreboardTeam_setPrefix.invoke(team, toNMSComponent(IChatBaseComponent.optimizedComponent(prefix), clientVersion));
if (suffix != null) nms.ScoreboardTeam_setSuffix.invoke(team, toNMSComponent(IChatBaseComponent.optimizedComponent(suffix), clientVersion));
EnumChatFormat format = packet.getColor() != null ? packet.getColor() : EnumChatFormat.lastColorsOf(prefix);
nms.ScoreboardTeam_setColor.invoke(team, nms.EnumChatFormat_values[format.ordinal()]);
nms.ScoreboardTeam_setNameTagVisibility.invoke(team, String.valueOf(packet.getNametagVisibility()).equals("always") ? nms.EnumNameTagVisibility_values[0] : nms.EnumNameTagVisibility_values[1]);
nms.ScoreboardTeam_setNameTagVisibility.invoke(team, String.valueOf(packet.getNameTagVisibility()).equals("always") ? nms.EnumNameTagVisibility_values[0] : nms.EnumNameTagVisibility_values[1]);
nms.ScoreboardTeam_setCollisionRule.invoke(team, String.valueOf(packet.getCollisionRule()).equals("always") ? nms.EnumTeamPush_values[0] : nms.EnumTeamPush_values[1]);
return team;
}
private Object createTeamLegacy(PacketPlayOutScoreboardTeam packet, Object team, String prefix, String suffix) throws ReflectiveOperationException {
private void createTeamLegacy(PacketPlayOutScoreboardTeam packet, Object team, String prefix, String suffix) throws ReflectiveOperationException {
if (prefix != null) nms.ScoreboardTeam_setPrefix.invoke(team, prefix);
if (suffix != null) nms.ScoreboardTeam_setSuffix.invoke(team, suffix);
if (nms.getMinorVersion() >= 8) nms.ScoreboardTeam_setNameTagVisibility.invoke(team, String.valueOf(packet.getNametagVisibility()).equals("always") ? nms.EnumNameTagVisibility_values[0] : nms.EnumNameTagVisibility_values[1]);
if (nms.getMinorVersion() >= 8) nms.ScoreboardTeam_setNameTagVisibility.invoke(team, String.valueOf(packet.getNameTagVisibility()).equals("always") ? nms.EnumNameTagVisibility_values[0] : nms.EnumNameTagVisibility_values[1]);
if (nms.getMinorVersion() >= 9) nms.ScoreboardTeam_setCollisionRule.invoke(team, String.valueOf(packet.getCollisionRule()).equals("always") ? nms.EnumTeamPush_values[0] : nms.EnumTeamPush_values[1]);
return team;
}
@Override
@@ -341,42 +334,27 @@ public class BukkitPacketBuilder extends PacketBuilder {
EnumPlayerInfoAction action = EnumPlayerInfoAction.valueOf(nms.PacketPlayOutPlayerInfo_ACTION.get(nmsPacket).toString());
List<PlayerInfoData> listData = new ArrayList<>();
for (Object nmsData : (List<?>) nms.PacketPlayOutPlayerInfo_PLAYERS.get(nmsPacket)) {
Object nmsGamemode = nms.PlayerInfoData_getGamemode.invoke(nmsData);
EnumGamemode gamemode = (nmsGamemode == null) ? null : EnumGamemode.valueOf(nmsGamemode.toString());
Object nmsGameMode = nms.PlayerInfoData_getGamemode.invoke(nmsData);
EnumGamemode gameMode = (nmsGameMode == null) ? null : EnumGamemode.valueOf(nmsGameMode.toString());
GameProfile profile = (GameProfile) nms.PlayerInfoData_getProfile.invoke(nmsData);
Object nmsComponent = nms.PlayerInfoData_getDisplayName.invoke(nmsData);
IChatBaseComponent listName = nmsComponent == null ? null : fromNMSComponent(nmsComponent);
PropertyMap map = new PropertyMap();
map.putAll(profile.getProperties());
listData.add(new PlayerInfoData(profile.getName(), profile.getId(), map, (int) nms.PlayerInfoData_getLatency.invoke(nmsData), gamemode, listName));
listData.add(new PlayerInfoData(profile.getName(), profile.getId(), map, (int) nms.PlayerInfoData_getLatency.invoke(nmsData), gameMode, listName));
}
return new PacketPlayOutPlayerInfo(action, listData);
}
@Override
public PacketPlayOutScoreboardObjective readObjective(Object nmsPacket, ProtocolVersion clientVersion) throws ReflectiveOperationException {
String objective = (String) nms.PacketPlayOutScoreboardObjective_OBJECTIVENAME.get(nmsPacket);
String displayName;
Object component = nms.PacketPlayOutScoreboardObjective_DISPLAYNAME.get(nmsPacket);
if (nms.getMinorVersion() >= 13) {
IChatBaseComponent c = component == null ? null : fromNMSComponent(component);
displayName = c == null ? null : c.toLegacyText();
} else {
displayName = (String) component;
}
EnumScoreboardHealthDisplay renderType = null;
if (nms.getMinorVersion() >= 8) {
Object nmsRender = nms.PacketPlayOutScoreboardObjective_RENDERTYPE.get(nmsPacket);
if (nmsRender != null) {
renderType = EnumScoreboardHealthDisplay.valueOf(nmsRender.toString());
}
}
int method = nms.PacketPlayOutScoreboardObjective_METHOD.getInt(nmsPacket);
return new PacketPlayOutScoreboardObjective(method, objective, displayName, renderType);
public PacketPlayOutScoreboardObjective readObjective(Object nmsPacket) throws ReflectiveOperationException {
return new PacketPlayOutScoreboardObjective(nms.PacketPlayOutScoreboardObjective_METHOD.getInt(nmsPacket),
(String) nms.PacketPlayOutScoreboardObjective_OBJECTIVENAME.get(nmsPacket), null, null
);
}
@Override
public PacketPlayOutScoreboardDisplayObjective readDisplayObjective(Object nmsPacket, ProtocolVersion clientVersion) throws ReflectiveOperationException {
public PacketPlayOutScoreboardDisplayObjective readDisplayObjective(Object nmsPacket) throws ReflectiveOperationException {
return new PacketPlayOutScoreboardDisplayObjective(
nms.PacketPlayOutScoreboardDisplayObjective_POSITION.getInt(nmsPacket),
(String) nms.PacketPlayOutScoreboardDisplayObjective_OBJECTIVENAME.get(nmsPacket)
@@ -384,11 +362,12 @@ public class BukkitPacketBuilder extends PacketBuilder {
}
/**
* Builds entity bossbar packet
* Builds entity BossBar packet
* @param packet - packet to build
* @param clientVersion - client version
* @return entity bossbar packet
* @throws ReflectiveOperationException
* @return entity BossBar packet
* @throws ReflectiveOperationException
* if thrown by reflective operation
*/
private Object buildBossPacketEntity(PacketPlayOutBoss packet, ProtocolVersion clientVersion) throws ReflectiveOperationException {
if (packet.getOperation() == Action.UPDATE_STYLE) return null; //nothing to do here
@@ -415,7 +394,7 @@ public class BukkitPacketBuilder extends PacketBuilder {
}
/**
* A method yoinked from minecraft code used to convert double to int
* A method taken from minecraft code used to convert double to int
* @param paramDouble double value
* @return int value
*/
@@ -425,10 +404,11 @@ public class BukkitPacketBuilder extends PacketBuilder {
}
/**
* Converts minecraft IChatBaseComponent into TAB's component class. Currently does not support show_item hover event on 1.16+.
* Converts minecraft IChatBaseComponent into TAB's component class. Currently, does not support show_item hover event on 1.16+.
* @param component - component to convert
* @return converted component
* @throws ReflectiveOperationException
* @throws ReflectiveOperationException
* if thrown by reflective operation
*/
private IChatBaseComponent fromNMSComponent(Object component) throws ReflectiveOperationException {
if (!nms.ChatComponentText.isInstance(component)) return null; //paper
@@ -484,11 +464,12 @@ public class BukkitPacketBuilder extends PacketBuilder {
}
/**
* Converts TAB's IChatBaseComponent into minecraft's component. Currently does not support hover event.
* Converts TAB's IChatBaseComponent into minecraft's component. Currently, does not support hover event.
* @param component - component to convert
* @param clientVersion - client version used to decide RGB conversion
* @return converted component
* @throws ReflectiveOperationException
* @throws ReflectiveOperationException
* if thrown by reflective operation
*/
public Object toNMSComponent(IChatBaseComponent component, ProtocolVersion clientVersion) throws ReflectiveOperationException {
Object obj;
@@ -33,7 +33,7 @@ public class BukkitPipelineInjector extends PipelineInjector {
public class BukkitChannelDuplexHandler extends ChannelDuplexHandler {
//injected player
private TabPlayer player;
private final TabPlayer player;
/**
* Constructs new instance with given player
@@ -65,8 +65,8 @@ public class BukkitPipelineInjector extends PipelineInjector {
super.write(context, packet, channelPromise);
return;
}
if (nms.PacketPlayOutScoreboardDisplayObjective.isInstance(packet) && TAB.getInstance().getFeatureManager().onDisplayObjective(player, packet)) {
return;
if (nms.PacketPlayOutScoreboardDisplayObjective.isInstance(packet)){
TAB.getInstance().getFeatureManager().onDisplayObjective(player, packet);
}
if (nms.PacketPlayOutScoreboardObjective.isInstance(packet)) {
TAB.getInstance().getFeatureManager().onObjective(player, packet);
@@ -85,7 +85,8 @@ public class BukkitPipelineInjector extends PipelineInjector {
/**
* Removes all real players from team if packet does not come from TAB and reports this to override log
* @param packetPlayOutScoreboardTeam - team packet
* @throws ReflectiveOperationException
* @throws ReflectiveOperationException
* nmsGameMode
*/
@SuppressWarnings("unchecked")
private void modifyPlayers(Object packetPlayOutScoreboardTeam) throws ReflectiveOperationException {
@@ -109,7 +110,7 @@ public class BukkitPipelineInjector extends PipelineInjector {
}
}
nms.setField(packetPlayOutScoreboardTeam, nms.PacketPlayOutScoreboardTeam_PLAYERS, newList);
TAB.getInstance().getCPUManager().addTime("Nametags", TabConstants.CpuUsageCategory.ANTI_OVERRIDE, System.nanoTime()-time);
TAB.getInstance().getCPUManager().addTime("NameTags", TabConstants.CpuUsageCategory.ANTI_OVERRIDE, System.nanoTime()-time);
}
private TabPlayer getPlayer(String name) {
@@ -117,6 +117,12 @@ public class BukkitPlaceholderRegistry implements PlaceholderRegistry {
if (essentials != null && ((Essentials)essentials).getUser(p.getUniqueId()).isAfk()) return true;
return purpur && ((Player)p.getPlayer()).isAfk();
});
manager.registerPlayerPlaceholder("%essentialsnick%", 1000, p -> {
String nickname = null;
if (essentials != null)
nickname = ((Essentials)essentials).getUser(p.getUniqueId()).getNickname();
return nickname == null || nickname.length() == 0 ? p.getName() : nickname;
});
if (chat != null) {
manager.registerPlayerPlaceholder("%vault-prefix%", 500, p -> ((Chat) chat).getPlayerPrefix((Player) p.getPlayer()));
manager.registerPlayerPlaceholder("%vault-suffix%", 500, p -> ((Chat) chat).getPlayerSuffix((Player) p.getPlayer()));
@@ -133,13 +139,13 @@ public class BukkitPlaceholderRegistry implements PlaceholderRegistry {
}
private void registerOnlinePlaceholders(PlaceholderManager manager) {
manager.registerPlayerPlaceholder("%online%", -1, p -> {
manager.registerPlayerPlaceholder("%online%", 1000, p -> {
int count = 0;
for (TabPlayer all : TAB.getInstance().getOnlinePlayers()){
if (((Player) p.getPlayer()).canSee((Player) all.getPlayer())) count++;
}
return count;
}).enableTriggerMode();
});
manager.registerPlayerPlaceholder("%staffonline%", 2000, p -> {
int count = 0;
for (TabPlayer all : TAB.getInstance().getOnlinePlayers()){
@@ -189,9 +195,7 @@ public class BukkitPlaceholderRegistry implements PlaceholderRegistry {
}
};
Bukkit.getPluginManager().registerEvents(healthListener, plugin);
}, () -> {
HandlerList.unregisterAll(healthListener);
});
}, () -> HandlerList.unregisterAll(healthListener));
}
}
}
@@ -18,7 +18,7 @@ import me.neznamy.tab.api.chat.EnumChatFormat;
import me.neznamy.tab.api.protocol.PacketBuilder;
import me.neznamy.tab.platforms.bukkit.event.TabLoadEvent;
import me.neznamy.tab.platforms.bukkit.event.TabPlayerLoadEvent;
import me.neznamy.tab.platforms.bukkit.features.PerWorldPlayerlist;
import me.neznamy.tab.platforms.bukkit.features.PerWorldPlayerList;
import me.neznamy.tab.platforms.bukkit.features.PetFix;
import me.neznamy.tab.platforms.bukkit.features.TabExpansion;
import me.neznamy.tab.platforms.bukkit.features.WitherBossBar;
@@ -38,7 +38,7 @@ import me.neznamy.tab.shared.placeholders.UniversalPlaceholderRegistry;
import net.milkbowl.vault.permission.Permission;
/**
* Bukkit implementation of Platform
* Bukkit's implementation of Platform interface
*/
public class BukkitPlatform implements Platform {
@@ -49,9 +49,7 @@ public class BukkitPlatform implements Platform {
//booleans to check plugin presence
private boolean placeholderAPI;
private boolean viaversion;
private boolean idisguise;
private boolean libsdisguises;
private boolean libsDisguises;
private Plugin essentials;
/**
@@ -80,7 +78,6 @@ public class BukkitPlatform implements Platform {
if (Bukkit.getPluginManager().isPluginEnabled("ViaVersion")) {
try {
Class.forName("com.viaversion.viaversion.api.Via");
viaversion = true;
} catch (ClassNotFoundException e) {
TAB.getInstance().sendConsoleMessage("&c[TAB] An outdated version of ViaVersion (" + getPluginVersion("ViaVersion") + ") was detected.", true);
TAB.getInstance().sendConsoleMessage("&c[TAB] TAB only supports ViaVersion 4.0.0 and above. Disabling ViaVersion hook.", true);
@@ -91,14 +88,13 @@ public class BukkitPlatform implements Platform {
TAB.getInstance().sendConsoleMessage("&c[TAB] Detected plugin \"Tablisknu\", which causes TAB to not work properly. Consider removing the plugin.", true);
}
placeholderAPI = Bukkit.getPluginManager().isPluginEnabled("PlaceholderAPI");
idisguise = Bukkit.getPluginManager().isPluginEnabled("iDisguise");
libsdisguises = Bukkit.getPluginManager().isPluginEnabled("LibsDisguises");
libsDisguises = Bukkit.getPluginManager().isPluginEnabled("LibsDisguises");
essentials = Bukkit.getPluginManager().getPlugin("Essentials");
TAB tab = TAB.getInstance();
if (tab.getConfiguration().isPipelineInjection()) tab.getFeatureManager().registerFeature("injection", new BukkitPipelineInjector());
new BukkitPlaceholderRegistry(plugin).registerPlaceholders(tab.getPlaceholderManager());
new UniversalPlaceholderRegistry().registerPlaceholders(tab.getPlaceholderManager());
loadNametagFeature(tab);
loadNameTagFeature(tab);
tab.loadUniversalFeatures();
if (tab.getConfiguration().getConfig().getBoolean("bossbar.enabled", false)) {
if (tab.getServerVersion().getMinorVersion() < 9) {
@@ -108,7 +104,7 @@ public class BukkitPlatform implements Platform {
}
}
if (tab.getServerVersion().getMinorVersion() >= 9 && tab.getConfiguration().getConfig().getBoolean("fix-pet-names.enabled", false)) tab.getFeatureManager().registerFeature("petfix", new PetFix());
if (tab.getConfiguration().getConfig().getBoolean("per-world-playerlist.enabled", false)) tab.getFeatureManager().registerFeature("pwp", new PerWorldPlayerlist(plugin));
if (tab.getConfiguration().getConfig().getBoolean("per-world-playerlist.enabled", false)) tab.getFeatureManager().registerFeature("pwp", new PerWorldPlayerList(plugin));
if (placeholderAPI) {
new TabExpansion(plugin);
}
@@ -122,10 +118,10 @@ public class BukkitPlatform implements Platform {
}
/**
* Loads nametag feature from config
* Loads NameTag feature from config
* @param tab - tab instance
*/
private void loadNametagFeature(TAB tab) {
private void loadNameTagFeature(TAB tab) {
if (tab.getConfiguration().getConfig().getBoolean("scoreboard-teams.enabled", true)) {
if (tab.getConfiguration().getConfig().getBoolean("scoreboard-teams.unlimited-nametag-mode.enabled", false) && tab.getServerVersion().getMinorVersion() >= 8) {
tab.getFeatureManager().registerFeature("nametagx", new NameTagX(plugin));
@@ -186,7 +182,8 @@ public class BukkitPlatform implements Platform {
if (!getForceUpdate().contains(p.getName())) getForceUpdate().add(p.getName());
TAB.getInstance().getCPUManager().addPlaceholderTime(getIdentifier(), System.nanoTime()-time);
});
return getLastValues().get(p.getName());
String value = getLastValues().get(p.getName());
return value == null ? identifier : value;
}
});
return;
@@ -227,20 +224,12 @@ public class BukkitPlatform implements Platform {
return Bukkit.getMaxPlayers();
}
public boolean isViaversionEnabled() {
return viaversion;
}
public boolean isLibsdisguisesEnabled() {
return libsdisguises;
public boolean isLibsDisguisesEnabled() {
return libsDisguises;
}
public void setLibsdisguisesEnabled(boolean enabled) {
libsdisguises = enabled;
}
public boolean isIdisguiseEnabled() {
return idisguise;
public void setLibsDisguisesEnabled(boolean enabled) {
libsDisguises = enabled;
}
public Essentials getEssentials() {
@@ -42,8 +42,8 @@ public class BukkitTabPlayer extends ITabPlayer {
private Object playerConnection;
//player's visible boss bars
private final Map<UUID, BossBar> bossbars = new HashMap<>();
private final Map<UUID, com.viaversion.viaversion.api.legacy.bossbar.BossBar> viaBossbars = new HashMap<>();
private final Map<UUID, BossBar> bossBars = new HashMap<>();
private final Map<UUID, com.viaversion.viaversion.api.legacy.bossbar.BossBar> viaBossBars = new HashMap<>();
/**
* Constructs new instance with given parameter
@@ -102,10 +102,11 @@ public class BukkitTabPlayer extends ITabPlayer {
}
private void handle(PacketPlayOutBoss packet) {
BossBar bar;
BossBar bar = bossBars.get(packet.getId());
if (bar == null && packet.getOperation() != PacketPlayOutBoss.Action.ADD) return; //no idea how
switch (packet.getOperation()) {
case ADD:
if (bossbars.containsKey(packet.getId())) return;
if (bossBars.containsKey(packet.getId())) return;
bar = Bukkit.createBossBar(RGBUtils.getInstance().convertToBukkitFormat(packet.getName(), getVersion().getMinorVersion() >= 16 && TAB.getInstance().getServerVersion().getMinorVersion() >= 16),
BarColor.valueOf(packet.getColor().name()),
BarStyle.valueOf(packet.getOverlay().getBukkitName()));
@@ -113,25 +114,25 @@ public class BukkitTabPlayer extends ITabPlayer {
if (packet.isDarkenScreen()) bar.addFlag(BarFlag.DARKEN_SKY);
if (packet.isPlayMusic()) bar.addFlag(BarFlag.PLAY_BOSS_MUSIC);
bar.setProgress(packet.getPct());
bossbars.put(packet.getId(), bar);
bossBars.put(packet.getId(), bar);
bar.addPlayer(getPlayer());
break;
case REMOVE:
bossbars.get(packet.getId()).removePlayer(getPlayer());
bossbars.remove(packet.getId());
bar.removePlayer(getPlayer());
bossBars.remove(packet.getId());
break;
case UPDATE_PCT:
bossbars.get(packet.getId()).setProgress(packet.getPct());
bar.setProgress(packet.getPct());
break;
case UPDATE_NAME:
bossbars.get(packet.getId()).setTitle(RGBUtils.getInstance().convertToBukkitFormat(packet.getName(), getVersion().getMinorVersion() >= 16 && TAB.getInstance().getServerVersion().getMinorVersion() >= 16));
bar.setTitle(RGBUtils.getInstance().convertToBukkitFormat(packet.getName(), getVersion().getMinorVersion() >= 16 && TAB.getInstance().getServerVersion().getMinorVersion() >= 16));
break;
case UPDATE_STYLE:
bossbars.get(packet.getId()).setColor(BarColor.valueOf(packet.getColor().name()));
bossbars.get(packet.getId()).setStyle(BarStyle.valueOf(packet.getOverlay().getBukkitName()));
bar.setColor(BarColor.valueOf(packet.getColor().name()));
bar.setStyle(BarStyle.valueOf(packet.getOverlay().getBukkitName()));
break;
case UPDATE_PROPERTIES:
bar = bossbars.get(packet.getId());
bar = bossBars.get(packet.getId());
processFlag(bar, packet.isCreateWorldFog(), BarFlag.CREATE_FOG);
processFlag(bar, packet.isDarkenScreen(), BarFlag.DARKEN_SKY);
processFlag(bar, packet.isPlayMusic(), BarFlag.PLAY_BOSS_MUSIC);
@@ -145,7 +146,7 @@ public class BukkitTabPlayer extends ITabPlayer {
com.viaversion.viaversion.api.legacy.bossbar.BossBar bar;
switch (packet.getOperation()) {
case ADD:
if (viaBossbars.containsKey(packet.getId())) return;
if (viaBossBars.containsKey(packet.getId())) return;
bar = Via.getAPI().legacyAPI().createLegacyBossBar(RGBUtils.getInstance().convertToBukkitFormat(packet.getName(), getVersion().getMinorVersion() >= 16),
packet.getPct(),
BossColor.valueOf(packet.getColor().name()),
@@ -153,25 +154,25 @@ public class BukkitTabPlayer extends ITabPlayer {
//fog missing from via API
if (packet.isDarkenScreen()) bar.addFlag(BossFlag.DARKEN_SKY);
if (packet.isPlayMusic()) bar.addFlag(BossFlag.PLAY_BOSS_MUSIC);
viaBossbars.put(packet.getId(), bar);
viaBossBars.put(packet.getId(), bar);
bar.addPlayer(getPlayer().getUniqueId());
break;
case REMOVE:
viaBossbars.get(packet.getId()).removePlayer(getPlayer().getUniqueId());
viaBossbars.remove(packet.getId());
viaBossBars.get(packet.getId()).removePlayer(getPlayer().getUniqueId());
viaBossBars.remove(packet.getId());
break;
case UPDATE_PCT:
viaBossbars.get(packet.getId()).setHealth(packet.getPct());
viaBossBars.get(packet.getId()).setHealth(packet.getPct());
break;
case UPDATE_NAME:
viaBossbars.get(packet.getId()).setTitle(RGBUtils.getInstance().convertToBukkitFormat(packet.getName(), getVersion().getMinorVersion() >= 16));
viaBossBars.get(packet.getId()).setTitle(RGBUtils.getInstance().convertToBukkitFormat(packet.getName(), getVersion().getMinorVersion() >= 16));
break;
case UPDATE_STYLE:
viaBossbars.get(packet.getId()).setColor(BossColor.valueOf(packet.getColor().name()));
viaBossbars.get(packet.getId()).setStyle(BossStyle.valueOf(packet.getOverlay().getBukkitName()));
viaBossBars.get(packet.getId()).setColor(BossColor.valueOf(packet.getColor().name()));
viaBossBars.get(packet.getId()).setStyle(BossStyle.valueOf(packet.getOverlay().getBukkitName()));
break;
case UPDATE_PROPERTIES:
bar = viaBossbars.get(packet.getId());
bar = viaBossBars.get(packet.getId());
//fog missing from via API
processFlagVia(bar, packet.isDarkenScreen(), BossFlag.DARKEN_SKY);
processFlagVia(bar, packet.isPlayMusic(), BossFlag.PLAY_BOSS_MUSIC);
@@ -213,12 +214,12 @@ public class BukkitTabPlayer extends ITabPlayer {
@Override
public boolean isDisguised() {
try {
if (!((BukkitPlatform)TAB.getInstance().getPlatform()).isLibsdisguisesEnabled()) return false;
if (!((BukkitPlatform)TAB.getInstance().getPlatform()).isLibsDisguisesEnabled()) return false;
return DisguiseAPI.isDisguised(getPlayer());
} catch (NoClassDefFoundError | ExceptionInInitializerError e) {
//java.lang.NoClassDefFoundError: Could not initialize class me.libraryaddict.disguise.DisguiseAPI
TAB.getInstance().getErrorManager().printError("Failed to check disguise status using LibsDisguises", e);
((BukkitPlatform)TAB.getInstance().getPlatform()).setLibsdisguisesEnabled(false);
((BukkitPlatform)TAB.getInstance().getPlatform()).setLibsDisguisesEnabled(false);
return false;
}
}
@@ -22,14 +22,15 @@ import me.neznamy.tab.api.chat.EnumChatFormat;
import me.neznamy.tab.platforms.bukkit.nms.NMSStorage;
import me.neznamy.tab.shared.TAB;
import me.neznamy.tab.shared.TabConstants;
import org.jetbrains.annotations.NotNull;
/**
* Main class for Bukkit platform
*/
public class Main extends JavaPlugin {
private boolean viaversion;
private boolean protocolsupport;
private boolean viaVersion;
private boolean protocolSupport;
@Override
public void onEnable(){
@@ -38,8 +39,8 @@ public class Main extends JavaPlugin {
Bukkit.getPluginManager().disablePlugin(this);
return;
}
viaversion = Bukkit.getPluginManager().isPluginEnabled("ViaVersion");
protocolsupport = Bukkit.getPluginManager().isPluginEnabled("ProtocolSupport");
viaVersion = Bukkit.getPluginManager().isPluginEnabled("ViaVersion");
protocolSupport = Bukkit.getPluginManager().isPluginEnabled("ProtocolSupport");
TAB.setInstance(new TAB(new BukkitPlatform(this), ProtocolVersion.fromFriendlyName(Bukkit.getBukkitVersion().split("-")[0])));
if (TAB.getInstance().getServerVersion() == ProtocolVersion.UNKNOWN) {
Bukkit.getConsoleSender().sendMessage(EnumChatFormat.color("&c[TAB] Unknown server version: " + Bukkit.getBukkitVersion() + "! Plugin may not work correctly."));
@@ -101,12 +102,12 @@ public class Main extends JavaPlugin {
* @return protocol version of this player
*/
public int getProtocolVersion(Player player) {
if (protocolsupport){
if (protocolSupport){
int version = getProtocolVersionPS(player);
//some PS versions return -1 on unsupported server versions instead of throwing exception
if (version != -1 && version < TAB.getInstance().getServerVersion().getNetworkId()) return version;
}
if (viaversion) {
if (viaVersion) {
return getProtocolVersionVia(player, 0);
}
return TAB.getInstance().getServerVersion().getNetworkId();
@@ -155,10 +156,10 @@ public class Main extends JavaPlugin {
}
}
public class TABCommand implements CommandExecutor, TabCompleter {
public static class TABCommand implements CommandExecutor, TabCompleter {
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
if (TAB.getInstance().isDisabled()) {
for (String message : TAB.getInstance().getDisabledCommand().execute(args, sender.hasPermission(TabConstants.Permission.COMMAND_RELOAD), sender.hasPermission(TabConstants.Permission.COMMAND_ALL))) {
sender.sendMessage(EnumChatFormat.color(message));
@@ -175,7 +176,7 @@ public class Main extends JavaPlugin {
}
@Override
public List<String> onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, String[] args) {
TabPlayer p = null;
if (sender instanceof Player) {
p = TAB.getInstance().getPlayer(((Player)sender).getUniqueId());
@@ -2,6 +2,7 @@ package me.neznamy.tab.platforms.bukkit.event;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import org.jetbrains.annotations.NotNull;
/**
* Bukkit event that is called each time TAB fully loads. This includes server startup, reload,
@@ -12,7 +13,7 @@ public class TabLoadEvent extends Event {
private static final HandlerList handlers = new HandlerList();
@Override
public HandlerList getHandlers(){
public @NotNull HandlerList getHandlers(){
return getHandlerList();
}
@@ -4,6 +4,7 @@ import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import me.neznamy.tab.api.TabPlayer;
import org.jetbrains.annotations.NotNull;
/**
* Bukkit event that is called when player is successfully loaded after joining. This also includes plugin reloading.
@@ -19,7 +20,7 @@ public class TabPlayerLoadEvent extends Event {
}
@Override
public HandlerList getHandlers(){
public @NotNull HandlerList getHandlers(){
return getHandlerList();
}
@@ -19,10 +19,10 @@ import me.neznamy.tab.shared.TabConstants;
import me.neznamy.tab.shared.TAB;
/**
* Per-world-playerlist feature handler
* Per-world-PlayerList feature handler
*/
@SuppressWarnings("deprecation")
public class PerWorldPlayerlist extends TabFeature implements Listener {
public class PerWorldPlayerList extends TabFeature implements Listener {
//plugin instance
private final JavaPlugin plugin;
@@ -36,10 +36,10 @@ public class PerWorldPlayerlist extends TabFeature implements Listener {
* Constructs new instance with given parameters and loads config options
* @param plugin - plugin instance
*/
public PerWorldPlayerlist(JavaPlugin plugin) {
super("Per world playerlist", null);
public PerWorldPlayerList(JavaPlugin plugin) {
super("Per world PlayerList", null);
this.plugin = plugin;
TAB.getInstance().debug(String.format("Loaded PerWorldPlayerlist feature with parameters allowBypass=%s, ignoredWorlds=%s, sharedWorlds=%s", allowBypass, ignoredWorlds, sharedWorlds));
TAB.getInstance().debug(String.format("Loaded PerWorldPlayerList feature with parameters allowBypass=%s, ignoredWorlds=%s, sharedWorlds=%s", allowBypass, ignoredWorlds, sharedWorlds));
Bukkit.getPluginManager().registerEvents(this, plugin);
}
@@ -1,5 +1,6 @@
package me.neznamy.tab.platforms.bukkit.features;
import java.util.ConcurrentModificationException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -12,8 +13,8 @@ import me.neznamy.tab.platforms.bukkit.nms.datawatcher.DataWatcherItem;
import me.neznamy.tab.shared.TAB;
/**
* A feature to disable minecraft 1.9+ feature making tamed animals with custom names copy nametag properties of their owner
* This is achieved by listening to entity spawn (<1.15) / entity metadata packets and removing owner field from the datawatcher list
* A feature to disable minecraft 1.9+ feature making tamed animals with custom names copy NameTag properties of their owner
* This is achieved by listening to entity spawn (<1.15) / entity metadata packets and removing owner field from the DataWatcher list
* Since 1.16 this results in client sending entity use packet twice, so we must cancel the 2nd one to prevent double toggle
*/
public class PetFix extends TabFeature {
@@ -21,7 +22,7 @@ public class PetFix extends TabFeature {
//nms storage
private final NMSStorage nms = NMSStorage.getInstance();
//datawatcher position of pet owner field
//DataWatcher position of pet owner field
private final int petOwnerPosition = getPetOwnerPosition();
//logger of last interacts to prevent feature not working on 1.16
@@ -60,7 +61,8 @@ public class PetFix extends TabFeature {
/**
* Cancels a packet if previous one arrived with no delay to prevent double toggle on 1.16
* @throws ReflectiveOperationException
* @throws ReflectiveOperationException
* if thrown by reflective operation
*/
@Override
public boolean onPacketReceive(TabPlayer sender, Object packet) throws ReflectiveOperationException {
@@ -86,8 +88,9 @@ public class PetFix extends TabFeature {
}
/**
* Removes pet owner field from datawatcher
* @throws ReflectiveOperationException
* Removes pet owner field from DataWatcher
* @throws ReflectiveOperationException
* if thrown by reflective operation
*/
@SuppressWarnings("unchecked")
@Override
@@ -96,14 +99,19 @@ public class PetFix extends TabFeature {
Object removedEntry = null;
List<Object> items = (List<Object>) nms.PacketPlayOutEntityMetadata_LIST.get(packet);
if (items == null) return;
for (Object item : items) {
if (item == null) continue;
if (nms.DataWatcherObject_SLOT.getInt(nms.DataWatcherItem_TYPE.get(item)) == petOwnerPosition) {
Object value = nms.DataWatcherItem_VALUE.get(item);
if (value instanceof java.util.Optional || value instanceof com.google.common.base.Optional) {
removedEntry = item;
try {
for (Object item : items) {
if (item == null) continue;
if (nms.DataWatcherObject_SLOT.getInt(nms.DataWatcherItem_TYPE.get(item)) == petOwnerPosition) {
Object value = nms.DataWatcherItem_VALUE.get(item);
if (value instanceof java.util.Optional || value instanceof com.google.common.base.Optional) {
removedEntry = item;
}
}
}
} catch (ConcurrentModificationException e) {
//no idea how can this list change in another thread since it's created for the packet but whatever, try again
onPacketSend(receiver, packet);
}
if (removedEntry != null) items.remove(removedEntry);
} else if (nms.PacketPlayOutSpawnEntityLiving.isInstance(packet) && nms.PacketPlayOutSpawnEntityLiving_DATAWATCHER != null) {
@@ -13,6 +13,7 @@ import me.neznamy.tab.api.scoreboard.Scoreboard;
import me.neznamy.tab.api.scoreboard.ScoreboardManager;
import me.neznamy.tab.shared.TAB;
import me.neznamy.tab.shared.features.scoreboard.ScoreboardManagerImpl;
import org.jetbrains.annotations.NotNull;
/**
* TAB's expansion for PlaceholderAPI
@@ -42,22 +43,22 @@ public class TabExpansion extends PlaceholderExpansion {
}
@Override
public String getAuthor(){
public @NotNull String getAuthor(){
return plugin.getDescription().getAuthors().toString();
}
@Override
public String getIdentifier(){
public @NotNull String getIdentifier(){
return "tab";
}
@Override
public String getVersion(){
public @NotNull String getVersion(){
return plugin.getDescription().getVersion();
}
@Override
public String onPlaceholderRequest(Player player, String identifier){
public String onPlaceholderRequest(Player player, @NotNull String identifier){
if (player == null) return "";
TabPlayer p = TAB.getInstance().getPlayer(player.getUniqueId());
if ("scoreboard_visible".equals(identifier)) {
@@ -1,6 +1,6 @@
package me.neznamy.tab.platforms.bukkit.features;
import java.util.Arrays;
import java.util.Collections;
import org.bukkit.Bukkit;
import org.bukkit.Location;
@@ -32,10 +32,10 @@ public class WitherBossBar extends BossBarManagerImpl implements Listener {
*/
public WitherBossBar(JavaPlugin plugin) {
Bukkit.getPluginManager().registerEvents(this, plugin);
//when MC is on fullscreen, bossbar disappears after 1 second of not being seen
//when MC is on fullscreen, BossBar disappears after 1 second of not being seen
//when in a small window, it's about 100ms
TAB.getInstance().getPlaceholderManager().registerPlayerPlaceholder("%location%", 100, p -> ((Player)p.getPlayer()).getLocation());
addUsedPlaceholders(Arrays.asList("%location%"));
addUsedPlaceholders(Collections.singletonList("%location%"));
}
@Override
@@ -27,11 +27,11 @@ import me.neznamy.tab.shared.TAB;
*/
public class BukkitArmorStand implements ArmorStand {
private static boolean alwaysVisible = TAB.getInstance().getConfiguration().isArmorStandsAlwaysVisible();
private final boolean alwaysVisible = TAB.getInstance().getConfiguration().isArmorStandsAlwaysVisible();
//entity id counter to pick unique entity IDs
private static int idCounter = 2000000000;
//nametag feature
//NameTag feature
private final NameTagX manager = (NameTagX) TAB.getInstance().getFeatureManager().getFeature("nametagx");
//owner of the armor stand
@@ -59,7 +59,7 @@ public class BukkitArmorStand implements ArmorStand {
private final Property property;
//if offset is static or dynamic based on other armor stands
private boolean staticOffset;
private final boolean staticOffset;
//entity destroy packet
private final PacketPlayOutEntityDestroy destroyPacket = new PacketPlayOutEntityDestroy(entityId);
@@ -149,7 +149,7 @@ public class BukkitArmorStand implements ArmorStand {
this.sneaking = sneaking;
for (TabPlayer viewer : owner.getArmorStandManager().getNearbyPlayers()) {
if (viewer.getVersion().getMinorVersion() == 14 && !alwaysVisible) {
//1.14.x client sided bug, despawning completely
//1.14.x client sided bug, de-spawning completely
if (sneaking) {
viewer.sendCustomPacket(destroyPacket, TabConstants.PacketCategory.UNLIMITED_NAMETAGS_SNEAK);
} else {
@@ -196,7 +196,7 @@ public class BukkitArmorStand implements ArmorStand {
/**
* Returns general visibility rule for everyone with limited info
* @return true if should be visible, false if not
* @return true if armor stand should be visible, false if not
*/
public boolean getVisibility() {
if (owner.isDisguised() || manager.getVehicleManager().isOnBoat(owner)) return false;
@@ -261,7 +261,7 @@ public class BukkitArmorStand implements ArmorStand {
* Creates data watcher with specified display name for viewer
* @param displayName - armor stand name
* @param viewer - player to apply checks against
* @return datawatcher for viewer
* @return DataWatcher for viewer
*/
public DataWatcher createDataWatcher(String displayName, TabPlayer viewer) {
DataWatcher datawatcher = new DataWatcher();
@@ -299,7 +299,6 @@ public class BukkitArmorStand implements ArmorStand {
/**
* Returns list of packets to send to make armor stand spawn with metadata
* @param viewer - viewer to apply relational placeholders for
* @param addToRegistered - if player should be added to registered or not
* @return List of packets that spawn the armor stand
*/
public TabPacket[] getSpawnPackets(TabPlayer viewer) {
@@ -16,19 +16,19 @@ import me.neznamy.tab.shared.TAB;
*/
public class EventListener implements Listener {
//the nametag feature handler
//the NameTag feature handler
private final NameTagX feature;
/**
* Constructs new instance with given parameters
* @param feature - nametagx feature handler
* @param feature - NameTag feature handler
*/
public EventListener(NameTagX feature) {
this.feature = feature;
}
/**
* Sneak event listener to despawn & spawn armor stands to skip animation
* Sneak event listener to de-spawn & spawn armor stands to skip animation
* @param e - sneak event
*/
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
@@ -1,6 +1,6 @@
package me.neznamy.tab.platforms.bukkit.features.unlimitedtags;
import java.util.Arrays;
import java.util.Collections;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
@@ -23,7 +23,7 @@ public class LocationRefresher extends TabFeature {
Location l = ((Player)p.getPlayer()).getLocation();
return l.getX()+l.getY()+l.getZ(); //less cpu usage than literal Location#toString() and then .equals() when comparing last value
});
addUsedPlaceholders(Arrays.asList("%location0%")); //making sure it's not the same one as in WiherBossBar
addUsedPlaceholders(Collections.singletonList("%location0%")); //making sure it's not the same one as in WitherBossBar
}
@Override
@@ -24,7 +24,7 @@ import me.neznamy.tab.shared.TabConstants;
import me.neznamy.tab.shared.features.nametags.NameTag;
/**
* The core class for unlimited nametag mode
* The core class for unlimited NameTag mode
*/
public class NameTagX extends NameTag implements UnlimitedNametagManager {
@@ -53,15 +53,14 @@ public class NameTagX extends NameTag implements UnlimitedNametagManager {
/**
* Constructs new instance with given parameters and loads config options
* @param plugin - plugin instance
* @param nms - nms storage
*/
public NameTagX(JavaPlugin plugin) {
Collections.reverse(dynamicLines);
Bukkit.getPluginManager().registerEvents(eventListener, plugin);
TAB.getInstance().getFeatureManager().registerFeature("nametagx-packet", new PacketListener(this));
TAB.getInstance().getFeatureManager().registerFeature("nametagx-vehicle", vehicleManager);
TAB.getInstance().getFeatureManager().registerFeature("nametagx-location", new LocationRefresher(this));
TAB.getInstance().debug(String.format("Loaded Unlimited nametag feature with parameters markerFor18x=%s, disableOnBoats=%s, spaceBetweenLines=%s, disabledUnlimitedWorlds=%s",
TAB.getInstance().getFeatureManager().registerFeature("NameTagX-packet", new PacketListener(this));
TAB.getInstance().getFeatureManager().registerFeature("NameTagX-vehicle", vehicleManager);
TAB.getInstance().getFeatureManager().registerFeature("NameTagX-location", new LocationRefresher(this));
TAB.getInstance().debug(String.format("Loaded Unlimited NameTag feature with parameters markerFor18x=%s, disableOnBoats=%s, spaceBetweenLines=%s, disabledUnlimitedWorlds=%s",
markerFor18x, disableOnBoats, spaceBetweenLines, disabledUnlimitedWorlds));
}
@@ -85,7 +84,7 @@ public class NameTagX extends NameTag implements UnlimitedNametagManager {
}
private void startVisibilityRefreshTask() {
TAB.getInstance().getCPUManager().startRepeatingMeasuredTask(500, "refreshing nametag visibility", this, TabConstants.CpuUsageCategory.REFRESHING_NAMETAG_VISIBILITY, () -> {
TAB.getInstance().getCPUManager().startRepeatingMeasuredTask(500, "refreshing NameTag visibility", this, TabConstants.CpuUsageCategory.REFRESHING_NAMETAG_VISIBILITY, () -> {
for (TabPlayer p : TAB.getInstance().getOnlinePlayers()) {
if (!p.isLoaded() || isPlayerDisabled(p)) continue;
@@ -152,7 +151,7 @@ public class NameTagX extends NameTag implements UnlimitedNametagManager {
* @param sendMutually - if packets should be sent both ways
*/
public void spawnArmorStands(TabPlayer owner, TabPlayer viewer, boolean sendMutually) {
if (owner == viewer) return; //not displaying own armorstands
if (owner == viewer) return; //not displaying own armor stands
if (((Player) viewer.getPlayer()).getWorld() != ((Player) owner.getPlayer()).getWorld()) return; //different world
if (isPlayerDisabled(owner)) return;
if (getDistance(viewer, owner) <= 48) {
@@ -246,12 +245,13 @@ public class NameTagX extends NameTag implements UnlimitedNametagManager {
@Override
public String getFeatureName() {
return "Unlimited Nametags";
return "Unlimited NameTags";
}
@Override
public boolean getTeamVisibility(TabPlayer p, TabPlayer viewer) {
if (p.hasInvisibilityPotion()) return false; //1.8.x client sided bug
if (vehicleManager == null) return false; //class is still being initialized and this was called from super constructor
return vehicleManager.isOnBoat(p) || isPlayerDisabled(p);
}
@@ -329,35 +329,35 @@ public class NameTagX extends NameTag implements UnlimitedNametagManager {
@Override
public void setPrefix(TabPlayer player, String prefix) {
player.getProperty(TabConstants.Property.TAGPREFIX).setTemporaryValue(prefix);
rebuildNametagLine(player);
rebuildNameTagLine(player);
player.forceRefresh();
}
@Override
public void setSuffix(TabPlayer player, String suffix) {
player.getProperty(TabConstants.Property.TAGSUFFIX).setTemporaryValue(suffix);
rebuildNametagLine(player);
rebuildNameTagLine(player);
player.forceRefresh();
}
@Override
public void resetPrefix(TabPlayer player) {
player.getProperty(TabConstants.Property.TAGPREFIX).setTemporaryValue(null);
rebuildNametagLine(player);
rebuildNameTagLine(player);
player.forceRefresh();
}
@Override
public void resetSuffix(TabPlayer player) {
player.getProperty(TabConstants.Property.TAGSUFFIX).setTemporaryValue(null);
rebuildNametagLine(player);
rebuildNameTagLine(player);
player.forceRefresh();
}
@Override
public void setName(TabPlayer player, String customname) {
player.getProperty(TabConstants.Property.CUSTOMTAGNAME).setTemporaryValue(customname);
rebuildNametagLine(player);
public void setName(TabPlayer player, String customName) {
player.getProperty(TabConstants.Property.CUSTOMTAGNAME).setTemporaryValue(customName);
rebuildNameTagLine(player);
player.forceRefresh();
}
@@ -370,7 +370,7 @@ public class NameTagX extends NameTag implements UnlimitedNametagManager {
@Override
public void resetName(TabPlayer player) {
player.getProperty(TabConstants.Property.CUSTOMTAGNAME).setTemporaryValue(null);
rebuildNametagLine(player);
rebuildNameTagLine(player);
player.forceRefresh();
}
@@ -400,7 +400,7 @@ public class NameTagX extends NameTag implements UnlimitedNametagManager {
return player.getProperty(line).getOriginalRawValue();
}
private void rebuildNametagLine(TabPlayer player) {
private void rebuildNameTagLine(TabPlayer player) {
player.setProperty(this, TabConstants.Property.NAMETAG, player.getProperty(TabConstants.Property.TAGPREFIX).getCurrentRawValue() +
player.getProperty(TabConstants.Property.CUSTOMTAGNAME).getCurrentRawValue() + player.getProperty(TabConstants.Property.TAGSUFFIX).getCurrentRawValue());
}
@@ -13,7 +13,7 @@ import me.neznamy.tab.shared.TAB;
/**
* The packet listening part for securing proper functionality of armor stands
* Bukkit events are too unreliable and delayed/ahead which causes desync
* Bukkit events are too unreliable and delayed/ahead which causes de-sync
*/
public class PacketListener extends TabFeature {
@@ -119,8 +119,8 @@ public class PacketListener extends TabFeature {
}
private void onEntityDestroy(TabPlayer receiver, int entity) {
TabPlayer despawnedPlayer = nameTagX.getEntityIdMap().get(entity);
if (despawnedPlayer != null && despawnedPlayer.isLoaded() && !nameTagX.isPlayerDisabled(despawnedPlayer))
TAB.getInstance().getCPUManager().runMeasuredTask("processing EntityDestroy", nameTagX, TabConstants.CpuUsageCategory.PACKET_ENTITY_DESTROY, () -> despawnedPlayer.getArmorStandManager().destroy(receiver));
TabPlayer deSpawnedPlayer = nameTagX.getEntityIdMap().get(entity);
if (deSpawnedPlayer != null && deSpawnedPlayer.isLoaded() && !nameTagX.isPlayerDisabled(deSpawnedPlayer))
TAB.getInstance().getCPUManager().runMeasuredTask("processing EntityDestroy", nameTagX, TabConstants.CpuUsageCategory.PACKET_ENTITY_DESTROY, () -> deSpawnedPlayer.getArmorStandManager().destroy(receiver));
}
}
@@ -1,9 +1,6 @@
package me.neznamy.tab.platforms.bukkit.features.unlimitedtags;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import org.bukkit.entity.Entity;
@@ -30,7 +27,7 @@ public class VehicleRefresher extends TabFeature {
public VehicleRefresher(NameTagX feature) {
super(feature.getFeatureName(), "Refreshing vehicles");
this.feature = feature;
addUsedPlaceholders(Arrays.asList("%vehicle%"));
addUsedPlaceholders(Collections.singletonList("%vehicle%"));
TAB.getInstance().getPlaceholderManager().registerPlayerPlaceholder("%vehicle%", 100, p -> ((Player)p.getPlayer()).getVehicle());
}
@@ -86,7 +83,7 @@ public class VehicleRefresher extends TabFeature {
return vehicle.getPassengers();
} else {
if (vehicle.getPassenger() != null) {
return Arrays.asList(vehicle.getPassenger());
return Collections.singletonList(vehicle.getPassenger());
} else {
return new ArrayList<>();
}
@@ -98,8 +95,8 @@ public class VehicleRefresher extends TabFeature {
* @param p - player to load passengers of
*/
public void loadPassengers(TabPlayer p) {
if (((Entity) p.getPlayer()).getVehicle() == null) return;
Entity vehicle = ((Entity) p.getPlayer()).getVehicle();
if (vehicle == null) return;
vehicles.put(vehicle.getEntityId(), getPassengers(vehicle));
}
@@ -45,7 +45,6 @@ public final class NMSStorage {
public final Class<?> EntityPlayer = getNMSClass("net.minecraft.server.level.EntityPlayer", "EntityPlayer");
private final Class<?> Entity = getNMSClass("net.minecraft.world.entity.Entity", "Entity");
private final Class<?> EntityLiving = getNMSClass("net.minecraft.world.entity.EntityLiving", "EntityLiving");
private final Class<?> NetworkManager = getNMSClass("net.minecraft.network.NetworkManager", "NetworkManager");
private final Class<?> PlayerConnection = getNMSClass("net.minecraft.server.network.PlayerConnection", "PlayerConnection");
public Constructor<?> newEntityArmorStand;
public final Field PING = getField(EntityPlayer, "ping", "latency", "field_71138_i", "field_13967", "e");
@@ -224,9 +223,11 @@ public final class NMSStorage {
/**
* Creates new instance, initializes required NMS classes and fields
* @throws ReflectiveOperationException
* @throws ReflectiveOperationException
* If any class, field or method fails to load
*/
public NMSStorage() throws ReflectiveOperationException {
Class<?> NetworkManager = getNMSClass("net.minecraft.network.NetworkManager", "NetworkManager");
if (minorVersion >= 7) {
NETWORK_MANAGER = getFields(PlayerConnection, NetworkManager).get(0);
}
@@ -255,7 +256,7 @@ public final class NMSStorage {
* Sets new instance
* @param instance - new instance
*/
public final static void setInstance(NMSStorage instance) {
public static void setInstance(NMSStorage instance) {
NMSStorage.instance = instance;
}
@@ -263,11 +264,11 @@ public final class NMSStorage {
* Returns instance
* @return instance
*/
public final static NMSStorage getInstance() {
public static NMSStorage getInstance() {
return instance;
}
private final void initializeChatComponents() throws ReflectiveOperationException {
private void initializeChatComponents() throws ReflectiveOperationException {
if (minorVersion < 7) return;
Class<?> ChatBaseComponent = getNMSClass("net.minecraft.network.chat.ChatBaseComponent", "ChatBaseComponent");
Class<?> ChatClickable = getNMSClass("net.minecraft.network.chat.ChatClickable", "ChatClickable");
@@ -318,7 +319,7 @@ public final class NMSStorage {
}
}
private final void initializeChatPacket() throws ReflectiveOperationException {
private void initializeChatPacket() throws ReflectiveOperationException {
Class<?> PacketPlayOutChat = getNMSClass("net.minecraft.network.protocol.game.PacketPlayOutChat", "PacketPlayOutChat", "Packet3Chat");
if (minorVersion >= 12) {
ChatMessageType = getNMSClass("net.minecraft.network.chat.ChatMessageType", "ChatMessageType");
@@ -335,7 +336,7 @@ public final class NMSStorage {
}
}
private final void initializeDataWatcher() throws ReflectiveOperationException {
private void initializeDataWatcher() throws ReflectiveOperationException {
if (minorVersion >= 9) {
Class<?> DataWatcherObject = getNMSClass("net.minecraft.network.syncher.DataWatcherObject", "DataWatcherObject");
DataWatcherRegistry = getNMSClass("net.minecraft.network.syncher.DataWatcherRegistry", "DataWatcherRegistry");
@@ -352,7 +353,7 @@ public final class NMSStorage {
registry = new DataWatcherRegistry(this);
}
private final void initializeEntityPackets() throws ReflectiveOperationException {
private void initializeEntityPackets() throws ReflectiveOperationException {
if (minorVersion >= 17 || serverVersion.getMinorVersion() >= 17) {
newPacketPlayOutSpawnEntityLiving = PacketPlayOutSpawnEntityLiving.getConstructor(EntityLiving);
newPacketPlayOutEntityTeleport = PacketPlayOutEntityTeleport.getConstructor(Entity);
@@ -395,7 +396,7 @@ public final class NMSStorage {
}
}
private final void initializeHeaderFooterPacket() throws ReflectiveOperationException {
private void initializeHeaderFooterPacket() throws ReflectiveOperationException {
if (minorVersion < 8) return;
Class<?> PacketPlayOutPlayerListHeaderFooter = getNMSClass("net.minecraft.network.protocol.game.PacketPlayOutPlayerListHeaderFooter", "PacketPlayOutPlayerListHeaderFooter");
PacketPlayOutPlayerListHeaderFooter_HEADER = getFields(PacketPlayOutPlayerListHeaderFooter, IChatBaseComponent).get(0);
@@ -407,7 +408,7 @@ public final class NMSStorage {
}
}
private final void initializePlayerInfoPacket() throws ReflectiveOperationException {
private void initializePlayerInfoPacket() throws ReflectiveOperationException {
if (minorVersion < 8) return;
PacketPlayOutPlayerInfo = getNMSClass("net.minecraft.network.protocol.game.PacketPlayOutPlayerInfo", "PacketPlayOutPlayerInfo");
Class<?> EnumPlayerInfoAction = getNMSClass("net.minecraft.network.protocol.game.PacketPlayOutPlayerInfo$EnumPlayerInfoAction", "PacketPlayOutPlayerInfo$EnumPlayerInfoAction", "EnumPlayerInfoAction", "net.minecraft.class_2703$class_5893");
@@ -425,7 +426,7 @@ public final class NMSStorage {
EnumGamemode_values = getEnumValues(EnumGamemode);
}
private final void initializeScoreboardPackets() throws ReflectiveOperationException {
private void initializeScoreboardPackets() throws ReflectiveOperationException {
List<Field> list = getFields(PacketPlayOutScoreboardObjective, int.class);
PacketPlayOutScoreboardObjective_METHOD = list.get(list.size()-1);
Class<?> EnumScoreboardAction = null;
@@ -452,7 +453,7 @@ public final class NMSStorage {
}
}
private final void initializeTeamPackets() throws ReflectiveOperationException {
private void initializeTeamPackets() throws ReflectiveOperationException {
PacketPlayOutScoreboardTeam = getNMSClass("net.minecraft.network.protocol.game.PacketPlayOutScoreboardTeam", "PacketPlayOutScoreboardTeam", "Packet209SetScoreboardTeam");
Class<?> ScoreboardTeam = getNMSClass("net.minecraft.world.scores.ScoreboardTeam", "ScoreboardTeam");
newScoreboardTeam = ScoreboardTeam.getConstructor(Scoreboard, String.class);
@@ -519,14 +520,14 @@ public final class NMSStorage {
private Class<?> getLegacyClass(String name) throws ClassNotFoundException {
try {
return Class.forName("net.minecraft.server." + serverPackage + "." + name);
} catch (ClassNotFoundException e) {
} catch (ClassNotFoundException | NullPointerException e) {
try {
//modded server?
Class<?> clazz = Main.class.getClassLoader().loadClass("net.minecraft.server." + serverPackage + "." + name);
if (clazz != null) return clazz;
throw new ClassNotFoundException(name);
} catch (ClassNotFoundException e1) {
//fabric
} catch (ClassNotFoundException | NullPointerException e1) {
//maybe fabric?
return Class.forName(name);
}
}
@@ -558,7 +559,10 @@ public final class NMSStorage {
Class<?>[] types = m.getParameterTypes();
boolean valid = true;
for (int i=0; i<types.length; i++) {
if (types[i] != parameterTypes[i]) valid = false;
if (types[i] != parameterTypes[i]) {
valid = false;
break;
}
}
if (valid) list.add(m);
}
@@ -573,7 +577,10 @@ public final class NMSStorage {
Class<?>[] types = m.getParameterTypes();
boolean valid = true;
for (int i=0; i<types.length; i++) {
if (types[i] != parameterTypes[i]) valid = false;
if (types[i] != parameterTypes[i]) {
valid = false;
break;
}
}
if (valid) list.add(m);
}
@@ -11,7 +11,7 @@ import me.neznamy.tab.platforms.bukkit.nms.NMSStorage;
*/
public class DataWatcher {
//datawatcher data
//DataWatcher data
private final Map<Integer, DataWatcherItem> dataValues = new HashMap<>();
//a helper for easier data write
@@ -54,7 +54,8 @@ public class DataWatcher {
/**
* Converts the class into an instance of NMS.DataWatcher
* @return an instance of NMS.DataWatcher with same data
* @throws ReflectiveOperationException
* @throws ReflectiveOperationException
* if thrown by reflective operation
*/
public Object toNMS() throws ReflectiveOperationException {
NMSStorage nms = NMSStorage.getInstance();
@@ -79,9 +80,10 @@ public class DataWatcher {
/**
* Reads NMS data watcher and returns and instance of this class with same data
* @param nmsWatcher - NMS datawatcher to read
* @param nmsWatcher - NMS DataWatcher to read
* @return an instance of this class with same values
* @throws ReflectiveOperationException
* @throws ReflectiveOperationException
* if thrown by reflective operation
*/
@SuppressWarnings("unchecked")
public static DataWatcher fromNMS(Object nmsWatcher) throws ReflectiveOperationException {
@@ -9,14 +9,14 @@ import me.neznamy.tab.platforms.bukkit.nms.NMSStorage;
import me.neznamy.tab.shared.TAB;
/**
* A class to help assigning DataWatcher items as positions often change per-version
* A class to help to assign DataWatcher items as positions often change per-version
*/
public class DataWatcherHelper {
//position of armor stand flags
private final int armorStandFlagsPosition = getArmorStandFlagsPosition();
//original datawatcher to write to
//original DataWatcher to write to
private final DataWatcher data;
//data watcher registry
@@ -25,7 +25,8 @@ public class DataWatcherItem {
* Returns and instance of this class from given NMS item
* @param nmsItem - NMS item
* @return instance of this class with same data
* @throws ReflectiveOperationException
* @throws ReflectiveOperationException
* if thrown by reflective operation
*/
public static DataWatcherItem fromNMS(Object nmsItem) throws ReflectiveOperationException {
NMSStorage nms = NMSStorage.getInstance();
@@ -5,7 +5,7 @@ package me.neznamy.tab.platforms.bukkit.nms.datawatcher;
*/
public class DataWatcherObject {
//position in datawatcher
//position in DataWatcher
private final int position;
//value class type used since 1.9
@@ -13,7 +13,7 @@ public class DataWatcherObject {
/**
* Constructs a new instance of this class with given parameters
* @param position - position in datawatcher
* @param position - position in DataWatcher
* @param classType - value class type
*/
public DataWatcherObject(int position, Object classType){
@@ -11,7 +11,7 @@ import net.md_5.bungee.event.EventHandler;
import net.md_5.bungee.event.EventPriority;
/**
* The core for bungeecord forwarding events into all enabled features
* The core for BungeeCord forwarding events into all enabled features
*/
public class BungeeEventListener implements Listener {
@@ -33,13 +33,14 @@ public class BungeeEventListener implements Listener {
/**
* Listener to join / server switch to forward the event to all features
* @param e
* @param e
* switch event
*/
@EventHandler(priority = EventPriority.LOW)
public void onSwitch(ServerSwitchEvent e){
if (TAB.getInstance().isDisabled()) return;
if (TAB.getInstance().getPlayer(e.getPlayer().getUniqueId()) == null) {
TAB.getInstance().getFeatureManager().onJoin(new BungeeTabPlayer(e.getPlayer(), plm));
TAB.getInstance().getFeatureManager().onJoin(new BungeeTabPlayer(e.getPlayer()));
} else {
TAB.getInstance().getFeatureManager().onServerChange(e.getPlayer().getUniqueId(), e.getPlayer().getServer().getInfo().getName());
}
@@ -47,7 +48,8 @@ public class BungeeEventListener implements Listener {
/**
* Listener to chat packets to forward the event to all features
* @param e
* @param e
* chat event
*/
@EventHandler
public void onChat(ChatEvent e) {
@@ -18,7 +18,6 @@ import me.neznamy.tab.api.protocol.PacketPlayOutScoreboardTeam;
import me.neznamy.tab.api.protocol.PacketPlayOutPlayerInfo.EnumGamemode;
import me.neznamy.tab.api.protocol.PacketPlayOutPlayerInfo.EnumPlayerInfoAction;
import me.neznamy.tab.api.protocol.PacketPlayOutPlayerInfo.PlayerInfoData;
import me.neznamy.tab.api.protocol.PacketPlayOutScoreboardObjective.EnumScoreboardHealthDisplay;
import net.md_5.bungee.protocol.packet.BossBar;
import net.md_5.bungee.protocol.packet.Chat;
import net.md_5.bungee.protocol.packet.PlayerListHeaderFooter;
@@ -107,10 +106,10 @@ public class BungeePacketBuilder extends PacketBuilder {
public Object build(PacketPlayOutScoreboardTeam packet, ProtocolVersion clientVersion) {
int color = 0;
if (clientVersion.getMinorVersion() >= 13) {
color = (packet.getColor() != null ? packet.getColor() : EnumChatFormat.lastColorsOf(packet.getPlayerPrefix())).getNetworkId();
color = (packet.getColor() != null ? packet.getColor() : EnumChatFormat.lastColorsOf(packet.getPlayerPrefix())).ordinal();
}
return new Team(packet.getName(), (byte)packet.getMethod(), jsonOrCut(packet.getName(), clientVersion, 16), jsonOrCut(packet.getPlayerPrefix(), clientVersion, 16), jsonOrCut(packet.getPlayerSuffix(), clientVersion, 16),
packet.getNametagVisibility(), packet.getCollisionRule(), color, (byte)packet.getOptions(), packet.getPlayers().toArray(new String[0]));
packet.getNameTagVisibility(), packet.getCollisionRule(), color, (byte)packet.getOptions(), packet.getPlayers().toArray(new String[0]));
}
@Override
@@ -124,20 +123,12 @@ public class BungeePacketBuilder extends PacketBuilder {
}
@Override
public PacketPlayOutScoreboardObjective readObjective(Object bungeePacket, ProtocolVersion clientVersion) {
ScoreboardObjective packet = (ScoreboardObjective) bungeePacket;
String title;
if (clientVersion.getMinorVersion() >= 13) {
title = packet.getValue() == null ? null : IChatBaseComponent.deserialize(packet.getValue()).toLegacyText();
} else {
title = packet.getValue();
}
EnumScoreboardHealthDisplay renderType = (packet.getType() == null ? null : EnumScoreboardHealthDisplay.valueOf(packet.getType().toString().toUpperCase()));
return new PacketPlayOutScoreboardObjective(packet.getAction(), packet.getName(), title, renderType);
public PacketPlayOutScoreboardObjective readObjective(Object bungeePacket) {
return new PacketPlayOutScoreboardObjective(((ScoreboardObjective) bungeePacket).getAction(), ((ScoreboardObjective) bungeePacket).getName(), null, null);
}
@Override
public PacketPlayOutScoreboardDisplayObjective readDisplayObjective(Object bungeePacket, ProtocolVersion clientVersion){
public PacketPlayOutScoreboardDisplayObjective readDisplayObjective(Object bungeePacket){
return new PacketPlayOutScoreboardDisplayObjective(((ScoreboardDisplay) bungeePacket).getPosition(), ((ScoreboardDisplay) bungeePacket).getName());
}
}
@@ -28,7 +28,7 @@ import net.md_5.bungee.protocol.packet.Team;
public class BungeePipelineInjector extends PipelineInjector {
//packets that must be deserialized and bungeecord does not do it automatically
//packets that must be deserialized and BungeeCord does not do it automatically
private final Map<Class<? extends DefinedPacket>, Supplier<DefinedPacket>> extraPackets = new HashMap<>();
/**
@@ -48,7 +48,7 @@ public class BungeePipelineInjector extends PipelineInjector {
public class BungeeChannelDuplexHandler extends ChannelDuplexHandler {
//injected player
private TabPlayer player;
private final TabPlayer player;
/**
* Constructs new instance with given player
@@ -61,7 +61,7 @@ public class BungeePipelineInjector extends PipelineInjector {
@Override
public void write(ChannelHandlerContext context, Object packet, ChannelPromise channelPromise) {
long time = System.nanoTime();
Object modifiedPacket = packet instanceof ByteBuf && bytebufDeserialization ? deserialize((ByteBuf) packet) : packet;
Object modifiedPacket = packet instanceof ByteBuf && byteBufDeserialization ? deserialize((ByteBuf) packet) : packet;
TAB.getInstance().getCPUManager().addTime("Packet deserializing", TabConstants.CpuUsageCategory.BYTEBUF, System.nanoTime()-time);
try {
switch(modifiedPacket.getClass().getSimpleName()) {
@@ -74,9 +74,7 @@ public class BungeePipelineInjector extends PipelineInjector {
}
break;
case "ScoreboardDisplay":
if (TAB.getInstance().getFeatureManager().onDisplayObjective(player, modifiedPacket)) {
return;
}
TAB.getInstance().getFeatureManager().onDisplayObjective(player, modifiedPacket);
break;
case "ScoreboardObjective":
TAB.getInstance().getFeatureManager().onObjective(player, modifiedPacket);
@@ -124,7 +122,7 @@ public class BungeePipelineInjector extends PipelineInjector {
}
}
packet.setPlayers(col.toArray(new String[0]));
TAB.getInstance().getCPUManager().addTime("Nametags", TabConstants.CpuUsageCategory.ANTI_OVERRIDE, System.nanoTime()-time);
TAB.getInstance().getCPUManager().addTime("NameTags", TabConstants.CpuUsageCategory.ANTI_OVERRIDE, System.nanoTime()-time);
}
private String getName(TabPlayer p) {
@@ -136,10 +134,10 @@ public class BungeePipelineInjector extends PipelineInjector {
}
/**
* Deserializes bytebuf in case it is one of the tracked packets coming from backend server and returns it.
* Deserializes byte buf in case it is one of the tracked packets coming from backend server and returns it.
* If the packet is not one of them, returns input
* @param buf - bytebuf to deserialize
* @return deserialized packet or input bytebuf if packet is not tracked
* @param buf - byte buf to deserialize
* @return deserialized packet or input byte buf if packet is not tracked
*/
private Object deserialize(ByteBuf buf) {
int marker = buf.readerIndex();
@@ -11,7 +11,7 @@ import net.md_5.bungee.api.config.ServerInfo;
import net.md_5.bungee.api.connection.ProxiedPlayer;
/**
* Bungeecord registry to register bungeecord-only placeholders
* BungeeCord registry to register BungeeCord-only placeholders
*/
public class BungeePlaceholderRegistry extends ProxyPlaceholderRegistry {
@@ -22,7 +22,7 @@ import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.plugin.Plugin;
/**
* Bungeecord implementation of Platform
* BungeeCord implementation of Platform
*/
public class BungeePlatform extends ProxyPlatform {
@@ -63,7 +63,7 @@ public class BungeePlatform extends ProxyPlatform {
tab.getFeatureManager().registerFeature("redisbungee", new RedisBungeeSupport(plugin));
}
for (ProxiedPlayer p : ProxyServer.getInstance().getPlayers()) {
tab.addPlayer(new BungeeTabPlayer(p, plm));
tab.addPlayer(new BungeeTabPlayer(p));
}
}
@@ -27,9 +27,6 @@ public class BungeeTabPlayer extends ProxyTabPlayer {
private static Object directionData;
private static Method getId;
/**
* Initializes fields to get player channel later
*/
static {
try {
Field f = Protocol.class.getDeclaredField("TO_CLIENT");
@@ -46,10 +43,10 @@ public class BungeeTabPlayer extends ProxyTabPlayer {
/**
* Constructs new instance for given player
* @param p - bungeecord player
* @param p - BungeeCord player
*/
public BungeeTabPlayer(ProxiedPlayer p, PluginMessageHandler plm) {
super(plm, p, p.getUniqueId(), p.getName(), p.getServer() != null ? p.getServer().getInfo().getName() : "-", "N/A");
public BungeeTabPlayer(ProxiedPlayer p) {
super(p, p.getUniqueId(), p.getName(), p.getServer() != null ? p.getServer().getInfo().getName() : "-");
try {
channel = ((ChannelWrapper) wrapperField.get(getPlayer().getPendingConnection())).getHandle();
} catch (IllegalAccessException e) {
@@ -61,7 +61,7 @@ public class Main extends Plugin {
/**
* TAB command for bungeecord
*/
public class BTABCommand extends Command implements TabExecutor {
public static class BTABCommand extends Command implements TabExecutor {
/**
* Constructs new instance
@@ -4,7 +4,7 @@ import me.neznamy.tab.api.TabPlayer;
import net.md_5.bungee.api.plugin.Event;
/**
* Bungeecord event that is called when player is successfully loaded after joining. This also includes plugin reloading.
* BungeeCord event that is called when player is successfully loaded after joining. This also includes plugin reloading.
*/
public class TabPlayerLoadEvent extends Event {
@@ -23,9 +23,9 @@ import me.neznamy.tab.api.protocol.PacketPlayOutPlayerInfo.PlayerInfoData;
import me.neznamy.tab.api.protocol.PacketPlayOutScoreboardTeam;
import me.neznamy.tab.shared.TAB;
import me.neznamy.tab.shared.TabConstants;
import me.neznamy.tab.shared.features.Playerlist;
import me.neznamy.tab.shared.features.PlayerList;
import me.neznamy.tab.shared.features.RedisSupport;
import me.neznamy.tab.shared.features.globalplayerlist.GlobalPlayerlist;
import me.neznamy.tab.shared.features.globalplayerlist.GlobalPlayerList;
import me.neznamy.tab.shared.features.nametags.NameTag;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.config.ServerInfo;
@@ -39,8 +39,8 @@ public class RedisBungeeSupport extends TabFeature implements RedisSupport, List
private static final String CHANNEL_NAME = "TAB";
private final Map<String, RedisPlayer> redisPlayers = new ConcurrentHashMap<>();
private final GlobalPlayerlist global = (GlobalPlayerlist) TAB.getInstance().getFeatureManager().getFeature("globalplayerlist");
private final Playerlist playerlist = (Playerlist) TAB.getInstance().getFeatureManager().getFeature("playerlist");
private final GlobalPlayerList global = (GlobalPlayerList) TAB.getInstance().getFeatureManager().getFeature("globalplayerlist");
private final PlayerList playerlist = (PlayerList) TAB.getInstance().getFeatureManager().getFeature("playerlist");
private final NameTag nametags = (NameTag) TAB.getInstance().getFeatureManager().getFeature("nametag16");
private final UUID proxy = UUID.randomUUID();
@@ -324,7 +324,7 @@ public class RedisBungeeSupport extends TabFeature implements RedisSupport, List
}
@Override
public void updateBelowname(TabPlayer p, String value) {
public void updateBelowName(TabPlayer p, String value) {
JSONObject json = new JSONObject();
json.put("proxy", proxy.toString());
json.put("action", "belowname");
@@ -387,7 +387,7 @@ public class RedisBungeeSupport extends TabFeature implements RedisSupport, List
return redisPlayers;
}
public Playerlist getPlayerlist() {
public PlayerList getPlayerlist() {
return playerlist;
}
@@ -1,6 +1,6 @@
package me.neznamy.tab.platforms.bungeecord.redisbungee;
import java.util.Arrays;
import java.util.Collections;
import java.util.UUID;
import org.json.simple.JSONObject;
@@ -23,20 +23,20 @@ import me.neznamy.tab.shared.features.nametags.NameTag;
public class RedisPlayer {
private RedisBungeeSupport redis;
private boolean disabledPlayerlist;
private boolean disabledNametags;
private boolean disabledPlayerList;
private boolean disabledNameTags;
private UUID uniqueId;
private String name;
private String server;
private String tabformat;
private String tabFormat;
private String teamName;
private boolean vanished;
private String[][] skin;
private String tagprefix;
private String tagsuffix;
private boolean namevisibility;
private String belowname;
private String tagPrefix;
private String tagSuffix;
private boolean nameVisibility;
private String belowName;
private String yellowNumber;
private boolean staff;
@@ -49,7 +49,7 @@ public class RedisPlayer {
player.uniqueId = UUID.fromString((String) json.get("UUID"));
player.name = (String) json.get("name");
player.server = (String) json.get("server");
player.tabformat = (String) json.get("tabformat");
player.tabFormat = (String) json.get("tabformat");
player.teamName = (String) json.get("teamname");
player.vanished = (boolean) json.get("vanished");
String skinValue = (String) json.get("skin-value");
@@ -61,14 +61,14 @@ public class RedisPlayer {
} else {
player.skin = new String[0][0];
}
player.tagprefix = (String) json.get("tagprefix");
player.tagsuffix = (String) json.get("tagsuffix");
player.namevisibility = (boolean) json.get("namevisibility");
player.belowname = (String) json.get("belowname");
player.tagPrefix = (String) json.get("tagprefix");
player.tagSuffix = (String) json.get("tagsuffix");
player.nameVisibility = (boolean) json.get("namevisibility");
player.belowName = (String) json.get("belowname");
player.yellowNumber = (String) json.get("yellow-number");
player.staff = (boolean) json.get("staff");
player.disabledPlayerlist = redis.getPlayerlist() == null || redis.getPlayerlist().isDisabled(player.server, null);
player.disabledNametags = redis.getNametags() == null || redis.getNametags().isDisabled(player.server, null);
player.disabledPlayerList = redis.getPlayerlist() == null || redis.getPlayerlist().isDisabled(player.server, null);
player.disabledNameTags = redis.getNametags() == null || redis.getNametags().isDisabled(player.server, null);
return player;
}
@@ -110,11 +110,11 @@ public class RedisPlayer {
public PacketPlayOutPlayerInfo getAddPacket() {
return new PacketPlayOutPlayerInfo(EnumPlayerInfoAction.ADD_PLAYER, new PlayerInfoData(name, uniqueId, skin, 0, EnumGamemode.SURVIVAL,
disabledPlayerlist ? null : IChatBaseComponent.optimizedComponent(tabformat)));
disabledPlayerList ? null : IChatBaseComponent.optimizedComponent(tabFormat)));
}
public PacketPlayOutPlayerInfo getUpdatePacket() {
return new PacketPlayOutPlayerInfo(EnumPlayerInfoAction.UPDATE_DISPLAY_NAME, new PlayerInfoData(uniqueId, disabledPlayerlist ? null : IChatBaseComponent.optimizedComponent(tabformat)));
return new PacketPlayOutPlayerInfo(EnumPlayerInfoAction.UPDATE_DISPLAY_NAME, new PlayerInfoData(uniqueId, disabledPlayerList ? null : IChatBaseComponent.optimizedComponent(tabFormat)));
}
public PacketPlayOutPlayerInfo getRemovePacket() {
@@ -124,23 +124,23 @@ public class RedisPlayer {
}
public PacketPlayOutScoreboardTeam getRegisterTeamPacket() {
if (disabledNametags) return null;
return new PacketPlayOutScoreboardTeam(teamName, tagprefix, tagsuffix, namevisibility ? "always" : "never", "always", Arrays.asList(name), 0);
if (disabledNameTags) return null;
return new PacketPlayOutScoreboardTeam(teamName, tagPrefix, tagSuffix, nameVisibility ? "always" : "never", "always", Collections.singletonList(name), 0);
}
public PacketPlayOutScoreboardTeam getUpdateTeamPacket() {
if (disabledNametags) return null;
return new PacketPlayOutScoreboardTeam(teamName, tagprefix, tagsuffix, namevisibility ? "always" : "never", "always", 0);
if (disabledNameTags) return null;
return new PacketPlayOutScoreboardTeam(teamName, tagPrefix, tagSuffix, nameVisibility ? "always" : "never", "always", 0);
}
public PacketPlayOutScoreboardTeam getUnregisterTeamPacket() {
if (disabledNametags) return null;
if (disabledNameTags) return null;
return new PacketPlayOutScoreboardTeam(teamName);
}
public PacketPlayOutScoreboardScore getBelowNameUpdatePacket() {
if (belowname == null) return null;
return new PacketPlayOutScoreboardScore(Action.CHANGE, BelowName.OBJECTIVE_NAME, name, TAB.getInstance().getErrorManager().parseInteger(belowname, 0, "belowname number"));
if (belowName == null) return null;
return new PacketPlayOutScoreboardScore(Action.CHANGE, BelowName.OBJECTIVE_NAME, name, TAB.getInstance().getErrorManager().parseInteger(belowName, 0, "belowname number"));
}
public PacketPlayOutScoreboardScore getYellowNumberUpdatePacket() {
@@ -155,9 +155,9 @@ public class RedisPlayer {
public void setServer(String server) {
this.server = server;
if (redis.getPlayerlist() != null) {
if (disabledPlayerlist) {
if (disabledPlayerList) {
if (!redis.getPlayerlist().isDisabled(server, null)) {
disabledPlayerlist = false;
disabledPlayerList = false;
for (TabPlayer all : TAB.getInstance().getOnlinePlayers()) {
if (all.getVersion().getMinorVersion() < 8) continue;
all.sendCustomPacket(getUpdatePacket(), redis);
@@ -165,7 +165,7 @@ public class RedisPlayer {
}
} else {
if (redis.getPlayerlist().isDisabled(server, null)) {
disabledPlayerlist = true;
disabledPlayerList = true;
for (TabPlayer all : TAB.getInstance().getOnlinePlayers()) {
if (all.getVersion().getMinorVersion() < 8) continue;
all.sendCustomPacket(getUpdatePacket(), redis);
@@ -174,16 +174,16 @@ public class RedisPlayer {
}
}
if (redis.getNametags() != null) {
if (disabledNametags) {
if (disabledNameTags) {
if (!redis.getNametags().isDisabled(server, null)) {
disabledNametags = false;
disabledNameTags = false;
for (TabPlayer all : TAB.getInstance().getOnlinePlayers()) {
all.sendCustomPacket(getRegisterTeamPacket(), redis);
}
}
} else {
if (redis.getNametags().isDisabled(server, null)) {
disabledNametags = true;
disabledNameTags = true;
for (TabPlayer all : TAB.getInstance().getOnlinePlayers()) {
all.sendCustomPacket(getUnregisterTeamPacket(), redis);
}
@@ -201,7 +201,7 @@ public class RedisPlayer {
}
public String getTabFormat() {
return tabformat;
return tabFormat;
}
public String getTeamName() {
@@ -209,29 +209,25 @@ public class RedisPlayer {
}
public void setTabFormat(String format) {
this.tabformat = format;
this.tabFormat = format;
}
public void setTagPrefix(String tagprefix) {
this.tagprefix = tagprefix;
this.tagPrefix = tagprefix;
}
public void setTagSuffix(String tagsuffix) {
this.tagsuffix = tagsuffix;
this.tagSuffix = tagsuffix;
}
public void setBelowName(String belowname) {
this.belowname = belowname;
this.belowName = belowname;
}
public UUID getUniqueId() {
return uniqueId;
}
public String getYellowNumber() {
return yellowNumber;
}
public void setYellowNumber(String yellowNumber) {
this.yellowNumber = yellowNumber;
}
@@ -241,7 +237,7 @@ public class RedisPlayer {
}
public boolean hasDisabledPlayerlist() {
return disabledPlayerlist;
return disabledPlayerList;
}
public void setTeamName(String teamName) {
+3 -2
View File
@@ -1,6 +1,7 @@
name: @name@
main: me.neznamy.tab.platforms.bungeecord.Main
version: @version@
description: @description@
author: NEZNAMY
softDepends: [RedisBungee]
description: @description@
depends: []
softDepends: [RedisBungee, LuckPerms, PremiumVanish]
+1 -1
View File
@@ -1,5 +1,5 @@
# Project properties - we put these here so they can be modified without causing a recompile of the build scripts
projectVersion=3.0.0
projectVersion=3.0.1
# Gradle properties
org.gradle.daemon=true
+2 -2
View File
@@ -18,7 +18,7 @@ kotlin = "1.6.0"
# Platforms
bukkit = "1.16.5-R0.1-SNAPSHOT"
bungeecord = "1.18-R0.1-SNAPSHOT"
krypton = "0.50.2"
krypton = "0.58"
velocity = "1.1.0"
# Platform extras
@@ -38,7 +38,7 @@ redisBungee = "0.6.5-SNAPSHOT"
netty = { group = "io.netty", name = "netty-all", version.ref = "netty" }
jsonSimple = { group = "com.googlecode.json-simple", name = "json-simple", version.ref = "jsonSimple" }
snakeyaml = { group = "org.yaml", name = "snakeyaml", version.ref = "snakeyaml" }
yamlAssist = { group = "com.github.NEZNAMY", name = "YamlAssist", version.ref = "yamlAssist" }
yamlAssist = { group = "me.neznamy", name = "yamlassist", version.ref = "yamlAssist" }
gson = { group = "com.google.code.gson", name = "gson", version.ref = "gson" }
# General
+3 -1
View File
@@ -6,7 +6,9 @@ plugins {
dependencies {
implementation(projects.shared)
compileOnly(libs.krypton.api)
compileOnly(libs.krypton.server)
compileOnly(libs.krypton.server) {
exclude("ca.spottedleaf", "dataconverter")
}
compileOnly(libs.kotlin.stdlib)
compileOnly(libs.via)
kapt(libs.krypton.annotationProcessor)
@@ -15,8 +15,7 @@ import me.neznamy.tab.api.protocol.PacketPlayOutScoreboardTeam
import net.kyori.adventure.text.Component
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer
import org.kryptonmc.api.auth.ProfileProperty
import org.kryptonmc.api.registry.Registries
import org.kryptonmc.api.world.GameModes
import org.kryptonmc.api.world.GameMode
import org.kryptonmc.krypton.packet.out.play.PacketOutDisplayObjective
import org.kryptonmc.krypton.packet.out.play.PacketOutObjective
import org.kryptonmc.krypton.packet.out.play.PacketOutPlayerInfo
@@ -45,7 +44,7 @@ object KryptonPacketBuilder : PacketBuilder() {
it.uniqueId,
it.name ?: "",
it.skin as? List<ProfileProperty> ?: emptyList(),
Registries.GAME_MODES[(it.gameMode?.ordinal ?: 0) - 1] ?: GameModes.SURVIVAL,
GameMode.fromId((it.gameMode?.ordinal ?: 0) - 1) ?: GameMode.SURVIVAL,
it.latency,
if (displayName != null) GsonComponentSerializer.gson().deserialize(displayName) else Component.empty()
)
@@ -91,7 +90,7 @@ object KryptonPacketBuilder : PacketBuilder() {
toComponent(suffix, clientVersion),
packet.options and 1 > 0,
packet.options and 2 > 0,
packet.nametagVisibility ?: "",
packet.nameTagVisibility ?: "",
packet.collisionRule ?: "",
players,
if (action == PacketOutTeam.Action.ADD_MEMBERS || action == PacketOutTeam.Action.REMOVE_MEMBERS) players else emptySet()
@@ -102,21 +101,20 @@ object KryptonPacketBuilder : PacketBuilder() {
if (packet !is PacketOutPlayerInfo) return null
val action = PacketPlayOutPlayerInfo.EnumPlayerInfoAction.valueOf(packet.action.name)
val listData = packet.players.map {
val mode = PacketPlayOutPlayerInfo.EnumGamemode.valueOf(it.gameMode.key().value().uppercase())
val listName = IChatBaseComponent.deserialize(GsonComponentSerializer.gson().serialize(it.displayName))
val serializedListName = if (it.displayName != null) GsonComponentSerializer.gson().serialize(it.displayName!!) else null
PacketPlayOutPlayerInfo.PlayerInfoData(
it.name,
it.uuid,
it.properties,
it.latency,
mode,
listName
PacketPlayOutPlayerInfo.EnumGamemode.values()[it.gameMode.ordinal + 1],
if (serializedListName != null) IChatBaseComponent.deserialize(serializedListName) else null
)
}
return PacketPlayOutPlayerInfo(action, listData)
}
override fun readObjective(packet: Any?, clientVersion: ProtocolVersion?): PacketPlayOutScoreboardObjective? = null
override fun readObjective(packet: Any?): PacketPlayOutScoreboardObjective? = null
override fun readDisplayObjective(packet: Any?, clientVersion: ProtocolVersion?): PacketPlayOutScoreboardDisplayObjective? = null
override fun readDisplayObjective(packet: Any?): PacketPlayOutScoreboardDisplayObjective? = null
}
@@ -12,12 +12,12 @@ import java.util.function.Function
class KryptonPipelineInjector : PipelineInjector("handler") {
init {
channelFunction = Function { KryptonChannelDuplexHandler(it) }
channelFunction = Function(::KryptonChannelDuplexHandler)
}
inner class KryptonChannelDuplexHandler(private val player: TabPlayer) : ChannelDuplexHandler() {
override fun channelRead(ctx: ChannelHandlerContext?, msg: Any?) {
override fun channelRead(ctx: ChannelHandlerContext, msg: Any) {
try {
if (TAB.getInstance().featureManager.onPacketReceive(player, msg)) return
super.channelRead(ctx, msg)
@@ -26,7 +26,7 @@ class KryptonPipelineInjector : PipelineInjector("handler") {
}
}
override fun write(ctx: ChannelHandlerContext?, msg: Any?, promise: ChannelPromise?) {
override fun write(ctx: ChannelHandlerContext, msg: Any, promise: ChannelPromise) {
try {
if (msg is PacketOutPlayerInfo) {
super.write(ctx, TAB.getInstance().featureManager.onPacketPlayOutPlayerInfo(player, msg), promise)
@@ -39,7 +39,7 @@ class KryptonPipelineInjector : PipelineInjector("handler") {
try {
super.write(ctx, msg, promise)
} catch (exception: Exception) {
TAB.getInstance().errorManager.printError("Failed to forward packet ${msg?.javaClass?.simpleName} to ${player.name}", exception)
TAB.getInstance().errorManager.printError("Failed to forward packet ${msg.javaClass.simpleName} to ${player.name}", exception)
}
}
}
@@ -22,40 +22,40 @@ class KryptonPlaceholderRegistry(private val plugin: Main) : PlaceholderRegistry
// TPS
val tps = plugin.server.spark.tps()!!
manager.registerServerPlaceholder("%tps_5s%", 5000) { format(tps.poll(TicksPerSecond.SECONDS_5)) }
manager.registerServerPlaceholder("%tps_10s%", 10000) { format(tps.poll(TicksPerSecond.SECONDS_10)) }
manager.registerServerPlaceholder("%tps_1m%", 1000000) { format(tps.poll(TicksPerSecond.MINUTES_1)) }
manager.registerServerPlaceholder("%tps_5m%", 5000000) { format(tps.poll(TicksPerSecond.MINUTES_5)) }
manager.registerServerPlaceholder("%tps_15m%", 15000000) { format(tps.poll(TicksPerSecond.MINUTES_15)) }
manager.registerServerPlaceholder("%tps_5s%", 1000) { format(tps.poll(TicksPerSecond.SECONDS_5)) }
manager.registerServerPlaceholder("%tps_10s%", 1000) { format(tps.poll(TicksPerSecond.SECONDS_10)) }
manager.registerServerPlaceholder("%tps_1m%", 1000) { format(tps.poll(TicksPerSecond.MINUTES_1)) }
manager.registerServerPlaceholder("%tps_5m%", 1000) { format(tps.poll(TicksPerSecond.MINUTES_5)) }
manager.registerServerPlaceholder("%tps_15m%", 1000) { format(tps.poll(TicksPerSecond.MINUTES_15)) }
// MSPT
val mspt = plugin.server.spark.mspt()!!
manager.registerServerPlaceholder("%mspt_min_10s%", 10000) { formatMSPT(mspt.poll(MillisPerTick.SECONDS_10).min()) }
manager.registerServerPlaceholder("%mspt_max_10s%", 10000) { formatMSPT(mspt.poll(MillisPerTick.SECONDS_10).max()) }
manager.registerServerPlaceholder("%mspt_mean_10s%", 10000) { formatMSPT(mspt.poll(MillisPerTick.SECONDS_10).mean()) }
manager.registerServerPlaceholder("%mspt_median_10s%", 10000) { formatMSPT(mspt.poll(MillisPerTick.SECONDS_10).median()) }
manager.registerServerPlaceholder("%mspt_percentile95_10s%", 10000) {
manager.registerServerPlaceholder("%mspt_min_10s%", 1000) { formatMSPT(mspt.poll(MillisPerTick.SECONDS_10).min()) }
manager.registerServerPlaceholder("%mspt_max_10s%", 1000) { formatMSPT(mspt.poll(MillisPerTick.SECONDS_10).max()) }
manager.registerServerPlaceholder("%mspt_mean_10s%", 1000) { formatMSPT(mspt.poll(MillisPerTick.SECONDS_10).mean()) }
manager.registerServerPlaceholder("%mspt_median_10s%", 1000) { formatMSPT(mspt.poll(MillisPerTick.SECONDS_10).median()) }
manager.registerServerPlaceholder("%mspt_percentile95_10s%", 1000) {
formatMSPT(mspt.poll(MillisPerTick.SECONDS_10).percentile95th())
}
manager.registerServerPlaceholder("%mspt_min_1m%", 1000000) { formatMSPT(mspt.poll(MillisPerTick.MINUTES_1).min()) }
manager.registerServerPlaceholder("%mspt_max_1m%", 1000000) { formatMSPT(mspt.poll(MillisPerTick.MINUTES_1).max()) }
manager.registerServerPlaceholder("%mspt_mean_1m%", 1000000) { formatMSPT(mspt.poll(MillisPerTick.MINUTES_1).mean()) }
manager.registerServerPlaceholder("%mspt_median_1m%", 1000000) { formatMSPT(mspt.poll(MillisPerTick.MINUTES_1).median()) }
manager.registerServerPlaceholder("%mspt_percentile95_1m%", 1000000) {
manager.registerServerPlaceholder("%mspt_min_1m%", 1000) { formatMSPT(mspt.poll(MillisPerTick.MINUTES_1).min()) }
manager.registerServerPlaceholder("%mspt_max_1m%", 1000) { formatMSPT(mspt.poll(MillisPerTick.MINUTES_1).max()) }
manager.registerServerPlaceholder("%mspt_mean_1m%", 1000) { formatMSPT(mspt.poll(MillisPerTick.MINUTES_1).mean()) }
manager.registerServerPlaceholder("%mspt_median_1m%", 1000) { formatMSPT(mspt.poll(MillisPerTick.MINUTES_1).median()) }
manager.registerServerPlaceholder("%mspt_percentile95_1m%", 1000) {
formatMSPT(mspt.poll(MillisPerTick.SECONDS_10).percentile95th())
}
// CPU process
val process = plugin.server.spark.cpuProcess()
manager.registerServerPlaceholder("%cpu_process_10s%", 10000) { format(process.poll(CpuUsage.SECONDS_10)) }
manager.registerServerPlaceholder("%cpu_process_1m%", 1000000) { format(process.poll(CpuUsage.MINUTES_1)) }
manager.registerServerPlaceholder("%cpu_process_15m%", 15000000) { format(process.poll(CpuUsage.MINUTES_15)) }
manager.registerServerPlaceholder("%cpu_process_10s%", 1000) { format(process.poll(CpuUsage.SECONDS_10)) }
manager.registerServerPlaceholder("%cpu_process_1m%", 1000) { format(process.poll(CpuUsage.MINUTES_1)) }
manager.registerServerPlaceholder("%cpu_process_15m%", 1000) { format(process.poll(CpuUsage.MINUTES_15)) }
// CPU system
val system = plugin.server.spark.cpuSystem()
manager.registerServerPlaceholder("%cpu_system_10s%", 10000) { format(system.poll(CpuUsage.SECONDS_10)) }
manager.registerServerPlaceholder("%cpu_system_1m%", 1000000) { format(system.poll(CpuUsage.MINUTES_1)) }
manager.registerServerPlaceholder("%cpu_system_15m%", 15000000) { format(system.poll(CpuUsage.MINUTES_15)) }
manager.registerServerPlaceholder("%cpu_system_10s%", 1000) { format(system.poll(CpuUsage.SECONDS_10)) }
manager.registerServerPlaceholder("%cpu_system_1m%", 1000) { format(system.poll(CpuUsage.MINUTES_1)) }
manager.registerServerPlaceholder("%cpu_system_15m%", 1000) { format(system.poll(CpuUsage.MINUTES_15)) }
registerOnlinePlaceholders(manager)
}
@@ -13,7 +13,6 @@ import me.neznamy.tab.shared.features.nametags.NameTag
import me.neznamy.tab.shared.permission.LuckPerms
import me.neznamy.tab.shared.permission.None
import me.neznamy.tab.shared.permission.PermissionPlugin
import me.neznamy.tab.shared.placeholders.PlayerPlaceholderImpl
import me.neznamy.tab.shared.placeholders.UniversalPlaceholderRegistry
import net.kyori.adventure.text.Component
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer
@@ -22,7 +21,7 @@ import java.io.File
class KryptonPlatform(
private val plugin: Main,
private val folder: File,
private val folder: File
) : Platform {
private val server = plugin.server
@@ -33,23 +32,24 @@ class KryptonPlatform(
}
override fun loadFeatures() {
val tab = TAB.getInstance()
if (tab.configuration.isPipelineInjection) tab.featureManager.registerFeature("injection", KryptonPipelineInjector())
if (TAB.getInstance().configuration.isPipelineInjection) {
TAB.getInstance().featureManager.registerFeature("injection", KryptonPipelineInjector())
}
// Placeholders
KryptonPlaceholderRegistry(plugin).registerPlaceholders(tab.placeholderManager)
UniversalPlaceholderRegistry().registerPlaceholders(tab.placeholderManager)
KryptonPlaceholderRegistry(plugin).registerPlaceholders(TAB.getInstance().placeholderManager)
UniversalPlaceholderRegistry().registerPlaceholders(TAB.getInstance().placeholderManager)
// Load features
loadNametagFeature(tab)
tab.loadUniversalFeatures()
if (tab.config.getBoolean("bossbar.enabled", false)) {
tab.featureManager.registerFeature("bossbar", BossBarManagerImpl())
loadNametagFeature()
TAB.getInstance().loadUniversalFeatures()
if (TAB.getInstance().config.getBoolean("bossbar.enabled", false)) {
TAB.getInstance().featureManager.registerFeature("bossbar", BossBarManagerImpl())
}
if (tab.config.getBoolean("per-world-playerlist.enabled", false)) {
tab.featureManager.registerFeature("pwp", PerWorldPlayerList(plugin))
if (TAB.getInstance().config.getBoolean("per-world-playerlist.enabled", false)) {
TAB.getInstance().featureManager.registerFeature("pwp", PerWorldPlayerList(plugin))
}
server.players.forEach { tab.addPlayer(KryptonTabPlayer(it, plugin.protocolVersion(it))) }
server.players.forEach { TAB.getInstance().addPlayer(KryptonTabPlayer(it, plugin.protocolVersion(it))) }
}
override fun sendConsoleMessage(message: String, translateColors: Boolean) {
@@ -60,40 +60,24 @@ class KryptonPlatform(
override fun registerUnknownPlaceholder(identifier: String) {
val manager = TAB.getInstance().placeholderManager
if (identifier.startsWith("%rel_")) {
manager.registerPlayerPlaceholder(identifier, manager.defaultRefresh) { identifier }
// One day, when PlaceholderAPI v3 is a thing, this will work. One day...
manager.registerRelationalPlaceholder(identifier, manager.getRelationalRefresh(identifier)) { _, _ -> "" }
return
}
val serverIntervals = manager.serverPlaceholderRefreshIntervals
val playerIntervals = manager.playerPlaceholderRefreshIntervals
if (identifier.startsWith("%sync:")) {
val refresh = when {
serverIntervals.containsKey(identifier) -> serverIntervals[identifier]!!
playerIntervals.containsKey(identifier) -> playerIntervals[identifier]!!
else -> manager.defaultRefresh
}
manager.registerPlaceholder(object : PlayerPlaceholderImpl(identifier, refresh, null) {
override fun request(player: TabPlayer): Any? {
server.scheduler.run(plugin) {
val time = System.nanoTime()
lastValues[player.name] = identifier
if (!forceUpdate.contains(player.name)) forceUpdate.add(player.name)
TAB.getInstance().cpuManager.addPlaceholderTime(identifier, System.nanoTime() - time)
}
return lastValues[player.name]
}
})
return
}
if (serverIntervals.containsKey(identifier)) {
manager.registerServerPlaceholder(identifier, serverIntervals[identifier]!!) { identifier }
return
}
val refresh = if (serverIntervals.containsKey(identifier)) serverIntervals[identifier]!! else manager.defaultRefresh
manager.registerPlayerPlaceholder(identifier, refresh) { identifier }
if (playerIntervals.containsKey(identifier)) {
manager.registerPlayerPlaceholder(identifier, playerIntervals[identifier]!!) { identifier }
return
}
manager.registerPlayerPlaceholder(identifier, manager.defaultRefresh) { identifier }
}
override fun getServerVersion(): String = "${server.platform.name}v${server.platform.version}"
override fun getServerVersion(): String = "${server.platform.name} ${server.platform.version}"
override fun getDataFolder(): File = folder
@@ -117,12 +101,12 @@ class KryptonPlatform(
override fun getConfigName(): String = "kryptonconfig.yml"
private fun loadNametagFeature(tab: TAB) {
if (!tab.config.getBoolean("scoreboard-teams.enabled", true)) return
if (tab.config.getBoolean("scoreboard-teams.unlimited-nametag-mode.enabled", false)) {
tab.featureManager.registerFeature("nametagx", NameTagX())
private fun loadNametagFeature() {
if (!TAB.getInstance().config.getBoolean("scoreboard-teams.enabled", true)) return
if (TAB.getInstance().config.getBoolean("scoreboard-teams.unlimited-nametag-mode.enabled", false)) {
TAB.getInstance().featureManager.registerFeature("nametagx", NameTagX(plugin))
} else {
tab.featureManager.registerFeature("nametag16", NameTag())
TAB.getInstance().featureManager.registerFeature("nametag16", NameTag())
}
}
}
@@ -71,7 +71,7 @@ class KryptonTabPlayer(
override fun isVanished(): Boolean = delegate.isVanished
override fun getGamemode(): Int = Registries.GAME_MODES.idOf(delegate.gameMode)
override fun getGamemode(): Int = delegate.gameMode.ordinal
private fun handle(packet: PacketPlayOutBoss) {
when (packet.operation) {
Loaded 100 of 199 files, more files were not shown because too many files have changed in this diff. Show more