mirror of
https://github.com/NEZNAMY/TAB.git
synced 2026-11-12 20:22:01 -05:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
48c565d85d | ||
|
|
86b3cc4044 | ||
|
|
6a2d5091b8 | ||
|
|
4fc139c0c6 | ||
|
|
e5d800f469 | ||
|
|
4879ac28b5 | ||
|
|
bd0badab48 | ||
|
|
5575a26d3b | ||
|
|
d8cbe96949 | ||
|
|
cfb506a7ff | ||
|
|
31d259210c | ||
|
|
39112b8d41 | ||
|
|
4c92286ebb | ||
|
|
a317aeba85 | ||
|
|
dcaf17294e | ||
|
|
0bc734689a | ||
|
|
d0c2c00cc9 | ||
|
|
fd02328af9 | ||
|
|
3b7de31324 | ||
|
|
ebd67dd025 | ||
|
|
4557a39ae2 | ||
|
|
ce1eb299d3 | ||
|
|
20ab3f0a72 | ||
|
|
d61f90c25c | ||
|
|
90474e7592 | ||
|
|
a2e28003bc | ||
|
|
6e409c3dcd | ||
|
|
85a699c8de | ||
|
|
a788d1fb23 | ||
|
|
ab5b72375c | ||
|
|
3a023c51b5 | ||
|
|
0ad91bcafe | ||
|
|
f41ea3bcab | ||
|
|
327dc4b416 | ||
|
|
27e7779456 | ||
|
|
a7b2f5bb22 | ||
|
|
19fcb7c946 | ||
|
|
2706cd5881 | ||
|
|
4e2abd9c5b | ||
|
|
51ba2fa80a | ||
|
|
fd60cd0a21 | ||
|
|
5025372c05 | ||
|
|
4806bd075f | ||
|
|
370d17757a | ||
|
|
a648d7e75f | ||
|
|
518e1c5310 | ||
|
|
11539d8290 | ||
|
|
073caa9515 | ||
|
|
2b06b11916 | ||
|
|
032b0f8a41 | ||
|
|
9391363f9b | ||
|
|
467fb2e9c7 | ||
|
|
257893b8de | ||
|
|
e919839de5 | ||
|
|
77d372cbee | ||
|
|
03e9facaf7 | ||
|
|
f3e459d911 | ||
|
|
36feff0e04 | ||
|
|
0320140a1b | ||
|
|
4fb1b1c9f9 | ||
|
|
37f3896a41 | ||
|
|
e1c152d95d | ||
|
|
dffac5deb8 | ||
|
|
8aa3bbfad3 | ||
|
|
5bb4006e55 | ||
|
|
e06a406682 | ||
|
|
a19719be4b | ||
|
|
35856a9f3d | ||
|
|
cf1d5d5ee2 | ||
|
|
f69a845e51 | ||
|
|
db67e93bb8 | ||
|
|
313f089222 | ||
|
|
458c08ded7 | ||
|
|
fe6cc7417f | ||
|
|
181c94a808 | ||
|
|
9ff6f02d8d | ||
|
|
3cf74516d9 | ||
|
|
31f5502c16 | ||
|
|
671d60bd72 | ||
|
|
294e866501 | ||
|
|
96789100e3 | ||
|
|
ea934fc7fb | ||
|
|
d529b7b340 | ||
|
|
092ca7f9f8 | ||
|
|
79f4bdb869 | ||
|
|
b0d2d0f7dc | ||
|
|
cdf58c1dfe | ||
|
|
4680de6022 | ||
|
|
e8f61181b6 | ||
|
|
75e9e007d0 | ||
|
|
3574ef7c0b | ||
|
|
86158036d2 | ||
|
|
e73beb47a3 | ||
|
|
0db5f1dd73 | ||
|
|
6dcdc2aa58 | ||
|
|
64601137e8 | ||
|
|
af7697b670 | ||
|
|
9e4f46088b | ||
|
|
91e71a9b9c | ||
|
|
1198ffb847 | ||
|
|
72116ecd0c | ||
|
|
04ebb7123d | ||
|
|
43096beafe | ||
|
|
2a08c62456 | ||
|
|
b62d74c3fa | ||
|
|
652fb5a6ad | ||
|
|
d1f25cc19f | ||
|
|
dc6a9d9761 | ||
|
|
838d725715 | ||
|
|
c45acb39ca | ||
|
|
957edf2a52 | ||
|
|
d969c6ed0e | ||
|
|
dd6fca961c | ||
|
|
e88a6df456 | ||
|
|
3a4530c999 | ||
|
|
b623dba40a | ||
|
|
e2fd945109 | ||
|
|
e6dc3cda31 | ||
|
|
18d8ff127a | ||
|
|
4a9526451f | ||
|
|
669d89c870 | ||
|
|
39161f2af5 | ||
|
|
be8c33e3fc | ||
|
|
7c1a27f9df | ||
|
|
342cc93dbf | ||
|
|
6f07cf439b | ||
|
|
1d4d00b69b |
No files matched your search
@@ -1,3 +1,7 @@
|
||||
plugins {
|
||||
id("net.kyori.blossom") version "1.2.0"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnlyApi(libs.netty)
|
||||
api(libs.jsonSimple) {
|
||||
@@ -6,4 +10,16 @@ dependencies {
|
||||
compileOnlyApi(libs.snakeyaml)
|
||||
api(libs.yamlAssist)
|
||||
compileOnlyApi(libs.gson)
|
||||
compileOnlyApi(libs.adventureMiniMessage)
|
||||
compileOnlyApi(libs.adventureApi)
|
||||
compileOnlyApi(libs.adventureLegacy)
|
||||
}
|
||||
|
||||
blossom {
|
||||
replaceToken("@plugin_version@", project.version)
|
||||
replaceTokenIn("src/main/java/me/neznamy/tab/api/TabConstants.java")
|
||||
}
|
||||
|
||||
tasks.javadoc {
|
||||
enabled = project.hasProperty("enable-javadoc")
|
||||
}
|
||||
@@ -1,5 +1,10 @@
|
||||
package me.neznamy.tab.api;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Feature manager allows registration and work with features.
|
||||
*/
|
||||
public interface FeatureManager {
|
||||
|
||||
/**
|
||||
@@ -38,4 +43,55 @@ public interface FeatureManager {
|
||||
* @return the feature or null if feature does not exist
|
||||
*/
|
||||
TabFeature getFeature(String name);
|
||||
|
||||
/**
|
||||
* Calls onQuit(TabPlayer) to all enabled features
|
||||
*
|
||||
* @param disconnectedPlayer
|
||||
* player who disconnected
|
||||
*/
|
||||
void onQuit(TabPlayer disconnectedPlayer);
|
||||
|
||||
/**
|
||||
* Calls onJoin(TabPlayer) to all enabled features
|
||||
*
|
||||
* @param connectedPlayer
|
||||
* player who connected
|
||||
*/
|
||||
void onJoin(TabPlayer connectedPlayer);
|
||||
|
||||
/**
|
||||
* Calls onServerChange(TabPlayer, String, String) to all enabled features
|
||||
*
|
||||
* @param playerUUID
|
||||
* player who switched server
|
||||
* @param to
|
||||
* name of the new server
|
||||
*/
|
||||
void onServerChange(UUID playerUUID, String to);
|
||||
|
||||
/**
|
||||
* Calls onWorldChange(TabPlayer, String, String) to all enabled features
|
||||
*
|
||||
* @param playerUUID
|
||||
* player who switched world
|
||||
* @param to
|
||||
* name of the new world
|
||||
*/
|
||||
void onWorldChange(UUID playerUUID, String to);
|
||||
|
||||
/**
|
||||
* Calls onCommand(TabPlayer, String) to all enabled features
|
||||
*
|
||||
* @param sender
|
||||
* command sender
|
||||
* @param command
|
||||
* command line including /
|
||||
* @return {@code true} if some feature marked the command for cancel, {@code false} if not
|
||||
*/
|
||||
boolean onCommand(TabPlayer sender, String command);
|
||||
|
||||
void markObjective();
|
||||
|
||||
void markDisplayObjective();
|
||||
}
|
||||
@@ -1,5 +1,9 @@
|
||||
package me.neznamy.tab.api;
|
||||
|
||||
/**
|
||||
* An interface representing a property assigned to a player,
|
||||
* which may contain placeholders and can be changed using the API.
|
||||
*/
|
||||
public interface Property {
|
||||
|
||||
/**
|
||||
|
||||
@@ -3,30 +3,124 @@ package me.neznamy.tab.api;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Interface representing user or group configuration.
|
||||
* Implementation is either using file or MySQL, if it's enabled.
|
||||
*/
|
||||
public interface PropertyConfiguration {
|
||||
|
||||
void setProperty(String name, String property, String server, String world, String value);
|
||||
/**
|
||||
* Sets property value of group or user to specified value. If {@code world} or
|
||||
* {@code server} is not {@code null}, value will be inserted as a per-world or
|
||||
* per-server setting. If both {@code world} and {@code server} are {@code null},
|
||||
* value is inserted as a global setting.
|
||||
*
|
||||
* @param groupOrUser
|
||||
* Name of group or user, depending on what this instance handles
|
||||
* @param property
|
||||
* Name of property to set
|
||||
* @param server
|
||||
* Name of server to apply setting to, {@code null} for global setting
|
||||
* @param world
|
||||
* Name of world to apply setting to, {@code null} for global setting
|
||||
* @param value
|
||||
* Value of the property
|
||||
*/
|
||||
void setProperty(String groupOrUser, String property, String server, String world, String value);
|
||||
|
||||
String[] getProperty(String name, String property, String server, String world);
|
||||
/**
|
||||
* Gets property of group or user. If {@code server} or {@code world}
|
||||
* are not {@code null}, per-server / per-world settings are checked first
|
||||
* to try to find a match. If no match is found, global value is returned.
|
||||
* Returned value is an array with 2 elements, with first argument being value
|
||||
* and second being source. If nothing is found, empty array is returned.
|
||||
*
|
||||
* @param groupOrUser
|
||||
* Name of group or user, depending on what this instance handles
|
||||
* @param property
|
||||
* Name of property to get
|
||||
* @param server
|
||||
* Server the player is currently in, to allow check for per-server settings
|
||||
* @param world
|
||||
* World the player is currently in, to allow check for per-world settings
|
||||
* @return Array with 2 elements with value being first, source second if found,
|
||||
* empty array if nothing was found.
|
||||
*/
|
||||
String[] getProperty(String groupOrUser, String property, String server, String world);
|
||||
|
||||
void remove(String name);
|
||||
/**
|
||||
* Removes all data applied to specified group or user.
|
||||
*
|
||||
* @param groupOrUser
|
||||
* Name of group or user, depending on what this instance handles
|
||||
*/
|
||||
void remove(String groupOrUser);
|
||||
|
||||
Map<String, Object> getGlobalSettings(String name);
|
||||
/**
|
||||
* Returns map of global settings applied to specified group or user.
|
||||
* Map key is property name, value is property value.
|
||||
*
|
||||
* @param groupOrUser
|
||||
* Name of group or user, depending on what this instance handles
|
||||
* @return Map of global settings of specified group or user
|
||||
*/
|
||||
Map<String, Object> getGlobalSettings(String groupOrUser);
|
||||
|
||||
Map<String, Map<String, Object>> getPerWorldSettings(String name);
|
||||
/**
|
||||
* Returns map of per-world settings of specified group or user.
|
||||
* Map key is world name, value is property name-value map in that world.
|
||||
*
|
||||
* @param groupOrUser
|
||||
* Name of group or user, depending on what this instance handles
|
||||
* @return Map of per-world settings of specified group or user
|
||||
*/
|
||||
Map<String, Map<String, Object>> getPerWorldSettings(String groupOrUser);
|
||||
|
||||
Map<String, Map<String, Object>> getPerServerSettings(String name);
|
||||
/**
|
||||
* Returns map of per-server settings of specified group or user.
|
||||
* Map key is server name, value is property name-value map in that server.
|
||||
*
|
||||
* @param groupOrUser
|
||||
* Name of group or user, depending on what this instance handles
|
||||
* @return Map of per-server settings of specified group or user
|
||||
*/
|
||||
Map<String, Map<String, Object>> getPerServerSettings(String groupOrUser);
|
||||
|
||||
/**
|
||||
* Returns set of all groups or users that have anything configured,
|
||||
* either globally or in some world or server.
|
||||
*
|
||||
* @return Set of all entries with something configured
|
||||
*/
|
||||
Set<String> getAllEntries();
|
||||
|
||||
default Map<String, Map<String, Object>> convertMap(Map<String, Map<String, Map<String, Object>>> map, String key) {
|
||||
/**
|
||||
* Converts per-world or per-server map into a per-world or per-server map
|
||||
* with values only belonging to entered group or user. In other words, extracts
|
||||
* settings belonging to group or user from the map.
|
||||
*
|
||||
* @param map
|
||||
* Original per-world or per-server setting map
|
||||
* @param groupOrUser
|
||||
* Name of group or user, depending on what this instance handles
|
||||
* @return Converted map only containing data of specified group or user
|
||||
*/
|
||||
default Map<String, Map<String, Object>> convertMap(Map<String, Map<String, Map<String, Object>>> map, String groupOrUser) {
|
||||
Map<String, Map<String, Object>> converted = new HashMap<>();
|
||||
for (Map.Entry<String, Map<String, Map<String, Object>>> entry : map.entrySet()) {
|
||||
converted.put(entry.getKey(), entry.getValue().get(key));
|
||||
converted.put(entry.getKey(), entry.getValue().get(groupOrUser));
|
||||
}
|
||||
return converted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts object into string. For most objects, {@link Object#toString()} is called.
|
||||
* For lists, entries are connected with {@code "\n"}.
|
||||
*
|
||||
* @param obj
|
||||
* Object to convert
|
||||
* @return Converted string
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
default String toString(Object obj) {
|
||||
if (obj instanceof List) {
|
||||
@@ -35,6 +129,15 @@ public interface PropertyConfiguration {
|
||||
return obj.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts string into object. If string contains {@code "\n"},
|
||||
* a list is created using {@code "\n"} as a separator. Otherwise,
|
||||
* inserted string is returned.
|
||||
*
|
||||
* @param string
|
||||
* String to convert
|
||||
* @return Converted object
|
||||
*/
|
||||
default Object fromString(String string) {
|
||||
if (string != null && string.contains("\n")) {
|
||||
return Arrays.asList(string.split("\n"));
|
||||
|
||||
@@ -8,6 +8,8 @@ public enum ProtocolVersion {
|
||||
UNKNOWN_SERVER_VERSION ("Unknown"),
|
||||
UNKNOWN_CLIENT_VERSION ("Unknown"),
|
||||
PROXY ("Proxy"),
|
||||
V1_19_1 (760),
|
||||
V1_19 (759),
|
||||
V1_18_2 (758),
|
||||
V1_18_1 (757),
|
||||
V1_18 (757),
|
||||
@@ -65,13 +67,13 @@ public enum ProtocolVersion {
|
||||
/** Value array to iterate over to avoid array creations on each call */
|
||||
public static final ProtocolVersion[] VALUES = values();
|
||||
|
||||
//version's network id found at https://wiki.vg/Protocol_version_numbers
|
||||
/** Version's network id found at https://wiki.vg/Protocol_version_numbers */
|
||||
private final int networkId;
|
||||
|
||||
//minor version, such as 16
|
||||
/** Version's minor version, such as 16 for 1.16.x */
|
||||
private int minorVersion;
|
||||
|
||||
//friendly name displayed in %player-version% placeholder
|
||||
/** Version's friendly name displayed in %player-version% placeholder */
|
||||
private final String friendlyName;
|
||||
|
||||
/**
|
||||
|
||||
@@ -15,14 +15,31 @@ import me.neznamy.tab.api.team.TeamManager;
|
||||
*/
|
||||
public abstract class TabAPI {
|
||||
|
||||
/** Instance of the API */
|
||||
private static TabAPI instance;
|
||||
|
||||
/**
|
||||
* Returns API instance. If instance was not set by the plugin, throws
|
||||
* {@code IllegalStateException}. This is usually caused by shading the API
|
||||
* into own project, which is not allowed. Another option is calling the method
|
||||
* before plugin was able to load.
|
||||
*
|
||||
* @return API instance
|
||||
* @throws IllegalStateException
|
||||
* If instance is {@code null}
|
||||
*/
|
||||
public static TabAPI getInstance() {
|
||||
if (instance == null) throw new IllegalStateException("API instance is null. This likely means you shaded TAB's API into your project" +
|
||||
" instead of only using it, which is not allowed.");
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instance setter for internal use by the plugin only.
|
||||
*
|
||||
* @param instance
|
||||
* API instance
|
||||
*/
|
||||
public static void setInstance(TabAPI instance) {
|
||||
TabAPI.instance = instance;
|
||||
}
|
||||
@@ -53,26 +70,31 @@ public abstract class TabAPI {
|
||||
public abstract TabPlayer[] getOnlinePlayers();
|
||||
|
||||
/**
|
||||
* Return BossBar manager instance if the feature is enabled. Returns null otherwise.
|
||||
* Return BossBar manager instance if the feature is enabled. If not, returns {@code null}.
|
||||
*
|
||||
* @return BossBar manager
|
||||
*/
|
||||
public abstract BossBarManager getBossBarManager();
|
||||
|
||||
/**
|
||||
* Returns scoreboard manager instance if the feature is enabled. Returns null otherwise.
|
||||
* Returns scoreboard manager instance if the feature is enabled. If not, returns {@code null}.
|
||||
*
|
||||
* @return scoreboard manager
|
||||
*/
|
||||
public abstract ScoreboardManager getScoreboardManager();
|
||||
|
||||
/**
|
||||
* Returns team manager instance if the feature is enabled, false otherwise
|
||||
* Returns team manager instance if the feature is enabled. If not, returns {@code null}.
|
||||
*
|
||||
* @return team manager
|
||||
*/
|
||||
public abstract TeamManager getTeamManager();
|
||||
|
||||
/**
|
||||
* Returns header/footer manager instance if the feature is enabled. If not, returns {@code null}.
|
||||
*
|
||||
* @return Header/footer manager
|
||||
*/
|
||||
public abstract HeaderFooterManager getHeaderFooterManager();
|
||||
|
||||
/**
|
||||
@@ -89,6 +111,11 @@ public abstract class TabAPI {
|
||||
*/
|
||||
public abstract FeatureManager getFeatureManager();
|
||||
|
||||
/**
|
||||
* Returns Tablist name format manager instance if the feature is enabled. If not, returns {@code null}.
|
||||
*
|
||||
* @return Tablist name format manager
|
||||
*/
|
||||
public abstract TablistFormatManager getTablistFormatManager();
|
||||
|
||||
/**
|
||||
@@ -111,23 +138,79 @@ public abstract class TabAPI {
|
||||
* @param message
|
||||
* message to print
|
||||
* @param translateColors
|
||||
* true if colors should be translated, false if not
|
||||
* {@code true} if colors should be translated, {@code false} if not
|
||||
*/
|
||||
public abstract void sendConsoleMessage(String message, boolean translateColors);
|
||||
|
||||
/**
|
||||
* Returns TAB's Thread manager, which allows task submitting
|
||||
*
|
||||
* @return ThreadManager instance
|
||||
*/
|
||||
public abstract ThreadManager getThreadManager();
|
||||
|
||||
/**
|
||||
* Returns TAB's cache file used to store player toggle data
|
||||
*
|
||||
* @return TAB's player cache file
|
||||
*/
|
||||
public abstract ConfigurationFile getPlayerCache();
|
||||
|
||||
/**
|
||||
* Returns TAB's config.yml file
|
||||
*
|
||||
* @return config.yml file
|
||||
*/
|
||||
public abstract ConfigurationFile getConfig();
|
||||
|
||||
/**
|
||||
* Returns TAB's group configuration
|
||||
*
|
||||
* @return TAB's group configuration
|
||||
*/
|
||||
public abstract PropertyConfiguration getGroups();
|
||||
|
||||
/**
|
||||
* Returns TAB's user configuration
|
||||
*
|
||||
* @return TAB's user configuration
|
||||
*/
|
||||
public abstract PropertyConfiguration getUsers();
|
||||
|
||||
/**
|
||||
* Sends a debug message into console if the option
|
||||
* is enabled in config.
|
||||
*
|
||||
* @param message
|
||||
* Message to send
|
||||
*/
|
||||
public abstract void debug(String message);
|
||||
|
||||
/**
|
||||
* Logs an error into errors.log file
|
||||
*
|
||||
* @param message
|
||||
* Error message
|
||||
* @param t
|
||||
* Thrown error
|
||||
*/
|
||||
public abstract void logError(String message, Throwable t);
|
||||
|
||||
/**
|
||||
* Sets name of file with syntax error, which prevented
|
||||
* the plugin from enabling. Internal use only.
|
||||
*
|
||||
* @param file
|
||||
* Name of file with syntax error
|
||||
*/
|
||||
public abstract void setBrokenFile(String file);
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the plugin is currently disabled due to an error,
|
||||
* either a yaml syntax error or an internal startup error. Returns {@code false}
|
||||
* if the plugin is properly running.
|
||||
*
|
||||
* @return {@code true} if disabled, {@code false} if running correctly
|
||||
*/
|
||||
public abstract boolean isPluginDisabled();
|
||||
}
|
||||
+87
-5
@@ -1,4 +1,4 @@
|
||||
package me.neznamy.tab.shared;
|
||||
package me.neznamy.tab.api;
|
||||
|
||||
/**
|
||||
* A class containing various constants used everywhere in the plugin
|
||||
@@ -7,7 +7,8 @@ package me.neznamy.tab.shared;
|
||||
public class TabConstants {
|
||||
|
||||
public static final String PLUGIN_VERSION = "@plugin_version@";
|
||||
public static final String DEFAULT_GROUP = "NONE";
|
||||
public static final String NO_GROUP = "NONE";
|
||||
public static final String DEFAULT_GROUP = "_DEFAULT_";
|
||||
public static final String PLUGIN_MESSAGE_CHANNEL_NAME = "tab:bridge-2";
|
||||
public static final String REDIS_CHANNEL_NAME = "TAB";
|
||||
|
||||
@@ -49,7 +50,6 @@ public class TabConstants {
|
||||
public static final String PLACEHOLDER_REFRESHING = "Refreshing placeholders";
|
||||
public static final String GROUP_REFRESHING = "Refreshing groups";
|
||||
|
||||
public static final String V1_8_0_BUG_COMPENSATION = "Compensating for 1.8.0 bugs";
|
||||
public static final String REFRESHING_NAME_TAG_VISIBILITY = "Refreshing NameTag visibility";
|
||||
public static final String SCOREBOARD_PACKET_CHECK = "Checking for other plugins";
|
||||
public static final String PROCESSING_PLAYER_MOVEMENT = "Processing player movement";
|
||||
@@ -260,6 +260,10 @@ public class TabConstants {
|
||||
return "scoreboard-" + line;
|
||||
}
|
||||
|
||||
public static String scoreboardLine(String scoreboard, int index) {
|
||||
return "scoreboard-score-" + scoreboard + "-" + index;
|
||||
}
|
||||
|
||||
public static String layout(String name) {
|
||||
return "layout-" + name;
|
||||
}
|
||||
@@ -279,9 +283,87 @@ public class TabConstants {
|
||||
public static String bossBarColorStyle(String name) {
|
||||
return "BossBar-color-style-" + name;
|
||||
}
|
||||
}
|
||||
|
||||
public static String scoreboardLine(String scoreboard, int index) {
|
||||
return "scoreboard-score-" + scoreboard + "-" + index;
|
||||
/**
|
||||
* All internal placeholders offered by the plugin
|
||||
*/
|
||||
public static class Placeholder {
|
||||
|
||||
// Universal
|
||||
public static final String DISPLAY_NAME = "%displayname%";
|
||||
public static final String GROUP = "%group%";
|
||||
public static final String VANISHED = "%vanished%";
|
||||
public static final String WORLD = "%world%";
|
||||
public static final String WORLD_ONLINE = "%worldonline%";
|
||||
public static final String SERVER = "%server%";
|
||||
public static final String SERVER_ONLINE = "%serveronline%";
|
||||
public static final String PLAYER = "%player%";
|
||||
public static final String TIME = "%time%";
|
||||
public static final String DATE = "%date%";
|
||||
public static final String PING = "%ping%";
|
||||
public static final String PLAYER_VERSION = "%player-version%";
|
||||
public static final String PLAYER_VERSION_ID = "%player-version-id%";
|
||||
public static final String MEMORY_USED = "%memory-used%";
|
||||
public static final String MEMORY_MAX = "%memory-max%";
|
||||
public static final String MEMORY_USED_GB = "%memory-used-gb%";
|
||||
public static final String MEMORY_MAX_GB = "%memory-max-gb%";
|
||||
public static final String ONLINE = "%online%";
|
||||
public static final String STAFF_ONLINE = "%staffonline%";
|
||||
public static final String NON_STAFF_ONLINE = "%nonstaffonline%";
|
||||
public static final String LUCKPERMS_PREFIX = "%luckperms-prefix%";
|
||||
public static final String LUCKPERMS_SUFFIX = "%luckperms-suffix%";
|
||||
public static final String COUNTDOWN = "%countdown%";
|
||||
|
||||
// Placeholders for internal use
|
||||
public static final String COLLISION = "%collision%";
|
||||
public static final String INVISIBLE = "%invisible%";
|
||||
public static final String VEHICLE = "%vehicle%";
|
||||
|
||||
// Bukkit only
|
||||
public static final String TPS = "%tps%";
|
||||
public static final String MSPT = "%mspt%";
|
||||
public static final String AFK = "%afk%";
|
||||
public static final String ESSENTIALS_NICK = "%essentialsnick%";
|
||||
public static final String VAULT_PREFIX = "%vault-prefix%";
|
||||
public static final String VAULT_SUFFIX = "%vault-suffix%";
|
||||
public static final String HEALTH = "%health%";
|
||||
|
||||
public static String condition(String name) {
|
||||
return "%condition:" + name + "%";
|
||||
}
|
||||
|
||||
public static String animation(String name) {
|
||||
return "%animation:" + name + "%";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* All plugins TAB hooks into
|
||||
*/
|
||||
public static class Plugin {
|
||||
|
||||
public static final String LUCKPERMS = "LuckPerms";
|
||||
public static final String VAULT = "Vault";
|
||||
public static final String PLACEHOLDER_API = "PlaceholderAPI";
|
||||
public static final String LIBS_DISGUISES = "LibsDisguises";
|
||||
public static final String VIAVERSION = "ViaVersion";
|
||||
public static final String PROTOCOL_SUPPORT = "ProtocolSupport";
|
||||
public static final String ESSENTIALS = "Essentials";
|
||||
public static final String REDIS_BUNGEE = "RedisBungee";
|
||||
public static final String PREMIUM_VANISH = "PremiumVanish";
|
||||
}
|
||||
|
||||
/**
|
||||
* TAB's custom metrics charts
|
||||
*/
|
||||
public static class MetricsChart {
|
||||
|
||||
public static final String PERMISSION_SYSTEM = "permission_system";
|
||||
public static final String GLOBAL_PLAYER_LIST_ENABLED = "global_playerlist_enabled";
|
||||
public static final String PLACEHOLDER_API = "placeholderapi";
|
||||
public static final String SERVER_VERSION = "server_version";
|
||||
public static final String UNLIMITED_NAME_TAG_MODE_ENABLED = "unlimited_nametag_mode_enabled";
|
||||
|
||||
}
|
||||
}
|
||||
@@ -6,38 +6,53 @@ import me.neznamy.tab.api.protocol.PacketPlayOutPlayerInfo;
|
||||
import me.neznamy.tab.api.protocol.PacketPlayOutScoreboardDisplayObjective;
|
||||
import me.neznamy.tab.api.protocol.PacketPlayOutScoreboardObjective;
|
||||
|
||||
/**
|
||||
* Abstract class representing a core feature of the plugin.
|
||||
* <p>
|
||||
* It receives all kinds of events and can react to them.
|
||||
*/
|
||||
public abstract class TabFeature {
|
||||
|
||||
/** Feature's name displayed in /tab cpu */
|
||||
private final String featureName;
|
||||
|
||||
/** Feature's function name displayed in place of refreshing in /tab cpu */
|
||||
private final String refreshDisplayName;
|
||||
protected final String[] disabledServers;
|
||||
private final boolean serverWhitelistMode;
|
||||
protected final String[] disabledWorlds;
|
||||
private final boolean worldWhitelistMode;
|
||||
|
||||
/** Servers where the feature is disabled (or enabled if using whitelist mode) */
|
||||
protected String[] disabledServers = new String[0];
|
||||
|
||||
/** Flag tracking whether disabled server list is a whitelist or blacklist */
|
||||
private boolean serverWhitelistMode = false;
|
||||
|
||||
/** Worlds where the feature is disabled (or enabled if using whitelist mode) */
|
||||
protected String[] disabledWorlds = new String[0];
|
||||
|
||||
/** Flag tracking whether disabled world list is a whitelist or blacklist */
|
||||
private boolean worldWhitelistMode = false;
|
||||
|
||||
/** Players located in currently disabled worlds / servers */
|
||||
private final Set<TabPlayer> disabledPlayers = Collections.newSetFromMap(new WeakHashMap<>());
|
||||
|
||||
/**
|
||||
* List of methods overridden (implemented) by each feature.
|
||||
* If a method is not overridden, it is not called at all.
|
||||
* This avoids a massive spam for every single method
|
||||
* in every single feature in /tab cpu output
|
||||
*/
|
||||
private final List<String> methodOverrides = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Constructs new instance with given parameters and loads method overrides
|
||||
*
|
||||
* @param featureName
|
||||
* Feature's name in /tab cpu
|
||||
* @param refreshDisplayName
|
||||
* "refreshing" cpu display type name of the feature
|
||||
*/
|
||||
protected TabFeature(String featureName, String refreshDisplayName) {
|
||||
this(featureName, refreshDisplayName, null, null);
|
||||
}
|
||||
|
||||
protected TabFeature(String featureName, String refreshDisplayName, List<String> disabledServers, List<String> disabledWorlds) {
|
||||
this.featureName = featureName;
|
||||
this.refreshDisplayName = refreshDisplayName;
|
||||
if (disabledServers != null) {
|
||||
this.disabledServers = disabledServers.toArray(new String[0]);
|
||||
serverWhitelistMode = disabledServers.contains("WHITELIST");
|
||||
} else {
|
||||
this.disabledServers = new String[0];
|
||||
serverWhitelistMode = false;
|
||||
}
|
||||
if (disabledWorlds != null) {
|
||||
this.disabledWorlds = disabledWorlds.toArray(new String[0]);
|
||||
worldWhitelistMode = disabledWorlds.contains("WHITELIST");
|
||||
} else {
|
||||
this.disabledWorlds = new String[0];
|
||||
worldWhitelistMode = false;
|
||||
}
|
||||
try {
|
||||
if (getClass().getMethod("onCommand", TabPlayer.class, String.class).getDeclaringClass() != TabFeature.class)
|
||||
methodOverrides.add("onCommand");
|
||||
@@ -49,12 +64,16 @@ public abstract class TabFeature {
|
||||
methodOverrides.add("onWorldChange");
|
||||
if (getClass().getMethod("onServerChange", TabPlayer.class, String.class, String.class).getDeclaringClass() != TabFeature.class)
|
||||
methodOverrides.add("onServerChange");
|
||||
if (getClass().getMethod("onDisplayObjective", TabPlayer.class, PacketPlayOutScoreboardDisplayObjective.class).getDeclaringClass() != TabFeature.class)
|
||||
if (getClass().getMethod("onDisplayObjective", TabPlayer.class, PacketPlayOutScoreboardDisplayObjective.class).getDeclaringClass() != TabFeature.class) {
|
||||
methodOverrides.add("onDisplayObjective");
|
||||
TabAPI.getInstance().getFeatureManager().markDisplayObjective();
|
||||
}
|
||||
if (getClass().getMethod("onLoginPacket", TabPlayer.class).getDeclaringClass() != TabFeature.class)
|
||||
methodOverrides.add("onLoginPacket");
|
||||
if (getClass().getMethod("onObjective", TabPlayer.class, PacketPlayOutScoreboardObjective.class).getDeclaringClass() != TabFeature.class)
|
||||
if (getClass().getMethod("onObjective", TabPlayer.class, PacketPlayOutScoreboardObjective.class).getDeclaringClass() != TabFeature.class) {
|
||||
methodOverrides.add("onObjective");
|
||||
TabAPI.getInstance().getFeatureManager().markObjective();
|
||||
}
|
||||
if (getClass().getMethod("onPlayerInfo", TabPlayer.class, PacketPlayOutPlayerInfo.class).getDeclaringClass() != TabFeature.class)
|
||||
methodOverrides.add("onPlayerInfo");
|
||||
if (getClass().getMethod("onPacketReceive", TabPlayer.class, Object.class).getDeclaringClass() != TabFeature.class)
|
||||
@@ -71,7 +90,34 @@ public abstract class TabFeature {
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all players and sends packets
|
||||
* Constructs new instance with given parameters and loads method overrides.
|
||||
* Also loads lists of disabled worlds and servers of this feature with config
|
||||
* section path specified with {@code configSection} parameter.
|
||||
*
|
||||
* @param featureName
|
||||
* Feature's name in /tab cpu
|
||||
* @param refreshDisplayName
|
||||
* "refreshing" cpu display type name of the feature
|
||||
* @param configSection
|
||||
* Configuration section of the feature to load disabled
|
||||
* servers / worlds from
|
||||
*/
|
||||
protected TabFeature(String featureName, String refreshDisplayName, String configSection) {
|
||||
this(featureName, refreshDisplayName);
|
||||
List<String> disabledServers = TabAPI.getInstance().getConfig().getStringList(configSection + ".disable-in-servers");
|
||||
List<String> disabledWorlds = TabAPI.getInstance().getConfig().getStringList(configSection + ".disable-in-worlds");
|
||||
if (disabledServers != null) {
|
||||
this.disabledServers = disabledServers.toArray(new String[0]);
|
||||
serverWhitelistMode = disabledServers.contains("WHITELIST");
|
||||
}
|
||||
if (disabledWorlds != null) {
|
||||
this.disabledWorlds = disabledWorlds.toArray(new String[0]);
|
||||
worldWhitelistMode = disabledWorlds.contains("WHITELIST");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all online players and sends packets
|
||||
*/
|
||||
public void load() {
|
||||
//empty by default
|
||||
@@ -85,13 +131,13 @@ public abstract class TabFeature {
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes command from player
|
||||
* Processes command from player. This is typically a toggle command.
|
||||
*
|
||||
* @param sender
|
||||
* command sender
|
||||
* @param message
|
||||
* command line
|
||||
* @return true if event should be cancelled, false if not
|
||||
* @return {@code true} if event should be cancelled, {@code true} if not
|
||||
*/
|
||||
public boolean onCommand(TabPlayer sender, String message) {
|
||||
return false;
|
||||
@@ -232,6 +278,12 @@ public abstract class TabFeature {
|
||||
//empty by default
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes vanish status change of player
|
||||
*
|
||||
* @param player
|
||||
* Player who changed vanish status
|
||||
*/
|
||||
public void onVanishStatusChange(TabPlayer player){
|
||||
//empty by default
|
||||
}
|
||||
@@ -248,13 +300,13 @@ public abstract class TabFeature {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if world or server is disabled, false if not
|
||||
* Returns {@code true} if world or server is disabled, {@code false} if not
|
||||
*
|
||||
* @param server
|
||||
* server to check
|
||||
* @param world
|
||||
* world to check
|
||||
* @return true if feature should be disabled, false if not
|
||||
* @return {@code true} if feature should be disabled, {@code false} if not
|
||||
*/
|
||||
public boolean isDisabled(String server, String world) {
|
||||
boolean contains = contains(disabledWorlds, world);
|
||||
@@ -265,6 +317,17 @@ public abstract class TabFeature {
|
||||
return contains;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if list contains the specified element or element
|
||||
* ends with {@code "*"} and element meeting that requirement is present,
|
||||
* {@code false} otherwise.
|
||||
*
|
||||
* @param list
|
||||
* List to check
|
||||
* @param element
|
||||
* Element to find
|
||||
* @return {@code true} if element was found, {@code false} if not
|
||||
*/
|
||||
protected boolean contains(String[] list, String element) {
|
||||
if (element == null) return false;
|
||||
for (String s : list) {
|
||||
@@ -286,24 +349,60 @@ public abstract class TabFeature {
|
||||
return featureName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns text to display in /tab cpu of this feature refreshing visuals
|
||||
*
|
||||
* @return Text to display as refreshing of this feature
|
||||
*/
|
||||
public String getRefreshDisplayName() {
|
||||
return refreshDisplayName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if method with specified name is overridden
|
||||
* in the implementation, {@code false} if not
|
||||
*
|
||||
* @param method
|
||||
* Method to check
|
||||
* @return {@code true} if overridden, {@code false} if not
|
||||
*/
|
||||
public boolean overridesMethod(String method) {
|
||||
return methodOverrides.contains(method);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if player is currently located in a server
|
||||
* or world, which is marked as disabled, {@code false} if not
|
||||
*
|
||||
* @param p
|
||||
* Player to check
|
||||
* @return {@code true} if player is in disabled server / world,
|
||||
* {@code false} if not
|
||||
*/
|
||||
public boolean isDisabledPlayer(TabPlayer p) {
|
||||
return disabledPlayers.contains(p);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds specified player into list of players in disabled
|
||||
* servers / worlds.
|
||||
*
|
||||
* @param p
|
||||
* Player to add
|
||||
*/
|
||||
public void addDisabledPlayer(TabPlayer p) {
|
||||
if (disabledPlayers.contains(p)) return;
|
||||
disabledPlayers.add(p);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes specified player from list of players in disabled
|
||||
* servers / worlds
|
||||
*
|
||||
* @param p
|
||||
* Player to check
|
||||
*/
|
||||
public void removeDisabledPlayer(TabPlayer p) {
|
||||
disabledPlayers.remove(p);
|
||||
}
|
||||
|
||||
public String getRefreshDisplayName() {
|
||||
return refreshDisplayName;
|
||||
}
|
||||
}
|
||||
@@ -114,34 +114,12 @@ public interface TabPlayer {
|
||||
*/
|
||||
void sendPacket(Object packet);
|
||||
|
||||
/**
|
||||
* Sends the player a platform-specific packet and adds that packet into counter that
|
||||
* is displayed in /tab cpu
|
||||
*
|
||||
* @param packet
|
||||
* an instance of packet depending on platform
|
||||
* @param feature
|
||||
* feature to increment sent packet counter of
|
||||
*/
|
||||
void sendPacket(Object packet, TabFeature feature);
|
||||
|
||||
/**
|
||||
* Sends the player a platform-specific packet and adds that packet into counter that
|
||||
* is displayed in /tab cpu
|
||||
*
|
||||
* @param packet
|
||||
* an instance of packet depending on platform
|
||||
* @param feature
|
||||
* feature to increment sent packet counter of
|
||||
*/
|
||||
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
|
||||
* @return the property or {@code null} if not found
|
||||
*/
|
||||
Property getProperty(String name);
|
||||
|
||||
@@ -164,14 +142,7 @@ public interface TabPlayer {
|
||||
void sendMessage(IChatBaseComponent message);
|
||||
|
||||
/**
|
||||
* Returns player's primary permission group
|
||||
*
|
||||
* @return player's group depending on configuration
|
||||
*/
|
||||
String getGroup();
|
||||
|
||||
/**
|
||||
* Returns player's channel or null if server is 1.7 or older
|
||||
* Returns player's netty channel. On servers running version 1.7 or older returns {@code null}.
|
||||
*
|
||||
* @return player's channel
|
||||
*/
|
||||
@@ -194,13 +165,14 @@ public interface TabPlayer {
|
||||
/**
|
||||
* Returns true once the player is successfully loaded (onJoin method ran through all methods)
|
||||
*
|
||||
* @return true if player is fully loaded, false otherwise
|
||||
* @return {@code true} if player is fully loaded, {@code false} otherwise
|
||||
*/
|
||||
boolean isLoaded();
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* created and {@code true} is returned. If it existed, it is overridden and {@code true} is returned.
|
||||
* {@code false} is returned otherwise.
|
||||
*
|
||||
* @param feature
|
||||
* feature using this property to get placeholders registered
|
||||
@@ -208,7 +180,7 @@ public interface TabPlayer {
|
||||
* property name
|
||||
* @param rawValue
|
||||
* new raw value
|
||||
* @return true if value changed / did not exist, false if value did not change
|
||||
* @return {@code true} if value changed / did not exist, {@code false} if value did not change
|
||||
*/
|
||||
boolean setProperty(TabFeature feature, String identifier, String rawValue);
|
||||
|
||||
@@ -217,24 +189,24 @@ public interface TabPlayer {
|
||||
*
|
||||
* @param property
|
||||
* property name to load
|
||||
* @return true if value did not exist or changed, false otherwise
|
||||
* @return {@code true} if value did not exist or changed, {@code false} otherwise
|
||||
*/
|
||||
boolean loadPropertyFromConfig(TabFeature feature, String property);
|
||||
|
||||
/**
|
||||
* Loads property from config using standard property loading algorithm. If the property is
|
||||
* not set in config, sets it to ifNotSet value
|
||||
* not set in config, {@code ifNotSet} value is used.
|
||||
*
|
||||
* @param property
|
||||
* property name to load
|
||||
* @param ifNotSet
|
||||
* value to use if property is not defined in config
|
||||
* @return true if value did not exist or changed, false otherwise
|
||||
* @return {@code true} if value did not exist or changed, {@code false} otherwise
|
||||
*/
|
||||
boolean 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 {@code null} if NameTag feature is disabled
|
||||
*
|
||||
* @return name of player's team
|
||||
*/
|
||||
@@ -248,32 +220,31 @@ public interface TabPlayer {
|
||||
String getTeamNameNote();
|
||||
|
||||
/**
|
||||
* Returns true if player is disguised using LibsDisguises
|
||||
* Returns {@code true} if player is disguised using LibsDisguises, {@code false} if not
|
||||
*
|
||||
* @return true if player is disguised, false if not
|
||||
* @return {@code true} if player is disguised, {@code false} if not
|
||||
*/
|
||||
boolean isDisguised();
|
||||
|
||||
/**
|
||||
* Returns true if player has invisibility potion, false if not. For bukkit, API is used, for BungeeCord
|
||||
* bukkit bridge is used
|
||||
* Returns {@code true} if player has invisibility potion, {@code false} if not.
|
||||
* For bukkit, API is used, for BungeeCord, bridge is used.
|
||||
*
|
||||
* @return true if player has invisibility potion, false if not
|
||||
* @return {@code true} if player has invisibility potion, {@code false} if not
|
||||
*/
|
||||
boolean hasInvisibilityPotion();
|
||||
|
||||
/**
|
||||
* Currently only PV hook on BungeeCord for global PlayerList function. Looking to expand this
|
||||
* in the future
|
||||
* Checks if player is vanished using any supported vanish plugin and returns the result.
|
||||
*
|
||||
* @return true if vanished with PV on BungeeCord
|
||||
* @return {@code true} if player is vanished, {@code false} if not
|
||||
*/
|
||||
boolean isVanished();
|
||||
|
||||
/**
|
||||
* Returns true if player is online according to server
|
||||
* Calls platform-specific method and returns the result
|
||||
*
|
||||
* @return true if online, false if not
|
||||
* @return {@code true} if player is online, {@code false} if not
|
||||
*/
|
||||
boolean isOnline();
|
||||
|
||||
@@ -283,14 +254,60 @@ public interface TabPlayer {
|
||||
* @return GameMode of the player
|
||||
*/
|
||||
int getGamemode();
|
||||
|
||||
|
||||
/**
|
||||
* Returns {@code true} if this is a bedrock player, {@code false} if not
|
||||
*
|
||||
* @return {@code true} if player is a bedrock player, {@code false} if not
|
||||
*/
|
||||
boolean isBedrockPlayer();
|
||||
|
||||
/**
|
||||
* Returns player's primary permission group. If group has been changed using
|
||||
* {@link #setTemporaryGroup(String)}, returns that value. Otherwise, returns group
|
||||
* detected by standard group assign logic
|
||||
*
|
||||
* @return player's primary permission group
|
||||
*/
|
||||
String getGroup();
|
||||
|
||||
/**
|
||||
* Temporarily overrides player's group and applies all changes coming from new group.
|
||||
* This includes all properties and sorting, if used.
|
||||
*
|
||||
* @param group
|
||||
* New group to use
|
||||
* @see #hasTemporaryGroup()
|
||||
* @see #resetTemporaryGroup()
|
||||
*/
|
||||
void setTemporaryGroup(String group);
|
||||
|
||||
/**
|
||||
* Returns temporary group applied to the player using {@link #setTemporaryGroup(String)}.
|
||||
* If no group was set, returns {@code null}
|
||||
*
|
||||
* @return Temporary group assigned to player or {@code null} if not set
|
||||
* @see #setTemporaryGroup(String)
|
||||
* @see #resetTemporaryGroup()
|
||||
*/
|
||||
boolean hasTemporaryGroup();
|
||||
|
||||
/**
|
||||
* Resets temporary group assigned using {@link #setTemporaryGroup(String)}.
|
||||
* If no temporary group is set, doesn't do anything.
|
||||
*
|
||||
* @see #setTemporaryGroup(String)
|
||||
* @see #hasTemporaryGroup()
|
||||
*/
|
||||
void resetTemporaryGroup();
|
||||
|
||||
/**
|
||||
* Returns player's game profile name as seen by other players. By default,
|
||||
* this returns player's name. If using a nickname / disguise plugin that changes
|
||||
* game profile name for other players and change was successfully detected, returns
|
||||
* that value.
|
||||
*
|
||||
* @return player's game profile name as seen by other players
|
||||
*/
|
||||
String getNickname();
|
||||
}
|
||||
@@ -1,29 +1,168 @@
|
||||
package me.neznamy.tab.api;
|
||||
|
||||
/**
|
||||
* An interface allowing to modify tablist display names
|
||||
* of players.
|
||||
* <p>
|
||||
* Instance can be obtained using {@link TabAPI#getTablistFormatManager()}.
|
||||
* This requires the feature to be enabled in config, otherwise the method will
|
||||
* return {@code null}.
|
||||
*/
|
||||
public interface TablistFormatManager {
|
||||
|
||||
/**
|
||||
* Changes player's prefix to provided value. Supports placeholders,
|
||||
* as well as any supported RGB formats.
|
||||
*
|
||||
* @param player
|
||||
* player to change prefix of
|
||||
* @param prefix
|
||||
* new prefix value
|
||||
* @see #resetPrefix(TabPlayer)
|
||||
* @see #getCustomPrefix(TabPlayer)
|
||||
* @see #getOriginalPrefix(TabPlayer)
|
||||
*/
|
||||
void setPrefix(TabPlayer player, String prefix);
|
||||
|
||||
|
||||
/**
|
||||
* Changes player's name to provided value. Supports placeholders,
|
||||
* as well as any supported RGB formats.
|
||||
*
|
||||
* @param player
|
||||
* player to change prefix of
|
||||
* @param customName
|
||||
* new customName value
|
||||
* @see #resetName(TabPlayer)
|
||||
* @see #getCustomName(TabPlayer)
|
||||
* @see #getOriginalName(TabPlayer)
|
||||
*/
|
||||
void setName(TabPlayer player, String customName);
|
||||
|
||||
|
||||
/**
|
||||
* Changes player's suffix to provided value. Supports placeholders,
|
||||
* as well as any supported RGB formats.
|
||||
*
|
||||
* @param player
|
||||
* player to change prefix of
|
||||
* @param suffix
|
||||
* new suffix value
|
||||
* @see #resetSuffix(TabPlayer)
|
||||
* @see #getCustomSuffix(TabPlayer)
|
||||
* @see #getOriginalSuffix(TabPlayer)
|
||||
*/
|
||||
void setSuffix(TabPlayer player, String suffix);
|
||||
|
||||
|
||||
/**
|
||||
* Resets player's prefix previously assigned using {@link #setPrefix(TabPlayer, String)}
|
||||
* method. If nothing was set, this method will not do anything.
|
||||
*
|
||||
* @param player
|
||||
* player to reset prefix of
|
||||
* @see #setPrefix(TabPlayer, String)
|
||||
* @see #getCustomPrefix(TabPlayer)
|
||||
* @see #getOriginalPrefix(TabPlayer)
|
||||
*/
|
||||
void resetPrefix(TabPlayer player);
|
||||
|
||||
|
||||
/**
|
||||
* Resets player's custom name previously assigned using {@link #setName(TabPlayer, String)}
|
||||
* method. If nothing was set, this method will not do anything.
|
||||
*
|
||||
* @param player
|
||||
* player to reset name of
|
||||
* @see #setName(TabPlayer, String)
|
||||
* @see #getCustomName(TabPlayer)
|
||||
* @see #getOriginalName(TabPlayer)
|
||||
*/
|
||||
void resetName(TabPlayer player);
|
||||
|
||||
|
||||
/**
|
||||
* Resets player's suffix previously assigned using {@link #setSuffix(TabPlayer, String)}
|
||||
* method. If nothing was set, this method will not do anything.
|
||||
*
|
||||
* @param player
|
||||
* player to reset suffix of
|
||||
* @see #setSuffix(TabPlayer, String)
|
||||
* @see #getCustomSuffix(TabPlayer)
|
||||
* @see #getOriginalSuffix(TabPlayer)
|
||||
*/
|
||||
void resetSuffix(TabPlayer player);
|
||||
|
||||
|
||||
/**
|
||||
* Returns prefix assigned using {@link #setPrefix(TabPlayer, String)} method.
|
||||
* If the method was not used, {@code null} is returned.
|
||||
*
|
||||
* @param player
|
||||
* player to get custom prefix of
|
||||
* @return player's custom prefix or {@code null} if not defined
|
||||
* @see #setPrefix(TabPlayer, String)
|
||||
* @see #resetPrefix(TabPlayer)
|
||||
* @see #getOriginalPrefix(TabPlayer)
|
||||
*/
|
||||
String getCustomPrefix(TabPlayer player);
|
||||
|
||||
|
||||
/**
|
||||
* Returns custom name assigned using {@link #setName(TabPlayer, String)} method.
|
||||
* If the method was not used, {@code null} is returned.
|
||||
*
|
||||
* @param player
|
||||
* player to get custom name of
|
||||
* @return player's custom name or {@code null} if not defined
|
||||
* @see #setName(TabPlayer, String)
|
||||
* @see #resetName(TabPlayer)
|
||||
* @see #getOriginalName(TabPlayer)
|
||||
*/
|
||||
String getCustomName(TabPlayer player);
|
||||
|
||||
|
||||
/**
|
||||
* Returns suffix assigned using {@link #setSuffix(TabPlayer, String)} method.
|
||||
* If the method was not used, {@code null} is returned.
|
||||
*
|
||||
* @param player
|
||||
* player to get custom suffix of
|
||||
* @return player's custom suffix or {@code null} if not defined
|
||||
* @see #setSuffix(TabPlayer, String)
|
||||
* @see #resetSuffix(TabPlayer)
|
||||
* @see #getOriginalSuffix(TabPlayer)
|
||||
*/
|
||||
String getCustomSuffix(TabPlayer player);
|
||||
|
||||
|
||||
/**
|
||||
* Returns player's original prefix applied using plugin's internal logic.
|
||||
* This value is not affected by API calls in any way.
|
||||
*
|
||||
* @param player
|
||||
* player to get original prefix of
|
||||
* @return player's original prefix
|
||||
* @see #setPrefix(TabPlayer, String)
|
||||
* @see #resetPrefix(TabPlayer)
|
||||
* @see #getCustomPrefix(TabPlayer)
|
||||
*/
|
||||
String getOriginalPrefix(TabPlayer player);
|
||||
|
||||
|
||||
/**
|
||||
* Returns player's original name applied using plugin's internal logic.
|
||||
* This value is not affected by API calls in any way.
|
||||
*
|
||||
* @param player
|
||||
* player to get original name of
|
||||
* @return player's original name
|
||||
* @see #setName(TabPlayer, String)
|
||||
* @see #resetName(TabPlayer)
|
||||
* @see #getCustomName(TabPlayer)
|
||||
*/
|
||||
String getOriginalName(TabPlayer player);
|
||||
|
||||
|
||||
/**
|
||||
* Returns player's original suffix applied using plugin's internal logic.
|
||||
* This value is not affected by API calls in any way.
|
||||
*
|
||||
* @param player
|
||||
* player to get original suffix of
|
||||
* @return player's original suffix
|
||||
* @see #setSuffix(TabPlayer, String)
|
||||
* @see #resetSuffix(TabPlayer)
|
||||
* @see #getCustomSuffix(TabPlayer)
|
||||
*/
|
||||
String getOriginalSuffix(TabPlayer player);
|
||||
|
||||
}
|
||||
@@ -199,4 +199,12 @@ public interface BossBar {
|
||||
* @return {@code true} if contains, {@code false} if not
|
||||
*/
|
||||
boolean containsPlayer(TabPlayer player);
|
||||
|
||||
/**
|
||||
* Returns {@code true} if this bossbar in configured as announcement-only bar,
|
||||
* {@code false} if not.
|
||||
*
|
||||
* @return {@code true} if bar is announcement only, {@code false} if not
|
||||
*/
|
||||
boolean isAnnouncementBar();
|
||||
}
|
||||
@@ -4,15 +4,16 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import me.neznamy.tab.api.TabAPI;
|
||||
import me.neznamy.tab.api.TabPlayer;
|
||||
|
||||
/**
|
||||
* 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()}.
|
||||
* Instance can be obtained using {@link TabAPI#getBossBarManager()}.
|
||||
* This requires the BossBar feature to be enabled in config, otherwise the method will
|
||||
* return null.
|
||||
* return {@code null}.
|
||||
*/
|
||||
public interface BossBarManager {
|
||||
|
||||
|
||||
@@ -231,7 +231,7 @@ public class IChatBaseComponent {
|
||||
*/
|
||||
public static IChatBaseComponent fromColoredText(String originalText){
|
||||
Preconditions.checkNotNull(originalText, "text");
|
||||
String text = RGBUtils.getInstance().applyFormats(EnumChatFormat.color(originalText), false);
|
||||
String text = RGBUtils.getInstance().applyFormats(EnumChatFormat.color(originalText));
|
||||
List<IChatBaseComponent> components = new ArrayList<>();
|
||||
StringBuilder builder = new StringBuilder();
|
||||
IChatBaseComponent component = new IChatBaseComponent();
|
||||
@@ -424,7 +424,7 @@ public class IChatBaseComponent {
|
||||
if (text == null) return null;
|
||||
if (componentCache.containsKey(text)) return componentCache.get(text);
|
||||
IChatBaseComponent component;
|
||||
if (text.contains("#") || text.contains("&x") || text.contains(EnumChatFormat.COLOR_CHAR + "x")){
|
||||
if (text.contains("#") || text.contains("&x") || text.contains(EnumChatFormat.COLOR_CHAR + "x") || text.contains("<")){
|
||||
//contains RGB colors
|
||||
component = IChatBaseComponent.fromColoredText(text);
|
||||
} else {
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
package me.neznamy.tab.api.chat;
|
||||
|
||||
import me.neznamy.tab.api.ProtocolVersion;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A class extending IChatBaseComponent that holds the original value
|
||||
* to avoid deserializing it, which is an unnecessary operation that
|
||||
* slows down the performance, as well as makes code more complicated
|
||||
* and open to problems.
|
||||
*/
|
||||
public class WrappedChatComponent extends IChatBaseComponent {
|
||||
|
||||
/** Original NMS component */
|
||||
private final Object originalComponent;
|
||||
|
||||
/**
|
||||
* Constructs new instance with given parameter
|
||||
*
|
||||
* @param originalComponent
|
||||
* Original NMS component
|
||||
*/
|
||||
public WrappedChatComponent(Object originalComponent) {
|
||||
this.originalComponent = originalComponent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the original NMS component
|
||||
* @return the original NMS component
|
||||
*/
|
||||
public Object get() {
|
||||
return originalComponent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
throw new UnsupportedOperationException("Not supported for " + getClass().getSimpleName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(ProtocolVersion clientVersion) {
|
||||
throw new UnsupportedOperationException("Not supported for " + getClass().getSimpleName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IChatBaseComponent> getExtra(){
|
||||
throw new UnsupportedOperationException("Not supported for " + getClass().getSimpleName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText() {
|
||||
throw new UnsupportedOperationException("Not supported for " + getClass().getSimpleName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChatModifier getModifier() {
|
||||
throw new UnsupportedOperationException("Not supported for " + getClass().getSimpleName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public IChatBaseComponent setExtra(List<IChatBaseComponent> components){
|
||||
throw new UnsupportedOperationException("Not supported for " + getClass().getSimpleName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addExtra(IChatBaseComponent child) {
|
||||
throw new UnsupportedOperationException("Not supported for " + getClass().getSimpleName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setModifier(ChatModifier modifier) {
|
||||
throw new UnsupportedOperationException("Not supported for " + getClass().getSimpleName());
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,13 @@
|
||||
package me.neznamy.tab.api.chat.rgb;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import me.neznamy.tab.api.chat.EnumChatFormat;
|
||||
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.RGBFormatter;
|
||||
import me.neznamy.tab.api.chat.rgb.format.UnnamedFormat1;
|
||||
import me.neznamy.tab.api.chat.rgb.format.*;
|
||||
import me.neznamy.tab.api.chat.rgb.gradient.CMIGradient;
|
||||
import me.neznamy.tab.api.chat.rgb.gradient.CommonGradient;
|
||||
import me.neznamy.tab.api.chat.rgb.gradient.GradientPattern;
|
||||
@@ -40,12 +38,18 @@ public class RGBUtils {
|
||||
* Constructs new instance and loads all RGB patterns and gradients
|
||||
*/
|
||||
public RGBUtils() {
|
||||
formats = new RGBFormatter[] {
|
||||
new BukkitFormat(),
|
||||
new CMIFormat(),
|
||||
new UnnamedFormat1(),
|
||||
new HtmlFormat()
|
||||
};
|
||||
List<RGBFormatter> list = new ArrayList<>();
|
||||
list.add(new BukkitFormat());
|
||||
list.add(new CMIFormat());
|
||||
list.add(new UnnamedFormat1());
|
||||
list.add(new HtmlFormat());
|
||||
list.add(new KyoriFormat());
|
||||
try {
|
||||
Class.forName("net.kyori.adventure.text.minimessage.MiniMessage");
|
||||
list.add(new MiniMessageFormat());
|
||||
} catch (ClassNotFoundException ignored) {}
|
||||
formats = list.toArray(new RGBFormatter[0]);
|
||||
|
||||
gradients = new GradientPattern[] {
|
||||
//{#RRGGBB>}text{#RRGGBB<}
|
||||
new CMIGradient(),
|
||||
@@ -72,21 +76,16 @@ public class RGBUtils {
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
public String applyFormats(String text) {
|
||||
Preconditions.checkNotNull(text, "text");
|
||||
String replaced = text;
|
||||
for (GradientPattern pattern : gradients) {
|
||||
replaced = pattern.applyPattern(replaced, ignorePlaceholders);
|
||||
replaced = pattern.applyPattern(replaced, false);
|
||||
}
|
||||
for (RGBFormatter formatter : formats) {
|
||||
replaced = formatter.reformat(replaced);
|
||||
@@ -94,6 +93,23 @@ public class RGBUtils {
|
||||
return replaced;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies all gradient formats to text and returns it. This only affects
|
||||
* usage where no placeholder is used inside.
|
||||
*
|
||||
* @param text
|
||||
* original text
|
||||
* @return text where all gradients with static text are converted to #RRGGBB
|
||||
*/
|
||||
public String applyCleanGradients(String text) {
|
||||
Preconditions.checkNotNull(text, "text");
|
||||
String replaced = text;
|
||||
for (GradientPattern pattern : gradients) {
|
||||
replaced = pattern.applyPattern(replaced, true);
|
||||
}
|
||||
return replaced;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts TAB's RGB format (#RRGGBB) into bukkit one
|
||||
* (&x&r&r&g&g&b&b) for modern
|
||||
@@ -110,7 +126,7 @@ public class RGBUtils {
|
||||
if (!text.contains("#")) return text; //no rgb codes
|
||||
if (rgbClient) {
|
||||
//converting random formats to TAB one
|
||||
String replaced = applyFormats(text, false);
|
||||
String replaced = applyFormats(text);
|
||||
for (Pattern p : new Pattern[]{tabPatternLegacy, tabPattern}) {
|
||||
Matcher m = p.matcher(replaced);
|
||||
while (m.find()) {
|
||||
@@ -135,7 +151,7 @@ public class RGBUtils {
|
||||
public String convertRGBtoLegacy(String text) {
|
||||
if (text == null) return null;
|
||||
if (!text.contains("#")) return EnumChatFormat.color(text);
|
||||
String applied = applyFormats(text, false);
|
||||
String applied = applyFormats(text);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < applied.length(); i++){
|
||||
char c = applied.charAt(i);
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package me.neznamy.tab.api.chat.rgb.format;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Formatter for <#RRGGBB>
|
||||
*/
|
||||
public class KyoriFormat implements RGBFormatter {
|
||||
|
||||
private final Pattern pattern = Pattern.compile("<#[0-9a-fA-F]{6}>");
|
||||
|
||||
@Override
|
||||
public String reformat(String text) {
|
||||
if (!text.contains("<#")) return text;
|
||||
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);
|
||||
}
|
||||
return replaced;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package me.neznamy.tab.api.chat.rgb.format;
|
||||
|
||||
import me.neznamy.tab.api.chat.EnumChatFormat;
|
||||
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||
|
||||
/**
|
||||
* Formatter for <#RRGGBB>
|
||||
*/
|
||||
public class MiniMessageFormat implements RGBFormatter {
|
||||
|
||||
@Override
|
||||
public String reformat(String text) {
|
||||
if (!text.contains("<")) return text;
|
||||
String format = text.replace(EnumChatFormat.RESET.getFormat(), ""); //remove &r from header/footer newline inserts
|
||||
try {
|
||||
return LegacyComponentSerializer.legacySection().serialize(MiniMessage.miniMessage().deserialize(format));
|
||||
} catch (Exception ignored) {
|
||||
return text;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -224,7 +224,7 @@ public abstract class ConfigurationFile {
|
||||
}
|
||||
List<String> fixedList = new ArrayList<>();
|
||||
for (Object key : (List<Object>)value) {
|
||||
fixedList.add(key.toString());
|
||||
fixedList.add(String.valueOf(key));
|
||||
}
|
||||
return fixedList;
|
||||
}
|
||||
|
||||
@@ -6,11 +6,9 @@ public interface Placeholder {
|
||||
|
||||
String getIdentifier();
|
||||
|
||||
boolean isTriggerMode();
|
||||
|
||||
void enableTriggerMode();
|
||||
|
||||
void enableTriggerMode(Runnable onActivation, Runnable onDisable);
|
||||
|
||||
void unload();
|
||||
|
||||
boolean isUsed();
|
||||
}
|
||||
@@ -48,4 +48,6 @@ public interface PlaceholderManager {
|
||||
String findReplacement(String placeholder, String output);
|
||||
|
||||
List<String> getUsedPlaceholders();
|
||||
|
||||
Placeholder getPlaceholder(String identifier);
|
||||
}
|
||||
@@ -49,10 +49,20 @@ public interface ThreadManager {
|
||||
* usage type to add cpu usage to
|
||||
* @param task
|
||||
* the task
|
||||
* @return Future representing the submitted task
|
||||
*/
|
||||
RepeatingTask startRepeatingMeasuredTask(int intervalMilliseconds, TabFeature feature, String type, Runnable task);
|
||||
Future<?> startRepeatingMeasuredTask(int intervalMilliseconds, TabFeature feature, String type, Runnable task);
|
||||
|
||||
RepeatingTask startRepeatingTask(int intervalMilliseconds, Runnable task);
|
||||
/**
|
||||
* Starts a new task with defined repeat interval
|
||||
*
|
||||
* @param intervalMilliseconds
|
||||
* task interval
|
||||
* @param task
|
||||
* the task
|
||||
* @return Future representing the submitted task
|
||||
*/
|
||||
Future<?> startRepeatingTask(int intervalMilliseconds, Runnable task);
|
||||
|
||||
/**
|
||||
* Runs task with a delay and measures how long it took to process
|
||||
@@ -65,9 +75,18 @@ public interface ThreadManager {
|
||||
* usage type to add cpu usage to
|
||||
* @param task
|
||||
* the task
|
||||
* @return future allowing to cancel the task
|
||||
* @return Future representing the submitted task
|
||||
*/
|
||||
Future<?> runTaskLater(int delayMilliseconds, TabFeature feature, String type, Runnable task);
|
||||
|
||||
/**
|
||||
* Runs task with a delay
|
||||
*
|
||||
* @param delayMilliseconds
|
||||
* how long to run the task after
|
||||
* @param task
|
||||
* the task
|
||||
* @return Future representing the submitted task
|
||||
*/
|
||||
Future<?> runTaskLater(int delayMilliseconds, Runnable task);
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
package me.neznamy.tab.api.util;
|
||||
|
||||
import me.neznamy.tab.api.TabPlayer;
|
||||
|
||||
public class Preconditions {
|
||||
|
||||
private Preconditions(){}
|
||||
@@ -17,4 +19,8 @@ public class Preconditions {
|
||||
if (number.doubleValue() < min.doubleValue() || number.doubleValue() > max.doubleValue())
|
||||
throw new IllegalArgumentException(variable + " index out of range (" + min + " - " + max + ")");
|
||||
}
|
||||
|
||||
public static void checkLoaded(TabPlayer player) {
|
||||
if (!player.isLoaded()) throw new IllegalStateException("Player is not loaded yet. Try again later.");
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,8 @@ tasks {
|
||||
))
|
||||
}
|
||||
javadoc {
|
||||
// This saves a decent bit of processing power on slow machines
|
||||
enabled = false
|
||||
options.encoding = Charsets.UTF_8.name()
|
||||
(options as StandardJavadocDocletOptions).addStringOption("Xdoclint:none", "-quiet")
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ dependencies {
|
||||
compileOnly(libs.vault)
|
||||
compileOnly(libs.via)
|
||||
compileOnly(libs.authlib)
|
||||
compileOnly(libs.libsDisguises)
|
||||
compileOnly(libs.essentials)
|
||||
compileOnly(libs.essentials) {
|
||||
exclude("org.spigotmc", "spigot-api")
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package me.neznamy.tab.platforms.bukkit;
|
||||
|
||||
import me.neznamy.tab.api.TabAPI;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
@@ -8,15 +9,20 @@ import org.bukkit.event.player.PlayerCommandPreprocessEvent;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
|
||||
/**
|
||||
* The core for bukkit forwarding events into all enabled features
|
||||
*/
|
||||
public class BukkitEventListener implements Listener {
|
||||
|
||||
/** Platform instance */
|
||||
private final BukkitPlatform platform;
|
||||
|
||||
|
||||
/**
|
||||
* Constructs new instance with given parameter
|
||||
*
|
||||
* @param platform
|
||||
* Platform instance
|
||||
*/
|
||||
public BukkitEventListener(BukkitPlatform platform) {
|
||||
this.platform = platform;
|
||||
}
|
||||
@@ -29,8 +35,8 @@ public class BukkitEventListener implements Listener {
|
||||
*/
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onQuit(PlayerQuitEvent e){
|
||||
if (TAB.getInstance().isDisabled()) return;
|
||||
TAB.getInstance().getCPUManager().runTask(() -> TAB.getInstance().getFeatureManager().onQuit(TAB.getInstance().getPlayer(e.getPlayer().getUniqueId())));
|
||||
if (TabAPI.getInstance().isPluginDisabled()) return;
|
||||
TabAPI.getInstance().getThreadManager().runTask(() -> TabAPI.getInstance().getFeatureManager().onQuit(TabAPI.getInstance().getPlayer(e.getPlayer().getUniqueId())));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -41,8 +47,8 @@ public class BukkitEventListener implements Listener {
|
||||
*/
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onJoin(PlayerJoinEvent e) {
|
||||
if (TAB.getInstance().isDisabled()) return;
|
||||
TAB.getInstance().getCPUManager().runTask(() -> TAB.getInstance().getFeatureManager().onJoin(new BukkitTabPlayer(e.getPlayer(), platform.getProtocolVersion(e.getPlayer()))));
|
||||
if (TabAPI.getInstance().isPluginDisabled()) return;
|
||||
TabAPI.getInstance().getThreadManager().runTask(() -> TabAPI.getInstance().getFeatureManager().onJoin(new BukkitTabPlayer(e.getPlayer(), platform.getProtocolVersion(e.getPlayer()))));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -53,8 +59,8 @@ public class BukkitEventListener implements Listener {
|
||||
*/
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onWorldChange(PlayerChangedWorldEvent e){
|
||||
if (TAB.getInstance().isDisabled()) return;
|
||||
TAB.getInstance().getCPUManager().runTask(() -> TAB.getInstance().getFeatureManager().onWorldChange(e.getPlayer().getUniqueId(), e.getPlayer().getWorld().getName()));
|
||||
if (TabAPI.getInstance().isPluginDisabled()) return;
|
||||
TabAPI.getInstance().getThreadManager().runTask(() -> TabAPI.getInstance().getFeatureManager().onWorldChange(e.getPlayer().getUniqueId(), e.getPlayer().getWorld().getName()));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -65,7 +71,7 @@ public class BukkitEventListener implements Listener {
|
||||
*/
|
||||
@EventHandler
|
||||
public void onCommand(PlayerCommandPreprocessEvent e) {
|
||||
if (TAB.getInstance().isDisabled()) return;
|
||||
if (TAB.getInstance().getFeatureManager().onCommand(TAB.getInstance().getPlayer(e.getPlayer().getUniqueId()), e.getMessage())) e.setCancelled(true);
|
||||
if (TabAPI.getInstance().isPluginDisabled()) return;
|
||||
if (TabAPI.getInstance().getFeatureManager().onCommand(TabAPI.getInstance().getPlayer(e.getPlayer().getUniqueId()), e.getMessage())) e.setCancelled(true);
|
||||
}
|
||||
}
|
||||
@@ -1,82 +1,54 @@
|
||||
package me.neznamy.tab.platforms.bukkit;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.EnumMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.mojang.authlib.properties.Property;
|
||||
import me.neznamy.tab.api.protocol.*;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.EntityType;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
|
||||
import com.mojang.authlib.properties.Property;
|
||||
import me.neznamy.tab.api.ProtocolVersion;
|
||||
import me.neznamy.tab.api.chat.ChatClickable.EnumClickAction;
|
||||
import me.neznamy.tab.api.chat.ChatComponentEntity;
|
||||
import me.neznamy.tab.api.chat.ChatHoverable.EnumHoverAction;
|
||||
import me.neznamy.tab.api.TabAPI;
|
||||
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.WrappedChatComponent;
|
||||
import me.neznamy.tab.api.protocol.*;
|
||||
import me.neznamy.tab.api.protocol.PacketPlayOutBoss.Action;
|
||||
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.platforms.bukkit.nms.NMSStorage;
|
||||
import me.neznamy.tab.platforms.bukkit.nms.PacketPlayOutEntityDestroy;
|
||||
import me.neznamy.tab.platforms.bukkit.nms.PacketPlayOutEntityMetadata;
|
||||
import me.neznamy.tab.platforms.bukkit.nms.PacketPlayOutEntityTeleport;
|
||||
import me.neznamy.tab.platforms.bukkit.nms.PacketPlayOutSpawnEntityLiving;
|
||||
import me.neznamy.tab.platforms.bukkit.nms.*;
|
||||
import me.neznamy.tab.platforms.bukkit.nms.datawatcher.DataWatcher;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.EntityType;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.*;
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
public class BukkitPacketBuilder extends PacketBuilder {
|
||||
|
||||
//nms storage
|
||||
/** NMS data storage */
|
||||
private final NMSStorage nms = NMSStorage.getInstance();
|
||||
|
||||
//entity type ids
|
||||
/** Map of entity type ids for entities used by the plugin */
|
||||
private final EnumMap<EntityType, Integer> entityIds = new EnumMap<>(EntityType.class);
|
||||
|
||||
/** Component cache for better performance (1.16+ players) */
|
||||
private final Map<IChatBaseComponent, Object> componentCacheModern = new HashMap<>();
|
||||
private final Map<IChatBaseComponent, Object> componentCacheLegacy = new HashMap<>();
|
||||
|
||||
private Object emptyScoreboard;
|
||||
private Object dummyEntity;
|
||||
/** Component cache for better performance (1.15- players) */
|
||||
private final Map<IChatBaseComponent, Object> componentCacheLegacy = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Constructs new instance
|
||||
*/
|
||||
public BukkitPacketBuilder() {
|
||||
if (nms.getMinorVersion() >= 13) {
|
||||
if (nms.getMinorVersion() >= 19) {
|
||||
entityIds.put(EntityType.ARMOR_STAND, 2);
|
||||
} else if (nms.getMinorVersion() >= 13) {
|
||||
entityIds.put(EntityType.ARMOR_STAND, 1);
|
||||
entityIds.put(EntityType.WITHER, 83);
|
||||
} else {
|
||||
entityIds.put(EntityType.WITHER, 64);
|
||||
if (nms.getMinorVersion() >= 8){
|
||||
entityIds.put(EntityType.ARMOR_STAND, 30);
|
||||
}
|
||||
}
|
||||
try {
|
||||
emptyScoreboard = nms.newScoreboard.newInstance();
|
||||
} catch (ReflectiveOperationException e) {
|
||||
Bukkit.getConsoleSender().sendMessage(EnumChatFormat.color("&c[TAB] Failed to create instance of \"Scoreboard\""));
|
||||
}
|
||||
if (nms.getMinorVersion() >= 8) {
|
||||
try {
|
||||
dummyEntity = nms.newEntityArmorStand.newInstance(nms.World_getHandle.invoke(Bukkit.getWorlds().get(0)), 0, 0, 0);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
Bukkit.getConsoleSender().sendMessage(EnumChatFormat.color("&c[TAB] Failed to create instance of \"EntityArmorStand\""));
|
||||
}
|
||||
}
|
||||
buildMap.put(PacketPlayOutEntityMetadata.class, (packet, version) -> build((PacketPlayOutEntityMetadata)packet));
|
||||
buildMap.put(PacketPlayOutEntityTeleport.class, (packet, version) -> build((PacketPlayOutEntityTeleport)packet));
|
||||
buildMap.put(PacketPlayOutEntityDestroy.class, (packet, version) -> build((PacketPlayOutEntityDestroy)packet));
|
||||
@@ -96,19 +68,22 @@ public class BukkitPacketBuilder extends PacketBuilder {
|
||||
@Override
|
||||
public Object build(PacketPlayOutChat packet, ProtocolVersion clientVersion) throws ReflectiveOperationException {
|
||||
Object component = toNMSComponent(packet.getMessage(), clientVersion);
|
||||
if (nms.getMinorVersion() >= 16) {
|
||||
if (nms.getMinorVersion() >= 19)
|
||||
try {
|
||||
return nms.newPacketPlayOutChat.newInstance(component, packet.getType() == PacketPlayOutChat.ChatMessageType.GAME_INFO);
|
||||
} catch (Exception e) {
|
||||
//1.19.0
|
||||
return nms.newPacketPlayOutChat.newInstance(component, packet.getType().ordinal());
|
||||
}
|
||||
if (nms.getMinorVersion() >= 16)
|
||||
return nms.newPacketPlayOutChat.newInstance(component, nms.ChatMessageType_values[packet.getType().ordinal()], UUID.randomUUID());
|
||||
}
|
||||
if (nms.getMinorVersion() >= 12) {
|
||||
if (nms.getMinorVersion() >= 12)
|
||||
return nms.newPacketPlayOutChat.newInstance(component, Enum.valueOf((Class<Enum>) nms.ChatMessageType, packet.getType().toString()));
|
||||
}
|
||||
if (nms.getMinorVersion() >= 8) {
|
||||
if (nms.getMinorVersion() >= 8)
|
||||
return nms.newPacketPlayOutChat.newInstance(component, (byte) packet.getType().ordinal());
|
||||
}
|
||||
if (nms.getMinorVersion() == 7) {
|
||||
if (nms.getMinorVersion() == 7)
|
||||
return nms.newPacketPlayOutChat.newInstance(component);
|
||||
}
|
||||
throw new IllegalStateException("Not supported on <1.7");
|
||||
return packet;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -120,13 +95,14 @@ public class BukkitPacketBuilder extends PacketBuilder {
|
||||
GameProfile profile = new GameProfile(data.getUniqueId(), data.getName());
|
||||
if (data.getSkin() != null) profile.getProperties().put("textures", new Property("textures", data.getSkin().getValue(), data.getSkin().getSignature()));
|
||||
List<Object> parameters = new ArrayList<>();
|
||||
if (nms.newPlayerInfoData.getParameterCount() == 5) {
|
||||
if (nms.newPlayerInfoData.getParameterTypes()[0] == nms.PacketPlayOutPlayerInfo) {
|
||||
parameters.add(nmsPacket);
|
||||
}
|
||||
parameters.add(profile);
|
||||
parameters.add(data.getLatency());
|
||||
parameters.add(data.getGameMode() == null ? null : nms.EnumGamemode_values[nms.EnumGamemode_values.length-EnumGamemode.VALUES.length+data.getGameMode().ordinal()]); //not_set was removed in 1.17
|
||||
parameters.add(data.getDisplayName() == null ? null : toNMSComponent(data.getDisplayName(), clientVersion));
|
||||
if (nms.getMinorVersion() >= 19) parameters.add(null);
|
||||
items.add(nms.newPlayerInfoData.newInstance(parameters.toArray()));
|
||||
}
|
||||
nms.setField(nmsPacket, nms.PacketPlayOutPlayerInfo_PLAYERS, items);
|
||||
@@ -178,7 +154,7 @@ public class BukkitPacketBuilder extends PacketBuilder {
|
||||
if (packet.getAction() == PacketPlayOutScoreboardScore.Action.REMOVE) {
|
||||
return nms.newPacketPlayOutScoreboardScore_String.newInstance(packet.getPlayer());
|
||||
}
|
||||
Object score = nms.newScoreboardScore.newInstance(emptyScoreboard, newScoreboardObjective(packet.getObjectiveName()), packet.getPlayer());
|
||||
Object score = nms.newScoreboardScore.newInstance(nms.emptyScoreboard, newScoreboardObjective(packet.getObjectiveName()), packet.getPlayer());
|
||||
nms.ScoreboardScore_setScore.invoke(score, packet.getScore());
|
||||
if (nms.getMinorVersion() >= 8) {
|
||||
return nms.newPacketPlayOutScoreboardScore.newInstance(score);
|
||||
@@ -189,7 +165,7 @@ public class BukkitPacketBuilder extends PacketBuilder {
|
||||
@Override
|
||||
public Object build(PacketPlayOutScoreboardTeam packet, ProtocolVersion clientVersion) throws ReflectiveOperationException {
|
||||
if (nms.PacketPlayOutScoreboardTeam == null) return null; //fabric
|
||||
Object team = nms.newScoreboardTeam.newInstance(emptyScoreboard, packet.getName());
|
||||
Object team = nms.newScoreboardTeam.newInstance(nms.emptyScoreboard, packet.getName());
|
||||
String prefix = packet.getPlayerPrefix();
|
||||
String suffix = packet.getPlayerSuffix();
|
||||
if (clientVersion.getMinorVersion() < 13) {
|
||||
@@ -224,9 +200,11 @@ public class BukkitPacketBuilder extends PacketBuilder {
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds entity destroy packet with given parameter
|
||||
* Builds entity destroy packet from custom packet class
|
||||
*
|
||||
* @return destroy packet
|
||||
* @param packet
|
||||
* Destroy packet
|
||||
* @return NMS destroy packet
|
||||
* @throws ReflectiveOperationException
|
||||
* if thrown by reflective operation
|
||||
*/
|
||||
@@ -239,26 +217,36 @@ public class BukkitPacketBuilder extends PacketBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds entity metadata packet from custom packet class
|
||||
*
|
||||
* @param packet
|
||||
* Metadata packet
|
||||
* @return NMS metadata packet
|
||||
* @throws ReflectiveOperationException
|
||||
* if thrown by reflective operation
|
||||
*/
|
||||
public Object build(PacketPlayOutEntityMetadata packet) throws ReflectiveOperationException {
|
||||
return nms.newPacketPlayOutEntityMetadata.newInstance(packet.getEntityId(), packet.getDataWatcher().toNMS(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds entity spawn packet with given parameters
|
||||
* Builds entity spawn packet from custom packet class
|
||||
*
|
||||
* @return entity spawn packet
|
||||
* @param packet
|
||||
* Spawn packet
|
||||
* @return NMS spawn packet
|
||||
* @throws ReflectiveOperationException
|
||||
* if thrown by reflective operation
|
||||
*/
|
||||
public Object build(PacketPlayOutSpawnEntityLiving packet) throws ReflectiveOperationException {
|
||||
Object nmsPacket;
|
||||
if (nms.getMinorVersion() >= 17) {
|
||||
nmsPacket = nms.newPacketPlayOutSpawnEntityLiving.newInstance(dummyEntity);
|
||||
nmsPacket = nms.newPacketPlayOutSpawnEntityLiving.newInstance(nms.dummyEntity);
|
||||
} else {
|
||||
nmsPacket = nms.newPacketPlayOutSpawnEntityLiving.newInstance();
|
||||
}
|
||||
nms.setField(nmsPacket, nms.PacketPlayOutSpawnEntityLiving_ENTITYID, packet.getEntityId());
|
||||
nms.setField(nmsPacket, nms.PacketPlayOutSpawnEntityLiving_ENTITYTYPE, entityIds.get(packet.getEntityType()));
|
||||
nms.setField(nmsPacket, nms.PacketPlayOutSpawnEntityLiving_YAW, (byte)(packet.getLocation().getYaw() * 256.0f / 360.0f));
|
||||
nms.setField(nmsPacket, nms.PacketPlayOutSpawnEntityLiving_PITCH, (byte)(packet.getLocation().getPitch() * 256.0f / 360.0f));
|
||||
if (nms.getMinorVersion() <= 14) {
|
||||
@@ -274,20 +262,28 @@ public class BukkitPacketBuilder extends PacketBuilder {
|
||||
nms.setField(nmsPacket, nms.PacketPlayOutSpawnEntityLiving_Y, floor(packet.getLocation().getY()*32));
|
||||
nms.setField(nmsPacket, nms.PacketPlayOutSpawnEntityLiving_Z, floor(packet.getLocation().getZ()*32));
|
||||
}
|
||||
int id = entityIds.get(packet.getEntityType());
|
||||
if (nms.getMinorVersion() >= 19) {
|
||||
nms.setField(nmsPacket, nms.PacketPlayOutSpawnEntityLiving_ENTITYTYPE, nms.Registry_a.invoke(nms.IRegistry_X, id));
|
||||
} else {
|
||||
nms.setField(nmsPacket, nms.PacketPlayOutSpawnEntityLiving_ENTITYTYPE, id);
|
||||
}
|
||||
return nmsPacket;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds entity teleport packet with given parameters
|
||||
* Builds entity teleport packet from custom packet class
|
||||
*
|
||||
* @return entity teleport packet
|
||||
* @param packet
|
||||
* Teleport packet
|
||||
* @return NMS teleport packet
|
||||
* @throws ReflectiveOperationException
|
||||
* if thrown by reflective operation
|
||||
*/
|
||||
public Object build(PacketPlayOutEntityTeleport packet) throws ReflectiveOperationException {
|
||||
Object nmsPacket;
|
||||
if (nms.getMinorVersion() >= 17) {
|
||||
nmsPacket = nms.newPacketPlayOutEntityTeleport.newInstance(dummyEntity);
|
||||
nmsPacket = nms.newPacketPlayOutEntityTeleport.newInstance(nms.dummyEntity);
|
||||
} else {
|
||||
nmsPacket = nms.newPacketPlayOutEntityTeleport.newInstance();
|
||||
}
|
||||
@@ -305,7 +301,23 @@ public class BukkitPacketBuilder extends PacketBuilder {
|
||||
nms.setField(nmsPacket, nms.PacketPlayOutEntityTeleport_PITCH, (byte) (packet.getLocation().getPitch()/360*256));
|
||||
return nmsPacket;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Writes data into NMS team from custom team packet. Used on 1.13+ servers.
|
||||
*
|
||||
* @param packet
|
||||
* Packet to read from
|
||||
* @param clientVersion
|
||||
* Version of player
|
||||
* @param team
|
||||
* Team to write to
|
||||
* @param prefix
|
||||
* Prefix to use
|
||||
* @param suffix
|
||||
* Suffix to use
|
||||
* @throws ReflectiveOperationException
|
||||
* if thrown by reflective operation
|
||||
*/
|
||||
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));
|
||||
@@ -315,6 +327,20 @@ public class BukkitPacketBuilder extends PacketBuilder {
|
||||
nms.ScoreboardTeam_setCollisionRule.invoke(team, String.valueOf(packet.getCollisionRule()).equals("always") ? nms.EnumTeamPush_values[0] : nms.EnumTeamPush_values[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes data into NMS team from custom team packet. Used on 1.12- servers.
|
||||
*
|
||||
* @param packet
|
||||
* Packet to read from
|
||||
* @param team
|
||||
* Team to write to
|
||||
* @param prefix
|
||||
* Prefix to use
|
||||
* @param suffix
|
||||
* Suffix to use
|
||||
* @throws ReflectiveOperationException
|
||||
* if thrown by reflective operation
|
||||
*/
|
||||
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);
|
||||
@@ -332,10 +358,10 @@ public class BukkitPacketBuilder extends PacketBuilder {
|
||||
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);
|
||||
IChatBaseComponent listName = nmsComponent == null ? null : new WrappedChatComponent(nmsComponent);
|
||||
Skin skin = null;
|
||||
if (!profile.getProperties().get("textures").isEmpty()) {
|
||||
Property pr = (Property) profile.getProperties().get("textures").iterator().next();
|
||||
Property pr = profile.getProperties().get("textures").iterator().next();
|
||||
skin = new Skin(pr.getValue(), pr.getSignature());
|
||||
}
|
||||
listData.add(new PlayerInfoData(profile.getName(), profile.getId(), skin,
|
||||
@@ -389,6 +415,7 @@ public class BukkitPacketBuilder extends PacketBuilder {
|
||||
}
|
||||
if (packet.getAction() == Action.ADD) {
|
||||
w.helper().setEntityFlags((byte) 32);
|
||||
w.helper().setWitherInvulnerableTime(880); // Magic number
|
||||
return build(new PacketPlayOutSpawnEntityLiving(entityId, new UUID(0, 0), EntityType.WITHER, new Location(null, 0,0,0), w));
|
||||
} else {
|
||||
return build(new PacketPlayOutEntityMetadata(entityId, w));
|
||||
@@ -408,69 +435,7 @@ public class BukkitPacketBuilder extends PacketBuilder {
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* if thrown by reflective operation
|
||||
*/
|
||||
private IChatBaseComponent fromNMSComponent(Object component) throws ReflectiveOperationException {
|
||||
if (!nms.ChatComponentText.isInstance(component)) return null; //paper
|
||||
IChatBaseComponent chat = new IChatBaseComponent((String) nms.ChatComponentText_text.get(component));
|
||||
Object modifier = nms.ChatBaseComponent_modifier.get(component);
|
||||
if (modifier != null) {
|
||||
chat.getModifier().setColor(fromNMSColor(nms.ChatModifier_color.get(modifier)));
|
||||
chat.getModifier().setBold((Boolean) nms.ChatModifier_bold.get(modifier));
|
||||
chat.getModifier().setItalic((Boolean) nms.ChatModifier_italic.get(modifier));
|
||||
chat.getModifier().setObfuscated((Boolean) nms.ChatModifier_obfuscated.get(modifier));
|
||||
chat.getModifier().setStrikethrough((Boolean) nms.ChatModifier_strikethrough.get(modifier));
|
||||
chat.getModifier().setUnderlined((Boolean) nms.ChatModifier_underlined.get(modifier));
|
||||
Object clickEvent = nms.ChatModifier_clickEvent.get(modifier);
|
||||
if (clickEvent != null) {
|
||||
chat.getModifier().onClick(EnumClickAction.valueOf(nms.ChatClickable_action.get(clickEvent).toString().toUpperCase()), (String) nms.ChatClickable_value.get(clickEvent));
|
||||
}
|
||||
Object hoverEvent = nms.ChatModifier_hoverEvent.get(modifier);
|
||||
if (hoverEvent != null) {
|
||||
EnumHoverAction action;
|
||||
IChatBaseComponent value;
|
||||
if (nms.getMinorVersion() >= 16) {
|
||||
//does not support show_item on 1.16+
|
||||
JsonObject json = (JsonObject) nms.ChatHoverable_serialize.invoke(hoverEvent);
|
||||
action = EnumHoverAction.valueOf(json.get("action").getAsString().toUpperCase());
|
||||
value = IChatBaseComponent.deserialize(json.get("contents").getAsJsonObject().toString());
|
||||
} else {
|
||||
action = EnumHoverAction.valueOf(nms.ChatHoverable_getAction.invoke(hoverEvent).toString().toUpperCase());
|
||||
value = fromNMSComponent(nms.ChatHoverable_getValue.invoke(hoverEvent));
|
||||
}
|
||||
chat.getModifier().onHover(action, value);
|
||||
}
|
||||
}
|
||||
for (Object extra : (List<Object>) nms.ChatBaseComponent_extra.get(component)) {
|
||||
chat.addExtra(fromNMSComponent(extra));
|
||||
}
|
||||
return chat;
|
||||
}
|
||||
|
||||
private TextColor fromNMSColor(Object color) throws ReflectiveOperationException {
|
||||
if (color == null) return null;
|
||||
if (nms.getMinorVersion() >= 16) {
|
||||
String name = (String) nms.ChatHexColor_name.get(color);
|
||||
if (name != null) {
|
||||
//legacy code
|
||||
return new TextColor(EnumChatFormat.valueOf(name.toUpperCase(Locale.US)));
|
||||
} else {
|
||||
int rgb = (int) nms.ChatHexColor_rgb.get(color);
|
||||
return new TextColor((rgb >> 16) & 0xFF, (rgb >> 8) & 0xFF, rgb & 0xFF);
|
||||
}
|
||||
} else {
|
||||
return new TextColor(EnumChatFormat.valueOf(((Enum)color).name()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts TAB's IChatBaseComponent into minecraft's component. Currently, does not support hover event.
|
||||
* Converts TAB's IChatBaseComponent into minecraft's component.
|
||||
*
|
||||
* @param component
|
||||
* component to convert
|
||||
@@ -481,86 +446,28 @@ public class BukkitPacketBuilder extends PacketBuilder {
|
||||
* if thrown by reflective operation
|
||||
*/
|
||||
public Object toNMSComponent(IChatBaseComponent component, ProtocolVersion clientVersion) throws ReflectiveOperationException {
|
||||
Object obj;
|
||||
if (clientVersion.getMinorVersion() >= 16) {
|
||||
if (componentCacheModern.containsKey(component)) return componentCacheModern.get(component);
|
||||
obj = toNMSComponent0(component, clientVersion);
|
||||
if (componentCacheModern.size() > 10000) componentCacheModern.clear();
|
||||
componentCacheModern.put(component, obj);
|
||||
} else {
|
||||
if (componentCacheLegacy.containsKey(component)) return componentCacheLegacy.get(component);
|
||||
obj = toNMSComponent0(component, clientVersion);
|
||||
if (componentCacheLegacy.size() > 10000) componentCacheLegacy.clear();
|
||||
componentCacheLegacy.put(component, obj);
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
//separate method to prevent extras counting cpu again due to recursion and finally showing higher usage than real
|
||||
private Object toNMSComponent0(IChatBaseComponent component, ProtocolVersion clientVersion) throws ReflectiveOperationException {
|
||||
if (component == null) return null;
|
||||
Object chat = nms.newChatComponentText.newInstance(component.getText());
|
||||
Object modifier;
|
||||
Object clickEvent = component.getModifier().getClickEvent() == null ? null : nms.newChatClickable.newInstance(Enum.valueOf((Class<Enum>) nms.EnumClickAction,
|
||||
component.getModifier().getClickEvent().getAction().toString().toUpperCase()), component.getModifier().getClickEvent().getValue());
|
||||
if (nms.getMinorVersion() >= 16) {
|
||||
Object color = null;
|
||||
if (component.getModifier().getColor() != null) {
|
||||
if (clientVersion.getMinorVersion() >= 16) {
|
||||
color = nms.ChatHexColor_ofInt.invoke(null, (component.getModifier().getColor().getRed() << 16) + (component.getModifier().getColor().getGreen() << 8) + component.getModifier().getColor().getBlue());
|
||||
} else {
|
||||
color = nms.ChatHexColor_ofString.invoke(null, component.getModifier().getColor().getLegacyColor().toString().toLowerCase());
|
||||
}
|
||||
}
|
||||
Object hoverEvent = null;
|
||||
if (component.getModifier().getHoverEvent() != null) {
|
||||
Object nmsAction = nms.EnumHoverAction_a.invoke(null, component.getModifier().getHoverEvent().getAction().toString().toLowerCase());
|
||||
switch (component.getModifier().getHoverEvent().getAction()) {
|
||||
case SHOW_TEXT:
|
||||
hoverEvent = nms.newChatHoverable.newInstance(nmsAction, toNMSComponent0(component.getModifier().getHoverEvent().getValue(), clientVersion));
|
||||
break;
|
||||
case SHOW_ENTITY:
|
||||
hoverEvent = nms.EnumHoverAction_fromJson.invoke(nmsAction, ((ChatComponentEntity) component.getModifier().getHoverEvent().getValue()).toJson());
|
||||
break;
|
||||
case SHOW_ITEM:
|
||||
hoverEvent = nms.EnumHoverAction_fromLegacyComponent.invoke(nmsAction, toNMSComponent0(component.getModifier().getHoverEvent().getValue(), clientVersion));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
modifier = nms.newChatModifier.newInstance(
|
||||
color,
|
||||
component.getModifier().getBold(),
|
||||
component.getModifier().getItalic(),
|
||||
component.getModifier().getUnderlined(),
|
||||
component.getModifier().getStrikethrough(),
|
||||
component.getModifier().getObfuscated(),
|
||||
clickEvent, hoverEvent, null, null);
|
||||
} else {
|
||||
modifier = nms.newChatModifier.newInstance();
|
||||
if (component.getModifier().getColor() != null) nms.setField(modifier, nms.ChatModifier_color, Enum.valueOf((Class<Enum>) nms.EnumChatFormat, component.getModifier().getColor().getLegacyColor().toString()));
|
||||
nms.setField(modifier, nms.ChatModifier_bold, component.getModifier().getBold());
|
||||
nms.setField(modifier, nms.ChatModifier_italic, component.getModifier().getItalic());
|
||||
nms.setField(modifier, nms.ChatModifier_underlined, component.getModifier().getUnderlined());
|
||||
nms.setField(modifier, nms.ChatModifier_strikethrough, component.getModifier().getStrikethrough());
|
||||
nms.setField(modifier, nms.ChatModifier_obfuscated, component.getModifier().getObfuscated());
|
||||
if (clickEvent != null) nms.setField(modifier, nms.ChatModifier_clickEvent, clickEvent);
|
||||
if (component.getModifier().getHoverEvent() != null) {
|
||||
nms.setField(modifier, nms.ChatModifier_hoverEvent, nms.newChatHoverable.newInstance(nms.EnumHoverAction_a.invoke(null,
|
||||
component.getModifier().getHoverEvent().getAction().toString().toLowerCase()), toNMSComponent0(component.getModifier().getHoverEvent().getValue(), clientVersion)));
|
||||
}
|
||||
}
|
||||
nms.setField(chat, nms.ChatBaseComponent_modifier, modifier);
|
||||
for (IChatBaseComponent extra : component.getExtra()) {
|
||||
nms.ChatComponentText_addSibling.invoke(chat, toNMSComponent0(extra, clientVersion));
|
||||
}
|
||||
if (component instanceof WrappedChatComponent) return ((WrappedChatComponent) component).get();
|
||||
Map<IChatBaseComponent, Object> cache = clientVersion.getMinorVersion() >= 16 ? componentCacheModern : componentCacheLegacy;
|
||||
if (cache.containsKey(component)) return cache.get(component);
|
||||
if (cache.size() > 10000) cache.clear();
|
||||
Object chat = nms.ChatSerializer_DESERIALIZE.invoke(null, component.toString(clientVersion));
|
||||
cache.put(component, chat);
|
||||
return chat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Scoreboard Objective with given name.
|
||||
*
|
||||
* @param objectiveName
|
||||
* Objective name
|
||||
* @return NMS Objective
|
||||
* @throws ReflectiveOperationException
|
||||
* if thrown by reflective operation
|
||||
*/
|
||||
private Object newScoreboardObjective(String objectiveName) throws ReflectiveOperationException {
|
||||
if (nms.getMinorVersion() >= 13) {
|
||||
return nms.newScoreboardObjective.newInstance(null, objectiveName, null, nms.newChatComponentText.newInstance(""), null);
|
||||
return nms.newScoreboardObjective.newInstance(null, objectiveName, null, toNMSComponent(new IChatBaseComponent(""), TabAPI.getInstance().getServerVersion()), null);
|
||||
}
|
||||
return nms.newScoreboardObjective.newInstance(null, objectiveName, nms.IScoreboardCriteria_self.get(null));
|
||||
}
|
||||
|
||||
@@ -9,16 +9,18 @@ import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelPromise;
|
||||
import me.neznamy.tab.api.TabFeature;
|
||||
import me.neznamy.tab.api.TabPlayer;
|
||||
import me.neznamy.tab.api.util.Preconditions;
|
||||
import me.neznamy.tab.platforms.bukkit.nms.NMSStorage;
|
||||
import me.neznamy.tab.shared.TabConstants;
|
||||
import me.neznamy.tab.api.TabConstants;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.shared.features.PipelineInjector;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Pipeline injection for bukkit
|
||||
*/
|
||||
public class BukkitPipelineInjector extends PipelineInjector {
|
||||
|
||||
//nms storage
|
||||
/** NMS data storage */
|
||||
private final NMSStorage nms = NMSStorage.getInstance();
|
||||
|
||||
/**
|
||||
@@ -38,7 +40,7 @@ public class BukkitPipelineInjector extends PipelineInjector {
|
||||
*/
|
||||
public class BukkitChannelDuplexHandler extends ChannelDuplexHandler {
|
||||
|
||||
//injected player
|
||||
/** Injected player */
|
||||
private final TabPlayer player;
|
||||
|
||||
/**
|
||||
@@ -48,7 +50,6 @@ public class BukkitPipelineInjector extends PipelineInjector {
|
||||
* player to inject
|
||||
*/
|
||||
public BukkitChannelDuplexHandler(TabPlayer player) {
|
||||
Preconditions.checkNotNull(player, "player");
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
@@ -70,7 +71,9 @@ public class BukkitPipelineInjector extends PipelineInjector {
|
||||
return;
|
||||
}
|
||||
if (antiOverrideTeams && nms.PacketPlayOutScoreboardTeam != null && nms.PacketPlayOutScoreboardTeam.isInstance(packet)) {
|
||||
long time = System.nanoTime();
|
||||
modifyPlayers(packet);
|
||||
TAB.getInstance().getCPUManager().addTime("NameTags", TabConstants.CpuUsageCategory.ANTI_OVERRIDE, System.nanoTime()-time);
|
||||
super.write(context, packet, channelPromise);
|
||||
return;
|
||||
}
|
||||
@@ -101,7 +104,8 @@ public class BukkitPipelineInjector extends PipelineInjector {
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private void modifyPlayers(Object packetPlayOutScoreboardTeam) throws ReflectiveOperationException {
|
||||
long time = System.nanoTime();
|
||||
int action = nms.PacketPlayOutScoreboardTeam_ACTION.getInt(packetPlayOutScoreboardTeam);
|
||||
if (action == 1 || action == 2 || action == 4) return;
|
||||
Collection<String> players = (Collection<String>) nms.PacketPlayOutScoreboardTeam_PLAYERS.get(packetPlayOutScoreboardTeam);
|
||||
String teamName = (String) nms.PacketPlayOutScoreboardTeam_NAME.get(packetPlayOutScoreboardTeam);
|
||||
if (players == null) return;
|
||||
@@ -121,9 +125,17 @@ public class BukkitPipelineInjector extends PipelineInjector {
|
||||
}
|
||||
}
|
||||
nms.setField(packetPlayOutScoreboardTeam, nms.PacketPlayOutScoreboardTeam_PLAYERS, newList);
|
||||
TAB.getInstance().getCPUManager().addTime("NameTags", TabConstants.CpuUsageCategory.ANTI_OVERRIDE, System.nanoTime()-time);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns player with matching game profile name. This is different from
|
||||
* real name when a nick plugin changing names of players is used. If no
|
||||
* player was found, returns {@code null}.
|
||||
*
|
||||
* @param name
|
||||
* Game profile name
|
||||
* @return Player with matching game profile name
|
||||
*/
|
||||
private TabPlayer getPlayer(String name) {
|
||||
for (TabPlayer p : TAB.getInstance().getOnlinePlayers()) {
|
||||
if (p.getNickname().equals(name)) return p;
|
||||
|
||||
+59
-62
@@ -5,17 +5,25 @@ import java.lang.reflect.Method;
|
||||
import java.text.NumberFormat;
|
||||
import java.util.Locale;
|
||||
|
||||
import me.neznamy.tab.api.TabConstants;
|
||||
import me.neznamy.tab.api.TabPlayer;
|
||||
import me.neznamy.tab.api.placeholder.PlayerPlaceholder;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import net.ess3.api.events.NickChangeEvent;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.RegisteredServiceProvider;
|
||||
|
||||
import com.earth2me.essentials.Essentials;
|
||||
|
||||
import me.neznamy.tab.api.placeholder.PlaceholderManager;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.shared.placeholders.UniversalPlaceholderRegistry;
|
||||
import net.milkbowl.vault.chat.Chat;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
/**
|
||||
* Bukkit registry to register bukkit-only and universal placeholders
|
||||
@@ -25,26 +33,21 @@ public class BukkitPlaceholderRegistry extends UniversalPlaceholderRegistry {
|
||||
/** Number formatter for 2 decimal places */
|
||||
private final NumberFormat numberFormat = NumberFormat.getNumberInstance(Locale.US);
|
||||
|
||||
private Object chat;
|
||||
private final Plugin essentials = Bukkit.getPluginManager().getPlugin("Essentials");
|
||||
private final JavaPlugin plugin;
|
||||
private Chat chat;
|
||||
private final Plugin essentials = Bukkit.getPluginManager().getPlugin(TabConstants.Plugin.ESSENTIALS);
|
||||
private Object server;
|
||||
private Field recentTps;
|
||||
private boolean paperTps;
|
||||
private boolean paperMspt;
|
||||
private Method playerIsAfk;
|
||||
private Method paperTps;
|
||||
private Method paperMspt;
|
||||
private Method purpurIsAfk;
|
||||
|
||||
/**
|
||||
* Constructs new instance with given parameter
|
||||
*/
|
||||
public BukkitPlaceholderRegistry() {
|
||||
public BukkitPlaceholderRegistry(JavaPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
numberFormat.setMaximumFractionDigits(2);
|
||||
try {
|
||||
if (Bukkit.getPluginManager().isPluginEnabled("Vault")) {
|
||||
RegisteredServiceProvider<?> rspChat = Bukkit.getServicesManager().getRegistration(Class.forName("net.milkbowl.vault.chat.Chat"));
|
||||
if (rspChat != null) chat = rspChat.getProvider();
|
||||
}
|
||||
} catch (ClassNotFoundException e) {
|
||||
//modded server without vault
|
||||
if (Bukkit.getPluginManager().isPluginEnabled(TabConstants.Plugin.VAULT)) {
|
||||
RegisteredServiceProvider<Chat> rspChat = Bukkit.getServicesManager().getRegistration(Chat.class);
|
||||
if (rspChat != null) chat = rspChat.getProvider();
|
||||
}
|
||||
try {
|
||||
server = Bukkit.getServer().getClass().getMethod("getServer").invoke(Bukkit.getServer());
|
||||
@@ -52,70 +55,64 @@ public class BukkitPlaceholderRegistry extends UniversalPlaceholderRegistry {
|
||||
} catch (ReflectiveOperationException e) {
|
||||
//not spigot
|
||||
}
|
||||
try {
|
||||
Bukkit.class.getMethod("getTPS");
|
||||
paperTps = true;
|
||||
} catch (NoSuchMethodException e) {
|
||||
//not paper
|
||||
}
|
||||
try {
|
||||
Bukkit.class.getMethod("getAverageTickTime");
|
||||
paperMspt = true;
|
||||
} catch (NoSuchMethodException e) {
|
||||
//not paper
|
||||
}
|
||||
try {
|
||||
playerIsAfk = Player.class.getMethod("isAfk");
|
||||
} catch (NoSuchMethodException e) {
|
||||
//not purpur
|
||||
}
|
||||
try { paperTps = Bukkit.class.getMethod("getTPS"); } catch (NoSuchMethodException ignored) {}
|
||||
try { paperMspt = Bukkit.class.getMethod("getAverageTickTime"); } catch (NoSuchMethodException ignored) {}
|
||||
try { purpurIsAfk = Player.class.getMethod("isAfk"); } catch (NoSuchMethodException ignored) {}
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public void registerPlaceholders(PlaceholderManager manager) {
|
||||
super.registerPlaceholders(manager);
|
||||
manager.registerPlayerPlaceholder("%displayname%", 500, p -> ((Player) p.getPlayer()).getDisplayName());
|
||||
if (paperTps) {
|
||||
manager.registerServerPlaceholder("%tps%", 1000, () -> formatTPS(Bukkit.getTPS()[0]));
|
||||
manager.registerPlayerPlaceholder(TabConstants.Placeholder.DISPLAY_NAME, 500, p -> ((Player) p.getPlayer()).getDisplayName());
|
||||
if (paperTps != null) {
|
||||
manager.registerServerPlaceholder(TabConstants.Placeholder.TPS, 1000, () -> formatTPS(Bukkit.getTPS()[0]));
|
||||
} else if (recentTps != null) {
|
||||
manager.registerServerPlaceholder("%tps%", 1000, () -> {
|
||||
manager.registerServerPlaceholder(TabConstants.Placeholder.TPS, 1000, () -> {
|
||||
try {
|
||||
return formatTPS(((double[]) recentTps.get(server))[0]);
|
||||
} catch (IllegalAccessException e) {
|
||||
return "-1";
|
||||
return -1;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
manager.registerServerPlaceholder("%tps%", -1, () -> "-1").enableTriggerMode();
|
||||
manager.registerServerPlaceholder(TabConstants.Placeholder.TPS, -1, () -> -1);
|
||||
}
|
||||
if (paperMspt) {
|
||||
manager.registerServerPlaceholder("%mspt%", 1000, () -> numberFormat.format(Bukkit.getAverageTickTime()));
|
||||
if (paperMspt != null) {
|
||||
manager.registerServerPlaceholder(TabConstants.Placeholder.MSPT, 1000, () -> numberFormat.format(Bukkit.getAverageTickTime()));
|
||||
}
|
||||
manager.registerPlayerPlaceholder("%afk%", 500, p -> {
|
||||
manager.registerPlayerPlaceholder(TabConstants.Placeholder.AFK, 500, p -> {
|
||||
if (essentials != null && ((Essentials)essentials).getUser(p.getUniqueId()).isAfk()) return true;
|
||||
if (playerIsAfk == null) return false;
|
||||
try {
|
||||
return playerIsAfk.invoke(p.getPlayer());
|
||||
} catch (ReflectiveOperationException exception) {
|
||||
TAB.getInstance().getErrorManager().printError("Failed to get AFK status of " + p.getName() + " using Purpur", exception);
|
||||
}
|
||||
return false;
|
||||
return purpurIsAfk != null && ((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%", 1000, p -> ((Chat) chat).getPlayerPrefix((Player) p.getPlayer()));
|
||||
manager.registerPlayerPlaceholder("%vault-suffix%", 1000, p -> ((Chat) chat).getPlayerSuffix((Player) p.getPlayer()));
|
||||
if (essentials != null) {
|
||||
PlayerPlaceholder nick = manager.registerPlayerPlaceholder(TabConstants.Placeholder.ESSENTIALS_NICK, -1, p -> {
|
||||
String nickname = ((Essentials)essentials).getUser(p.getUniqueId()).getNickname();
|
||||
return nickname == null ? p.getName() : nickname;
|
||||
});
|
||||
Listener nickListener = new Listener() {
|
||||
@EventHandler
|
||||
public void onNickChange(NickChangeEvent e) {
|
||||
String name = e.getValue() == null ? e.getAffected().getName() : e.getValue();
|
||||
TabPlayer player = TAB.getInstance().getPlayer(e.getAffected().getUUID());
|
||||
if (player == null) return;
|
||||
nick.updateValue(player, name);
|
||||
}
|
||||
};
|
||||
nick.enableTriggerMode(() -> Bukkit.getPluginManager().registerEvents(nickListener, plugin),
|
||||
() -> HandlerList.unregisterAll(nickListener));
|
||||
} else {
|
||||
manager.registerServerPlaceholder("%vault-prefix%", -1, () -> "").enableTriggerMode();
|
||||
manager.registerServerPlaceholder("%vault-suffix%", -1, () -> "").enableTriggerMode();
|
||||
manager.registerPlayerPlaceholder(TabConstants.Placeholder.ESSENTIALS_NICK, -1, TabPlayer::getName);
|
||||
}
|
||||
manager.registerPlayerPlaceholder("%health%", 100, p -> (int) Math.ceil(((Player) p.getPlayer()).getHealth()));
|
||||
|
||||
if (chat != null) {
|
||||
manager.registerPlayerPlaceholder(TabConstants.Placeholder.VAULT_PREFIX, 1000, p -> chat.getPlayerPrefix((Player) p.getPlayer()));
|
||||
manager.registerPlayerPlaceholder(TabConstants.Placeholder.VAULT_SUFFIX, 1000, p -> chat.getPlayerSuffix((Player) p.getPlayer()));
|
||||
} else {
|
||||
manager.registerServerPlaceholder(TabConstants.Placeholder.VAULT_PREFIX, -1, () -> "");
|
||||
manager.registerServerPlaceholder(TabConstants.Placeholder.VAULT_SUFFIX, -1, () -> "");
|
||||
}
|
||||
manager.registerPlayerPlaceholder(TabConstants.Placeholder.HEALTH, 100, p -> (int) Math.ceil(((Player) p.getPlayer()).getHealth()));
|
||||
}
|
||||
|
||||
private String formatTPS(double tps) {
|
||||
|
||||
@@ -4,7 +4,7 @@ import com.earth2me.essentials.Essentials;
|
||||
import com.viaversion.viaversion.api.Via;
|
||||
import me.clip.placeholderapi.PlaceholderAPI;
|
||||
import me.neznamy.tab.api.TabPlayer;
|
||||
import me.neznamy.tab.api.util.Preconditions;
|
||||
import me.neznamy.tab.api.chat.EnumChatFormat;
|
||||
import me.neznamy.tab.platforms.bukkit.event.TabLoadEvent;
|
||||
import me.neznamy.tab.platforms.bukkit.event.TabPlayerLoadEvent;
|
||||
import me.neznamy.tab.platforms.bukkit.features.BukkitTabExpansion;
|
||||
@@ -15,7 +15,7 @@ import me.neznamy.tab.platforms.bukkit.features.unlimitedtags.BukkitNameTagX;
|
||||
import me.neznamy.tab.platforms.bukkit.permission.Vault;
|
||||
import me.neznamy.tab.shared.Platform;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.shared.TabConstants;
|
||||
import me.neznamy.tab.api.TabConstants;
|
||||
import me.neznamy.tab.shared.features.PlaceholderManagerImpl;
|
||||
import me.neznamy.tab.shared.features.bossbar.BossBarManagerImpl;
|
||||
import me.neznamy.tab.shared.features.nametags.NameTag;
|
||||
@@ -41,11 +41,11 @@ public class BukkitPlatform extends Platform {
|
||||
private final JavaPlugin plugin;
|
||||
|
||||
/** Variables checking presence of other plugins to hook into */
|
||||
private final boolean placeholderAPI = Bukkit.getPluginManager().isPluginEnabled("PlaceholderAPI");
|
||||
private boolean libsDisguises = Bukkit.getPluginManager().isPluginEnabled("LibsDisguises");
|
||||
private final Plugin essentials = Bukkit.getPluginManager().getPlugin("Essentials");
|
||||
private final boolean placeholderAPI = Bukkit.getPluginManager().isPluginEnabled(TabConstants.Plugin.PLACEHOLDER_API);
|
||||
private boolean libsDisguises = Bukkit.getPluginManager().isPluginEnabled(TabConstants.Plugin.LIBS_DISGUISES);
|
||||
private final Plugin essentials = Bukkit.getPluginManager().getPlugin(TabConstants.Plugin.ESSENTIALS);
|
||||
private Plugin viaVersion;
|
||||
private final boolean protocolSupport = Bukkit.getPluginManager().isPluginEnabled("ProtocolSupport");
|
||||
private final boolean protocolSupport = Bukkit.getPluginManager().isPluginEnabled(TabConstants.Plugin.PROTOCOL_SUPPORT);
|
||||
|
||||
/**
|
||||
* Constructs new instance with given plugin parameter
|
||||
@@ -55,18 +55,17 @@ public class BukkitPlatform extends Platform {
|
||||
*/
|
||||
public BukkitPlatform(JavaPlugin plugin) {
|
||||
super(new BukkitPacketBuilder());
|
||||
Preconditions.checkNotNull(plugin, "plugin");
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PermissionPlugin detectPermissionPlugin() {
|
||||
if (Bukkit.getPluginManager().isPluginEnabled("LuckPerms")) {
|
||||
return new LuckPerms(getPluginVersion("LuckPerms"));
|
||||
} else if (Bukkit.getPluginManager().isPluginEnabled("Vault")) {
|
||||
if (Bukkit.getPluginManager().isPluginEnabled(TabConstants.Plugin.LUCKPERMS)) {
|
||||
return new LuckPerms(getPluginVersion(TabConstants.Plugin.LUCKPERMS));
|
||||
} else if (Bukkit.getPluginManager().isPluginEnabled(TabConstants.Plugin.VAULT)) {
|
||||
RegisteredServiceProvider<Permission> provider = Bukkit.getServicesManager().getRegistration(Permission.class);
|
||||
if (provider == null) return new None();
|
||||
return new Vault(provider.getProvider(), getPluginVersion("Vault"));
|
||||
return new Vault(provider.getProvider(), getPluginVersion(TabConstants.Plugin.VAULT));
|
||||
} else {
|
||||
return new None();
|
||||
}
|
||||
@@ -74,26 +73,20 @@ public class BukkitPlatform extends Platform {
|
||||
|
||||
@Override
|
||||
public void loadFeatures() {
|
||||
if (Bukkit.getPluginManager().isPluginEnabled("ViaVersion")) {
|
||||
if (Bukkit.getPluginManager().isPluginEnabled(TabConstants.Plugin.VIAVERSION)) {
|
||||
try {
|
||||
Class.forName("com.viaversion.viaversion.api.Via");
|
||||
viaVersion = Bukkit.getPluginManager().getPlugin("ViaVersion");
|
||||
viaVersion = Bukkit.getPluginManager().getPlugin(TabConstants.Plugin.VIAVERSION);
|
||||
} catch (ClassNotFoundException e) {
|
||||
TAB.getInstance().sendConsoleMessage("&cAn outdated version of ViaVersion (" + getPluginVersion("ViaVersion") + ") was detected.", true);
|
||||
TAB.getInstance().sendConsoleMessage("&cAn outdated version of ViaVersion (" + getPluginVersion(TabConstants.Plugin.VIAVERSION) + ") was detected.", true);
|
||||
TAB.getInstance().sendConsoleMessage("&cTAB only supports ViaVersion 4.0.0 and above. Disabling ViaVersion hook.", true);
|
||||
TAB.getInstance().sendConsoleMessage("&cThis might cause problems, such as limitations still being present for latest MC clients as well as RGB not working.", true);
|
||||
}
|
||||
}
|
||||
if (Bukkit.getPluginManager().isPluginEnabled("Tablisknu")) {
|
||||
TAB.getInstance().sendConsoleMessage("&cDetected plugin \"Tablisknu\", which causes TAB to not work properly. Consider removing the plugin.", true);
|
||||
}
|
||||
if (Bukkit.getPluginManager().isPluginEnabled("SkBee")) {
|
||||
TAB.getInstance().sendConsoleMessage("&cDetected plugin \"SkBee\", which causes TAB's scoreboard to not show. Consider removing the plugin.", true);
|
||||
}
|
||||
TAB tab = TAB.getInstance();
|
||||
if (tab.getConfiguration().isPipelineInjection())
|
||||
tab.getFeatureManager().registerFeature(TabConstants.Feature.PIPELINE_INJECTION, new BukkitPipelineInjector());
|
||||
new BukkitPlaceholderRegistry().registerPlaceholders(tab.getPlaceholderManager());
|
||||
new BukkitPlaceholderRegistry(plugin).registerPlaceholders(tab.getPlaceholderManager());
|
||||
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(TabConstants.Feature.UNLIMITED_NAME_TAGS, new BukkitNameTagX(plugin));
|
||||
@@ -125,7 +118,6 @@ public class BukkitPlatform extends Platform {
|
||||
|
||||
@Override
|
||||
public String getPluginVersion(String plugin) {
|
||||
Preconditions.checkNotNull(plugin, "plugin");
|
||||
Plugin pl = Bukkit.getPluginManager().getPlugin(plugin);
|
||||
return pl == null ? null : pl.getDescription().getVersion();
|
||||
}
|
||||
@@ -154,7 +146,6 @@ public class BukkitPlatform extends Platform {
|
||||
|
||||
@Override
|
||||
public void registerUnknownPlaceholder(String identifier) {
|
||||
Preconditions.checkNotNull(identifier, "identifier");
|
||||
PlaceholderManagerImpl pl = TAB.getInstance().getPlaceholderManager();
|
||||
if (identifier.startsWith("%rel_")) {
|
||||
//relational placeholder
|
||||
@@ -231,11 +222,6 @@ public class BukkitPlatform extends Platform {
|
||||
return (Essentials) essentials;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isProxy() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getConfigName() {
|
||||
return "bukkitconfig.yml";
|
||||
@@ -271,7 +257,7 @@ public class BukkitPlatform extends Platform {
|
||||
try {
|
||||
Object protocolVersion = Class.forName("protocolsupport.api.ProtocolSupportAPI").getMethod("getProtocolVersion", Player.class).invoke(null, player);
|
||||
int version = (int) protocolVersion.getClass().getMethod("getId").invoke(protocolVersion);
|
||||
TAB.getInstance().debug("ProtocolSupport returned protocol version " + version + " for " + player.getName() + "(online=" + player.isOnline() + ")");
|
||||
TAB.getInstance().debug("ProtocolSupport returned protocol version " + version + " for " + player.getName() + " (online=" + player.isOnline() + ")");
|
||||
return version;
|
||||
} catch (ReflectiveOperationException e) {
|
||||
TAB.getInstance().getErrorManager().printError(String.format("Failed to get protocol version of %s using ProtocolSupport", player.getName()), e);
|
||||
@@ -298,7 +284,7 @@ public class BukkitPlatform extends Platform {
|
||||
Thread.sleep(5);
|
||||
return getProtocolVersionVia(player, retryLevel + 1);
|
||||
}
|
||||
TAB.getInstance().debug("ViaVersion returned protocol version " + version + " for " + player.getName() + "(online=" + player.isOnline() + ")");
|
||||
TAB.getInstance().debug("ViaVersion returned protocol version " + version + " for " + player.getName() + " (online=" + player.isOnline() + ")");
|
||||
return version;
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
@@ -308,4 +294,18 @@ public class BukkitPlatform extends Platform {
|
||||
return TAB.getInstance().getServerVersion().getNetworkId();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends console message using ConsoleCommandSender, due to
|
||||
* Paper not translating colors correctly in Logger messages
|
||||
*
|
||||
* @param message
|
||||
* Message to send
|
||||
* @param translateColors
|
||||
* Whether color codes should be translated or not
|
||||
*/
|
||||
@Override
|
||||
public void sendConsoleMessage(String message, boolean translateColors) {
|
||||
Bukkit.getConsoleSender().sendMessage("[TAB] " + (translateColors ? EnumChatFormat.color(message) : message));
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package me.neznamy.tab.platforms.bukkit;
|
||||
import java.util.*;
|
||||
|
||||
import com.mojang.authlib.properties.Property;
|
||||
import me.neznamy.tab.api.protocol.PacketPlayOutChat;
|
||||
import me.neznamy.tab.api.protocol.Skin;
|
||||
import me.neznamy.tab.api.util.Preconditions;
|
||||
import org.bukkit.Bukkit;
|
||||
@@ -10,6 +11,7 @@ import org.bukkit.boss.BarColor;
|
||||
import org.bukkit.boss.BarFlag;
|
||||
import org.bukkit.boss.BarStyle;
|
||||
import org.bukkit.boss.BossBar;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.metadata.MetadataValue;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
@@ -22,7 +24,6 @@ import com.viaversion.viaversion.api.legacy.bossbar.BossFlag;
|
||||
import com.viaversion.viaversion.api.legacy.bossbar.BossStyle;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
import me.libraryaddict.disguise.DisguiseAPI;
|
||||
import me.neznamy.tab.api.chat.rgb.RGBUtils;
|
||||
import me.neznamy.tab.api.protocol.PacketPlayOutBoss;
|
||||
import me.neznamy.tab.platforms.bukkit.nms.NMSStorage;
|
||||
@@ -55,7 +56,7 @@ public class BukkitTabPlayer extends ITabPlayer {
|
||||
* Player's protocol network id
|
||||
*/
|
||||
public BukkitTabPlayer(Player p, int protocolVersion){
|
||||
super(p, p.getUniqueId(), p.getName(), "N/A", p.getWorld().getName(), protocolVersion);
|
||||
super(p, p.getUniqueId(), p.getName(), "N/A", p.getWorld().getName(), protocolVersion, true);
|
||||
try {
|
||||
handle = NMSStorage.getInstance().getHandle.invoke(player);
|
||||
playerConnection = NMSStorage.getInstance().PLAYER_CONNECTION.get(handle);
|
||||
@@ -95,6 +96,8 @@ public class BukkitTabPlayer extends ITabPlayer {
|
||||
} else {
|
||||
handleVia((PacketPlayOutBoss) nmsPacket);
|
||||
}
|
||||
} else if (nmsPacket instanceof PacketPlayOutChat) {
|
||||
getPlayer().sendMessage(((PacketPlayOutChat) nmsPacket).getMessage().toLegacyText());
|
||||
} else {
|
||||
NMSStorage.getInstance().sendPacket.invoke(playerConnection, nmsPacket);
|
||||
}
|
||||
@@ -240,8 +243,8 @@ public class BukkitTabPlayer extends ITabPlayer {
|
||||
public boolean isDisguised() {
|
||||
try {
|
||||
if (!((BukkitPlatform)TAB.getInstance().getPlatform()).isLibsDisguisesEnabled()) return false;
|
||||
return DisguiseAPI.isDisguised(getPlayer());
|
||||
} catch (LinkageError e) {
|
||||
return (boolean) Class.forName("me.libraryaddict.disguise.DisguiseAPI").getMethod("isDisguised", Entity.class).invoke(null, getPlayer());
|
||||
} catch (LinkageError | ReflectiveOperationException 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);
|
||||
@@ -249,7 +252,6 @@ public class BukkitTabPlayer extends ITabPlayer {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Skin getSkin() {
|
||||
try {
|
||||
|
||||
@@ -5,6 +5,8 @@ import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import me.neznamy.tab.api.TabAPI;
|
||||
import me.neznamy.tab.platforms.bukkit.nms.*;
|
||||
import org.bstats.bukkit.Metrics;
|
||||
import org.bstats.charts.SimplePie;
|
||||
import org.bukkit.Bukkit;
|
||||
@@ -14,9 +16,8 @@ import org.bukkit.plugin.java.JavaPlugin;
|
||||
import me.neznamy.tab.api.ProtocolVersion;
|
||||
import me.neznamy.tab.api.TabPlayer;
|
||||
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 me.neznamy.tab.api.TabConstants;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
@@ -26,24 +27,25 @@ public class Main extends JavaPlugin {
|
||||
|
||||
@Override
|
||||
public void onEnable(){
|
||||
getLogger().info(EnumChatFormat.color("&7Server version: " + Bukkit.getBukkitVersion().split("-")[0] + " (" + Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3] + ")"));
|
||||
String version = Bukkit.getBukkitVersion().split("-")[0];
|
||||
String serverPackage = Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3];
|
||||
Bukkit.getConsoleSender().sendMessage(EnumChatFormat.color("[TAB] Server version: " + version + " (" + serverPackage + ")"));
|
||||
if (!isVersionSupported()){
|
||||
Bukkit.getPluginManager().disablePlugin(this);
|
||||
return;
|
||||
}
|
||||
BukkitPlatform platform = new BukkitPlatform(this);
|
||||
TAB.setInstance(new TAB(platform, ProtocolVersion.fromFriendlyName(Bukkit.getBukkitVersion().split("-")[0]),
|
||||
Bukkit.getBukkitVersion().split("-")[0] + " (" + Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3] + ")", getDataFolder(), getLogger()));
|
||||
TAB.setInstance(new TAB(platform, ProtocolVersion.fromFriendlyName(version), version + " (" + serverPackage + ")", getDataFolder(), getLogger()));
|
||||
if (TAB.getInstance().getServerVersion() == ProtocolVersion.UNKNOWN_SERVER_VERSION) {
|
||||
getLogger().info(EnumChatFormat.color("&cUnknown server version: " + Bukkit.getBukkitVersion() + "! Plugin may not work correctly."));
|
||||
Bukkit.getConsoleSender().sendMessage(EnumChatFormat.color("&c[TAB] Unknown server version: " + Bukkit.getBukkitVersion() + "! Plugin may not work correctly."));
|
||||
}
|
||||
Bukkit.getPluginManager().registerEvents(new BukkitEventListener(platform), this);
|
||||
TAB.getInstance().load();
|
||||
Metrics metrics = new Metrics(this, 5304);
|
||||
metrics.addCustomChart(new SimplePie("unlimited_nametag_mode_enabled", () -> TAB.getInstance().getFeatureManager().isFeatureEnabled(TabConstants.Feature.UNLIMITED_NAME_TAGS) ? "Yes" : "No"));
|
||||
metrics.addCustomChart(new SimplePie("placeholderapi", () -> Bukkit.getPluginManager().isPluginEnabled("PlaceholderAPI") ? "Yes" : "No"));
|
||||
metrics.addCustomChart(new SimplePie("permission_system", () -> TAB.getInstance().getGroupManager().getPlugin().getName()));
|
||||
metrics.addCustomChart(new SimplePie("server_version", () -> "1." + TAB.getInstance().getServerVersion().getMinorVersion() + ".x"));
|
||||
metrics.addCustomChart(new SimplePie(TabConstants.MetricsChart.UNLIMITED_NAME_TAG_MODE_ENABLED, () -> TAB.getInstance().getFeatureManager().isFeatureEnabled(TabConstants.Feature.UNLIMITED_NAME_TAGS) ? "Yes" : "No"));
|
||||
metrics.addCustomChart(new SimplePie(TabConstants.MetricsChart.PLACEHOLDER_API, () -> Bukkit.getPluginManager().isPluginEnabled(TabConstants.Plugin.PLACEHOLDER_API) ? "Yes" : "No"));
|
||||
metrics.addCustomChart(new SimplePie(TabConstants.MetricsChart.PERMISSION_SYSTEM, () -> TAB.getInstance().getGroupManager().getPlugin().getName()));
|
||||
metrics.addCustomChart(new SimplePie(TabConstants.MetricsChart.SERVER_VERSION, () -> "1." + TAB.getInstance().getServerVersion().getMinorVersion() + ".x"));
|
||||
PluginCommand cmd = Bukkit.getPluginCommand("tab");
|
||||
if (cmd == null) return;
|
||||
TABCommand command = new TABCommand();
|
||||
@@ -53,7 +55,7 @@ public class Main extends JavaPlugin {
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
//null check due to L31 return making L34 not run
|
||||
//null check due to L34 return making L37 not run
|
||||
if (TAB.getInstance() != null) TAB.getInstance().unload();
|
||||
}
|
||||
|
||||
@@ -69,22 +71,33 @@ public class Main extends JavaPlugin {
|
||||
"v1_5_R1", "v1_5_R2", "v1_5_R3", "v1_6_R1", "v1_6_R2", "v1_6_R3",
|
||||
"v1_7_R1", "v1_7_R2", "v1_7_R3", "v1_7_R4", "v1_8_R1", "v1_8_R2", "v1_8_R3",
|
||||
"v1_9_R1", "v1_9_R2", "v1_10_R1", "v1_11_R1", "v1_12_R1", "v1_13_R1", "v1_13_R2",
|
||||
"v1_14_R1", "v1_15_R1", "v1_16_R1", "v1_16_R2", "v1_16_R3", "v1_17_R1", "v1_18_R1", "v1_18_R2");
|
||||
"v1_14_R1", "v1_15_R1", "v1_16_R1", "v1_16_R2", "v1_16_R3", "v1_17_R1", "v1_18_R1",
|
||||
"v1_18_R2", "v1_19_R1");
|
||||
String serverPackage = Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3];
|
||||
try {
|
||||
long time = System.currentTimeMillis();
|
||||
NMSStorage.setInstance(new NMSStorage());
|
||||
int minorVersion = Integer.parseInt(serverPackage.split("_")[1]);
|
||||
if (minorVersion >= 17) {
|
||||
try {
|
||||
NMSStorage.setInstance(new BukkitModernNMSStorage());
|
||||
} catch (ClassNotFoundException e) {
|
||||
NMSStorage.setInstance(new MojangModernNMSStorage());
|
||||
}
|
||||
} else {
|
||||
NMSStorage.setInstance(new LegacyNMSStorage());
|
||||
}
|
||||
if (supportedVersions.contains(serverPackage)) {
|
||||
getLogger().info(EnumChatFormat.color("&7Loaded NMS hook in " + (System.currentTimeMillis()-time) + "ms"));
|
||||
Bukkit.getConsoleSender().sendMessage(EnumChatFormat.color("[TAB] Loaded NMS hook in " + (System.currentTimeMillis()-time) + "ms"));
|
||||
return true;
|
||||
} else {
|
||||
getLogger().info(EnumChatFormat.color("&cNo compatibility issue was found, but this plugin version does not claim to support your server package (" + serverPackage + "). This jar has only been tested on 1.5.x - 1.18.2. Disabling just to stay safe."));
|
||||
Bukkit.getConsoleSender().sendMessage(EnumChatFormat.color("&c[TAB] No compatibility issue was found, but this plugin version does not claim to support your server package (" + serverPackage + "). This jar has only been tested on 1.5.x - 1.19. Disabling just to stay safe."));
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
if (supportedVersions.contains(serverPackage)) {
|
||||
getLogger().log(Level.SEVERE, EnumChatFormat.color("&cYour server version is marked as compatible, but a compatibility issue was found. Please report the error below (include your server version & fork too)"), ex);
|
||||
Bukkit.getConsoleSender().sendMessage(EnumChatFormat.color("&c[TAB] Your server version is marked as compatible, but a compatibility issue was found. Please report the error below (include your server version & fork too)"));
|
||||
getLogger().log(Level.SEVERE, "", ex);
|
||||
} else {
|
||||
getLogger().info(EnumChatFormat.color("&cYour server version is completely unsupported. This plugin version only supports 1.5.x - 1.18.2. Disabling."));
|
||||
Bukkit.getConsoleSender().sendMessage(EnumChatFormat.color("&c[TAB] Your server version is completely unsupported. This plugin version only supports 1.5.x - 1.19. Disabling."));
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@@ -93,11 +106,11 @@ public class Main extends JavaPlugin {
|
||||
/**
|
||||
* Command handler for /tab command
|
||||
*/
|
||||
public static class TABCommand implements CommandExecutor, TabCompleter {
|
||||
private static class TABCommand implements CommandExecutor, TabCompleter {
|
||||
|
||||
@Override
|
||||
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
|
||||
if (TAB.getInstance().isDisabled()) {
|
||||
if (TabAPI.getInstance().isPluginDisabled()) {
|
||||
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));
|
||||
}
|
||||
|
||||
+11
-45
@@ -2,14 +2,14 @@ package me.neznamy.tab.platforms.bukkit.features;
|
||||
|
||||
import me.clip.placeholderapi.PlaceholderAPI;
|
||||
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
|
||||
import me.neznamy.tab.api.TabAPI;
|
||||
import me.neznamy.tab.api.TabConstants;
|
||||
import me.neznamy.tab.api.TabFeature;
|
||||
import me.neznamy.tab.api.TabPlayer;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.shared.TabConstants;
|
||||
import me.neznamy.tab.shared.features.TabExpansion;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
@@ -27,11 +27,6 @@ public class BukkitTabExpansion extends PlaceholderExpansion implements TabExpan
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canRegister(){
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String getAuthor(){
|
||||
return "NEZNAMY";
|
||||
@@ -49,51 +44,22 @@ public class BukkitTabExpansion extends PlaceholderExpansion implements TabExpan
|
||||
|
||||
@Override
|
||||
public String onPlaceholderRequest(Player player, @NotNull String identifier){
|
||||
if (player == null) return "";
|
||||
TabPlayer p = TAB.getInstance().getPlayer(player.getUniqueId());
|
||||
if (identifier.startsWith("replace_")) {
|
||||
String placeholder = "%" + identifier.substring(8) + "%";
|
||||
String output = PlaceholderAPI.setPlaceholders(player, placeholder);
|
||||
return TAB.getInstance().getPlaceholderManager().findReplacement(placeholder, output);
|
||||
return TabAPI.getInstance().getPlaceholderManager().findReplacement(placeholder, output);
|
||||
}
|
||||
if (identifier.startsWith("placeholder_")) {
|
||||
TAB.getInstance().getPlaceholderManager().addUsedPlaceholders(Collections.singletonList("%" + identifier.substring(12) + "%"));
|
||||
TabAPI.getInstance().getPlaceholderManager().addUsedPlaceholder("%" + identifier.substring(12) + "%", (TabFeature) TabAPI.getInstance().getPlaceholderManager());
|
||||
}
|
||||
return values.computeIfAbsent(p, pl -> new HashMap<>()).get(identifier);
|
||||
if (player == null) return "<Player cannot be null>";
|
||||
TabPlayer p = TabAPI.getInstance().getPlayer(player.getUniqueId());
|
||||
if (p == null || !p.isLoaded()) return "<Player is not loaded>";
|
||||
return values.get(p).get(identifier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setScoreboardVisible(TabPlayer player, boolean visible) {
|
||||
values.computeIfAbsent(player, p -> new HashMap<>()).put("scoreboard_visible", visible ? "Enabled" : "Disabled");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setScoreboardName(TabPlayer player, String name) {
|
||||
values.computeIfAbsent(player, p -> new HashMap<>()).put("scoreboard_name", name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBossBarVisible(TabPlayer player, boolean visible) {
|
||||
values.computeIfAbsent(player, p -> new HashMap<>()).put("bossbar_visible", visible ? "Enabled" : "Disabled");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNameTagPreview(TabPlayer player, boolean previewing) {
|
||||
values.computeIfAbsent(player, p -> new HashMap<>()).put("ntpreview", previewing ? "Enabled" : "Disabled");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPlaceholderValue(TabPlayer player, String placeholder, String value) {
|
||||
values.computeIfAbsent(player, p -> new HashMap<>()).put("placeholder_" + placeholder.substring(1, placeholder.length()-1), value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPropertyValue(TabPlayer player, String property, String value) {
|
||||
values.computeIfAbsent(player, p -> new HashMap<>()).put(property, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRawPropertyValue(TabPlayer player, String property, String value) {
|
||||
values.computeIfAbsent(player, p -> new HashMap<>()).put(property + "_raw", value);
|
||||
public void setValue(TabPlayer player, String key, String value) {
|
||||
values.computeIfAbsent(player, p -> new HashMap<>()).put(key, value);
|
||||
}
|
||||
}
|
||||
+6
-5
@@ -5,6 +5,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import me.neznamy.tab.api.TabAPI;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
@@ -15,7 +16,7 @@ import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import me.neznamy.tab.api.TabFeature;
|
||||
import me.neznamy.tab.shared.TabConstants;
|
||||
import me.neznamy.tab.api.TabConstants;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
|
||||
/**
|
||||
@@ -28,9 +29,9 @@ public class PerWorldPlayerList extends TabFeature implements Listener {
|
||||
private final JavaPlugin plugin;
|
||||
|
||||
//config options
|
||||
private final boolean allowBypass = TAB.getInstance().getConfiguration().getConfig().getBoolean("per-world-playerlist.allow-bypass-permission", false);
|
||||
private final List<String> ignoredWorlds = TAB.getInstance().getConfiguration().getConfig().getStringList("per-world-playerlist.ignore-effect-in-worlds", Arrays.asList("ignoredworld", "build"));
|
||||
private final Map<String, List<String>> sharedWorlds = TAB.getInstance().getConfiguration().getConfig().getConfigurationSection("per-world-playerlist.shared-playerlist-world-groups");
|
||||
private final boolean allowBypass = TabAPI.getInstance().getConfig().getBoolean("per-world-playerlist.allow-bypass-permission", false);
|
||||
private final List<String> ignoredWorlds = TabAPI.getInstance().getConfig().getStringList("per-world-playerlist.ignore-effect-in-worlds", Arrays.asList("ignoredworld", "build"));
|
||||
private final Map<String, List<String>> sharedWorlds = TabAPI.getInstance().getConfig().getConfigurationSection("per-world-playerlist.shared-playerlist-world-groups");
|
||||
|
||||
/**
|
||||
* Constructs new instance with given parameters and loads config options
|
||||
@@ -41,7 +42,7 @@ public class PerWorldPlayerList extends TabFeature implements Listener {
|
||||
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));
|
||||
TabAPI.getInstance().debug(String.format("Loaded PerWorldPlayerList feature with parameters allowBypass=%s, ignoredWorlds=%s, sharedWorlds=%s", allowBypass, ignoredWorlds, sharedWorlds));
|
||||
Bukkit.getPluginManager().registerEvents(this, plugin);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
package me.neznamy.tab.platforms.bukkit.features;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import me.neznamy.tab.api.TabAPI;
|
||||
import me.neznamy.tab.api.TabFeature;
|
||||
import me.neznamy.tab.api.TabPlayer;
|
||||
import me.neznamy.tab.platforms.bukkit.nms.NMSStorage;
|
||||
import me.neznamy.tab.platforms.bukkit.nms.datawatcher.DataWatcher;
|
||||
import me.neznamy.tab.platforms.bukkit.nms.datawatcher.DataWatcherItem;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
|
||||
import java.util.ConcurrentModificationException;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
/**
|
||||
* A feature to disable minecraft 1.9+ feature making tamed animals
|
||||
@@ -45,7 +48,7 @@ public class PetFix extends TabFeature {
|
||||
*/
|
||||
public PetFix() {
|
||||
super("Pet name fix", null);
|
||||
TAB.getInstance().debug("Loaded PetFix feature");
|
||||
TabAPI.getInstance().debug("Loaded PetFix feature");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -55,7 +58,7 @@ public class PetFix extends TabFeature {
|
||||
*/
|
||||
private int getPetOwnerPosition() {
|
||||
if (nms.getMinorVersion() >= 17) {
|
||||
//1.17.x, 1.18.x
|
||||
//1.17.x, 1.18.x, 1.19.x
|
||||
return 18;
|
||||
} else if (nms.getMinorVersion() >= 15) {
|
||||
//1.15.x, 1.16.x
|
||||
@@ -80,15 +83,13 @@ public class PetFix extends TabFeature {
|
||||
*/
|
||||
@Override
|
||||
public boolean onPacketReceive(TabPlayer sender, Object packet) throws ReflectiveOperationException {
|
||||
if (nms.PacketPlayInUseEntity.isInstance(packet)) {
|
||||
if (lastInteractFix.containsKey(sender) && (System.currentTimeMillis() - lastInteractFix.get(sender) < INTERACT_COOLDOWN)) {
|
||||
if (nms.PacketPlayInUseEntity.isInstance(packet) && isInteract(nms.PacketPlayInUseEntity_ACTION.get(packet))) {
|
||||
if (System.currentTimeMillis() - lastInteractFix.getOrDefault(sender, 0L) < INTERACT_COOLDOWN) {
|
||||
//last interact packet was sent right now, cancelling to prevent double-toggle due to this feature enabled
|
||||
return true;
|
||||
}
|
||||
if (isInteract(nms.PacketPlayInUseEntity_ACTION.get(packet))) {
|
||||
//this is the first packet, saving player so the next packet can be cancelled
|
||||
lastInteractFix.put(sender, System.currentTimeMillis());
|
||||
}
|
||||
//this is the first packet, saving player so the next packet can be cancelled
|
||||
lastInteractFix.put(sender, System.currentTimeMillis());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package me.neznamy.tab.platforms.bukkit.features;
|
||||
|
||||
import me.neznamy.tab.api.util.Preconditions;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
@@ -13,7 +12,7 @@ import org.bukkit.plugin.java.JavaPlugin;
|
||||
import me.neznamy.tab.api.TabPlayer;
|
||||
import me.neznamy.tab.api.bossbar.BossBar;
|
||||
import me.neznamy.tab.platforms.bukkit.nms.PacketPlayOutEntityTeleport;
|
||||
import me.neznamy.tab.shared.TabConstants;
|
||||
import me.neznamy.tab.api.TabConstants;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.shared.features.bossbar.BossBarManagerImpl;
|
||||
|
||||
@@ -32,7 +31,6 @@ public class WitherBossBar extends BossBarManagerImpl implements Listener {
|
||||
* plugin instance
|
||||
*/
|
||||
public WitherBossBar(JavaPlugin plugin) {
|
||||
Preconditions.checkNotNull(plugin, "plugin");
|
||||
Bukkit.getPluginManager().registerEvents(this, plugin);
|
||||
//when MC is on fullscreen, BossBar disappears after 1 second of not being seen
|
||||
//when in a small window, it's about 100ms
|
||||
|
||||
+34
-34
@@ -1,16 +1,6 @@
|
||||
package me.neznamy.tab.platforms.bukkit.features.unlimitedtags;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.entity.Pose;
|
||||
|
||||
import me.neznamy.tab.api.ArmorStand;
|
||||
import me.neznamy.tab.api.Property;
|
||||
import me.neznamy.tab.api.TabPlayer;
|
||||
import me.neznamy.tab.api.*;
|
||||
import me.neznamy.tab.api.chat.EnumChatFormat;
|
||||
import me.neznamy.tab.api.chat.IChatBaseComponent;
|
||||
import me.neznamy.tab.api.protocol.TabPacket;
|
||||
@@ -19,8 +9,13 @@ import me.neznamy.tab.platforms.bukkit.nms.PacketPlayOutEntityMetadata;
|
||||
import me.neznamy.tab.platforms.bukkit.nms.PacketPlayOutEntityTeleport;
|
||||
import me.neznamy.tab.platforms.bukkit.nms.PacketPlayOutSpawnEntityLiving;
|
||||
import me.neznamy.tab.platforms.bukkit.nms.datawatcher.DataWatcher;
|
||||
import me.neznamy.tab.shared.TabConstants;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.entity.Pose;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* A class representing an armor stand attached to a player (if the feature is enabled)
|
||||
@@ -31,7 +26,7 @@ public class BukkitArmorStand implements ArmorStand {
|
||||
private static int idCounter = 2000000000;
|
||||
|
||||
//NameTag feature
|
||||
private final BukkitNameTagX manager = (BukkitNameTagX) TAB.getInstance().getFeatureManager().getFeature(TabConstants.Feature.UNLIMITED_NAME_TAGS);
|
||||
private final BukkitNameTagX manager = (BukkitNameTagX) TabAPI.getInstance().getFeatureManager().getFeature(TabConstants.Feature.UNLIMITED_NAME_TAGS);
|
||||
|
||||
private final BukkitArmorStandManager asm;
|
||||
|
||||
@@ -73,6 +68,7 @@ public class BukkitArmorStand implements ArmorStand {
|
||||
this.yOffset = yOffset;
|
||||
this.property = owner.getProperty(propertyName);
|
||||
visible = getVisibility();
|
||||
sneaking = player.isSneaking();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -204,20 +200,28 @@ public class BukkitArmorStand implements ArmorStand {
|
||||
/**
|
||||
* Returns general location where armor stand should be at time of calling
|
||||
*
|
||||
* @param viewer
|
||||
* Player looking at the armor stand
|
||||
* @return Location where armor stand should be for everyone
|
||||
*/
|
||||
public Location getLocation() {
|
||||
public Location getLocation(TabPlayer viewer) {
|
||||
double x = player.getLocation().getX();
|
||||
double y = getY() + yOffset + 2;
|
||||
double y = getY() + yOffset;
|
||||
double z = player.getLocation().getZ();
|
||||
if (player.isSleeping()) {
|
||||
y -= 1.76;
|
||||
} else {
|
||||
if (TAB.getInstance().getServerVersion().getMinorVersion() >= 9) {
|
||||
y -= (sneaking ? 0.45 : 0.18);
|
||||
if (!player.isSleeping()) {
|
||||
if (sneaking) {
|
||||
if (viewer.getVersion().getMinorVersion() >= 15) {
|
||||
y += 1.37;
|
||||
} else if (viewer.getVersion().getMinorVersion() >= 9) {
|
||||
y += 1.52;
|
||||
} else {
|
||||
y += 1.7;
|
||||
}
|
||||
} else {
|
||||
y -= (sneaking ? 0.30 : 0.18);
|
||||
y += viewer.getVersion().getMinorVersion() >= 9 ? 1.8 : 1.84; // Normal
|
||||
}
|
||||
} else {
|
||||
y += viewer.getVersion().getMinorVersion() >= 9 ? 0.2 : 0.26; // Sleeping
|
||||
}
|
||||
return new Location(null,x,y,z);
|
||||
}
|
||||
@@ -245,15 +249,15 @@ public class BukkitArmorStand implements ArmorStand {
|
||||
}
|
||||
}
|
||||
//1.13+ swimming or 1.9+ flying with elytra
|
||||
if (isSwimming() || (TAB.getInstance().getServerVersion().getMinorVersion() >= 9 && player.isGliding())) {
|
||||
if (isSwimming() || (TabAPI.getInstance().getServerVersion().getMinorVersion() >= 9 && player.isGliding())) {
|
||||
return player.getLocation().getY()-1.22;
|
||||
}
|
||||
return player.getLocation().getY();
|
||||
}
|
||||
|
||||
private boolean isSwimming() {
|
||||
if (TAB.getInstance().getServerVersion().getMinorVersion() >= 14 && player.getPose() == Pose.SWIMMING) return true;
|
||||
return TAB.getInstance().getServerVersion().getMinorVersion() == 13 && player.isSwimming();
|
||||
if (TabAPI.getInstance().getServerVersion().getMinorVersion() >= 14 && player.getPose() == Pose.SWIMMING) return true;
|
||||
return TabAPI.getInstance().getServerVersion().getMinorVersion() == 13 && player.isSwimming();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -311,7 +315,7 @@ public class BukkitArmorStand implements ArmorStand {
|
||||
public TabPacket[] getSpawnPackets(TabPlayer viewer) {
|
||||
visible = getVisibility();
|
||||
DataWatcher dataWatcher = createDataWatcher(property.getFormat(viewer), viewer);
|
||||
if (TAB.getInstance().getServerVersion().getMinorVersion() >= 15) {
|
||||
if (TabAPI.getInstance().getServerVersion().getMinorVersion() >= 15) {
|
||||
return new TabPacket[] {
|
||||
new PacketPlayOutSpawnEntityLiving(entityId, uuid, EntityType.ARMOR_STAND, getArmorStandLocationFor(viewer), null),
|
||||
new PacketPlayOutEntityMetadata(entityId, dataWatcher)
|
||||
@@ -331,18 +335,14 @@ public class BukkitArmorStand implements ArmorStand {
|
||||
* @return location of armor stand
|
||||
*/
|
||||
public Location getArmorStandLocationFor(TabPlayer viewer) {
|
||||
return viewer.getVersion().getMinorVersion() == 8 && !manager.isMarkerFor18x() ? getLocation().clone().add(0,-2,0) : getLocation();
|
||||
return viewer.getVersion().getMinorVersion() == 8 && !manager.isMarkerFor18x() ? getLocation(viewer).add(0,-2,0) : getLocation(viewer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void respawn(TabPlayer viewer) {
|
||||
viewer.sendCustomPacket(destroyPacket, TabConstants.PacketCategory.UNLIMITED_NAMETAGS_DESPAWN);
|
||||
Runnable spawn = () -> spawn(viewer);
|
||||
if (viewer.getVersion().getMinorVersion() == 8) {
|
||||
//1.8.0 client sided bug
|
||||
TAB.getInstance().getCPUManager().runTaskLater(50, manager, TabConstants.CpuUsageCategory.V1_8_0_BUG_COMPENSATION, spawn);
|
||||
} else {
|
||||
spawn.run();
|
||||
}
|
||||
// 1.8.0 will not see entity that respawned in the same tick
|
||||
// creating new delayed task every time someone sneaks can be abused and cause OOM
|
||||
spawn(viewer);
|
||||
}
|
||||
}
|
||||
+22
-48
@@ -3,7 +3,7 @@ package me.neznamy.tab.platforms.bukkit.features.unlimitedtags;
|
||||
import me.neznamy.tab.api.ArmorStand;
|
||||
import me.neznamy.tab.api.ArmorStandManager;
|
||||
import me.neznamy.tab.api.TabPlayer;
|
||||
import me.neznamy.tab.shared.TabConstants;
|
||||
import me.neznamy.tab.api.TabConstants;
|
||||
import me.neznamy.tab.shared.features.nametags.unlimited.NameTagX;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -16,7 +16,6 @@ import java.util.Map;
|
||||
*/
|
||||
public class BukkitArmorStandManager implements ArmorStandManager {
|
||||
|
||||
private final NameTagX nameTagX;
|
||||
//map of registered armor stands
|
||||
private final Map<String, ArmorStand> armorStands = new LinkedHashMap<>();
|
||||
|
||||
@@ -29,14 +28,13 @@ public class BukkitArmorStandManager implements ArmorStandManager {
|
||||
private TabPlayer[] nearbyPlayerArray = new TabPlayer[0];
|
||||
|
||||
public BukkitArmorStandManager(NameTagX nameTagX, TabPlayer owner) {
|
||||
this.nameTagX = nameTagX;
|
||||
owner.setProperty(nameTagX, TabConstants.Property.NAMETAG, owner.getProperty(TabConstants.Property.TAGPREFIX).getCurrentRawValue()
|
||||
+ owner.getProperty(TabConstants.Property.CUSTOMTAGNAME).getCurrentRawValue()
|
||||
+ owner.getProperty(TabConstants.Property.TAGSUFFIX).getCurrentRawValue());
|
||||
double height = 0;
|
||||
for (String line : nameTagX.getDynamicLines()) {
|
||||
addArmorStand(line, new BukkitArmorStand(this, owner, line, height, false));
|
||||
height += nameTagX.getSpaceBetweenLines();
|
||||
height += 0.26;
|
||||
}
|
||||
for (Map.Entry<String, Object> line : nameTagX.getStaticLines().entrySet()) {
|
||||
addArmorStand(line.getKey(), new BukkitArmorStand(this, owner, line.getKey(), Double.parseDouble(line.getValue().toString()), true));
|
||||
@@ -54,6 +52,13 @@ public class BukkitArmorStandManager implements ArmorStandManager {
|
||||
for (ArmorStand a : armorStandArray) a.teleport(viewer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Teleports armor stands to player's current location for all nearby players
|
||||
*/
|
||||
public void teleport() {
|
||||
for (ArmorStand a : armorStandArray) a.teleport();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns array of nearby players
|
||||
* @return array of nearby players
|
||||
@@ -99,13 +104,6 @@ public class BukkitArmorStandManager implements ArmorStandManager {
|
||||
for (ArmorStand a : armorStandArray) a.sneak(sneaking);
|
||||
}
|
||||
|
||||
/**
|
||||
* Teleports armor stands to player's current location for all nearby players
|
||||
*/
|
||||
public void teleport() {
|
||||
for (ArmorStand a : armorStandArray) a.teleport();
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs respawn operation on all armor stands to skip teleport animation
|
||||
*/
|
||||
@@ -130,26 +128,15 @@ public class BukkitArmorStandManager implements ArmorStandManager {
|
||||
for (ArmorStand a : armorStandArray) a.spawn(viewer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends destroy packet of all armor stands to specified player and removes them from nearby players list
|
||||
*
|
||||
* @param viewer
|
||||
* player to destroy armor stands for
|
||||
*/
|
||||
public void destroy(TabPlayer viewer) {
|
||||
for (ArmorStand a : armorStandArray) a.destroy(viewer);
|
||||
unregisterPlayer(viewer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fixes heights of all armor stands due to dynamic lines
|
||||
*/
|
||||
public void fixArmorStandHeights() {
|
||||
double currentY = -nameTagX.getSpaceBetweenLines();
|
||||
double currentY = -0.26;
|
||||
for (ArmorStand as : armorStandArray) {
|
||||
if (as.hasStaticOffset()) continue;
|
||||
if (as.getProperty().get().length() != 0) {
|
||||
currentY += nameTagX.getSpaceBetweenLines();
|
||||
currentY += 0.26;
|
||||
as.setOffset(currentY);
|
||||
}
|
||||
}
|
||||
@@ -169,30 +156,6 @@ public class BukkitArmorStandManager implements ArmorStandManager {
|
||||
for (TabPlayer p : nearbyPlayerArray) as.spawn(p);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets armor stand by name
|
||||
*
|
||||
* @param name
|
||||
* Name to get armor stand by
|
||||
* @return Armor stand with given name or null if not found
|
||||
*/
|
||||
public ArmorStand getArmorStand(String name) {
|
||||
return armorStands.get(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes armor stand by given name if exists
|
||||
*
|
||||
* @param name
|
||||
* Name of line to remove
|
||||
*/
|
||||
public void removeArmorStand(String name) {
|
||||
if (!armorStands.containsKey(name)) return;
|
||||
armorStands.get(name).destroy();
|
||||
armorStands.remove(name);
|
||||
armorStandArray = armorStands.values().toArray(new ArmorStand[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes specified player from list of nearby players
|
||||
*
|
||||
@@ -207,6 +170,17 @@ public class BukkitArmorStandManager implements ArmorStandManager {
|
||||
for (ArmorStand a : armorStandArray) a.updateVisibility(force);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends destroy packet of all armor stands to specified player and removes them from nearby players list
|
||||
*
|
||||
* @param viewer
|
||||
* player to destroy armor stands for
|
||||
*/
|
||||
public void destroy(TabPlayer viewer) {
|
||||
for (ArmorStand a : armorStandArray) a.destroy(viewer);
|
||||
unregisterPlayer(viewer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
for (ArmorStand a : armorStandArray) a.destroy();
|
||||
|
||||
+19
-12
@@ -1,8 +1,8 @@
|
||||
package me.neznamy.tab.platforms.bukkit.features.unlimitedtags;
|
||||
|
||||
import me.neznamy.tab.api.TabAPI;
|
||||
import me.neznamy.tab.api.TabConstants;
|
||||
import me.neznamy.tab.api.TabPlayer;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.shared.TabConstants;
|
||||
import me.neznamy.tab.shared.features.nametags.unlimited.NameTagX;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
@@ -29,16 +29,16 @@ public class BukkitNameTagX extends NameTagX {
|
||||
public BukkitNameTagX(JavaPlugin plugin) {
|
||||
super(BukkitArmorStandManager::new);
|
||||
Bukkit.getPluginManager().registerEvents(eventListener, plugin);
|
||||
TAB.getInstance().getFeatureManager().registerFeature(TabConstants.Feature.UNLIMITED_NAME_TAGS_PACKET_LISTENER, new PacketListener(this));
|
||||
TAB.getInstance().getFeatureManager().registerFeature(TabConstants.Feature.UNLIMITED_NAME_TAGS_VEHICLE_REFRESHER, vehicleManager);
|
||||
TabAPI.getInstance().getFeatureManager().registerFeature(TabConstants.Feature.UNLIMITED_NAME_TAGS_PACKET_LISTENER, new PacketListener(this));
|
||||
TabAPI.getInstance().getFeatureManager().registerFeature(TabConstants.Feature.UNLIMITED_NAME_TAGS_VEHICLE_REFRESHER, vehicleManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
super.load();
|
||||
for (TabPlayer all : TAB.getInstance().getOnlinePlayers()) {
|
||||
for (TabPlayer all : TabAPI.getInstance().getOnlinePlayers()) {
|
||||
if (isPlayerDisabled(all)) continue;
|
||||
for (TabPlayer viewer : TAB.getInstance().getOnlinePlayers()) {
|
||||
for (TabPlayer viewer : TabAPI.getInstance().getOnlinePlayers()) {
|
||||
spawnArmorStands(viewer, all);
|
||||
}
|
||||
}
|
||||
@@ -46,9 +46,9 @@ public class BukkitNameTagX extends NameTagX {
|
||||
}
|
||||
|
||||
private void startVisibilityRefreshTask() {
|
||||
TAB.getInstance().getCPUManager().startRepeatingMeasuredTask(500, this, TabConstants.CpuUsageCategory.REFRESHING_NAME_TAG_VISIBILITY, () -> {
|
||||
TabAPI.getInstance().getThreadManager().startRepeatingMeasuredTask(500, this, TabConstants.CpuUsageCategory.REFRESHING_NAME_TAG_VISIBILITY, () -> {
|
||||
|
||||
for (TabPlayer p : TAB.getInstance().getOnlinePlayers()) {
|
||||
for (TabPlayer p : TabAPI.getInstance().getOnlinePlayers()) {
|
||||
if (isPlayerDisabled(p)) continue;
|
||||
getArmorStandManager(p).updateVisibility(false);
|
||||
}
|
||||
@@ -65,7 +65,7 @@ public class BukkitNameTagX extends NameTagX {
|
||||
public void onJoin(TabPlayer connectedPlayer) {
|
||||
super.onJoin(connectedPlayer);
|
||||
if (isPlayerDisabled(connectedPlayer)) return;
|
||||
for (TabPlayer viewer : TAB.getInstance().getOnlinePlayers()) {
|
||||
for (TabPlayer viewer : TabAPI.getInstance().getOnlinePlayers()) {
|
||||
spawnArmorStands(viewer, connectedPlayer);
|
||||
spawnArmorStands(connectedPlayer, viewer);
|
||||
}
|
||||
@@ -77,6 +77,7 @@ public class BukkitNameTagX extends NameTagX {
|
||||
}
|
||||
|
||||
private void spawnArmorStands(TabPlayer viewer, TabPlayer target) {
|
||||
if (viewer.getVersion().getMinorVersion() < 8) return;
|
||||
if (target == viewer || isPlayerDisabled(target)) return;
|
||||
if (((Player) viewer.getPlayer()).getWorld() != ((Player) target.getPlayer()).getWorld()) return;
|
||||
if (getDistance(viewer, target) <= 48 && ((Player)viewer.getPlayer()).canSee((Player)target.getPlayer()) && !target.isVanished())
|
||||
@@ -95,7 +96,7 @@ public class BukkitNameTagX extends NameTagX {
|
||||
@Override
|
||||
public void resumeArmorStands(TabPlayer player) {
|
||||
if (isPlayerDisabled(player)) return;
|
||||
for (TabPlayer viewer : TAB.getInstance().getOnlinePlayers()) {
|
||||
for (TabPlayer viewer : TabAPI.getInstance().getOnlinePlayers()) {
|
||||
spawnArmorStands(viewer, player);
|
||||
}
|
||||
}
|
||||
@@ -107,7 +108,7 @@ public class BukkitNameTagX extends NameTagX {
|
||||
|
||||
@Override
|
||||
public void updateNameTagVisibilityView(TabPlayer player) {
|
||||
for (TabPlayer all : TAB.getInstance().getOnlinePlayers()) {
|
||||
for (TabPlayer all : TabAPI.getInstance().getOnlinePlayers()) {
|
||||
getArmorStandManager(all).updateVisibility(true);
|
||||
}
|
||||
}
|
||||
@@ -115,7 +116,7 @@ public class BukkitNameTagX extends NameTagX {
|
||||
@Override
|
||||
public void onQuit(TabPlayer disconnectedPlayer) {
|
||||
super.onQuit(disconnectedPlayer);
|
||||
for (TabPlayer all : TAB.getInstance().getOnlinePlayers()) {
|
||||
for (TabPlayer all : TabAPI.getInstance().getOnlinePlayers()) {
|
||||
getArmorStandManager(all).unregisterPlayer(disconnectedPlayer);
|
||||
}
|
||||
armorStandManagerMap.get(disconnectedPlayer).destroy();
|
||||
@@ -134,6 +135,12 @@ public class BukkitNameTagX extends NameTagX {
|
||||
if (isPreviewingNametag(p)) {
|
||||
getArmorStandManager(p).spawn(p);
|
||||
}
|
||||
//for some reason this is needed for some users
|
||||
for (TabPlayer viewer : TabAPI.getInstance().getOnlinePlayers()) {
|
||||
if (viewer.getWorld().equals(from)) {
|
||||
getArmorStandManager(p).destroy(viewer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+7
-8
@@ -1,15 +1,14 @@
|
||||
package me.neznamy.tab.platforms.bukkit.features.unlimitedtags;
|
||||
|
||||
import me.neznamy.tab.api.TabAPI;
|
||||
import me.neznamy.tab.api.TabConstants;
|
||||
import me.neznamy.tab.api.TabPlayer;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerRespawnEvent;
|
||||
import org.bukkit.event.player.PlayerToggleSneakEvent;
|
||||
|
||||
import me.neznamy.tab.api.TabPlayer;
|
||||
import me.neznamy.tab.shared.TabConstants;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
|
||||
/**
|
||||
* The event listener part for securing proper functionality of armor stands
|
||||
*/
|
||||
@@ -36,9 +35,9 @@ public class EventListener implements Listener {
|
||||
*/
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onSneak(PlayerToggleSneakEvent e) {
|
||||
TabPlayer p = TAB.getInstance().getPlayer(e.getPlayer().getUniqueId());
|
||||
TabPlayer p = TabAPI.getInstance().getPlayer(e.getPlayer().getUniqueId());
|
||||
if (p == null || feature.isPlayerDisabled(p)) return;
|
||||
TAB.getInstance().getCPUManager().runMeasuredTask(feature, TabConstants.CpuUsageCategory.PLAYER_SNEAK, () -> feature.getArmorStandManager(p).sneak(e.isSneaking()));
|
||||
TabAPI.getInstance().getThreadManager().runMeasuredTask(feature, TabConstants.CpuUsageCategory.PLAYER_SNEAK, () -> feature.getArmorStandManager(p).sneak(e.isSneaking()));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -49,8 +48,8 @@ public class EventListener implements Listener {
|
||||
*/
|
||||
@EventHandler
|
||||
public void onRespawn(PlayerRespawnEvent e) {
|
||||
TAB.getInstance().getCPUManager().runMeasuredTask(feature, TabConstants.CpuUsageCategory.PLAYER_RESPAWN, () -> {
|
||||
TabPlayer respawned = TAB.getInstance().getPlayer(e.getPlayer().getUniqueId());
|
||||
TabAPI.getInstance().getThreadManager().runMeasuredTask(feature, TabConstants.CpuUsageCategory.PLAYER_RESPAWN, () -> {
|
||||
TabPlayer respawned = TabAPI.getInstance().getPlayer(e.getPlayer().getUniqueId());
|
||||
if (feature.isPlayerDisabled(respawned)) return;
|
||||
feature.getArmorStandManager(respawned).teleport();
|
||||
});
|
||||
|
||||
+14
-15
@@ -1,18 +1,17 @@
|
||||
package me.neznamy.tab.platforms.bukkit.features.unlimitedtags;
|
||||
|
||||
import me.neznamy.tab.api.TabAPI;
|
||||
import me.neznamy.tab.api.TabConstants;
|
||||
import me.neznamy.tab.api.TabFeature;
|
||||
import me.neznamy.tab.api.TabPlayer;
|
||||
import me.neznamy.tab.platforms.bukkit.nms.NMSStorage;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import me.neznamy.tab.api.TabFeature;
|
||||
import me.neznamy.tab.api.TabPlayer;
|
||||
import me.neznamy.tab.platforms.bukkit.nms.NMSStorage;
|
||||
import me.neznamy.tab.shared.TabConstants;
|
||||
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 de-sync
|
||||
@@ -41,7 +40,7 @@ public class PacketListener extends TabFeature {
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
for (TabPlayer all : TAB.getInstance().getOnlinePlayers()) {
|
||||
for (TabPlayer all : TabAPI.getInstance().getOnlinePlayers()) {
|
||||
entityIdMap.put(((Player) all.getPlayer()).getEntityId(), all);
|
||||
}
|
||||
}
|
||||
@@ -61,7 +60,7 @@ public class PacketListener extends TabFeature {
|
||||
if (sender.getVersion().getMinorVersion() == 8 && nms.PacketPlayInUseEntity.isInstance(packet)) {
|
||||
int entityId = nms.PacketPlayInUseEntity_ENTITY.getInt(packet);
|
||||
TabPlayer attacked = null;
|
||||
for (TabPlayer all : TAB.getInstance().getOnlinePlayers()) {
|
||||
for (TabPlayer all : TabAPI.getInstance().getOnlinePlayers()) {
|
||||
if (all.isLoaded() && nameTagX.getArmorStandManager(all).hasArmorStandWithID(entityId)) {
|
||||
attacked = all;
|
||||
break;
|
||||
@@ -114,14 +113,14 @@ public class PacketListener extends TabFeature {
|
||||
if (pl != null) {
|
||||
//player moved
|
||||
if (nameTagX.isPlayerDisabled(pl) || !pl.isLoaded()) return;
|
||||
TAB.getInstance().getCPUManager().runMeasuredTask(nameTagX, TabConstants.CpuUsageCategory.PACKET_ENTITY_MOVE,
|
||||
TabAPI.getInstance().getThreadManager().runMeasuredTask(nameTagX, TabConstants.CpuUsageCategory.PACKET_ENTITY_MOVE,
|
||||
() -> nameTagX.getArmorStandManager(pl).teleport(receiver));
|
||||
} else if ((vehicleList = nameTagX.getVehicleManager().getVehicles().get(entityId)) != null){
|
||||
//a vehicle carrying something moved
|
||||
for (Entity entity : vehicleList) {
|
||||
TabPlayer passenger = entityIdMap.get(entity.getEntityId());
|
||||
if (passenger != null && nameTagX.getArmorStandManager(passenger) != null) {
|
||||
TAB.getInstance().getCPUManager().runMeasuredTask(nameTagX, TabConstants.CpuUsageCategory.PACKET_ENTITY_MOVE_PASSENGER,
|
||||
TabAPI.getInstance().getThreadManager().runMeasuredTask(nameTagX, TabConstants.CpuUsageCategory.PACKET_ENTITY_MOVE_PASSENGER,
|
||||
() -> nameTagX.getArmorStandManager(passenger).teleport(receiver));
|
||||
}
|
||||
}
|
||||
@@ -131,7 +130,7 @@ public class PacketListener extends TabFeature {
|
||||
private void onEntitySpawn(TabPlayer receiver, int entityId) {
|
||||
TabPlayer spawnedPlayer = entityIdMap.get(entityId);
|
||||
if (spawnedPlayer != null && spawnedPlayer.isLoaded() && !nameTagX.isPlayerDisabled(spawnedPlayer)) {
|
||||
TAB.getInstance().getCPUManager().runMeasuredTask(nameTagX, TabConstants.CpuUsageCategory.PACKET_ENTITY_SPAWN,
|
||||
TabAPI.getInstance().getThreadManager().runMeasuredTask(nameTagX, TabConstants.CpuUsageCategory.PACKET_ENTITY_SPAWN,
|
||||
() -> nameTagX.getArmorStandManager(spawnedPlayer).spawn(receiver));
|
||||
}
|
||||
}
|
||||
@@ -152,7 +151,7 @@ public class PacketListener extends TabFeature {
|
||||
TabPlayer deSpawnedPlayer = entityIdMap.get(entity);
|
||||
if (deSpawnedPlayer != null && deSpawnedPlayer.isLoaded() && !nameTagX.isPlayerDisabled(deSpawnedPlayer)) {
|
||||
BukkitArmorStandManager asm = nameTagX.getArmorStandManager(deSpawnedPlayer);
|
||||
TAB.getInstance().getCPUManager().runMeasuredTask(nameTagX, TabConstants.CpuUsageCategory.PACKET_ENTITY_DESTROY,
|
||||
TabAPI.getInstance().getThreadManager().runMeasuredTask(nameTagX, TabConstants.CpuUsageCategory.PACKET_ENTITY_DESTROY,
|
||||
() -> asm.destroy(receiver));
|
||||
}
|
||||
}
|
||||
|
||||
+15
-33
@@ -1,17 +1,15 @@
|
||||
package me.neznamy.tab.platforms.bukkit.features.unlimitedtags;
|
||||
|
||||
import me.neznamy.tab.api.TabAPI;
|
||||
import me.neznamy.tab.api.TabConstants;
|
||||
import me.neznamy.tab.api.TabFeature;
|
||||
import me.neznamy.tab.api.TabPlayer;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import me.neznamy.tab.shared.TabConstants;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import me.neznamy.tab.api.TabFeature;
|
||||
import me.neznamy.tab.api.TabPlayer;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
|
||||
public class VehicleRefresher extends TabFeature {
|
||||
|
||||
//map of players currently in a vehicle
|
||||
@@ -28,31 +26,30 @@ public class VehicleRefresher extends TabFeature {
|
||||
public VehicleRefresher(BukkitNameTagX feature) {
|
||||
super(feature.getFeatureName(), "Refreshing vehicles");
|
||||
this.feature = feature;
|
||||
TAB.getInstance().getCPUManager().startRepeatingMeasuredTask(50,
|
||||
TabAPI.getInstance().getThreadManager().startRepeatingMeasuredTask(50,
|
||||
this, TabConstants.CpuUsageCategory.PROCESSING_PLAYER_MOVEMENT, () -> {
|
||||
for (TabPlayer inVehicle : playersInVehicle.keySet()) {
|
||||
if (!inVehicle.isOnline() || feature.getArmorStandManager(inVehicle) == null) continue; // not removed from WeakHashMap yet
|
||||
feature.getArmorStandManager(inVehicle).teleport();
|
||||
// feature.getVehicleManager().processPassengers((Entity) inVehicle.getPlayer());
|
||||
}
|
||||
for (TabPlayer p : TAB.getInstance().getOnlinePlayers()) {
|
||||
for (TabPlayer p : TabAPI.getInstance().getOnlinePlayers()) {
|
||||
if (feature.isPreviewingNametag(p)) {
|
||||
feature.getArmorStandManager(p).teleport(p);
|
||||
}
|
||||
}
|
||||
});
|
||||
addUsedPlaceholders(Collections.singletonList("%vehicle%"));
|
||||
TAB.getInstance().getPlaceholderManager().registerPlayerPlaceholder("%vehicle%", 100, p -> ((Player)p.getPlayer()).getVehicle() == null ? "" : ((Player)p.getPlayer()).getVehicle());
|
||||
addUsedPlaceholders(Collections.singletonList(TabConstants.Placeholder.VEHICLE));
|
||||
TabAPI.getInstance().getPlaceholderManager().registerPlayerPlaceholder(TabConstants.Placeholder.VEHICLE, 100, p -> ((Player)p.getPlayer()).getVehicle() == null ? "" : ((Player)p.getPlayer()).getVehicle());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
for (TabPlayer p : TAB.getInstance().getOnlinePlayers()) {
|
||||
for (TabPlayer p : TabAPI.getInstance().getOnlinePlayers()) {
|
||||
Entity vehicle = ((Player)p.getPlayer()).getVehicle();
|
||||
if (vehicle != null) {
|
||||
vehicles.put(vehicle.getEntityId(), getPassengers(vehicle));
|
||||
playersInVehicle.put(p, vehicle);
|
||||
if (feature.isDisableOnBoats() && vehicle.getType() == EntityType.BOAT) {
|
||||
if (feature.isDisableOnBoats() && vehicle.getType().toString().contains("BOAT")) {
|
||||
playersOnBoats.add(p);
|
||||
}
|
||||
}
|
||||
@@ -92,7 +89,7 @@ public class VehicleRefresher extends TabFeature {
|
||||
vehicles.put(vehicle.getEntityId(), getPassengers(vehicle));
|
||||
feature.getArmorStandManager(p).respawn(); //making teleport instant instead of showing teleport animation
|
||||
playersInVehicle.put(p, vehicle);
|
||||
if (feature.isDisableOnBoats() && vehicle.getType() == EntityType.BOAT) {
|
||||
if (feature.isDisableOnBoats() && vehicle.getType().toString().contains("BOAT")) {
|
||||
playersOnBoats.add(p);
|
||||
feature.updateTeamData(p);
|
||||
}
|
||||
@@ -116,7 +113,7 @@ public class VehicleRefresher extends TabFeature {
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public List<Entity> getPassengers(Entity vehicle){
|
||||
if (TAB.getInstance().getServerVersion().getMinorVersion() >= 11) {
|
||||
if (TabAPI.getInstance().getServerVersion().getMinorVersion() >= 11) {
|
||||
return vehicle.getPassengers();
|
||||
} else {
|
||||
if (vehicle.getPassenger() != null) {
|
||||
@@ -126,19 +123,4 @@ public class VehicleRefresher extends TabFeature {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Teleports armor stands of all passengers on specified vehicle
|
||||
*
|
||||
* @param vehicle
|
||||
* entity to check passengers of
|
||||
*/
|
||||
public void processPassengers(Entity vehicle) {
|
||||
for (Entity passenger : getPassengers(vehicle)) {
|
||||
if (passenger instanceof Player) {
|
||||
feature.getArmorStandManager(TAB.getInstance().getPlayer(passenger.getUniqueId())).teleport();
|
||||
}
|
||||
processPassengers(passenger);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
package me.neznamy.tab.platforms.bukkit.nms;
|
||||
|
||||
/**
|
||||
* NMS loader for minecraft 1.17+ using Mojang packaging and bukkit names.
|
||||
*/
|
||||
public class BukkitModernNMSStorage extends ModernNMSStorage {
|
||||
|
||||
/**
|
||||
* Creates new instance, initializes required NMS classes and fields
|
||||
*
|
||||
* @throws ReflectiveOperationException
|
||||
* If any class, field or method fails to load
|
||||
*/
|
||||
public BukkitModernNMSStorage() throws ReflectiveOperationException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadNamedFieldsAndMethods() throws ReflectiveOperationException {
|
||||
PING = getField(EntityPlayer, "e");
|
||||
ChatSerializer_DESERIALIZE = getMethod(ChatSerializer, "a", String.class);
|
||||
DataWatcher_REGISTER = getMethod(DataWatcher, new String[]{"register", "a"}, DataWatcherObject, Object.class); // {Bukkit, Bukkit 1.18+}
|
||||
ScoreboardScore_setScore = getMethod(ScoreboardScore, new String[]{"setScore", "b"}, int.class); // {Bukkit, Bukkit 1.18+}
|
||||
ScoreboardTeam_setAllowFriendlyFire = getMethod(ScoreboardTeam, new String[]{"setAllowFriendlyFire", "a"}, boolean.class); // {Bukkit, Bukkit 1.18+}
|
||||
ScoreboardTeam_setCanSeeFriendlyInvisibles = getMethod(ScoreboardTeam, new String[]{"setCanSeeFriendlyInvisibles", "b"}, boolean.class); // {Bukkit, Bukkit 1.18+}
|
||||
ScoreboardTeam_setPrefix = getMethod(ScoreboardTeam, new String[]{"setPrefix", "b"}, IChatBaseComponent); // {Bukkit, Bukkit 1.18+}
|
||||
ScoreboardTeam_setSuffix = getMethod(ScoreboardTeam, new String[]{"setSuffix", "c"}, IChatBaseComponent); // {Bukkit, Bukkit 1.18+}
|
||||
ScoreboardTeam_setNameTagVisibility = getMethod(ScoreboardTeam, new String[]{"setNameTagVisibility", "a"}, EnumNameTagVisibility); // {Bukkit, Bukkit 1.18+}
|
||||
if (minorVersion >= 19) {
|
||||
Registry_a = Registry.getMethod("a", int.class);
|
||||
IRegistry_X = IRegistry.getDeclaredField("X").get(null);
|
||||
PacketPlayOutSpawnEntityLiving_ENTITYTYPE = getField(PacketPlayOutSpawnEntityLiving, "e");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadClasses() throws ClassNotFoundException {
|
||||
ChatSerializer = Class.forName("net.minecraft.network.chat.IChatBaseComponent$ChatSerializer");
|
||||
World = Class.forName("net.minecraft.world.level.World");
|
||||
EntityArmorStand = Class.forName("net.minecraft.world.entity.decoration.EntityArmorStand");
|
||||
EntityHuman = Class.forName("net.minecraft.world.entity.player.EntityHuman");
|
||||
NetworkManager = Class.forName("net.minecraft.network.NetworkManager");
|
||||
IChatBaseComponent = Class.forName("net.minecraft.network.chat.IChatBaseComponent");
|
||||
Packet = Class.forName("net.minecraft.network.protocol.Packet");
|
||||
EnumChatFormat = Class.forName("net.minecraft.EnumChatFormat");
|
||||
EntityPlayer = Class.forName("net.minecraft.server.level.EntityPlayer");
|
||||
Entity = Class.forName("net.minecraft.world.entity.Entity");
|
||||
EntityLiving = Class.forName("net.minecraft.world.entity.EntityLiving");
|
||||
PlayerConnection = Class.forName("net.minecraft.server.network.PlayerConnection");
|
||||
PacketPlayOutPlayerListHeaderFooter = Class.forName("net.minecraft.network.protocol.game.PacketPlayOutPlayerListHeaderFooter");
|
||||
PacketPlayOutChat = getModernClass("net.minecraft.network.protocol.game.ClientboundSystemChatPacket",
|
||||
"net.minecraft.network.protocol.game.PacketPlayOutChat");
|
||||
if (minorVersion < 19) {
|
||||
ChatMessageType = Class.forName("net.minecraft.network.chat.ChatMessageType");
|
||||
}
|
||||
|
||||
// DataWatcher
|
||||
DataWatcher = Class.forName("net.minecraft.network.syncher.DataWatcher");
|
||||
DataWatcherItem = Class.forName("net.minecraft.network.syncher.DataWatcher$Item");
|
||||
DataWatcherObject = Class.forName("net.minecraft.network.syncher.DataWatcherObject");
|
||||
DataWatcherRegistry = Class.forName("net.minecraft.network.syncher.DataWatcherRegistry");
|
||||
DataWatcherSerializer = Class.forName("net.minecraft.network.syncher.DataWatcherSerializer");
|
||||
|
||||
// Entities
|
||||
PacketPlayOutSpawnEntityLiving = getModernClass("net.minecraft.network.protocol.game.PacketPlayOutSpawnEntityLiving",
|
||||
"net.minecraft.network.protocol.game.PacketPlayOutSpawnEntity");
|
||||
PacketPlayOutEntityTeleport = Class.forName("net.minecraft.network.protocol.game.PacketPlayOutEntityTeleport");
|
||||
PacketPlayInUseEntity = Class.forName("net.minecraft.network.protocol.game.PacketPlayInUseEntity");
|
||||
PacketPlayInUseEntity$d = Class.forName("net.minecraft.network.protocol.game.PacketPlayInUseEntity$d");
|
||||
PacketPlayOutEntity = Class.forName("net.minecraft.network.protocol.game.PacketPlayOutEntity");
|
||||
PacketPlayOutEntityDestroy = Class.forName("net.minecraft.network.protocol.game.PacketPlayOutEntityDestroy");
|
||||
PacketPlayOutEntityLook = Class.forName("net.minecraft.network.protocol.game.PacketPlayOutEntity$PacketPlayOutEntityLook");
|
||||
PacketPlayOutEntityMetadata = Class.forName("net.minecraft.network.protocol.game.PacketPlayOutEntityMetadata");
|
||||
PacketPlayOutNamedEntitySpawn = Class.forName("net.minecraft.network.protocol.game.PacketPlayOutNamedEntitySpawn");
|
||||
EnumEntityUseAction = Class.forName("net.minecraft.network.protocol.game.PacketPlayInUseEntity$EnumEntityUseAction");
|
||||
if (minorVersion >= 19) {
|
||||
Registry = Class.forName("net.minecraft.core.Registry");
|
||||
IRegistry = Class.forName("net.minecraft.core.IRegistry");
|
||||
}
|
||||
|
||||
// Player Info
|
||||
PacketPlayOutPlayerInfo = Class.forName("net.minecraft.network.protocol.game.PacketPlayOutPlayerInfo");
|
||||
EnumPlayerInfoAction = Class.forName("net.minecraft.network.protocol.game.PacketPlayOutPlayerInfo$EnumPlayerInfoAction");
|
||||
PlayerInfoData = Class.forName("net.minecraft.network.protocol.game.PacketPlayOutPlayerInfo$PlayerInfoData");
|
||||
EnumGamemode = Class.forName("net.minecraft.world.level.EnumGamemode");
|
||||
|
||||
// Scoreboard
|
||||
PacketPlayOutScoreboardDisplayObjective = Class.forName("net.minecraft.network.protocol.game.PacketPlayOutScoreboardDisplayObjective");
|
||||
PacketPlayOutScoreboardObjective = Class.forName("net.minecraft.network.protocol.game.PacketPlayOutScoreboardObjective");
|
||||
Scoreboard = Class.forName("net.minecraft.world.scores.Scoreboard");
|
||||
PacketPlayOutScoreboardScore = Class.forName("net.minecraft.network.protocol.game.PacketPlayOutScoreboardScore");
|
||||
ScoreboardObjective = Class.forName("net.minecraft.world.scores.ScoreboardObjective");
|
||||
ScoreboardScore = Class.forName("net.minecraft.world.scores.ScoreboardScore");
|
||||
IScoreboardCriteria = Class.forName("net.minecraft.world.scores.criteria.IScoreboardCriteria");
|
||||
EnumScoreboardHealthDisplay = Class.forName("net.minecraft.world.scores.criteria.IScoreboardCriteria$EnumScoreboardHealthDisplay");
|
||||
EnumScoreboardAction = Class.forName("net.minecraft.server.ScoreboardServer$Action");
|
||||
PacketPlayOutScoreboardTeam = Class.forName("net.minecraft.network.protocol.game.PacketPlayOutScoreboardTeam");
|
||||
ScoreboardTeam = Class.forName("net.minecraft.world.scores.ScoreboardTeam");
|
||||
EnumNameTagVisibility = Class.forName("net.minecraft.world.scores.ScoreboardTeamBase$EnumNameTagVisibility");
|
||||
EnumTeamPush = Class.forName("net.minecraft.world.scores.ScoreboardTeamBase$EnumTeamPush");
|
||||
PacketPlayOutScoreboardTeam_PlayerAction = Class.forName("net.minecraft.network.protocol.game.PacketPlayOutScoreboardTeam$a");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
package me.neznamy.tab.platforms.bukkit.nms;
|
||||
|
||||
import me.neznamy.tab.platforms.bukkit.Main;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* NMS loader for Minecraft 1.16.5 and lower using old NMS class structure.
|
||||
*/
|
||||
public class LegacyNMSStorage extends NMSStorage {
|
||||
|
||||
/**
|
||||
* Creates new instance, initializes required NMS classes and fields
|
||||
*
|
||||
* @throws ReflectiveOperationException
|
||||
* If any class, field or method fails to load
|
||||
*/
|
||||
public LegacyNMSStorage() throws ReflectiveOperationException {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns class with given potential names in same order
|
||||
*
|
||||
* @param names
|
||||
* possible class names
|
||||
* @return class for specified names
|
||||
* @throws ClassNotFoundException
|
||||
* if class does not exist
|
||||
*/
|
||||
private Class<?> getLegacyClass(String... names) throws ClassNotFoundException {
|
||||
for (String name : names) {
|
||||
try {
|
||||
return getLegacyClass(name);
|
||||
} catch (ClassNotFoundException e) {
|
||||
//not the first class name in array
|
||||
}
|
||||
}
|
||||
throw new ClassNotFoundException("No class found with possible names " + Arrays.toString(names));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns class from given name
|
||||
*
|
||||
* @param name
|
||||
* class name
|
||||
* @return class from given name
|
||||
* @throws ClassNotFoundException
|
||||
* if class was not found
|
||||
*/
|
||||
private Class<?> getLegacyClass(String name) throws ClassNotFoundException {
|
||||
try {
|
||||
return Class.forName("net.minecraft.server." + serverPackage + "." + name);
|
||||
} catch (ClassNotFoundException | NullPointerException e) {
|
||||
try {
|
||||
//modded server?
|
||||
Class<?> clazz = Main.class.getClassLoader().loadClass("net.minecraft.server." + serverPackage + "." + name);
|
||||
if (clazz != null) return clazz;
|
||||
} catch (NullPointerException ignored) {}
|
||||
throw new ClassNotFoundException(name);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadNamedFieldsAndMethods() throws ReflectiveOperationException {
|
||||
PING = getField(EntityPlayer, "ping", "field_71138_i"); // {Bukkit, Thermos}
|
||||
ScoreboardScore_setScore = getMethod(ScoreboardScore, new String[]{"setScore", "func_96647_c"}, int.class); // {Bukkit, Thermos}
|
||||
ScoreboardTeam_setAllowFriendlyFire = getMethod(ScoreboardTeam,
|
||||
new String[]{"setAllowFriendlyFire", "func_96660_a"}, boolean.class); // {Bukkit, Thermos}
|
||||
ScoreboardTeam_setCanSeeFriendlyInvisibles = getMethod(ScoreboardTeam,
|
||||
new String[]{"setCanSeeFriendlyInvisibles", "func_98300_b"}, boolean.class); // {Bukkit, Thermos}
|
||||
if (minorVersion >= 7) {
|
||||
ChatSerializer_DESERIALIZE = getMethod(ChatSerializer, new String[]{"a", "func_150699_a"}, String.class); // {Bukkit, Thermos}
|
||||
}
|
||||
if (minorVersion >= 8) {
|
||||
ScoreboardTeam_setNameTagVisibility = getMethod(ScoreboardTeam, "setNameTagVisibility", EnumNameTagVisibility);
|
||||
}
|
||||
if (minorVersion >= 9) {
|
||||
DataWatcher_REGISTER = getMethod(DataWatcher, "register", DataWatcherObject, Object.class);
|
||||
} else {
|
||||
DataWatcher_REGISTER = getMethod(DataWatcher, new String[]{"a", "func_75682_a"}, int.class, Object.class); // {Bukkit, Thermos}
|
||||
}
|
||||
if (minorVersion >= 13) {
|
||||
ScoreboardTeam_setPrefix = getMethod(ScoreboardTeam, "setPrefix", IChatBaseComponent);
|
||||
ScoreboardTeam_setSuffix = getMethod(ScoreboardTeam, "setSuffix", IChatBaseComponent);
|
||||
} else {
|
||||
ScoreboardTeam_setPrefix = getMethod(ScoreboardTeam, new String[]{"setPrefix", "func_96666_b"}, String.class); // {Bukkit, Thermos}
|
||||
ScoreboardTeam_setSuffix = getMethod(ScoreboardTeam, new String[]{"setSuffix", "func_96662_c"}, String.class); // {Bukkit, Thermos}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadClasses() throws ClassNotFoundException {
|
||||
EntityHuman = getLegacyClass("EntityHuman");
|
||||
World = getLegacyClass("World");
|
||||
Packet = getLegacyClass("Packet");
|
||||
EnumChatFormat = getLegacyClass("EnumChatFormat");
|
||||
EntityPlayer = getLegacyClass("EntityPlayer");
|
||||
Entity = getLegacyClass("Entity");
|
||||
EntityLiving = getLegacyClass("EntityLiving");
|
||||
PlayerConnection = getLegacyClass("PlayerConnection");
|
||||
PacketPlayOutChat = getLegacyClass("PacketPlayOutChat", "Packet3Chat");
|
||||
NetworkManager = getLegacyClass("NetworkManager");
|
||||
if (minorVersion >= 7) {
|
||||
IChatBaseComponent = getLegacyClass("IChatBaseComponent");
|
||||
ChatSerializer = getLegacyClass("IChatBaseComponent$ChatSerializer", "ChatSerializer");
|
||||
}
|
||||
if (minorVersion >= 8) {
|
||||
PacketPlayOutPlayerListHeaderFooter = getLegacyClass("PacketPlayOutPlayerListHeaderFooter");
|
||||
EntityArmorStand = getLegacyClass("EntityArmorStand");
|
||||
}
|
||||
if (minorVersion >= 12) {
|
||||
ChatMessageType = getLegacyClass("ChatMessageType");
|
||||
}
|
||||
|
||||
// DataWatcher
|
||||
DataWatcher = getLegacyClass("DataWatcher");
|
||||
DataWatcherItem = getLegacyClass("DataWatcher$Item", "DataWatcher$WatchableObject", "WatchableObject");
|
||||
if (minorVersion >= 9) {
|
||||
DataWatcherObject = getLegacyClass("DataWatcherObject");
|
||||
DataWatcherRegistry = getLegacyClass("DataWatcherRegistry");
|
||||
DataWatcherSerializer = getLegacyClass("DataWatcherSerializer");
|
||||
}
|
||||
|
||||
// Entities
|
||||
PacketPlayOutSpawnEntityLiving = getLegacyClass("PacketPlayOutSpawnEntityLiving", "Packet24MobSpawn");
|
||||
PacketPlayOutEntityTeleport = getLegacyClass("PacketPlayOutEntityTeleport", "Packet34EntityTeleport");
|
||||
PacketPlayInUseEntity = getLegacyClass("PacketPlayInUseEntity", "Packet7UseEntity");
|
||||
PacketPlayOutEntity = getLegacyClass("PacketPlayOutEntity", "Packet30Entity");
|
||||
PacketPlayOutEntityDestroy = getLegacyClass("PacketPlayOutEntityDestroy", "Packet29DestroyEntity");
|
||||
PacketPlayOutEntityLook = getLegacyClass("PacketPlayOutEntity$PacketPlayOutEntityLook", "PacketPlayOutEntityLook", "Packet32EntityLook");
|
||||
PacketPlayOutEntityMetadata = getLegacyClass("PacketPlayOutEntityMetadata", "Packet40EntityMetadata");
|
||||
PacketPlayOutNamedEntitySpawn = getLegacyClass("PacketPlayOutNamedEntitySpawn", "Packet20NamedEntitySpawn");
|
||||
if (minorVersion >= 7) {
|
||||
EnumEntityUseAction = getLegacyClass("PacketPlayInUseEntity$EnumEntityUseAction", "EnumEntityUseAction");
|
||||
}
|
||||
|
||||
// Player Info
|
||||
if (minorVersion >= 8) {
|
||||
PacketPlayOutPlayerInfo = getLegacyClass("PacketPlayOutPlayerInfo");
|
||||
EnumPlayerInfoAction = getLegacyClass("PacketPlayOutPlayerInfo$EnumPlayerInfoAction", "EnumPlayerInfoAction");
|
||||
PlayerInfoData = getLegacyClass("PacketPlayOutPlayerInfo$PlayerInfoData", "PlayerInfoData");
|
||||
EnumGamemode = getLegacyClass("EnumGamemode", "WorldSettings$EnumGamemode");
|
||||
}
|
||||
|
||||
// Scoreboard
|
||||
PacketPlayOutScoreboardDisplayObjective = getLegacyClass("PacketPlayOutScoreboardDisplayObjective", "Packet208SetScoreboardDisplayObjective");
|
||||
PacketPlayOutScoreboardObjective = getLegacyClass("PacketPlayOutScoreboardObjective", "Packet206SetScoreboardObjective");
|
||||
PacketPlayOutScoreboardTeam = getLegacyClass("PacketPlayOutScoreboardTeam", "Packet209SetScoreboardTeam");
|
||||
PacketPlayOutScoreboardScore = getLegacyClass("PacketPlayOutScoreboardScore", "Packet207SetScoreboardScore");
|
||||
Scoreboard = getLegacyClass("Scoreboard");
|
||||
ScoreboardObjective = getLegacyClass("ScoreboardObjective");
|
||||
ScoreboardScore = getLegacyClass("ScoreboardScore");
|
||||
IScoreboardCriteria = getLegacyClass("IScoreboardCriteria");
|
||||
ScoreboardTeam = getLegacyClass("ScoreboardTeam");
|
||||
if (minorVersion >= 8) {
|
||||
EnumScoreboardHealthDisplay = getLegacyClass("IScoreboardCriteria$EnumScoreboardHealthDisplay", "EnumScoreboardHealthDisplay");
|
||||
EnumScoreboardAction = getLegacyClass("ScoreboardServer$Action", "PacketPlayOutScoreboardScore$EnumScoreboardAction", "EnumScoreboardAction");
|
||||
EnumNameTagVisibility = getLegacyClass("ScoreboardTeamBase$EnumNameTagVisibility", "EnumNameTagVisibility");
|
||||
}
|
||||
if (minorVersion >= 9) {
|
||||
EnumTeamPush = getLegacyClass("ScoreboardTeamBase$EnumTeamPush");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package me.neznamy.tab.platforms.bukkit.nms;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* NMS loader for minecraft 1.17+ using Mojang packaging.
|
||||
*/
|
||||
public abstract class ModernNMSStorage extends NMSStorage {
|
||||
|
||||
protected Class<?> IRegistry;
|
||||
protected Class<?> Registry;
|
||||
|
||||
/**
|
||||
* Creates new instance, initializes required NMS classes and fields
|
||||
*
|
||||
* @throws ReflectiveOperationException
|
||||
* If any class, field or method fails to load
|
||||
*/
|
||||
public ModernNMSStorage() throws ReflectiveOperationException {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns class with given potential names in same order
|
||||
*
|
||||
* @param names
|
||||
* possible class names
|
||||
* @return class for specified names
|
||||
* @throws ClassNotFoundException
|
||||
* if class does not exist
|
||||
*/
|
||||
protected Class<?> getModernClass(String... names) throws ClassNotFoundException {
|
||||
for (String name : names) {
|
||||
try {
|
||||
return Class.forName(name);
|
||||
} catch (ClassNotFoundException e) {
|
||||
//not the first class name in array
|
||||
}
|
||||
}
|
||||
throw new ClassNotFoundException("No class found with possible names " + Arrays.toString(names));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
package me.neznamy.tab.platforms.bukkit.nms;
|
||||
|
||||
/**
|
||||
* NMS loader for minecraft 1.17+ using Mojang packaging and names.
|
||||
*/
|
||||
public class MojangModernNMSStorage extends ModernNMSStorage {
|
||||
|
||||
/**
|
||||
* Creates new instance, initializes required NMS classes and fields
|
||||
*
|
||||
* @throws ReflectiveOperationException
|
||||
* If any class, field or method fails to load
|
||||
*/
|
||||
public MojangModernNMSStorage() throws ReflectiveOperationException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadNamedFieldsAndMethods() throws ReflectiveOperationException {
|
||||
PING = getField(EntityPlayer, "latency");
|
||||
ChatSerializer_DESERIALIZE = getMethod(ChatSerializer, "fromJson", String.class);
|
||||
DataWatcher_REGISTER = getMethod(DataWatcher, "define", DataWatcherObject, Object.class);
|
||||
ScoreboardScore_setScore = getMethod(ScoreboardScore, "setScore", int.class);
|
||||
ScoreboardTeam_setAllowFriendlyFire = getMethod(ScoreboardTeam, "setAllowFriendlyFire", boolean.class);
|
||||
ScoreboardTeam_setCanSeeFriendlyInvisibles = getMethod(ScoreboardTeam, "setSeeFriendlyInvisibles", boolean.class);
|
||||
ScoreboardTeam_setPrefix = getMethod(ScoreboardTeam, "setPlayerPrefix", IChatBaseComponent);
|
||||
ScoreboardTeam_setSuffix = getMethod(ScoreboardTeam, "setPlayerSuffix", IChatBaseComponent);
|
||||
ScoreboardTeam_setNameTagVisibility = getMethod(ScoreboardTeam, "setNameTagVisibility", EnumNameTagVisibility);
|
||||
if (minorVersion >= 19) {
|
||||
Registry_a = Registry.getMethod("byId", int.class);
|
||||
IRegistry_X = IRegistry.getDeclaredField("ENTITY_TYPE").get(null);
|
||||
PacketPlayOutSpawnEntityLiving_ENTITYTYPE = getField(PacketPlayOutSpawnEntityLiving, "type");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadClasses() throws ClassNotFoundException {
|
||||
IChatBaseComponent = Class.forName("net.minecraft.network.chat.Component");
|
||||
ChatSerializer = Class.forName("net.minecraft.network.chat.Component$Serializer");
|
||||
World = Class.forName("net.minecraft.world.level.Level");
|
||||
EntityArmorStand = Class.forName("net.minecraft.world.entity.decoration.ArmorStand");
|
||||
EntityHuman = Class.forName("net.minecraft.world.entity.player.Player");
|
||||
NetworkManager = Class.forName("net.minecraft.network.Connection");
|
||||
Packet = Class.forName("net.minecraft.network.protocol.Packet");
|
||||
EnumChatFormat = Class.forName("net.minecraft.ChatFormatting");
|
||||
EntityPlayer = Class.forName("net.minecraft.server.level.ServerPlayer");
|
||||
Entity = Class.forName("net.minecraft.world.entity.Entity");
|
||||
EntityLiving = Class.forName("net.minecraft.world.entity.LivingEntity");
|
||||
PlayerConnection = Class.forName("net.minecraft.server.network.ServerGamePacketListenerImpl");
|
||||
PacketPlayOutPlayerListHeaderFooter = Class.forName("net.minecraft.network.protocol.game.ClientboundTabListPacket");
|
||||
PacketPlayOutChat = getModernClass("net.minecraft.network.protocol.game.ClientboundSystemChatPacket",
|
||||
"net.minecraft.network.protocol.game.ClientboundChatPacket");
|
||||
if (minorVersion < 19) {
|
||||
ChatMessageType = Class.forName("net.minecraft.network.chat.ChatType");
|
||||
}
|
||||
|
||||
// DataWatcher
|
||||
DataWatcher = Class.forName("net.minecraft.network.syncher.SynchedEntityData");
|
||||
DataWatcherItem = Class.forName("net.minecraft.network.syncher.SynchedEntityData$DataItem");
|
||||
DataWatcherObject = Class.forName("net.minecraft.network.syncher.EntityDataAccessor");
|
||||
DataWatcherRegistry = Class.forName("net.minecraft.network.syncher.EntityDataSerializers");
|
||||
DataWatcherSerializer = Class.forName("net.minecraft.network.syncher.EntityDataSerializer");
|
||||
|
||||
// Entities
|
||||
PacketPlayOutSpawnEntityLiving = getModernClass("net.minecraft.network.protocol.game.ClientboundAddMobPacket",
|
||||
"net.minecraft.network.protocol.game.ClientboundAddEntityPacket");
|
||||
PacketPlayOutEntityTeleport = Class.forName("net.minecraft.network.protocol.game.ClientboundTeleportEntityPacket");
|
||||
PacketPlayInUseEntity = Class.forName("net.minecraft.network.protocol.game.ServerboundInteractPacket");
|
||||
PacketPlayInUseEntity$d = Class.forName("net.minecraft.network.protocol.game.ServerboundInteractPacket$InteractionAction");
|
||||
PacketPlayOutEntity = Class.forName("net.minecraft.network.protocol.game.ClientboundMoveEntityPacket");
|
||||
PacketPlayOutEntityDestroy = Class.forName("net.minecraft.network.protocol.game.ClientboundRemoveEntitiesPacket");
|
||||
PacketPlayOutEntityLook = Class.forName("net.minecraft.network.protocol.game.ClientboundMoveEntityPacket$Rot");
|
||||
PacketPlayOutEntityMetadata = Class.forName("net.minecraft.network.protocol.game.ClientboundSetEntityDataPacket");
|
||||
PacketPlayOutNamedEntitySpawn = Class.forName("net.minecraft.network.protocol.game.ClientboundAddPlayerPacket");
|
||||
EnumEntityUseAction = Class.forName("net.minecraft.network.protocol.game.ServerboundInteractPacket$Action");
|
||||
if (minorVersion >= 19) {
|
||||
Registry = Class.forName("net.minecraft.core.IdMap");
|
||||
IRegistry = Class.forName("net.minecraft.core.Registry");
|
||||
}
|
||||
|
||||
// Player Info
|
||||
PacketPlayOutPlayerInfo = Class.forName("net.minecraft.network.protocol.game.ClientboundPlayerInfoPacket");
|
||||
EnumPlayerInfoAction = Class.forName("net.minecraft.network.protocol.game.ClientboundPlayerInfoPacket$Action");
|
||||
PlayerInfoData = Class.forName("net.minecraft.network.protocol.game.ClientboundPlayerInfoPacket$PlayerUpdate");
|
||||
EnumGamemode = Class.forName("net.minecraft.world.level.GameType");
|
||||
|
||||
// Scoreboard
|
||||
PacketPlayOutScoreboardDisplayObjective = Class.forName("net.minecraft.network.protocol.game.ClientboundSetDisplayObjectivePacket");
|
||||
PacketPlayOutScoreboardObjective = Class.forName("net.minecraft.network.protocol.game.ClientboundSetObjectivePacket");
|
||||
Scoreboard = Class.forName("net.minecraft.world.scores.Scoreboard");
|
||||
PacketPlayOutScoreboardScore = Class.forName("net.minecraft.network.protocol.game.ClientboundSetScorePacket");
|
||||
ScoreboardObjective = Class.forName("net.minecraft.world.scores.Objective");
|
||||
ScoreboardScore = Class.forName("net.minecraft.world.scores.Score");
|
||||
IScoreboardCriteria = Class.forName("net.minecraft.world.scores.criteria.ObjectiveCriteria");
|
||||
EnumScoreboardHealthDisplay = Class.forName("net.minecraft.world.scores.criteria.ObjectiveCriteria$RenderType");
|
||||
EnumScoreboardAction = Class.forName("net.minecraft.server.ServerScoreboard$Method");
|
||||
PacketPlayOutScoreboardTeam = Class.forName("net.minecraft.network.protocol.game.ClientboundSetPlayerTeamPacket");
|
||||
ScoreboardTeam = Class.forName("net.minecraft.world.scores.PlayerTeam");
|
||||
EnumNameTagVisibility = Class.forName("net.minecraft.world.scores.Team$Visibility");
|
||||
EnumTeamPush = Class.forName("net.minecraft.world.scores.Team$CollisionRule");
|
||||
PacketPlayOutScoreboardTeam_PlayerAction = Class.forName("net.minecraft.network.protocol.game.ClientboundSetPlayerTeamPacket$Action");
|
||||
}
|
||||
}
|
||||
@@ -1,166 +1,134 @@
|
||||
package me.neznamy.tab.platforms.bukkit.nms;
|
||||
|
||||
import java.lang.reflect.AccessibleObject;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
import me.neznamy.tab.api.ProtocolVersion;
|
||||
import me.neznamy.tab.platforms.bukkit.Main;
|
||||
import me.neznamy.tab.platforms.bukkit.nms.datawatcher.DataWatcherRegistry;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import java.lang.reflect.*;
|
||||
import java.util.*;
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public final class NMSStorage {
|
||||
public abstract class NMSStorage {
|
||||
|
||||
//instance of this class
|
||||
private static NMSStorage instance;
|
||||
|
||||
//server package, such as "v1_16_R3"
|
||||
private final String serverPackage = Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3];
|
||||
protected final String serverPackage = Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3];
|
||||
|
||||
//server minor version such as "16"
|
||||
private final int minorVersion = Integer.parseInt(serverPackage.split("_")[1]);
|
||||
protected final int minorVersion = Integer.parseInt(serverPackage.split("_")[1]);
|
||||
|
||||
//another field due to fabric which uses 1.16 package on 1.17 server
|
||||
private final ProtocolVersion serverVersion = ProtocolVersion.fromFriendlyName(Bukkit.getBukkitVersion().split("-")[0]);
|
||||
|
||||
//base
|
||||
private final Class<?> Packet = getNMSClass("net.minecraft.network.protocol.Packet", "Packet");
|
||||
public final Class<?> EnumChatFormat = getNMSClass("net.minecraft.EnumChatFormat", "EnumChatFormat");
|
||||
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<?> 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");
|
||||
public final Field PLAYER_CONNECTION = getFields(EntityPlayer, PlayerConnection).get(0);
|
||||
protected Class<?> Packet;
|
||||
protected Class<?> NetworkManager;
|
||||
protected Class<?> EntityArmorStand;
|
||||
protected Class<?> World;
|
||||
public Class<?> EnumChatFormat;
|
||||
public Class<?> EntityPlayer;
|
||||
protected Class<?> EntityHuman;
|
||||
protected Class<?> Entity;
|
||||
protected Class<?> EntityLiving;
|
||||
protected Class<?> PlayerConnection;
|
||||
public Field PING;
|
||||
public Field PLAYER_CONNECTION;
|
||||
public Field NETWORK_MANAGER;
|
||||
public Field CHANNEL;
|
||||
public final Method getHandle = Class.forName("org.bukkit.craftbukkit." + serverPackage + ".entity.CraftPlayer").getMethod("getHandle");
|
||||
public final Method sendPacket = getMethods(PlayerConnection, void.class, Packet).get(0);
|
||||
public Method getHandle;
|
||||
public Method sendPacket;
|
||||
public Method getProfile;
|
||||
public final Method World_getHandle = Class.forName("org.bukkit.craftbukkit." + serverPackage + ".CraftWorld").getMethod("getHandle");
|
||||
public final Enum[] EnumChatFormat_values = getEnumValues(EnumChatFormat);
|
||||
public Enum[] EnumChatFormat_values;
|
||||
|
||||
//chat
|
||||
public Class<?> ChatComponentText;
|
||||
public Class<?> ChatHoverable;
|
||||
public Class<?> EnumClickAction;
|
||||
private Class<?> IChatBaseComponent;
|
||||
public Constructor<?> newChatComponentText;
|
||||
public Constructor<?> newChatClickable;
|
||||
public Constructor<?> newChatModifier;
|
||||
public Constructor<?> newChatHoverable;
|
||||
public Field ChatBaseComponent_extra;
|
||||
public Field ChatBaseComponent_modifier;
|
||||
public Field ChatComponentText_text;
|
||||
public Field ChatClickable_action;
|
||||
public Field ChatClickable_value;
|
||||
public Field ChatModifier_bold;
|
||||
public Field ChatModifier_italic;
|
||||
public Field ChatModifier_underlined;
|
||||
public Field ChatModifier_strikethrough;
|
||||
public Field ChatModifier_obfuscated;
|
||||
public Field ChatModifier_clickEvent;
|
||||
public Field ChatModifier_hoverEvent;
|
||||
public Field ChatHexColor_name;
|
||||
public Field ChatHexColor_rgb;
|
||||
public Field ChatModifier_color;
|
||||
public Method ChatComponentText_addSibling;
|
||||
public Method EnumHoverAction_a;
|
||||
public Method ChatHoverable_getAction;
|
||||
public Method ChatHexColor_ofInt;
|
||||
public Method ChatHexColor_ofString;
|
||||
public Method ChatHoverable_serialize;
|
||||
public Method ChatHoverable_getValue;
|
||||
public Method EnumHoverAction_fromJson;
|
||||
public Method EnumHoverAction_fromLegacyComponent;
|
||||
protected Class<?> IChatBaseComponent;
|
||||
protected Class<?> ChatSerializer;
|
||||
public Method ChatSerializer_DESERIALIZE;
|
||||
|
||||
//PacketPlayOutChat
|
||||
protected Class<?> PacketPlayOutChat;
|
||||
public Class<?> ChatMessageType;
|
||||
public Constructor<?> newPacketPlayOutChat;
|
||||
public Enum[] ChatMessageType_values;
|
||||
|
||||
//DataWatcher
|
||||
private final Class<?> DataWatcher = getNMSClass("net.minecraft.network.syncher.DataWatcher", "DataWatcher");
|
||||
private final Class<?> DataWatcherItem = getNMSClass("net.minecraft.network.syncher.DataWatcher$Item", "DataWatcher$Item", "DataWatcher$WatchableObject", "WatchableObject");
|
||||
protected Class<?> DataWatcher;
|
||||
protected Class<?> DataWatcherItem;
|
||||
protected Class<?> DataWatcherObject;
|
||||
protected Class<?> DataWatcherSerializer;
|
||||
public Class<?> DataWatcherRegistry;
|
||||
public final Constructor<?> newDataWatcher = DataWatcher.getConstructors()[0];
|
||||
public Constructor<?> newDataWatcher;
|
||||
public Constructor<?> newDataWatcherObject;
|
||||
public Field DataWatcherItem_TYPE;
|
||||
public final Field DataWatcherItem_VALUE = getFields(DataWatcherItem, Object.class).get(0);
|
||||
public Field DataWatcherItem_VALUE;
|
||||
public Field DataWatcherObject_SLOT;
|
||||
public Field DataWatcherObject_SERIALIZER;
|
||||
public Method DataWatcher_REGISTER;
|
||||
private DataWatcherRegistry registry;
|
||||
private final DataWatcherRegistry registry;
|
||||
|
||||
//PacketPlayOutSpawnEntityLiving
|
||||
public final Class<?> PacketPlayOutSpawnEntityLiving = getNMSClass("net.minecraft.network.protocol.game.PacketPlayOutSpawnEntityLiving", "PacketPlayOutSpawnEntityLiving", "Packet24MobSpawn");
|
||||
public Class<?> PacketPlayOutSpawnEntityLiving;
|
||||
public Constructor<?> newPacketPlayOutSpawnEntityLiving;
|
||||
public final Field PacketPlayOutSpawnEntityLiving_ENTITYID = getFields(PacketPlayOutSpawnEntityLiving, int.class).get(0);
|
||||
public final Field PacketPlayOutSpawnEntityLiving_ENTITYTYPE = getFields(PacketPlayOutSpawnEntityLiving, int.class).get(1);
|
||||
public final Field PacketPlayOutSpawnEntityLiving_YAW = getFields(PacketPlayOutSpawnEntityLiving, byte.class).get(0);
|
||||
public final Field PacketPlayOutSpawnEntityLiving_PITCH = getFields(PacketPlayOutSpawnEntityLiving, byte.class).get(0);
|
||||
public Field PacketPlayOutSpawnEntityLiving_ENTITYID;
|
||||
public Field PacketPlayOutSpawnEntityLiving_ENTITYTYPE;
|
||||
public Field PacketPlayOutSpawnEntityLiving_YAW;
|
||||
public Field PacketPlayOutSpawnEntityLiving_PITCH;
|
||||
public Field PacketPlayOutSpawnEntityLiving_UUID;
|
||||
public Field PacketPlayOutSpawnEntityLiving_X;
|
||||
public Field PacketPlayOutSpawnEntityLiving_Y;
|
||||
public Field PacketPlayOutSpawnEntityLiving_Z;
|
||||
public Field PacketPlayOutSpawnEntityLiving_DATAWATCHER;
|
||||
public Method Registry_a;
|
||||
public Object IRegistry_X;
|
||||
|
||||
//PacketPlayOutEntityTeleport
|
||||
public final Class<?> PacketPlayOutEntityTeleport = getNMSClass("net.minecraft.network.protocol.game.PacketPlayOutEntityTeleport", "PacketPlayOutEntityTeleport", "Packet34EntityTeleport");
|
||||
public Class<?> PacketPlayOutEntityTeleport;
|
||||
public Constructor<?> newPacketPlayOutEntityTeleport;
|
||||
public final Field PacketPlayOutEntityTeleport_ENTITYID = getFields(PacketPlayOutEntityTeleport, int.class).get(0);
|
||||
public Field PacketPlayOutEntityTeleport_ENTITYID;
|
||||
public Field PacketPlayOutEntityTeleport_X;
|
||||
public Field PacketPlayOutEntityTeleport_Y;
|
||||
public Field PacketPlayOutEntityTeleport_Z;
|
||||
public final Field PacketPlayOutEntityTeleport_YAW = getFields(PacketPlayOutEntityTeleport, byte.class).get(0);
|
||||
public final Field PacketPlayOutEntityTeleport_PITCH = getFields(PacketPlayOutEntityTeleport, byte.class).get(1);
|
||||
public Field PacketPlayOutEntityTeleport_YAW;
|
||||
public Field PacketPlayOutEntityTeleport_PITCH;
|
||||
|
||||
//PacketPlayOutPlayerListHeaderFooter
|
||||
protected Class<?> PacketPlayOutPlayerListHeaderFooter;
|
||||
public Constructor<?> newPacketPlayOutPlayerListHeaderFooter;
|
||||
public Field PacketPlayOutPlayerListHeaderFooter_HEADER;
|
||||
public Field PacketPlayOutPlayerListHeaderFooter_FOOTER;
|
||||
|
||||
//other entity packets
|
||||
public final Class<?> PacketPlayInUseEntity = getNMSClass("net.minecraft.network.protocol.game.PacketPlayInUseEntity", "PacketPlayInUseEntity", "Packet7UseEntity");
|
||||
public Class<?> PacketPlayInUseEntity;
|
||||
public Class<?> PacketPlayInUseEntity$d;
|
||||
protected Class<?> EnumEntityUseAction;
|
||||
public Field PacketPlayInUseEntity_ENTITY;
|
||||
public Field PacketPlayInUseEntity_ACTION;
|
||||
|
||||
public final Class<?> PacketPlayOutEntity = getNMSClass("net.minecraft.network.protocol.game.PacketPlayOutEntity", "PacketPlayOutEntity", "Packet30Entity");
|
||||
public final Field PacketPlayOutEntity_ENTITYID = getFields(PacketPlayOutEntity, int.class).get(0);
|
||||
public Class<?> PacketPlayOutEntity;
|
||||
public Field PacketPlayOutEntity_ENTITYID;
|
||||
|
||||
public final Class<?> PacketPlayOutEntityDestroy = getNMSClass("net.minecraft.network.protocol.game.PacketPlayOutEntityDestroy", "PacketPlayOutEntityDestroy", "Packet29DestroyEntity");
|
||||
public Class<?> PacketPlayOutEntityDestroy;
|
||||
public Constructor<?> newPacketPlayOutEntityDestroy;
|
||||
public final Field PacketPlayOutEntityDestroy_ENTITIES = setAccessible(PacketPlayOutEntityDestroy.getDeclaredFields()[0]);
|
||||
public Field PacketPlayOutEntityDestroy_ENTITIES;
|
||||
|
||||
public final Class<?> PacketPlayOutEntityLook = getNMSClass("net.minecraft.network.protocol.game.PacketPlayOutEntity$PacketPlayOutEntityLook", "PacketPlayOutEntity$PacketPlayOutEntityLook", "PacketPlayOutEntityLook", "Packet32EntityLook");
|
||||
public Class<?> PacketPlayOutEntityLook;
|
||||
|
||||
public final Class<?> PacketPlayOutEntityMetadata = getNMSClass("net.minecraft.network.protocol.game.PacketPlayOutEntityMetadata", "PacketPlayOutEntityMetadata", "Packet40EntityMetadata");
|
||||
public final Constructor<?> newPacketPlayOutEntityMetadata = PacketPlayOutEntityMetadata.getConstructor(int.class, DataWatcher, boolean.class);
|
||||
public final Field PacketPlayOutEntityMetadata_LIST = getFields(PacketPlayOutEntityMetadata, List.class).get(0);
|
||||
public Class<?> PacketPlayOutEntityMetadata;
|
||||
public Constructor<?> newPacketPlayOutEntityMetadata;
|
||||
public Field PacketPlayOutEntityMetadata_LIST;
|
||||
|
||||
public final Class<?> PacketPlayOutNamedEntitySpawn = getNMSClass("net.minecraft.network.protocol.game.PacketPlayOutNamedEntitySpawn", "PacketPlayOutNamedEntitySpawn", "Packet20NamedEntitySpawn");
|
||||
public final Field PacketPlayOutNamedEntitySpawn_ENTITYID = getFields(PacketPlayOutNamedEntitySpawn, int.class).get(0);
|
||||
public Class<?> PacketPlayOutNamedEntitySpawn;
|
||||
public Field PacketPlayOutNamedEntitySpawn_ENTITYID;
|
||||
|
||||
//PacketPlayOutPlayerInfo
|
||||
public Class<?> PacketPlayOutPlayerInfo;
|
||||
protected Class<?> EnumPlayerInfoAction;
|
||||
protected Class<?> PlayerInfoData;
|
||||
protected Class<?> EnumGamemode;
|
||||
public Constructor<?> newPacketPlayOutPlayerInfo;
|
||||
public Constructor<?> newPlayerInfoData;
|
||||
public Field PacketPlayOutPlayerInfo_ACTION;
|
||||
@@ -173,38 +141,44 @@ public final class NMSStorage {
|
||||
public Enum[] EnumGamemode_values;
|
||||
|
||||
//scoreboard objectives
|
||||
public final Class<?> PacketPlayOutScoreboardDisplayObjective = getNMSClass("net.minecraft.network.protocol.game.PacketPlayOutScoreboardDisplayObjective", "PacketPlayOutScoreboardDisplayObjective", "Packet208SetScoreboardDisplayObjective");
|
||||
public final Class<?> PacketPlayOutScoreboardObjective = getNMSClass("net.minecraft.network.protocol.game.PacketPlayOutScoreboardObjective", "PacketPlayOutScoreboardObjective", "Packet206SetScoreboardObjective");
|
||||
private final Class<?> Scoreboard = getNMSClass("net.minecraft.world.scores.Scoreboard", "Scoreboard");
|
||||
private final Class<?> PacketPlayOutScoreboardScore = getNMSClass("net.minecraft.network.protocol.game.PacketPlayOutScoreboardScore", "PacketPlayOutScoreboardScore", "Packet207SetScoreboardScore");
|
||||
private final Class<?> ScoreboardObjective = getNMSClass("net.minecraft.world.scores.ScoreboardObjective", "ScoreboardObjective");
|
||||
private final Class<?> ScoreboardScore = getNMSClass("net.minecraft.world.scores.ScoreboardScore", "ScoreboardScore");
|
||||
private final Class<?> IScoreboardCriteria = getNMSClass("net.minecraft.world.scores.criteria.IScoreboardCriteria", "IScoreboardCriteria");
|
||||
public Class<?> PacketPlayOutScoreboardDisplayObjective;
|
||||
public Class<?> PacketPlayOutScoreboardObjective;
|
||||
protected Class<?> Scoreboard;
|
||||
protected Class<?> PacketPlayOutScoreboardScore;
|
||||
protected Class<?> ScoreboardObjective;
|
||||
protected Class<?> ScoreboardScore;
|
||||
protected Class<?> IScoreboardCriteria;
|
||||
public Class<?> EnumScoreboardHealthDisplay;
|
||||
public final Constructor<?> newScoreboardObjective = ScoreboardObjective.getConstructors()[0];
|
||||
public final Constructor<?> newScoreboard = Scoreboard.getConstructor();
|
||||
public final Constructor<?> newScoreboardScore = ScoreboardScore.getConstructor(Scoreboard, ScoreboardObjective, String.class);
|
||||
public final Constructor<?> newPacketPlayOutScoreboardDisplayObjective = PacketPlayOutScoreboardDisplayObjective.getConstructor(int.class, ScoreboardObjective);
|
||||
protected Class<?> EnumScoreboardAction;
|
||||
public Constructor<?> newScoreboardObjective;
|
||||
protected Constructor<?> newScoreboard;
|
||||
public Constructor<?> newScoreboardScore;
|
||||
public Constructor<?> newPacketPlayOutScoreboardDisplayObjective;
|
||||
public Constructor<?> newPacketPlayOutScoreboardObjective;
|
||||
public Constructor<?> newPacketPlayOutScoreboardScore_1_13;
|
||||
public Constructor<?> newPacketPlayOutScoreboardScore_String;
|
||||
public Constructor<?> newPacketPlayOutScoreboardScore;
|
||||
public final Field PacketPlayOutScoreboardDisplayObjective_POSITION = getFields(PacketPlayOutScoreboardDisplayObjective, int.class).get(0);
|
||||
public final Field PacketPlayOutScoreboardDisplayObjective_OBJECTIVENAME = getFields(PacketPlayOutScoreboardDisplayObjective, String.class).get(0);
|
||||
public final Field PacketPlayOutScoreboardObjective_OBJECTIVENAME = getFields(PacketPlayOutScoreboardObjective, String.class).get(0);
|
||||
public Field PacketPlayOutScoreboardDisplayObjective_POSITION;
|
||||
public Field PacketPlayOutScoreboardDisplayObjective_OBJECTIVENAME;
|
||||
public Field PacketPlayOutScoreboardObjective_OBJECTIVENAME;
|
||||
public Field PacketPlayOutScoreboardObjective_METHOD;
|
||||
public final Field IScoreboardCriteria_self = getFields(IScoreboardCriteria, IScoreboardCriteria).get(0);
|
||||
public Field IScoreboardCriteria_self;
|
||||
public Field PacketPlayOutScoreboardObjective_RENDERTYPE;
|
||||
public Field PacketPlayOutScoreboardObjective_DISPLAYNAME;
|
||||
public final Method ScoreboardScore_setScore = getMethod(ScoreboardScore, new String[]{"setScore", "func_96647_c", "method_1128", "b"}, int.class);
|
||||
public Method ScoreboardScore_setScore;
|
||||
public Enum[] EnumScoreboardHealthDisplay_values;
|
||||
public Enum[] EnumScoreboardAction_values;
|
||||
|
||||
//PacketPlayOutScoreboardTeam
|
||||
public Class<?> PacketPlayOutScoreboardTeam;
|
||||
protected Class<?> ScoreboardTeam;
|
||||
protected Class<?> EnumNameTagVisibility;
|
||||
protected Class<?> EnumTeamPush;
|
||||
protected Class<?> PacketPlayOutScoreboardTeam_PlayerAction;
|
||||
public Constructor<?> newScoreboardTeam;
|
||||
public Constructor<?> newPacketPlayOutScoreboardTeam;
|
||||
public Field PacketPlayOutScoreboardTeam_NAME;
|
||||
public Field PacketPlayOutScoreboardTeam_ACTION;
|
||||
public Field PacketPlayOutScoreboardTeam_PLAYERS;
|
||||
public Method ScoreboardTeam_getPlayerNameSet;
|
||||
public Method ScoreboardTeam_setNameTagVisibility;
|
||||
@@ -221,37 +195,38 @@ public final class NMSStorage {
|
||||
public Enum[] EnumTeamPush_values;
|
||||
public Enum[] PacketPlayOutScoreboardTeam_PlayerAction_values;
|
||||
|
||||
/**
|
||||
* Creates new instance, initializes required NMS classes and fields
|
||||
*
|
||||
* @throws ReflectiveOperationException
|
||||
* If any class, field or method fails to load
|
||||
*/
|
||||
//other
|
||||
public Object emptyScoreboard;
|
||||
public Object dummyEntity;
|
||||
|
||||
public NMSStorage() throws ReflectiveOperationException {
|
||||
ProtocolVersion.UNKNOWN_SERVER_VERSION.setMinorVersion(minorVersion); //fixing compatibility with forks that set version field value to "Unknown"
|
||||
Class<?> NetworkManager = getNMSClass("net.minecraft.network.NetworkManager", "NetworkManager");
|
||||
loadClasses();
|
||||
if (minorVersion >= 7) {
|
||||
NETWORK_MANAGER = getFields(PlayerConnection, NetworkManager).get(0);
|
||||
}
|
||||
if (minorVersion >= 8) {
|
||||
CHANNEL = getFields(NetworkManager, Channel.class).get(0);
|
||||
getProfile = getMethods(getNMSClass("net.minecraft.world.entity.player.EntityHuman", "EntityHuman"), GameProfile.class).get(0);
|
||||
newEntityArmorStand = getNMSClass("net.minecraft.world.entity.decoration.EntityArmorStand", "EntityArmorStand")
|
||||
.getConstructor(getNMSClass("net.minecraft.world.level.World", "World"), double.class, double.class, double.class);
|
||||
}
|
||||
initializeChatComponents();
|
||||
initializeChatPacket();
|
||||
initializeDataWatcher();
|
||||
initializeEntityPackets();
|
||||
initializeHeaderFooterPacket();
|
||||
initializePlayerInfoPacket();
|
||||
initializeScoreboardPackets();
|
||||
try {
|
||||
initializeTeamPackets();
|
||||
} catch (ClassNotFoundException e) {
|
||||
Bukkit.getConsoleSender().sendMessage(me.neznamy.tab.api.chat.EnumChatFormat.color("&c[TAB] Failed to load PacketPlayOutScoreboardTeam"));
|
||||
//fabric with missing team packet
|
||||
getProfile = getMethods(EntityHuman, GameProfile.class).get(0);
|
||||
Constructor<?> newEntityArmorStand = EntityArmorStand.getConstructor(World, double.class, double.class, double.class);
|
||||
Method World_getHandle = Class.forName("org.bukkit.craftbukkit." + serverPackage + ".CraftWorld").getMethod("getHandle");
|
||||
dummyEntity = newEntityArmorStand.newInstance(World_getHandle.invoke(Bukkit.getWorlds().get(0)), 0, 0, 0);
|
||||
}
|
||||
PLAYER_CONNECTION = getFields(EntityPlayer, PlayerConnection).get(0);
|
||||
getHandle = Class.forName("org.bukkit.craftbukkit." + serverPackage + ".entity.CraftPlayer").getMethod("getHandle");
|
||||
sendPacket = getMethods(PlayerConnection, void.class, Packet).get(0);
|
||||
EnumChatFormat_values = getEnumValues(EnumChatFormat);
|
||||
registry = new DataWatcherRegistry(this);
|
||||
dataWatcher();
|
||||
entityTeleport();
|
||||
spawnEntityLiving();
|
||||
chat();
|
||||
playerListHeaderFooter();
|
||||
playerInfo();
|
||||
otherEntity();
|
||||
scoreboard();
|
||||
scoreboardTeam();
|
||||
loadNamedFieldsAndMethods();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -273,64 +248,18 @@ public final class NMSStorage {
|
||||
return instance;
|
||||
}
|
||||
|
||||
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");
|
||||
ChatComponentText = getNMSClass("net.minecraft.network.chat.ChatComponentText", "ChatComponentText");
|
||||
ChatHoverable = getNMSClass("net.minecraft.network.chat.ChatHoverable", "ChatHoverable");
|
||||
Class<?> ChatModifier = getNMSClass("net.minecraft.network.chat.ChatModifier", "ChatModifier");
|
||||
EnumClickAction = getNMSClass("net.minecraft.network.chat.ChatClickable$EnumClickAction", "ChatClickable$EnumClickAction", "EnumClickAction");
|
||||
Class<?> EnumHoverAction = getNMSClass("net.minecraft.network.chat.ChatHoverable$EnumHoverAction", "ChatHoverable$EnumHoverAction", "EnumHoverAction");
|
||||
IChatBaseComponent = getNMSClass("net.minecraft.network.chat.IChatBaseComponent", "IChatBaseComponent");
|
||||
newChatComponentText = ChatComponentText.getConstructor(String.class);
|
||||
newChatClickable = ChatClickable.getConstructor(EnumClickAction, String.class);
|
||||
ChatBaseComponent_extra = getFields(ChatBaseComponent, List.class).get(0);
|
||||
ChatBaseComponent_modifier = getFields(ChatBaseComponent, ChatModifier).get(0);
|
||||
ChatComponentText_text = getFields(ChatComponentText, String.class).get(0);
|
||||
ChatClickable_action = getFields(ChatClickable, EnumClickAction).get(0);
|
||||
ChatClickable_value = getFields(ChatClickable, String.class).get(0);
|
||||
List<Field> booleans = getFields(ChatModifier, Boolean.class);
|
||||
ChatModifier_bold = booleans.get(0);
|
||||
ChatModifier_italic = booleans.get(1);
|
||||
ChatModifier_underlined = booleans.get(2);
|
||||
ChatModifier_strikethrough = booleans.get(3);
|
||||
ChatModifier_obfuscated = booleans.get(4);
|
||||
ChatModifier_clickEvent = getFields(ChatModifier, ChatClickable).get(0);
|
||||
ChatModifier_hoverEvent = getFields(ChatModifier, ChatHoverable).get(0);
|
||||
ChatComponentText_addSibling = getMethod(ChatComponentText, new String[]{"addSibling", "a", "func_150257_a", "method_10852"}, IChatBaseComponent);
|
||||
EnumHoverAction_a = getMethod(EnumHoverAction, new String[]{"a", "func_150684_a", "method_27670"}, String.class);
|
||||
ChatHoverable_getAction = getMethods(ChatHoverable, EnumHoverAction).get(0);
|
||||
if (minorVersion >= 16) {
|
||||
Class<?> ChatHexColor = getNMSClass("net.minecraft.network.chat.ChatHexColor", "ChatHexColor");
|
||||
Class<?> MinecraftKey = getNMSClass("net.minecraft.resources.MinecraftKey", "MinecraftKey");
|
||||
newChatModifier = setAccessible(ChatModifier.getDeclaredConstructor(ChatHexColor, Boolean.class, Boolean.class, Boolean.class, Boolean.class, Boolean.class, ChatClickable, ChatHoverable, String.class, MinecraftKey));
|
||||
newChatHoverable = ChatHoverable.getConstructor(EnumHoverAction, Object.class);
|
||||
List<Field> list = getFields(ChatHexColor, String.class);
|
||||
ChatHexColor_name = list.get(list.size()-1);
|
||||
ChatHexColor_rgb = getFields(ChatHexColor, int.class).get(0);
|
||||
ChatModifier_color = getFields(ChatModifier, ChatHexColor).get(0);
|
||||
ChatHexColor_ofInt = getMethods(ChatHexColor, ChatHexColor, int.class).get(0);
|
||||
ChatHexColor_ofString = getMethods(ChatHexColor, ChatHexColor, String.class).get(0);
|
||||
ChatHoverable_serialize = getMethods(ChatHoverable, JsonObject.class).get(0);
|
||||
ChatHoverable_getValue = getMethods(ChatHoverable, Object.class, EnumHoverAction).get(0);
|
||||
EnumHoverAction_fromJson = getMethods(EnumHoverAction, ChatHoverable, JsonElement.class).get(0);
|
||||
EnumHoverAction_fromLegacyComponent = getMethods(EnumHoverAction, ChatHoverable, IChatBaseComponent).get(0);
|
||||
} else {
|
||||
newChatModifier = ChatModifier.getConstructor();
|
||||
newChatHoverable = ChatHoverable.getConstructor(EnumHoverAction, IChatBaseComponent);
|
||||
ChatModifier_color = getFields(ChatModifier, EnumChatFormat).get(0);
|
||||
ChatHoverable_getValue = getMethods(ChatHoverable, IChatBaseComponent).get(0);
|
||||
}
|
||||
}
|
||||
|
||||
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");
|
||||
protected void chat() throws ReflectiveOperationException {
|
||||
if (minorVersion >= 12 && minorVersion <= 18) {
|
||||
ChatMessageType_values = getEnumValues(ChatMessageType);
|
||||
}
|
||||
if (minorVersion >= 16) {
|
||||
if (minorVersion >= 19) {
|
||||
try {
|
||||
newPacketPlayOutChat = PacketPlayOutChat.getConstructor(IChatBaseComponent, boolean.class);
|
||||
} catch (NoSuchMethodException e) {
|
||||
//1.19.0
|
||||
newPacketPlayOutChat = PacketPlayOutChat.getConstructor(IChatBaseComponent, int.class);
|
||||
}
|
||||
} else if (minorVersion >= 16) {
|
||||
newPacketPlayOutChat = PacketPlayOutChat.getConstructor(IChatBaseComponent, ChatMessageType, UUID.class);
|
||||
} else if (minorVersion >= 12) {
|
||||
newPacketPlayOutChat = PacketPlayOutChat.getConstructor(IChatBaseComponent, ChatMessageType);
|
||||
@@ -341,84 +270,8 @@ public final class NMSStorage {
|
||||
}
|
||||
}
|
||||
|
||||
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");
|
||||
Class<?> DataWatcherSerializer = getNMSClass("net.minecraft.network.syncher.DataWatcherSerializer", "DataWatcherSerializer");
|
||||
newDataWatcherObject = DataWatcherObject.getConstructor(int.class, DataWatcherSerializer);
|
||||
DataWatcherItem_TYPE = getFields(DataWatcherItem, DataWatcherObject).get(0);
|
||||
DataWatcherObject_SLOT = getFields(DataWatcherObject, int.class).get(0);
|
||||
DataWatcherObject_SERIALIZER = getFields(DataWatcherObject, DataWatcherSerializer).get(0);
|
||||
DataWatcher_REGISTER = getMethod(DataWatcher, new String[]{"register", "method_12784", "a"}, DataWatcherObject, Object.class);
|
||||
} else {
|
||||
DataWatcherItem_TYPE = getFields(DataWatcherItem, int.class).get(1);
|
||||
DataWatcher_REGISTER = getMethod(DataWatcher, new String[]{"a", "func_75682_a"}, int.class, Object.class);
|
||||
}
|
||||
registry = new DataWatcherRegistry(this);
|
||||
}
|
||||
|
||||
private void initializeEntityPackets() throws ReflectiveOperationException {
|
||||
if (minorVersion >= 17 || serverVersion.getMinorVersion() >= 17) {
|
||||
newPacketPlayOutSpawnEntityLiving = PacketPlayOutSpawnEntityLiving.getConstructor(EntityLiving);
|
||||
newPacketPlayOutEntityTeleport = PacketPlayOutEntityTeleport.getConstructor(Entity);
|
||||
} else {
|
||||
newPacketPlayOutSpawnEntityLiving = PacketPlayOutSpawnEntityLiving.getConstructor();
|
||||
newPacketPlayOutEntityTeleport = PacketPlayOutEntityTeleport.getConstructor();
|
||||
}
|
||||
if (minorVersion >= 17) {
|
||||
PacketPlayInUseEntity$d = Class.forName("net.minecraft.network.protocol.game.PacketPlayInUseEntity$d");
|
||||
}
|
||||
try {
|
||||
newPacketPlayOutEntityDestroy = PacketPlayOutEntityDestroy.getConstructor(int[].class);
|
||||
} catch (NoSuchMethodException e) {
|
||||
//1.17.0
|
||||
newPacketPlayOutEntityDestroy = PacketPlayOutEntityDestroy.getConstructor(int.class);
|
||||
}
|
||||
if (minorVersion >= 7) {
|
||||
Class<?> EnumEntityUseAction = getNMSClass("net.minecraft.network.protocol.game.PacketPlayInUseEntity$EnumEntityUseAction", "PacketPlayInUseEntity$EnumEntityUseAction", "EnumEntityUseAction", "net.minecraft.class_2824$class_5906");
|
||||
PacketPlayInUseEntity_ENTITY = getFields(PacketPlayInUseEntity, int.class).get(0);
|
||||
PacketPlayInUseEntity_ACTION = getFields(PacketPlayInUseEntity, EnumEntityUseAction).get(0);
|
||||
}
|
||||
if (minorVersion >= 9) {
|
||||
PacketPlayOutSpawnEntityLiving_UUID = getFields(PacketPlayOutSpawnEntityLiving, UUID.class).get(0);
|
||||
PacketPlayOutSpawnEntityLiving_X = getFields(PacketPlayOutSpawnEntityLiving, double.class).get(0);
|
||||
PacketPlayOutSpawnEntityLiving_Y = getFields(PacketPlayOutSpawnEntityLiving, double.class).get(1);
|
||||
PacketPlayOutSpawnEntityLiving_Z = getFields(PacketPlayOutSpawnEntityLiving, double.class).get(2);
|
||||
PacketPlayOutEntityTeleport_X = getFields(PacketPlayOutEntityTeleport, double.class).get(0);
|
||||
PacketPlayOutEntityTeleport_Y = getFields(PacketPlayOutEntityTeleport, double.class).get(1);
|
||||
PacketPlayOutEntityTeleport_Z = getFields(PacketPlayOutEntityTeleport, double.class).get(2);
|
||||
} else {
|
||||
PacketPlayOutSpawnEntityLiving_X = getFields(PacketPlayOutSpawnEntityLiving, int.class).get(2);
|
||||
PacketPlayOutSpawnEntityLiving_Y = getFields(PacketPlayOutSpawnEntityLiving, int.class).get(3);
|
||||
PacketPlayOutSpawnEntityLiving_Z = getFields(PacketPlayOutSpawnEntityLiving, int.class).get(4);
|
||||
PacketPlayOutEntityTeleport_X = getFields(PacketPlayOutEntityTeleport, int.class).get(1);
|
||||
PacketPlayOutEntityTeleport_Y = getFields(PacketPlayOutEntityTeleport, int.class).get(2);
|
||||
PacketPlayOutEntityTeleport_Z = getFields(PacketPlayOutEntityTeleport, int.class).get(3);
|
||||
}
|
||||
if (minorVersion <= 14) {
|
||||
PacketPlayOutSpawnEntityLiving_DATAWATCHER = getFields(PacketPlayOutSpawnEntityLiving, DataWatcher).get(0);
|
||||
}
|
||||
}
|
||||
|
||||
private void initializeHeaderFooterPacket() throws ReflectiveOperationException {
|
||||
protected void playerInfo() throws ReflectiveOperationException {
|
||||
if (minorVersion < 8) return;
|
||||
Class<?> PacketPlayOutPlayerListHeaderFooter = getNMSClass("net.minecraft.network.protocol.game.PacketPlayOutPlayerListHeaderFooter", "PacketPlayOutPlayerListHeaderFooter");
|
||||
PacketPlayOutPlayerListHeaderFooter_HEADER = getFields(PacketPlayOutPlayerListHeaderFooter, IChatBaseComponent).get(0);
|
||||
PacketPlayOutPlayerListHeaderFooter_FOOTER = getFields(PacketPlayOutPlayerListHeaderFooter, IChatBaseComponent).get(1);
|
||||
if (minorVersion >= 17 || serverVersion.getMinorVersion() >= 17) {
|
||||
newPacketPlayOutPlayerListHeaderFooter = PacketPlayOutPlayerListHeaderFooter.getConstructor(IChatBaseComponent, IChatBaseComponent);
|
||||
} else {
|
||||
newPacketPlayOutPlayerListHeaderFooter = PacketPlayOutPlayerListHeaderFooter.getConstructor();
|
||||
}
|
||||
}
|
||||
|
||||
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");
|
||||
Class<?> PlayerInfoData = getNMSClass("net.minecraft.network.protocol.game.PacketPlayOutPlayerInfo$PlayerInfoData", "PacketPlayOutPlayerInfo$PlayerInfoData", "PlayerInfoData");
|
||||
Class<?> EnumGamemode = getNMSClass("net.minecraft.world.level.EnumGamemode", "EnumGamemode", "WorldSettings$EnumGamemode");
|
||||
newPacketPlayOutPlayerInfo = PacketPlayOutPlayerInfo.getConstructor(EnumPlayerInfoAction, Array.newInstance(EntityPlayer, 0).getClass());
|
||||
newPlayerInfoData = PlayerInfoData.getConstructors()[0];
|
||||
PacketPlayOutPlayerInfo_ACTION = getFields(PacketPlayOutPlayerInfo, EnumPlayerInfoAction).get(0);
|
||||
@@ -431,14 +284,115 @@ public final class NMSStorage {
|
||||
EnumGamemode_values = getEnumValues(EnumGamemode);
|
||||
}
|
||||
|
||||
private void initializeScoreboardPackets() throws ReflectiveOperationException {
|
||||
protected void spawnEntityLiving() throws ReflectiveOperationException {
|
||||
if (minorVersion >= 17 || serverVersion.getMinorVersion() >= 17) {
|
||||
newPacketPlayOutSpawnEntityLiving = PacketPlayOutSpawnEntityLiving.getConstructor(EntityLiving);
|
||||
} else {
|
||||
newPacketPlayOutSpawnEntityLiving = PacketPlayOutSpawnEntityLiving.getConstructor();
|
||||
}
|
||||
PacketPlayOutSpawnEntityLiving_ENTITYID = getFields(PacketPlayOutSpawnEntityLiving, int.class).get(0);
|
||||
PacketPlayOutSpawnEntityLiving_YAW = getFields(PacketPlayOutSpawnEntityLiving, byte.class).get(0);
|
||||
PacketPlayOutSpawnEntityLiving_PITCH = getFields(PacketPlayOutSpawnEntityLiving, byte.class).get(0);
|
||||
if (minorVersion >= 9) {
|
||||
PacketPlayOutSpawnEntityLiving_UUID = getFields(PacketPlayOutSpawnEntityLiving, UUID.class).get(0);
|
||||
if (minorVersion >= 19) {
|
||||
PacketPlayOutSpawnEntityLiving_X = getFields(PacketPlayOutSpawnEntityLiving, double.class).get(2);
|
||||
PacketPlayOutSpawnEntityLiving_Y = getFields(PacketPlayOutSpawnEntityLiving, double.class).get(3);
|
||||
PacketPlayOutSpawnEntityLiving_Z = getFields(PacketPlayOutSpawnEntityLiving, double.class).get(4);
|
||||
} else {
|
||||
PacketPlayOutSpawnEntityLiving_X = getFields(PacketPlayOutSpawnEntityLiving, double.class).get(0);
|
||||
PacketPlayOutSpawnEntityLiving_Y = getFields(PacketPlayOutSpawnEntityLiving, double.class).get(1);
|
||||
PacketPlayOutSpawnEntityLiving_Z = getFields(PacketPlayOutSpawnEntityLiving, double.class).get(2);
|
||||
}
|
||||
} else {
|
||||
PacketPlayOutSpawnEntityLiving_X = getFields(PacketPlayOutSpawnEntityLiving, int.class).get(2);
|
||||
PacketPlayOutSpawnEntityLiving_Y = getFields(PacketPlayOutSpawnEntityLiving, int.class).get(3);
|
||||
PacketPlayOutSpawnEntityLiving_Z = getFields(PacketPlayOutSpawnEntityLiving, int.class).get(4);
|
||||
}
|
||||
if (minorVersion < 19) {
|
||||
PacketPlayOutSpawnEntityLiving_ENTITYTYPE = getFields(PacketPlayOutSpawnEntityLiving, int.class).get(1);
|
||||
}
|
||||
if (minorVersion <= 14) {
|
||||
PacketPlayOutSpawnEntityLiving_DATAWATCHER = getFields(PacketPlayOutSpawnEntityLiving, DataWatcher).get(0);
|
||||
}
|
||||
}
|
||||
|
||||
protected void entityTeleport() throws ReflectiveOperationException {
|
||||
PacketPlayOutEntityTeleport_ENTITYID = getFields(PacketPlayOutEntityTeleport, int.class).get(0);
|
||||
PacketPlayOutEntityTeleport_YAW = getFields(PacketPlayOutEntityTeleport, byte.class).get(0);
|
||||
PacketPlayOutEntityTeleport_PITCH = getFields(PacketPlayOutEntityTeleport, byte.class).get(1);
|
||||
if (minorVersion >= 17 || serverVersion.getMinorVersion() >= 17) {
|
||||
newPacketPlayOutEntityTeleport = PacketPlayOutEntityTeleport.getConstructor(Entity);
|
||||
} else {
|
||||
newPacketPlayOutEntityTeleport = PacketPlayOutEntityTeleport.getConstructor();
|
||||
}
|
||||
if (minorVersion >= 9) {
|
||||
PacketPlayOutEntityTeleport_X = getFields(PacketPlayOutEntityTeleport, double.class).get(0);
|
||||
PacketPlayOutEntityTeleport_Y = getFields(PacketPlayOutEntityTeleport, double.class).get(1);
|
||||
PacketPlayOutEntityTeleport_Z = getFields(PacketPlayOutEntityTeleport, double.class).get(2);
|
||||
} else {
|
||||
PacketPlayOutEntityTeleport_X = getFields(PacketPlayOutEntityTeleport, int.class).get(1);
|
||||
PacketPlayOutEntityTeleport_Y = getFields(PacketPlayOutEntityTeleport, int.class).get(2);
|
||||
PacketPlayOutEntityTeleport_Z = getFields(PacketPlayOutEntityTeleport, int.class).get(3);
|
||||
}
|
||||
}
|
||||
|
||||
protected void playerListHeaderFooter() throws ReflectiveOperationException {
|
||||
if (minorVersion < 8) return;
|
||||
PacketPlayOutPlayerListHeaderFooter_HEADER = getFields(PacketPlayOutPlayerListHeaderFooter, IChatBaseComponent).get(0);
|
||||
PacketPlayOutPlayerListHeaderFooter_FOOTER = getFields(PacketPlayOutPlayerListHeaderFooter, IChatBaseComponent).get(1);
|
||||
if (minorVersion >= 17 || serverVersion.getMinorVersion() >= 17) {
|
||||
newPacketPlayOutPlayerListHeaderFooter = PacketPlayOutPlayerListHeaderFooter.getConstructor(IChatBaseComponent, IChatBaseComponent);
|
||||
} else {
|
||||
newPacketPlayOutPlayerListHeaderFooter = PacketPlayOutPlayerListHeaderFooter.getConstructor();
|
||||
}
|
||||
}
|
||||
|
||||
protected void otherEntity() throws ReflectiveOperationException {
|
||||
PacketPlayOutEntity_ENTITYID = getFields(PacketPlayOutEntity, int.class).get(0);
|
||||
PacketPlayOutEntityDestroy_ENTITIES = setAccessible(PacketPlayOutEntityDestroy.getDeclaredFields()[0]);
|
||||
newPacketPlayOutEntityMetadata = PacketPlayOutEntityMetadata.getConstructor(int.class, DataWatcher, boolean.class);
|
||||
PacketPlayOutEntityMetadata_LIST = getFields(PacketPlayOutEntityMetadata, List.class).get(0);
|
||||
PacketPlayOutNamedEntitySpawn_ENTITYID = getFields(PacketPlayOutNamedEntitySpawn, int.class).get(0);
|
||||
if (minorVersion >= 7) {
|
||||
PacketPlayInUseEntity_ENTITY = getFields(PacketPlayInUseEntity, int.class).get(0);
|
||||
PacketPlayInUseEntity_ACTION = getFields(PacketPlayInUseEntity, EnumEntityUseAction).get(0);
|
||||
}
|
||||
try {
|
||||
newPacketPlayOutEntityDestroy = PacketPlayOutEntityDestroy.getConstructor(int[].class);
|
||||
} catch (NoSuchMethodException e) {
|
||||
//1.17.0
|
||||
newPacketPlayOutEntityDestroy = PacketPlayOutEntityDestroy.getConstructor(int.class);
|
||||
}
|
||||
}
|
||||
|
||||
protected void dataWatcher() throws ReflectiveOperationException {
|
||||
newDataWatcher = DataWatcher.getConstructors()[0];
|
||||
DataWatcherItem_VALUE = getFields(DataWatcherItem, Object.class).get(0);
|
||||
if (minorVersion >= 9) {
|
||||
newDataWatcherObject = DataWatcherObject.getConstructor(int.class, DataWatcherSerializer);
|
||||
DataWatcherItem_TYPE = getFields(DataWatcherItem, DataWatcherObject).get(0);
|
||||
DataWatcherObject_SLOT = getFields(DataWatcherObject, int.class).get(0);
|
||||
DataWatcherObject_SERIALIZER = getFields(DataWatcherObject, DataWatcherSerializer).get(0);
|
||||
} else {
|
||||
DataWatcherItem_TYPE = getFields(DataWatcherItem, int.class).get(1);
|
||||
}
|
||||
}
|
||||
|
||||
protected void scoreboard() throws ReflectiveOperationException {
|
||||
newScoreboardObjective = ScoreboardObjective.getConstructors()[0];
|
||||
newScoreboard = Scoreboard.getConstructor();
|
||||
emptyScoreboard = newScoreboard.newInstance();
|
||||
newScoreboardScore = ScoreboardScore.getConstructor(Scoreboard, ScoreboardObjective, String.class);
|
||||
newPacketPlayOutScoreboardDisplayObjective = PacketPlayOutScoreboardDisplayObjective.getConstructor(int.class, ScoreboardObjective);
|
||||
PacketPlayOutScoreboardDisplayObjective_POSITION = getFields(PacketPlayOutScoreboardDisplayObjective, int.class).get(0);
|
||||
PacketPlayOutScoreboardDisplayObjective_OBJECTIVENAME = getFields(PacketPlayOutScoreboardDisplayObjective, String.class).get(0);
|
||||
PacketPlayOutScoreboardObjective_OBJECTIVENAME = getFields(PacketPlayOutScoreboardObjective, String.class).get(0);
|
||||
IScoreboardCriteria_self = getFields(IScoreboardCriteria, IScoreboardCriteria).get(0);
|
||||
List<Field> list = getFields(PacketPlayOutScoreboardObjective, int.class);
|
||||
PacketPlayOutScoreboardObjective_METHOD = list.get(list.size()-1);
|
||||
Class<?> EnumScoreboardAction = null;
|
||||
if (minorVersion >= 8) {
|
||||
EnumScoreboardHealthDisplay = getNMSClass("net.minecraft.world.scores.criteria.IScoreboardCriteria$EnumScoreboardHealthDisplay", "IScoreboardCriteria$EnumScoreboardHealthDisplay", "EnumScoreboardHealthDisplay");
|
||||
EnumScoreboardHealthDisplay_values = getEnumValues(EnumScoreboardHealthDisplay);
|
||||
EnumScoreboardAction = getNMSClass("net.minecraft.server.ScoreboardServer$Action", "ScoreboardServer$Action", "PacketPlayOutScoreboardScore$EnumScoreboardAction", "EnumScoreboardAction");
|
||||
EnumScoreboardAction_values = getEnumValues(EnumScoreboardAction);
|
||||
PacketPlayOutScoreboardObjective_RENDERTYPE = getFields(PacketPlayOutScoreboardObjective, EnumScoreboardHealthDisplay).get(0);
|
||||
}
|
||||
@@ -458,35 +412,23 @@ public final class NMSStorage {
|
||||
}
|
||||
}
|
||||
|
||||
private void initializeTeamPackets() throws ReflectiveOperationException {
|
||||
PacketPlayOutScoreboardTeam = getNMSClass("net.minecraft.network.protocol.game.PacketPlayOutScoreboardTeam", "PacketPlayOutScoreboardTeam", "Packet209SetScoreboardTeam");
|
||||
Class<?> ScoreboardTeam = getNMSClass("net.minecraft.world.scores.ScoreboardTeam", "ScoreboardTeam");
|
||||
protected void scoreboardTeam() throws ReflectiveOperationException {
|
||||
newScoreboardTeam = ScoreboardTeam.getConstructor(Scoreboard, String.class);
|
||||
PacketPlayOutScoreboardTeam_NAME = getFields(PacketPlayOutScoreboardTeam, String.class).get(0);
|
||||
PacketPlayOutScoreboardTeam_ACTION = getInstanceFields(PacketPlayOutScoreboardTeam, int.class).get(0);
|
||||
PacketPlayOutScoreboardTeam_PLAYERS = getFields(PacketPlayOutScoreboardTeam, Collection.class).get(0);
|
||||
ScoreboardTeam_getPlayerNameSet = getMethods(ScoreboardTeam, Collection.class).get(0);
|
||||
ScoreboardTeam_setAllowFriendlyFire = getMethod(ScoreboardTeam, new String[]{"setAllowFriendlyFire", "a", "func_96660_a"}, boolean.class);
|
||||
ScoreboardTeam_setCanSeeFriendlyInvisibles = getMethod(ScoreboardTeam, new String[]{"setCanSeeFriendlyInvisibles", "b", "func_98300_b"}, boolean.class);
|
||||
if (minorVersion >= 8) {
|
||||
Class<?> EnumNameTagVisibility = getNMSClass("net.minecraft.world.scores.ScoreboardTeamBase$EnumNameTagVisibility", "ScoreboardTeamBase$EnumNameTagVisibility", "EnumNameTagVisibility");
|
||||
EnumNameTagVisibility_values = getEnumValues(EnumNameTagVisibility);
|
||||
ScoreboardTeam_setNameTagVisibility = getMethod(ScoreboardTeam, new String[]{"setNameTagVisibility", "a", "method_1149"}, EnumNameTagVisibility);
|
||||
}
|
||||
if (minorVersion >= 9) {
|
||||
Class<?> EnumTeamPush = getNMSClass("net.minecraft.world.scores.ScoreboardTeamBase$EnumTeamPush", "ScoreboardTeamBase$EnumTeamPush");
|
||||
EnumTeamPush_values = getEnumValues(EnumTeamPush);
|
||||
ScoreboardTeam_setCollisionRule = getMethods(ScoreboardTeam, void.class, EnumTeamPush).get(0);
|
||||
}
|
||||
if (minorVersion >= 13) {
|
||||
ScoreboardTeam_setPrefix = getMethod(ScoreboardTeam, new String[]{"setPrefix", "method_1138", "b"}, IChatBaseComponent);
|
||||
ScoreboardTeam_setSuffix = getMethod(ScoreboardTeam, new String[]{"setSuffix", "method_1139", "c"}, IChatBaseComponent);
|
||||
ScoreboardTeam_setColor = getMethods(ScoreboardTeam, void.class, EnumChatFormat).get(0);
|
||||
} else {
|
||||
ScoreboardTeam_setPrefix = getMethod(ScoreboardTeam, new String[]{"setPrefix", "func_96666_b"}, String.class);
|
||||
ScoreboardTeam_setSuffix = getMethod(ScoreboardTeam, new String[]{"setSuffix", "func_96662_c"}, String.class);
|
||||
}
|
||||
if (minorVersion >= 17 || serverVersion.getMinorVersion() >= 17) {
|
||||
Class<?> PacketPlayOutScoreboardTeam_PlayerAction = Class.forName("net.minecraft.network.protocol.game.PacketPlayOutScoreboardTeam$a");
|
||||
if (minorVersion >= 17) {
|
||||
PacketPlayOutScoreboardTeam_of = getMethods(PacketPlayOutScoreboardTeam, PacketPlayOutScoreboardTeam, ScoreboardTeam).get(0);
|
||||
PacketPlayOutScoreboardTeam_ofBoolean = getMethods(PacketPlayOutScoreboardTeam, PacketPlayOutScoreboardTeam, ScoreboardTeam, boolean.class).get(0);
|
||||
PacketPlayOutScoreboardTeam_ofString = getMethods(PacketPlayOutScoreboardTeam, PacketPlayOutScoreboardTeam, ScoreboardTeam, String.class, PacketPlayOutScoreboardTeam_PlayerAction).get(0);
|
||||
@@ -496,53 +438,9 @@ public final class NMSStorage {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns class with given potential names in same order
|
||||
*
|
||||
* @param names
|
||||
* possible class names
|
||||
* @return class for specified names
|
||||
* @throws ClassNotFoundException
|
||||
* if class does not exist
|
||||
*/
|
||||
private Class<?> getNMSClass(String fullPath_1_17, String... names) throws ClassNotFoundException {
|
||||
if (minorVersion >= 17) {
|
||||
return Class.forName(fullPath_1_17);
|
||||
}
|
||||
for (String name : names) {
|
||||
try {
|
||||
return getLegacyClass(name);
|
||||
} catch (ClassNotFoundException e) {
|
||||
//not the first class name in array
|
||||
}
|
||||
}
|
||||
throw new ClassNotFoundException("No class found with possible names {modern = " + fullPath_1_17 + ", legacy = " + Arrays.toString(names) + "}");
|
||||
}
|
||||
public abstract void loadClasses() throws ClassNotFoundException;
|
||||
|
||||
/**
|
||||
* Returns class from given name
|
||||
*
|
||||
* @param name
|
||||
* class name
|
||||
* @return class from given name
|
||||
* @throws ClassNotFoundException
|
||||
* if class was not found
|
||||
*/
|
||||
private Class<?> getLegacyClass(String name) throws ClassNotFoundException {
|
||||
try {
|
||||
return Class.forName("net.minecraft.server." + serverPackage + "." + name);
|
||||
} 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 | NullPointerException e1) {
|
||||
//maybe fabric?
|
||||
return Class.forName(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
public abstract void loadNamedFieldsAndMethods() throws ReflectiveOperationException;
|
||||
|
||||
/**
|
||||
* Returns method with specified possible names and parameters. Throws exception if no such method was found
|
||||
@@ -557,7 +455,7 @@ public final class NMSStorage {
|
||||
* @throws NoSuchMethodException
|
||||
* if no such method exists
|
||||
*/
|
||||
private Method getMethod(Class<?> clazz, String[] names, Class<?>... parameterTypes) throws NoSuchMethodException {
|
||||
protected Method getMethod(Class<?> clazz, String[] names, Class<?>... parameterTypes) throws NoSuchMethodException {
|
||||
for (String name : names) {
|
||||
try {
|
||||
return getMethod(clazz, name, parameterTypes);
|
||||
@@ -582,7 +480,7 @@ public final class NMSStorage {
|
||||
Arrays.toString(parameterTypes) + " in class " + clazz.getName() + ". Methods with matching parameters: " + list);
|
||||
}
|
||||
|
||||
private Method getMethod(Class<?> clazz, String name, Class<?>... parameterTypes) throws NoSuchMethodException {
|
||||
protected Method getMethod(Class<?> clazz, String name, Class<?>... parameterTypes) throws NoSuchMethodException {
|
||||
List<Method> list = new ArrayList<>();
|
||||
for (Method m : clazz.getMethods()) {
|
||||
if (!m.getName().equals(name) || m.getParameterCount() != parameterTypes.length) continue;
|
||||
@@ -600,7 +498,7 @@ public final class NMSStorage {
|
||||
throw new NoSuchMethodException("No method found with name " + name + " in class " + clazz.getName() + " with parameters " + Arrays.toString(parameterTypes));
|
||||
}
|
||||
|
||||
private List<Method> getMethods(Class<?> clazz, Class<?> returnType, Class<?>... parameterTypes){
|
||||
protected List<Method> getMethods(Class<?> clazz, Class<?> returnType, Class<?>... parameterTypes){
|
||||
List<Method> list = new ArrayList<>();
|
||||
for (Method m : clazz.getDeclaredMethods()) {
|
||||
if (m.getReturnType() != returnType || m.getParameterCount() != parameterTypes.length || !Modifier.isPublic(m.getModifiers())) continue;
|
||||
@@ -626,7 +524,7 @@ public final class NMSStorage {
|
||||
* field type to check for
|
||||
* @return list of all fields with specified class type
|
||||
*/
|
||||
private List<Field> getFields(Class<?> clazz, Class<?> type){
|
||||
protected List<Field> getFields(Class<?> clazz, Class<?> type){
|
||||
if (clazz == null) throw new IllegalArgumentException("Source class cannot be null");
|
||||
List<Field> list = new ArrayList<>();
|
||||
for (Field field : clazz.getDeclaredFields()) {
|
||||
@@ -637,6 +535,26 @@ public final class NMSStorage {
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all instance fields of class with defined class type
|
||||
*
|
||||
* @param clazz
|
||||
* class to check fields of
|
||||
* @param type
|
||||
* field type to check for
|
||||
* @return list of all fields with specified class type
|
||||
*/
|
||||
public List<Field> getInstanceFields(Class<?> clazz, Class<?> type){
|
||||
if (clazz == null) throw new IllegalArgumentException("Source class cannot be null");
|
||||
List<Field> list = new ArrayList<>();
|
||||
for (Field field : clazz.getDeclaredFields()) {
|
||||
if (field.getType() == type && !Modifier.isStatic(field.getModifiers())) {
|
||||
list.add(setAccessible(field));
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns field with specified name and makes it accessible
|
||||
*
|
||||
@@ -648,7 +566,7 @@ public final class NMSStorage {
|
||||
* @throws NoSuchFieldException
|
||||
* if field was not found
|
||||
*/
|
||||
private Field getField(Class<?> clazz, String name) throws NoSuchFieldException {
|
||||
protected Field getField(Class<?> clazz, String name) throws NoSuchFieldException {
|
||||
for (Field f : clazz.getDeclaredFields()) {
|
||||
if (f.getName().equals(name) || (f.getName().split("_").length == 3 && f.getName().split("_")[2].equals(name))) {
|
||||
return setAccessible(f);
|
||||
@@ -657,7 +575,7 @@ public final class NMSStorage {
|
||||
throw new NoSuchFieldException("Field \"" + name + "\" was not found in class " + clazz.getName());
|
||||
}
|
||||
|
||||
private Field getField(Class<?> clazz, String... potentialNames) throws NoSuchFieldException {
|
||||
protected Field getField(Class<?> clazz, String... potentialNames) throws NoSuchFieldException {
|
||||
for (String name : potentialNames) {
|
||||
try {
|
||||
return getField(clazz, name);
|
||||
@@ -668,14 +586,13 @@ public final class NMSStorage {
|
||||
throw new NoSuchFieldException("No field found in class " + clazz.getName() + " with potential names " + Arrays.toString(potentialNames));
|
||||
}
|
||||
|
||||
private Enum[] getEnumValues(Class<?> enumClass) {
|
||||
protected Enum[] getEnumValues(Class<?> enumClass) {
|
||||
if (enumClass == null) throw new IllegalArgumentException("Class cannot be null");
|
||||
if (!enumClass.isEnum()) throw new IllegalArgumentException(enumClass.getName() + " is not an enum class");
|
||||
try {
|
||||
return (Enum[]) enumClass.getMethod("values").invoke(null);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
//this should never happen
|
||||
TAB.getInstance().getErrorManager().criticalError("Failed to load enum constants of " + enumClass.getName(), e);
|
||||
return new Enum[0];
|
||||
}
|
||||
}
|
||||
@@ -696,4 +613,26 @@ public final class NMSStorage {
|
||||
o.setAccessible(true);
|
||||
return o;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets values of all static fields in a class
|
||||
*
|
||||
* @param clazz
|
||||
* class to return field values from
|
||||
* @return map of values
|
||||
*/
|
||||
public Map<String, Object> getStaticFields(Class<?> clazz){
|
||||
Map<String, Object> fields = new HashMap<>();
|
||||
for (Field field : clazz.getDeclaredFields()) {
|
||||
if (Modifier.isStatic(field.getModifiers())) {
|
||||
setAccessible(field);
|
||||
try {
|
||||
fields.put(field.getName(), field.get(null));
|
||||
} catch (IllegalAccessException e) {
|
||||
//this will never happen
|
||||
}
|
||||
}
|
||||
}
|
||||
return fields;
|
||||
}
|
||||
}
|
||||
+28
-21
@@ -1,14 +1,14 @@
|
||||
package me.neznamy.tab.platforms.bukkit.nms.datawatcher;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import me.neznamy.tab.api.ProtocolVersion;
|
||||
import me.neznamy.tab.api.TabAPI;
|
||||
import me.neznamy.tab.api.chat.IChatBaseComponent;
|
||||
import me.neznamy.tab.api.util.Preconditions;
|
||||
import me.neznamy.tab.platforms.bukkit.BukkitPacketBuilder;
|
||||
import me.neznamy.tab.platforms.bukkit.nms.NMSStorage;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* A class to help to assign DataWatcher items as positions often change per-version
|
||||
*/
|
||||
@@ -30,7 +30,6 @@ public class DataWatcherHelper {
|
||||
* data to write to
|
||||
*/
|
||||
public DataWatcherHelper(DataWatcher data) {
|
||||
Preconditions.checkNotNull(data, "dataWatcher");
|
||||
this.data = data;
|
||||
this.registry = NMSStorage.getInstance().getDataWatcherRegistry();
|
||||
}
|
||||
@@ -41,16 +40,16 @@ public class DataWatcherHelper {
|
||||
* @return armor stand flags position based on server version
|
||||
*/
|
||||
private int getArmorStandFlagsPosition() {
|
||||
if (TAB.getInstance().getServerVersion().getMinorVersion() >= 17) {
|
||||
//1.17.x, 1.18.x
|
||||
if (TabAPI.getInstance().getServerVersion().getMinorVersion() >= 17) {
|
||||
//1.17.x, 1.18.x, 1.19.x
|
||||
return 15;
|
||||
} else if (TAB.getInstance().getServerVersion().getMinorVersion() >= 15) {
|
||||
} else if (TabAPI.getInstance().getServerVersion().getMinorVersion() >= 15) {
|
||||
//1.15.x, 1.16.x
|
||||
return 14;
|
||||
} else if (TAB.getInstance().getServerVersion().getMinorVersion() >= 14) {
|
||||
} else if (TabAPI.getInstance().getServerVersion().getMinorVersion() >= 14) {
|
||||
//1.14.x
|
||||
return 13;
|
||||
} else if (TAB.getInstance().getServerVersion().getMinorVersion() >= 10) {
|
||||
} else if (TabAPI.getInstance().getServerVersion().getMinorVersion() >= 10) {
|
||||
//1.10.x - 1.13.x
|
||||
return 11;
|
||||
} else {
|
||||
@@ -78,26 +77,23 @@ public class DataWatcherHelper {
|
||||
* client version
|
||||
*/
|
||||
public void setCustomName(String customName, ProtocolVersion clientVersion) {
|
||||
Preconditions.checkNotNull(customName, "customName");
|
||||
Preconditions.checkNotNull(clientVersion, "clientVersion");
|
||||
if (TAB.getInstance().getServerVersion().getMinorVersion() >= 13) {
|
||||
if (TabAPI.getInstance().getServerVersion().getMinorVersion() >= 13) {
|
||||
try {
|
||||
data.setValue(new DataWatcherObject(2, registry.getOptionalComponent()), Optional.ofNullable(((BukkitPacketBuilder)TAB.getInstance().getPlatform().getPacketBuilder()).toNMSComponent(IChatBaseComponent.optimizedComponent(customName), clientVersion)));
|
||||
} catch (ReflectiveOperationException e) {
|
||||
TAB.getInstance().getErrorManager().printError("Failed to create component", e);
|
||||
}
|
||||
} else if (TAB.getInstance().getServerVersion().getMinorVersion() >= 8){
|
||||
} else if (TabAPI.getInstance().getServerVersion().getMinorVersion() >= 8){
|
||||
data.setValue(new DataWatcherObject(2, registry.getString()), customName);
|
||||
} else {
|
||||
//name length is limited to 64 characters on <1.8
|
||||
String cutName = (customName.length() > 64 ? customName.substring(0, 64) : customName);
|
||||
if (TAB.getInstance().getServerVersion().getMinorVersion() >= 6){
|
||||
data.setValue(new DataWatcherObject(10, registry.getString()), cutName);
|
||||
if (TabAPI.getInstance().getServerVersion().getMinorVersion() >= 6){
|
||||
data.setValue(new DataWatcherObject(10, null), cutName);
|
||||
} else {
|
||||
data.setValue(new DataWatcherObject(5, registry.getString()), cutName);
|
||||
data.setValue(new DataWatcherObject(5, null), cutName);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -107,10 +103,10 @@ public class DataWatcherHelper {
|
||||
* if visible or not
|
||||
*/
|
||||
public void setCustomNameVisible(boolean visible) {
|
||||
if (TAB.getInstance().getServerVersion().getMinorVersion() >= 9) {
|
||||
if (TabAPI.getInstance().getServerVersion().getMinorVersion() >= 9) {
|
||||
data.setValue(new DataWatcherObject(3, registry.getBoolean()), visible);
|
||||
} else {
|
||||
data.setValue(new DataWatcherObject(3, registry.getByte()), (byte)(visible?1:0));
|
||||
data.setValue(new DataWatcherObject(3, null), (byte)(visible?1:0));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,10 +117,10 @@ public class DataWatcherHelper {
|
||||
* health of entity
|
||||
*/
|
||||
public void setHealth(float health) {
|
||||
if (TAB.getInstance().getServerVersion().getMinorVersion() >= 6) {
|
||||
if (TabAPI.getInstance().getServerVersion().getMinorVersion() >= 6) {
|
||||
data.setValue(new DataWatcherObject(6, registry.getFloat()), health);
|
||||
} else {
|
||||
data.setValue(new DataWatcherObject(16, registry.getInteger()), (int)health);
|
||||
data.setValue(new DataWatcherObject(16, null), (int)health);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,4 +133,15 @@ public class DataWatcherHelper {
|
||||
public void setArmorStandFlags(byte flags) {
|
||||
data.setValue(new DataWatcherObject(armorStandFlagsPosition, registry.getByte()), flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes wither invulnerable time
|
||||
* @param time
|
||||
* Time, apparently
|
||||
*/
|
||||
public void setWitherInvulnerableTime(int time) {
|
||||
if (TAB.getInstance().getServerVersion().getMinorVersion() > 8)
|
||||
throw new UnsupportedOperationException("Not supported on 1.9+");
|
||||
data.setValue(new DataWatcherObject(20, null), time);
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -1,8 +1,8 @@
|
||||
package me.neznamy.tab.platforms.bukkit.nms.datawatcher;
|
||||
|
||||
import me.neznamy.tab.api.TabAPI;
|
||||
import me.neznamy.tab.api.util.Preconditions;
|
||||
import me.neznamy.tab.platforms.bukkit.nms.NMSStorage;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
|
||||
public class DataWatcherItem {
|
||||
|
||||
@@ -38,7 +38,7 @@ public class DataWatcherItem {
|
||||
*/
|
||||
public static DataWatcherItem fromNMS(Object nmsItem) throws ReflectiveOperationException {
|
||||
NMSStorage nms = NMSStorage.getInstance();
|
||||
if (TAB.getInstance().getServerVersion().getMinorVersion() >= 9) {
|
||||
if (TabAPI.getInstance().getServerVersion().getMinorVersion() >= 9) {
|
||||
Object nmsObject = nms.DataWatcherItem_TYPE.get(nmsItem);
|
||||
return new DataWatcherItem(new DataWatcherObject(nms.DataWatcherObject_SLOT.getInt(nmsObject), nms.DataWatcherObject_SERIALIZER.get(nmsObject)), nms.DataWatcherItem_VALUE.get(nmsItem));
|
||||
} else {
|
||||
|
||||
+19
-144
@@ -1,121 +1,52 @@
|
||||
package me.neznamy.tab.platforms.bukkit.nms.datawatcher;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import me.neznamy.tab.platforms.bukkit.nms.NMSStorage;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A class representing the n.m.s.DataWatcherRegistry class to make work with it much easier
|
||||
*/
|
||||
public class DataWatcherRegistry {
|
||||
|
||||
private Object registryByte;
|
||||
private Object registryShort;
|
||||
private Object registryInteger;
|
||||
private Object registryFloat;
|
||||
private Object registryString;
|
||||
private Object registryIChatBaseComponent;
|
||||
private Object registryOptionalIChatBaseComponent;
|
||||
private Object registryOptionalItemStack;
|
||||
private Object registryItemStack;
|
||||
private Object registryOptionalIBlockData;
|
||||
private Object registryBoolean;
|
||||
private Object registryParticleParam;
|
||||
private Object registryVector3f;
|
||||
private Object registryBlockPosition;
|
||||
private Object registryOptionalBlockPosition;
|
||||
private Object registryEnumDirection;
|
||||
private Object registryOptionalUUID;
|
||||
private Object registryNBTTagCompound;
|
||||
private Object registryVillagerData;
|
||||
private Object registryOptionalInt;
|
||||
private Object registryEntityPose;
|
||||
|
||||
/**
|
||||
* Initializes required NMS classes and fields
|
||||
*/
|
||||
public DataWatcherRegistry(NMSStorage nms) {
|
||||
if (nms.getMinorVersion() >= 9) {
|
||||
Map<String, Object> fields = getStaticFields(nms.DataWatcherRegistry, nms);
|
||||
registryByte = fields.get("a");
|
||||
registryInteger = fields.get("b");
|
||||
registryFloat = fields.get("c");
|
||||
registryString = fields.get("d");
|
||||
registryIChatBaseComponent = fields.get("e");
|
||||
if (nms.getMinorVersion() >= 13) {
|
||||
registryOptionalIChatBaseComponent = fields.get("f");
|
||||
registryItemStack = fields.get("g");
|
||||
registryOptionalIBlockData = fields.get("h");
|
||||
registryBoolean = fields.get("i");
|
||||
registryParticleParam = fields.get("j");
|
||||
registryVector3f = fields.get("k");
|
||||
registryBlockPosition = fields.get("l");
|
||||
registryOptionalBlockPosition = fields.get("m");
|
||||
registryEnumDirection = fields.get("n");
|
||||
registryOptionalUUID = fields.get("o");
|
||||
registryNBTTagCompound = fields.get("p");
|
||||
if (nms.getMinorVersion() >= 15) {
|
||||
registryVillagerData = fields.get("q");
|
||||
registryOptionalInt = fields.get("r");
|
||||
registryEntityPose = fields.get("s");
|
||||
Map<String, Object> fields = nms.getStaticFields(nms.DataWatcherRegistry);
|
||||
if (fields.containsKey("a")) {
|
||||
// Bukkit mapping
|
||||
registryByte = fields.get("a");
|
||||
registryFloat = fields.get("c");
|
||||
registryString = fields.get("d");
|
||||
if (nms.getMinorVersion() >= 13) {
|
||||
registryOptionalIChatBaseComponent = fields.get("f");
|
||||
registryBoolean = fields.get("i");
|
||||
} else {
|
||||
registryBoolean = fields.get("h");
|
||||
}
|
||||
} else {
|
||||
registryOptionalIBlockData = fields.get("g");
|
||||
registryBoolean = fields.get("h");
|
||||
registryVector3f = fields.get("i");
|
||||
registryBlockPosition = fields.get("j");
|
||||
registryOptionalBlockPosition = fields.get("k");
|
||||
registryEnumDirection = fields.get("l");
|
||||
registryOptionalUUID = fields.get("m");
|
||||
if (nms.getMinorVersion() >= 12) {
|
||||
registryNBTTagCompound = fields.get("n");
|
||||
}
|
||||
if (nms.getMinorVersion() >= 11) {
|
||||
registryItemStack = fields.get("f");
|
||||
} else {
|
||||
registryOptionalItemStack = fields.get("f");
|
||||
}
|
||||
// Mojang mapping
|
||||
registryByte = fields.get("BYTE");
|
||||
registryFloat = fields.get("FLOAT");
|
||||
registryString = fields.get("STRING");
|
||||
registryOptionalIChatBaseComponent = fields.get("OPTIONAL_COMPONENT");
|
||||
registryBoolean = fields.get("BOOLEAN");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets values of all static fields in a class
|
||||
*
|
||||
* @param clazz
|
||||
* class to return field values from
|
||||
* @return map of values
|
||||
*/
|
||||
private Map<String, Object> getStaticFields(Class<?> clazz, NMSStorage nms){
|
||||
Map<String, Object> fields = new HashMap<>();
|
||||
for (Field field : clazz.getDeclaredFields()) {
|
||||
if (Modifier.isStatic(field.getModifiers())) {
|
||||
nms.setAccessible(field);
|
||||
try {
|
||||
fields.put(field.getName(), field.get(null));
|
||||
} catch (IllegalAccessException e) {
|
||||
//this will never happen
|
||||
}
|
||||
}
|
||||
}
|
||||
return fields;
|
||||
}
|
||||
|
||||
public Object getByte() {
|
||||
return registryByte;
|
||||
}
|
||||
|
||||
public Object getShort() {
|
||||
return registryShort;
|
||||
}
|
||||
|
||||
public Object getInteger() {
|
||||
return registryInteger;
|
||||
}
|
||||
|
||||
public Object getFloat() {
|
||||
return registryFloat;
|
||||
}
|
||||
@@ -124,67 +55,11 @@ public class DataWatcherRegistry {
|
||||
return registryString;
|
||||
}
|
||||
|
||||
public Object getComponent() {
|
||||
return registryIChatBaseComponent;
|
||||
}
|
||||
|
||||
public Object getOptionalComponent() {
|
||||
return registryOptionalIChatBaseComponent;
|
||||
}
|
||||
|
||||
public Object getOptionalItemStack() {
|
||||
return registryOptionalItemStack;
|
||||
}
|
||||
|
||||
public Object getItemStack() {
|
||||
return registryItemStack;
|
||||
}
|
||||
|
||||
public Object getOptionalIBlockData() {
|
||||
return registryOptionalIBlockData;
|
||||
}
|
||||
|
||||
public Object getBoolean() {
|
||||
return registryBoolean;
|
||||
}
|
||||
|
||||
public Object getParticleParam() {
|
||||
return registryParticleParam;
|
||||
}
|
||||
|
||||
public Object getVector3f() {
|
||||
return registryVector3f;
|
||||
}
|
||||
|
||||
public Object getBlockPosition() {
|
||||
return registryBlockPosition;
|
||||
}
|
||||
|
||||
public Object getOptionalBlockPosition() {
|
||||
return registryOptionalBlockPosition;
|
||||
}
|
||||
|
||||
public Object getEnumDirection() {
|
||||
return registryEnumDirection;
|
||||
}
|
||||
|
||||
public Object getOptionalUUID() {
|
||||
return registryOptionalUUID;
|
||||
}
|
||||
|
||||
public Object getNBTTagCompound() {
|
||||
return registryNBTTagCompound;
|
||||
}
|
||||
|
||||
public Object getVillagerData() {
|
||||
return registryVillagerData;
|
||||
}
|
||||
|
||||
public Object getOptionalInt() {
|
||||
return registryOptionalInt;
|
||||
}
|
||||
|
||||
public Object getEntityPose() {
|
||||
return registryEntityPose;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
package me.neznamy.tab.platforms.bukkit.permission;
|
||||
|
||||
import me.neznamy.tab.shared.TabConstants;
|
||||
import me.neznamy.tab.api.TabConstants;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import me.neznamy.tab.api.TabPlayer;
|
||||
@@ -30,7 +30,7 @@ public class Vault extends PermissionPlugin {
|
||||
|
||||
@Override
|
||||
public String getPrimaryGroup(TabPlayer p) {
|
||||
if (getName().equals("SuperPerms")) return TabConstants.DEFAULT_GROUP; //Vault's dummy implementation throws exception on every request
|
||||
if (getName().equals("SuperPerms")) return TabConstants.NO_GROUP; //Vault's dummy implementation throws exception on every request
|
||||
return permission.getPrimaryGroup((Player) p.getPlayer());
|
||||
}
|
||||
|
||||
|
||||
@@ -55,7 +55,6 @@ scoreboard-teams:
|
||||
enabled: false
|
||||
use-marker-tag-for-1-8-x-clients: false
|
||||
disable-on-boats: true
|
||||
space-between-lines: 0.22
|
||||
disable-in-worlds:
|
||||
- disabledworld
|
||||
dynamic-lines:
|
||||
@@ -137,7 +136,7 @@ scoreboard:
|
||||
lines:
|
||||
- "%animation:MyAnimation1%"
|
||||
- "&6Online:"
|
||||
- "* &eOnline&7: &f%online%&7/&4%maxplayers%"
|
||||
- "* &eOnline&7: &f%online%"
|
||||
- "* &eCurrent World&7: &f%worldonline%"
|
||||
- "* &eStaff&7: &f%staffonline%"
|
||||
- " "
|
||||
|
||||
+20
-14
@@ -1,8 +1,7 @@
|
||||
package me.neznamy.tab.platforms.bungeecord;
|
||||
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.shared.TabConstants;
|
||||
import me.neznamy.tab.shared.proxy.ProxyPlatform;
|
||||
import me.neznamy.tab.api.TabAPI;
|
||||
import me.neznamy.tab.api.TabConstants;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.event.ChatEvent;
|
||||
import net.md_5.bungee.api.event.PlayerDisconnectEvent;
|
||||
@@ -16,6 +15,12 @@ import net.md_5.bungee.event.EventHandler;
|
||||
*/
|
||||
public class BungeeEventListener implements Listener {
|
||||
|
||||
private final BungeePlatform platform;
|
||||
|
||||
public BungeeEventListener(BungeePlatform platform) {
|
||||
this.platform = platform;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnect event listener to forward the event to all features
|
||||
*
|
||||
@@ -24,9 +29,9 @@ public class BungeeEventListener implements Listener {
|
||||
*/
|
||||
@EventHandler
|
||||
public void onQuit(PlayerDisconnectEvent e){
|
||||
if (TAB.getInstance().isDisabled()) return;
|
||||
TAB.getInstance().getCPUManager().runTask(() ->
|
||||
TAB.getInstance().getFeatureManager().onQuit(TAB.getInstance().getPlayer(e.getPlayer().getUniqueId())));
|
||||
if (TabAPI.getInstance().isPluginDisabled()) return;
|
||||
TabAPI.getInstance().getThreadManager().runTask(() ->
|
||||
TabAPI.getInstance().getFeatureManager().onQuit(TabAPI.getInstance().getPlayer(e.getPlayer().getUniqueId())));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -37,12 +42,12 @@ public class BungeeEventListener implements Listener {
|
||||
*/
|
||||
@EventHandler
|
||||
public void onSwitch(ServerSwitchEvent e){
|
||||
if (TAB.getInstance().isDisabled()) return;
|
||||
TAB.getInstance().getCPUManager().runTask(() -> {
|
||||
if (TAB.getInstance().getPlayer(e.getPlayer().getUniqueId()) == null) {
|
||||
TAB.getInstance().getFeatureManager().onJoin(new BungeeTabPlayer(e.getPlayer()));
|
||||
if (TabAPI.getInstance().isPluginDisabled()) return;
|
||||
TabAPI.getInstance().getThreadManager().runTask(() -> {
|
||||
if (TabAPI.getInstance().getPlayer(e.getPlayer().getUniqueId()) == null) {
|
||||
TabAPI.getInstance().getFeatureManager().onJoin(new BungeeTabPlayer(e.getPlayer()));
|
||||
} else {
|
||||
TAB.getInstance().getFeatureManager().onServerChange(e.getPlayer().getUniqueId(), e.getPlayer().getServer().getInfo().getName());
|
||||
TabAPI.getInstance().getFeatureManager().onServerChange(e.getPlayer().getUniqueId(), e.getPlayer().getServer().getInfo().getName());
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -55,8 +60,9 @@ public class BungeeEventListener implements Listener {
|
||||
*/
|
||||
@EventHandler
|
||||
public void onChat(ChatEvent e) {
|
||||
if (TAB.getInstance().isDisabled()) return;
|
||||
if (e.getMessage().startsWith("/") && TAB.getInstance().getFeatureManager().onCommand(TAB.getInstance().getPlayer(((ProxiedPlayer)e.getSender()).getUniqueId()), e.getMessage())) e.setCancelled(true);
|
||||
if (TabAPI.getInstance().isPluginDisabled()) return;
|
||||
if (e.isCommand() && TabAPI.getInstance().getFeatureManager().onCommand(TabAPI.getInstance().getPlayer(
|
||||
((ProxiedPlayer)e.getSender()).getUniqueId()), e.getMessage())) e.setCancelled(true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -70,7 +76,7 @@ public class BungeeEventListener implements Listener {
|
||||
if (!event.getTag().equals(TabConstants.PLUGIN_MESSAGE_CHANNEL_NAME)) return;
|
||||
if (event.getReceiver() instanceof ProxiedPlayer) {
|
||||
event.setCancelled(true);
|
||||
((ProxyPlatform)TAB.getInstance().getPlatform()).getPluginMessageHandler().onPluginMessage(
|
||||
platform.getPluginMessageHandler().onPluginMessage(
|
||||
((ProxiedPlayer) event.getReceiver()).getUniqueId(), event.getData());
|
||||
}
|
||||
}
|
||||
|
||||
+11
-13
@@ -10,16 +10,10 @@ import me.neznamy.tab.api.protocol.*;
|
||||
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 net.md_5.bungee.protocol.packet.BossBar;
|
||||
import net.md_5.bungee.protocol.packet.Chat;
|
||||
import net.md_5.bungee.protocol.packet.PlayerListHeaderFooter;
|
||||
import net.md_5.bungee.protocol.packet.PlayerListItem;
|
||||
import net.md_5.bungee.protocol.Property;
|
||||
import net.md_5.bungee.protocol.packet.*;
|
||||
import net.md_5.bungee.protocol.packet.PlayerListItem.Item;
|
||||
import net.md_5.bungee.protocol.packet.ScoreboardDisplay;
|
||||
import net.md_5.bungee.protocol.packet.ScoreboardObjective;
|
||||
import net.md_5.bungee.protocol.packet.ScoreboardObjective.HealthDisplay;
|
||||
import net.md_5.bungee.protocol.packet.ScoreboardScore;
|
||||
import net.md_5.bungee.protocol.packet.Team;
|
||||
|
||||
/**
|
||||
* Packet builder for BungeeCord platform
|
||||
@@ -40,7 +34,11 @@ public class BungeePacketBuilder extends PacketBuilder {
|
||||
|
||||
@Override
|
||||
public Object build(PacketPlayOutChat packet, ProtocolVersion clientVersion) {
|
||||
return new Chat(packet.getMessage().toString(clientVersion), (byte) packet.getType().ordinal());
|
||||
if (clientVersion.getMinorVersion() >= 19) {
|
||||
return new SystemChat(packet.getMessage().toString(clientVersion), (byte) packet.getType().ordinal());
|
||||
} else {
|
||||
return new Chat(packet.getMessage().toString(clientVersion), (byte) packet.getType().ordinal());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -55,14 +53,14 @@ public class BungeePacketBuilder extends PacketBuilder {
|
||||
item.setDisplayName(data.getDisplayName().toLegacyText());
|
||||
}
|
||||
} else if (clientVersion.getMinorVersion() < 8) {
|
||||
item.setDisplayName(data.getName()); //avoiding NPE, 1.7 client requires this, 1.8 added a leading boolean
|
||||
item.setDisplayName(String.valueOf(data.getName())); //avoiding NPE, 1.7 client requires this, 1.8 added a leading boolean
|
||||
}
|
||||
if (data.getGameMode() != null) item.setGamemode(data.getGameMode().ordinal()-1);
|
||||
item.setPing(data.getLatency());
|
||||
if (data.getSkin() != null) {
|
||||
item.setProperties(new String[][]{{"textures", data.getSkin().getValue(), data.getSkin().getSignature()}});
|
||||
item.setProperties(new Property[]{new Property("textures", data.getSkin().getValue(), data.getSkin().getSignature())});
|
||||
} else {
|
||||
item.setProperties(new String[0][0]);
|
||||
item.setProperties(new Property[0]);
|
||||
}
|
||||
item.setUsername(data.getName());
|
||||
item.setUuid(data.getUniqueId());
|
||||
@@ -109,7 +107,7 @@ public class BungeePacketBuilder extends PacketBuilder {
|
||||
PlayerListItem item = (PlayerListItem) bungeePacket;
|
||||
List<PlayerInfoData> listData = new ArrayList<>();
|
||||
for (Item i : item.getItems()) {
|
||||
Skin skin = i.getProperties() == null || i.getProperties().length == 0 ? null : new Skin(i.getProperties()[0][1], i.getProperties()[0][2]);
|
||||
Skin skin = i.getProperties() == null || i.getProperties().length == 0 ? null : new Skin(i.getProperties()[0].getValue(), i.getProperties()[0].getSignature());
|
||||
listData.add(new PlayerInfoData(i.getUsername(), i.getUuid(), skin, i.getPing(), EnumGamemode.VALUES[i.getGamemode()+1], IChatBaseComponent.deserialize(i.getDisplayName())));
|
||||
}
|
||||
return new PacketPlayOutPlayerInfo(EnumPlayerInfoAction.valueOf(item.getAction().toString().replace("GAMEMODE", "GAME_MODE")), listData);
|
||||
|
||||
+18
-11
@@ -7,9 +7,8 @@ import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelPromise;
|
||||
import me.neznamy.tab.api.TabFeature;
|
||||
import me.neznamy.tab.api.TabPlayer;
|
||||
import me.neznamy.tab.api.util.Preconditions;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.shared.TabConstants;
|
||||
import me.neznamy.tab.api.TabConstants;
|
||||
import me.neznamy.tab.shared.features.PipelineInjector;
|
||||
import me.neznamy.tab.shared.features.redis.RedisPlayer;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
@@ -22,11 +21,15 @@ import java.util.Collection;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* Pipeline injection to secure proper functionality
|
||||
* of some features by preventing other plugins
|
||||
* from overriding it.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public class BungeePipelineInjector extends PipelineInjector {
|
||||
|
||||
//packets that must be deserialized and BungeeCord does not do it automatically
|
||||
|
||||
/** Packets used by the plugin that must be deserialized and BungeeCord does not do it automatically */
|
||||
private final Class<? extends DefinedPacket>[] extraPacketClasses = new Class[]{Team.class, ScoreboardDisplay.class, ScoreboardObjective.class};
|
||||
private final Supplier<DefinedPacket>[] extraPacketSuppliers = new Supplier[]{Team::new, ScoreboardDisplay::new, ScoreboardObjective::new};
|
||||
|
||||
@@ -47,7 +50,7 @@ public class BungeePipelineInjector extends PipelineInjector {
|
||||
*/
|
||||
public class BungeeChannelDuplexHandler extends ChannelDuplexHandler {
|
||||
|
||||
//injected player
|
||||
/** Injected player */
|
||||
protected final TabPlayer player;
|
||||
|
||||
/**
|
||||
@@ -57,7 +60,6 @@ public class BungeePipelineInjector extends PipelineInjector {
|
||||
* player to inject
|
||||
*/
|
||||
public BungeeChannelDuplexHandler(TabPlayer player) {
|
||||
Preconditions.checkNotNull(player, "player");
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
@@ -70,7 +72,9 @@ public class BungeePipelineInjector extends PipelineInjector {
|
||||
return;
|
||||
case "Team":
|
||||
if (antiOverrideTeams) {
|
||||
long time = System.nanoTime();
|
||||
modifyPlayers((Team) packet);
|
||||
TAB.getInstance().getCPUManager().addTime("NameTags", TabConstants.CpuUsageCategory.ANTI_OVERRIDE, System.nanoTime()-time);
|
||||
}
|
||||
break;
|
||||
case "ScoreboardDisplay":
|
||||
@@ -93,7 +97,7 @@ public class BungeePipelineInjector extends PipelineInjector {
|
||||
try {
|
||||
super.write(context, packet, channelPromise);
|
||||
} catch (Exception e) {
|
||||
TAB.getInstance().getErrorManager().printError("Failed to forward packet " + packet.getClass().getSimpleName() + " to " + player.getName(), e);
|
||||
TAB.getInstance().getErrorManager().printError(String.format("Failed to forward packet %s to %s", packet.getClass().getSimpleName(), player.getName()), e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,8 +108,7 @@ public class BungeePipelineInjector extends PipelineInjector {
|
||||
* packet to modify
|
||||
*/
|
||||
private void modifyPlayers(Team packet){
|
||||
long time = System.nanoTime();
|
||||
if (packet.getPlayers() == null) return;
|
||||
if (packet.getMode() == 1 || packet.getMode() == 2 || packet.getMode() == 4) return;
|
||||
Collection<String> col = Lists.newArrayList(packet.getPlayers());
|
||||
for (TabPlayer p : TAB.getInstance().getOnlinePlayers()) {
|
||||
if (col.contains(p.getNickname()) && !((TabFeature)TAB.getInstance().getTeamManager()).isDisabledPlayer(p) &&
|
||||
@@ -124,10 +127,14 @@ public class BungeePipelineInjector extends PipelineInjector {
|
||||
}
|
||||
}
|
||||
packet.setPlayers(col.toArray(new String[0]));
|
||||
TAB.getInstance().getCPUManager().addTime("NameTags", TabConstants.CpuUsageCategory.ANTI_OVERRIDE, System.nanoTime()-time);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Channel duplex handler override if features using packets that must be
|
||||
* deserialized manually are used. If they are disabled, deserialization is
|
||||
* disabled for better performance.
|
||||
*/
|
||||
public class DeserializableBungeeChannelDuplexHandler extends BungeeChannelDuplexHandler {
|
||||
|
||||
/**
|
||||
@@ -144,7 +151,7 @@ public class BungeePipelineInjector extends PipelineInjector {
|
||||
public void write(ChannelHandlerContext context, Object packet, ChannelPromise channelPromise) {
|
||||
long time = System.nanoTime();
|
||||
Object modifiedPacket = packet instanceof ByteBuf ? deserialize((ByteBuf) packet) : packet;
|
||||
TAB.getInstance().getCPUManager().addTime("Packet deserializing", TabConstants.CpuUsageCategory.BYTE_BUF, System.nanoTime()-time);
|
||||
TAB.getInstance().getCPUManager().addTime(TabConstants.Feature.PACKET_DESERIALIZING, TabConstants.CpuUsageCategory.BYTE_BUF, System.nanoTime()-time);
|
||||
super.write(context, modifiedPacket, channelPromise);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
package me.neznamy.tab.platforms.bungeecord;
|
||||
|
||||
import com.imaginarycode.minecraft.redisbungee.RedisBungeeAPI;
|
||||
import me.neznamy.tab.api.TabPlayer;
|
||||
import me.neznamy.tab.api.util.Preconditions;
|
||||
import me.neznamy.tab.platforms.bungeecord.event.TabLoadEvent;
|
||||
import me.neznamy.tab.platforms.bungeecord.event.TabPlayerLoadEvent;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.shared.TabConstants;
|
||||
import me.neznamy.tab.api.TabConstants;
|
||||
import me.neznamy.tab.shared.proxy.ProxyPlatform;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
@@ -18,7 +14,7 @@ import net.md_5.bungee.api.plugin.Plugin;
|
||||
public class BungeePlatform extends ProxyPlatform {
|
||||
|
||||
/**
|
||||
* Constructs new instance with given parameter
|
||||
* Constructs new instance
|
||||
*/
|
||||
public BungeePlatform() {
|
||||
super(new BungeePacketBuilder());
|
||||
@@ -29,9 +25,9 @@ public class BungeePlatform extends ProxyPlatform {
|
||||
TAB tab = TAB.getInstance();
|
||||
if (tab.getConfiguration().isPipelineInjection())
|
||||
tab.getFeatureManager().registerFeature(TabConstants.Feature.PIPELINE_INJECTION, new BungeePipelineInjector());
|
||||
tab.getPlaceholderManager().registerPlayerPlaceholder("%displayname%", 500, p -> ((ProxiedPlayer) p.getPlayer()).getDisplayName());
|
||||
tab.getPlaceholderManager().registerPlayerPlaceholder(TabConstants.Placeholder.DISPLAY_NAME, 500, p -> ((ProxiedPlayer) p.getPlayer()).getDisplayName());
|
||||
super.loadFeatures();
|
||||
if (ProxyServer.getInstance().getPluginManager().getPlugin("RedisBungee") != null) {
|
||||
if (ProxyServer.getInstance().getPluginManager().getPlugin(TabConstants.Plugin.REDIS_BUNGEE) != null) {
|
||||
if (RedisBungeeAPI.getRedisBungeeApi() != null) {
|
||||
tab.getFeatureManager().registerFeature(TabConstants.Feature.REDIS_BUNGEE, new RedisBungeeSupport());
|
||||
} else {
|
||||
@@ -43,19 +39,8 @@ public class BungeePlatform extends ProxyPlatform {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void callLoadEvent() {
|
||||
ProxyServer.getInstance().getPluginManager().callEvent(new TabLoadEvent());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void callLoadEvent(TabPlayer player) {
|
||||
ProxyServer.getInstance().getPluginManager().callEvent(new TabPlayerLoadEvent(player));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPluginVersion(String plugin) {
|
||||
Preconditions.checkNotNull(plugin, "plugin");
|
||||
Plugin pl = ProxyServer.getInstance().getPluginManager().getPlugin(plugin);
|
||||
return pl == null ? null : pl.getDescription().getVersion();
|
||||
}
|
||||
|
||||
@@ -1,45 +1,69 @@
|
||||
package me.neznamy.tab.platforms.bungeecord;
|
||||
|
||||
import de.myzelyam.api.vanish.BungeeVanishAPI;
|
||||
import io.netty.channel.Channel;
|
||||
import me.neznamy.tab.api.ProtocolVersion;
|
||||
import me.neznamy.tab.api.TabConstants;
|
||||
import me.neznamy.tab.api.protocol.Skin;
|
||||
import me.neznamy.tab.api.util.Preconditions;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.shared.TabConstants;
|
||||
import me.neznamy.tab.shared.proxy.ProxyTabPlayer;
|
||||
import net.md_5.bungee.UserConnection;
|
||||
import net.md_5.bungee.api.ProxyConfig;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.connection.InitialHandler;
|
||||
import net.md_5.bungee.connection.LoginResult;
|
||||
import net.md_5.bungee.netty.ChannelWrapper;
|
||||
import net.md_5.bungee.protocol.DefinedPacket;
|
||||
import net.md_5.bungee.protocol.Protocol;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* TabPlayer for BungeeCord
|
||||
* TabPlayer implementation for BungeeCord
|
||||
*/
|
||||
public class BungeeTabPlayer extends ProxyTabPlayer {
|
||||
|
||||
//bungee internals to get player channel
|
||||
/** Inaccessible bungee internals */
|
||||
private static Method InitialHandler_getLoginProfile;
|
||||
private static Method ChannelWrapper_getHandle;
|
||||
private static Method LoginResult_Property_getValue;
|
||||
private static Method LoginResult_Property_getSignature;
|
||||
private static Method LoginResult_getProperties;
|
||||
private static Method UserConnection_getGamemode;
|
||||
private static Field wrapperField;
|
||||
private static Object directionData;
|
||||
private static Method getId;
|
||||
|
||||
/** Rewriting offline tablist uuids coming from backend servers to online uuids on online servers */
|
||||
private static boolean tablistRewriteEnabled = true;
|
||||
|
||||
static {
|
||||
try {
|
||||
Class<?> initialHandler = Class.forName("net.md_5.bungee.connection.InitialHandler");
|
||||
InitialHandler_getLoginProfile = initialHandler.getMethod("getLoginProfile");
|
||||
Class<?> channelWrapper = Class.forName("net.md_5.bungee.netty.ChannelWrapper");
|
||||
ChannelWrapper_getHandle = channelWrapper.getMethod("getHandle");
|
||||
Class<?> loginResult = Class.forName("net.md_5.bungee.connection.LoginResult");
|
||||
Class<?> loginResult_Property = Class.forName("net.md_5.bungee.protocol.Property");
|
||||
LoginResult_Property_getValue = loginResult_Property.getMethod("getValue");
|
||||
LoginResult_Property_getSignature = loginResult_Property.getMethod("getSignature");
|
||||
LoginResult_getProperties = loginResult.getMethod("getProperties");
|
||||
Class<?> userConnection = Class.forName("net.md_5.bungee.UserConnection");
|
||||
UserConnection_getGamemode = userConnection.getMethod("getGamemode");
|
||||
Field f = Protocol.class.getDeclaredField("TO_CLIENT");
|
||||
f.setAccessible(true);
|
||||
directionData = f.get(Protocol.GAME);
|
||||
getId = directionData.getClass().getDeclaredMethod("getId", Class.class, int.class);
|
||||
getId.setAccessible(true);
|
||||
wrapperField = InitialHandler.class.getDeclaredField("ch");
|
||||
wrapperField = initialHandler.getDeclaredField("ch");
|
||||
wrapperField.setAccessible(true);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
TAB.getInstance().getErrorManager().criticalError("Failed to initialize fields for packet analysis", e);
|
||||
TAB.getInstance().getErrorManager().criticalError("Failed to initialize bungee internal fields", e);
|
||||
}
|
||||
try {
|
||||
tablistRewriteEnabled = !(boolean) ProxyConfig.class.getMethod("isDisableTabListRewrite").invoke(ProxyServer.getInstance().getConfig());
|
||||
} catch (ReflectiveOperationException e) {
|
||||
// not Waterfall, always true on BungeeCord
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,10 +74,10 @@ public class BungeeTabPlayer extends ProxyTabPlayer {
|
||||
* BungeeCord player
|
||||
*/
|
||||
public BungeeTabPlayer(ProxiedPlayer p) {
|
||||
super(p, p.getUniqueId(), p.getName(), p.getServer() != null ? p.getServer().getInfo().getName() : "-", -1);
|
||||
super(p, p.getUniqueId(), p.getName(), p.getServer() != null ? p.getServer().getInfo().getName() : "-", -1, tablistRewriteEnabled);
|
||||
try {
|
||||
channel = ((ChannelWrapper) wrapperField.get(getPlayer().getPendingConnection())).getHandle();
|
||||
} catch (IllegalAccessException e) {
|
||||
channel = (Channel) ChannelWrapper_getHandle.invoke(wrapperField.get(getPlayer().getPendingConnection()));
|
||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||
TAB.getInstance().getErrorManager().criticalError("Failed to get channel of " + getPlayer().getName(), e);
|
||||
}
|
||||
}
|
||||
@@ -81,9 +105,17 @@ public class BungeeTabPlayer extends ProxyTabPlayer {
|
||||
|
||||
@Override
|
||||
public Skin getSkin() {
|
||||
LoginResult loginResult = ((InitialHandler)getPlayer().getPendingConnection()).getLoginProfile();
|
||||
if (loginResult == null || loginResult.getProperties() == null || loginResult.getProperties().length == 0) return null;
|
||||
return new Skin(loginResult.getProperties()[0].getValue(), loginResult.getProperties()[0].getSignature());
|
||||
try {
|
||||
Object loginResult = InitialHandler_getLoginProfile.invoke(getPlayer().getPendingConnection());
|
||||
if (loginResult == null) return null;
|
||||
Object[] properties = (Object[]) LoginResult_getProperties.invoke(loginResult);
|
||||
if (properties == null || properties.length == 0) return null;
|
||||
return new Skin((String) LoginResult_Property_getValue.invoke(properties[0]),
|
||||
(String) LoginResult_Property_getSignature.invoke(properties[0]));
|
||||
} catch (ReflectiveOperationException e) {
|
||||
TAB.getInstance().getErrorManager().printError("Failed to get skin of " + getName(), e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -116,9 +148,9 @@ public class BungeeTabPlayer extends ProxyTabPlayer {
|
||||
@Override
|
||||
public boolean isVanished() {
|
||||
try {
|
||||
if (ProxyServer.getInstance().getPluginManager().getPlugin("PremiumVanish") != null && BungeeVanishAPI.isInvisible(getPlayer())) return true;
|
||||
if (ProxyServer.getInstance().getPluginManager().getPlugin(TabConstants.Plugin.PREMIUM_VANISH) != null && BungeeVanishAPI.isInvisible(getPlayer())) return true;
|
||||
} catch (Exception e) {
|
||||
TAB.getInstance().getErrorManager().printError("PremiumVanish v" + TAB.getInstance().getPlatform().getPluginVersion("PremiumVanish") +
|
||||
TAB.getInstance().getErrorManager().printError("PremiumVanish v" + TAB.getInstance().getPlatform().getPluginVersion(TabConstants.Plugin.PREMIUM_VANISH) +
|
||||
" generated an error when retrieving vanish status of " + getName(), e);
|
||||
}
|
||||
return super.isVanished();
|
||||
@@ -131,7 +163,12 @@ public class BungeeTabPlayer extends ProxyTabPlayer {
|
||||
|
||||
@Override
|
||||
public int getGamemode() {
|
||||
return ((UserConnection)player).getGamemode();
|
||||
try {
|
||||
return (int) UserConnection_getGamemode.invoke(player);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
TAB.getInstance().getErrorManager().printError("Failed to get gamemode of " + getPlayer().getName(), e);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -9,7 +9,7 @@ import me.neznamy.tab.api.ProtocolVersion;
|
||||
import me.neznamy.tab.api.TabPlayer;
|
||||
import me.neznamy.tab.api.chat.EnumChatFormat;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.shared.TabConstants;
|
||||
import me.neznamy.tab.api.TabConstants;
|
||||
import net.md_5.bungee.api.CommandSender;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
import net.md_5.bungee.api.chat.TextComponent;
|
||||
@@ -26,17 +26,18 @@ public class Main extends Plugin {
|
||||
@Override
|
||||
public void onEnable(){
|
||||
if (!isVersionSupported()) {
|
||||
getLogger().info(EnumChatFormat.color("&cThe plugin requires BungeeCord build #1330 and up to work. Get it at https://ci.md-5.net/job/BungeeCord/"));
|
||||
getLogger().info(EnumChatFormat.color("&cThe plugin requires BungeeCord build #1637 and up to work. Get it at https://ci.md-5.net/job/BungeeCord/"));
|
||||
return;
|
||||
}
|
||||
BungeePlatform platform = new BungeePlatform();
|
||||
ProxyServer.getInstance().registerChannel(TabConstants.PLUGIN_MESSAGE_CHANNEL_NAME);
|
||||
TAB.setInstance(new TAB(new BungeePlatform(), ProtocolVersion.PROXY, getProxy().getVersion(), getDataFolder(), getLogger()));
|
||||
getProxy().getPluginManager().registerListener(this, new BungeeEventListener());
|
||||
TAB.setInstance(new TAB(platform, ProtocolVersion.PROXY, getProxy().getVersion(), getDataFolder(), getLogger()));
|
||||
getProxy().getPluginManager().registerListener(this, new BungeeEventListener(platform));
|
||||
getProxy().getPluginManager().registerCommand(this, new BTABCommand());
|
||||
TAB.getInstance().load();
|
||||
Metrics metrics = new Metrics(this, 10535);
|
||||
metrics.addCustomChart(new SimplePie("permission_system", () -> TAB.getInstance().getGroupManager().getPlugin().getName()));
|
||||
metrics.addCustomChart(new SimplePie("global_playerlist_enabled", () -> TAB.getInstance().getFeatureManager().isFeatureEnabled(TabConstants.Feature.GLOBAL_PLAYER_LIST) ? "Yes" : "No"));
|
||||
metrics.addCustomChart(new SimplePie(TabConstants.MetricsChart.PERMISSION_SYSTEM, () -> TAB.getInstance().getGroupManager().getPlugin().getName()));
|
||||
metrics.addCustomChart(new SimplePie(TabConstants.MetricsChart.GLOBAL_PLAYER_LIST_ENABLED, () -> TAB.getInstance().getFeatureManager().isFeatureEnabled(TabConstants.Feature.GLOBAL_PLAYER_LIST) ? "Yes" : "No"));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -46,7 +47,7 @@ public class Main extends Plugin {
|
||||
*/
|
||||
private boolean isVersionSupported() {
|
||||
try {
|
||||
Class.forName("net.md_5.bungee.protocol.packet.ScoreboardObjective$HealthDisplay");
|
||||
Class.forName("net.md_5.bungee.protocol.Property");
|
||||
return true;
|
||||
} catch (ClassNotFoundException e) {
|
||||
return false;
|
||||
@@ -59,9 +60,9 @@ public class Main extends Plugin {
|
||||
}
|
||||
|
||||
/**
|
||||
* TAB command for bungeecord
|
||||
* TAB command for BungeeCord
|
||||
*/
|
||||
public static class BTABCommand extends Command implements TabExecutor {
|
||||
private static class BTABCommand extends Command implements TabExecutor {
|
||||
|
||||
/**
|
||||
* Constructs new instance
|
||||
@@ -72,7 +73,7 @@ public class Main extends Plugin {
|
||||
|
||||
@Override
|
||||
public void execute(CommandSender sender, String[] args) {
|
||||
if (TAB.getInstance().isDisabled()) {
|
||||
if (TAB.getInstance().isPluginDisabled()) {
|
||||
for (String message : TAB.getInstance().getDisabledCommand().execute(args, sender.hasPermission(TabConstants.Permission.COMMAND_RELOAD), sender.hasPermission(TabConstants.Permission.COMMAND_ALL))) {
|
||||
sender.sendMessage(new TextComponent(EnumChatFormat.color(message)));
|
||||
}
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@ package me.neznamy.tab.platforms.bungeecord;
|
||||
|
||||
import com.imaginarycode.minecraft.redisbungee.RedisBungeeAPI;
|
||||
import com.imaginarycode.minecraft.redisbungee.events.PubSubMessageEvent;
|
||||
import me.neznamy.tab.shared.TabConstants;
|
||||
import me.neznamy.tab.api.TabConstants;
|
||||
import me.neznamy.tab.shared.features.redis.RedisSupport;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
import net.md_5.bungee.api.plugin.Listener;
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
package me.neznamy.tab.platforms.bungeecord.event;
|
||||
|
||||
import net.md_5.bungee.api.plugin.Event;
|
||||
|
||||
/**
|
||||
* Bungee event that is called each time TAB fully loads. This includes server startup, reload and
|
||||
* /btab reload
|
||||
*
|
||||
* @deprecated for removal, use {@link me.neznamy.tab.api.event.plugin.TabLoadEvent}
|
||||
*/
|
||||
@Deprecated
|
||||
public class TabLoadEvent extends Event {
|
||||
|
||||
}
|
||||
-23
@@ -1,23 +0,0 @@
|
||||
package me.neznamy.tab.platforms.bungeecord.event;
|
||||
|
||||
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.
|
||||
*
|
||||
* @deprecated for removal, use {@link me.neznamy.tab.api.event.player.PlayerLoadEvent}
|
||||
*/
|
||||
@Deprecated
|
||||
public class TabPlayerLoadEvent extends Event {
|
||||
|
||||
private final TabPlayer player;
|
||||
|
||||
public TabPlayerLoadEvent(TabPlayer player) {
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
public TabPlayer getPlayer() {
|
||||
return player;
|
||||
}
|
||||
}
|
||||
@@ -61,7 +61,6 @@ scoreboard-teams:
|
||||
enabled: false
|
||||
use-marker-tag-for-1-8-x-clients: false
|
||||
disable-on-boats: true
|
||||
space-between-lines: 0.22
|
||||
disable-in-worlds:
|
||||
- disabledworld
|
||||
disable-in-servers:
|
||||
@@ -154,7 +153,7 @@ scoreboard:
|
||||
lines:
|
||||
- "%animation:MyAnimation1%"
|
||||
- "&6Online:"
|
||||
- "* &eOnline&7: &f%online%&7/&4%maxplayers%"
|
||||
- "* &eOnline&7: &f%online%"
|
||||
- "* &eCurrent World&7: &f%worldonline%"
|
||||
- "* &eStaff&7: &f%staffonline%"
|
||||
- " "
|
||||
@@ -200,10 +199,10 @@ placeholder-output-replacements:
|
||||
"no": ""
|
||||
"%essentials_nickname%":
|
||||
"%essentials_nickname%": "%player%" # placeholder did not parse correctly, show real name instead
|
||||
|
||||
|
||||
# bukkit-only placeholders used in default groups.yml, doing this as a fix
|
||||
"%afk%":
|
||||
"%afk%": ""
|
||||
"%afk%": ""
|
||||
"%vault-prefix%":
|
||||
"%vault-prefix%" : ""
|
||||
"%vault-suffix%":
|
||||
|
||||
+1
-1
@@ -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.1.1
|
||||
projectVersion=3.1.3
|
||||
|
||||
# Gradle properties
|
||||
org.gradle.daemon=true
|
||||
|
||||
+16
-14
@@ -3,12 +3,13 @@ metadata.format.version = "1.1"
|
||||
[versions]
|
||||
|
||||
# API
|
||||
netty = "4.1.75.Final"
|
||||
netty = "4.1.78.Final"
|
||||
jsonSimple = "1.1.1"
|
||||
snakeyaml = "1.30"
|
||||
yamlAssist = "1.0.5"
|
||||
gson = "2.9.0"
|
||||
slf4j = "1.7.36"
|
||||
minimessage = "4.11.0"
|
||||
|
||||
# General
|
||||
luckperms = "5.4"
|
||||
@@ -19,20 +20,19 @@ event = "3.0.0"
|
||||
|
||||
# Platforms
|
||||
bukkit = "1.16.5-R0.1-SNAPSHOT"
|
||||
bungeecord = "1.18-R0.1-SNAPSHOT"
|
||||
bungeecord = "1.19-R0.1-SNAPSHOT"
|
||||
krypton = "0.59.2"
|
||||
velocity = "1.1.0"
|
||||
velocity = "3.0.1"
|
||||
|
||||
# Platform extras
|
||||
placeholderapi = "2.10.9"
|
||||
placeholderapi = "2.11.1"
|
||||
vault = "1.7"
|
||||
via = "4.0.0"
|
||||
authlib = "1.11"
|
||||
bstats = "2.2.1"
|
||||
libsDisguises = "10.0.26"
|
||||
essentials = "2.19.2"
|
||||
via = "4.3.1"
|
||||
authlib = "1.5.25"
|
||||
bstats = "3.0.0"
|
||||
essentials = "2.19.4"
|
||||
premiumVanish = "2.0.3"
|
||||
redisBungee = "0.6.5-SNAPSHOT"
|
||||
redisBungee = "0.7.2"
|
||||
|
||||
[libraries]
|
||||
|
||||
@@ -43,6 +43,9 @@ snakeyaml = { group = "org.yaml", name = "snakeyaml", version.ref = "snakeyaml"
|
||||
yamlAssist = { group = "me.neznamy", name = "yamlassist", version.ref = "yamlAssist" }
|
||||
gson = { group = "com.google.code.gson", name = "gson", version.ref = "gson" }
|
||||
slf4j = { group = "org.slf4j", name = "slf4j-api", version.ref = "slf4j"}
|
||||
adventureMiniMessage = { group = "net.kyori", name = "adventure-text-minimessage", version.ref = "minimessage" }
|
||||
adventureApi = { group = "net.kyori", name = "adventure-api", version.ref = "minimessage" }
|
||||
adventureLegacy = { group = "net.kyori", name = "adventure-text-serializer-legacy", version.ref = "minimessage" }
|
||||
|
||||
# General
|
||||
luckperms = { group = "net.luckperms", name = "api", version.ref = "luckperms" }
|
||||
@@ -52,8 +55,8 @@ kotlin-stdlib = { group = "org.jetbrains.kotlin", name = "kotlin-stdlib", versio
|
||||
event = { group = "net.kyori", name = "event-method", version.ref = "event" }
|
||||
|
||||
# Platforms
|
||||
bukkit = { group = "com.destroystokyo.paper", name = "paper-api", version.ref = "bukkit" }
|
||||
bungeecord = { group = "net.md-5", name = "bungeecord-proxy", version.ref = "bungeecord" }
|
||||
bukkit = { group = "org.purpurmc.purpur", name = "purpur-api", version.ref = "bukkit" }
|
||||
bungeecord = { group = "net.md-5", name = "bungeecord-api", version.ref = "bungeecord" }
|
||||
krypton-api = { group = "org.kryptonmc", name = "krypton-api", version.ref = "krypton" }
|
||||
krypton-server = { group = "org.kryptonmc", name = "krypton-server", version.ref = "krypton" }
|
||||
krypton-annotationProcessor = { group = "org.kryptonmc", name = "krypton-annotation-processor", version.ref = "krypton" }
|
||||
@@ -64,10 +67,9 @@ placeholderapi = { group = "me.clip", name = "placeholderapi", version.ref = "pl
|
||||
vault = { group = "com.github.MilkBowl", name = "VaultAPI", version.ref = "vault" }
|
||||
via = { group = "com.viaversion", name = "viaversion-api", version.ref = "via" }
|
||||
authlib = { group = "com.mojang", name = "authlib", version.ref = "authlib" }
|
||||
libsDisguises = { group = "LibsDisguises", name = "LibsDisguises", version.ref = "libsDisguises" }
|
||||
essentials = { group = "net.essentialsx", name = "EssentialsX", version.ref = "essentials" }
|
||||
premiumVanish = { group = "com.github.MyzelYam", name = "PremiumVanishAPI", version.ref = "premiumVanish" }
|
||||
redisBungee = { group = "com.imaginarycode.minecraft", name = "RedisBungee", version.ref = "redisBungee" }
|
||||
redisBungee = { group = "com.github.limework.redisbungee", name = "RedisBungee-Bungee", version.ref = "redisBungee" }
|
||||
|
||||
# Metrics
|
||||
bstats-bukkit = { group = "org.bstats", name = "bstats-bukkit", version.ref = "bstats" }
|
||||
|
||||
+10
-15
@@ -3,21 +3,16 @@ enableFeaturePreview("VERSION_CATALOGS")
|
||||
|
||||
dependencyResolutionManagement {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven("https://jitpack.io")
|
||||
maven("https://repo.extendedclip.com/content/repositories/placeholderapi/")
|
||||
maven("https://repo.viaversion.com/")
|
||||
maven("https://repo.aikar.co/content/groups/aikar/")
|
||||
maven("https://repo.md-5.net/content/groups/public/")
|
||||
maven("https://ci.lucko.me/plugin/repository/everything/")
|
||||
maven("https://repo.essentialsx.net/releases/")
|
||||
maven("https://repo.codemc.org/repository/maven-public")
|
||||
maven("https://repo.kryptonmc.org/releases")
|
||||
maven("https://repo.kryptonmc.org/snapshots")
|
||||
maven("https://oss.sonatype.org/content/repositories/snapshots/")
|
||||
maven("https://nexus.velocitypowered.com/repository/maven-public/")
|
||||
maven("https://repo.opencollab.dev/maven-snapshots/")
|
||||
maven("https://papermc.io/repo/repository/maven-public/")
|
||||
mavenCentral() // Netty, SnakeYaml, json-simple, Gson, slf4j, Guava, Kyori event, bStats, AuthLib
|
||||
maven("https://jitpack.io") // PremiumVanish
|
||||
maven("https://repo.extendedclip.com/content/repositories/placeholderapi/") // PlaceholderAPI
|
||||
maven("https://repo.viaversion.com/") // ViaVersion
|
||||
maven("https://repo.essentialsx.net/releases/") // Essentials
|
||||
maven("https://repo.codemc.org/repository/maven-public/") // RedisBungee, BungeeCord
|
||||
maven("https://repo.kryptonmc.org/releases") // YamlAssist, LuckPerms
|
||||
maven("https://repo.opencollab.dev/maven-snapshots/") // Floodgate
|
||||
maven("https://repo.purpurmc.org/snapshots") // Purpur, Vault
|
||||
maven("https://repo.papermc.io/repository/maven-public/") // Velocity
|
||||
}
|
||||
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
|
||||
}
|
||||
|
||||
+1
-10
@@ -1,7 +1,3 @@
|
||||
plugins {
|
||||
id("net.kyori.blossom") version "1.2.0"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api(projects.api)
|
||||
api(libs.event) {
|
||||
@@ -12,9 +8,4 @@ dependencies {
|
||||
compileOnlyApi(libs.guava)
|
||||
compileOnlyApi(libs.floodgate)
|
||||
compileOnlyApi(libs.slf4j)
|
||||
}
|
||||
|
||||
blossom {
|
||||
replaceToken("@plugin_version@", project.version)
|
||||
replaceTokenIn("src/main/java/me/neznamy/tab/shared/TabConstants.java")
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,6 @@ import java.util.concurrent.atomic.AtomicLong;
|
||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||
|
||||
import me.neznamy.tab.api.TabFeature;
|
||||
import me.neznamy.tab.api.task.RepeatingTask;
|
||||
import me.neznamy.tab.api.task.ThreadManager;
|
||||
|
||||
/**
|
||||
@@ -18,7 +17,7 @@ import me.neznamy.tab.api.task.ThreadManager;
|
||||
public class CpuManager implements ThreadManager {
|
||||
|
||||
/** Data reset interval in milliseconds */
|
||||
private static final int BUFFER_SIZE_MILLIS = 10000;
|
||||
private final int BUFFER_SIZE_MILLIS = 10000;
|
||||
|
||||
/** Active time in current time period saved as nanoseconds from features */
|
||||
private Map<String, Map<String, AtomicLong>> featureUsageCurrent = new ConcurrentHashMap<>();
|
||||
@@ -48,7 +47,7 @@ public class CpuManager implements ThreadManager {
|
||||
private ExecutorService thread = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().setNameFormat("TAB Processing Thread").build());
|
||||
|
||||
/** Thread pool for delayed and repeating tasks to perform sleep before submitting task to main thread */
|
||||
private final ThreadPoolExecutor threadPool = (ThreadPoolExecutor) Executors.newCachedThreadPool(
|
||||
private final ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(20,
|
||||
new ThreadFactoryBuilder().setNameFormat("TAB Repeating / Delayed Thread %d").build());
|
||||
|
||||
/** Tasks submitted to main thread before plugin was fully enabled */
|
||||
@@ -359,48 +358,22 @@ public class CpuManager implements ThreadManager {
|
||||
}
|
||||
|
||||
@Override
|
||||
public RepeatingTask startRepeatingMeasuredTask(int intervalMilliseconds, TabFeature feature, String type, Runnable task) {
|
||||
return new TabRepeatingTask(threadPool, task, feature, type, intervalMilliseconds);
|
||||
public Future<?> startRepeatingMeasuredTask(int intervalMilliseconds, TabFeature feature, String type, Runnable task) {
|
||||
return threadPool.scheduleAtFixedRate(() -> runMeasuredTask(feature, type, task), 0, intervalMilliseconds, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RepeatingTask startRepeatingTask(int intervalMilliseconds, Runnable task) {
|
||||
return new TabRepeatingTask(threadPool, task, null, null, intervalMilliseconds);
|
||||
public Future<?> startRepeatingTask(int intervalMilliseconds, Runnable task) {
|
||||
return threadPool.scheduleAtFixedRate(() -> runTask(task), 0, intervalMilliseconds, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Future<?> runTaskLater(int delayMilliseconds, TabFeature feature, String type, Runnable task) {
|
||||
try {
|
||||
return threadPool.submit(() -> {
|
||||
try {
|
||||
Thread.sleep(delayMilliseconds);
|
||||
runMeasuredTask(feature, type, task);
|
||||
} catch (InterruptedException pluginDisabled) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
});
|
||||
} catch (OutOfMemoryError e) {
|
||||
TAB.getInstance().getErrorManager().criticalError("Failed to create new delayed task, active thread count: " +
|
||||
threadPool.getActiveCount() + " / " + threadPool.getPoolSize(), e);
|
||||
return null;
|
||||
}
|
||||
return threadPool.schedule(() -> runMeasuredTask(feature, type, task), delayMilliseconds, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Future<?> runTaskLater(int delayMilliseconds, Runnable task) {
|
||||
try {
|
||||
return threadPool.submit(() -> {
|
||||
try {
|
||||
Thread.sleep(delayMilliseconds);
|
||||
submit(task);
|
||||
} catch (InterruptedException pluginDisabled) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
});
|
||||
} catch (OutOfMemoryError e) {
|
||||
TAB.getInstance().getErrorManager().criticalError("Failed to create new delayed task, active thread count: " +
|
||||
threadPool.getActiveCount() + " / " + threadPool.getPoolSize(), e);
|
||||
return null;
|
||||
}
|
||||
return threadPool.schedule(() -> submit(task), delayMilliseconds, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
}
|
||||
@@ -110,7 +110,7 @@ public class DynamicText implements Property {
|
||||
rawFormattedValue0 = sb.toString();
|
||||
}
|
||||
}
|
||||
rawFormattedValue0 = RGBUtils.getInstance().applyFormats(rawFormattedValue0, true);
|
||||
rawFormattedValue0 = RGBUtils.getInstance().applyCleanGradients(rawFormattedValue0);
|
||||
rawFormattedValue = EnumChatFormat.color(rawFormattedValue0);
|
||||
placeholders = placeholders0.toArray(new String[0]);
|
||||
relPlaceholders = relPlaceholders0.toArray(new String[0]);
|
||||
|
||||
@@ -9,6 +9,7 @@ import java.nio.file.Files;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
|
||||
import me.neznamy.tab.api.TabConstants;
|
||||
import me.neznamy.tab.api.chat.EnumChatFormat;
|
||||
import me.neznamy.tab.api.chat.IChatBaseComponent;
|
||||
|
||||
@@ -108,13 +109,18 @@ public class ErrorManager {
|
||||
private synchronized void printError(String message, List<String> error, boolean intoConsoleToo, File file) {
|
||||
try {
|
||||
if (!file.exists()) Files.createFile(file.toPath());
|
||||
if (file.length() > 1000000) return; //not going over 1 MB
|
||||
try (BufferedWriter buf = new BufferedWriter(new FileWriter(file, true))){
|
||||
if (message != null) {
|
||||
write(buf, "&c[TAB v" + TabConstants.PLUGIN_VERSION + "] ", EnumChatFormat.decolor(message), intoConsoleToo);
|
||||
if (file.length() < 1000000)
|
||||
buf.write(dateFormat.format(new Date()) + IChatBaseComponent.fromColoredText("&c[TAB v" + TabConstants.PLUGIN_VERSION + "] ").toRawText() + EnumChatFormat.decolor(message) + System.getProperty("line.separator"));
|
||||
if (intoConsoleToo || TAB.getInstance().getConfiguration().isDebugMode())
|
||||
TAB.getInstance().sendConsoleMessage(EnumChatFormat.color("&c[TAB v" + TabConstants.PLUGIN_VERSION + "] ") + EnumChatFormat.decolor(message), false);
|
||||
}
|
||||
for (String line : error) {
|
||||
write(buf, "&c", line, intoConsoleToo);
|
||||
if (file.length() < 1000000)
|
||||
buf.write(dateFormat.format(new Date()) + IChatBaseComponent.fromColoredText("&c").toRawText() + line + System.getProperty("line.separator"));
|
||||
if (intoConsoleToo || TAB.getInstance().getConfiguration().isDebugMode())
|
||||
TAB.getInstance().sendConsoleMessage(EnumChatFormat.color("&c") + line, false);
|
||||
}
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
@@ -154,23 +160,6 @@ public class ErrorManager {
|
||||
printError(message, t, false, placeholderErrorLog);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes message into buffer and console if set
|
||||
*
|
||||
* @param buf
|
||||
* writer to write message to
|
||||
* @param message
|
||||
* message to write
|
||||
* @param forceConsole
|
||||
* whether to send into console even without debug mode
|
||||
* @throws IOException
|
||||
* if I/O writer operation fails
|
||||
*/
|
||||
private void write(BufferedWriter buf, String prefix, String message, boolean forceConsole) throws IOException {
|
||||
buf.write(dateFormat.format(new Date()) + IChatBaseComponent.fromColoredText(prefix).toRawText() + message + System.getProperty("line.separator"));
|
||||
if (TAB.getInstance().getConfiguration().isDebugMode() || forceConsole) TAB.getInstance().sendConsoleMessage(EnumChatFormat.color(prefix) + message, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints error message and stack trace into errors.log file as well as the console
|
||||
*
|
||||
|
||||
@@ -5,6 +5,7 @@ import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import me.neznamy.tab.api.FeatureManager;
|
||||
import me.neznamy.tab.api.TabConstants;
|
||||
import me.neznamy.tab.api.TabFeature;
|
||||
import me.neznamy.tab.api.TabPlayer;
|
||||
import me.neznamy.tab.api.placeholder.PlayerPlaceholder;
|
||||
@@ -28,6 +29,10 @@ public class FeatureManagerImpl implements FeatureManager {
|
||||
/** All registered features in an array to avoid memory allocations on iteration */
|
||||
private TabFeature[] values = new TabFeature[0];
|
||||
|
||||
private boolean objectiveListeners = false;
|
||||
|
||||
private boolean displayObjectiveListeners = false;
|
||||
|
||||
/**
|
||||
* Calls load() on all features.
|
||||
* This function is called on plugin startup.
|
||||
@@ -94,12 +99,7 @@ public class FeatureManagerImpl implements FeatureManager {
|
||||
return pack;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls onQuit(TabPlayer) on all features
|
||||
*
|
||||
* @param disconnectedPlayer
|
||||
* player who disconnected
|
||||
*/
|
||||
@Override
|
||||
public void onQuit(TabPlayer disconnectedPlayer) {
|
||||
if (disconnectedPlayer == null) return;
|
||||
long millis = System.currentTimeMillis();
|
||||
@@ -113,22 +113,21 @@ public class FeatureManagerImpl implements FeatureManager {
|
||||
TAB.getInstance().debug("Player quit of " + disconnectedPlayer.getName() + " processed in " + (System.currentTimeMillis()-millis) + "ms");
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls onJoin(TabPlayer) on all features
|
||||
*
|
||||
* @param connectedPlayer
|
||||
* player who connected
|
||||
*/
|
||||
@Override
|
||||
public void onJoin(TabPlayer connectedPlayer) {
|
||||
if (!connectedPlayer.isOnline()) return;
|
||||
long millis = System.currentTimeMillis();
|
||||
TAB.getInstance().addPlayer(connectedPlayer);
|
||||
for (TabFeature f : values) {
|
||||
if (!f.overridesMethod("onJoin")) continue;
|
||||
long time = System.nanoTime();
|
||||
f.onJoin(connectedPlayer);
|
||||
TAB.getInstance().getCPUManager().addTime(f, TabConstants.CpuUsageCategory.PLAYER_JOIN, System.nanoTime()-time);
|
||||
TAB.getInstance().debug("Feature " + f.getClass().getSimpleName() + " processed player join in " + (System.nanoTime()-time)/1000000 + "ms");
|
||||
try {
|
||||
if (!f.overridesMethod("onJoin")) continue;
|
||||
long time = System.nanoTime();
|
||||
f.onJoin(connectedPlayer);
|
||||
TAB.getInstance().getCPUManager().addTime(f, TabConstants.CpuUsageCategory.PLAYER_JOIN, System.nanoTime()-time);
|
||||
TAB.getInstance().debug("Feature " + f.getClass().getSimpleName() + " processed player join in " + (System.nanoTime()-time)/1000000 + "ms");
|
||||
} catch (Throwable e) {
|
||||
TAB.getInstance().getErrorManager().criticalError("Feature " + f.getClass().getSimpleName() + " failed to process player " + connectedPlayer.getName(), e);
|
||||
}
|
||||
}
|
||||
((ITabPlayer)connectedPlayer).markAsLoaded(true);
|
||||
TAB.getInstance().debug("Player join of " + connectedPlayer.getName() + " processed in " + (System.currentTimeMillis()-millis) + "ms");
|
||||
@@ -138,14 +137,7 @@ public class FeatureManagerImpl implements FeatureManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls onWorldChange(TabPlayer, String, String) on all features
|
||||
*
|
||||
* @param playerUUID
|
||||
* player who switched world
|
||||
* @param to
|
||||
* name of the new world
|
||||
*/
|
||||
@Override
|
||||
public void onWorldChange(UUID playerUUID, String to) {
|
||||
TabPlayer changed = TAB.getInstance().getPlayer(playerUUID);
|
||||
if (changed == null) return;
|
||||
@@ -157,17 +149,10 @@ public class FeatureManagerImpl implements FeatureManager {
|
||||
f.onWorldChange(changed, from, to);
|
||||
TAB.getInstance().getCPUManager().addTime(f, TabConstants.CpuUsageCategory.WORLD_SWITCH, System.nanoTime()-time);
|
||||
}
|
||||
((PlayerPlaceholder)TAB.getInstance().getPlaceholderManager().getPlaceholder("%world%")).updateValue(changed, to);
|
||||
((PlayerPlaceholder)TAB.getInstance().getPlaceholderManager().getPlaceholder(TabConstants.Placeholder.WORLD)).updateValue(changed, to);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls onServerChange(TabPlayer, String, String) on all features
|
||||
*
|
||||
* @param playerUUID
|
||||
* player who switched server
|
||||
* @param to
|
||||
* name of the new server
|
||||
*/
|
||||
@Override
|
||||
public void onServerChange(UUID playerUUID, String to) {
|
||||
TabPlayer changed = TAB.getInstance().getPlayer(playerUUID);
|
||||
if (changed == null) return;
|
||||
@@ -181,18 +166,10 @@ public class FeatureManagerImpl implements FeatureManager {
|
||||
f.onServerChange(changed, from, to);
|
||||
TAB.getInstance().getCPUManager().addTime(f, TabConstants.CpuUsageCategory.SERVER_SWITCH, System.nanoTime()-time);
|
||||
}
|
||||
((PlayerPlaceholder)TAB.getInstance().getPlaceholderManager().getPlaceholder("%server%")).updateValue(changed, to);
|
||||
((PlayerPlaceholder)TAB.getInstance().getPlaceholderManager().getPlaceholder(TabConstants.Placeholder.SERVER)).updateValue(changed, to);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls onCommand(TabPlayer, String) on all features
|
||||
*
|
||||
* @param sender
|
||||
* command sender
|
||||
* @param command
|
||||
* command line including /
|
||||
* @return {@code true} if command should be cancelled, {@code false} if not
|
||||
*/
|
||||
@Override
|
||||
public boolean onCommand(TabPlayer sender, String command) {
|
||||
if (sender == null) return false;
|
||||
boolean cancel = false;
|
||||
@@ -205,6 +182,16 @@ public class FeatureManagerImpl implements FeatureManager {
|
||||
return cancel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markObjective() {
|
||||
objectiveListeners = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markDisplayObjective() {
|
||||
displayObjectiveListeners = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls onPacketReceive(TabPlayer, Object) on all features
|
||||
*
|
||||
@@ -277,6 +264,7 @@ public class FeatureManagerImpl implements FeatureManager {
|
||||
* if reflective operation fails
|
||||
*/
|
||||
public void onDisplayObjective(TabPlayer packetReceiver, Object packet) throws ReflectiveOperationException {
|
||||
if (!displayObjectiveListeners) return;
|
||||
long time = System.nanoTime();
|
||||
PacketPlayOutScoreboardDisplayObjective display = TAB.getInstance().getPlatform().getPacketBuilder().readDisplayObjective(packet);
|
||||
TAB.getInstance().getCPUManager().addTime(TabConstants.Feature.PACKET_DESERIALIZING, TabConstants.CpuUsageCategory.PACKET_DISPLAY_OBJECTIVE, System.nanoTime()-time);
|
||||
@@ -297,6 +285,7 @@ public class FeatureManagerImpl implements FeatureManager {
|
||||
* if reflective operation fails
|
||||
*/
|
||||
public void onObjective(TabPlayer packetReceiver, Object packet) throws ReflectiveOperationException {
|
||||
if (!objectiveListeners) return;
|
||||
long time = System.nanoTime();
|
||||
PacketPlayOutScoreboardObjective display = TAB.getInstance().getPlatform().getPacketBuilder().readObjective(packet);
|
||||
TAB.getInstance().getCPUManager().addTime(TabConstants.Feature.PACKET_DESERIALIZING, TabConstants.CpuUsageCategory.PACKET_OBJECTIVE, System.nanoTime()-time);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package me.neznamy.tab.shared;
|
||||
|
||||
import me.neznamy.tab.api.TabConstants;
|
||||
import me.neznamy.tab.api.TabFeature;
|
||||
import me.neznamy.tab.api.TabPlayer;
|
||||
import me.neznamy.tab.shared.permission.PermissionPlugin;
|
||||
@@ -58,21 +59,22 @@ public class GroupManager extends TabFeature {
|
||||
*/
|
||||
private String getByPrimary(TabPlayer player) {
|
||||
try {
|
||||
return plugin.getPrimaryGroup(player);
|
||||
String group = plugin.getPrimaryGroup(player);
|
||||
return group == null ? TabConstants.NO_GROUP : group;
|
||||
} catch (Exception e) {
|
||||
TAB.getInstance().getErrorManager().printError("Failed to get permission group of " + player.getName() + " using " + plugin.getName() + " v" + plugin.getVersion(), e);
|
||||
return TabConstants.DEFAULT_GROUP;
|
||||
return TabConstants.NO_GROUP;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns player's permission group based on highest permission
|
||||
* or {@link TabConstants#DEFAULT_GROUP} if player has no permission.
|
||||
* or {@link TabConstants#NO_GROUP} if player has no permission.
|
||||
*
|
||||
* @param player
|
||||
* Player to get permission group of
|
||||
* @return Highest permission group player has permission for
|
||||
* or {@link TabConstants#DEFAULT_GROUP} if player does not have any
|
||||
* or {@link TabConstants#NO_GROUP} if player does not have any
|
||||
*/
|
||||
private String getByPermission(TabPlayer player) {
|
||||
for (String group : primaryGroupFindingList) {
|
||||
@@ -80,7 +82,7 @@ public class GroupManager extends TabFeature {
|
||||
return group;
|
||||
}
|
||||
}
|
||||
return TabConstants.DEFAULT_GROUP;
|
||||
return TabConstants.NO_GROUP;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
package me.neznamy.tab.shared;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
import me.neznamy.tab.api.Property;
|
||||
import me.neznamy.tab.api.ProtocolVersion;
|
||||
import me.neznamy.tab.api.TabFeature;
|
||||
import me.neznamy.tab.api.TabPlayer;
|
||||
import me.neznamy.tab.api.*;
|
||||
import me.neznamy.tab.api.chat.IChatBaseComponent;
|
||||
import me.neznamy.tab.api.placeholder.PlayerPlaceholder;
|
||||
import me.neznamy.tab.api.protocol.*;
|
||||
@@ -14,7 +12,6 @@ import me.neznamy.tab.api.protocol.PacketPlayOutChat.ChatMessageType;
|
||||
import me.neznamy.tab.api.team.TeamManager;
|
||||
import me.neznamy.tab.api.util.Preconditions;
|
||||
import me.neznamy.tab.shared.event.impl.PlayerLoadEventImpl;
|
||||
import me.neznamy.tab.shared.features.NickCompatibility;
|
||||
import org.geysermc.floodgate.api.FloodgateApi;
|
||||
|
||||
/**
|
||||
@@ -32,6 +29,9 @@ public abstract class ITabPlayer implements TabPlayer {
|
||||
/** Player's unique ID */
|
||||
private final UUID uniqueId;
|
||||
|
||||
/** Player's tablist UUID */
|
||||
private final UUID tabListId;
|
||||
|
||||
/**
|
||||
* World the player is currently in, {@code "N/A"} if TAB is
|
||||
* installed on proxy and bukkit bridge is not installed
|
||||
@@ -77,6 +77,9 @@ public abstract class ITabPlayer implements TabPlayer {
|
||||
/** Scoreboard objectives player has registered */
|
||||
private final List<String> registeredObjectives = new ArrayList<>();
|
||||
|
||||
/** Player's name as seen in GameProfile, can be altered by nick plugins */
|
||||
private String nickname;
|
||||
|
||||
/**
|
||||
* Constructs new instance with given parameters
|
||||
*
|
||||
@@ -92,16 +95,21 @@ public abstract class ITabPlayer implements TabPlayer {
|
||||
* Player's world
|
||||
* @param protocolVersion
|
||||
* Player's game version
|
||||
* @param useRealId
|
||||
* Whether tablist uses real uuid or offline
|
||||
*/
|
||||
protected ITabPlayer(Object player, UUID uniqueId, String name, String server, String world, int protocolVersion) {
|
||||
protected ITabPlayer(Object player, UUID uniqueId, String name, String server, String world, int protocolVersion, boolean useRealId) {
|
||||
this.player = player;
|
||||
this.uniqueId = uniqueId;
|
||||
this.name = name;
|
||||
this.nickname = name;
|
||||
this.server = server;
|
||||
this.world = world;
|
||||
this.version = ProtocolVersion.fromNetworkId(protocolVersion);
|
||||
this.bedrockPlayer = TAB.getInstance().isFloodgateInstalled() && FloodgateApi.getInstance() != null && FloodgateApi.getInstance().isFloodgatePlayer(uniqueId);
|
||||
this.permissionGroup = TAB.getInstance().getGroupManager().detectPermissionGroup(this);
|
||||
UUID offlineId = UUID.nameUUIDFromBytes(("OfflinePlayer:" + name).getBytes(StandardCharsets.UTF_8));
|
||||
this.tabListId = useRealId ? getUniqueId() : offlineId;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -133,6 +141,11 @@ public abstract class ITabPlayer implements TabPlayer {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setProperty(TabFeature feature, String identifier, String rawValue) {
|
||||
return setProperty(feature, identifier, rawValue, null, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets team name to given value
|
||||
*
|
||||
@@ -175,7 +188,7 @@ public abstract class ITabPlayer implements TabPlayer {
|
||||
Preconditions.checkNotNull(permissionGroup, "permissionGroup");
|
||||
if (this.permissionGroup.equals(permissionGroup)) return;
|
||||
this.permissionGroup = permissionGroup;
|
||||
((PlayerPlaceholder)TAB.getInstance().getPlaceholderManager().getPlaceholder("%group%")).updateValue(this, permissionGroup);
|
||||
((PlayerPlaceholder)TAB.getInstance().getPlaceholderManager().getPlaceholder(TabConstants.Placeholder.GROUP)).updateValue(this, permissionGroup);
|
||||
forceRefresh();
|
||||
}
|
||||
|
||||
@@ -233,12 +246,12 @@ public abstract class ITabPlayer implements TabPlayer {
|
||||
} else {
|
||||
component = new IChatBaseComponent(message);
|
||||
}
|
||||
sendCustomPacket(new PacketPlayOutChat(component, ChatMessageType.CHAT));
|
||||
sendCustomPacket(new PacketPlayOutChat(component, ChatMessageType.SYSTEM));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMessage(IChatBaseComponent message) {
|
||||
sendCustomPacket(new PacketPlayOutChat(message, ChatMessageType.CHAT));
|
||||
sendCustomPacket(new PacketPlayOutChat(message, ChatMessageType.SYSTEM));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -253,11 +266,12 @@ public abstract class ITabPlayer implements TabPlayer {
|
||||
|
||||
@Override
|
||||
public UUID getTablistUUID() {
|
||||
return uniqueId;
|
||||
return tabListId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forceRefresh() {
|
||||
if (!onJoinFinished) return;
|
||||
TAB.getInstance().getFeatureManager().refresh(this, true);
|
||||
}
|
||||
|
||||
@@ -277,7 +291,7 @@ public abstract class ITabPlayer implements TabPlayer {
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void sendCustomPacket(TabPacket packet) {
|
||||
public void sendCustomPacket(TabPacket packet) {
|
||||
if (packet == null) return;
|
||||
//avoiding BungeeCord bug kicking all players
|
||||
if (packet instanceof PacketPlayOutScoreboardTeam) {
|
||||
@@ -335,18 +349,6 @@ public abstract class ITabPlayer implements TabPlayer {
|
||||
sendCustomPacket(packet);
|
||||
if (feature != null) TAB.getInstance().getCPUManager().packetSent(feature);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendPacket(Object nmsPacket, TabFeature feature) {
|
||||
sendPacket(nmsPacket);
|
||||
if (feature != null) TAB.getInstance().getCPUManager().packetSent(feature.getFeatureName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendPacket(Object packet, String feature) {
|
||||
sendPacket(packet);
|
||||
if (feature != null) TAB.getInstance().getCPUManager().packetSent(feature);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Property getProperty(String name) {
|
||||
@@ -404,14 +406,13 @@ public abstract class ITabPlayer implements TabPlayer {
|
||||
public boolean isBedrockPlayer() {
|
||||
return bedrockPlayer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setProperty(TabFeature feature, String identifier, String rawValue) {
|
||||
return setProperty(feature, identifier, rawValue, null, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNickname() {
|
||||
return ((NickCompatibility) TAB.getInstance().getFeatureManager().getFeature(TabConstants.Feature.NICK_COMPATIBILITY)).getNickname(this);
|
||||
return nickname;
|
||||
}
|
||||
|
||||
public void setNickname(String nickname) {
|
||||
this.nickname = nickname;
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,10 @@
|
||||
package me.neznamy.tab.shared;
|
||||
|
||||
import me.neznamy.tab.api.TabPlayer;
|
||||
import me.neznamy.tab.api.chat.EnumChatFormat;
|
||||
import me.neznamy.tab.api.protocol.PacketBuilder;
|
||||
import me.neznamy.tab.shared.permission.PermissionPlugin;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
/**
|
||||
* An interface with methods that are called in universal code,
|
||||
@@ -48,6 +50,15 @@ public abstract class Platform {
|
||||
return packetBuilder;
|
||||
}
|
||||
|
||||
public void sendConsoleMessage(String message, boolean translateColors) {
|
||||
Object logger = TAB.getInstance().getLogger();
|
||||
if (logger instanceof java.util.logging.Logger) {
|
||||
((java.util.logging.Logger) logger).info(translateColors ? EnumChatFormat.color(message) : message);
|
||||
} else if (logger instanceof Logger) {
|
||||
((Logger) logger).info(translateColors ? EnumChatFormat.color(message) : message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects permission plugin and returns it's representing object
|
||||
*
|
||||
@@ -69,13 +80,6 @@ public abstract class Platform {
|
||||
*/
|
||||
public abstract void registerUnknownPlaceholder(String identifier);
|
||||
|
||||
/**
|
||||
* Returns {@code true} if this platform is a proxy, {@code false} if a game server
|
||||
*
|
||||
* @return {@code true} if this platform is a proxy, {@code false} if a game server
|
||||
*/
|
||||
public abstract boolean isProxy();
|
||||
|
||||
/**
|
||||
* Performs platform-specific plugin manager call and returns the result.
|
||||
* If plugin is not installed, returns {@code null}.
|
||||
|
||||
@@ -1,22 +1,6 @@
|
||||
package me.neznamy.tab.shared;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import me.neznamy.tab.api.chat.EnumChatFormat;
|
||||
import me.neznamy.tab.shared.event.EventBusImpl;
|
||||
import me.neznamy.tab.shared.event.impl.TabLoadEventImpl;
|
||||
import org.slf4j.Logger;
|
||||
import org.yaml.snakeyaml.error.YAMLException;
|
||||
|
||||
import me.neznamy.tab.api.HeaderFooterManager;
|
||||
import me.neznamy.tab.api.PropertyConfiguration;
|
||||
import me.neznamy.tab.api.ProtocolVersion;
|
||||
import me.neznamy.tab.api.TabAPI;
|
||||
import me.neznamy.tab.api.TabPlayer;
|
||||
import me.neznamy.tab.api.TablistFormatManager;
|
||||
import me.neznamy.tab.api.*;
|
||||
import me.neznamy.tab.api.bossbar.BossBarManager;
|
||||
import me.neznamy.tab.api.config.ConfigurationFile;
|
||||
import me.neznamy.tab.api.scoreboard.ScoreboardManager;
|
||||
@@ -24,20 +8,20 @@ import me.neznamy.tab.api.team.TeamManager;
|
||||
import me.neznamy.tab.shared.command.DisabledCommand;
|
||||
import me.neznamy.tab.shared.command.TabCommand;
|
||||
import me.neznamy.tab.shared.config.Configs;
|
||||
import me.neznamy.tab.shared.event.EventBusImpl;
|
||||
import me.neznamy.tab.shared.event.impl.TabLoadEventImpl;
|
||||
import me.neznamy.tab.shared.features.*;
|
||||
import me.neznamy.tab.shared.features.alignedplayerlist.AlignedPlayerList;
|
||||
import me.neznamy.tab.shared.features.BelowName;
|
||||
import me.neznamy.tab.shared.features.GhostPlayerFix;
|
||||
import me.neznamy.tab.shared.features.HeaderFooter;
|
||||
import me.neznamy.tab.shared.features.NickCompatibility;
|
||||
import me.neznamy.tab.shared.features.PingSpoof;
|
||||
import me.neznamy.tab.shared.features.PlaceholderManagerImpl;
|
||||
import me.neznamy.tab.shared.features.PlayerList;
|
||||
import me.neznamy.tab.shared.features.SpectatorFix;
|
||||
import me.neznamy.tab.shared.features.YellowNumber;
|
||||
import me.neznamy.tab.shared.features.layout.LayoutManager;
|
||||
import me.neznamy.tab.shared.features.nametags.NameTag;
|
||||
import me.neznamy.tab.shared.features.scoreboard.ScoreboardManagerImpl;
|
||||
import me.neznamy.tab.shared.features.sorting.Sorting;
|
||||
import org.yaml.snakeyaml.error.YAMLException;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* Main class of the plugin storing data and implementing API
|
||||
@@ -112,6 +96,9 @@ public class TAB extends TabAPI {
|
||||
/** Plugin's console logger provided by platform */
|
||||
private final Object logger;
|
||||
|
||||
/** File with YAML syntax error, which prevented plugin from loading */
|
||||
private String brokenFile;
|
||||
|
||||
/**
|
||||
* Constructs new instance with given parameters and sets this
|
||||
* new instance as {@link me.neznamy.tab.api.TabAPI} instance.
|
||||
@@ -162,11 +149,10 @@ public class TAB extends TabAPI {
|
||||
public String load() {
|
||||
try {
|
||||
long time = System.currentTimeMillis();
|
||||
this.errorManager = new ErrorManager();
|
||||
errorManager = new ErrorManager();
|
||||
cpu = new CpuManager();
|
||||
featureManager = new FeatureManagerImpl();
|
||||
configuration = new Configs(this);
|
||||
configuration.loadFiles();
|
||||
configuration = new Configs();
|
||||
featureManager.registerFeature(TabConstants.Feature.PLACEHOLDER_MANAGER, new PlaceholderManagerImpl());
|
||||
featureManager.registerFeature(TabConstants.Feature.GROUP_MANAGER, new GroupManager(platform.detectPermissionPlugin()));
|
||||
platform.loadFeatures();
|
||||
@@ -182,7 +168,8 @@ public class TAB extends TabAPI {
|
||||
} catch (YAMLException e) {
|
||||
sendConsoleMessage("&cDid not enable due to a broken configuration file.", true);
|
||||
kill();
|
||||
return configuration.getReloadFailedMessage();
|
||||
return (configuration == null ? "&4Failed to reload, file %file% has broken syntax. Check console for more info."
|
||||
: configuration.getMessages().getReloadFailBrokenFile()).replace("%file%", brokenFile);
|
||||
} catch (Exception e) {
|
||||
errorManager.criticalError("Failed to enable. Did you just invent a new way to break the plugin by misconfiguring it?", e);
|
||||
kill();
|
||||
@@ -201,7 +188,7 @@ public class TAB extends TabAPI {
|
||||
if (configuration.getMysql() != null) configuration.getMysql().closeConnection();
|
||||
featureManager.unload();
|
||||
sendConsoleMessage("&aDisabled in " + (System.currentTimeMillis()-time) + "ms", true);
|
||||
} catch (Exception e) {
|
||||
} catch (Exception | NoClassDefFoundError e) {
|
||||
errorManager.criticalError("Failed to disable", e);
|
||||
}
|
||||
kill();
|
||||
@@ -350,15 +337,6 @@ public class TAB extends TabAPI {
|
||||
return configuration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@link #disabled}
|
||||
*
|
||||
* @return {@link #disabled}
|
||||
*/
|
||||
public boolean isDisabled() {
|
||||
return disabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@link #command}
|
||||
*
|
||||
@@ -395,6 +373,15 @@ public class TAB extends TabAPI {
|
||||
return dataFolder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@link #logger}
|
||||
*
|
||||
* @return {@link #logger}
|
||||
*/
|
||||
public Object getLogger() {
|
||||
return logger;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EventBusImpl getEventBus() {
|
||||
return eventBus;
|
||||
@@ -441,11 +428,7 @@ public class TAB extends TabAPI {
|
||||
|
||||
@Override
|
||||
public void sendConsoleMessage(String message, boolean translateColors) {
|
||||
if (logger instanceof java.util.logging.Logger) {
|
||||
((java.util.logging.Logger) logger).info(translateColors ? EnumChatFormat.color(message) : message);
|
||||
} else if (logger instanceof Logger) {
|
||||
((Logger) logger).info(translateColors ? EnumChatFormat.color(message) : message);
|
||||
}
|
||||
platform.sendConsoleMessage(message, translateColors);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -485,7 +468,7 @@ public class TAB extends TabAPI {
|
||||
|
||||
@Override
|
||||
public void setBrokenFile(String file) {
|
||||
configuration.setBrokenFile(file);
|
||||
this.brokenFile = file;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -505,6 +488,11 @@ public class TAB extends TabAPI {
|
||||
|
||||
@Override
|
||||
public void debug(String message) {
|
||||
if (configuration.isDebugMode()) sendConsoleMessage("&9[DEBUG] " + message, true);
|
||||
if (configuration != null && configuration.isDebugMode()) sendConsoleMessage("&9[DEBUG] " + message, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPluginDisabled() {
|
||||
return disabled;
|
||||
}
|
||||
}
|
||||
@@ -1,100 +0,0 @@
|
||||
package me.neznamy.tab.shared;
|
||||
|
||||
import me.neznamy.tab.api.TabFeature;
|
||||
import me.neznamy.tab.api.task.RepeatingTask;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
/**
|
||||
* Implementation of RepeatingTask interface which submits provided task
|
||||
* to TAB's processing thread in configured interval.
|
||||
*/
|
||||
public class TabRepeatingTask implements RepeatingTask {
|
||||
|
||||
/** Executor service to submit the repeating task to */
|
||||
private final ExecutorService exe;
|
||||
|
||||
/** Task to run periodically */
|
||||
private final Runnable runnable;
|
||||
|
||||
/** Feature creating this task, used in cpu command output */
|
||||
private final TabFeature feature;
|
||||
|
||||
/** Sub-feature creating this task, used in cpu command output */
|
||||
private final String type;
|
||||
|
||||
/** Interval in milliseconds how often to submit the task to main thread */
|
||||
private int interval;
|
||||
|
||||
/** Task pointer returned by executor service to allow this task to be cancelled */
|
||||
private Future<?> task;
|
||||
|
||||
/**
|
||||
* Constructs new instance with given parameters and starts the task.
|
||||
*
|
||||
* @param exe
|
||||
* Executor service to submit the repeating task to
|
||||
* @param runnable
|
||||
* Task to run periodically
|
||||
* @param feature
|
||||
* Feature creating this task, used in cpu command output
|
||||
* @param type
|
||||
* Sub-feature creating this task, used in cpu command output
|
||||
* @param interval
|
||||
* Interval in milliseconds how often to submit the task to main thread
|
||||
*/
|
||||
public TabRepeatingTask(ExecutorService exe, Runnable runnable, TabFeature feature, String type, int interval) {
|
||||
if (interval < 0) throw new IllegalArgumentException("Interval cannot be negative");
|
||||
this.exe = exe;
|
||||
this.runnable = runnable;
|
||||
this.feature = feature;
|
||||
this.type = type;
|
||||
this.interval = interval;
|
||||
createTask();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the repeating task and submits it to executor service.
|
||||
*/
|
||||
private void createTask() {
|
||||
task = exe.submit(() -> {
|
||||
long nextLoop = System.currentTimeMillis();
|
||||
while (true) {
|
||||
try {
|
||||
nextLoop += interval;
|
||||
long sleep = nextLoop - System.currentTimeMillis();
|
||||
if (sleep > interval) sleep = interval; //servers who travel back in time
|
||||
if (sleep > 0) Thread.sleep(sleep);
|
||||
if (feature != null) {
|
||||
TAB.getInstance().getCPUManager().runMeasuredTask(feature, type, runnable);
|
||||
} else {
|
||||
TAB.getInstance().getCPUManager().runTask(runnable);
|
||||
}
|
||||
} catch (InterruptedException pluginDisabled) {
|
||||
Thread.currentThread().interrupt();
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInterval() {
|
||||
return interval;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInterval(int interval) {
|
||||
if (interval < 0) throw new IllegalArgumentException("Interval cannot be negative");
|
||||
//restarting task to break sleep in case of interval reduction
|
||||
cancel();
|
||||
this.interval = interval;
|
||||
createTask();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
task.cancel(true);
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@ package me.neznamy.tab.shared.command;
|
||||
import me.neznamy.tab.api.TabPlayer;
|
||||
import me.neznamy.tab.api.bossbar.BossBarManager;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.shared.TabConstants;
|
||||
import me.neznamy.tab.api.TabConstants;
|
||||
|
||||
/**
|
||||
* Handler for "/tab bossbar" subcommand
|
||||
|
||||
@@ -12,7 +12,7 @@ import me.neznamy.tab.api.chat.EnumChatFormat;
|
||||
import me.neznamy.tab.api.chat.IChatBaseComponent;
|
||||
import me.neznamy.tab.api.placeholder.Placeholder;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.shared.TabConstants;
|
||||
import me.neznamy.tab.api.TabConstants;
|
||||
|
||||
/**
|
||||
* Handler for "/tab cpu" subcommand
|
||||
@@ -20,9 +20,7 @@ import me.neznamy.tab.shared.TabConstants;
|
||||
public class CpuCommand extends SubCommand {
|
||||
|
||||
private final DecimalFormat decimal3 = new DecimalFormat("#.###");
|
||||
|
||||
private static final char LINE_CHAR = (char)9553;
|
||||
private static final String SEPARATOR = "&8&l" + LINE_CHAR + "&8&m ";
|
||||
private final char LINE_CHAR = (char)9553;
|
||||
|
||||
/**
|
||||
* Constructs new instance
|
||||
@@ -33,6 +31,7 @@ public class CpuCommand extends SubCommand {
|
||||
|
||||
@Override
|
||||
public void execute(TabPlayer sender, String[] args) {
|
||||
String SEPARATOR = "&8&l" + LINE_CHAR + "&8&m ";
|
||||
TAB tab = TAB.getInstance();
|
||||
Map<String, Float> placeholders = tab.getCPUManager().getPlaceholderUsage();
|
||||
double placeholdersTotal = placeholders.values().stream().mapToDouble(Float::floatValue).sum();
|
||||
@@ -77,7 +76,7 @@ public class CpuCommand extends SubCommand {
|
||||
if (printCounter++ == 5) break;
|
||||
String refresh = "";
|
||||
Placeholder p = TAB.getInstance().getPlaceholderManager().getPlaceholder(entry.getKey());
|
||||
if (p != null && !p.isTriggerMode()) refresh = " &8(" + p.getRefresh() + ")&7";
|
||||
if (p != null && p.getRefresh() != -1) refresh = " &8(" + p.getRefresh() + ")&7";
|
||||
String colorized = entry.getKey().startsWith("%sync:") ? "&c" + decimal3.format(entry.getValue()) : colorize(decimal3.format(entry.getValue()), 1, 0.3f);
|
||||
sendMessage(sender, String.format("&8&l%s &7%s - %s%%", LINE_CHAR, entry.getKey() + refresh, colorized));
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import me.neznamy.tab.api.TabPlayer;
|
||||
import me.neznamy.tab.api.chat.EnumChatFormat;
|
||||
import me.neznamy.tab.shared.DynamicText;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.shared.TabConstants;
|
||||
import me.neznamy.tab.api.TabConstants;
|
||||
import me.neznamy.tab.shared.features.PlayerList;
|
||||
import me.neznamy.tab.shared.features.nametags.NameTag;
|
||||
|
||||
@@ -126,7 +126,7 @@ public class DebugCommand extends SubCommand {
|
||||
*/
|
||||
private String getGroup(TabPlayer analyzed) {
|
||||
if (TAB.getInstance().getGroupManager().isGroupsByPermissions()) {
|
||||
return "&eHighest permission for group: &a" + analyzed.getGroup();
|
||||
return "&eHighest group permission: &8tab.group.&a" + analyzed.getGroup();
|
||||
}
|
||||
return "&ePrimary permission group: &a" + analyzed.getGroup();
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package me.neznamy.tab.shared.command;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import me.neznamy.tab.api.ProtocolVersion;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
|
||||
/**
|
||||
@@ -32,7 +33,7 @@ public class DisabledCommand {
|
||||
}
|
||||
} else {
|
||||
if (hasAdminPermission) {
|
||||
String command = !TAB.getInstance().getPlatform().isProxy() ? "/tab" : "/btab";
|
||||
String command = TAB.getInstance().getServerVersion() != ProtocolVersion.PROXY ? "/tab" : "/btab";
|
||||
messages.add("&m ");
|
||||
messages.add(" &cPlugin is disabled due to an error. Check console for more details.");
|
||||
messages.add(" &8>> &3&l" + command + " reload");
|
||||
|
||||
@@ -5,7 +5,7 @@ import java.util.stream.Collectors;
|
||||
|
||||
import me.neznamy.tab.api.TabPlayer;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.shared.TabConstants;
|
||||
import me.neznamy.tab.api.TabConstants;
|
||||
|
||||
/**
|
||||
* Handler for "/tab group" subcommand
|
||||
@@ -41,11 +41,11 @@ public class GroupCommand extends PropertyCommand {
|
||||
String server = null;
|
||||
if (args[args.length-2].equals("-w")) {
|
||||
world = args[args.length-1];
|
||||
value = value.substring(0, value.length()-world.length()-4);
|
||||
value = value.startsWith("-w") ? "" : value.substring(0, value.length()-world.length()-4);
|
||||
}
|
||||
if (args[args.length-2].equals("-s")) {
|
||||
server = args[args.length-1];
|
||||
value = value.substring(0, value.length()-server.length()-4);
|
||||
value = value.startsWith("-s") ? "" : value.substring(0, value.length()-server.length()-4);
|
||||
}
|
||||
if ((value.startsWith("\"") && value.endsWith("\"")) || (value.startsWith("'") && value.endsWith("'"))) {
|
||||
value = value.substring(1, value.length()-1);
|
||||
@@ -54,7 +54,7 @@ public class GroupCommand extends PropertyCommand {
|
||||
if (hasPermission(sender, TabConstants.Permission.COMMAND_DATA_REMOVE)) {
|
||||
TAB.getInstance().getConfiguration().getGroups().remove(group);
|
||||
for (TabPlayer pl : TAB.getInstance().getOnlinePlayers()) {
|
||||
if (pl.getGroup().equals(group) || "_DEFAULT_".equals(group)){
|
||||
if (pl.getGroup().equals(group) || TabConstants.DEFAULT_GROUP.equals(group)){
|
||||
pl.forceRefresh();
|
||||
}
|
||||
}
|
||||
@@ -123,7 +123,7 @@ public class GroupCommand extends PropertyCommand {
|
||||
if (property.length > 0 && String.valueOf(value.length() == 0 ? null : value).equals(String.valueOf(property[0]))) return;
|
||||
TAB.getInstance().getConfiguration().getGroups().setProperty(group, type, server, world, value.length() == 0 ? null : value);
|
||||
for (TabPlayer pl : TAB.getInstance().getOnlinePlayers()) {
|
||||
if (pl.getGroup().equals(group) || "_DEFAULT_".equals(group)){
|
||||
if (pl.getGroup().equals(group) || TabConstants.DEFAULT_GROUP.equals(group)){
|
||||
pl.forceRefresh();
|
||||
}
|
||||
}
|
||||
@@ -133,7 +133,7 @@ public class GroupCommand extends PropertyCommand {
|
||||
public List<String> complete(TabPlayer sender, String[] arguments) {
|
||||
if (arguments.length == 1) {
|
||||
Set<String> groups = new HashSet<>(TAB.getInstance().getConfiguration().getGroups().getAllEntries());
|
||||
groups.add("_DEFAULT_");
|
||||
groups.add(TabConstants.DEFAULT_GROUP);
|
||||
return groups.stream().filter(group -> group.toLowerCase().startsWith(arguments[0].toLowerCase())).collect(Collectors.toList());
|
||||
}
|
||||
return super.complete(sender, arguments);
|
||||
|
||||
@@ -2,7 +2,7 @@ package me.neznamy.tab.shared.command;
|
||||
|
||||
import me.neznamy.tab.api.TabPlayer;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.shared.TabConstants;
|
||||
import me.neznamy.tab.api.TabConstants;
|
||||
|
||||
/**
|
||||
* Handler for "/tab groups" subcommand
|
||||
|
||||
@@ -3,7 +3,7 @@ package me.neznamy.tab.shared.command;
|
||||
import me.neznamy.tab.api.PropertyConfiguration;
|
||||
import me.neznamy.tab.api.TabPlayer;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.shared.TabConstants;
|
||||
import me.neznamy.tab.api.TabConstants;
|
||||
import me.neznamy.tab.shared.config.Configs;
|
||||
import me.neznamy.tab.shared.config.MySQL;
|
||||
import me.neznamy.tab.shared.config.file.YamlPropertyConfigurationFile;
|
||||
|
||||
@@ -3,7 +3,7 @@ package me.neznamy.tab.shared.command;
|
||||
import me.neznamy.tab.api.TabPlayer;
|
||||
import me.neznamy.tab.api.team.TeamManager;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.shared.TabConstants;
|
||||
import me.neznamy.tab.api.TabConstants;
|
||||
import me.neznamy.tab.shared.features.nametags.unlimited.NameTagX;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
@@ -11,7 +11,7 @@ import me.neznamy.tab.api.chat.IChatBaseComponent;
|
||||
import me.neznamy.tab.api.placeholder.Placeholder;
|
||||
import me.neznamy.tab.shared.DynamicText;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.shared.TabConstants;
|
||||
import me.neznamy.tab.api.TabConstants;
|
||||
|
||||
/**
|
||||
* Handler for "/tab parse <player> <placeholder>" subcommand
|
||||
|
||||
@@ -5,7 +5,7 @@ import java.util.List;
|
||||
|
||||
import me.neznamy.tab.api.TabPlayer;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.shared.TabConstants;
|
||||
import me.neznamy.tab.api.TabConstants;
|
||||
|
||||
/**
|
||||
* Handler for "/tab player" subcommand
|
||||
@@ -33,11 +33,11 @@ public class PlayerCommand extends PropertyCommand {
|
||||
String server = null;
|
||||
if (args[args.length-2].equals("-w")) {
|
||||
world = args[args.length-1];
|
||||
value = value.substring(0, value.length()-world.length()-4);
|
||||
value = value.startsWith("-w") ? "" : value.substring(0, value.length()-world.length()-4);
|
||||
}
|
||||
if (args[args.length-2].equals("-s")) {
|
||||
server = args[args.length-1];
|
||||
value = value.substring(0, value.length()-server.length()-4);
|
||||
value = value.startsWith("-s") ? "" : value.substring(0, value.length()-server.length()-4);
|
||||
}
|
||||
if ((value.startsWith("\"") && value.endsWith("\"")) || (value.startsWith("'") && value.endsWith("'"))) {
|
||||
value = value.substring(1, value.length()-1);
|
||||
|
||||
@@ -5,7 +5,7 @@ import java.util.List;
|
||||
|
||||
import me.neznamy.tab.api.TabPlayer;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.shared.TabConstants;
|
||||
import me.neznamy.tab.api.TabConstants;
|
||||
|
||||
/**
|
||||
* Handler for "/tab playeruuid" subcommand
|
||||
@@ -38,11 +38,11 @@ public class PlayerUUIDCommand extends PropertyCommand {
|
||||
String server = null;
|
||||
if (args[args.length-2].equals("-w")) {
|
||||
world = args[args.length-1];
|
||||
value = value.substring(0, value.length()-world.length()-4);
|
||||
value = value.startsWith("-w") ? "" : value.substring(0, value.length()-world.length()-4);
|
||||
}
|
||||
if (args[args.length-2].equals("-s")) {
|
||||
server = args[args.length-1];
|
||||
value = value.substring(0, value.length()-server.length()-4);
|
||||
value = value.startsWith("-s") ? "" : value.substring(0, value.length()-server.length()-4);
|
||||
}
|
||||
if ((value.startsWith("\"") && value.endsWith("\"")) || (value.startsWith("'") && value.endsWith("'"))) {
|
||||
value = value.substring(1, value.length()-1);
|
||||
|
||||
@@ -2,7 +2,7 @@ package me.neznamy.tab.shared.command;
|
||||
|
||||
import me.neznamy.tab.api.TabPlayer;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.shared.TabConstants;
|
||||
import me.neznamy.tab.api.TabConstants;
|
||||
|
||||
/**
|
||||
* Handler for "/tab reload" subcommand
|
||||
|
||||
@@ -8,7 +8,7 @@ import java.util.List;
|
||||
import me.neznamy.tab.api.TabPlayer;
|
||||
import me.neznamy.tab.api.scoreboard.Scoreboard;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.shared.TabConstants;
|
||||
import me.neznamy.tab.api.TabConstants;
|
||||
import me.neznamy.tab.shared.features.scoreboard.ScoreboardManagerImpl;
|
||||
|
||||
/**
|
||||
@@ -40,6 +40,7 @@ public class ScoreboardCommand extends SubCommand {
|
||||
return;
|
||||
}
|
||||
TabPlayer p = getTarget(sender, args);
|
||||
if (p == null) return;
|
||||
if (scoreboard.getOtherPluginScoreboards().containsKey(p)) return; //not overriding other plugins
|
||||
boolean silent = args.length >= 3 && args[2].equals("-s");
|
||||
switch(args[0]) {
|
||||
@@ -88,6 +89,10 @@ public class ScoreboardCommand extends SubCommand {
|
||||
sendMessage(sender, getMessages().getNoPermission());
|
||||
return;
|
||||
}
|
||||
if (sender == null) {
|
||||
sendMessage(sender, getMessages().getCommandOnlyFromGame());
|
||||
return;
|
||||
}
|
||||
target = sender;
|
||||
} else {
|
||||
if (!hasPermission(sender,TabConstants.Permission.COMMAND_SCOREBOARD_SHOW_OTHER)) {
|
||||
@@ -104,15 +109,20 @@ public class ScoreboardCommand extends SubCommand {
|
||||
}
|
||||
|
||||
private TabPlayer getTarget(TabPlayer sender, String[] args) {
|
||||
TabPlayer target = sender;
|
||||
if (args.length >= 2 && TAB.getInstance().getPlayer(args[1]) != null) {
|
||||
if (hasPermission(sender, TabConstants.Permission.COMMAND_SCOREBOARD_TOGGLE_OTHER)) {
|
||||
target = TAB.getInstance().getPlayer(args[1]);
|
||||
return TAB.getInstance().getPlayer(args[1]);
|
||||
} else {
|
||||
sendMessage(sender, getMessages().getNoPermission());
|
||||
}
|
||||
} else {
|
||||
if (hasPermission(sender, TabConstants.Permission.COMMAND_SCOREBOARD_TOGGLE)) {
|
||||
return sender;
|
||||
} else {
|
||||
sendMessage(sender, getMessages().getNoPermission());
|
||||
}
|
||||
}
|
||||
return target;
|
||||
return null;
|
||||
}
|
||||
|
||||
private ScoreboardManagerImpl getScoreboardManager() {
|
||||
|
||||
@@ -7,7 +7,7 @@ import java.util.List;
|
||||
import me.neznamy.tab.api.TabPlayer;
|
||||
import me.neznamy.tab.api.team.TeamManager;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.shared.TabConstants;
|
||||
import me.neznamy.tab.api.TabConstants;
|
||||
|
||||
public class SetCollisionCommand extends SubCommand {
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import java.util.stream.Collectors;
|
||||
|
||||
import me.neznamy.tab.api.TabPlayer;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.shared.TabConstants;
|
||||
import me.neznamy.tab.api.TabConstants;
|
||||
import me.neznamy.tab.shared.config.MessageFile;
|
||||
/**
|
||||
* Abstract class representing a subcommand of "/tab" command
|
||||
|
||||
@@ -6,11 +6,12 @@ import java.util.List;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import me.neznamy.tab.api.ProtocolVersion;
|
||||
import me.neznamy.tab.api.TabPlayer;
|
||||
import me.neznamy.tab.api.chat.EnumChatFormat;
|
||||
import me.neznamy.tab.api.chat.IChatBaseComponent;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.shared.TabConstants;
|
||||
import me.neznamy.tab.api.TabConstants;
|
||||
|
||||
/**
|
||||
* The core command handler
|
||||
@@ -38,6 +39,7 @@ public class TabCommand extends SubCommand {
|
||||
registerSubCommand(new SetCollisionCommand());
|
||||
registerSubCommand(new ScoreboardCommand());
|
||||
registerSubCommand(new WidthCommand());
|
||||
//registerSubCommand(new WidthCheckCommand());
|
||||
List<String> properties = Lists.newArrayList(TabConstants.Property.TABPREFIX, TabConstants.Property.TABSUFFIX, TabConstants.Property.TAGPREFIX, TabConstants.Property.TAGSUFFIX, TabConstants.Property.CUSTOMTABNAME, TabConstants.Property.ABOVENAME, TabConstants.Property.BELOWNAME, TabConstants.Property.CUSTOMTAGNAME);
|
||||
properties.addAll(((DebugCommand) getSubcommands().get("debug")).getExtraLines());
|
||||
SubCommand.setAllProperties(properties.toArray(new String[0]));
|
||||
@@ -80,7 +82,7 @@ public class TabCommand extends SubCommand {
|
||||
TAB.getInstance().sendConsoleMessage("&3TAB v" + TabConstants.PLUGIN_VERSION, true);
|
||||
}
|
||||
for (String message : getMessages().getHelpMenu()) {
|
||||
if (TAB.getInstance().getPlatform().isProxy()) message = message.replace("/tab", "/btab");
|
||||
if (TAB.getInstance().getServerVersion() == ProtocolVersion.PROXY) message = message.replace("/tab", "/btab");
|
||||
sendMessage(sender, message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
package me.neznamy.tab.shared.command;
|
||||
|
||||
import me.neznamy.tab.api.TabConstants;
|
||||
import me.neznamy.tab.api.TabPlayer;
|
||||
import me.neznamy.tab.api.chat.EnumChatFormat;
|
||||
import me.neznamy.tab.api.chat.IChatBaseComponent;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Handler for "/tab width" subcommand
|
||||
*/
|
||||
public class WidthCheckCommand extends SubCommand {
|
||||
|
||||
private final byte[] widths = loadWidths();
|
||||
|
||||
/**
|
||||
* Constructs new instance
|
||||
*/
|
||||
public WidthCheckCommand() {
|
||||
super("widthcheck", TabConstants.Permission.COMMAND_WIDTH);
|
||||
}
|
||||
|
||||
private byte[] loadWidths() {
|
||||
byte[] widths = new byte[65536];
|
||||
InputStream file = getClass().getClassLoader().getResourceAsStream("widths.txt");
|
||||
if (file == null) {
|
||||
TAB.getInstance().getErrorManager().criticalError("Failed to load widths.txt file. Is it inside the jar? Aligned suffix will not work.", null);
|
||||
return widths;
|
||||
}
|
||||
int characterId = 1;
|
||||
for (String line : new BufferedReader(new InputStreamReader(file)).lines().collect(Collectors.toList())) {
|
||||
widths[characterId++] = (byte) Float.parseFloat(line);
|
||||
}
|
||||
Map<Integer, Integer> widthOverrides = TAB.getInstance().getConfiguration().getConfig().getConfigurationSection("tablist-name-formatting.character-width-overrides");
|
||||
for (Map.Entry<Integer, Integer> entry : widthOverrides.entrySet()) {
|
||||
widths[entry.getKey()] = entry.getValue().byteValue();
|
||||
}
|
||||
return widths;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(TabPlayer sender, String[] args) {
|
||||
if (sender == null) {
|
||||
sendMessage(null, getMessages().getCommandOnlyFromGame());
|
||||
return;
|
||||
}
|
||||
if (args.length == 1) {
|
||||
int i = Integer.parseInt(args[0]);
|
||||
if (i > Character.MAX_VALUE) {
|
||||
sendMessage(sender, "&cCharacter ID out of range: 0-" + (int) Character.MAX_VALUE);
|
||||
return;
|
||||
}
|
||||
int ROWS = 15;
|
||||
int COLUMNS = 10;
|
||||
StringBuilder line = new StringBuilder();
|
||||
for (int row = 0; row < ROWS; row++) {
|
||||
line.append(".");
|
||||
for (int column = 0; column < COLUMNS; column++) {
|
||||
int character = row*COLUMNS+column + i;
|
||||
if (character >= Character.MAX_VALUE) continue;
|
||||
line.append(buildSpaces(21-widths[character]));
|
||||
line.append((char)character);
|
||||
line.append("&e|&r");
|
||||
}
|
||||
line.append(" ").append(row * COLUMNS + i).append("-").append((row + 1) * COLUMNS + i - 1).append("\n");
|
||||
}
|
||||
IChatBaseComponent msg = IChatBaseComponent.fromColoredText(line + "§7§l[Previous]");
|
||||
msg.getModifier().onClickRunCommand("/tab widthcheck " + (i-ROWS*COLUMNS));
|
||||
IChatBaseComponent next = new IChatBaseComponent(" §7§l[Next]");
|
||||
next.getModifier().onClickRunCommand("/tab widthcheck " + (i+ROWS*COLUMNS));
|
||||
msg.addExtra(next);
|
||||
sender.sendMessage(msg);
|
||||
}
|
||||
}
|
||||
|
||||
private String buildSpaces(int pixelWidth) {
|
||||
if (pixelWidth < 12) throw new IllegalArgumentException("Cannot build space lower than 12 pixels wide (" + pixelWidth + ")");
|
||||
int pixelsLeft = pixelWidth;
|
||||
StringBuilder output = new StringBuilder();
|
||||
while (pixelsLeft % 5 != 0) {
|
||||
pixelsLeft -= 4;
|
||||
output.append(' ');
|
||||
}
|
||||
output.append(EnumChatFormat.COLOR_CHAR);
|
||||
output.append('l');
|
||||
while (pixelsLeft > 0) {
|
||||
pixelsLeft -= 5;
|
||||
output.append(' ');
|
||||
}
|
||||
output.append(EnumChatFormat.COLOR_CHAR);
|
||||
output.append('r');
|
||||
return output.toString();
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import me.neznamy.tab.api.TabPlayer;
|
||||
import me.neznamy.tab.api.chat.EnumChatFormat;
|
||||
import me.neznamy.tab.api.chat.IChatBaseComponent;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.shared.TabConstants;
|
||||
import me.neznamy.tab.api.TabConstants;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@@ -152,7 +152,7 @@ public class WidthCommand extends SubCommand {
|
||||
|
||||
public void sendWidth(TabPlayer sender, char character, int amount) {
|
||||
List<IChatBaseComponent> messages = new ArrayList<>();
|
||||
IChatBaseComponent charMessage = new IChatBaseComponent(EnumChatFormat.color("&2" + character + " &d|"));
|
||||
IChatBaseComponent charMessage = new IChatBaseComponent(EnumChatFormat.color("|&2" + character + " &d|"));
|
||||
|
||||
messages.add(new IChatBaseComponent(EnumChatFormat.color("&b[TAB] Click the line with closest width &7(ID: &f" + (int) character + "&7)")));
|
||||
|
||||
@@ -188,7 +188,7 @@ public class WidthCommand extends SubCommand {
|
||||
pixelsRemaining -= 2;
|
||||
text.append('i');
|
||||
}
|
||||
IChatBaseComponent component = new IChatBaseComponent(EnumChatFormat.color("&b&k" + text + " &e|&b (" + width + " pixels) &7&l[Click to apply]"));
|
||||
IChatBaseComponent component = new IChatBaseComponent(EnumChatFormat.color("|&b&k" + text + " &e|&b (" + width + " pixels) &7&l[Click to apply]"));
|
||||
component.getModifier().onClickRunCommand("/tab width set " + c + " " + width);
|
||||
component.getModifier().onHoverShowText(new IChatBaseComponent("Click to set width to " + width + " pixels"));
|
||||
return component;
|
||||
|
||||
@@ -8,9 +8,8 @@ import me.neznamy.tab.api.TabPlayer;
|
||||
import me.neznamy.tab.api.bossbar.BossBar;
|
||||
import me.neznamy.tab.api.bossbar.BossBarManager;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.shared.TabConstants;
|
||||
import me.neznamy.tab.api.TabConstants;
|
||||
import me.neznamy.tab.shared.command.SubCommand;
|
||||
import me.neznamy.tab.shared.features.bossbar.BossBarLine;
|
||||
|
||||
/**
|
||||
* Handler for "/tab announce bar" subcommand
|
||||
@@ -48,7 +47,7 @@ public class AnnounceBarCommand extends SubCommand {
|
||||
sendMessage(sender, getMessages().getBossBarNotFound(barName));
|
||||
return;
|
||||
}
|
||||
if (!((BossBarLine)bar).isAnnouncementOnly()) {
|
||||
if (!bar.isAnnouncementBar()) {
|
||||
sendMessage(sender, getMessages().getBossBarNotMarkedAsAnnouncement());
|
||||
return;
|
||||
}
|
||||
@@ -66,8 +65,9 @@ public class AnnounceBarCommand extends SubCommand {
|
||||
if (b == null) return new ArrayList<>();
|
||||
List<String> suggestions = new ArrayList<>();
|
||||
if (arguments.length == 1) {
|
||||
for (String bar : b.getRegisteredBossBars().keySet()) {
|
||||
if (bar.toLowerCase().startsWith(arguments[0].toLowerCase())) suggestions.add(bar);
|
||||
for (BossBar bar : b.getRegisteredBossBars().values()) {
|
||||
if (bar.getName().toLowerCase().startsWith(arguments[0].toLowerCase()) &&
|
||||
bar.isAnnouncementBar()) suggestions.add(bar.getName());
|
||||
}
|
||||
} else if (arguments.length == 2 && b.getBossBar(arguments[0]) != null){
|
||||
for (String time : Arrays.asList("5", "10", "30", "60", "120")) {
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ import me.neznamy.tab.api.TabPlayer;
|
||||
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.TabConstants;
|
||||
import me.neznamy.tab.api.TabConstants;
|
||||
import me.neznamy.tab.shared.command.SubCommand;
|
||||
|
||||
/**
|
||||
|
||||
@@ -8,9 +8,8 @@ import me.neznamy.tab.api.TabPlayer;
|
||||
import me.neznamy.tab.api.bossbar.BossBar;
|
||||
import me.neznamy.tab.api.bossbar.BossBarManager;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.shared.TabConstants;
|
||||
import me.neznamy.tab.api.TabConstants;
|
||||
import me.neznamy.tab.shared.command.SubCommand;
|
||||
import me.neznamy.tab.shared.features.bossbar.BossBarLine;
|
||||
|
||||
/**
|
||||
* Handler for "/tab announce bar" subcommand
|
||||
@@ -53,7 +52,7 @@ public class SendBarCommand extends SubCommand {
|
||||
sendMessage(sender, getMessages().getBossBarNotFound(barName));
|
||||
return;
|
||||
}
|
||||
if (!((BossBarLine)bar).isAnnouncementOnly()) {
|
||||
if (!bar.isAnnouncementBar()) {
|
||||
sendMessage(sender, getMessages().getBossBarNotMarkedAsAnnouncement());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package me.neznamy.tab.shared.config;
|
||||
|
||||
import me.neznamy.tab.api.PropertyConfiguration;
|
||||
import me.neznamy.tab.api.ProtocolVersion;
|
||||
import me.neznamy.tab.api.config.ConfigurationFile;
|
||||
import me.neznamy.tab.api.config.YamlConfigurationFile;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
@@ -19,33 +20,27 @@ import java.util.List;
|
||||
*/
|
||||
public class Configs {
|
||||
|
||||
private final TAB tab;
|
||||
|
||||
private final Converter converter = new Converter();
|
||||
|
||||
//config.yml file
|
||||
private ConfigurationFile config;
|
||||
private final ConfigurationFile config = new YamlConfigurationFile(getClass().getClassLoader().getResourceAsStream(TAB.getInstance().getPlatform().getConfigName()),
|
||||
new File(TAB.getInstance().getDataFolder(), "config.yml"));
|
||||
|
||||
private boolean bukkitPermissions;
|
||||
|
||||
//hidden config options
|
||||
private boolean unregisterBeforeRegister;
|
||||
private boolean removeGhostPlayers;
|
||||
private boolean pipelineInjection;
|
||||
private final boolean bukkitPermissions = TAB.getInstance().getServerVersion() == ProtocolVersion.PROXY && config.getBoolean("use-bukkit-permissions-manager", false);
|
||||
private final boolean debugMode = config.getBoolean("debug", false);
|
||||
private final boolean removeGhostPlayers = getSecretOption("remove-ghost-players", false);
|
||||
private final boolean pipelineInjection = getSecretOption("pipeline-injection", true) && TAB.getInstance().getServerVersion().getMinorVersion() >= 8;
|
||||
|
||||
//animations.yml file
|
||||
private ConfigurationFile animation;
|
||||
private final ConfigurationFile animation = new YamlConfigurationFile(getClass().getClassLoader().getResourceAsStream("animations.yml"),
|
||||
new File(TAB.getInstance().getDataFolder(), "animations.yml"));
|
||||
|
||||
//messages.yml file
|
||||
private MessageFile messages;
|
||||
|
||||
//default reload message in case plugin did not load translation file due to an error
|
||||
private String reloadFailed = "&4Failed to reload, file %file% has broken syntax. Check console for more info.";
|
||||
private final MessageFile messages = new MessageFile();
|
||||
|
||||
//playerdata.yml, used for bossbar & scoreboard toggle saving
|
||||
private ConfigurationFile playerdata;
|
||||
|
||||
private ConfigurationFile layout;
|
||||
private final ConfigurationFile layout = new YamlConfigurationFile(getClass().getClassLoader().getResourceAsStream("layout.yml"),
|
||||
new File(TAB.getInstance().getDataFolder(), "layout.yml"));
|
||||
|
||||
private PropertyConfiguration groupFile;
|
||||
|
||||
@@ -53,58 +48,20 @@ public class Configs {
|
||||
|
||||
private MySQL mysql;
|
||||
|
||||
private boolean debugMode;
|
||||
|
||||
private String brokenFile;
|
||||
|
||||
/**
|
||||
* Constructs new instance with given parameter
|
||||
*
|
||||
* @param tab
|
||||
* tab instance
|
||||
*/
|
||||
public Configs(TAB tab) {
|
||||
this.tab = tab;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all configuration files and converts files to latest version
|
||||
* Constructs new instance and loads configuration files.
|
||||
* If needed, converts old configuration files as well.
|
||||
*
|
||||
* @throws IOException
|
||||
* if File I/O operation fails
|
||||
* @throws YAMLException
|
||||
* if files contain syntax errors
|
||||
*/
|
||||
public void loadFiles() throws YAMLException, IOException {
|
||||
messages = new MessageFile();
|
||||
ClassLoader loader = Configs.class.getClassLoader();
|
||||
loadConfig();
|
||||
animation = new YamlConfigurationFile(loader.getResourceAsStream("animations.yml"), new File(tab.getDataFolder(), "animations.yml"));
|
||||
converter.convertAnimationFile(animation);
|
||||
layout = new YamlConfigurationFile(loader.getResourceAsStream("layout.yml"), new File(tab.getDataFolder(), "layout.yml"));
|
||||
reloadFailed = messages.getReloadFailBrokenFile();
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads config.yml and some of its values
|
||||
*
|
||||
* @throws IOException
|
||||
* if File I/O operation fails
|
||||
* @throws YAMLException
|
||||
* if files contain syntax errors
|
||||
*/
|
||||
public void loadConfig() throws YAMLException, IOException {
|
||||
config = new YamlConfigurationFile(Configs.class.getClassLoader().getResourceAsStream(tab.getPlatform().getConfigName()), new File(tab.getDataFolder(), "config.yml"));
|
||||
public Configs() throws YAMLException, IOException {
|
||||
Converter converter = new Converter();
|
||||
converter.convertToV3(config);
|
||||
converter.removeOldOptions(config);
|
||||
debugMode = getConfig().getBoolean("debug", false);
|
||||
if (tab.getPlatform().isProxy()) {
|
||||
bukkitPermissions = getConfig().getBoolean("use-bukkit-permissions-manager", false);
|
||||
} else {
|
||||
unregisterBeforeRegister = getSecretOption("unregister-before-register", true);
|
||||
}
|
||||
removeGhostPlayers = getSecretOption("remove-ghost-players", false);
|
||||
pipelineInjection = getSecretOption("pipeline-injection", true) && tab.getServerVersion().getMinorVersion() >= 8;
|
||||
converter.convertAnimationFile(animation);
|
||||
if (config.getBoolean("mysql.enabled", false)) {
|
||||
try {
|
||||
mysql = new MySQL(config.getString("mysql.host", "127.0.0.1"), config.getInt("mysql.port", 3306),
|
||||
@@ -116,8 +73,8 @@ public class Configs {
|
||||
TAB.getInstance().getErrorManager().criticalError("Failed to connect to MySQL", e);
|
||||
}
|
||||
}
|
||||
groupFile = new YamlPropertyConfigurationFile(Configs.class.getClassLoader().getResourceAsStream("groups.yml"), new File(tab.getDataFolder(), "groups.yml"));
|
||||
userFile = new YamlPropertyConfigurationFile(Configs.class.getClassLoader().getResourceAsStream("users.yml"), new File(tab.getDataFolder(), "users.yml"));
|
||||
groupFile = new YamlPropertyConfigurationFile(getClass().getClassLoader().getResourceAsStream("groups.yml"), new File(TAB.getInstance().getDataFolder(), "groups.yml"));
|
||||
userFile = new YamlPropertyConfigurationFile(getClass().getClassLoader().getResourceAsStream("users.yml"), new File(TAB.getInstance().getDataFolder(), "users.yml"));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -131,14 +88,10 @@ public class Configs {
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T getSecretOption(String path, T defaultValue) {
|
||||
Object value = getConfig().getObject(path);
|
||||
Object value = config.getObject(path);
|
||||
return value == null ? defaultValue : (T) value;
|
||||
}
|
||||
|
||||
public boolean isUnregisterBeforeRegister() {
|
||||
return unregisterBeforeRegister;
|
||||
}
|
||||
|
||||
public MessageFile getMessages() {
|
||||
return messages;
|
||||
}
|
||||
@@ -167,20 +120,15 @@ public class Configs {
|
||||
return pipelineInjection;
|
||||
}
|
||||
|
||||
public String getReloadFailedMessage() {
|
||||
String message = messages == null ? reloadFailed : messages.getReloadFailBrokenFile();
|
||||
return message.replace("%file%", brokenFile);
|
||||
}
|
||||
|
||||
public ConfigurationFile getPlayerDataFile() {
|
||||
if (playerdata == null) {
|
||||
File file = new File(tab.getDataFolder(), "playerdata.yml");
|
||||
File file = new File(TAB.getInstance().getDataFolder(), "playerdata.yml");
|
||||
try {
|
||||
if (file.exists() || file.createNewFile()) {
|
||||
playerdata = new YamlConfigurationFile(null, file);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
tab.getErrorManager().criticalError("Failed to load playerdata.yml", e);
|
||||
TAB.getInstance().getErrorManager().criticalError("Failed to load playerdata.yml", e);
|
||||
}
|
||||
}
|
||||
return playerdata;
|
||||
@@ -215,8 +163,4 @@ public class Configs {
|
||||
public boolean isDebugMode() {
|
||||
return debugMode;
|
||||
}
|
||||
|
||||
public void setBrokenFile(String file) {
|
||||
this.brokenFile = file;
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,10 @@
|
||||
package me.neznamy.tab.shared.config;
|
||||
|
||||
import me.neznamy.tab.api.ProtocolVersion;
|
||||
import me.neznamy.tab.api.config.ConfigurationFile;
|
||||
import me.neznamy.tab.api.config.YamlConfigurationFile;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.api.TabConstants;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@@ -112,7 +114,7 @@ public class Converter {
|
||||
newConfig.set("scoreboard-teams.anti-override", oldConfig.getBoolean("anti-override.scoreboard-teams", true));
|
||||
newConfig.set("scoreboard-teams.enable-collision", oldConfig.getBoolean("enable-collision", true));
|
||||
newConfig.set("scoreboard-teams.disable-in-worlds", oldConfig.getStringList("disable-features-in-worlds.nametag", Collections.singletonList("disabledworld")));
|
||||
if (TAB.getInstance().getPlatform().isProxy()) {
|
||||
if (TAB.getInstance().getServerVersion() == ProtocolVersion.PROXY) {
|
||||
newConfig.set("scoreboard-teams.disable-in-servers", oldConfig.getStringList("disable-features-in-servers.nametag", Collections.singletonList("disabledserver")));
|
||||
} else {
|
||||
newConfig.set("scoreboard-teams.unlimited-nametag-mode.enabled", oldConfig.getBoolean("unlimited-nametag-prefix-suffix-mode.enabled", false));
|
||||
@@ -157,7 +159,7 @@ public class Converter {
|
||||
sortingTypes.add(type + ":" + sortingPlaceholder);
|
||||
}
|
||||
}
|
||||
sortingTypes.add("PLACEHOLDER_A_TO_Z:%player%");
|
||||
sortingTypes.add("PLACEHOLDER_A_TO_Z:" + TabConstants.Placeholder.PLAYER);
|
||||
newConfig.set("scoreboard-teams.sorting-types", sortingTypes);
|
||||
}
|
||||
|
||||
@@ -165,7 +167,7 @@ public class Converter {
|
||||
newConfig.set("tablist-name-formatting.enabled", oldConfig.getBoolean("change-tablist-prefix-suffix", true));
|
||||
newConfig.set("tablist-name-formatting.anti-override", oldConfig.getBoolean("anti-override.tablist-names", true));
|
||||
newConfig.set("tablist-name-formatting.disable-in-worlds", oldConfig.getStringList("disable-features-in-worlds.tablist-names", Collections.singletonList("disabledworld")));
|
||||
if (TAB.getInstance().getPlatform().isProxy())
|
||||
if (TAB.getInstance().getServerVersion() == ProtocolVersion.PROXY)
|
||||
newConfig.set("tablist-name-formatting.disable-in-servers", oldConfig.getStringList("disable-features-in-servers.tablist-names", Collections.singletonList("disabledserver")));
|
||||
if (premiumConfig != null) {
|
||||
newConfig.set("tablist-name-formatting.align-tabsuffix-on-the-right", premiumConfig.getBoolean("align-tabsuffix-on-the-right", false));
|
||||
@@ -177,17 +179,17 @@ public class Converter {
|
||||
}
|
||||
|
||||
private void convertYellowNumber(ConfigurationFile oldConfig, ConfigurationFile newConfig) {
|
||||
newConfig.set("yellow-number-in-tablist.enabled", !oldConfig.getString("yellow-number-in-tablist","%ping%").equals(""));
|
||||
newConfig.set("yellow-number-in-tablist.value", oldConfig.getString("yellow-number-in-tablist","%ping%"));
|
||||
newConfig.set("yellow-number-in-tablist.enabled", !oldConfig.getString("yellow-number-in-tablist", TabConstants.Placeholder.PING).equals(""));
|
||||
newConfig.set("yellow-number-in-tablist.value", oldConfig.getString("yellow-number-in-tablist", TabConstants.Placeholder.PING));
|
||||
newConfig.set("yellow-number-in-tablist.disable-in-worlds", oldConfig.getStringList("disable-features-in-worlds.yellow-number", Collections.singletonList("disabledworld")));
|
||||
if (TAB.getInstance().getPlatform().isProxy())
|
||||
if (TAB.getInstance().getServerVersion() == ProtocolVersion.PROXY)
|
||||
newConfig.set("yellow-number-in-tablist.disable-in-servers", oldConfig.getStringList("disable-features-in-servers.yellow-number", Collections.singletonList("disabledserver")));
|
||||
}
|
||||
|
||||
private void convertBelowName(ConfigurationFile oldConfig, ConfigurationFile newConfig) {
|
||||
newConfig.set("belowname-objective", oldConfig.getConfigurationSection("classic-vanilla-belowname"));
|
||||
newConfig.set("belowname-objective.disable-in-worlds", oldConfig.getStringList("disable-features-in-worlds.belowname", Collections.singletonList("disabledworld")));
|
||||
if (TAB.getInstance().getPlatform().isProxy())
|
||||
if (TAB.getInstance().getServerVersion() == ProtocolVersion.PROXY)
|
||||
newConfig.set("belowname-objective.disable-in-servers", oldConfig.getStringList("disable-features-in-servers.belowname", Collections.singletonList("disabledserver")));
|
||||
}
|
||||
|
||||
@@ -197,12 +199,12 @@ public class Converter {
|
||||
newConfig.set("bossbar.remember-toggle-choice", bossBar.getBoolean("remember-toggle-choice", false));
|
||||
newConfig.set("bossbar.hidden-by-default", bossBar.getBoolean("hidden-by-default", false));
|
||||
newConfig.set("bossbar.disable-in-worlds", bossBar.getObject("disable-features-in-worlds.bossbar"));
|
||||
if (TAB.getInstance().getPlatform().isProxy())
|
||||
if (TAB.getInstance().getServerVersion() == ProtocolVersion.PROXY)
|
||||
newConfig.set("bossbar.disable-in-servers", oldConfig.getStringList("disable-features-in-servers.bossbar", Collections.singletonList("disabledserver")));
|
||||
Map<Object, Map<String, Object>> bars = bossBar.getConfigurationSection("bars");
|
||||
Map<String, List<Object>> perWorldBossBars = bossBar.getConfigurationSection("per-world");
|
||||
List<Object> activeBossBars = new ArrayList<>(bossBar.getStringList("default-bars", new ArrayList<>()));
|
||||
String separator = TAB.getInstance().getPlatform().isProxy() ? "server" : "world";
|
||||
String separator = TAB.getInstance().getServerVersion() == ProtocolVersion.PROXY ? "server" : "world";
|
||||
if (perWorldBossBars != null) {
|
||||
for (Map.Entry<String, List<Object>> entry : perWorldBossBars.entrySet()) {
|
||||
for (Object bar : entry.getValue()) {
|
||||
@@ -224,7 +226,7 @@ public class Converter {
|
||||
}
|
||||
|
||||
private void convertScoreboard(ConfigurationFile newConfig, ConfigurationFile premiumConfig) {
|
||||
String separator = TAB.getInstance().getPlatform().isProxy() ? "server" : "world";
|
||||
String separator = TAB.getInstance().getServerVersion() == ProtocolVersion.PROXY ? "server" : "world";
|
||||
newConfig.set("scoreboard", premiumConfig.getObject("scoreboard"));
|
||||
newConfig.set("scoreboard.permission-required-to-toggle", null);
|
||||
Map<String, Map<String,Object>> scoreboards = premiumConfig.getConfigurationSection("scoreboards");
|
||||
@@ -261,7 +263,7 @@ public class Converter {
|
||||
newConfig.set("scoreboard.delay-on-join-milliseconds", 0);
|
||||
newConfig.set("scoreboard.respect-other-plugins", true);
|
||||
newConfig.set("scoreboard.disable-in-worlds", Collections.singletonList("disabledworld"));
|
||||
if (TAB.getInstance().getPlatform().isProxy()) {
|
||||
if (TAB.getInstance().getServerVersion() == ProtocolVersion.PROXY) {
|
||||
newConfig.set("scoreboard.disable-in-servers", Collections.singletonList("disabledserver"));
|
||||
}
|
||||
newConfig.set("scoreboard.scoreboards.admin.display-condition", "permission:tab.scoreboard.admin");
|
||||
@@ -280,10 +282,10 @@ public class Converter {
|
||||
newConfig.set("header-footer.header", oldConfig.getStringList("header"));
|
||||
newConfig.set("header-footer.footer", oldConfig.getStringList("footer"));
|
||||
newConfig.set("header-footer.disable-in-worlds", oldConfig.getStringList("disable-features-in-worlds.header-footer", Collections.singletonList("disabledworld")));
|
||||
if (TAB.getInstance().getPlatform().isProxy())
|
||||
if (TAB.getInstance().getServerVersion() == ProtocolVersion.PROXY)
|
||||
newConfig.set("header-footer.disable-in-servers", oldConfig.getStringList("disable-features-in-servers.header-footer", Collections.singletonList("disabledserver")));
|
||||
|
||||
String separator = TAB.getInstance().getPlatform().isProxy() ? "server" : "world";
|
||||
String separator = TAB.getInstance().getServerVersion() == ProtocolVersion.PROXY ? "server" : "world";
|
||||
Map<String, Map<String, Object>> perWorldSettings = oldConfig.getConfigurationSection("per-" + separator + "-settings");
|
||||
Map<String, Object> headerFooterMap = new LinkedHashMap<>();
|
||||
for (Map.Entry<String, Map<String, Object>> worldEntry : new LinkedHashMap<>(perWorldSettings).entrySet()) {
|
||||
@@ -312,7 +314,7 @@ public class Converter {
|
||||
newConfig.set("conditions.nick.yes", "%player%");
|
||||
newConfig.set("conditions.nick.no", "~%essentials_nickname%");
|
||||
}
|
||||
if (!TAB.getInstance().getPlatform().isProxy()) {
|
||||
if (TAB.getInstance().getServerVersion() != ProtocolVersion.PROXY) {
|
||||
newConfig.set("placeholder-output-replacements.%afk%.true", placeholders.remove("afk-yes"));
|
||||
newConfig.set("placeholder-output-replacements.%afk%.false", placeholders.remove("afk-no"));
|
||||
}
|
||||
@@ -331,7 +333,7 @@ public class Converter {
|
||||
newConfig.set("mysql.username", "user");
|
||||
newConfig.set("mysql.password", "password");
|
||||
|
||||
if (TAB.getInstance().getPlatform().isProxy()) {
|
||||
if (TAB.getInstance().getServerVersion() == ProtocolVersion.PROXY) {
|
||||
newConfig.set("global-playerlist", oldConfig.getConfigurationSection("global-playerlist"));
|
||||
newConfig.set("global-playerlist.update-latency", false);
|
||||
newConfig.set("use-bukkit-permissions-manager", false);
|
||||
@@ -345,7 +347,7 @@ public class Converter {
|
||||
groups.setValues(oldConfig.getConfigurationSection("Groups"));
|
||||
users.setValues(oldConfig.getConfigurationSection("Users"));
|
||||
|
||||
String separator = TAB.getInstance().getPlatform().isProxy() ? "server" : "world";
|
||||
String separator = TAB.getInstance().getServerVersion() == ProtocolVersion.PROXY ? "server" : "world";
|
||||
Map<String,Map<String,Object>> perWorldSettings = oldConfig.getConfigurationSection("per-" + separator + "-settings");
|
||||
Map<String,Object> groupMap = new LinkedHashMap<>();
|
||||
Map<String,Object> userMap = new LinkedHashMap<>();
|
||||
@@ -359,13 +361,13 @@ public class Converter {
|
||||
}
|
||||
}
|
||||
groups.set("per-" + separator, groupMap);
|
||||
groups.set("_DEFAULT_", groups.getConfigurationSection("_OTHER_"));
|
||||
groups.set(TabConstants.DEFAULT_GROUP, groups.getConfigurationSection("_OTHER_"));
|
||||
groups.set("_OTHER_", null);
|
||||
users.set("per-" + separator, userMap);
|
||||
for (Object world : groups.getConfigurationSection("per-" + separator).keySet()) {
|
||||
String gPath = "per-" + separator + "." + world;
|
||||
if (!groups.hasConfigOption(gPath + "._OTHER_")) continue;
|
||||
groups.set(gPath + "._DEFAULT_", groups.getObject(gPath + "._OTHER_"));
|
||||
groups.set(gPath + "." + TabConstants.DEFAULT_GROUP, groups.getObject(gPath + "._OTHER_"));
|
||||
groups.set(gPath + "._OTHER_", null);
|
||||
}
|
||||
}
|
||||
|
||||
+9
-9
@@ -5,6 +5,7 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.*;
|
||||
|
||||
import me.neznamy.tab.api.TabConstants;
|
||||
import org.yaml.snakeyaml.error.YAMLException;
|
||||
|
||||
import me.neznamy.tab.api.PropertyConfiguration;
|
||||
@@ -13,9 +14,8 @@ import me.neznamy.tab.shared.TAB;
|
||||
|
||||
public class YamlPropertyConfigurationFile extends YamlConfigurationFile implements PropertyConfiguration {
|
||||
|
||||
private static final String PER_SERVER = "per-server";
|
||||
private static final String PER_WORLD = "per-world";
|
||||
private static final String DEFAULT_GROUP = "_DEFAULT_";
|
||||
private final String PER_SERVER = "per-server";
|
||||
private final String PER_WORLD = "per-world";
|
||||
|
||||
private final String category;
|
||||
private final List<Object> worldGroups = new ArrayList<>(getConfigurationSection(PER_WORLD).keySet());
|
||||
@@ -43,20 +43,20 @@ public class YamlPropertyConfigurationFile extends YamlConfigurationFile impleme
|
||||
if ((value = getObject(new String[] {PER_WORLD, TAB.getInstance().getConfiguration().getGroup(worldGroups, world), name, property})) != null) {
|
||||
return new String[] {toString(value), category + "=" + name + ", world=" + world};
|
||||
}
|
||||
if ((value = getObject(new String[] {PER_WORLD, TAB.getInstance().getConfiguration().getGroup(worldGroups, world), DEFAULT_GROUP, property})) != null) {
|
||||
return new String[] {toString(value), category + "=" + DEFAULT_GROUP + ", world=" + world};
|
||||
if ((value = getObject(new String[] {PER_WORLD, TAB.getInstance().getConfiguration().getGroup(worldGroups, world), TabConstants.DEFAULT_GROUP, property})) != null) {
|
||||
return new String[] {toString(value), category + "=" + TabConstants.DEFAULT_GROUP + ", world=" + world};
|
||||
}
|
||||
if ((value = getObject(new String[] {PER_SERVER, TAB.getInstance().getConfiguration().getGroup(serverGroups, server), name, property})) != null) {
|
||||
return new String[] {toString(value), category + "=" + name + ", server=" + server};
|
||||
}
|
||||
if ((value = getObject(new String[] {PER_SERVER, TAB.getInstance().getConfiguration().getGroup(serverGroups, server), DEFAULT_GROUP, property})) != null) {
|
||||
return new String[] {toString(value), category + "=" + DEFAULT_GROUP + ", server=" + server};
|
||||
if ((value = getObject(new String[] {PER_SERVER, TAB.getInstance().getConfiguration().getGroup(serverGroups, server), TabConstants.DEFAULT_GROUP, property})) != null) {
|
||||
return new String[] {toString(value), category + "=" + TabConstants.DEFAULT_GROUP + ", server=" + server};
|
||||
}
|
||||
if ((value = getObject(new String[] {name, property})) != null) {
|
||||
return new String[] {toString(value), category + "=" + name};
|
||||
}
|
||||
if ((value = getObject(new String[] {DEFAULT_GROUP, property})) != null) {
|
||||
return new String[] {toString(value), category + "=" + DEFAULT_GROUP};
|
||||
if ((value = getObject(new String[] {TabConstants.DEFAULT_GROUP, property})) != null) {
|
||||
return new String[] {toString(value), category + "=" + TabConstants.DEFAULT_GROUP};
|
||||
}
|
||||
return new String[0];
|
||||
}
|
||||
|
||||
+10
-11
@@ -2,6 +2,7 @@ package me.neznamy.tab.shared.config.mysql;
|
||||
|
||||
import me.neznamy.tab.api.PropertyConfiguration;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.api.TabConstants;
|
||||
import me.neznamy.tab.shared.config.MySQL;
|
||||
|
||||
import javax.sql.rowset.CachedRowSet;
|
||||
@@ -10,7 +11,6 @@ import java.util.*;
|
||||
|
||||
public class MySQLGroupConfiguration implements PropertyConfiguration {
|
||||
|
||||
private static final String DEFAULT_GROUP = "_DEFAULT_";
|
||||
private final MySQL mysql;
|
||||
|
||||
private final Map<String, Map<String, Object>> values = new HashMap<>();
|
||||
@@ -23,19 +23,18 @@ public class MySQLGroupConfiguration implements PropertyConfiguration {
|
||||
CachedRowSet crs = mysql.getCRS("select * from tab_groups");
|
||||
while (crs.next()) {
|
||||
String group = crs.getString("group");
|
||||
if (!group.equals(DEFAULT_GROUP)) group = group.toLowerCase(Locale.US);
|
||||
if (!group.equals(TabConstants.DEFAULT_GROUP)) group = group.toLowerCase(Locale.US);
|
||||
String property = crs.getString("property");
|
||||
String value = crs.getString("value");
|
||||
String world = crs.getString("world");
|
||||
String server = crs.getString("server");
|
||||
TAB.getInstance().debug("Loaded group: " + String.format("%s, %s, %s, %s, %s", group, property, value, world, server));
|
||||
setProperty0(group, property, server, world, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProperty(String group, String property, String server, String world, String value) {
|
||||
String lowercaseGroup = group.equals(DEFAULT_GROUP) ? group : group.toLowerCase(Locale.US);
|
||||
String lowercaseGroup = group.equals(TabConstants.DEFAULT_GROUP) ? group : group.toLowerCase(Locale.US);
|
||||
try {
|
||||
if (getProperty(lowercaseGroup, property, server, world) != null) {
|
||||
mysql.execute("delete from `tab_groups` where `group` = ? and `property` = ? and world " + querySymbol(world == null) + " ? and server " + querySymbol(server == null) + " ?", lowercaseGroup, property, world, server);
|
||||
@@ -63,25 +62,25 @@ public class MySQLGroupConfiguration implements PropertyConfiguration {
|
||||
|
||||
@Override
|
||||
public String[] getProperty(String group, String property, String server, String world) {
|
||||
String lowercaseGroup = group.equals(DEFAULT_GROUP) ? group : group.toLowerCase(Locale.US);
|
||||
String lowercaseGroup = group.equals(TabConstants.DEFAULT_GROUP) ? group : group.toLowerCase(Locale.US);
|
||||
Object value;
|
||||
if ((value = perWorld.getOrDefault(world, new HashMap<>()).getOrDefault(lowercaseGroup, new HashMap<>()).get(property)) != null) {
|
||||
return new String[] {toString(value), String.format("group=%s,world=%s", lowercaseGroup, world)};
|
||||
}
|
||||
if ((value = perWorld.getOrDefault(world, new HashMap<>()).getOrDefault(DEFAULT_GROUP, new HashMap<>()).get(property)) != null) {
|
||||
return new String[] {toString(value), String.format("group=%s,world=%s", DEFAULT_GROUP, world)};
|
||||
if ((value = perWorld.getOrDefault(world, new HashMap<>()).getOrDefault(TabConstants.DEFAULT_GROUP, new HashMap<>()).get(property)) != null) {
|
||||
return new String[] {toString(value), String.format("group=%s,world=%s", TabConstants.DEFAULT_GROUP, world)};
|
||||
}
|
||||
if ((value = perServer.getOrDefault(server, new HashMap<>()).getOrDefault(lowercaseGroup, new HashMap<>()).get(property)) != null) {
|
||||
return new String[] {toString(value), String.format("group=%s,server=%s", lowercaseGroup, server)};
|
||||
}
|
||||
if ((value = perServer.getOrDefault(server, new HashMap<>()).getOrDefault(DEFAULT_GROUP, new HashMap<>()).get(property)) != null) {
|
||||
return new String[] {toString(value), String.format("group=%s,server=%s", DEFAULT_GROUP, server)};
|
||||
if ((value = perServer.getOrDefault(server, new HashMap<>()).getOrDefault(TabConstants.DEFAULT_GROUP, new HashMap<>()).get(property)) != null) {
|
||||
return new String[] {toString(value), String.format("group=%s,server=%s", TabConstants.DEFAULT_GROUP, server)};
|
||||
}
|
||||
if ((value = values.getOrDefault(lowercaseGroup, new HashMap<>()).get(property)) != null) {
|
||||
return new String[] {toString(value), String.format("group=%s", lowercaseGroup)};
|
||||
}
|
||||
if ((value = values.getOrDefault(DEFAULT_GROUP, new HashMap<>()).get(property)) != null) {
|
||||
return new String[] {toString(value), String.format("group=%s", DEFAULT_GROUP)};
|
||||
if ((value = values.getOrDefault(TabConstants.DEFAULT_GROUP, new HashMap<>()).get(property)) != null) {
|
||||
return new String[] {toString(value), String.format("group=%s", TabConstants.DEFAULT_GROUP)};
|
||||
}
|
||||
return new String[0];
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import me.neznamy.tab.api.protocol.PacketPlayOutScoreboardObjective.EnumScoreboa
|
||||
import me.neznamy.tab.api.protocol.PacketPlayOutScoreboardScore;
|
||||
import me.neznamy.tab.api.protocol.PacketPlayOutScoreboardScore.Action;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.shared.TabConstants;
|
||||
import me.neznamy.tab.api.TabConstants;
|
||||
import me.neznamy.tab.shared.features.redis.RedisSupport;
|
||||
|
||||
/**
|
||||
@@ -22,13 +22,12 @@ public class BelowName extends TabFeature {
|
||||
public static final String OBJECTIVE_NAME = "TAB-BelowName";
|
||||
public static final int DISPLAY_SLOT = 2;
|
||||
|
||||
private final String rawNumber = TAB.getInstance().getConfiguration().getConfig().getString("belowname-objective.number", "%health%");
|
||||
private final String rawNumber = TAB.getInstance().getConfiguration().getConfig().getString("belowname-objective.number", TabConstants.Placeholder.HEALTH);
|
||||
private final String rawText = TAB.getInstance().getConfiguration().getConfig().getString("belowname-objective.text", "Health");
|
||||
private final TabFeature textRefresher = new TextRefresher();
|
||||
|
||||
public BelowName() {
|
||||
super("BelowName", "Updating BelowName number", TAB.getInstance().getConfiguration().getConfig().getStringList("belowname-objective.disable-in-servers"),
|
||||
TAB.getInstance().getConfiguration().getConfig().getStringList("belowname-objective.disable-in-worlds"));
|
||||
super("BelowName", "Updating BelowName number", "belowname-objective");
|
||||
TAB.getInstance().getFeatureManager().registerFeature(TabConstants.Feature.BELOW_NAME_TEXT, textRefresher);
|
||||
TAB.getInstance().debug(String.format("Loaded BelowName feature with parameters number=%s, text=%s, disabledWorlds=%s, disabledServers=%s", rawNumber, rawText, Arrays.toString(disabledWorlds), Arrays.toString(disabledServers)));
|
||||
}
|
||||
@@ -107,6 +106,7 @@ public class BelowName extends TabFeature {
|
||||
onJoin(p);
|
||||
return;
|
||||
}
|
||||
if (disabledNow) return;
|
||||
int number = getValue(p);
|
||||
for (TabPlayer all : TAB.getInstance().getOnlinePlayers()){
|
||||
if (sameServerAndWorld(all, p)) {
|
||||
|
||||
Loaded 100 of 162 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user