Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4510491177 | ||
|
|
01b3a12377 | ||
|
|
64ae9863fb | ||
|
|
ecd315a407 | ||
|
|
678eed288e | ||
|
|
9510455cb1 | ||
|
|
e925ce23d0 | ||
|
|
c68cad6a1e | ||
|
|
01d6eda4fb | ||
|
|
73e7119bbc | ||
|
|
cea781382a | ||
|
|
cf25b84e86 | ||
|
|
86e1d22390 | ||
|
|
1625be111f | ||
|
|
00cda3b2aa | ||
|
|
85a00a4436 | ||
|
|
37aec1a497 | ||
|
|
ef637616ee | ||
|
|
af3b5067fb | ||
|
|
53e5b15f96 | ||
|
|
6a3afae607 | ||
|
|
2e05c7d9d1 | ||
|
|
fb698a04b7 | ||
|
|
52bdf30ddb | ||
|
|
a92f07aa40 | ||
|
|
003ff7f99d | ||
|
|
47b9806ae7 | ||
|
|
d2a7c65e08 | ||
|
|
e232336a5f | ||
|
|
8816c75212 | ||
|
|
f9d54751ba | ||
|
|
43d41ee761 | ||
|
|
4512ba8d5e | ||
|
|
8b55bca564 | ||
|
|
d8d54970d3 | ||
|
|
15ea4482f9 | ||
|
|
87f9f38eac | ||
|
|
dba559f041 | ||
|
|
c610b6f323 | ||
|
|
a5fb900e19 | ||
|
|
09d6e455f5 | ||
|
|
e68097b0f4 | ||
|
|
0744fed953 | ||
|
|
de0adf4067 | ||
|
|
76bf2b3efc | ||
|
|
c089badeb4 | ||
|
|
b3b99d366a | ||
|
|
4a36486f65 | ||
|
|
75126d00d9 | ||
|
|
17ebf95d5b | ||
|
|
c764420cfe | ||
|
|
28f05fc2af | ||
|
|
a420892887 | ||
|
|
d910dc5913 | ||
|
|
c9c1cbc349 |
No files matched your search
@@ -57,5 +57,7 @@ body:
|
||||
required: true
|
||||
- label: I have read the wiki to make sure it's not an issue with configuration
|
||||
required: true
|
||||
- label: I ticked all of the boxes without actually reading them
|
||||
required: false
|
||||
- label: I have read the Compatibility wiki page and am not trying to run the plugin on an unsupported server version / platform
|
||||
required: true
|
||||
@@ -51,5 +51,7 @@ body:
|
||||
required: true
|
||||
- label: I have included a paste of the error
|
||||
required: true
|
||||
- label: I ticked all of the boxes without actually reading them
|
||||
required: false
|
||||
- label: I have read the Compatibility wiki page and am not trying to run the plugin on an unsupported server version / platform
|
||||
required: true
|
||||
@@ -17,10 +17,10 @@ Once the plugin compiles, grab the jar from `/jar/build/libs/` folder.
|
||||
# Links
|
||||
The precompiled JAR can be downloaded for free from:
|
||||
* GitHub releases: https://github.com/NEZNAMY/TAB/releases
|
||||
* MC-Market: https://www.mc-market.org/resources/20631/
|
||||
* BuiltByBit: https://builtbybit.com/resources/20631/
|
||||
|
||||
Supporting my work:
|
||||
* MC-Market: https://www.mc-market.org/resources/14009/
|
||||
Support my work & receive official assistance with configuration:
|
||||
* BuiltByBit: https://builtbybit.com/resources/14009/
|
||||
* Polymart: https://polymart.org/resource/484
|
||||
|
||||
Other links:
|
||||
@@ -44,4 +44,4 @@ is in quality of the report (typically providing correct steps to reproduce that
|
||||
for problems of any kind including bugs. This way you will help make the actual releases more stable / help get stable releases sooner.
|
||||
* Help improve the wiki by opening a [Wiki change issue](https://github.com/NEZNAMY/TAB/issues/new?assignees=&labels=Wiki&template=wiki_change.yml),
|
||||
where you can improve existing descriptions, add information you found missing, fix typos / grammar mistakes or add more examples of usage of functions.
|
||||
* [Buy a copy](https://www.mc-market.org/resources/14009/) of the plugin or [send a donation](https://paypal.me/neznamy1) to keep the plugin active.
|
||||
* [Buy a copy](https://builtbybit.com/resources/14009/) of the plugin or [send a donation](https://paypal.me/neznamy1) to keep the plugin active.
|
||||
@@ -8,6 +8,7 @@ public enum ProtocolVersion {
|
||||
UNKNOWN_SERVER_VERSION ("Unknown"),
|
||||
UNKNOWN_CLIENT_VERSION ("Unknown"),
|
||||
PROXY ("Proxy"),
|
||||
V1_19_3 (761),
|
||||
V1_19_2 (760),
|
||||
V1_19_1 (760),
|
||||
V1_19 (759),
|
||||
|
||||
@@ -83,6 +83,8 @@ public class TabConstants {
|
||||
public static final String NAMETAGS_TEAM_UNREGISTER = "NameTags (Team unregister)";
|
||||
public static final String NAMETAGS_TEAM_UPDATE = "NameTags (Team update)";
|
||||
|
||||
public static final String SORTING_CHANGING_TEAM_NAME = "Sorting (Changing team name)";
|
||||
|
||||
public static final String SCOREBOARD_TITLE = "Scoreboard (Title)";
|
||||
public static final String SCOREBOARD_LINES = "Scoreboard (Lines)";
|
||||
|
||||
@@ -333,6 +335,9 @@ public class TabConstants {
|
||||
public static final String VAULT_SUFFIX = "%vault-suffix%";
|
||||
public static final String HEALTH = "%health%";
|
||||
|
||||
public static final int MINIMUM_REFRESH_INTERVAL = 50;
|
||||
|
||||
|
||||
public static String condition(String name) {
|
||||
return "%condition:" + name + "%";
|
||||
}
|
||||
@@ -340,6 +345,10 @@ public class TabConstants {
|
||||
public static String animation(String name) {
|
||||
return "%animation:" + name + "%";
|
||||
}
|
||||
|
||||
public static String globalPlayerListGroup(String group) {
|
||||
return "%playerlist-group_" + group + "%";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -212,13 +212,6 @@ public interface TabPlayer {
|
||||
*/
|
||||
String getTeamName();
|
||||
|
||||
/**
|
||||
* Returns user-friendly explanation of team name
|
||||
*
|
||||
* @return explanation behind team name
|
||||
*/
|
||||
String getTeamNameNote();
|
||||
|
||||
/**
|
||||
* Returns {@code true} if player is disguised using LibsDisguises, {@code false} if not
|
||||
*
|
||||
@@ -318,4 +311,10 @@ public interface TabPlayer {
|
||||
* @return Player's direct chat message signing key
|
||||
*/
|
||||
Object getProfilePublicKey();
|
||||
|
||||
/**
|
||||
* Return player's chat session ID
|
||||
* @return player's chat session ID
|
||||
*/
|
||||
UUID getChatSessionId();
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package me.neznamy.tab.api.protocol;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@@ -12,8 +13,8 @@ import me.neznamy.tab.api.util.Preconditions;
|
||||
*/
|
||||
public class PacketPlayOutPlayerInfo implements TabPacket {
|
||||
|
||||
/** Packet action */
|
||||
private final EnumPlayerInfoAction action;
|
||||
/** Packet actions */
|
||||
private final EnumSet<EnumPlayerInfoAction> actions;
|
||||
|
||||
/** List of affected entries */
|
||||
private final List<PlayerInfoData> entries;
|
||||
@@ -27,10 +28,7 @@ public class PacketPlayOutPlayerInfo implements TabPacket {
|
||||
* Affected entries
|
||||
*/
|
||||
public PacketPlayOutPlayerInfo(EnumPlayerInfoAction action, PlayerInfoData... entries) {
|
||||
Preconditions.checkNotNull(action, "action");
|
||||
Preconditions.checkNotNull(entries, "entries");
|
||||
this.action = action;
|
||||
this.entries = Arrays.asList(entries);
|
||||
this(action, Arrays.asList(entries));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -44,22 +42,61 @@ public class PacketPlayOutPlayerInfo implements TabPacket {
|
||||
public PacketPlayOutPlayerInfo(EnumPlayerInfoAction action, List<PlayerInfoData> entries) {
|
||||
Preconditions.checkNotNull(action, "action");
|
||||
Preconditions.checkNotNull(entries, "entries");
|
||||
this.action = action;
|
||||
if (action == EnumPlayerInfoAction.ADD_PLAYER) {
|
||||
actions = EnumSet.of(EnumPlayerInfoAction.ADD_PLAYER,
|
||||
EnumPlayerInfoAction.INITIALIZE_CHAT,
|
||||
EnumPlayerInfoAction.UPDATE_GAME_MODE,
|
||||
EnumPlayerInfoAction.UPDATE_LISTED,
|
||||
EnumPlayerInfoAction.UPDATE_LATENCY,
|
||||
EnumPlayerInfoAction.UPDATE_DISPLAY_NAME);
|
||||
} else {
|
||||
this.actions = EnumSet.of(action);
|
||||
}
|
||||
this.entries = entries;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs new instance with given parameters.
|
||||
*
|
||||
* @param actions
|
||||
* Packet actions
|
||||
* @param entries
|
||||
* Affected entries
|
||||
*/
|
||||
public PacketPlayOutPlayerInfo(EnumSet<EnumPlayerInfoAction> actions, PlayerInfoData... entries) {
|
||||
Preconditions.checkNotNull(actions, "action");
|
||||
Preconditions.checkNotNull(entries, "entries");
|
||||
this.actions = actions;
|
||||
this.entries = Arrays.asList(entries);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs new instance with given parameters.
|
||||
*
|
||||
* @param actions
|
||||
* Packet actions
|
||||
* @param entries
|
||||
* Affected entries
|
||||
*/
|
||||
public PacketPlayOutPlayerInfo(EnumSet<EnumPlayerInfoAction> actions, List<PlayerInfoData> entries) {
|
||||
Preconditions.checkNotNull(actions, "action");
|
||||
Preconditions.checkNotNull(entries, "entries");
|
||||
this.actions = actions;
|
||||
this.entries = entries;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("PacketPlayOutPlayerInfo{action=%s,entries=%s}", action, entries);
|
||||
return String.format("PacketPlayOutPlayerInfo{actions=%s,entries=%s}", actions, entries);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@link #action}
|
||||
* Returns {@link #actions}
|
||||
*
|
||||
* @return packet action
|
||||
*/
|
||||
public EnumPlayerInfoAction getAction() {
|
||||
return action;
|
||||
public EnumSet<EnumPlayerInfoAction> getActions() {
|
||||
return actions;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -79,6 +116,9 @@ public class PacketPlayOutPlayerInfo implements TabPacket {
|
||||
/** Latency */
|
||||
private int latency;
|
||||
|
||||
/** I have no idea what this is */
|
||||
private boolean listed;
|
||||
|
||||
/** GameMode */
|
||||
private EnumGamemode gameMode = EnumGamemode.SURVIVAL; //ProtocolLib causes NPE even when action does not use GameMode
|
||||
|
||||
@@ -97,12 +137,15 @@ public class PacketPlayOutPlayerInfo implements TabPacket {
|
||||
/** Player's skin, null for empty skin */
|
||||
private Skin skin;
|
||||
|
||||
/** Chat session ID */
|
||||
private UUID chatSessionId;
|
||||
|
||||
/** Player's chat signing key */
|
||||
private Object profilePublicKey;
|
||||
|
||||
/**
|
||||
* Constructs new instance with given parameters. Suitable for
|
||||
* {@link EnumPlayerInfoAction}.ADD_PLAYER action
|
||||
* {@link EnumPlayerInfoAction#ADD_PLAYER} action
|
||||
*
|
||||
* @param name
|
||||
* Player's name
|
||||
@@ -119,20 +162,22 @@ public class PacketPlayOutPlayerInfo implements TabPacket {
|
||||
* @param profilePublicKey
|
||||
* Player's chat signing key
|
||||
*/
|
||||
public PlayerInfoData(String name, UUID uniqueId, Skin skin, int latency, EnumGamemode gameMode, IChatBaseComponent displayName, Object profilePublicKey) {
|
||||
public PlayerInfoData(String name, UUID uniqueId, Skin skin, boolean listed, int latency, EnumGamemode gameMode, IChatBaseComponent displayName, UUID chatSessionId, Object profilePublicKey) {
|
||||
Preconditions.checkNotNull(uniqueId, "uuid");
|
||||
this.name = name;
|
||||
this.uniqueId = uniqueId;
|
||||
this.skin = skin;
|
||||
this.listed = listed;
|
||||
this.latency = latency;
|
||||
this.gameMode = gameMode;
|
||||
this.displayName = displayName;
|
||||
this.chatSessionId = chatSessionId;
|
||||
this.profilePublicKey = profilePublicKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs new instance with given parameters. Suitable for
|
||||
* {@link EnumPlayerInfoAction}.UPDATE_GAME_MODE action
|
||||
* {@link EnumPlayerInfoAction#UPDATE_GAME_MODE} action
|
||||
*
|
||||
* @param uniqueId
|
||||
* Player's uuid
|
||||
@@ -147,7 +192,7 @@ public class PacketPlayOutPlayerInfo implements TabPacket {
|
||||
|
||||
/**
|
||||
* Constructs new instance with given parameters. Suitable for
|
||||
* {@link EnumPlayerInfoAction}.UPDATE_LATENCY action
|
||||
* {@link EnumPlayerInfoAction#UPDATE_LATENCY} action
|
||||
*
|
||||
* @param uniqueId
|
||||
* Player's uuid
|
||||
@@ -162,7 +207,7 @@ public class PacketPlayOutPlayerInfo implements TabPacket {
|
||||
|
||||
/**
|
||||
* Constructs new instance with given parameters. Suitable for
|
||||
* {@link EnumPlayerInfoAction}.UPDATE_DISPLAY_NAME action
|
||||
* {@link EnumPlayerInfoAction#UPDATE_DISPLAY_NAME} action
|
||||
*
|
||||
* @param uniqueId
|
||||
* Player's uuid
|
||||
@@ -177,7 +222,7 @@ public class PacketPlayOutPlayerInfo implements TabPacket {
|
||||
|
||||
/**
|
||||
* Constructs new instance with given parameter. Suitable for
|
||||
* {@link EnumPlayerInfoAction}.REMOVE_PLAYER action
|
||||
* {@link EnumPlayerInfoAction#REMOVE_PLAYER} action
|
||||
*
|
||||
* @param uniqueId
|
||||
* Player's uuid
|
||||
@@ -211,6 +256,25 @@ public class PacketPlayOutPlayerInfo implements TabPacket {
|
||||
this.latency = latency;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@link #listed}
|
||||
*
|
||||
* @return listed
|
||||
*/
|
||||
public boolean isListed() {
|
||||
return listed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets {@link #listed} to specified value
|
||||
*
|
||||
* @param listed
|
||||
* Listed flag
|
||||
*/
|
||||
public void setListed(boolean listed) {
|
||||
this.listed = listed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@link #displayName}
|
||||
*
|
||||
@@ -306,6 +370,25 @@ public class PacketPlayOutPlayerInfo implements TabPacket {
|
||||
this.skin = skin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@link #chatSessionId}
|
||||
*
|
||||
* @return chatSessionId
|
||||
*/
|
||||
public UUID getChatSessionId() {
|
||||
return chatSessionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets {@link #chatSessionId} to specified value
|
||||
*
|
||||
* @param chatSessionId
|
||||
* chatSessionId to use
|
||||
*/
|
||||
public void setChatSessionId(UUID chatSessionId) {
|
||||
this.chatSessionId = chatSessionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@link #profilePublicKey}
|
||||
*
|
||||
@@ -328,12 +411,13 @@ public class PacketPlayOutPlayerInfo implements TabPacket {
|
||||
|
||||
/**
|
||||
* En enum representing packet action
|
||||
* Calling ordinal() will return action's network ID.
|
||||
*/
|
||||
public enum EnumPlayerInfoAction {
|
||||
|
||||
ADD_PLAYER,
|
||||
INITIALIZE_CHAT,
|
||||
UPDATE_GAME_MODE,
|
||||
UPDATE_LISTED,
|
||||
UPDATE_LATENCY,
|
||||
UPDATE_DISPLAY_NAME,
|
||||
REMOVE_PLAYER
|
||||
|
||||
@@ -4,6 +4,9 @@ plugins {
|
||||
}
|
||||
|
||||
indra {
|
||||
publishReleasesTo("krypton-repo", "https://repo.kryptonmc.org/releases")
|
||||
publishSnapshotsTo("krypton-repo", "https://repo.kryptonmc.org/snapshots")
|
||||
publishReleasesTo("krypton", "https://repo.kryptonmc.org/releases")
|
||||
publishSnapshotsTo("krypton", "https://repo.kryptonmc.org/snapshots")
|
||||
configurePublications {
|
||||
artifactId = "tab-$artifactId"
|
||||
}
|
||||
}
|
||||
@@ -14,11 +14,13 @@ import me.neznamy.tab.api.protocol.PacketPlayOutPlayerInfo.EnumPlayerInfoAction;
|
||||
import me.neznamy.tab.api.protocol.PacketPlayOutPlayerInfo.PlayerInfoData;
|
||||
import me.neznamy.tab.platforms.bukkit.nms.*;
|
||||
import me.neznamy.tab.platforms.bukkit.nms.datawatcher.DataWatcher;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.EntityType;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
public class BukkitPacketBuilder extends PacketBuilder {
|
||||
@@ -76,9 +78,9 @@ public class BukkitPacketBuilder extends PacketBuilder {
|
||||
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());
|
||||
return nms.newPacketPlayOutChat.newInstance(component, Enum.valueOf(nms.ChatMessageType, packet.getType().toString()), UUID.randomUUID());
|
||||
if (nms.getMinorVersion() >= 12)
|
||||
return nms.newPacketPlayOutChat.newInstance(component, Enum.valueOf((Class<Enum>) nms.ChatMessageType, packet.getType().toString()));
|
||||
return nms.newPacketPlayOutChat.newInstance(component, Enum.valueOf(nms.ChatMessageType, packet.getType().toString()));
|
||||
if (nms.getMinorVersion() >= 8)
|
||||
return nms.newPacketPlayOutChat.newInstance(component, (byte) packet.getType().ordinal());
|
||||
if (nms.getMinorVersion() == 7)
|
||||
@@ -89,24 +91,56 @@ public class BukkitPacketBuilder extends PacketBuilder {
|
||||
@Override
|
||||
public Object build(PacketPlayOutPlayerInfo packet, ProtocolVersion clientVersion) throws ReflectiveOperationException {
|
||||
if (nms.getMinorVersion() < 8) return null;
|
||||
Object nmsPacket = nms.newPacketPlayOutPlayerInfo.newInstance(nms.EnumPlayerInfoAction_values[packet.getAction().ordinal()], Array.newInstance(nms.EntityPlayer, 0));
|
||||
List<Object> items = new ArrayList<>();
|
||||
for (PlayerInfoData data : packet.getEntries()) {
|
||||
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.getParameterTypes()[0] == nms.PacketPlayOutPlayerInfo) {
|
||||
parameters.add(nmsPacket);
|
||||
if (nms.ClientboundPlayerInfoRemovePacket != null) {
|
||||
//1.19.3+
|
||||
if (packet.getActions().contains(EnumPlayerInfoAction.REMOVE_PLAYER)) {
|
||||
return nms.newClientboundPlayerInfoRemovePacket.newInstance(
|
||||
packet.getEntries().stream().map(PlayerInfoData::getUniqueId).collect(Collectors.toList())
|
||||
);
|
||||
}
|
||||
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(data.getProfilePublicKey());
|
||||
items.add(nms.newPlayerInfoData.newInstance(parameters.toArray()));
|
||||
Enum[] array = packet.getActions().stream().map(action -> Enum.valueOf(nms.EnumPlayerInfoAction, action.toString())).toArray(Enum[]::new);
|
||||
Object nmsPacket = nms.newPacketPlayOutPlayerInfo.newInstance(array[0], nms.getHandle.invoke(Bukkit.getOnlinePlayers().iterator().next()));
|
||||
List<Object> items = new ArrayList<>();
|
||||
for (PlayerInfoData data : packet.getEntries()) {
|
||||
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()));
|
||||
Object obj = nms.newPlayerInfoData.newInstance(
|
||||
data.getUniqueId(),
|
||||
profile,
|
||||
data.isListed(),
|
||||
data.getLatency(),
|
||||
data.getGameMode() == null ? null : Enum.valueOf(nms.EnumGamemode, data.getGameMode().toString()),
|
||||
data.getDisplayName() == null ? null : toNMSComponent(data.getDisplayName(), clientVersion),
|
||||
data.getProfilePublicKey() == null ? null : nms.newRemoteChatSession$Data.newInstance(data.getChatSessionId(), data.getProfilePublicKey()));
|
||||
items.add(obj);
|
||||
}
|
||||
nms.setField(nmsPacket, nms.PacketPlayOutPlayerInfo_ACTION, EnumSet.of(array[0], array));
|
||||
nms.setField(nmsPacket, nms.PacketPlayOutPlayerInfo_PLAYERS, items);
|
||||
return nmsPacket;
|
||||
} else {
|
||||
//1.19.2-
|
||||
EnumPlayerInfoAction action = packet.getActions().contains(EnumPlayerInfoAction.ADD_PLAYER) ?
|
||||
EnumPlayerInfoAction.ADD_PLAYER : packet.getActions().iterator().next();
|
||||
Object nmsPacket = nms.newPacketPlayOutPlayerInfo.newInstance(Enum.valueOf(nms.EnumPlayerInfoAction, action.toString()), Array.newInstance(nms.EntityPlayer, 0));
|
||||
List<Object> items = new ArrayList<>();
|
||||
for (PlayerInfoData data : packet.getEntries()) {
|
||||
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.getParameterTypes()[0] == nms.PacketPlayOutPlayerInfo) {
|
||||
parameters.add(nmsPacket);
|
||||
}
|
||||
parameters.add(profile);
|
||||
parameters.add(data.getLatency());
|
||||
parameters.add(data.getGameMode() == null ? null : Enum.valueOf(nms.EnumGamemode, data.getGameMode().toString()));
|
||||
parameters.add(data.getDisplayName() == null ? null : toNMSComponent(data.getDisplayName(), clientVersion));
|
||||
if (nms.getMinorVersion() >= 19) parameters.add(data.getProfilePublicKey());
|
||||
items.add(nms.newPlayerInfoData.newInstance(parameters.toArray()));
|
||||
}
|
||||
nms.setField(nmsPacket, nms.PacketPlayOutPlayerInfo_PLAYERS, items);
|
||||
return nmsPacket;
|
||||
}
|
||||
nms.setField(nmsPacket, nms.PacketPlayOutPlayerInfo_PLAYERS, items);
|
||||
return nmsPacket;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -132,7 +166,7 @@ public class BukkitPacketBuilder extends PacketBuilder {
|
||||
if (nms.getMinorVersion() >= 13) {
|
||||
return nms.newPacketPlayOutScoreboardObjective.newInstance(nms.newScoreboardObjective.newInstance(null, packet.getObjectiveName(), null,
|
||||
toNMSComponent(IChatBaseComponent.optimizedComponent(displayName), clientVersion),
|
||||
packet.getRenderType() == null ? null : nms.EnumScoreboardHealthDisplay_values[packet.getRenderType().ordinal()]),
|
||||
packet.getRenderType() == null ? null : Enum.valueOf(nms.EnumScoreboardHealthDisplay, packet.getRenderType().toString())),
|
||||
packet.getAction());
|
||||
}
|
||||
|
||||
@@ -140,7 +174,7 @@ public class BukkitPacketBuilder extends PacketBuilder {
|
||||
nms.setField(nmsPacket, nms.PacketPlayOutScoreboardObjective_OBJECTIVENAME, packet.getObjectiveName());
|
||||
nms.setField(nmsPacket, nms.PacketPlayOutScoreboardObjective_DISPLAYNAME, displayName);
|
||||
if (nms.getMinorVersion() >= 8 && packet.getRenderType() != null) {
|
||||
nms.setField(nmsPacket, nms.PacketPlayOutScoreboardObjective_RENDERTYPE, Enum.valueOf((Class<Enum>) nms.EnumScoreboardHealthDisplay, packet.getRenderType().toString()));
|
||||
nms.setField(nmsPacket, nms.PacketPlayOutScoreboardObjective_RENDERTYPE, Enum.valueOf(nms.EnumScoreboardHealthDisplay, packet.getRenderType().toString()));
|
||||
}
|
||||
nms.setField(nmsPacket, nms.PacketPlayOutScoreboardObjective_METHOD, packet.getAction());
|
||||
return nmsPacket;
|
||||
@@ -149,7 +183,7 @@ public class BukkitPacketBuilder extends PacketBuilder {
|
||||
@Override
|
||||
public Object build(PacketPlayOutScoreboardScore packet, ProtocolVersion clientVersion) throws ReflectiveOperationException {
|
||||
if (nms.getMinorVersion() >= 13) {
|
||||
return nms.newPacketPlayOutScoreboardScore_1_13.newInstance(nms.EnumScoreboardAction_values[packet.getAction().ordinal()], packet.getObjectiveName(), packet.getPlayer(), packet.getScore());
|
||||
return nms.newPacketPlayOutScoreboardScore_1_13.newInstance(Enum.valueOf(nms.EnumScoreboardAction, packet.getAction().toString()), packet.getObjectiveName(), packet.getPlayer(), packet.getScore());
|
||||
}
|
||||
if (packet.getAction() == PacketPlayOutScoreboardScore.Action.REMOVE) {
|
||||
return nms.newPacketPlayOutScoreboardScore_String.newInstance(packet.getPlayer());
|
||||
@@ -189,9 +223,9 @@ public class BukkitPacketBuilder extends PacketBuilder {
|
||||
case 2:
|
||||
return nms.PacketPlayOutScoreboardTeam_ofBoolean.invoke(null, team, false);
|
||||
case 3:
|
||||
return nms.PacketPlayOutScoreboardTeam_ofString.invoke(null, team, packet.getPlayers().toArray(new String[0])[0], nms.PacketPlayOutScoreboardTeam_PlayerAction_values[0]);
|
||||
return nms.PacketPlayOutScoreboardTeam_ofString.invoke(null, team, packet.getPlayers().iterator().next(), Enum.valueOf(nms.PacketPlayOutScoreboardTeam_PlayerAction, "ADD"));
|
||||
case 4:
|
||||
return nms.PacketPlayOutScoreboardTeam_ofString.invoke(null, team, packet.getPlayers().toArray(new String[0])[0], nms.PacketPlayOutScoreboardTeam_PlayerAction_values[1]);
|
||||
return nms.PacketPlayOutScoreboardTeam_ofString.invoke(null, team, packet.getPlayers().iterator().next(), Enum.valueOf(nms.PacketPlayOutScoreboardTeam_PlayerAction, "REMOVE"));
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid action: " + packet.getAction());
|
||||
}
|
||||
@@ -227,7 +261,12 @@ public class BukkitPacketBuilder extends PacketBuilder {
|
||||
* if thrown by reflective operation
|
||||
*/
|
||||
public Object build(PacketPlayOutEntityMetadata packet) throws ReflectiveOperationException {
|
||||
return nms.newPacketPlayOutEntityMetadata.newInstance(packet.getEntityId(), packet.getDataWatcher().toNMS(), true);
|
||||
if (nms.newPacketPlayOutEntityMetadata.getParameterCount() == 2) {
|
||||
//1.19.3+
|
||||
return nms.newPacketPlayOutEntityMetadata.newInstance(packet.getEntityId(), nms.DataWatcher_b.invoke(packet.getDataWatcher().toNMS()));
|
||||
} else {
|
||||
return nms.newPacketPlayOutEntityMetadata.newInstance(packet.getEntityId(), packet.getDataWatcher().toNMS(), true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -264,7 +303,7 @@ public class BukkitPacketBuilder extends PacketBuilder {
|
||||
}
|
||||
int id = entityIds.get(packet.getEntityType());
|
||||
if (nms.getMinorVersion() >= 19) {
|
||||
nms.setField(nmsPacket, nms.PacketPlayOutSpawnEntityLiving_ENTITYTYPE, nms.Registry_a.invoke(nms.IRegistry_X, id));
|
||||
nms.setField(nmsPacket, nms.PacketPlayOutSpawnEntityLiving_ENTITYTYPE, nms.EntityTypes_ARMOR_STAND); // :(
|
||||
} else {
|
||||
nms.setField(nmsPacket, nms.PacketPlayOutSpawnEntityLiving_ENTITYTYPE, id);
|
||||
}
|
||||
@@ -322,9 +361,9 @@ public class BukkitPacketBuilder extends PacketBuilder {
|
||||
if (prefix != null) nms.ScoreboardTeam_setPrefix.invoke(team, toNMSComponent(IChatBaseComponent.optimizedComponent(prefix), clientVersion));
|
||||
if (suffix != null) nms.ScoreboardTeam_setSuffix.invoke(team, toNMSComponent(IChatBaseComponent.optimizedComponent(suffix), clientVersion));
|
||||
EnumChatFormat format = packet.getColor() != null ? packet.getColor() : EnumChatFormat.lastColorsOf(prefix);
|
||||
nms.ScoreboardTeam_setColor.invoke(team, nms.EnumChatFormat_values[format.ordinal()]);
|
||||
nms.ScoreboardTeam_setNameTagVisibility.invoke(team, String.valueOf(packet.getNameTagVisibility()).equals("always") ? nms.EnumNameTagVisibility_values[0] : nms.EnumNameTagVisibility_values[1]);
|
||||
nms.ScoreboardTeam_setCollisionRule.invoke(team, String.valueOf(packet.getCollisionRule()).equals("always") ? nms.EnumTeamPush_values[0] : nms.EnumTeamPush_values[1]);
|
||||
nms.ScoreboardTeam_setColor.invoke(team, Enum.valueOf(nms.EnumChatFormat, format.toString()));
|
||||
nms.ScoreboardTeam_setNameTagVisibility.invoke(team, Enum.valueOf(nms.EnumNameTagVisibility, String.valueOf(packet.getNameTagVisibility()).equals("always") ? "ALWAYS" : "NEVER"));
|
||||
nms.ScoreboardTeam_setCollisionRule.invoke(team, Enum.valueOf(nms.EnumTeamPush, String.valueOf(packet.getCollisionRule()).equals("always") ? "ALWAYS" : "NEVER"));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -344,31 +383,71 @@ public class BukkitPacketBuilder extends PacketBuilder {
|
||||
private void createTeamLegacy(PacketPlayOutScoreboardTeam packet, Object team, String prefix, String suffix) throws ReflectiveOperationException {
|
||||
if (prefix != null) nms.ScoreboardTeam_setPrefix.invoke(team, prefix);
|
||||
if (suffix != null) nms.ScoreboardTeam_setSuffix.invoke(team, suffix);
|
||||
if (nms.getMinorVersion() >= 8) nms.ScoreboardTeam_setNameTagVisibility.invoke(team, String.valueOf(packet.getNameTagVisibility()).equals("always") ? nms.EnumNameTagVisibility_values[0] : nms.EnumNameTagVisibility_values[1]);
|
||||
if (nms.getMinorVersion() >= 9) nms.ScoreboardTeam_setCollisionRule.invoke(team, String.valueOf(packet.getCollisionRule()).equals("always") ? nms.EnumTeamPush_values[0] : nms.EnumTeamPush_values[1]);
|
||||
if (nms.getMinorVersion() >= 8) nms.ScoreboardTeam_setNameTagVisibility.invoke(team, Enum.valueOf(nms.EnumNameTagVisibility, packet.getNameTagVisibility().equals("always") ? "ALWAYS" : "NEVER"));
|
||||
if (nms.getMinorVersion() >= 9) nms.ScoreboardTeam_setCollisionRule.invoke(team, Enum.valueOf(nms.EnumTeamPush, packet.getCollisionRule().equals("always") ? "ALWAYS" : "NEVER"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public PacketPlayOutPlayerInfo readPlayerInfo(Object nmsPacket, ProtocolVersion clientVersion) throws ReflectiveOperationException {
|
||||
if (nms.getMinorVersion() < 8) return null;
|
||||
EnumPlayerInfoAction action = EnumPlayerInfoAction.valueOf(nms.PacketPlayOutPlayerInfo_ACTION.get(nmsPacket).toString());
|
||||
List<PlayerInfoData> listData = new ArrayList<>();
|
||||
for (Object nmsData : (List<?>) nms.PacketPlayOutPlayerInfo_PLAYERS.get(nmsPacket)) {
|
||||
Object nmsGameMode = nms.PlayerInfoData_getGamemode.invoke(nmsData);
|
||||
EnumGamemode gameMode = (nmsGameMode == null) ? null : EnumGamemode.valueOf(nmsGameMode.toString());
|
||||
GameProfile profile = (GameProfile) nms.PlayerInfoData_getProfile.invoke(nmsData);
|
||||
Object nmsComponent = nms.PlayerInfoData_getDisplayName.invoke(nmsData);
|
||||
IChatBaseComponent listName = nmsComponent == null ? null : new WrappedChatComponent(nmsComponent);
|
||||
Skin skin = null;
|
||||
if (!profile.getProperties().get("textures").isEmpty()) {
|
||||
Property pr = profile.getProperties().get("textures").iterator().next();
|
||||
skin = new Skin(pr.getValue(), pr.getSignature());
|
||||
if (nms.ClientboundPlayerInfoRemovePacket != null) {
|
||||
//1.19.3+
|
||||
if (nms.ClientboundPlayerInfoRemovePacket.isInstance(nmsPacket)) {
|
||||
List<UUID> entries = (List<UUID>) nms.ClientboundPlayerInfoRemovePacket_getEntries.invoke(nmsPacket);
|
||||
return new PacketPlayOutPlayerInfo(
|
||||
EnumPlayerInfoAction.REMOVE_PLAYER,
|
||||
entries.stream().map(PlayerInfoData::new).collect(Collectors.toList())
|
||||
);
|
||||
}
|
||||
Object profilePublicKey = nms.getMinorVersion() >= 19 ? nms.PlayerInfoData_getProfilePublicKeyRecord.invoke(nmsData) : null;
|
||||
listData.add(new PlayerInfoData(profile.getName(), profile.getId(), skin,
|
||||
(int) nms.PlayerInfoData_getLatency.invoke(nmsData), gameMode, listName, profilePublicKey));
|
||||
EnumSet<?> set = (EnumSet<?>) nms.PacketPlayOutPlayerInfo_ACTION.get(nmsPacket);
|
||||
EnumPlayerInfoAction[] array = set.stream().map(action -> EnumPlayerInfoAction.valueOf(action.toString())).toArray(EnumPlayerInfoAction[]::new);
|
||||
EnumSet<EnumPlayerInfoAction> actions = EnumSet.of(array[0], array);
|
||||
List<PlayerInfoData> listData = new ArrayList<>();
|
||||
for (Object nmsData : (List<?>) nms.PacketPlayOutPlayerInfo_PLAYERS.get(nmsPacket)) {
|
||||
Object nmsGameMode = nms.PlayerInfoData_getGamemode.invoke(nmsData);
|
||||
EnumGamemode gameMode = (nmsGameMode == null) ? null : EnumGamemode.valueOf(nmsGameMode.toString());
|
||||
GameProfile profile = (GameProfile) nms.PlayerInfoData_getProfile.invoke(nmsData);
|
||||
Object nmsComponent = nms.PlayerInfoData_getDisplayName.invoke(nmsData);
|
||||
Skin skin = null;
|
||||
if (!profile.getProperties().get("textures").isEmpty()) {
|
||||
Property pr = profile.getProperties().get("textures").iterator().next();
|
||||
skin = new Skin(pr.getValue(), pr.getSignature());
|
||||
}
|
||||
Object remoteChatSession = nms.PlayerInfoData_getProfilePublicKeyRecord.invoke(nmsData);
|
||||
listData.add(
|
||||
new PlayerInfoData(
|
||||
profile.getName(),
|
||||
profile.getId(),
|
||||
skin,
|
||||
(boolean) nms.PlayerInfoData_isListed.invoke(nmsData),
|
||||
(int) nms.PlayerInfoData_getLatency.invoke(nmsData),
|
||||
gameMode,
|
||||
nmsComponent == null ? null : new WrappedChatComponent(nmsComponent),
|
||||
remoteChatSession == null ? null : (UUID) nms.RemoteChatSession$Data_getSessionId.invoke(remoteChatSession),
|
||||
remoteChatSession == null ? null : nms.RemoteChatSession$Data_getProfilePublicKey.invoke(remoteChatSession)));
|
||||
}
|
||||
return new PacketPlayOutPlayerInfo(actions, listData);
|
||||
} else {
|
||||
//1.19.2-
|
||||
EnumPlayerInfoAction action = EnumPlayerInfoAction.valueOf(nms.PacketPlayOutPlayerInfo_ACTION.get(nmsPacket).toString());
|
||||
List<PlayerInfoData> listData = new ArrayList<>();
|
||||
for (Object nmsData : (List<?>) nms.PacketPlayOutPlayerInfo_PLAYERS.get(nmsPacket)) {
|
||||
Object nmsGameMode = nms.PlayerInfoData_getGamemode.invoke(nmsData);
|
||||
EnumGamemode gameMode = (nmsGameMode == null) ? null : EnumGamemode.valueOf(nmsGameMode.toString());
|
||||
GameProfile profile = (GameProfile) nms.PlayerInfoData_getProfile.invoke(nmsData);
|
||||
Object nmsComponent = nms.PlayerInfoData_getDisplayName.invoke(nmsData);
|
||||
IChatBaseComponent listName = nmsComponent == null ? null : new WrappedChatComponent(nmsComponent);
|
||||
Skin skin = null;
|
||||
if (!profile.getProperties().get("textures").isEmpty()) {
|
||||
Property pr = profile.getProperties().get("textures").iterator().next();
|
||||
skin = new Skin(pr.getValue(), pr.getSignature());
|
||||
}
|
||||
Object profilePublicKey = nms.getMinorVersion() >= 19 ? nms.PlayerInfoData_getProfilePublicKeyRecord.invoke(nmsData) : null;
|
||||
listData.add(new PlayerInfoData(profile.getName(), profile.getId(), skin, true,
|
||||
(int) nms.PlayerInfoData_getLatency.invoke(nmsData), gameMode, listName, null, profilePublicKey));
|
||||
}
|
||||
return new PacketPlayOutPlayerInfo(action, listData);
|
||||
}
|
||||
return new PacketPlayOutPlayerInfo(action, listData);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -13,6 +13,7 @@ import me.neznamy.tab.platforms.bukkit.nms.NMSStorage;
|
||||
import me.neznamy.tab.api.TabConstants;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.shared.features.PipelineInjector;
|
||||
import me.neznamy.tab.shared.features.sorting.Sorting;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
@@ -66,7 +67,8 @@ public class BukkitPipelineInjector extends PipelineInjector {
|
||||
@Override
|
||||
public void write(ChannelHandlerContext context, Object packet, ChannelPromise channelPromise) {
|
||||
try {
|
||||
if (nms.PacketPlayOutPlayerInfo.isInstance(packet)) {
|
||||
if (nms.PacketPlayOutPlayerInfo.isInstance(packet) ||
|
||||
(nms.ClientboundPlayerInfoRemovePacket != null && nms.ClientboundPlayerInfoRemovePacket.isInstance(packet))) {
|
||||
super.write(context, TAB.getInstance().getFeatureManager().onPacketPlayOutPlayerInfo(player, packet), channelPromise);
|
||||
return;
|
||||
}
|
||||
@@ -117,9 +119,10 @@ public class BukkitPipelineInjector extends PipelineInjector {
|
||||
newList.add(entry);
|
||||
continue;
|
||||
}
|
||||
Sorting sorting = (Sorting) TAB.getInstance().getFeatureManager().getFeature(TabConstants.Feature.SORTING);
|
||||
if (!((TabFeature)TAB.getInstance().getTeamManager()).isDisabledPlayer(p) &&
|
||||
!TAB.getInstance().getTeamManager().hasTeamHandlingPaused(p) && !teamName.equals(p.getTeamName())) {
|
||||
logTeamOverride(teamName, p.getName(), p.getTeamName());
|
||||
!TAB.getInstance().getTeamManager().hasTeamHandlingPaused(p) && !teamName.equals(sorting.getShortTeamName(p))) {
|
||||
logTeamOverride(teamName, p.getName(), sorting.getShortTeamName(p));
|
||||
} else {
|
||||
newList.add(entry);
|
||||
}
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
package me.neznamy.tab.platforms.bukkit;
|
||||
|
||||
import com.earth2me.essentials.Essentials;
|
||||
import com.viaversion.viaversion.api.Via;
|
||||
import me.clip.placeholderapi.PlaceholderAPI;
|
||||
import me.neznamy.tab.api.TabConstants;
|
||||
import me.neznamy.tab.api.TabPlayer;
|
||||
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;
|
||||
import me.neznamy.tab.platforms.bukkit.features.PerWorldPlayerList;
|
||||
import me.neznamy.tab.platforms.bukkit.features.PetFix;
|
||||
@@ -15,10 +13,10 @@ 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.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;
|
||||
import me.neznamy.tab.shared.features.sorting.Sorting;
|
||||
import me.neznamy.tab.shared.permission.LuckPerms;
|
||||
import me.neznamy.tab.shared.permission.None;
|
||||
import me.neznamy.tab.shared.permission.PermissionPlugin;
|
||||
@@ -43,7 +41,6 @@ public class BukkitPlatform extends Platform {
|
||||
/** Variables checking presence of other plugins to hook into */
|
||||
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(TabConstants.Plugin.PROTOCOL_SUPPORT);
|
||||
|
||||
@@ -88,6 +85,7 @@ public class BukkitPlatform extends Platform {
|
||||
tab.getFeatureManager().registerFeature(TabConstants.Feature.PIPELINE_INJECTION, new BukkitPipelineInjector());
|
||||
new BukkitPlaceholderRegistry(plugin).registerPlaceholders(tab.getPlaceholderManager());
|
||||
if (tab.getConfiguration().getConfig().getBoolean("scoreboard-teams.enabled", true)) {
|
||||
tab.getFeatureManager().registerFeature(TabConstants.Feature.SORTING, new Sorting());
|
||||
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));
|
||||
} else {
|
||||
@@ -182,16 +180,6 @@ public class BukkitPlatform extends Platform {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void callLoadEvent() {
|
||||
Bukkit.getPluginManager().callEvent(new TabLoadEvent());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void callLoadEvent(TabPlayer player) {
|
||||
Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, () -> Bukkit.getPluginManager().callEvent(new TabPlayerLoadEvent(player)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns status of LibsDisguises plugin presence
|
||||
*
|
||||
@@ -213,20 +201,6 @@ public class BukkitPlatform extends Platform {
|
||||
libsDisguises = enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Essentials' main class if the plugin is installed, {@code null} if not
|
||||
*
|
||||
* @return Essentials instance or {@code null} if plugin is not installed
|
||||
*/
|
||||
public Essentials getEssentials() {
|
||||
return (Essentials) essentials;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getConfigName() {
|
||||
return "bukkitconfig.yml";
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets protocol version of requested player and returns it.
|
||||
*
|
||||
|
||||
@@ -16,7 +16,6 @@ import org.bukkit.entity.Player;
|
||||
import org.bukkit.metadata.MetadataValue;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
|
||||
import com.earth2me.essentials.Essentials;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import com.viaversion.viaversion.api.Via;
|
||||
import com.viaversion.viaversion.api.legacy.bossbar.BossColor;
|
||||
@@ -56,7 +55,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, true);
|
||||
super(p, p.getUniqueId(), p.getName(), TAB.getInstance().getConfiguration().getServerName(), p.getWorld().getName(), protocolVersion, true);
|
||||
try {
|
||||
handle = NMSStorage.getInstance().getHandle.invoke(player);
|
||||
playerConnection = NMSStorage.getInstance().PLAYER_CONNECTION.get(handle);
|
||||
@@ -277,10 +276,7 @@ public class BukkitTabPlayer extends ITabPlayer {
|
||||
|
||||
@Override
|
||||
public boolean isVanished() {
|
||||
Essentials essentials = ((BukkitPlatform)TAB.getInstance().getPlatform()).getEssentials();
|
||||
if (essentials != null && essentials.getUser(getUniqueId()).isVanished()) return true;
|
||||
List<MetadataValue> metadata = getPlayer().getMetadata("vanished");
|
||||
return !metadata.isEmpty() && metadata.get(0).asBoolean();
|
||||
return getPlayer().getMetadata("vanished").stream().anyMatch(MetadataValue::asBoolean);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@@ -293,15 +289,36 @@ public class BukkitTabPlayer extends ITabPlayer {
|
||||
public Object getProfilePublicKey() {
|
||||
if (NMSStorage.getInstance().getMinorVersion() < 19) return null;
|
||||
try {
|
||||
Object key = NMSStorage.getInstance().EntityHuman_ProfilePublicKey.get(handle);
|
||||
if (key == null) return null;
|
||||
return NMSStorage.getInstance().ProfilePublicKey_getRecord.invoke(key);
|
||||
if (NMSStorage.getInstance().RemoteChatSession != null) {
|
||||
//1.19.3+
|
||||
Object session = NMSStorage.getInstance().EntityPlayer_RemoteChatSession.get(handle);
|
||||
if (session == null) return null;
|
||||
Object key = NMSStorage.getInstance().RemoteChatSession_getProfilePublicKey.invoke(session);
|
||||
return NMSStorage.getInstance().ProfilePublicKey_getRecord.invoke(key);
|
||||
} else {
|
||||
Object key = NMSStorage.getInstance().EntityHuman_ProfilePublicKey.get(handle);
|
||||
if (key == null) return null;
|
||||
return NMSStorage.getInstance().ProfilePublicKey_getRecord.invoke(key);
|
||||
}
|
||||
} catch (ReflectiveOperationException e) {
|
||||
TAB.getInstance().getErrorManager().printError("Failed to get profile key of " + getName(), e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID getChatSessionId() {
|
||||
if (NMSStorage.getInstance().RemoteChatSession != null) return null;
|
||||
try {
|
||||
Object session = NMSStorage.getInstance().EntityPlayer_RemoteChatSession.get(handle);
|
||||
if (session == null) return null;
|
||||
return (UUID) NMSStorage.getInstance().RemoteChatSession_getSessionId.invoke(session);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
TAB.getInstance().getErrorManager().printError("Failed to get chat session of " + getName(), e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Channel getChannel() {
|
||||
try {
|
||||
|
||||
@@ -72,7 +72,7 @@ public class Main extends JavaPlugin {
|
||||
"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_19_R1");
|
||||
"v1_18_R2", "v1_19_R1", "v1_19_R2");
|
||||
String serverPackage = Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3];
|
||||
try {
|
||||
long time = System.currentTimeMillis();
|
||||
@@ -81,6 +81,7 @@ public class Main extends JavaPlugin {
|
||||
try {
|
||||
NMSStorage.setInstance(new BukkitModernNMSStorage());
|
||||
} catch (ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
NMSStorage.setInstance(new MojangModernNMSStorage());
|
||||
}
|
||||
} else {
|
||||
@@ -90,14 +91,14 @@ public class Main extends JavaPlugin {
|
||||
Bukkit.getConsoleSender().sendMessage(EnumChatFormat.color("[TAB] Loaded NMS hook in " + (System.currentTimeMillis()-time) + "ms"));
|
||||
return true;
|
||||
} else {
|
||||
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.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.2 - 1.19.3. Disabling just to stay safe."));
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
if (supportedVersions.contains(serverPackage)) {
|
||||
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 {
|
||||
Bukkit.getConsoleSender().sendMessage(EnumChatFormat.color("&c[TAB] Your server version is completely unsupported. This plugin version only supports 1.5.x - 1.19.2. Disabling."));
|
||||
Bukkit.getConsoleSender().sendMessage(EnumChatFormat.color("&c[TAB] Your server version is completely unsupported. This plugin version only supports 1.5.2 - 1.19.3. Disabling."));
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
package me.neznamy.tab.platforms.bukkit.event;
|
||||
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.HandlerList;
|
||||
|
||||
/**
|
||||
* Bukkit event that is called each time TAB fully loads. This includes server startup, reload,
|
||||
* /tab reload and /plugman reload tab
|
||||
*
|
||||
* @deprecated for removal, use {@link me.neznamy.tab.api.event.plugin.TabLoadEvent}
|
||||
*/
|
||||
@Deprecated
|
||||
public class TabLoadEvent extends Event {
|
||||
|
||||
private static final HandlerList handlers = new HandlerList();
|
||||
|
||||
@Override
|
||||
public HandlerList getHandlers(){
|
||||
return getHandlerList();
|
||||
}
|
||||
|
||||
public static HandlerList getHandlerList() {
|
||||
return handlers;
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
package me.neznamy.tab.platforms.bukkit.event;
|
||||
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.HandlerList;
|
||||
|
||||
import me.neznamy.tab.api.TabPlayer;
|
||||
|
||||
/**
|
||||
* Bukkit 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 static final HandlerList handlers = new HandlerList();
|
||||
|
||||
private final TabPlayer player;
|
||||
|
||||
public TabPlayerLoadEvent(TabPlayer player) {
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HandlerList getHandlers(){
|
||||
return getHandlerList();
|
||||
}
|
||||
|
||||
public static HandlerList getHandlerList() {
|
||||
return handlers;
|
||||
}
|
||||
|
||||
public TabPlayer getPlayer() {
|
||||
return player;
|
||||
}
|
||||
}
|
||||
+11
-3
@@ -6,6 +6,7 @@ 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.features.TabExpansion;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -45,9 +46,16 @@ public class BukkitTabExpansion extends PlaceholderExpansion implements TabExpan
|
||||
@Override
|
||||
public String onPlaceholderRequest(Player player, @NotNull String identifier){
|
||||
if (identifier.startsWith("replace_")) {
|
||||
String placeholder = "%" + identifier.substring(8) + "%";
|
||||
String output = PlaceholderAPI.setPlaceholders(player, placeholder);
|
||||
return TabAPI.getInstance().getPlaceholderManager().findReplacement(placeholder, output);
|
||||
String text = "%" + identifier.substring(8) + "%";
|
||||
String textBefore;
|
||||
do {
|
||||
textBefore = text;
|
||||
for (String placeholder : TAB.getInstance().getPlaceholderManager().detectPlaceholders(text)) {
|
||||
text = text.replace(placeholder, TabAPI.getInstance().getPlaceholderManager().findReplacement(placeholder,
|
||||
PlaceholderAPI.setPlaceholders(player, placeholder)));
|
||||
}
|
||||
} while (!textBefore.equals(text));
|
||||
return text;
|
||||
}
|
||||
if (identifier.startsWith("placeholder_")) {
|
||||
TabAPI.getInstance().getPlaceholderManager().addUsedPlaceholder("%" + identifier.substring(12) + "%", (TabFeature) TabAPI.getInstance().getPlaceholderManager());
|
||||
|
||||
@@ -125,8 +125,16 @@ public class PetFix extends TabFeature {
|
||||
try {
|
||||
for (Object item : items) {
|
||||
if (item == null) continue;
|
||||
if (nms.DataWatcherObject_SLOT.getInt(nms.DataWatcherItem_TYPE.get(item)) == petOwnerPosition) {
|
||||
Object value = nms.DataWatcherItem_VALUE.get(item);
|
||||
int slot;
|
||||
Object value;
|
||||
if (nms.is1_19_3Plus()) {
|
||||
slot = nms.DataWatcher$DataValue_POSITION.getInt(item);
|
||||
value = nms.DataWatcher$DataValue_VALUE.get(item);
|
||||
} else {
|
||||
slot = nms.DataWatcherObject_SLOT.getInt(nms.DataWatcherItem_TYPE.get(item));
|
||||
value = nms.DataWatcherItem_VALUE.get(item);
|
||||
}
|
||||
if (slot == petOwnerPosition) {
|
||||
if (value instanceof Optional || value instanceof com.google.common.base.Optional) {
|
||||
removedEntry = item;
|
||||
}
|
||||
|
||||
+33
-18
@@ -3,6 +3,7 @@ package me.neznamy.tab.platforms.bukkit.nms;
|
||||
/**
|
||||
* NMS loader for minecraft 1.17+ using Mojang packaging and bukkit names.
|
||||
*/
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
public class BukkitModernNMSStorage extends ModernNMSStorage {
|
||||
|
||||
/**
|
||||
@@ -26,8 +27,7 @@ public class BukkitModernNMSStorage extends ModernNMSStorage {
|
||||
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);
|
||||
EntityTypes_ARMOR_STAND = EntityTypes.getDeclaredField("d").get(null);
|
||||
PacketPlayOutSpawnEntityLiving_ENTITYTYPE = getField(PacketPlayOutSpawnEntityLiving, "e");
|
||||
}
|
||||
}
|
||||
@@ -41,16 +41,17 @@ public class BukkitModernNMSStorage extends ModernNMSStorage {
|
||||
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");
|
||||
EnumChatFormat = (Class<Enum>) 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");
|
||||
ChatMessageType = (Class<Enum>) Class.forName("net.minecraft.network.chat.ChatMessageType");
|
||||
}
|
||||
|
||||
// DataWatcher
|
||||
@@ -59,6 +60,9 @@ public class BukkitModernNMSStorage extends ModernNMSStorage {
|
||||
DataWatcherObject = Class.forName("net.minecraft.network.syncher.DataWatcherObject");
|
||||
DataWatcherRegistry = Class.forName("net.minecraft.network.syncher.DataWatcherRegistry");
|
||||
DataWatcherSerializer = Class.forName("net.minecraft.network.syncher.DataWatcherSerializer");
|
||||
if (is1_19_3Plus()) {
|
||||
DataWatcher$DataValue = Class.forName("net.minecraft.network.syncher.DataWatcher$b");
|
||||
}
|
||||
|
||||
// Entities
|
||||
PacketPlayOutSpawnEntityLiving = getModernClass("net.minecraft.network.protocol.game.PacketPlayOutSpawnEntityLiving",
|
||||
@@ -71,19 +75,30 @@ public class BukkitModernNMSStorage extends ModernNMSStorage {
|
||||
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");
|
||||
EnumEntityUseAction = (Class<Enum>) 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");
|
||||
ProfilePublicKey = Class.forName("net.minecraft.world.entity.player.ProfilePublicKey");
|
||||
ProfilePublicKey$a = Class.forName("net.minecraft.world.entity.player.ProfilePublicKey$a");
|
||||
EntityTypes = Class.forName("net.minecraft.world.entity.EntityTypes");
|
||||
}
|
||||
|
||||
// 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");
|
||||
if (minorVersion >= 19) {
|
||||
ProfilePublicKey = Class.forName("net.minecraft.world.entity.player.ProfilePublicKey");
|
||||
ProfilePublicKey$a = Class.forName("net.minecraft.world.entity.player.ProfilePublicKey$a");
|
||||
}
|
||||
if (is1_19_3Plus()) {
|
||||
//1.19.3+
|
||||
ClientboundPlayerInfoRemovePacket = Class.forName("net.minecraft.network.protocol.game.ClientboundPlayerInfoRemovePacket");
|
||||
PacketPlayOutPlayerInfo = Class.forName("net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket");
|
||||
EnumPlayerInfoAction = (Class<Enum>) Class.forName("net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket$a");
|
||||
PlayerInfoData = Class.forName("net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket$b");
|
||||
RemoteChatSession = Class.forName("net.minecraft.network.chat.RemoteChatSession");
|
||||
RemoteChatSession$Data = Class.forName("net.minecraft.network.chat.RemoteChatSession$a");
|
||||
} else {
|
||||
PacketPlayOutPlayerInfo = Class.forName("net.minecraft.network.protocol.game.PacketPlayOutPlayerInfo");
|
||||
EnumPlayerInfoAction = (Class<Enum>) Class.forName("net.minecraft.network.protocol.game.PacketPlayOutPlayerInfo$EnumPlayerInfoAction");
|
||||
PlayerInfoData = Class.forName("net.minecraft.network.protocol.game.PacketPlayOutPlayerInfo$PlayerInfoData");
|
||||
}
|
||||
EnumGamemode = (Class<Enum>) Class.forName("net.minecraft.world.level.EnumGamemode");
|
||||
|
||||
// Scoreboard
|
||||
PacketPlayOutScoreboardDisplayObjective = Class.forName("net.minecraft.network.protocol.game.PacketPlayOutScoreboardDisplayObjective");
|
||||
@@ -93,12 +108,12 @@ public class BukkitModernNMSStorage extends ModernNMSStorage {
|
||||
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");
|
||||
EnumScoreboardHealthDisplay = (Class<Enum>) Class.forName("net.minecraft.world.scores.criteria.IScoreboardCriteria$EnumScoreboardHealthDisplay");
|
||||
EnumScoreboardAction = (Class<Enum>) 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");
|
||||
EnumNameTagVisibility = (Class<Enum>) Class.forName("net.minecraft.world.scores.ScoreboardTeamBase$EnumNameTagVisibility");
|
||||
EnumTeamPush = (Class<Enum>) Class.forName("net.minecraft.world.scores.ScoreboardTeamBase$EnumTeamPush");
|
||||
PacketPlayOutScoreboardTeam_PlayerAction = (Class<Enum>) Class.forName("net.minecraft.network.protocol.game.PacketPlayOutScoreboardTeam$a");
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import java.util.Arrays;
|
||||
/**
|
||||
* NMS loader for Minecraft 1.16.5 and lower using old NMS class structure.
|
||||
*/
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
public class LegacyNMSStorage extends NMSStorage {
|
||||
|
||||
/**
|
||||
@@ -72,7 +73,7 @@ public class LegacyNMSStorage extends NMSStorage {
|
||||
ChatSerializer_DESERIALIZE = getMethod(ChatSerializer, new String[]{"a", "func_150699_a"}, String.class); // {Bukkit, Thermos}
|
||||
}
|
||||
if (minorVersion >= 8) {
|
||||
ScoreboardTeam_setNameTagVisibility = getMethod(ScoreboardTeam, "setNameTagVisibility", EnumNameTagVisibility);
|
||||
ScoreboardTeam_setNameTagVisibility = getMethod(ScoreboardTeam, new String[] {"setNameTagVisibility", "a"}, EnumNameTagVisibility); // {1.8.1+, 1.8}
|
||||
}
|
||||
if (minorVersion >= 9) {
|
||||
DataWatcher_REGISTER = getMethod(DataWatcher, "register", DataWatcherObject, Object.class);
|
||||
@@ -93,7 +94,7 @@ public class LegacyNMSStorage extends NMSStorage {
|
||||
EntityHuman = getLegacyClass("EntityHuman");
|
||||
World = getLegacyClass("World");
|
||||
Packet = getLegacyClass("Packet");
|
||||
EnumChatFormat = getLegacyClass("EnumChatFormat");
|
||||
EnumChatFormat = (Class<Enum>) getLegacyClass("EnumChatFormat");
|
||||
EntityPlayer = getLegacyClass("EntityPlayer");
|
||||
Entity = getLegacyClass("Entity");
|
||||
EntityLiving = getLegacyClass("EntityLiving");
|
||||
@@ -109,7 +110,7 @@ public class LegacyNMSStorage extends NMSStorage {
|
||||
EntityArmorStand = getLegacyClass("EntityArmorStand");
|
||||
}
|
||||
if (minorVersion >= 12) {
|
||||
ChatMessageType = getLegacyClass("ChatMessageType");
|
||||
ChatMessageType = (Class<Enum>) getLegacyClass("ChatMessageType");
|
||||
}
|
||||
|
||||
// DataWatcher
|
||||
@@ -131,15 +132,15 @@ public class LegacyNMSStorage extends NMSStorage {
|
||||
PacketPlayOutEntityMetadata = getLegacyClass("PacketPlayOutEntityMetadata", "Packet40EntityMetadata");
|
||||
PacketPlayOutNamedEntitySpawn = getLegacyClass("PacketPlayOutNamedEntitySpawn", "Packet20NamedEntitySpawn");
|
||||
if (minorVersion >= 7) {
|
||||
EnumEntityUseAction = getLegacyClass("PacketPlayInUseEntity$EnumEntityUseAction", "EnumEntityUseAction");
|
||||
EnumEntityUseAction = (Class<Enum>) getLegacyClass("PacketPlayInUseEntity$EnumEntityUseAction", "EnumEntityUseAction");
|
||||
}
|
||||
|
||||
// Player Info
|
||||
if (minorVersion >= 8) {
|
||||
PacketPlayOutPlayerInfo = getLegacyClass("PacketPlayOutPlayerInfo");
|
||||
EnumPlayerInfoAction = getLegacyClass("PacketPlayOutPlayerInfo$EnumPlayerInfoAction", "EnumPlayerInfoAction");
|
||||
EnumPlayerInfoAction = (Class<Enum>) getLegacyClass("PacketPlayOutPlayerInfo$EnumPlayerInfoAction", "EnumPlayerInfoAction");
|
||||
PlayerInfoData = getLegacyClass("PacketPlayOutPlayerInfo$PlayerInfoData", "PlayerInfoData");
|
||||
EnumGamemode = getLegacyClass("EnumGamemode", "WorldSettings$EnumGamemode");
|
||||
EnumGamemode = (Class<Enum>) getLegacyClass("EnumGamemode", "WorldSettings$EnumGamemode");
|
||||
}
|
||||
|
||||
// Scoreboard
|
||||
@@ -153,12 +154,12 @@ public class LegacyNMSStorage extends NMSStorage {
|
||||
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");
|
||||
EnumScoreboardHealthDisplay = (Class<Enum>) getLegacyClass("IScoreboardCriteria$EnumScoreboardHealthDisplay", "EnumScoreboardHealthDisplay");
|
||||
EnumScoreboardAction = (Class<Enum>) getLegacyClass("ScoreboardServer$Action", "PacketPlayOutScoreboardScore$EnumScoreboardAction", "EnumScoreboardAction");
|
||||
EnumNameTagVisibility = (Class<Enum>) getLegacyClass("ScoreboardTeamBase$EnumNameTagVisibility", "EnumNameTagVisibility");
|
||||
}
|
||||
if (minorVersion >= 9) {
|
||||
EnumTeamPush = getLegacyClass("ScoreboardTeamBase$EnumTeamPush");
|
||||
EnumTeamPush = (Class<Enum>) getLegacyClass("ScoreboardTeamBase$EnumTeamPush");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,10 +7,6 @@ import java.util.Arrays;
|
||||
*/
|
||||
public abstract class ModernNMSStorage extends NMSStorage {
|
||||
|
||||
/** Additional classes used in 1.19+ */
|
||||
protected Class<?> IRegistry;
|
||||
protected Class<?> Registry;
|
||||
|
||||
/**
|
||||
* Creates new instance, initializes required NMS classes and fields
|
||||
*
|
||||
|
||||
+31
-18
@@ -3,6 +3,7 @@ package me.neznamy.tab.platforms.bukkit.nms;
|
||||
/**
|
||||
* NMS loader for minecraft 1.17+ using Mojang packaging and names.
|
||||
*/
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
public class MojangModernNMSStorage extends ModernNMSStorage {
|
||||
|
||||
/**
|
||||
@@ -26,8 +27,7 @@ public class MojangModernNMSStorage extends ModernNMSStorage {
|
||||
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);
|
||||
EntityTypes_ARMOR_STAND = EntityTypes.getDeclaredField("ARMOR_STAND").get(null);
|
||||
PacketPlayOutSpawnEntityLiving_ENTITYTYPE = getField(PacketPlayOutSpawnEntityLiving, "type");
|
||||
}
|
||||
}
|
||||
@@ -41,7 +41,7 @@ public class MojangModernNMSStorage extends ModernNMSStorage {
|
||||
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");
|
||||
EnumChatFormat = (Class<Enum>) 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");
|
||||
@@ -50,7 +50,7 @@ public class MojangModernNMSStorage extends ModernNMSStorage {
|
||||
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");
|
||||
ChatMessageType = (Class<Enum>) Class.forName("net.minecraft.network.chat.ChatType");
|
||||
}
|
||||
|
||||
// DataWatcher
|
||||
@@ -59,6 +59,9 @@ public class MojangModernNMSStorage extends ModernNMSStorage {
|
||||
DataWatcherObject = Class.forName("net.minecraft.network.syncher.EntityDataAccessor");
|
||||
DataWatcherRegistry = Class.forName("net.minecraft.network.syncher.EntityDataSerializers");
|
||||
DataWatcherSerializer = Class.forName("net.minecraft.network.syncher.EntityDataSerializer");
|
||||
if (is1_19_3Plus()) {
|
||||
DataWatcher$DataValue = Class.forName("net.minecraft.network.syncher.SynchedEntityData$DataValue");
|
||||
}
|
||||
|
||||
// Entities
|
||||
PacketPlayOutSpawnEntityLiving = getModernClass("net.minecraft.network.protocol.game.ClientboundAddMobPacket",
|
||||
@@ -71,19 +74,29 @@ public class MojangModernNMSStorage extends ModernNMSStorage {
|
||||
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");
|
||||
EnumEntityUseAction = (Class<Enum>) 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");
|
||||
ProfilePublicKey = Class.forName("net.minecraft.world.entity.player.ProfilePublicKey");
|
||||
ProfilePublicKey$a = Class.forName("net.minecraft.world.entity.player.ProfilePublicKey$Data");
|
||||
EntityTypes = Class.forName("net.minecraft.world.entity.EntityType");
|
||||
}
|
||||
|
||||
// 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");
|
||||
if (minorVersion >= 19) {
|
||||
ProfilePublicKey = Class.forName("net.minecraft.world.entity.player.ProfilePublicKey");
|
||||
ProfilePublicKey$a = Class.forName("net.minecraft.world.entity.player.ProfilePublicKey$Data");
|
||||
}
|
||||
if (is1_19_3Plus()) {
|
||||
ClientboundPlayerInfoRemovePacket = Class.forName("net.minecraft.network.protocol.game.ClientboundPlayerInfoRemovePacket");
|
||||
PacketPlayOutPlayerInfo = Class.forName("net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket");
|
||||
EnumPlayerInfoAction = (Class<Enum>) Class.forName("net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket$Action");
|
||||
PlayerInfoData = Class.forName("net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket$Entry");
|
||||
RemoteChatSession = Class.forName("net.minecraft.network.chat.RemoteChatSession");
|
||||
RemoteChatSession$Data = Class.forName("net.minecraft.network.chat.RemoteChatSession$Data");
|
||||
} else {
|
||||
PacketPlayOutPlayerInfo = Class.forName("net.minecraft.network.protocol.game.ClientboundPlayerInfoPacket");
|
||||
EnumPlayerInfoAction = (Class<Enum>) Class.forName("net.minecraft.network.protocol.game.ClientboundPlayerInfoPacket$Action");
|
||||
PlayerInfoData = Class.forName("net.minecraft.network.protocol.game.ClientboundPlayerInfoPacket$PlayerUpdate");
|
||||
}
|
||||
EnumGamemode = (Class<Enum>) Class.forName("net.minecraft.world.level.GameType");
|
||||
|
||||
// Scoreboard
|
||||
PacketPlayOutScoreboardDisplayObjective = Class.forName("net.minecraft.network.protocol.game.ClientboundSetDisplayObjectivePacket");
|
||||
@@ -93,12 +106,12 @@ public class MojangModernNMSStorage extends ModernNMSStorage {
|
||||
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");
|
||||
EnumScoreboardHealthDisplay = (Class<Enum>) Class.forName("net.minecraft.world.scores.criteria.ObjectiveCriteria$RenderType");
|
||||
EnumScoreboardAction = (Class<Enum>) 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");
|
||||
EnumNameTagVisibility = (Class<Enum>) Class.forName("net.minecraft.world.scores.Team$Visibility");
|
||||
EnumTeamPush = (Class<Enum>) Class.forName("net.minecraft.world.scores.Team$CollisionRule");
|
||||
PacketPlayOutScoreboardTeam_PlayerAction = (Class<Enum>) Class.forName("net.minecraft.network.protocol.game.ClientboundSetPlayerTeamPacket$Action");
|
||||
}
|
||||
}
|
||||
@@ -29,7 +29,7 @@ public abstract class NMSStorage {
|
||||
protected Class<?> NetworkManager;
|
||||
protected Class<?> EntityArmorStand;
|
||||
protected Class<?> World;
|
||||
public Class<?> EnumChatFormat;
|
||||
public Class<Enum> EnumChatFormat;
|
||||
public Class<?> EntityPlayer;
|
||||
protected Class<?> EntityHuman;
|
||||
protected Class<?> Entity;
|
||||
@@ -40,10 +40,10 @@ public abstract class NMSStorage {
|
||||
public Field NETWORK_MANAGER;
|
||||
public Field CHANNEL;
|
||||
public Field EntityHuman_ProfilePublicKey;
|
||||
public Field EntityPlayer_RemoteChatSession;
|
||||
public Method getHandle;
|
||||
public Method sendPacket;
|
||||
public Method getProfile;
|
||||
public Enum[] EnumChatFormat_values;
|
||||
|
||||
/** Chat components */
|
||||
protected Class<?> IChatBaseComponent;
|
||||
@@ -52,9 +52,8 @@ public abstract class NMSStorage {
|
||||
|
||||
/** PacketPlayOutChat */
|
||||
protected Class<?> PacketPlayOutChat;
|
||||
public Class<?> ChatMessageType;
|
||||
public Class<Enum> ChatMessageType;
|
||||
public Constructor<?> newPacketPlayOutChat;
|
||||
public Enum[] ChatMessageType_values;
|
||||
|
||||
/** DataWatcher */
|
||||
protected Class<?> DataWatcher;
|
||||
@@ -69,10 +68,17 @@ public abstract class NMSStorage {
|
||||
public Field DataWatcherObject_SLOT;
|
||||
public Field DataWatcherObject_SERIALIZER;
|
||||
public Method DataWatcher_REGISTER;
|
||||
public Method DataWatcher_b;
|
||||
private final DataWatcherRegistry registry;
|
||||
//1.19.3+
|
||||
protected Class<?> DataWatcher$DataValue;
|
||||
public Field DataWatcher$DataValue_POSITION;
|
||||
public Field DataWatcher$DataValue_VALUE;
|
||||
public Method DataWatcher_markDirty;
|
||||
|
||||
/** PacketPlayOutSpawnEntityLiving */
|
||||
public Class<?> PacketPlayOutSpawnEntityLiving;
|
||||
public Class<?> EntityTypes;
|
||||
public Constructor<?> newPacketPlayOutSpawnEntityLiving;
|
||||
public Field PacketPlayOutSpawnEntityLiving_ENTITYID;
|
||||
public Field PacketPlayOutSpawnEntityLiving_ENTITYTYPE;
|
||||
@@ -83,8 +89,7 @@ public abstract class NMSStorage {
|
||||
public Field PacketPlayOutSpawnEntityLiving_Y;
|
||||
public Field PacketPlayOutSpawnEntityLiving_Z;
|
||||
public Field PacketPlayOutSpawnEntityLiving_DATAWATCHER;
|
||||
public Method Registry_a;
|
||||
public Object IRegistry_X;
|
||||
public Object EntityTypes_ARMOR_STAND;
|
||||
|
||||
/** PacketPlayOutEntityTeleport */
|
||||
public Class<?> PacketPlayOutEntityTeleport;
|
||||
@@ -105,7 +110,7 @@ public abstract class NMSStorage {
|
||||
/** Other entity packets */
|
||||
public Class<?> PacketPlayInUseEntity;
|
||||
public Class<?> PacketPlayInUseEntity$d;
|
||||
protected Class<?> EnumEntityUseAction;
|
||||
protected Class<Enum> EnumEntityUseAction;
|
||||
public Field PacketPlayInUseEntity_ENTITY;
|
||||
public Field PacketPlayInUseEntity_ACTION;
|
||||
|
||||
@@ -127,9 +132,9 @@ public abstract class NMSStorage {
|
||||
|
||||
/** PacketPlayOutPlayerInfo */
|
||||
public Class<?> PacketPlayOutPlayerInfo;
|
||||
protected Class<?> EnumPlayerInfoAction;
|
||||
public Class<Enum> EnumPlayerInfoAction;
|
||||
protected Class<?> PlayerInfoData;
|
||||
protected Class<?> EnumGamemode;
|
||||
public Class<Enum> EnumGamemode;
|
||||
protected Class<?> ProfilePublicKey;
|
||||
protected Class<?> ProfilePublicKey$a;
|
||||
public Constructor<?> newPacketPlayOutPlayerInfo;
|
||||
@@ -137,13 +142,25 @@ public abstract class NMSStorage {
|
||||
public Field PacketPlayOutPlayerInfo_ACTION;
|
||||
public Field PacketPlayOutPlayerInfo_PLAYERS;
|
||||
public Method PlayerInfoData_getProfile;
|
||||
public Method PlayerInfoData_isListed;
|
||||
public Method PlayerInfoData_getLatency;
|
||||
public Method PlayerInfoData_getGamemode;
|
||||
public Method PlayerInfoData_getDisplayName;
|
||||
public Method PlayerInfoData_getProfilePublicKeyRecord;
|
||||
public Method ProfilePublicKey_getRecord;
|
||||
public Enum[] EnumPlayerInfoAction_values;
|
||||
public Enum[] EnumGamemode_values;
|
||||
//1.19.3+
|
||||
public Class<?> ClientboundPlayerInfoRemovePacket;
|
||||
public Class<?> RemoteChatSession;
|
||||
public Class<?> RemoteChatSession$Data;
|
||||
public Constructor<?> newClientboundPlayerInfoRemovePacket;
|
||||
public Constructor<?> newRemoteChatSession;
|
||||
public Constructor<?> newRemoteChatSession$Data;
|
||||
public Method ClientboundPlayerInfoRemovePacket_getEntries;
|
||||
public Method RemoteChatSession_getSessionId;
|
||||
public Method RemoteChatSession_getProfilePublicKey;
|
||||
public Method RemoteChatSession$Data_getSessionId;
|
||||
public Method RemoteChatSession$Data_getProfilePublicKey;
|
||||
|
||||
|
||||
/** Scoreboard objectives */
|
||||
public Class<?> PacketPlayOutScoreboardDisplayObjective;
|
||||
@@ -153,8 +170,8 @@ public abstract class NMSStorage {
|
||||
protected Class<?> ScoreboardObjective;
|
||||
protected Class<?> ScoreboardScore;
|
||||
protected Class<?> IScoreboardCriteria;
|
||||
public Class<?> EnumScoreboardHealthDisplay;
|
||||
protected Class<?> EnumScoreboardAction;
|
||||
public Class<Enum> EnumScoreboardHealthDisplay;
|
||||
public Class<Enum> EnumScoreboardAction;
|
||||
public Constructor<?> newScoreboardObjective;
|
||||
protected Constructor<?> newScoreboard;
|
||||
public Constructor<?> newScoreboardScore;
|
||||
@@ -171,15 +188,13 @@ public abstract class NMSStorage {
|
||||
public Field PacketPlayOutScoreboardObjective_RENDERTYPE;
|
||||
public Field PacketPlayOutScoreboardObjective_DISPLAYNAME;
|
||||
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 Class<Enum> EnumNameTagVisibility;
|
||||
public Class<Enum> EnumTeamPush;
|
||||
public Class<Enum> PacketPlayOutScoreboardTeam_PlayerAction;
|
||||
public Constructor<?> newScoreboardTeam;
|
||||
public Constructor<?> newPacketPlayOutScoreboardTeam;
|
||||
public Field PacketPlayOutScoreboardTeam_NAME;
|
||||
@@ -196,9 +211,6 @@ public abstract class NMSStorage {
|
||||
public Method PacketPlayOutScoreboardTeam_of;
|
||||
public Method PacketPlayOutScoreboardTeam_ofBoolean;
|
||||
public Method PacketPlayOutScoreboardTeam_ofString;
|
||||
public Enum[] EnumNameTagVisibility_values;
|
||||
public Enum[] EnumTeamPush_values;
|
||||
public Enum[] PacketPlayOutScoreboardTeam_PlayerAction_values;
|
||||
|
||||
/** Other */
|
||||
public Object emptyScoreboard;
|
||||
@@ -226,7 +238,6 @@ public abstract class NMSStorage {
|
||||
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();
|
||||
@@ -266,9 +277,6 @@ public abstract class NMSStorage {
|
||||
* If some method, field or constructor was not found
|
||||
*/
|
||||
protected void chat() throws ReflectiveOperationException {
|
||||
if (minorVersion >= 12 && minorVersion <= 18) {
|
||||
ChatMessageType_values = getEnumValues(ChatMessageType);
|
||||
}
|
||||
if (minorVersion >= 19) {
|
||||
try {
|
||||
newPacketPlayOutChat = PacketPlayOutChat.getConstructor(IChatBaseComponent, boolean.class);
|
||||
@@ -295,20 +303,36 @@ public abstract class NMSStorage {
|
||||
*/
|
||||
protected void playerInfo() throws ReflectiveOperationException {
|
||||
if (minorVersion < 8) return;
|
||||
newPacketPlayOutPlayerInfo = PacketPlayOutPlayerInfo.getConstructor(EnumPlayerInfoAction, Array.newInstance(EntityPlayer, 0).getClass());
|
||||
if (is1_19_3Plus()) {
|
||||
newClientboundPlayerInfoRemovePacket = ClientboundPlayerInfoRemovePacket.getConstructor(List.class);
|
||||
newPacketPlayOutPlayerInfo = PacketPlayOutPlayerInfo.getConstructor(EnumPlayerInfoAction, EntityPlayer);
|
||||
ClientboundPlayerInfoRemovePacket_getEntries = getMethods(ClientboundPlayerInfoRemovePacket, List.class).get(0);
|
||||
PacketPlayOutPlayerInfo_ACTION = getFields(PacketPlayOutPlayerInfo, EnumSet.class).get(0);
|
||||
newRemoteChatSession$Data = RemoteChatSession$Data.getConstructor(UUID.class, ProfilePublicKey$a);
|
||||
RemoteChatSession$Data_getSessionId = getMethods(RemoteChatSession$Data, UUID.class).get(0);
|
||||
RemoteChatSession$Data_getProfilePublicKey = getMethods(RemoteChatSession$Data, ProfilePublicKey$a).get(0);
|
||||
PlayerInfoData_getProfilePublicKeyRecord = getMethods(PlayerInfoData, RemoteChatSession$Data).get(0);
|
||||
EntityPlayer_RemoteChatSession = getFields(EntityPlayer, RemoteChatSession).get(0);
|
||||
PlayerInfoData_isListed = getMethods(PlayerInfoData, boolean.class).get(0);
|
||||
} else {
|
||||
newPacketPlayOutPlayerInfo = PacketPlayOutPlayerInfo.getConstructor(EnumPlayerInfoAction, Array.newInstance(EntityPlayer, 0).getClass());
|
||||
PacketPlayOutPlayerInfo_ACTION = getFields(PacketPlayOutPlayerInfo, EnumPlayerInfoAction).get(0);
|
||||
if (minorVersion >= 19) {
|
||||
PlayerInfoData_getProfilePublicKeyRecord = getMethods(PlayerInfoData, ProfilePublicKey$a).get(0);
|
||||
EntityHuman_ProfilePublicKey = getFields(EntityHuman, ProfilePublicKey).get(0);
|
||||
}
|
||||
}
|
||||
newPlayerInfoData = PlayerInfoData.getConstructors()[0];
|
||||
PacketPlayOutPlayerInfo_ACTION = getFields(PacketPlayOutPlayerInfo, EnumPlayerInfoAction).get(0);
|
||||
PacketPlayOutPlayerInfo_PLAYERS = getFields(PacketPlayOutPlayerInfo, List.class).get(0);
|
||||
PlayerInfoData_getProfile = getMethods(PlayerInfoData, GameProfile.class).get(0);
|
||||
PlayerInfoData_getLatency = getMethods(PlayerInfoData, int.class).get(0);
|
||||
for (Method m: getMethods(PlayerInfoData, int.class)) {
|
||||
// do not take .hashCode(), which is final
|
||||
if (!Modifier.isFinal(m.getModifiers())) PlayerInfoData_getLatency = m;
|
||||
}
|
||||
PlayerInfoData_getGamemode = getMethods(PlayerInfoData, EnumGamemode).get(0);
|
||||
PlayerInfoData_getDisplayName = getMethods(PlayerInfoData, IChatBaseComponent).get(0);
|
||||
EnumPlayerInfoAction_values = getEnumValues(EnumPlayerInfoAction);
|
||||
EnumGamemode_values = getEnumValues(EnumGamemode);
|
||||
if (minorVersion >= 19) {
|
||||
EntityHuman_ProfilePublicKey = getFields(EntityHuman, ProfilePublicKey).get(0);
|
||||
ProfilePublicKey_getRecord = getMethods(ProfilePublicKey, ProfilePublicKey$a).get(0);
|
||||
PlayerInfoData_getProfilePublicKeyRecord = getMethods(PlayerInfoData, ProfilePublicKey$a).get(0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -320,7 +344,11 @@ public abstract class NMSStorage {
|
||||
*/
|
||||
protected void spawnEntityLiving() throws ReflectiveOperationException {
|
||||
if (minorVersion >= 17) {
|
||||
newPacketPlayOutSpawnEntityLiving = PacketPlayOutSpawnEntityLiving.getConstructor(EntityLiving);
|
||||
if (is1_19_3Plus()) {
|
||||
newPacketPlayOutSpawnEntityLiving = PacketPlayOutSpawnEntityLiving.getConstructor(Entity);
|
||||
} else {
|
||||
newPacketPlayOutSpawnEntityLiving = PacketPlayOutSpawnEntityLiving.getConstructor(EntityLiving);
|
||||
}
|
||||
} else {
|
||||
newPacketPlayOutSpawnEntityLiving = PacketPlayOutSpawnEntityLiving.getConstructor();
|
||||
}
|
||||
@@ -403,7 +431,11 @@ public abstract class NMSStorage {
|
||||
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);
|
||||
if (is1_19_3Plus()) {
|
||||
newPacketPlayOutEntityMetadata = PacketPlayOutEntityMetadata.getConstructor(int.class, List.class);
|
||||
} else {
|
||||
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) {
|
||||
@@ -427,11 +459,17 @@ public abstract class NMSStorage {
|
||||
protected void dataWatcher() throws ReflectiveOperationException {
|
||||
newDataWatcher = DataWatcher.getConstructors()[0];
|
||||
DataWatcherItem_VALUE = getFields(DataWatcherItem, Object.class).get(0);
|
||||
DataWatcher_b = getMethods(DataWatcher, List.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);
|
||||
if (is1_19_3Plus()) {
|
||||
DataWatcher$DataValue_POSITION = getFields(DataWatcher$DataValue, int.class).get(0);
|
||||
DataWatcher$DataValue_VALUE = getFields(DataWatcher$DataValue, Object.class).get(0);
|
||||
DataWatcher_markDirty = getMethods(DataWatcher, void.class, DataWatcherObject).get(0);
|
||||
}
|
||||
} else {
|
||||
DataWatcherItem_TYPE = getFields(DataWatcherItem, int.class).get(1);
|
||||
}
|
||||
@@ -456,8 +494,6 @@ public abstract class NMSStorage {
|
||||
List<Field> list = getFields(PacketPlayOutScoreboardObjective, int.class);
|
||||
PacketPlayOutScoreboardObjective_METHOD = list.get(list.size()-1);
|
||||
if (minorVersion >= 8) {
|
||||
EnumScoreboardHealthDisplay_values = getEnumValues(EnumScoreboardHealthDisplay);
|
||||
EnumScoreboardAction_values = getEnumValues(EnumScoreboardAction);
|
||||
PacketPlayOutScoreboardObjective_RENDERTYPE = getFields(PacketPlayOutScoreboardObjective, EnumScoreboardHealthDisplay).get(0);
|
||||
}
|
||||
if (minorVersion >= 13) {
|
||||
@@ -488,11 +524,7 @@ public abstract class NMSStorage {
|
||||
PacketPlayOutScoreboardTeam_ACTION = getInstanceFields(PacketPlayOutScoreboardTeam, int.class).get(0);
|
||||
PacketPlayOutScoreboardTeam_PLAYERS = getFields(PacketPlayOutScoreboardTeam, Collection.class).get(0);
|
||||
ScoreboardTeam_getPlayerNameSet = getMethods(ScoreboardTeam, Collection.class).get(0);
|
||||
if (minorVersion >= 8) {
|
||||
EnumNameTagVisibility_values = getEnumValues(EnumNameTagVisibility);
|
||||
}
|
||||
if (minorVersion >= 9) {
|
||||
EnumTeamPush_values = getEnumValues(EnumTeamPush);
|
||||
ScoreboardTeam_setCollisionRule = getMethods(ScoreboardTeam, void.class, EnumTeamPush).get(0);
|
||||
}
|
||||
if (minorVersion >= 13) {
|
||||
@@ -502,7 +534,6 @@ public abstract class NMSStorage {
|
||||
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);
|
||||
PacketPlayOutScoreboardTeam_PlayerAction_values = getEnumValues(PacketPlayOutScoreboardTeam_PlayerAction);
|
||||
} else {
|
||||
newPacketPlayOutScoreboardTeam = PacketPlayOutScoreboardTeam.getConstructor(ScoreboardTeam, int.class);
|
||||
}
|
||||
@@ -706,22 +737,6 @@ public abstract class NMSStorage {
|
||||
throw new NoSuchFieldException("No field found in class " + clazz.getName() + " with potential names " + Arrays.toString(potentialNames));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all Enum values of specified class
|
||||
*
|
||||
* @param enumClass
|
||||
* Class to get values of
|
||||
* @return Array of all values of the enum class
|
||||
*/
|
||||
protected Enum[] getEnumValues(Class<?> enumClass) {
|
||||
if (!enumClass.isEnum()) throw new IllegalArgumentException(enumClass.getName() + " is not an enum class");
|
||||
try {
|
||||
return (Enum[]) enumClass.getMethod("values").invoke(null);
|
||||
} catch (ReflectiveOperationException ignored) {
|
||||
return new Enum[0]; // this will never happen
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns server's minor version
|
||||
* @return server's minor version
|
||||
@@ -787,4 +802,13 @@ public abstract class NMSStorage {
|
||||
}
|
||||
return fields;
|
||||
}
|
||||
|
||||
public boolean is1_19_3Plus() {
|
||||
try {
|
||||
Class.forName("net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket");
|
||||
return true;
|
||||
} catch (ClassNotFoundException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -85,6 +85,7 @@ public class DataWatcher {
|
||||
position = item.getType().getPosition();
|
||||
}
|
||||
nms.DataWatcher_REGISTER.invoke(nmsWatcher, position, item.getValue());
|
||||
if (nms.is1_19_3Plus()) nms.DataWatcher_markDirty.invoke(nmsWatcher, position);
|
||||
}
|
||||
return nmsWatcher;
|
||||
}
|
||||
|
||||
+5
-2
@@ -41,12 +41,15 @@ public class DataWatcherItem {
|
||||
*/
|
||||
public static DataWatcherItem fromNMS(Object nmsItem) throws ReflectiveOperationException {
|
||||
NMSStorage nms = NMSStorage.getInstance();
|
||||
Object value = nms.DataWatcherItem_VALUE.get(nmsItem);
|
||||
DataWatcherObject object;
|
||||
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));
|
||||
object = new DataWatcherObject(nms.DataWatcherObject_SLOT.getInt(nmsObject), nms.DataWatcherObject_SERIALIZER.get(nmsObject));
|
||||
} else {
|
||||
return new DataWatcherItem(new DataWatcherObject(nms.DataWatcherItem_TYPE.getInt(nmsItem), null), nms.DataWatcherItem_VALUE.get(nmsItem));
|
||||
object = new DataWatcherObject(nms.DataWatcherItem_TYPE.getInt(nmsItem), null);
|
||||
}
|
||||
return new DataWatcherItem(object, value);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+7
-2
@@ -36,8 +36,13 @@ public class DataWatcherRegistry {
|
||||
registryFloat = fields.get("c");
|
||||
registryString = fields.get("d");
|
||||
if (nms.getMinorVersion() >= 13) {
|
||||
registryOptionalIChatBaseComponent = fields.get("f");
|
||||
registryBoolean = fields.get("i");
|
||||
if (nms.is1_19_3Plus()) {
|
||||
registryOptionalIChatBaseComponent = fields.get("g");
|
||||
registryBoolean = fields.get("j");
|
||||
} else {
|
||||
registryOptionalIChatBaseComponent = fields.get("f");
|
||||
registryBoolean = fields.get("i");
|
||||
}
|
||||
} else {
|
||||
registryBoolean = fields.get("h");
|
||||
}
|
||||
|
||||
@@ -1,232 +0,0 @@
|
||||
# https://github.com/NEZNAMY/TAB/wiki/Feature-guide:-Header-&-Footer
|
||||
header-footer:
|
||||
enabled: true
|
||||
disable-in-worlds:
|
||||
- disabledworld
|
||||
header:
|
||||
- "&3&lServer name"
|
||||
- "&7&l>> %animation:Welcome%&3 &l%player%&7&l! &7&l<<"
|
||||
- "&7Online players: &f%online%"
|
||||
- "&6Online staff: &e%staffonline%"
|
||||
- ""
|
||||
- "%animation:MyAnimation1%"
|
||||
footer:
|
||||
- "%animation:MyAnimation1%"
|
||||
- "%animation:time%"
|
||||
- "%animation:ping-tps%"
|
||||
- "&7&l Used memory: %memory-used% MB / %memory-max% MB"
|
||||
- ""
|
||||
- "&7Visit our webpage %animation:web%"
|
||||
per-world:
|
||||
world1:
|
||||
header:
|
||||
- "an example of world with custom"
|
||||
footer:
|
||||
- "header/footer and prefix/suffix"
|
||||
world2;world3:
|
||||
header:
|
||||
- "This is a shared header for"
|
||||
- "world2 and world3"
|
||||
|
||||
# https://github.com/NEZNAMY/TAB/wiki/Feature-guide:-Tablist-name-formatting
|
||||
tablist-name-formatting:
|
||||
enabled: true
|
||||
align-tabsuffix-on-the-right: false
|
||||
character-width-overrides: {}
|
||||
anti-override: true
|
||||
disable-in-worlds:
|
||||
- disabledworld
|
||||
|
||||
# https://github.com/NEZNAMY/TAB/wiki/Feature-guide:-Nametags
|
||||
scoreboard-teams:
|
||||
enabled: true
|
||||
enable-collision: true
|
||||
invisible-nametags: false
|
||||
anti-override: true
|
||||
# https://github.com/NEZNAMY/TAB/wiki/Feature-guide:-Sorting-players-in-tablist
|
||||
sorting-types:
|
||||
- "GROUPS:owner,admin,mod,helper,builder,vip,default"
|
||||
- "PLACEHOLDER_A_TO_Z:%player%"
|
||||
case-sensitive-sorting: true
|
||||
can-see-friendly-invisibles: false
|
||||
disable-in-worlds:
|
||||
- disabledworld
|
||||
# https://github.com/NEZNAMY/TAB/wiki/Feature-guide:-Unlimited-nametag-mode
|
||||
unlimited-nametag-mode:
|
||||
enabled: false
|
||||
use-marker-tag-for-1-8-x-clients: false
|
||||
disable-on-boats: true
|
||||
disable-in-worlds:
|
||||
- disabledworld
|
||||
dynamic-lines:
|
||||
- abovename
|
||||
- nametag #the original one, combination of tagprefix + customtagname + tagsuffix
|
||||
- belowname
|
||||
- another
|
||||
static-lines:
|
||||
myCustomLine: 0.66
|
||||
|
||||
# https://github.com/NEZNAMY/TAB/wiki/Feature-guide:-Yellow-number
|
||||
yellow-number-in-tablist:
|
||||
enabled: true
|
||||
value: "%ping%"
|
||||
disable-in-worlds:
|
||||
- disabledworld
|
||||
|
||||
# https://github.com/NEZNAMY/TAB/wiki/Feature-guide:-Belowname
|
||||
belowname-objective:
|
||||
enabled: false
|
||||
number: "%health%"
|
||||
text: "&cHealth"
|
||||
disable-in-worlds:
|
||||
- disabledworld
|
||||
|
||||
# https://github.com/NEZNAMY/TAB/wiki/Feature-guide:-Spectator-fix
|
||||
prevent-spectator-effect:
|
||||
enabled: false
|
||||
|
||||
# https://github.com/NEZNAMY/TAB/wiki/Feature-guide:-Bossbar
|
||||
bossbar:
|
||||
enabled: false
|
||||
toggle-command: /bossbar
|
||||
remember-toggle-choice: false
|
||||
hidden-by-default: false
|
||||
disable-in-worlds:
|
||||
- disabledworld
|
||||
bars:
|
||||
ServerInfo:
|
||||
style: "PROGRESS" # for 1.9+: PROGRESS, NOTCHED_6, NOTCHED_10, NOTCHED_12, NOTCHED_20
|
||||
color: "%animation:barcolors%" # for 1.9+: BLUE, GREEN, PINK, PURPLE, RED, WHITE, YELLOW
|
||||
progress: "100" # in %
|
||||
text: "&fWebsite: &bwww.domain.com"
|
||||
|
||||
# https://github.com/NEZNAMY/TAB/wiki/Feature-guide:-Per-world-playerlist
|
||||
per-world-playerlist:
|
||||
enabled: false
|
||||
# players with tab.staff will always see all players
|
||||
allow-bypass-permission: false
|
||||
# players in these worlds will always see all players
|
||||
ignore-effect-in-worlds:
|
||||
- ignoredworld
|
||||
- build
|
||||
shared-playerlist-world-groups:
|
||||
lobby:
|
||||
- lobby1
|
||||
- lobby2
|
||||
minigames:
|
||||
- paintball
|
||||
- bedwars
|
||||
|
||||
# https://github.com/NEZNAMY/TAB/wiki/Feature-guide:-Scoreboard
|
||||
scoreboard:
|
||||
enabled: false
|
||||
toggle-command: /sb
|
||||
remember-toggle-choice: false
|
||||
hidden-by-default: false
|
||||
use-numbers: false
|
||||
static-number: 0
|
||||
delay-on-join-milliseconds: 0
|
||||
respect-other-plugins: true
|
||||
disable-in-worlds:
|
||||
- disabledworld
|
||||
scoreboards:
|
||||
admin:
|
||||
# Only players with tab.scoreboard.admin can see this scoreboard, others will see scoreboard1
|
||||
display-condition: "permission:tab.scoreboard.admin"
|
||||
title: "Admin scoreboard"
|
||||
lines:
|
||||
- "%animation:MyAnimation1%"
|
||||
- "&6Online:"
|
||||
- "* &eOnline&7: &f%online%"
|
||||
- "* &eCurrent World&7: &f%worldonline%"
|
||||
- "* &eStaff&7: &f%staffonline%"
|
||||
- " "
|
||||
- "&6Server Info:"
|
||||
- "* &bTPS&7: %tps%"
|
||||
- "* &bUptime&7: &f%server_uptime%"
|
||||
- "* &bMemory&7: &f%memory-used%&7/&4%memory-max%"
|
||||
- "%animation:MyAnimation1%"
|
||||
scoreboard1:
|
||||
title: "Default"
|
||||
lines:
|
||||
- "%animation:MyAnimation1%"
|
||||
- "&6My Stats:"
|
||||
- "* &eKills&7: &f%statistic_player_kills%"
|
||||
- "* &eDeaths&7: &f%statistic_deaths%"
|
||||
- "* &eHealth&7: &f%health%"
|
||||
- " "
|
||||
- "&6Personal Info:"
|
||||
- "* &bRank&7: &f%group%"
|
||||
- "* &bPing&7: &f%ping%&7ms"
|
||||
- "* &bWorld&7: &f%world%"
|
||||
- "%animation:MyAnimation1%"
|
||||
|
||||
# https://github.com/NEZNAMY/TAB/wiki/Feature-guide:-Ping-Spoof
|
||||
ping-spoof:
|
||||
enabled: false
|
||||
value: 0
|
||||
|
||||
# https://github.com/NEZNAMY/TAB/wiki/Feature-guide:-Pet-name-fix
|
||||
fix-pet-names:
|
||||
enabled: false
|
||||
|
||||
placeholders:
|
||||
date-format: "dd.MM.yyyy"
|
||||
time-format: "[HH:mm:ss / h:mm a]"
|
||||
time-offset: 0
|
||||
register-tab-expansion: false
|
||||
|
||||
# https://github.com/NEZNAMY/TAB/wiki/Feature-guide:-Placeholder-output-replacements
|
||||
placeholder-output-replacements:
|
||||
"%essentials_vanished%":
|
||||
"yes": "&7| Vanished"
|
||||
"no": ""
|
||||
"%afk%":
|
||||
true: " &o[AFK]&r"
|
||||
false: ""
|
||||
"%essentials_nickname%":
|
||||
"%essentials_nickname%": "%player%" #placeholder did not parse correctly, show real name instead
|
||||
|
||||
# https://github.com/NEZNAMY/TAB/wiki/Feature-guide:-Conditional-placeholders
|
||||
conditions:
|
||||
nick: # use it with %condition:nick%
|
||||
conditions:
|
||||
- "%player%=%essentials_nickname%"
|
||||
yes: "%player%"
|
||||
no: "~%essentials_nickname%"
|
||||
|
||||
placeholderapi-refresh-intervals:
|
||||
default-refresh-interval: 500
|
||||
server:
|
||||
"%server_uptime%": 1000
|
||||
"%server_tps_1_colored%": 1000
|
||||
"%server_unique_joins%": 5000
|
||||
player:
|
||||
"%player_health%": 200
|
||||
"%player_ping%": 1000
|
||||
"%vault_prefix%": 1000
|
||||
relational:
|
||||
"%rel_factionsuuid_relation_color%": 1000
|
||||
|
||||
# assigning groups by permission nodes instead of taking them from permission plugin
|
||||
assign-groups-by-permissions: false
|
||||
|
||||
# if the option above is true, all groups are taken based on permissions and the one higher in this list is used as primary
|
||||
# Warning! This is not sorting list and has nothing to do with sorting players in tablist!
|
||||
primary-group-finding-list:
|
||||
- Owner
|
||||
- Admin
|
||||
- Mod
|
||||
- Helper
|
||||
- default
|
||||
|
||||
debug: false
|
||||
|
||||
# https://github.com/NEZNAMY/TAB/wiki/MySQL
|
||||
mysql:
|
||||
enabled: false
|
||||
host: 127.0.0.1
|
||||
port: 3306
|
||||
database: tab
|
||||
username: user
|
||||
password: password
|
||||
+79
-9
@@ -1,7 +1,7 @@
|
||||
package me.neznamy.tab.platforms.bungeecord;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import me.neznamy.tab.api.ProtocolVersion;
|
||||
import me.neznamy.tab.api.chat.EnumChatFormat;
|
||||
@@ -44,6 +44,37 @@ public class BungeePacketBuilder extends PacketBuilder {
|
||||
|
||||
@Override
|
||||
public Object build(PacketPlayOutPlayerInfo packet, ProtocolVersion clientVersion) {
|
||||
if (clientVersion.getNetworkId() >= ProtocolVersion.V1_19_3.getNetworkId()) {
|
||||
if (packet.getActions().contains(EnumPlayerInfoAction.REMOVE_PLAYER)) {
|
||||
PlayerListItemRemove remove = new PlayerListItemRemove();
|
||||
remove.setUuids(packet.getEntries().stream().map(PlayerInfoData::getUniqueId).toArray(UUID[]::new));
|
||||
return remove;
|
||||
}
|
||||
List<Item> items = new ArrayList<>();
|
||||
for (PlayerInfoData data : packet.getEntries()) {
|
||||
Item item = new Item();
|
||||
if (data.getDisplayName() != null) item.setDisplayName(data.getDisplayName().toString(clientVersion));
|
||||
if (data.getGameMode() != null) item.setGamemode(data.getGameMode().ordinal()-1);
|
||||
item.setListed(data.isListed());
|
||||
item.setPing(data.getLatency());
|
||||
if (data.getSkin() != null) {
|
||||
item.setProperties(new Property[]{new Property("textures", data.getSkin().getValue(), data.getSkin().getSignature())});
|
||||
} else {
|
||||
item.setProperties(new Property[0]);
|
||||
}
|
||||
item.setUsername(data.getName());
|
||||
item.setUuid(data.getUniqueId());
|
||||
item.setChatSessionId(data.getChatSessionId());
|
||||
item.setPublicKey((PlayerPublicKey) data.getProfilePublicKey());
|
||||
items.add(item);
|
||||
}
|
||||
PlayerListItemUpdate bungeePacket = new PlayerListItemUpdate();
|
||||
PlayerListItemUpdate.Action[] array = packet.getActions().stream().map(action -> PlayerListItemUpdate.Action.valueOf(
|
||||
action.toString().replace("GAME_MODE", "GAMEMODE"))).toArray(PlayerListItemUpdate.Action[]::new);
|
||||
bungeePacket.setActions(EnumSet.of(array[0], array));
|
||||
bungeePacket.setItems(items.toArray(new Item[0]));
|
||||
return bungeePacket;
|
||||
}
|
||||
List<Item> items = new ArrayList<>();
|
||||
for (PlayerInfoData data : packet.getEntries()) {
|
||||
Item item = new Item();
|
||||
@@ -69,7 +100,9 @@ public class BungeePacketBuilder extends PacketBuilder {
|
||||
items.add(item);
|
||||
}
|
||||
PlayerListItem bungeePacket = new PlayerListItem();
|
||||
bungeePacket.setAction(PlayerListItem.Action.valueOf(packet.getAction().toString().replace("GAME_MODE", "GAMEMODE")));
|
||||
EnumPlayerInfoAction action = packet.getActions().contains(EnumPlayerInfoAction.ADD_PLAYER) ?
|
||||
EnumPlayerInfoAction.ADD_PLAYER : packet.getActions().iterator().next();
|
||||
bungeePacket.setAction(PlayerListItem.Action.valueOf(action.toString().replace("GAME_MODE", "GAMEMODE")));
|
||||
bungeePacket.setItems(items.toArray(new Item[0]));
|
||||
return bungeePacket;
|
||||
}
|
||||
@@ -106,13 +139,50 @@ public class BungeePacketBuilder extends PacketBuilder {
|
||||
|
||||
@Override
|
||||
public PacketPlayOutPlayerInfo readPlayerInfo(Object bungeePacket, ProtocolVersion clientVersion) {
|
||||
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].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()), i.getPublicKey()));
|
||||
if (clientVersion.getNetworkId() >= ProtocolVersion.V1_19_3.getNetworkId()) {
|
||||
if (bungeePacket instanceof PlayerListItemRemove) {
|
||||
return new PacketPlayOutPlayerInfo(
|
||||
EnumPlayerInfoAction.REMOVE_PLAYER,
|
||||
Arrays.stream(((PlayerListItemRemove) bungeePacket).getUuids()).map(PlayerInfoData::new).collect(Collectors.toList())
|
||||
);
|
||||
}
|
||||
PlayerListItemUpdate item = (PlayerListItemUpdate) 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].getValue(), i.getProperties()[0].getSignature());
|
||||
listData.add(new PlayerInfoData(
|
||||
i.getUsername(),
|
||||
i.getUuid(),
|
||||
skin,
|
||||
Boolean.TRUE.equals(i.getListed()),
|
||||
i.getPing() == null ? 0 : i.getPing(),
|
||||
i.getGamemode() == null ? null : EnumGamemode.VALUES[i.getGamemode()+1],
|
||||
IChatBaseComponent.deserialize(i.getDisplayName()),
|
||||
i.getChatSessionId(),
|
||||
i.getPublicKey()));
|
||||
}
|
||||
EnumPlayerInfoAction[] array = item.getActions().stream().map(action ->
|
||||
EnumPlayerInfoAction.valueOf(action.toString().replace("GAMEMODE", "GAME_MODE"))).toArray(EnumPlayerInfoAction[]::new);
|
||||
EnumSet<EnumPlayerInfoAction> actions = EnumSet.of(array[0], array);
|
||||
return new PacketPlayOutPlayerInfo(actions, listData);
|
||||
} else {
|
||||
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].getValue(), i.getProperties()[0].getSignature());
|
||||
listData.add(new PlayerInfoData(
|
||||
i.getUsername(),
|
||||
i.getUuid(),
|
||||
skin,
|
||||
true,
|
||||
i.getPing() == null ? 0 : i.getPing(),
|
||||
i.getGamemode() == null ? null : EnumGamemode.VALUES[i.getGamemode()+1],
|
||||
IChatBaseComponent.deserialize(i.getDisplayName()),
|
||||
null,
|
||||
i.getPublicKey()));
|
||||
}
|
||||
return new PacketPlayOutPlayerInfo(EnumPlayerInfoAction.valueOf(item.getAction().toString().replace("GAMEMODE", "GAME_MODE")), listData);
|
||||
}
|
||||
return new PacketPlayOutPlayerInfo(EnumPlayerInfoAction.valueOf(item.getAction().toString().replace("GAMEMODE", "GAME_MODE")), listData);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+7
-3
@@ -11,6 +11,7 @@ import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.api.TabConstants;
|
||||
import me.neznamy.tab.shared.features.PipelineInjector;
|
||||
import me.neznamy.tab.shared.features.redis.RedisPlayer;
|
||||
import me.neznamy.tab.shared.features.sorting.Sorting;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.protocol.DefinedPacket;
|
||||
import net.md_5.bungee.protocol.packet.ScoreboardDisplay;
|
||||
@@ -68,6 +69,8 @@ public class BungeePipelineInjector extends PipelineInjector {
|
||||
try {
|
||||
switch(packet.getClass().getSimpleName()) {
|
||||
case "PlayerListItem":
|
||||
case "PlayerListItemUpdate":
|
||||
case "PlayerListItemRemove":
|
||||
super.write(context, TAB.getInstance().getFeatureManager().onPacketPlayOutPlayerInfo(player, packet), channelPromise);
|
||||
return;
|
||||
case "Team":
|
||||
@@ -91,7 +94,7 @@ public class BungeePipelineInjector extends PipelineInjector {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} catch (Exception e){
|
||||
} catch (Exception | NoSuchMethodError e){
|
||||
TAB.getInstance().getErrorManager().printError("An error occurred when analyzing packets for player " + player.getName() + " with client version " + player.getVersion().getFriendlyName(), e);
|
||||
}
|
||||
try {
|
||||
@@ -111,9 +114,10 @@ public class BungeePipelineInjector extends PipelineInjector {
|
||||
if (packet.getMode() == 1 || packet.getMode() == 2 || packet.getMode() == 4) return;
|
||||
Collection<String> col = Lists.newArrayList(packet.getPlayers());
|
||||
for (TabPlayer p : TAB.getInstance().getOnlinePlayers()) {
|
||||
Sorting sorting = (Sorting) TAB.getInstance().getFeatureManager().getFeature(TabConstants.Feature.SORTING);
|
||||
if (col.contains(p.getNickname()) && !((TabFeature)TAB.getInstance().getTeamManager()).isDisabledPlayer(p) &&
|
||||
!TAB.getInstance().getTeamManager().hasTeamHandlingPaused(p) && !packet.getName().equals(p.getTeamName())) {
|
||||
logTeamOverride(packet.getName(), p.getName(), p.getTeamName());
|
||||
!TAB.getInstance().getTeamManager().hasTeamHandlingPaused(p) && !packet.getName().equals(sorting.getShortTeamName(p))) {
|
||||
logTeamOverride(packet.getName(), p.getName(), sorting.getShortTeamName(p));
|
||||
col.remove(p.getNickname());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import net.md_5.bungee.protocol.Protocol;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* TabPlayer implementation for BungeeCord
|
||||
@@ -142,6 +143,11 @@ public class BungeeTabPlayer extends ProxyTabPlayer {
|
||||
return ((InitialHandler)getPlayer().getPendingConnection()).getLoginRequest().getPublicKey();
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID getChatSessionId() {
|
||||
throw new UnsupportedOperationException("Not implemented yet");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendPluginMessage(byte[] message) {
|
||||
Preconditions.checkNotNull(message, "message");
|
||||
|
||||
@@ -26,7 +26,7 @@ public class Main extends Plugin {
|
||||
@Override
|
||||
public void onEnable(){
|
||||
if (!isVersionSupported()) {
|
||||
getLogger().info(EnumChatFormat.color("&cThe plugin requires BungeeCord build #1637 and up to work. Get it at https://ci.md-5.net/job/BungeeCord/"));
|
||||
getLogger().info(EnumChatFormat.color("&cThe plugin requires BungeeCord build #1671 and up (or an equivalent fork) to work."));
|
||||
return;
|
||||
}
|
||||
BungeePlatform platform = new BungeePlatform();
|
||||
@@ -47,7 +47,7 @@ public class Main extends Plugin {
|
||||
*/
|
||||
private boolean isVersionSupported() {
|
||||
try {
|
||||
Class.forName("net.md_5.bungee.protocol.Property");
|
||||
Class.forName("net.md_5.bungee.protocol.packet.PlayerListItemUpdate");
|
||||
return true;
|
||||
} catch (ClassNotFoundException e) {
|
||||
return false;
|
||||
|
||||
+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.5
|
||||
projectVersion=3.2.0
|
||||
|
||||
# Gradle properties
|
||||
org.gradle.daemon=true
|
||||
|
||||
@@ -5,7 +5,7 @@ metadata.format.version = "1.1"
|
||||
# API
|
||||
netty = "4.1.80.Final"
|
||||
jsonSimple = "1.1.1"
|
||||
snakeyaml = "1.30"
|
||||
snakeyaml = "1.33"
|
||||
yamlAssist = "1.0.5"
|
||||
gson = "2.9.1"
|
||||
slf4j = "1.7.36"
|
||||
|
||||
@@ -95,8 +95,6 @@ class KryptonPlatform(
|
||||
|
||||
override fun isPluginEnabled(plugin: String): Boolean = server.pluginManager.isLoaded(plugin)
|
||||
|
||||
override fun getConfigName(): String = "kryptonconfig.yml"
|
||||
|
||||
private fun loadNametagFeature() {
|
||||
if (!TAB.getInstance().config.getBoolean("scoreboard-teams.enabled", true)) return
|
||||
if (TAB.getInstance().config.getBoolean("scoreboard-teams.unlimited-nametag-mode.enabled", false)) {
|
||||
|
||||
@@ -1,214 +0,0 @@
|
||||
# Detailed explanation of all options available at https://github.com/NEZNAMY/TAB/wiki/config.yml
|
||||
|
||||
scoreboard-teams:
|
||||
enabled: true
|
||||
enable-collision: true
|
||||
invisible-nametags: false
|
||||
anti-override: true
|
||||
|
||||
# types: GROUPS:<group1>,<group2>... , PERMISSIONS:<permission1>,<perm2>... , PLACEHOLDER:<output1>,<output2>... , PLACEHOLDER_A_TO_Z, PLACEHOLDER_Z_TO_A, PLACEHOLDER_HIGH_TO_LOW, PLACEHOLDER_LOW_TO_HIGH
|
||||
sorting-types:
|
||||
- "GROUPS:owner,admin,mod,helper,builder,vip,default"
|
||||
- "PLACEHOLDER_A_TO_Z:%player%"
|
||||
case-sensitive-sorting: true
|
||||
disable-in-worlds:
|
||||
- disabledworld
|
||||
unlimited-nametag-mode:
|
||||
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:
|
||||
- abovename
|
||||
- nametag #the original one, combination of tagprefix + customtagname + tagsuffix
|
||||
- belowname
|
||||
- another
|
||||
static-lines:
|
||||
myCustomLine: 0.66
|
||||
|
||||
tablist-name-formatting:
|
||||
enabled: true
|
||||
align-tabsuffix-on-the-right: false
|
||||
character-width-overrides: {}
|
||||
anti-override: true
|
||||
disable-in-worlds:
|
||||
- disabledworld
|
||||
|
||||
header-footer:
|
||||
enabled: true
|
||||
disable-in-worlds:
|
||||
- disabledworld
|
||||
header:
|
||||
- "%animation:ServerName%"
|
||||
- "&7&l>> %animation:Welcome%&3 &l%player%&7&l! &7&l<<"
|
||||
- "&7Online players: &f%online%"
|
||||
- "&6Online staff: &e%staffonline%"
|
||||
- ""
|
||||
- "%animation:MyAnimation1%"
|
||||
footer:
|
||||
- "%animation:MyAnimation1%"
|
||||
- "%animation:time%"
|
||||
- "%animation:ping-tps%"
|
||||
- "&7&l Used memory: %memory-used% MB / %memory-max% MB"
|
||||
- ""
|
||||
- "&7Visit our webpage %animation:web%"
|
||||
per-world:
|
||||
world1:
|
||||
header:
|
||||
- "an example of world with custom"
|
||||
footer:
|
||||
- "header/footer and prefix/suffix"
|
||||
world2-world3:
|
||||
header:
|
||||
- "This is a shared header for"
|
||||
- "world2 and world3"
|
||||
|
||||
|
||||
yellow-number-in-tablist:
|
||||
enabled: true
|
||||
value: "%ping%"
|
||||
disable-in-worlds:
|
||||
- disabledworld
|
||||
|
||||
belowname-objective:
|
||||
enabled: false
|
||||
number: "%health%"
|
||||
text: "&c❤"
|
||||
disable-in-worlds:
|
||||
- disabledworld
|
||||
|
||||
# https://github.com/NEZNAMY/TAB/wiki/Feature-guide:-Spectator-fix
|
||||
prevent-spectator-effect:
|
||||
enabled: false
|
||||
|
||||
# https://github.com/NEZNAMY/TAB/wiki/Feature-guide:-Bossbar
|
||||
bossbar:
|
||||
enabled: false
|
||||
toggle-command: /bossbar
|
||||
remember-toggle-choice: false
|
||||
hidden-by-default: false
|
||||
disable-in-worlds:
|
||||
- disabledworld
|
||||
bars:
|
||||
ServerInfo:
|
||||
style: "PROGRESS" # can be one of: PROGRESS, NOTCHED_6, NOTCHED_10, NOTCHED_12, NOTCHED_20
|
||||
color: "%animation:barcolors%" # can be one of: BLUE, GREEN, PINK, PURPLE, RED, WHITE, YELLOW
|
||||
progress: "100" # in %
|
||||
text: "&fWebsite: &bwww.domain.com"
|
||||
tpsbar:
|
||||
announcement-bar: true #marks this bossbar as announcement one and doesn't send it always
|
||||
style: NOTCHED_20
|
||||
color: GREEN
|
||||
progress: "%mspt_mean_10s%"
|
||||
text: "&7TPS&e: %condition:tps_5s% &7MSPT&e: %condition:mspt_mean_10s% &7Ping&e: %condition:ping%&7ms"
|
||||
|
||||
# https://github.com/NEZNAMY/TAB/wiki/Feature-guide:-Per-world-playerlist
|
||||
per-world-playerlist:
|
||||
enabled: false
|
||||
# players with tab.staff will always see all players
|
||||
allow-bypass-permission: false
|
||||
# players in those worlds will always see all players
|
||||
ignore-effect-in-worlds:
|
||||
- ignoredworld
|
||||
- build
|
||||
shared-playerlist-world-groups:
|
||||
lobby:
|
||||
- lobby1
|
||||
- lobby2
|
||||
minigames:
|
||||
- paintball
|
||||
- bedwars
|
||||
|
||||
# https://github.com/NEZNAMY/TAB/wiki/Feature-guide:-Scoreboard-(premium-only)
|
||||
scoreboard:
|
||||
enabled: false
|
||||
# show/hide the scoreboard
|
||||
toggle-command: /sb
|
||||
remember-toggle-choice: false
|
||||
hidden-by-default: false
|
||||
# when enabled, will show 0-14 in red next to lines
|
||||
use-numbers: false
|
||||
# if use-numbers is disabled, this number will show in red next to all lines
|
||||
static-number: 0
|
||||
delay-on-join-milliseconds: 0
|
||||
respect-other-plugins: true
|
||||
disable-in-worlds:
|
||||
- disabledworld
|
||||
scoreboards:
|
||||
admin:
|
||||
# Only players with tab.scoreboard.admin can see this scoreboard, others will see scoreboard1
|
||||
display-condition: "permission:tab.scoreboard.admin"
|
||||
title: "Admin scoreboard"
|
||||
lines:
|
||||
- "%animation:MyAnimation1%"
|
||||
- "&6Online:"
|
||||
- "* &eOnline&7: &f%online%&7/&4%maxplayers%"
|
||||
- "* &eCurrent World&7: &f%worldonline%"
|
||||
- "* &eStaff&7: &f%staffonline%"
|
||||
- ""
|
||||
- "&6Server Info:"
|
||||
- "* &bTPS&7: %tps_5s%"
|
||||
- "* &bUptime&7: &f%server_uptime%"
|
||||
- "* &bMemory&7: &f%memory-used%&7/&4%memory-max%"
|
||||
- "%animation:MyAnimation1%"
|
||||
scoreboard1:
|
||||
title: "Default"
|
||||
lines:
|
||||
- "%animation:MyAnimation1%"
|
||||
- "&6My Stats:"
|
||||
- "* &eKills&7: &f%statistic_player_kills%"
|
||||
- "* &eDeaths&7: &f%statistic_deaths%"
|
||||
- "* &eHealth&7: &f%health%"
|
||||
- ""
|
||||
- "&6Personal Info:"
|
||||
- "* &bRank&7: &f%rank%"
|
||||
- "* &bPing&7: &f%ping%&7ms"
|
||||
- "* &bWorld&7: &f%world%"
|
||||
- "%animation:MyAnimation1%"
|
||||
|
||||
ping-spoof:
|
||||
enabled: false
|
||||
# when enabled, all players will have this value as their ping
|
||||
value: 0
|
||||
|
||||
# https://github.com/NEZNAMY/TAB/wiki/Feature-guide:-Pet-name-fix
|
||||
fix-pet-names:
|
||||
enabled: false
|
||||
|
||||
# https://github.com/NEZNAMY/TAB/wiki/config.yml#placeholders
|
||||
placeholders:
|
||||
date-format: "dd.MM.yyyy"
|
||||
time-format: "[HH:mm:ss / h:mm a]"
|
||||
time-offset: 0
|
||||
|
||||
# https://github.com/NEZNAMY/TAB/wiki/Feature-guide:-Placeholder-output-replacements-(premium-only)
|
||||
placeholder-output-replacements:
|
||||
"%essentials_vanished%":
|
||||
"yes": "&7| Vanished"
|
||||
"no": ""
|
||||
"%afk%":
|
||||
true: " &o[AFK]&r"
|
||||
false: ""
|
||||
|
||||
#if none of the above fits your needs, you can enable this to give groups using tab.group.<group name from the list below> permission
|
||||
assign-groups-by-permissions: false
|
||||
|
||||
#if the option above is true, all groups are taken based on permissions and the one higher in this list is used as primary
|
||||
primary-group-finding-list:
|
||||
- Owner
|
||||
- Admin
|
||||
- Mod
|
||||
- Helper
|
||||
- default
|
||||
|
||||
debug: false
|
||||
|
||||
mysql:
|
||||
enabled: false
|
||||
host: 127.0.0.1
|
||||
port: 3306
|
||||
database: tab
|
||||
username: user
|
||||
password: password
|
||||
@@ -89,7 +89,7 @@ public class CpuManager implements ThreadManager {
|
||||
*/
|
||||
public void enable() {
|
||||
enabled = true;
|
||||
taskQueue.forEach(this::submit);
|
||||
new ArrayList<>(taskQueue).forEach(this::submit);
|
||||
taskQueue.clear();
|
||||
}
|
||||
|
||||
|
||||
@@ -227,7 +227,8 @@ public class ErrorManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes interval divisible by 50 and sends error message if it was not already or was 0 or less
|
||||
* Makes interval divisible by {@link me.neznamy.tab.api.TabConstants.Placeholder#MINIMUM_REFRESH_INTERVAL}
|
||||
* and sends error message if it was not already or was 0 or less
|
||||
*
|
||||
* @param name
|
||||
* name of animation used in error message
|
||||
@@ -244,10 +245,10 @@ public class ErrorManager {
|
||||
startupWarn(String.format("Animation \"&e%s&c\" has refresh interval of %s. Refresh cannot be negative! &bUsing 1000.", name, interval));
|
||||
return 1000;
|
||||
}
|
||||
if (interval % 50 != 0) {
|
||||
int newInterval = interval - interval%50;
|
||||
if (newInterval == 0) newInterval = 50;
|
||||
startupWarn(String.format("Animation \"&e%s&c\" has refresh interval of %s which is not divisible by 50! &bUsing %s.", name, interval, newInterval));
|
||||
if (interval % TabConstants.Placeholder.MINIMUM_REFRESH_INTERVAL != 0) {
|
||||
int newInterval = interval - interval % TabConstants.Placeholder.MINIMUM_REFRESH_INTERVAL;
|
||||
if (newInterval == 0) newInterval = TabConstants.Placeholder.MINIMUM_REFRESH_INTERVAL;
|
||||
startupWarn(String.format("Animation \"&e%s&c\" has refresh interval of %s which is not divisible by " + TabConstants.Placeholder.MINIMUM_REFRESH_INTERVAL + "! &bUsing %s.", name, interval, newInterval));
|
||||
return newInterval;
|
||||
}
|
||||
return interval;
|
||||
|
||||
@@ -9,9 +9,9 @@ import me.neznamy.tab.api.chat.IChatBaseComponent;
|
||||
import me.neznamy.tab.api.placeholder.PlayerPlaceholder;
|
||||
import me.neznamy.tab.api.protocol.*;
|
||||
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.sorting.Sorting;
|
||||
import org.geysermc.floodgate.api.FloodgateApi;
|
||||
|
||||
/**
|
||||
@@ -47,12 +47,6 @@ public abstract class ITabPlayer implements TabPlayer {
|
||||
/** Player's permission group override using API */
|
||||
private String temporaryGroup;
|
||||
|
||||
/** Player's personal scoreboard team name */
|
||||
private String teamName;
|
||||
|
||||
/** Note explaining the team name, used in debug command */
|
||||
private String teamNameNote;
|
||||
|
||||
/** Player's game type, {@code true} for Bedrock, {@code false} for Java */
|
||||
private final boolean bedrockPlayer;
|
||||
|
||||
@@ -72,10 +66,10 @@ public abstract class ITabPlayer implements TabPlayer {
|
||||
private boolean onJoinFinished;
|
||||
|
||||
/** Scoreboard teams player has registered */
|
||||
private final List<String> registeredTeams = new ArrayList<>();
|
||||
private final Set<String> registeredTeams = new HashSet<>();
|
||||
|
||||
/** Scoreboard objectives player has registered */
|
||||
private final List<String> registeredObjectives = new ArrayList<>();
|
||||
private final Set<String> registeredObjectives = new HashSet<>();
|
||||
|
||||
/** Player's name as seen in GameProfile, can be altered by nick plugins */
|
||||
private String nickname;
|
||||
@@ -146,26 +140,6 @@ public abstract class ITabPlayer implements TabPlayer {
|
||||
return setProperty(feature, identifier, rawValue, null, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets team name to given value
|
||||
*
|
||||
* @param name
|
||||
* Team name to use
|
||||
*/
|
||||
public void setTeamName(String name) {
|
||||
teamName = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets team name note to given value
|
||||
*
|
||||
* @param note
|
||||
* New team name note
|
||||
*/
|
||||
public void setTeamNameNote(String note) {
|
||||
teamNameNote = note;
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the player as loaded and calls PlayerLoadEvent
|
||||
*
|
||||
@@ -175,7 +149,6 @@ public abstract class ITabPlayer implements TabPlayer {
|
||||
public void markAsLoaded(boolean join) {
|
||||
onJoinFinished = true;
|
||||
if (TAB.getInstance().getEventBus() != null) TAB.getInstance().getEventBus().fire(new PlayerLoadEventImpl(this, join));
|
||||
TAB.getInstance().getPlatform().callLoadEvent(this);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -298,13 +271,20 @@ public abstract class ITabPlayer implements TabPlayer {
|
||||
String team = ((PacketPlayOutScoreboardTeam) packet).getName();
|
||||
int method = ((PacketPlayOutScoreboardTeam) packet).getAction();
|
||||
if (method == 0) {
|
||||
if (registeredTeams.contains(team)) {
|
||||
if (!registeredTeams.add(team)) {
|
||||
TAB.getInstance().getErrorManager().printError("Tried to register duplicated team " + team + " to player " + getName());
|
||||
return;
|
||||
}
|
||||
registeredTeams.add(team);
|
||||
} else if (method == 1) {
|
||||
registeredTeams.remove(team);
|
||||
if (!registeredTeams.remove(team)) {
|
||||
TAB.getInstance().getErrorManager().printError("Tried to unregister non-existing team " + team + " for player " + getName());
|
||||
return;
|
||||
}
|
||||
} else if (method == 2) {
|
||||
if (!registeredTeams.contains(team)) {
|
||||
TAB.getInstance().getErrorManager().printError("Tried to modify non-existing team " + team + " for player " + getName());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
//avoiding BungeeCord bug kicking all players
|
||||
@@ -312,13 +292,20 @@ public abstract class ITabPlayer implements TabPlayer {
|
||||
String objective = ((PacketPlayOutScoreboardObjective) packet).getObjectiveName();
|
||||
int method = ((PacketPlayOutScoreboardObjective) packet).getAction();
|
||||
if (method == 0) {
|
||||
if (registeredObjectives.contains(objective)) {
|
||||
if (!registeredObjectives.add(objective)) {
|
||||
TAB.getInstance().getErrorManager().printError("Tried to register duplicated objective " + objective + " to player " + getName());
|
||||
return;
|
||||
}
|
||||
registeredObjectives.add(objective);
|
||||
} else if (method == 1) {
|
||||
registeredObjectives.remove(objective);
|
||||
if (!registeredObjectives.remove(objective)) {
|
||||
TAB.getInstance().getErrorManager().printError("Tried to unregister non-existing objective " + objective + " for player " + getName());
|
||||
return;
|
||||
}
|
||||
} else if (method == 2) {
|
||||
if (!registeredObjectives.contains(objective)) {
|
||||
TAB.getInstance().getErrorManager().printError("Tried to modify non-existing objective " + objective + " for player " + getName());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
//avoiding console spam from geyser
|
||||
@@ -391,20 +378,15 @@ public abstract class ITabPlayer implements TabPlayer {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTeamName() {
|
||||
TeamManager teams = TAB.getInstance().getTeamManager();
|
||||
if (teams != null && teams.getForcedTeamName(this) != null) return teams.getForcedTeamName(this);
|
||||
return teamName;
|
||||
public boolean isBedrockPlayer() {
|
||||
return bedrockPlayer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTeamNameNote() {
|
||||
return teamNameNote;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBedrockPlayer() {
|
||||
return bedrockPlayer;
|
||||
public String getTeamName() {
|
||||
Sorting sorting = (Sorting) TAB.getInstance().getFeatureManager().getFeature(TabConstants.Feature.SORTING);
|
||||
if (sorting == null) return null;
|
||||
return sorting.getShortTeamName(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
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;
|
||||
@@ -25,22 +24,6 @@ public abstract class Platform {
|
||||
this.packetBuilder = packetBuilder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls platform-specific load event.
|
||||
* This method is called when plugin is fully enabled.
|
||||
*/
|
||||
public void callLoadEvent(){
|
||||
//do nothing by default, old event system will be removed
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls platform-specific player load event.
|
||||
* This method is called when player is fully loaded.
|
||||
*/
|
||||
public void callLoadEvent(TabPlayer player){
|
||||
//do nothing by default, old event system will be removed
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns platform-specific packet builder implementation
|
||||
*
|
||||
@@ -89,12 +72,4 @@ public abstract class Platform {
|
||||
* @return Version string if plugin is installed, {@code null} if not
|
||||
*/
|
||||
public abstract String getPluginVersion(String plugin);
|
||||
|
||||
/**
|
||||
* Returns name of default config file for this platform
|
||||
* as it appears in the final jar in root directory.
|
||||
*
|
||||
* @return name of default config file for this platform
|
||||
*/
|
||||
public abstract String getConfigName();
|
||||
}
|
||||
@@ -160,7 +160,6 @@ public class TAB extends TabAPI {
|
||||
for (TabPlayer p : players) ((ITabPlayer)p).markAsLoaded(false);
|
||||
cpu.enable();
|
||||
if (eventBus != null) eventBus.fire(TabLoadEventImpl.getInstance());
|
||||
platform.callLoadEvent();
|
||||
disabled = false;
|
||||
sendConsoleMessage("&aEnabled in " + (System.currentTimeMillis()-time) + "ms", true);
|
||||
return configuration.getMessages().getReloadSuccess();
|
||||
@@ -232,7 +231,7 @@ public class TAB extends TabAPI {
|
||||
if (serverVersion.getMinorVersion() >= 8 && configuration.getLayout().getBoolean("enabled", false)) {
|
||||
if (getTeamManager() == null) {
|
||||
//sorting is disabled, but layout needs team names
|
||||
featureManager.registerFeature(TabConstants.Feature.SORTING, new Sorting(null));
|
||||
featureManager.registerFeature(TabConstants.Feature.SORTING, new Sorting());
|
||||
}
|
||||
featureManager.registerFeature(TabConstants.Feature.LAYOUT, new LayoutManager());
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ import me.neznamy.tab.shared.DynamicText;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.api.TabConstants;
|
||||
import me.neznamy.tab.shared.features.PlayerList;
|
||||
import me.neznamy.tab.shared.features.nametags.NameTag;
|
||||
import me.neznamy.tab.shared.features.sorting.Sorting;
|
||||
|
||||
/**
|
||||
* Handler for "/tab debug" subcommand
|
||||
@@ -111,9 +111,9 @@ public class DebugCommand extends SubCommand {
|
||||
* @return sorting type
|
||||
*/
|
||||
private String getSortingType() {
|
||||
NameTag nametag = (NameTag) TAB.getInstance().getTeamManager();
|
||||
if (nametag != null) {
|
||||
return nametag.getSorting().typesToString();
|
||||
Sorting sorting = (Sorting) TAB.getInstance().getFeatureManager().getFeature(TabConstants.Feature.SORTING);
|
||||
if (sorting != null) {
|
||||
return sorting.typesToString();
|
||||
} else {
|
||||
return "&cDISABLED";
|
||||
}
|
||||
@@ -141,17 +141,16 @@ public class DebugCommand extends SubCommand {
|
||||
* @return team name of specified player
|
||||
*/
|
||||
private String getTeamName(TabPlayer analyzed) {
|
||||
if (TAB.getInstance().getTeamManager() != null) {
|
||||
if (((TabFeature) TAB.getInstance().getTeamManager()).isDisabled(analyzed.getServer(), analyzed.getWorld())) {
|
||||
return "&eTeam name: &cSorting is disabled in player's world/server";
|
||||
} else {
|
||||
return "&eTeam name: &a" + analyzed.getTeamName();
|
||||
}
|
||||
Sorting sorting = (Sorting) TAB.getInstance().getFeatureManager().getFeature(TabConstants.Feature.SORTING);
|
||||
if (sorting == null) return "";
|
||||
if (TAB.getInstance().getTeamManager() != null &&
|
||||
((TabFeature) TAB.getInstance().getTeamManager()).isDisabled(analyzed.getServer(), analyzed.getWorld())) {
|
||||
return "&eTeam name: &cSorting is disabled in player's world/server";
|
||||
}
|
||||
return "";
|
||||
return "&eTeam name: &a" + (TAB.getInstance().getFeatureManager().isFeatureEnabled(TabConstants.Feature.LAYOUT)
|
||||
? sorting.getFullTeamName(analyzed) : sorting.getShortTeamName(analyzed));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns team name note of specified player
|
||||
*
|
||||
@@ -160,11 +159,13 @@ public class DebugCommand extends SubCommand {
|
||||
* @return team name note of specified player
|
||||
*/
|
||||
private String getTeamNameNote(TabPlayer analyzed) {
|
||||
Sorting sorting = (Sorting) TAB.getInstance().getFeatureManager().getFeature(TabConstants.Feature.SORTING);
|
||||
if (sorting == null) return "";
|
||||
if (TAB.getInstance().getTeamManager() != null &&
|
||||
!((TabFeature) TAB.getInstance().getTeamManager()).isDisabled(analyzed.getServer(), analyzed.getWorld()) &&
|
||||
analyzed.getTeamNameNote() != null)
|
||||
return "&eTeam name note: &r" + analyzed.getTeamNameNote();
|
||||
return "";
|
||||
((TabFeature) TAB.getInstance().getTeamManager()).isDisabled(analyzed.getServer(), analyzed.getWorld())) {
|
||||
return "";
|
||||
}
|
||||
return "&eSorting note: &r" + sorting.getTeamNameNote(analyzed);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -21,13 +21,14 @@ import java.util.List;
|
||||
public class Configs {
|
||||
|
||||
//config.yml file
|
||||
private final ConfigurationFile config = new YamlConfigurationFile(getClass().getClassLoader().getResourceAsStream(TAB.getInstance().getPlatform().getConfigName()),
|
||||
private final ConfigurationFile config = new YamlConfigurationFile(getClass().getClassLoader().getResourceAsStream("config.yml"),
|
||||
new File(TAB.getInstance().getDataFolder(), "config.yml"));
|
||||
|
||||
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;
|
||||
private final String serverName = getSecretOption("server-name", "N/A");
|
||||
|
||||
//animations.yml file
|
||||
private final ConfigurationFile animation = new YamlConfigurationFile(getClass().getClassLoader().getResourceAsStream("animations.yml"),
|
||||
@@ -64,12 +65,18 @@ public class Configs {
|
||||
converter.convertAnimationFile(animation);
|
||||
if (config.getBoolean("mysql.enabled", false)) {
|
||||
try {
|
||||
// Initialization to try to avoid java.sql.SQLException: No suitable driver found
|
||||
try {
|
||||
Class.forName("com.mysql.cj.jdbc.Driver");
|
||||
} catch (ClassNotFoundException e) {
|
||||
Class.forName("com.mysql.jdbc.Driver");
|
||||
}
|
||||
mysql = new MySQL(config.getString("mysql.host", "127.0.0.1"), config.getInt("mysql.port", 3306),
|
||||
config.getString("mysql.database", "tab"), config.getString("mysql.username", "user"), config.getString("mysql.password", "password"));
|
||||
groupFile = new MySQLGroupConfiguration(mysql);
|
||||
userFile = new MySQLUserConfiguration(mysql);
|
||||
return;
|
||||
} catch (SQLException e) {
|
||||
} catch (SQLException | ClassNotFoundException e) {
|
||||
TAB.getInstance().getErrorManager().criticalError("Failed to connect to MySQL", e);
|
||||
}
|
||||
}
|
||||
@@ -163,4 +170,8 @@ public class Configs {
|
||||
public boolean isDebugMode() {
|
||||
return debugMode;
|
||||
}
|
||||
|
||||
public String getServerName() {
|
||||
return serverName;
|
||||
}
|
||||
}
|
||||
@@ -107,9 +107,9 @@ public class HeaderFooter extends TabFeature implements HeaderFooterManager {
|
||||
if (value.length > 0) {
|
||||
return value[0];
|
||||
}
|
||||
List<String> lines = TAB.getInstance().getConfiguration().getConfig().getStringList("header-footer.per-server." + TAB.getInstance().getConfiguration().getGroup(serverGroups, p.getServer()) + "." + property);
|
||||
List<String> lines = TAB.getInstance().getConfiguration().getConfig().getStringList("header-footer.per-world." + TAB.getInstance().getConfiguration().getGroup(worldGroups, p.getWorld()) + "." + property);
|
||||
if (lines == null) {
|
||||
lines = TAB.getInstance().getConfiguration().getConfig().getStringList("header-footer.per-world." + TAB.getInstance().getConfiguration().getGroup(worldGroups, p.getWorld()) + "." + property);
|
||||
lines = TAB.getInstance().getConfiguration().getConfig().getStringList("header-footer.per-server." + TAB.getInstance().getConfiguration().getGroup(serverGroups, p.getServer()) + "." + property);
|
||||
}
|
||||
if (lines == null) {
|
||||
lines = TAB.getInstance().getConfiguration().getConfig().getStringList("header-footer." + property);
|
||||
|
||||
@@ -38,7 +38,7 @@ public class NickCompatibility extends TabFeature {
|
||||
|
||||
@Override
|
||||
public void onPlayerInfo(TabPlayer receiver, PacketPlayOutPlayerInfo packet) {
|
||||
if (packet.getAction() != EnumPlayerInfoAction.ADD_PLAYER) return;
|
||||
if (!packet.getActions().contains(EnumPlayerInfoAction.ADD_PLAYER)) return;
|
||||
for (PlayerInfoData data : packet.getEntries()) {
|
||||
TabPlayer packetPlayer = TAB.getInstance().getPlayerByTabListUUID(data.getUniqueId());
|
||||
if (packetPlayer != null && packetPlayer != receiver && !packetPlayer.getNickname().equals(data.getName())) {
|
||||
@@ -63,10 +63,10 @@ public class NickCompatibility extends TabFeature {
|
||||
|
||||
if (nameTags != null && !nameTags.hasTeamHandlingPaused(player)) {
|
||||
for (TabPlayer viewer : TAB.getInstance().getOnlinePlayers()) {
|
||||
viewer.sendCustomPacket(new PacketPlayOutScoreboardTeam(player.getTeamName()), this);
|
||||
viewer.sendCustomPacket(new PacketPlayOutScoreboardTeam(nameTags.getSorting().getShortTeamName(player)), this);
|
||||
String replacedPrefix = player.getProperty(TabConstants.Property.TAGPREFIX).getFormat(viewer);
|
||||
String replacedSuffix = player.getProperty(TabConstants.Property.TAGSUFFIX).getFormat(viewer);
|
||||
viewer.sendCustomPacket(new PacketPlayOutScoreboardTeam(player.getTeamName(), replacedPrefix, replacedSuffix, nameTags.translate(nameTags.getTeamVisibility(player, viewer)),
|
||||
viewer.sendCustomPacket(new PacketPlayOutScoreboardTeam(nameTags.getSorting().getShortTeamName(player), replacedPrefix, replacedSuffix, nameTags.translate(nameTags.getTeamVisibility(player, viewer)),
|
||||
nameTags.translate(nameTags.getCollisionManager().getCollision(player)), Collections.singletonList(player.getNickname()), nameTags.getTeamOptions()), this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ public class PingSpoof extends TabFeature {
|
||||
|
||||
@Override
|
||||
public void onPlayerInfo(TabPlayer receiver, PacketPlayOutPlayerInfo info) {
|
||||
if (info.getAction() != EnumPlayerInfoAction.UPDATE_LATENCY && info.getAction() != EnumPlayerInfoAction.ADD_PLAYER) return;
|
||||
if (!info.getActions().contains(EnumPlayerInfoAction.UPDATE_LATENCY)) return;
|
||||
for (PlayerInfoData playerInfoData : info.getEntries()) {
|
||||
if (TAB.getInstance().getPlayerByTabListUUID(playerInfoData.getUniqueId()) != null) playerInfoData.setLatency(value);
|
||||
if (layoutManager != null) {
|
||||
|
||||
@@ -72,19 +72,7 @@ public class PlaceholderManagerImpl extends TabFeature implements PlaceholderMan
|
||||
}
|
||||
|
||||
private void refresh(Map<TabPlayer, Set<TabFeature>> forceUpdate, Map<TabPlayer, Set<TabFeature>> update) {
|
||||
for (Entry<TabPlayer, Set<TabFeature>> entry : update.entrySet()) {
|
||||
if (forceUpdate.containsKey(entry.getKey())) {
|
||||
entry.getValue().removeAll(forceUpdate.get(entry.getKey()));
|
||||
}
|
||||
}
|
||||
long startRefreshTime = System.nanoTime();
|
||||
for (Entry<TabPlayer, Set<TabFeature>> entry : forceUpdate.entrySet()) {
|
||||
for (TabFeature r : entry.getValue()) {
|
||||
long startTime = System.nanoTime();
|
||||
r.refresh(entry.getKey(), true);
|
||||
TAB.getInstance().getCPUManager().addTime(r.getFeatureName(), r.getRefreshDisplayName(), System.nanoTime() - startTime);
|
||||
}
|
||||
}
|
||||
for (Entry<TabPlayer, Set<TabFeature>> entry : update.entrySet()) {
|
||||
for (TabFeature r : entry.getValue()) {
|
||||
long startTime = System.nanoTime();
|
||||
@@ -92,6 +80,13 @@ public class PlaceholderManagerImpl extends TabFeature implements PlaceholderMan
|
||||
TAB.getInstance().getCPUManager().addTime(r.getFeatureName(), r.getRefreshDisplayName(), System.nanoTime() - startTime);
|
||||
}
|
||||
}
|
||||
for (Entry<TabPlayer, Set<TabFeature>> entry : forceUpdate.entrySet()) {
|
||||
for (TabFeature r : entry.getValue()) {
|
||||
long startTime = System.nanoTime();
|
||||
r.refresh(entry.getKey(), true);
|
||||
TAB.getInstance().getCPUManager().addTime(r.getFeatureName(), r.getRefreshDisplayName(), System.nanoTime() - startTime);
|
||||
}
|
||||
}
|
||||
//subtracting back usage by this method from placeholder refreshing usage, since it is already counted under different name in this method
|
||||
TAB.getInstance().getCPUManager().addTime(getFeatureName(), TabConstants.CpuUsageCategory.PLACEHOLDER_REFRESHING, startRefreshTime-System.nanoTime());
|
||||
}
|
||||
@@ -252,7 +247,7 @@ public class PlaceholderManagerImpl extends TabFeature implements PlaceholderMan
|
||||
tabExpansion.setPlaceholderValue(all, p.getIdentifier(), p.getLastValue(all));
|
||||
}
|
||||
}
|
||||
if (p.getRefresh() % 50 == 0 && p.getRefresh() > 0) {
|
||||
if (p.getRefresh() % TabConstants.Placeholder.MINIMUM_REFRESH_INTERVAL == 0 && p.getRefresh() > 0) {
|
||||
int refresh = gcd(p.getRefresh(), refreshInterval);
|
||||
if (refreshInterval != refresh) {
|
||||
TAB.getInstance().debug("Decreasing refresh interval of placeholder refreshing task to " + refresh + "ms due to placeholder " + identifier);
|
||||
@@ -301,9 +296,17 @@ public class PlaceholderManagerImpl extends TabFeature implements PlaceholderMan
|
||||
|
||||
@Override
|
||||
public void onJoin(TabPlayer connectedPlayer) {
|
||||
if (tabExpansion == null) return;
|
||||
for (Placeholder p : usedPlaceholders) {
|
||||
if (p instanceof ServerPlaceholder) { // server placeholders don't update on join
|
||||
if (p instanceof RelationalPlaceholderImpl) {
|
||||
for (TabPlayer all : TAB.getInstance().getOnlinePlayers()) {
|
||||
((RelationalPlaceholderImpl)p).update(connectedPlayer, all);
|
||||
((RelationalPlaceholderImpl)p).update(all, connectedPlayer);
|
||||
}
|
||||
}
|
||||
if (p instanceof PlayerPlaceholderImpl) {
|
||||
((PlayerPlaceholderImpl)p).update(connectedPlayer);
|
||||
}
|
||||
if (tabExpansion != null && p instanceof ServerPlaceholder) { // server placeholders don't update on join
|
||||
tabExpansion.setPlaceholderValue(connectedPlayer, p.getIdentifier(), ((ServerPlaceholder) p).getLastValue());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,12 +146,14 @@ public class PlayerList extends TabFeature implements TablistFormatManager {
|
||||
public void onServerChange(TabPlayer p, String from, String to) {
|
||||
onWorldChange(p, null, null);
|
||||
if (TAB.getInstance().getFeatureManager().isFeatureEnabled(TabConstants.Feature.PIPELINE_INJECTION)) return;
|
||||
for (TabPlayer all : TAB.getInstance().getOnlinePlayers()) {
|
||||
if (p.getVersion().getMinorVersion() >= 8) p.sendCustomPacket(new PacketPlayOutPlayerInfo(EnumPlayerInfoAction.UPDATE_DISPLAY_NAME,
|
||||
new PlayerInfoData(getTablistUUID(all, p), getTabFormat(all, p))), this);
|
||||
if (all.getVersion().getMinorVersion() >= 8) all.sendCustomPacket(new PacketPlayOutPlayerInfo(EnumPlayerInfoAction.UPDATE_DISPLAY_NAME,
|
||||
new PlayerInfoData(getTablistUUID(p, all), getTabFormat(p, all))), this);
|
||||
}
|
||||
TAB.getInstance().getCPUManager().runTaskLater(300, this, TabConstants.CpuUsageCategory.PLAYER_JOIN, () -> {
|
||||
for (TabPlayer all : TAB.getInstance().getOnlinePlayers()) {
|
||||
if (p.getVersion().getMinorVersion() >= 8) p.sendCustomPacket(new PacketPlayOutPlayerInfo(EnumPlayerInfoAction.UPDATE_DISPLAY_NAME,
|
||||
new PlayerInfoData(getTablistUUID(all, p), getTabFormat(all, p))), this);
|
||||
if (all.getVersion().getMinorVersion() >= 8) all.sendCustomPacket(new PacketPlayOutPlayerInfo(EnumPlayerInfoAction.UPDATE_DISPLAY_NAME,
|
||||
new PlayerInfoData(getTablistUUID(p, all), getTabFormat(p, all))), this);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -217,11 +219,11 @@ public class PlayerList extends TabFeature implements TablistFormatManager {
|
||||
|
||||
@Override
|
||||
public void onPlayerInfo(TabPlayer receiver, PacketPlayOutPlayerInfo info) {
|
||||
if (disabling || !antiOverrideTabList || TabAPI.getInstance().getFeatureManager().isFeatureEnabled(TabConstants.Feature.LAYOUT)) return;
|
||||
if (info.getAction() != EnumPlayerInfoAction.UPDATE_DISPLAY_NAME && info.getAction() != EnumPlayerInfoAction.ADD_PLAYER) return;
|
||||
if (disabling || !antiOverrideTabList) return;
|
||||
if (!info.getActions().contains(EnumPlayerInfoAction.UPDATE_DISPLAY_NAME)) return;
|
||||
for (PlayerInfoData playerInfoData : info.getEntries()) {
|
||||
TabPlayer packetPlayer = TAB.getInstance().getPlayerByTabListUUID(playerInfoData.getUniqueId());
|
||||
if (packetPlayer != null && !isDisabledPlayer(packetPlayer)) {
|
||||
if (packetPlayer != null && !isDisabledPlayer(packetPlayer) && packetPlayer.getTablistUUID() == getTablistUUID(packetPlayer, receiver)) {
|
||||
playerInfoData.setDisplayName(getTabFormat(packetPlayer, receiver));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ public class SpectatorFix extends TabFeature {
|
||||
|
||||
@Override
|
||||
public void onPlayerInfo(TabPlayer receiver, PacketPlayOutPlayerInfo info) {
|
||||
if (info.getAction() != EnumPlayerInfoAction.UPDATE_GAME_MODE && info.getAction() != EnumPlayerInfoAction.ADD_PLAYER) return;
|
||||
if (!info.getActions().contains(EnumPlayerInfoAction.UPDATE_GAME_MODE)) return;
|
||||
for (PlayerInfoData playerInfoData : info.getEntries()) {
|
||||
if (playerInfoData.getGameMode() != EnumGamemode.SPECTATOR) continue;
|
||||
if (receiver.hasPermission(TabConstants.Permission.SPECTATOR_BYPASS)) continue;
|
||||
|
||||
+7
-11
@@ -36,7 +36,7 @@ public class BossBarManagerImpl extends TabFeature implements BossBarManager {
|
||||
private final List<BossBar> announcements = new ArrayList<>();
|
||||
|
||||
//players with toggled BossBar
|
||||
private final List<String> bossBarOffPlayers;
|
||||
private final List<String> bossBarOffPlayers = rememberToggleChoice ? TAB.getInstance().getConfiguration().getPlayerDataFile().getStringList("bossbar-off", new ArrayList<>()) : Collections.emptyList();
|
||||
|
||||
//time when BossBar announce ends, used for placeholder
|
||||
private long announceEndTime;
|
||||
@@ -54,11 +54,6 @@ public class BossBarManagerImpl extends TabFeature implements BossBarManager {
|
||||
if (!line.isAnnouncementBar()) defaultBars.add(bar.toString());
|
||||
}
|
||||
lineValues = lines.values().toArray(new BossBar[0]);
|
||||
if (rememberToggleChoice) {
|
||||
bossBarOffPlayers = TAB.getInstance().getConfiguration().getPlayerDataFile().getStringList("bossbar-off", new ArrayList<>());
|
||||
} else {
|
||||
bossBarOffPlayers = Collections.emptyList();
|
||||
}
|
||||
TAB.getInstance().getPlaceholderManager().registerServerPlaceholder(TabConstants.Placeholder.COUNTDOWN, 100, () -> (announceEndTime - System.currentTimeMillis()) / 1000);
|
||||
TAB.getInstance().debug(String.format("Loaded BossBar feature with parameters disabledWorlds=%s, disabledServers=%s, toggleCommand=%s, defaultBars=%s, hiddenByDefault=%s, remember_toggle_choice=%s",
|
||||
Arrays.toString(disabledWorlds), Arrays.toString(disabledServers), toggleCommand, defaultBars, hiddenByDefault, rememberToggleChoice));
|
||||
@@ -111,6 +106,7 @@ public class BossBarManagerImpl extends TabFeature implements BossBarManager {
|
||||
line.removePlayer(p); //remove all BossBars and then resend them again to keep them displayed in defined order
|
||||
}
|
||||
showBossBars(p, defaultBars);
|
||||
showBossBars(p, announcements.stream().map(BossBar::getName).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -178,7 +174,6 @@ public class BossBarManagerImpl extends TabFeature implements BossBarManager {
|
||||
* list of BossBars to check
|
||||
*/
|
||||
private void showBossBars(TabPlayer p, List<String> bars) {
|
||||
if (bars == null) return;
|
||||
for (String defaultBar : bars) {
|
||||
BossBarLine bar = (BossBarLine) lines.get(defaultBar);
|
||||
if (bar.isConditionMet(p) && !bar.containsPlayer(p)) {
|
||||
@@ -277,18 +272,19 @@ public class BossBarManagerImpl extends TabFeature implements BossBarManager {
|
||||
public void announceBossBar(String bossBar, int duration) {
|
||||
BossBar line = lines.get(bossBar);
|
||||
if (line == null) throw new IllegalArgumentException("No registered BossBar found with name " + bossBar);
|
||||
List<TabPlayer> players = Arrays.stream(TAB.getInstance().getOnlinePlayers()).filter(
|
||||
p -> !isDisabledPlayer(p) && hasBossBarVisible(p)).collect(Collectors.toList());
|
||||
TAB.getInstance().getCPUManager().runTask(() -> {
|
||||
TAB.getInstance().getPlaceholderManager().getPlaceholder(TabConstants.Placeholder.COUNTDOWN).markAsUsed();
|
||||
announcements.add(line);
|
||||
announceEndTime = System.currentTimeMillis() + duration* 1000L;
|
||||
for (TabPlayer all : TAB.getInstance().getOnlinePlayers()) {
|
||||
if (!hasBossBarVisible(all)) continue;
|
||||
for (TabPlayer all : players) {
|
||||
if (((BossBarLine)line).isConditionMet(all)) line.addPlayer(all);
|
||||
}
|
||||
});
|
||||
TAB.getInstance().getCPUManager().runTaskLater(duration*1000,
|
||||
this, "Removing announced BossBar", () -> {
|
||||
for (TabPlayer all : TAB.getInstance().getOnlinePlayers()) {
|
||||
if (!hasBossBarVisible(all)) continue;
|
||||
for (TabPlayer all : players) {
|
||||
line.removePlayer(all);
|
||||
}
|
||||
announcements.remove(line);
|
||||
|
||||
+27
-10
@@ -6,6 +6,7 @@ import java.util.Map.Entry;
|
||||
import me.neznamy.tab.api.TabFeature;
|
||||
import me.neznamy.tab.api.TabPlayer;
|
||||
import me.neznamy.tab.api.chat.IChatBaseComponent;
|
||||
import me.neznamy.tab.api.placeholder.ServerPlaceholder;
|
||||
import me.neznamy.tab.api.protocol.PacketPlayOutPlayerInfo;
|
||||
import me.neznamy.tab.api.protocol.PacketPlayOutPlayerInfo.EnumGamemode;
|
||||
import me.neznamy.tab.api.protocol.PacketPlayOutPlayerInfo.EnumPlayerInfoAction;
|
||||
@@ -25,12 +26,19 @@ public class GlobalPlayerList extends TabFeature {
|
||||
private final boolean vanishedAsSpectators = TAB.getInstance().getConfiguration().getConfig().getBoolean("global-playerlist.display-vanished-players-as-spectators", true);
|
||||
private final boolean isolateUnlistedServers = TAB.getInstance().getConfiguration().getConfig().getBoolean("global-playerlist.isolate-unlisted-servers", false);
|
||||
private final boolean fillProfileKey = TAB.getInstance().getConfiguration().getConfig().getBoolean("global-playerlist.fill-profile-key", false);
|
||||
private final List<ServerPlaceholder> placeholders = new ArrayList<>();
|
||||
private final Map<TabPlayer, Long> lastServerSwitch = new WeakHashMap<>();
|
||||
private final UUID EMPTY_ID = new UUID(0, 0);
|
||||
|
||||
public GlobalPlayerList() {
|
||||
super("Global PlayerList", null);
|
||||
boolean updateLatency = TAB.getInstance().getConfiguration().getConfig().getBoolean("global-playerlist.update-latency", false);
|
||||
if (updateLatency) TAB.getInstance().getFeatureManager().registerFeature(TabConstants.Feature.GLOBAL_PLAYER_LIST_LATENCY, new LatencyRefresher());
|
||||
TAB.getInstance().getPlaceholderManager().addUsedPlaceholders(Collections.singletonList(TabConstants.Placeholder.VANISHED));
|
||||
for (Entry<String, List<String>> entry : sharedServers.entrySet()) {
|
||||
placeholders.add(TAB.getInstance().getPlaceholderManager().registerServerPlaceholder(TabConstants.Placeholder.globalPlayerListGroup(entry.getKey()), -1,
|
||||
() -> Arrays.stream(TAB.getInstance().getOnlinePlayers()).filter(p -> entry.getValue().contains(p.getServer()) && !p.isVanished()).count()));
|
||||
}
|
||||
TAB.getInstance().debug(String.format("Loaded GlobalPlayerList feature with parameters spyServers=%s, sharedServers=%s, displayAsSpectators=%s, vanishedAsSpectators=%s, isolateUnlistedServers=%s, updateLatency=%s",
|
||||
spyServers, sharedServers, displayAsSpectators, vanishedAsSpectators, isolateUnlistedServers, updateLatency));
|
||||
}
|
||||
@@ -43,18 +51,19 @@ public class GlobalPlayerList extends TabFeature {
|
||||
if (shouldSee(viewer, displayed)) viewer.sendCustomPacket(getAddPacket(displayed, viewer), this);
|
||||
}
|
||||
}
|
||||
placeholders.forEach(pl -> pl.updateValue(pl.request()));
|
||||
}
|
||||
|
||||
public boolean shouldSee(TabPlayer viewer, TabPlayer displayed) {
|
||||
if (displayed == viewer) return true;
|
||||
if (displayed.isVanished() && !viewer.hasPermission(TabConstants.Permission.SEE_VANISHED)) return false;
|
||||
if (spyServers.contains(viewer.getServer())) return true;
|
||||
if (isSpyServer(viewer.getServer())) return true;
|
||||
return getServerGroup(viewer.getServer()).equals(getServerGroup(displayed.getServer()));
|
||||
}
|
||||
|
||||
public String getServerGroup(String serverName) {
|
||||
for (Entry<String, List<String>> group : sharedServers.entrySet()) {
|
||||
if (group.getValue().contains(serverName)) return group.getKey();
|
||||
if (group.getValue().stream().anyMatch(serverName::equalsIgnoreCase)) return group.getKey();
|
||||
}
|
||||
return isolateUnlistedServers ? "isolated:" + serverName : "DEFAULT";
|
||||
}
|
||||
@@ -80,6 +89,7 @@ public class GlobalPlayerList extends TabFeature {
|
||||
connectedPlayer.sendCustomPacket(getAddPacket(all, connectedPlayer), this);
|
||||
}
|
||||
}
|
||||
placeholders.forEach(pl -> pl.updateValue(pl.request()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -93,11 +103,14 @@ public class GlobalPlayerList extends TabFeature {
|
||||
if (all == disconnectedPlayer) continue;
|
||||
all.sendCustomPacket(remove, this);
|
||||
}
|
||||
//update after player is removed
|
||||
placeholders.forEach(pl -> pl.updateValue(pl.request()));
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServerChange(TabPlayer p, String from, String to) {
|
||||
lastServerSwitch.put(p, System.currentTimeMillis());
|
||||
Runnable r = () -> {
|
||||
PacketPlayOutPlayerInfo removeChanged = getRemovePacket(p);
|
||||
for (TabPlayer all : TAB.getInstance().getOnlinePlayers()) {
|
||||
@@ -119,12 +132,12 @@ public class GlobalPlayerList extends TabFeature {
|
||||
} else {
|
||||
r.run();
|
||||
}
|
||||
placeholders.forEach(pl -> pl.updateValue(pl.request()));
|
||||
}
|
||||
|
||||
public PacketPlayOutPlayerInfo getRemovePacket(TabPlayer p) {
|
||||
PlayerInfoData data = new PlayerInfoData(p.getTablistUUID());
|
||||
data.setName(p.getName());
|
||||
return new PacketPlayOutPlayerInfo(EnumPlayerInfoAction.REMOVE_PLAYER, data);
|
||||
return new PacketPlayOutPlayerInfo(EnumPlayerInfoAction.REMOVE_PLAYER,
|
||||
new PlayerInfoData(p.getTablistUUID()), new PlayerInfoData(EMPTY_ID));
|
||||
}
|
||||
|
||||
public PacketPlayOutPlayerInfo getAddPacket(TabPlayer p, TabPlayer viewer) {
|
||||
@@ -138,9 +151,11 @@ public class GlobalPlayerList extends TabFeature {
|
||||
p.getName(),
|
||||
p.getTablistUUID(),
|
||||
p.getSkin(),
|
||||
true,
|
||||
p.getPing(),
|
||||
vanishedAsSpectators && p.isVanished() ? EnumGamemode.SPECTATOR : EnumGamemode.CREATIVE,
|
||||
viewer.getVersion().getMinorVersion() >= 8 ? format : null,
|
||||
fillProfileKey ? p.getChatSessionId() : null,
|
||||
fillProfileKey ? p.getProfilePublicKey() : null
|
||||
)
|
||||
);
|
||||
@@ -148,11 +163,13 @@ public class GlobalPlayerList extends TabFeature {
|
||||
|
||||
@Override
|
||||
public void onPlayerInfo(TabPlayer receiver, PacketPlayOutPlayerInfo info) {
|
||||
if (info.getAction() == EnumPlayerInfoAction.REMOVE_PLAYER) {
|
||||
if (info.getActions().contains(EnumPlayerInfoAction.REMOVE_PLAYER)) {
|
||||
boolean packetFromTAB = info.getEntries().stream().anyMatch(data -> data.getUniqueId().equals(EMPTY_ID));
|
||||
for (PlayerInfoData playerInfoData : info.getEntries()) {
|
||||
TabPlayer packetPlayer = TAB.getInstance().getPlayerByTabListUUID(playerInfoData.getUniqueId());
|
||||
//not preventing NPC removals
|
||||
if (packetPlayer != null && (playerInfoData.getName() == null || playerInfoData.getName().length() == 0) && !packetPlayer.isVanished()) {
|
||||
if (packetPlayer != null && !packetFromTAB && !packetPlayer.isVanished() &&
|
||||
(System.currentTimeMillis()-lastServerSwitch.getOrDefault(packetPlayer, 0L) < 500)) {
|
||||
//remove packet not coming from tab
|
||||
//changing to random non-existing player, the easiest way to cancel the removal
|
||||
playerInfoData.setUniqueId(UUID.randomUUID());
|
||||
@@ -160,7 +177,7 @@ public class GlobalPlayerList extends TabFeature {
|
||||
}
|
||||
}
|
||||
if (!displayAsSpectators) return;
|
||||
if (info.getAction() == EnumPlayerInfoAction.ADD_PLAYER || info.getAction() == EnumPlayerInfoAction.UPDATE_GAME_MODE) {
|
||||
if (info.getActions().contains(EnumPlayerInfoAction.UPDATE_GAME_MODE)) {
|
||||
for (PlayerInfoData playerInfoData : info.getEntries()) {
|
||||
TabPlayer packetPlayer = TAB.getInstance().getPlayerByTabListUUID(playerInfoData.getUniqueId());
|
||||
if (packetPlayer != null && !receiver.getServer().equals(packetPlayer.getServer())) {
|
||||
@@ -189,7 +206,7 @@ public class GlobalPlayerList extends TabFeature {
|
||||
}
|
||||
}
|
||||
|
||||
public List<String> getSpyServers() {
|
||||
return spyServers;
|
||||
public boolean isSpyServer(String server) {
|
||||
return spyServers.stream().anyMatch(server::equalsIgnoreCase);
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import me.neznamy.tab.api.ProtocolVersion;
|
||||
import me.neznamy.tab.api.TabFeature;
|
||||
import me.neznamy.tab.api.TabPlayer;
|
||||
import me.neznamy.tab.api.chat.IChatBaseComponent;
|
||||
@@ -42,15 +43,19 @@ public class Layout extends TabFeature {
|
||||
groups.forEach(g -> list.addAll(g.getSlots(p)));
|
||||
for (FixedSlot slot : fixedSlots.values()) {
|
||||
p.setProperty(slot, slot.getPropertyName(), slot.getText());
|
||||
list.add(new PlayerInfoData("", slot.getId(), slot.getSkin(), slot.getPing(), EnumGamemode.CREATIVE, IChatBaseComponent.optimizedComponent(p.getProperty(slot.getPropertyName()).updateAndGet()), null));
|
||||
list.add(new PlayerInfoData(getEntryName(p, slot.getId().getLeastSignificantBits()), slot.getId(), slot.getSkin(), true, slot.getPing(), EnumGamemode.CREATIVE, IChatBaseComponent.optimizedComponent(p.getProperty(slot.getPropertyName()).updateAndGet()), null, null));
|
||||
}
|
||||
for (int slot : emptySlots) {
|
||||
list.add(new PlayerInfoData("", manager.getUUID(slot), manager.getSkinManager().getDefaultSkin(), manager.getEmptySlotPing(), EnumGamemode.CREATIVE, new IChatBaseComponent(""), null));
|
||||
list.add(new PlayerInfoData(getEntryName(p, slot), manager.getUUID(slot), manager.getSkinManager().getDefaultSkin(), true, manager.getEmptySlotPing(), EnumGamemode.CREATIVE, new IChatBaseComponent(""), null, null));
|
||||
}
|
||||
if (p.getVersion().getMinorVersion() < 8 || p.isBedrockPlayer()) return;
|
||||
p.sendCustomPacket(new PacketPlayOutPlayerInfo(EnumPlayerInfoAction.ADD_PLAYER, list), this);
|
||||
}
|
||||
|
||||
public String getEntryName(TabPlayer viewer, long slot) {
|
||||
return viewer.getVersion().getNetworkId() >= ProtocolVersion.V1_19_3.getNetworkId() ? "|slot_" + (10+slot) : "";
|
||||
}
|
||||
|
||||
public void removeFrom(TabPlayer p) {
|
||||
if (!viewers.contains(p)) return;
|
||||
viewers.remove(p);
|
||||
|
||||
@@ -9,10 +9,10 @@ import me.neznamy.tab.api.chat.EnumChatFormat;
|
||||
import me.neznamy.tab.api.protocol.PacketPlayOutPlayerInfo;
|
||||
import me.neznamy.tab.api.protocol.PacketPlayOutPlayerInfo.EnumPlayerInfoAction;
|
||||
import me.neznamy.tab.api.protocol.PacketPlayOutPlayerInfo.PlayerInfoData;
|
||||
import me.neznamy.tab.shared.ITabPlayer;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.api.TabConstants;
|
||||
import me.neznamy.tab.shared.features.layout.skin.SkinManager;
|
||||
import me.neznamy.tab.shared.features.sorting.Sorting;
|
||||
import me.neznamy.tab.shared.placeholders.conditions.Condition;
|
||||
|
||||
public class LayoutManager extends TabFeature {
|
||||
@@ -24,7 +24,6 @@ public class LayoutManager extends TabFeature {
|
||||
private final int emptySlotPing = TAB.getInstance().getConfiguration().getLayout().getInt("empty-slot-ping-value", 1000);
|
||||
private final boolean hideVanishedPlayers = TAB.getInstance().getConfiguration().getLayout().getBoolean("hide-vanished-players", true);
|
||||
private final SkinManager skinManager = new SkinManager(defaultSkin);
|
||||
|
||||
private final Map<Integer, UUID> uuids = new HashMap<Integer, UUID>(){{
|
||||
for (int slot=1; slot<=80; slot++) {
|
||||
put(slot, new UUID(0, translateSlot(slot)));
|
||||
@@ -32,7 +31,9 @@ public class LayoutManager extends TabFeature {
|
||||
}};
|
||||
private final Map<String, Layout> layouts = loadLayouts();
|
||||
private final WeakHashMap<TabPlayer, Layout> playerViews = new WeakHashMap<>();
|
||||
private final Map<TabPlayer, String> sortedPlayers = Collections.synchronizedMap(new TreeMap<>(Comparator.comparing(TabPlayer::getTeamName)));
|
||||
private final WeakHashMap<TabPlayer, String> teamNames = new WeakHashMap<>();
|
||||
private final Map<TabPlayer, String> sortedPlayers = Collections.synchronizedMap(new TreeMap<>(Comparator.comparing(teamNames::get)));
|
||||
private final Sorting sorting = (Sorting) TAB.getInstance().getFeatureManager().getFeature(TabConstants.Feature.SORTING);
|
||||
|
||||
public LayoutManager() {
|
||||
super("Layout", "Switching layouts");
|
||||
@@ -66,14 +67,18 @@ public class LayoutManager extends TabFeature {
|
||||
}
|
||||
for (String fixedSlot : (List<String>)map.getOrDefault("fixed-slots", Collections.emptyList())) {
|
||||
String[] array = fixedSlot.split("\\|");
|
||||
int slot = Integer.parseInt(array[0]);
|
||||
String text = array[1];
|
||||
String skin = array.length > 2 ? array[2] : "";
|
||||
int ping = array.length > 3 ? TAB.getInstance().getErrorManager().parseInteger(array[3], emptySlotPing) : emptySlotPing;
|
||||
FixedSlot f = new FixedSlot(l, slot, text, skin, ping);
|
||||
fixedSlots.put(slot, f);
|
||||
emptySlots.remove((Integer)slot);
|
||||
if (text.length() > 0) TAB.getInstance().getFeatureManager().registerFeature(TabConstants.Feature.layoutSlot(layout.getKey().toString(), slot), f);
|
||||
try {
|
||||
int slot = Integer.parseInt(array[0]);
|
||||
String text = array[1];
|
||||
String skin = array.length > 2 ? array[2] : "";
|
||||
int ping = array.length > 3 ? TAB.getInstance().getErrorManager().parseInteger(array[3], emptySlotPing) : emptySlotPing;
|
||||
FixedSlot f = new FixedSlot(l, slot, text, skin, ping);
|
||||
fixedSlots.put(slot, f);
|
||||
emptySlots.remove((Integer)slot);
|
||||
if (text.length() > 0) TAB.getInstance().getFeatureManager().registerFeature(TabConstants.Feature.layoutSlot(layout.getKey().toString(), slot), f);
|
||||
} catch (NumberFormatException e) {
|
||||
TAB.getInstance().getErrorManager().startupWarn("Layout \"" + layout.getKey() + "\"'s fixed slot line \"" + fixedSlot + "&c\" has invalid number as slot.");
|
||||
}
|
||||
}
|
||||
Map<String, Map<String, Object>> groups = (Map<String, Map<String, Object>>) map.get("groups");
|
||||
if (groups != null) {
|
||||
@@ -83,7 +88,7 @@ public class LayoutManager extends TabFeature {
|
||||
for (String line : (List<String>) group.getValue().get("slots")) {
|
||||
String[] arr = line.split("-");
|
||||
int from = Integer.parseInt(arr[0]);
|
||||
int to = Integer.parseInt(arr[1]);
|
||||
int to = arr.length == 1 ? from : Integer.parseInt(arr[1]);
|
||||
for (int i = from; i<= to; i++) {
|
||||
positions.add(i);
|
||||
}
|
||||
@@ -100,12 +105,15 @@ public class LayoutManager extends TabFeature {
|
||||
|
||||
@Override
|
||||
public void onJoin(TabPlayer p) {
|
||||
sortedPlayers.put(p, p.getTeamName());
|
||||
teamNames.put(p, sorting.getFullTeamName(p));
|
||||
sortedPlayers.put(p, sorting.getFullTeamName(p));
|
||||
Layout highest = getHighestLayout(p);
|
||||
if (highest != null) highest.sendTo(p);
|
||||
playerViews.put(p, highest);
|
||||
layouts.values().forEach(Layout::tick);
|
||||
|
||||
// Unformat original entries for players who can see a layout to avoid spaces due to unparsed placeholders and such
|
||||
if (highest == null) return;
|
||||
List<PlayerInfoData> data = new ArrayList<>();
|
||||
for (TabPlayer all : TAB.getInstance().getOnlinePlayers()) {
|
||||
data.add(new PlayerInfoData(all.getTablistUUID()));
|
||||
@@ -116,6 +124,7 @@ public class LayoutManager extends TabFeature {
|
||||
@Override
|
||||
public void onQuit(TabPlayer p) {
|
||||
sortedPlayers.remove(p);
|
||||
teamNames.remove(p);
|
||||
layouts.values().forEach(Layout::tick);
|
||||
}
|
||||
|
||||
@@ -179,7 +188,7 @@ public class LayoutManager extends TabFeature {
|
||||
|
||||
public void updateTeamName(TabPlayer p, String teamName) {
|
||||
sortedPlayers.remove(p);
|
||||
((ITabPlayer) p).setTeamName(teamName);
|
||||
teamNames.put(p, teamName);
|
||||
sortedPlayers.put(p, teamName);
|
||||
layouts.values().forEach(Layout::tick);
|
||||
}
|
||||
|
||||
@@ -45,9 +45,9 @@ public class PlayerSlot {
|
||||
PlayerInfoData data;
|
||||
TabPlayer player = this.player; //avoiding NPE from concurrent access
|
||||
if (player != null) {
|
||||
data = new PlayerInfoData("", id, player.getSkin(), player.getPing(), EnumGamemode.SURVIVAL, playerlist == null ? new IChatBaseComponent(player.getName()) : playerlist.getTabFormat(player, p), null);
|
||||
data = new PlayerInfoData(layout.getEntryName(p, id.getLeastSignificantBits()), id, player.getSkin(), true, player.getPing(), EnumGamemode.SURVIVAL, playerlist == null ? new IChatBaseComponent(player.getName()) : playerlist.getTabFormat(player, p), null, null);
|
||||
} else {
|
||||
data = new PlayerInfoData("", id, layout.getManager().getSkinManager().getDefaultSkin(), layout.getManager().getEmptySlotPing(), EnumGamemode.SURVIVAL, new IChatBaseComponent(text), null);
|
||||
data = new PlayerInfoData(layout.getEntryName(p, id.getLeastSignificantBits()), id, layout.getManager().getSkinManager().getDefaultSkin(), true, layout.getManager().getEmptySlotPing(), EnumGamemode.SURVIVAL, new IChatBaseComponent(text), null, null);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ import me.neznamy.tab.api.protocol.PacketPlayOutScoreboardTeam;
|
||||
import me.neznamy.tab.api.team.TeamManager;
|
||||
import me.neznamy.tab.api.util.Preconditions;
|
||||
import me.neznamy.tab.api.TabConstants;
|
||||
import me.neznamy.tab.shared.ITabPlayer;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.shared.features.TabExpansion;
|
||||
import me.neznamy.tab.shared.features.redis.RedisSupport;
|
||||
@@ -19,10 +18,10 @@ import me.neznamy.tab.shared.features.sorting.Sorting;
|
||||
|
||||
public class NameTag extends TabFeature implements TeamManager {
|
||||
|
||||
private final boolean invisibleNameTags = TAB.getInstance().getConfiguration().getConfig().getBoolean("scoreboard-teams.invisible-nametags", false);
|
||||
protected final boolean invisibleNameTags = TAB.getInstance().getConfiguration().getConfig().getBoolean("scoreboard-teams.invisible-nametags", false);
|
||||
private final boolean collisionRule = TAB.getInstance().getConfiguration().getConfig().getBoolean("scoreboard-teams.enable-collision", true);
|
||||
private final boolean canSeeFriendlyInvisibles = TAB.getInstance().getConfig().getBoolean("scoreboard-teams.can-see-friendly-invisibles", false);
|
||||
private final Sorting sorting = new Sorting(this);
|
||||
private final Sorting sorting = (Sorting) TAB.getInstance().getFeatureManager().getFeature(TabConstants.Feature.SORTING);
|
||||
private final CollisionManager collisionManager = new CollisionManager(this, collisionRule);
|
||||
|
||||
private final Set<TabPlayer> hiddenNameTag = Collections.newSetFromMap(new WeakHashMap<>());
|
||||
@@ -49,7 +48,6 @@ public class NameTag extends TabFeature implements TeamManager {
|
||||
public void load(){
|
||||
TabExpansion expansion = TAB.getInstance().getPlaceholderManager().getTabExpansion();
|
||||
for (TabPlayer all : TAB.getInstance().getOnlinePlayers()) {
|
||||
((ITabPlayer) all).setTeamName(getSorting().getTeamName(all));
|
||||
updateProperties(all);
|
||||
hiddenNameTagFor.put(all, new ArrayList<>());
|
||||
if (isDisabled(all.getServer(), all.getWorld())) {
|
||||
@@ -93,7 +91,7 @@ public class NameTag extends TabFeature implements TeamManager {
|
||||
|
||||
@Override
|
||||
public void onJoin(TabPlayer connectedPlayer) {
|
||||
((ITabPlayer) connectedPlayer).setTeamName(getSorting().getTeamName(connectedPlayer));
|
||||
sorting.constructTeamNames(connectedPlayer);
|
||||
updateProperties(connectedPlayer);
|
||||
hiddenNameTagFor.put(connectedPlayer, new ArrayList<>());
|
||||
for (TabPlayer all : TAB.getInstance().getOnlinePlayers()) {
|
||||
@@ -116,7 +114,7 @@ public class NameTag extends TabFeature implements TeamManager {
|
||||
@Override
|
||||
public void onQuit(TabPlayer disconnectedPlayer) {
|
||||
if (!isDisabledPlayer(disconnectedPlayer) && !hasTeamHandlingPaused(disconnectedPlayer)) {
|
||||
PacketPlayOutScoreboardTeam packet = new PacketPlayOutScoreboardTeam(disconnectedPlayer.getTeamName());
|
||||
PacketPlayOutScoreboardTeam packet = new PacketPlayOutScoreboardTeam(sorting.getShortTeamName(disconnectedPlayer));
|
||||
for (TabPlayer viewer : TAB.getInstance().getOnlinePlayers()) {
|
||||
if (viewer == disconnectedPlayer) continue; //player who just disconnected
|
||||
viewer.sendCustomPacket(packet, TabConstants.PacketCategory.NAMETAGS_TEAM_UNREGISTER);
|
||||
@@ -218,9 +216,9 @@ public class NameTag extends TabFeature implements TeamManager {
|
||||
unregisterTeam(player);
|
||||
forcedTeamName.put(player, name);
|
||||
registerTeam(player);
|
||||
if (name != null) ((ITabPlayer)player).setTeamNameNote("Set using API");
|
||||
if (name != null) sorting.setTeamNameNote(player, "Set using API");
|
||||
RedisSupport redis = (RedisSupport) TAB.getInstance().getFeatureManager().getFeature(TabConstants.Feature.REDIS_BUNGEE);
|
||||
if (redis != null) redis.updateTeamName(player, player.getTeamName());
|
||||
if (redis != null) redis.updateTeamName(player, sorting.getShortTeamName(player));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -246,7 +244,7 @@ public class NameTag extends TabFeature implements TeamManager {
|
||||
String currentPrefix = tagPrefix.getFormat(viewer);
|
||||
String currentSuffix = tagSuffix.getFormat(viewer);
|
||||
boolean visible = getTeamVisibility(p, viewer);
|
||||
viewer.sendCustomPacket(new PacketPlayOutScoreboardTeam(p.getTeamName(), currentPrefix, currentSuffix, translate(visible), translate(collisionManager.getCollision(p)), getTeamOptions()), TabConstants.PacketCategory.NAMETAGS_TEAM_UPDATE);
|
||||
viewer.sendCustomPacket(new PacketPlayOutScoreboardTeam(sorting.getShortTeamName(p), currentPrefix, currentSuffix, translate(visible), translate(collisionManager.getCollision(p)), getTeamOptions()), TabConstants.PacketCategory.NAMETAGS_TEAM_UPDATE);
|
||||
}
|
||||
RedisSupport redis = (RedisSupport) TAB.getInstance().getFeatureManager().getFeature(TabConstants.Feature.REDIS_BUNGEE);
|
||||
if (redis != null) redis.updateNameTag(p, p.getProperty(TabConstants.Property.TAGPREFIX).get(), p.getProperty(TabConstants.Property.TAGSUFFIX).get());
|
||||
@@ -256,13 +254,13 @@ public class NameTag extends TabFeature implements TeamManager {
|
||||
boolean visible = getTeamVisibility(p, viewer);
|
||||
String currentPrefix = p.getProperty(TabConstants.Property.TAGPREFIX).getFormat(viewer);
|
||||
String currentSuffix = p.getProperty(TabConstants.Property.TAGSUFFIX).getFormat(viewer);
|
||||
viewer.sendCustomPacket(new PacketPlayOutScoreboardTeam(p.getTeamName(), currentPrefix, currentSuffix, translate(visible), translate(collisionManager.getCollision(p)), getTeamOptions()), TabConstants.PacketCategory.NAMETAGS_TEAM_UPDATE);
|
||||
viewer.sendCustomPacket(new PacketPlayOutScoreboardTeam(sorting.getShortTeamName(p), currentPrefix, currentSuffix, translate(visible), translate(collisionManager.getCollision(p)), getTeamOptions()), TabConstants.PacketCategory.NAMETAGS_TEAM_UPDATE);
|
||||
}
|
||||
|
||||
public void unregisterTeam(TabPlayer p) {
|
||||
if (hasTeamHandlingPaused(p) || p.getTeamName() == null) return;
|
||||
if (hasTeamHandlingPaused(p) || sorting.getShortTeamName(p) == null) return;
|
||||
for (TabPlayer viewer : TAB.getInstance().getOnlinePlayers()) {
|
||||
viewer.sendCustomPacket(new PacketPlayOutScoreboardTeam(p.getTeamName()), TabConstants.PacketCategory.NAMETAGS_TEAM_UNREGISTER);
|
||||
viewer.sendCustomPacket(new PacketPlayOutScoreboardTeam(sorting.getShortTeamName(p)), TabConstants.PacketCategory.NAMETAGS_TEAM_UNREGISTER);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -276,23 +274,23 @@ public class NameTag extends TabFeature implements TeamManager {
|
||||
if (hasTeamHandlingPaused(p)) return;
|
||||
String replacedPrefix = p.getProperty(TabConstants.Property.TAGPREFIX).getFormat(viewer);
|
||||
String replacedSuffix = p.getProperty(TabConstants.Property.TAGSUFFIX).getFormat(viewer);
|
||||
viewer.sendCustomPacket(new PacketPlayOutScoreboardTeam(p.getTeamName(), replacedPrefix, replacedSuffix, translate(getTeamVisibility(p, viewer)),
|
||||
viewer.sendCustomPacket(new PacketPlayOutScoreboardTeam(sorting.getShortTeamName(p), replacedPrefix, replacedSuffix, translate(getTeamVisibility(p, viewer)),
|
||||
translate(collisionManager.getCollision(p)), Collections.singletonList(p.getNickname()), getTeamOptions()), TabConstants.PacketCategory.NAMETAGS_TEAM_REGISTER);
|
||||
}
|
||||
|
||||
private void updateTeam(TabPlayer p) {
|
||||
if (p.getTeamName() == null) return; //player not loaded yet
|
||||
String newName = getSorting().getTeamName(p);
|
||||
if (p.getTeamName().equals(newName)) {
|
||||
if (sorting.getShortTeamName(p) == null) return; //player not loaded yet
|
||||
String oldName = getSorting().getShortTeamName(p);
|
||||
getSorting().constructTeamNames(p);
|
||||
if (oldName.equals(sorting.getShortTeamName(p))) {
|
||||
updateTeamData(p);
|
||||
} else {
|
||||
unregisterTeam(p);
|
||||
LayoutManager layout = (LayoutManager) TAB.getInstance().getFeatureManager().getFeature(TabConstants.Feature.LAYOUT);
|
||||
if (layout != null) layout.updateTeamName(p, newName);
|
||||
((ITabPlayer) p).setTeamName(newName);
|
||||
if (layout != null) layout.updateTeamName(p, sorting.getFullTeamName(p));
|
||||
registerTeam(p);
|
||||
RedisSupport redis = (RedisSupport) TAB.getInstance().getFeatureManager().getFeature(TabConstants.Feature.REDIS_BUNGEE);
|
||||
if (redis != null) redis.updateTeamName(p, p.getTeamName());
|
||||
if (redis != null) redis.updateTeamName(p, sorting.getShortTeamName(p));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -36,6 +36,11 @@ public abstract class NameTagX extends NameTag implements UnlimitedNametagManage
|
||||
public NameTagX(BiFunction<NameTagX, TabPlayer, ArmorStandManager> armorStandFunction) {
|
||||
this.armorStandFunction = armorStandFunction;
|
||||
Collections.reverse(dynamicLines);
|
||||
if (invisibleNameTags) {
|
||||
TAB.getInstance().getErrorManager().startupWarn("Unlimited nametag mode is enabled as well as invisible nametags. These 2 options are mutually exclusive.");
|
||||
TAB.getInstance().getErrorManager().startupWarn("If you want nametags to be invisible, you don't need unlimited nametag mode at all.");
|
||||
TAB.getInstance().getErrorManager().startupWarn("If you want enhanced nametags without limits, making them invisible would defeat the purpose.");
|
||||
}
|
||||
TAB.getInstance().debug(String.format("Loaded Unlimited NameTag feature with parameters markerFor18x=%s, disableOnBoats=%s, disabledUnlimitedServers=%s, disabledUnlimitedWorlds=%s",
|
||||
markerFor18x, disableOnBoats, disabledUnlimitedServers, disabledUnlimitedWorlds));
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ public class RedisPlayer {
|
||||
private static String checkTeamName(RedisSupport redis, String currentName15, int id) {
|
||||
String potentialTeamName = currentName15 + (char)id;
|
||||
for (TabPlayer all : TAB.getInstance().getOnlinePlayers()) {
|
||||
if (all.getTeamName() != null && all.getTeamName().equals(potentialTeamName)) {
|
||||
if (redis.getSorting() != null && redis.getSorting().getShortTeamName(all).equals(potentialTeamName)) {
|
||||
return checkTeamName(redis, currentName15, id+1);
|
||||
}
|
||||
}
|
||||
@@ -110,7 +110,7 @@ public class RedisPlayer {
|
||||
if (p.getProperty(TabConstants.Property.YELLOW_NUMBER) != null) {
|
||||
json.put("yellow-number", p.getProperty(TabConstants.Property.YELLOW_NUMBER).get());
|
||||
}
|
||||
json.put("teamname", p.getTeamName());
|
||||
json.put("teamname", redis.getSorting() == null ? null : redis.getSorting().getShortTeamName(p));
|
||||
json.put("vanished", p.isVanished());
|
||||
json.put("staff", p.hasPermission(TabConstants.Permission.STAFF));
|
||||
if (p.getSkin() != null) {
|
||||
@@ -121,8 +121,8 @@ public class RedisPlayer {
|
||||
}
|
||||
|
||||
public PacketPlayOutPlayerInfo getAddPacket() {
|
||||
return new PacketPlayOutPlayerInfo(EnumPlayerInfoAction.ADD_PLAYER, new PlayerInfoData(nickname, uniqueId, skin, 0, EnumGamemode.SURVIVAL,
|
||||
disabledPlayerList ? null : IChatBaseComponent.optimizedComponent(tabFormat), null));
|
||||
return new PacketPlayOutPlayerInfo(EnumPlayerInfoAction.ADD_PLAYER, new PlayerInfoData(nickname, uniqueId, skin, true, 0, EnumGamemode.SURVIVAL,
|
||||
disabledPlayerList ? null : IChatBaseComponent.optimizedComponent(tabFormat), null, null));
|
||||
}
|
||||
|
||||
public PacketPlayOutPlayerInfo getUpdatePacket() {
|
||||
|
||||
@@ -10,6 +10,7 @@ import me.neznamy.tab.api.TabConstants;
|
||||
import me.neznamy.tab.shared.features.PlayerList;
|
||||
import me.neznamy.tab.shared.features.globalplayerlist.GlobalPlayerList;
|
||||
import me.neznamy.tab.shared.features.nametags.NameTag;
|
||||
import me.neznamy.tab.shared.features.sorting.Sorting;
|
||||
import org.json.simple.JSONObject;
|
||||
import org.json.simple.parser.JSONParser;
|
||||
import org.json.simple.parser.ParseException;
|
||||
@@ -39,6 +40,13 @@ public abstract class RedisSupport extends TabFeature {
|
||||
/** NameTag feature */
|
||||
private final NameTag nameTags = (NameTag) TAB.getInstance().getTeamManager();
|
||||
|
||||
/** Sorting feature */
|
||||
private final Sorting sorting = (Sorting) TAB.getInstance().getFeatureManager().getFeature(TabConstants.Feature.SORTING);
|
||||
|
||||
private final UUID EMPTY_ID = new UUID(0, 0);
|
||||
|
||||
private final Map<RedisPlayer, Long> lastServerSwitch = new WeakHashMap<>();
|
||||
|
||||
/**
|
||||
* Constructs new instance
|
||||
*/
|
||||
@@ -226,6 +234,7 @@ public abstract class RedisSupport extends TabFeature {
|
||||
target.setServer(server);
|
||||
return;
|
||||
}
|
||||
lastServerSwitch.put(target, System.currentTimeMillis());
|
||||
for (TabPlayer viewer : TAB.getInstance().getOnlinePlayers()) {
|
||||
if (viewer.getVersion().getMinorVersion() < 8) continue;
|
||||
boolean before = shouldSee(viewer, target.getServer(), target.isVanished());
|
||||
@@ -331,7 +340,7 @@ public abstract class RedisSupport extends TabFeature {
|
||||
|
||||
private boolean shouldSee(TabPlayer viewer, String viewerServer, String server, boolean targetVanished) {
|
||||
if (targetVanished && !viewer.hasPermission(TabConstants.Permission.SEE_VANISHED)) return false;
|
||||
if (global.getSpyServers().contains(viewerServer)) return true;
|
||||
if (global.isSpyServer(viewerServer)) return true;
|
||||
return global.getServerGroup(viewerServer).equals(global.getServerGroup(server));
|
||||
}
|
||||
|
||||
@@ -413,21 +422,24 @@ public abstract class RedisSupport extends TabFeature {
|
||||
|
||||
@Override
|
||||
public void onPlayerInfo(TabPlayer receiver, PacketPlayOutPlayerInfo info) {
|
||||
if (info.getAction() == PacketPlayOutPlayerInfo.EnumPlayerInfoAction.REMOVE_PLAYER && global != null) {
|
||||
if (info.getActions().contains(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.REMOVE_PLAYER) && global != null) {
|
||||
boolean packetFromTAB = info.getEntries().stream().anyMatch(data -> data.getUniqueId().equals(EMPTY_ID));
|
||||
for (PacketPlayOutPlayerInfo.PlayerInfoData playerInfoData : info.getEntries()) {
|
||||
RedisPlayer packetPlayer = redisPlayers.get(playerInfoData.getUniqueId().toString());
|
||||
if (packetPlayer != null && (playerInfoData.getName() == null || playerInfoData.getName().length() == 0) && !packetPlayer.isVanished()) {
|
||||
if (packetPlayer != null && !packetFromTAB && !packetPlayer.isVanished() &&
|
||||
(System.currentTimeMillis()-lastServerSwitch.getOrDefault(packetPlayer, 0L) < 500)) {
|
||||
//remove packet not coming from tab
|
||||
//changing to random non-existing player, the easiest way to cancel the removal
|
||||
playerInfoData.setUniqueId(UUID.randomUUID());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (info.getAction() != PacketPlayOutPlayerInfo.EnumPlayerInfoAction.UPDATE_DISPLAY_NAME && info.getAction() != PacketPlayOutPlayerInfo.EnumPlayerInfoAction.ADD_PLAYER) return;
|
||||
for (PacketPlayOutPlayerInfo.PlayerInfoData playerInfoData : info.getEntries()) {
|
||||
RedisPlayer packetPlayer = redisPlayers.get(playerInfoData.getUniqueId().toString());
|
||||
if (packetPlayer != null && !packetPlayer.hasDisabledPlayerlist()) {
|
||||
playerInfoData.setDisplayName(IChatBaseComponent.optimizedComponent(packetPlayer.getTabFormat()));
|
||||
if (info.getActions().contains(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.UPDATE_GAME_MODE)) {
|
||||
for (PacketPlayOutPlayerInfo.PlayerInfoData playerInfoData : info.getEntries()) {
|
||||
RedisPlayer packetPlayer = redisPlayers.get(playerInfoData.getUniqueId().toString());
|
||||
if (packetPlayer != null && !packetPlayer.hasDisabledPlayerlist()) {
|
||||
playerInfoData.setDisplayName(IChatBaseComponent.optimizedComponent(packetPlayer.getTabFormat()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -440,4 +452,8 @@ public abstract class RedisSupport extends TabFeature {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Sorting getSorting() {
|
||||
return sorting;
|
||||
}
|
||||
}
|
||||
@@ -240,4 +240,8 @@ public class ScoreboardImpl extends TabFeature implements Scoreboard {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void removePlayerFromSet(TabPlayer player) {
|
||||
players.remove(player);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -380,7 +380,7 @@ public class ScoreboardManagerImpl extends TabFeature implements ScoreboardManag
|
||||
otherPluginScoreboard.remove(packetReceiver);
|
||||
ScoreboardImpl scoreboard = activeScoreboard.get(packetReceiver);
|
||||
if (scoreboard != null) {
|
||||
scoreboard.removePlayer(packetReceiver);
|
||||
scoreboard.removePlayerFromSet(packetReceiver);
|
||||
scoreboard.addPlayer(packetReceiver);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@ import java.util.stream.Collectors;
|
||||
|
||||
import me.neznamy.tab.api.TabFeature;
|
||||
import me.neznamy.tab.api.TabPlayer;
|
||||
import me.neznamy.tab.api.protocol.PacketPlayOutScoreboardTeam;
|
||||
import me.neznamy.tab.api.team.TeamManager;
|
||||
import me.neznamy.tab.shared.ITabPlayer;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.api.TabConstants;
|
||||
@@ -27,7 +29,8 @@ import me.neznamy.tab.shared.features.sorting.types.SortingType;
|
||||
*/
|
||||
public class Sorting extends TabFeature {
|
||||
|
||||
private final NameTag nameTags;
|
||||
private NameTag nameTags;
|
||||
private LayoutManager layout;
|
||||
|
||||
//map of all registered sorting types
|
||||
private final Map<String, BiFunction<Sorting, String, SortingType>> types = new LinkedHashMap<>();
|
||||
@@ -37,16 +40,17 @@ public class Sorting extends TabFeature {
|
||||
|
||||
//active sorting types
|
||||
private final SortingType[] usedSortingTypes;
|
||||
|
||||
//team names and notes
|
||||
private final WeakHashMap<TabPlayer, String> shortTeamNames = new WeakHashMap<>();
|
||||
private final WeakHashMap<TabPlayer, String> fullTeamNames = new WeakHashMap<>();
|
||||
private final WeakHashMap<TabPlayer, String> teamNameNotes = new WeakHashMap<>();
|
||||
|
||||
/**
|
||||
* Constructs new instance, loads data from configuration and starts repeating task
|
||||
*
|
||||
* @param nameTags
|
||||
* NameTag feature
|
||||
* Constructs new instance and loads config options
|
||||
*/
|
||||
public Sorting(NameTag nameTags) {
|
||||
public Sorting() {
|
||||
super("Team name refreshing", "Refreshing team name");
|
||||
this.nameTags = nameTags;
|
||||
types.put("GROUPS", Groups::new);
|
||||
types.put("PERMISSIONS", Permissions::new);
|
||||
types.put("PLACEHOLDER", Placeholder::new);
|
||||
@@ -54,34 +58,36 @@ public class Sorting extends TabFeature {
|
||||
types.put("PLACEHOLDER_Z_TO_A", PlaceholderZtoA::new);
|
||||
types.put("PLACEHOLDER_LOW_TO_HIGH", PlaceholderLowToHigh::new);
|
||||
types.put("PLACEHOLDER_HIGH_TO_LOW", PlaceholderHighToLow::new);
|
||||
usedSortingTypes = compile(TAB.getInstance().getConfiguration().getConfig().getStringList("scoreboard-teams.sorting-types", new ArrayList<>()));
|
||||
usedSortingTypes = compile(TAB.getInstance().getConfig().getStringList("scoreboard-teams.sorting-types", new ArrayList<>()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh(TabPlayer p, boolean force) {
|
||||
if (nameTags != null && (nameTags.getForcedTeamName(p) != null || nameTags.hasTeamHandlingPaused(p))) return;
|
||||
String newName = getTeamName(p);
|
||||
if (!p.getTeamName().equals(newName)) {
|
||||
if (nameTags != null) nameTags.unregisterTeam(p);
|
||||
LayoutManager layout = (LayoutManager) TAB.getInstance().getFeatureManager().getFeature(TabConstants.Feature.LAYOUT);
|
||||
if (layout != null) layout.updateTeamName(p, newName);
|
||||
((ITabPlayer) p).setTeamName(newName);
|
||||
if (nameTags != null) nameTags.registerTeam(p);
|
||||
String previousShortName = shortTeamNames.get(p);
|
||||
constructTeamNames(p);
|
||||
if (!shortTeamNames.get(p).equals(previousShortName)) {
|
||||
if (nameTags != null && nameTags.getForcedTeamName(p) == null && !nameTags.hasTeamHandlingPaused(p)) {
|
||||
for (TabPlayer viewer : TAB.getInstance().getOnlinePlayers()) {
|
||||
viewer.sendCustomPacket(new PacketPlayOutScoreboardTeam(previousShortName), TabConstants.PacketCategory.SORTING_CHANGING_TEAM_NAME);
|
||||
}
|
||||
nameTags.registerTeam(p);
|
||||
}
|
||||
if (layout != null) layout.updateTeamName(p, fullTeamNames.get(p));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(){
|
||||
if (nameTags != null) return; //handled by NameTag feature
|
||||
public void load() {
|
||||
nameTags = (NameTag) TAB.getInstance().getTeamManager();
|
||||
layout = (LayoutManager) TAB.getInstance().getFeatureManager().getFeature(TabConstants.Feature.LAYOUT);
|
||||
for (TabPlayer all : TAB.getInstance().getOnlinePlayers()) {
|
||||
((ITabPlayer) all).setTeamName(getTeamName(all));
|
||||
constructTeamNames(all);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onJoin(TabPlayer connectedPlayer) {
|
||||
if (nameTags != null) return; //handled by NameTag feature
|
||||
((ITabPlayer) connectedPlayer).setTeamName(getTeamName(connectedPlayer));
|
||||
constructTeamNames(connectedPlayer);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -89,7 +95,7 @@ public class Sorting extends TabFeature {
|
||||
*
|
||||
* @return list of compiled sorting types
|
||||
*/
|
||||
private SortingType[] compile(List<String> options){
|
||||
private SortingType[] compile(List<String> options) {
|
||||
List<SortingType> list = new ArrayList<>();
|
||||
for (String element : options) {
|
||||
String[] arr = element.split(":");
|
||||
@@ -103,24 +109,32 @@ public class Sorting extends TabFeature {
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs team name for specified player
|
||||
* Constructs short team names, both short (up to 16 characters long)
|
||||
* and full for specified player
|
||||
*
|
||||
* @param p
|
||||
* player to build team name for
|
||||
* @return unique up to 16 character long sequence that sorts the player
|
||||
*/
|
||||
public String getTeamName(TabPlayer p) {
|
||||
((ITabPlayer) p).setTeamNameNote("");
|
||||
StringBuilder sb = new StringBuilder();
|
||||
public void constructTeamNames(TabPlayer p) {
|
||||
teamNameNotes.put(p, "");
|
||||
StringBuilder shortName = new StringBuilder();
|
||||
for (SortingType type : usedSortingTypes) {
|
||||
sb.append(type.getChars((ITabPlayer) p));
|
||||
shortName.append(type.getChars((ITabPlayer) p));
|
||||
}
|
||||
if (sb.length() > 15) {
|
||||
sb.setLength(15);
|
||||
StringBuilder fullName = new StringBuilder(shortName);
|
||||
if (TAB.getInstance().getFeatureManager().isFeatureEnabled(TabConstants.Feature.LAYOUT)) {
|
||||
//layout is enabled, start with max character to fix compatibility with plugins
|
||||
//which add empty player into a team such as LibsDisguises
|
||||
shortName.insert(0, Character.MAX_VALUE);
|
||||
}
|
||||
return checkTeamName(p, sb, 65);
|
||||
if (shortName.length() > 15) {
|
||||
shortName.setLength(15);
|
||||
}
|
||||
String finalShortName = checkTeamName(p, shortName, 65);
|
||||
shortTeamNames.put(p, finalShortName);
|
||||
fullTeamNames.put(p, fullName.append(finalShortName.charAt(finalShortName.length() - 1)).toString());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks if team name is available and proceeds to try new values until free name is found
|
||||
*
|
||||
@@ -133,12 +147,10 @@ public class Sorting extends TabFeature {
|
||||
* @return first available full team name
|
||||
*/
|
||||
private String checkTeamName(TabPlayer p, StringBuilder currentName, int id) {
|
||||
String potentialTeamName = currentName.toString();
|
||||
if (!caseSensitiveSorting) potentialTeamName = potentialTeamName.toLowerCase();
|
||||
potentialTeamName += (char)id;
|
||||
String potentialTeamName = currentName.toString() + (char)id;
|
||||
for (TabPlayer all : TAB.getInstance().getOnlinePlayers()) {
|
||||
if (all == p) continue;
|
||||
if (all.getTeamName() != null && all.getTeamName().equals(potentialTeamName)) {
|
||||
if (shortTeamNames.get(all) != null && shortTeamNames.get(all).equals(potentialTeamName)) {
|
||||
return checkTeamName(p, currentName, id+1);
|
||||
}
|
||||
}
|
||||
@@ -159,6 +171,28 @@ public class Sorting extends TabFeature {
|
||||
* @return user-friendly representation of sorting types
|
||||
*/
|
||||
public String typesToString() {
|
||||
return Arrays.stream(usedSortingTypes).map(Object::toString).collect(Collectors.joining(" then "));
|
||||
return Arrays.stream(usedSortingTypes).map(Object::toString).collect(Collectors.joining(" -> "));
|
||||
}
|
||||
|
||||
public String getShortTeamName(TabPlayer p) {
|
||||
TeamManager teams = TAB.getInstance().getTeamManager();
|
||||
if (teams != null && teams.getForcedTeamName(p) != null) return teams.getForcedTeamName(p);
|
||||
return shortTeamNames.get(p);
|
||||
}
|
||||
|
||||
public String getFullTeamName(TabPlayer p) {
|
||||
return fullTeamNames.get(p);
|
||||
}
|
||||
|
||||
public String getTeamNameNote(TabPlayer p) {
|
||||
return teamNameNotes.get(p);
|
||||
}
|
||||
|
||||
public void setTeamNameNote(TabPlayer p, String note) {
|
||||
teamNameNotes.put(p, note);
|
||||
}
|
||||
|
||||
public boolean isCaseSensitiveSorting() {
|
||||
return caseSensitiveSorting;
|
||||
}
|
||||
}
|
||||
@@ -12,31 +12,27 @@ import me.neznamy.tab.shared.features.sorting.Sorting;
|
||||
public class Groups extends SortingType {
|
||||
|
||||
//map of sorted groups in config
|
||||
private final LinkedHashMap<String, String> sortedGroups;
|
||||
private final LinkedHashMap<String, Integer> sortedGroups;
|
||||
|
||||
/**
|
||||
* Constructs new instance
|
||||
*/
|
||||
public Groups(Sorting sorting, String options) {
|
||||
super(sorting, TabConstants.Placeholder.GROUP);
|
||||
super(sorting, "GROUPS", TabConstants.Placeholder.GROUP);
|
||||
sortedGroups = convertSortingElements(options.split(","));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getChars(ITabPlayer p) {
|
||||
String group = p.getGroup();
|
||||
String chars = sortedGroups.get(group.toLowerCase());
|
||||
if (chars == null) {
|
||||
chars = String.valueOf(sortedGroups.size()+1);
|
||||
p.setTeamNameNote(p.getTeamNameNote() + "&cPlayer's primary group is not in sorting list. &r");
|
||||
String group = p.getGroup().toLowerCase();
|
||||
int position;
|
||||
if (!sortedGroups.containsKey(group.toLowerCase())) {
|
||||
position = sortedGroups.size() + 1;
|
||||
sorting.setTeamNameNote(p, sorting.getTeamNameNote(p) + "\n-> &cPrimary group (&e" + p.getGroup() + "&c) is not in sorting list. &r");
|
||||
} else {
|
||||
p.setTeamNameNote(p.getTeamNameNote() + String.format("Primary group is #%s in sorting list", Integer.parseInt(chars)) + ". &r");
|
||||
position = sortedGroups.get(group);
|
||||
sorting.setTeamNameNote(p, sorting.getTeamNameNote(p) + "\n-> Primary group (&e" + p.getGroup() + "&r) is &a#" + position + "&r in sorting list.");
|
||||
}
|
||||
return chars;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "GROUPS";
|
||||
return String.valueOf((char) (position + 47));
|
||||
}
|
||||
}
|
||||
+12
-16
@@ -10,17 +10,18 @@ import me.neznamy.tab.api.TabConstants;
|
||||
import me.neznamy.tab.shared.features.sorting.Sorting;
|
||||
|
||||
/**
|
||||
* Sorting by permission nodes tab.sort.<name>, where names are defined in sorting list
|
||||
* Sorting by permission nodes
|
||||
*/
|
||||
public class Permissions extends SortingType {
|
||||
|
||||
//map of sorted groups in config
|
||||
private final LinkedHashMap<String, String> sortedGroups;
|
||||
//map of permissions
|
||||
private final LinkedHashMap<String, Integer> sortedGroups;
|
||||
|
||||
/**
|
||||
* Constructs new instance
|
||||
*/
|
||||
public Permissions(Sorting sorting, String options) {
|
||||
super(sorting, "PERMISSIONS");
|
||||
sortedGroups = convertSortingElements(options.split(","));
|
||||
List<String> placeholders = new ArrayList<>();
|
||||
for (String permission : sortedGroups.keySet()) {
|
||||
@@ -33,26 +34,21 @@ public class Permissions extends SortingType {
|
||||
|
||||
@Override
|
||||
public String getChars(ITabPlayer p) {
|
||||
String chars = null;
|
||||
int position = 0;
|
||||
for (String permission : sortedGroups.keySet()) {
|
||||
if (p.hasPermission(permission)) {
|
||||
chars = sortedGroups.get(permission.toLowerCase());
|
||||
p.setTeamNameNote("Highest sorting permission: &e" + permission + " &a(#" + Integer.parseInt(chars) + " in list). &r");
|
||||
position = sortedGroups.get(permission.toLowerCase());
|
||||
sorting.setTeamNameNote(p, sorting.getTeamNameNote(p) + "\n-> Highest sorting permission: &e" + permission + " &a(#" + position + " in list). &r");
|
||||
if (p.hasPermission(TabConstants.Permission.TEST_PERMISSION)) {
|
||||
p.setTeamNameNote(p.getTeamNameNote() + "&cThis user appears to have all permissions. Is he OP? &r");
|
||||
sorting.setTeamNameNote(p, sorting.getTeamNameNote(p) + "&cThis user appears to have all permissions. Are they OP? &r");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (chars == null) {
|
||||
chars = String.valueOf(sortedGroups.size()+1);
|
||||
p.setTeamNameNote(p.getTeamNameNote() + "&cPlayer does not have any of the defined permissions. &r");
|
||||
if (position == 0) {
|
||||
position = sortedGroups.size()+1;
|
||||
sorting.setTeamNameNote(p, sorting.getTeamNameNote(p) + "\n-> &cPlayer does not have any of the defined permissions. &r");
|
||||
}
|
||||
return chars;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PERMISSIONS";
|
||||
return String.valueOf((char) (position + 47));
|
||||
}
|
||||
}
|
||||
+10
-14
@@ -13,7 +13,7 @@ import java.util.Locale;
|
||||
public class Placeholder extends SortingType {
|
||||
|
||||
//map Value-Number where number is used in team name based on value
|
||||
private final LinkedHashMap<String, String> sortingMap;
|
||||
private final LinkedHashMap<String, Integer> sortingMap;
|
||||
|
||||
/**
|
||||
* Constructs new instance with given parameters
|
||||
@@ -24,7 +24,7 @@ public class Placeholder extends SortingType {
|
||||
* options used by this sorting type
|
||||
*/
|
||||
public Placeholder(Sorting sorting, String options) {
|
||||
super(sorting, getPlaceholder(options));
|
||||
super(sorting, "PLACEHOLDER", getPlaceholder(options));
|
||||
String[] args = options.split(":");
|
||||
if (args.length > 1)
|
||||
sortingMap = convertSortingElements(args[args.length-1].split(","));
|
||||
@@ -50,19 +50,15 @@ public class Placeholder extends SortingType {
|
||||
@Override
|
||||
public String getChars(ITabPlayer p) {
|
||||
String output = EnumChatFormat.color(setPlaceholders(p));
|
||||
p.setTeamNameNote(p.getTeamNameNote() + sortingPlaceholder + " returned \"" + output + "\"");
|
||||
String sortingValue = sortingMap.get(output.toLowerCase(Locale.US));
|
||||
if (sortingValue == null) {
|
||||
sortingValue = String.valueOf(sortingMap.size()+1);
|
||||
p.setTeamNameNote(p.getTeamNameNote() + "&c (not in list)&r. ");
|
||||
sorting.setTeamNameNote(p, sorting.getTeamNameNote(p) + "\n-> " + sortingPlaceholder + " returned \"&e" + output + "&r\"");
|
||||
int position;
|
||||
if (!sortingMap.containsKey(output.toLowerCase(Locale.US))) {
|
||||
position = sortingMap.size()+1;
|
||||
sorting.setTeamNameNote(p, sorting.getTeamNameNote(p) + "&c (not in list)&r. ");
|
||||
} else {
|
||||
p.setTeamNameNote(p.getTeamNameNote() + "&r (#" + Integer.parseInt(sortingValue) + " in list). &r");
|
||||
position = sortingMap.get(output.toLowerCase(Locale.US));
|
||||
sorting.setTeamNameNote(p, sorting.getTeamNameNote(p) + "&r &a(#" + position + " in list). &r");
|
||||
}
|
||||
return sortingValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PLACEHOLDER";
|
||||
return String.valueOf((char) (position + 47));
|
||||
}
|
||||
}
|
||||
+3
-8
@@ -15,18 +15,13 @@ public class PlaceholderAtoZ extends SortingType {
|
||||
* placeholder to sort by
|
||||
*/
|
||||
public PlaceholderAtoZ(Sorting sorting, String sortingPlaceholder) {
|
||||
super(sorting, sortingPlaceholder);
|
||||
super(sorting, "PLACEHOLDER_A_TO_Z", sortingPlaceholder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getChars(ITabPlayer p) {
|
||||
String output = setPlaceholders(p);
|
||||
p.setTeamNameNote(p.getTeamNameNote() + sortingPlaceholder + " returned \"" + output + "\". &r");
|
||||
return output;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PLACEHOLDER_A_TO_Z";
|
||||
sorting.setTeamNameNote(p, sorting.getTeamNameNote(p) + "\n-> " + sortingPlaceholder + " returned \"&e" + output + "&r\". &r");
|
||||
return sorting.isCaseSensitiveSorting() ? output : output.toLowerCase();
|
||||
}
|
||||
}
|
||||
+2
-7
@@ -16,20 +16,15 @@ public class PlaceholderHighToLow extends SortingType {
|
||||
* placeholder to sort by
|
||||
*/
|
||||
public PlaceholderHighToLow(Sorting sorting, String sortingPlaceholder) {
|
||||
super(sorting, sortingPlaceholder);
|
||||
super(sorting, "PLACEHOLDER_HIGH_TO_LOW", sortingPlaceholder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getChars(ITabPlayer p) {
|
||||
String output = setPlaceholders(p);
|
||||
p.setTeamNameNote(p.getTeamNameNote() + sortingPlaceholder + " returned \"" + output + "\". &r");
|
||||
sorting.setTeamNameNote(p, sorting.getTeamNameNote(p) + "\n-> " + sortingPlaceholder + " returned \"&e" + output + "&r\". &r");
|
||||
double doubleValue = TAB.getInstance().getErrorManager().parseDouble(output, 0);
|
||||
String string = String.valueOf(DEFAULT_NUMBER - doubleValue);
|
||||
return string.length() > 10 ? string.substring(0, 10) : string;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PLACEHOLDER_HIGH_TO_LOW";
|
||||
}
|
||||
}
|
||||
+2
-7
@@ -16,20 +16,15 @@ public class PlaceholderLowToHigh extends SortingType {
|
||||
* placeholder to sort by
|
||||
*/
|
||||
public PlaceholderLowToHigh(Sorting sorting, String sortingPlaceholder) {
|
||||
super(sorting, sortingPlaceholder);
|
||||
super(sorting, "PLACEHOLDER_LOW_TO_HIGH", sortingPlaceholder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getChars(ITabPlayer p) {
|
||||
String output = setPlaceholders(p);
|
||||
p.setTeamNameNote(p.getTeamNameNote() + sortingPlaceholder + " returned \"" + output + "\". &r");
|
||||
sorting.setTeamNameNote(p, sorting.getTeamNameNote(p) + "\n-> " + sortingPlaceholder + " returned \"&e" + output + "&r\". &r");
|
||||
double doubleValue = TAB.getInstance().getErrorManager().parseDouble(output, 0);
|
||||
String string = String.valueOf(DEFAULT_NUMBER + doubleValue);
|
||||
return string.length() > 10 ? string.substring(0, 10) : string;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PLACEHOLDER_LOW_TO_HIGH";
|
||||
}
|
||||
}
|
||||
+4
-8
@@ -15,13 +15,13 @@ public class PlaceholderZtoA extends SortingType {
|
||||
* placeholder to sort by
|
||||
*/
|
||||
public PlaceholderZtoA(Sorting sorting, String sortingPlaceholder) {
|
||||
super(sorting, sortingPlaceholder);
|
||||
super(sorting, "PLACEHOLDER_Z_TO_A", sortingPlaceholder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getChars(ITabPlayer p) {
|
||||
char[] chars = setPlaceholders(p).toCharArray();
|
||||
p.setTeamNameNote(p.getTeamNameNote() + sortingPlaceholder + " returned \"" + new String(chars) + "\". &r");
|
||||
sorting.setTeamNameNote(p, sorting.getTeamNameNote(p) + "\n-> " + sortingPlaceholder + " returned \"&e" + new String(chars) + "&r\". &r");
|
||||
for (int i=0; i<chars.length; i++) {
|
||||
char c = chars[i];
|
||||
if (c >= 65 && c <= 90) {
|
||||
@@ -31,11 +31,7 @@ public class PlaceholderZtoA extends SortingType {
|
||||
chars[i] = (char) (219 - c);
|
||||
}
|
||||
}
|
||||
return new String(chars);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PLACEHOLDER_Z_TO_A";
|
||||
String s = new String(chars);
|
||||
return sorting.isCaseSensitiveSorting() ? s : s.toLowerCase();
|
||||
}
|
||||
}
|
||||
+18
-12
@@ -11,13 +11,19 @@ import me.neznamy.tab.shared.features.sorting.Sorting;
|
||||
|
||||
public abstract class SortingType {
|
||||
|
||||
private final String displayName;
|
||||
|
||||
//number to add to / subtract from to prevent incorrect sorting with negative values
|
||||
protected final int DEFAULT_NUMBER = 5000000;
|
||||
|
||||
//placeholder to sort by, if sorting type uses it
|
||||
protected String sortingPlaceholder;
|
||||
|
||||
protected SortingType(){
|
||||
protected Sorting sorting;
|
||||
|
||||
protected SortingType(Sorting sorting, String displayName) {
|
||||
this.sorting = sorting;
|
||||
this.displayName = displayName;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -26,7 +32,9 @@ public abstract class SortingType {
|
||||
* @param sortingPlaceholder
|
||||
* placeholder to sort by
|
||||
*/
|
||||
protected SortingType(Sorting sorting, String sortingPlaceholder){
|
||||
protected SortingType(Sorting sorting, String displayName, String sortingPlaceholder){
|
||||
this.sorting = sorting;
|
||||
this.displayName = displayName;
|
||||
if (!sortingPlaceholder.startsWith("%") || !sortingPlaceholder.endsWith("%")) {
|
||||
TAB.getInstance().getErrorManager().startupWarn("\"" + sortingPlaceholder + "\" is not a valid placeholder for " + this + " sorting type");
|
||||
} else {
|
||||
@@ -47,25 +55,23 @@ public abstract class SortingType {
|
||||
return TAB.getInstance().getPlaceholderManager().getPlaceholder(sortingPlaceholder).set(sortingPlaceholder, player);
|
||||
}
|
||||
|
||||
protected LinkedHashMap<String, String> convertSortingElements(String[] elements) {
|
||||
LinkedHashMap<String, String> sortedGroups = new LinkedHashMap<>();
|
||||
protected LinkedHashMap<String, Integer> convertSortingElements(String[] elements) {
|
||||
LinkedHashMap<String, Integer> sortedGroups = new LinkedHashMap<>();
|
||||
int index = 1;
|
||||
int charCount = String.valueOf(elements.length).length()+1; //1 char for <10 values, 2 chars for <100 etc
|
||||
for (String element : elements){
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(index);
|
||||
while (sb.length() < charCount) {
|
||||
sb.insert(0, "0");
|
||||
}
|
||||
for (String element0 : element.split("\\|")) {
|
||||
while (element0.startsWith(" ")) element0 = element0.substring(1);
|
||||
while (element0.endsWith(" ")) element0 = element0.substring(0, element0.length()-1);
|
||||
sortedGroups.put(EnumChatFormat.color(element0.toLowerCase()), sb.toString());
|
||||
sortedGroups.put(EnumChatFormat.color(element0.toLowerCase()), index++);
|
||||
}
|
||||
index++;
|
||||
}
|
||||
return sortedGroups;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String toString() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns current sorting characters of this sorting type for specified player
|
||||
|
||||
@@ -37,7 +37,7 @@ public class Animation {
|
||||
|
||||
/**
|
||||
* Constructs new instance with given arguments which are fixed if necessary, such as when
|
||||
* refresh is not divisible by 50
|
||||
* refresh is not divisible by {@link me.neznamy.tab.api.TabConstants.Placeholder#MINIMUM_REFRESH_INTERVAL}
|
||||
*
|
||||
* @param name
|
||||
* animation's name
|
||||
|
||||
@@ -31,7 +31,8 @@ public class PlayerPlaceholderImpl extends TabPlaceholder implements PlayerPlace
|
||||
* @param identifier
|
||||
* placeholder's identifier, must start and end with %
|
||||
* @param refresh
|
||||
* refresh interval in milliseconds, must be divisible by 50 or equal to -1 for trigger placeholders
|
||||
* refresh interval in milliseconds, must be divisible by {@link me.neznamy.tab.api.TabConstants.Placeholder#MINIMUM_REFRESH_INTERVAL}
|
||||
* or equal to -1 to disable automatic refreshing
|
||||
* @param function
|
||||
* refresh function which returns new up-to-date output on request
|
||||
*/
|
||||
|
||||
+2
-1
@@ -27,7 +27,8 @@ public class RelationalPlaceholderImpl extends TabPlaceholder implements Relatio
|
||||
* @param identifier
|
||||
* placeholder identifier, must start with {@code %rel_} and end with {@code %}
|
||||
* @param refresh
|
||||
* refresh interval in milliseconds, must be divisible by 50 or equal to -1 for trigger placeholders
|
||||
* refresh interval in milliseconds, must be divisible by {@link me.neznamy.tab.api.TabConstants.Placeholder#MINIMUM_REFRESH_INTERVAL}
|
||||
* or equal to -1 to disable automatic refreshing
|
||||
* @param function
|
||||
* refresh function which returns new up-to-date output on request
|
||||
*/
|
||||
|
||||
@@ -25,7 +25,8 @@ public class ServerPlaceholderImpl extends TabPlaceholder implements ServerPlace
|
||||
* @param identifier
|
||||
* placeholder's identifier, must start and end with %
|
||||
* @param refresh
|
||||
* refresh interval in milliseconds, must be divisible by 50 or equal to -1 for trigger placeholders
|
||||
* refresh interval in milliseconds, must be divisible by {@link me.neznamy.tab.api.TabConstants.Placeholder#MINIMUM_REFRESH_INTERVAL}
|
||||
* or equal to -1 to disable automatic refreshing
|
||||
* @param supplier
|
||||
* supplier returning fresh output on request
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package me.neznamy.tab.shared.placeholders;
|
||||
|
||||
import me.neznamy.tab.api.TabAPI;
|
||||
import me.neznamy.tab.api.TabConstants;
|
||||
import me.neznamy.tab.api.TabPlayer;
|
||||
import me.neznamy.tab.api.placeholder.Placeholder;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
@@ -52,11 +53,14 @@ public abstract class TabPlaceholder implements Placeholder {
|
||||
* @param identifier
|
||||
* placeholder's identifier, must start and end with %
|
||||
* @param refresh
|
||||
* refresh interval in milliseconds, must be divisible by 50 or equal to -1 for trigger placeholders
|
||||
* refresh interval in milliseconds, must be divisible by {@link me.neznamy.tab.api.TabConstants.Placeholder#MINIMUM_REFRESH_INTERVAL}
|
||||
* or equal to -1 to disable automatic refreshing
|
||||
*/
|
||||
protected TabPlaceholder(String identifier, int refresh) {
|
||||
if (refresh % 50 != 0 && refresh != -1) throw new IllegalArgumentException("Refresh interval must be divisible by 50");
|
||||
if (!identifier.startsWith("%") || !identifier.endsWith("%")) throw new IllegalArgumentException("Identifier must start and end with %");
|
||||
if (refresh % TabConstants.Placeholder.MINIMUM_REFRESH_INTERVAL != 0 && refresh != -1)
|
||||
throw new IllegalArgumentException("Refresh interval must be divisible by " + TabConstants.Placeholder.MINIMUM_REFRESH_INTERVAL);
|
||||
if (!identifier.startsWith("%") || !identifier.endsWith("%"))
|
||||
throw new IllegalArgumentException("Identifier must start and end with % (attempted to use \"" + identifier + "\")");
|
||||
this.identifier = identifier;
|
||||
this.refresh = refresh;
|
||||
replacements = new PlaceholderReplacementPattern(identifier, TAB.getInstance().getConfiguration().getConfig().getConfigurationSection("placeholder-output-replacements." + identifier));
|
||||
|
||||
+4
@@ -53,6 +53,9 @@ public class UniversalPlaceholderRegistry implements PlaceholderRegistry {
|
||||
if (plugin instanceof LuckPerms) {
|
||||
manager.registerPlayerPlaceholder(TabConstants.Placeholder.LUCKPERMS_PREFIX, 1000, ((LuckPerms)plugin)::getPrefix);
|
||||
manager.registerPlayerPlaceholder(TabConstants.Placeholder.LUCKPERMS_SUFFIX, 1000, ((LuckPerms)plugin)::getSuffix);
|
||||
} else {
|
||||
manager.registerServerPlaceholder(TabConstants.Placeholder.LUCKPERMS_PREFIX, -1, () -> "");
|
||||
manager.registerServerPlaceholder(TabConstants.Placeholder.LUCKPERMS_SUFFIX, -1, () -> "");
|
||||
}
|
||||
for (Object s : TAB.getInstance().getConfiguration().getAnimationFile().getValues().keySet()) {
|
||||
Animation a = new Animation(s.toString(), TAB.getInstance().getConfiguration().getAnimationFile().getStringList(s + ".texts"),
|
||||
@@ -76,6 +79,7 @@ public class UniversalPlaceholderRegistry implements PlaceholderRegistry {
|
||||
Condition c = new Condition(!"OR".equals(type), condition.getKey(), list, yes, no);
|
||||
manager.registerPlayerPlaceholder(TabConstants.Placeholder.condition(c.getName()), c.getRefresh(), c::getText);
|
||||
}
|
||||
Condition.finishSetups();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -3,8 +3,6 @@ package me.neznamy.tab.shared.placeholders.conditions;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import me.neznamy.tab.api.TabPlayer;
|
||||
import me.neznamy.tab.api.placeholder.Placeholder;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
@@ -58,10 +56,15 @@ public class Condition {
|
||||
*/
|
||||
private int refresh = -1;
|
||||
|
||||
/** List of all placeholders used inside this condition */
|
||||
private final List<String> placeholdersInConditions = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Constructs new instance with given parameters and registers
|
||||
* this condition to list as well as the placeholder.
|
||||
*
|
||||
* @param type
|
||||
* type of condition, {@code true} for AND type and {@code false} for OR type
|
||||
* @param name
|
||||
* name of condition
|
||||
* @param conditions
|
||||
@@ -90,9 +93,7 @@ public class Condition {
|
||||
}
|
||||
}
|
||||
subConditions = list.toArray(new SimpleCondition[0]);
|
||||
//adding placeholders in conditions to the map, so they are actually refreshed if not used anywhere else
|
||||
PlaceholderManagerImpl pm = TAB.getInstance().getPlaceholderManager();
|
||||
List<String> placeholdersInConditions = new ArrayList<>();
|
||||
for (String subCondition : conditions) {
|
||||
if (subCondition.startsWith("permission:")) {
|
||||
if (refresh > 1000 || refresh == -1) refresh = 1000; //permission refreshing will be done every second
|
||||
@@ -102,6 +103,13 @@ public class Condition {
|
||||
}
|
||||
placeholdersInConditions.addAll(pm.detectPlaceholders(yes));
|
||||
placeholdersInConditions.addAll(pm.detectPlaceholders(no));
|
||||
registeredConditions.put(name, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures refresh interval and registers nested placeholders
|
||||
*/
|
||||
public void finishSetup() {
|
||||
for (String placeholder : placeholdersInConditions) {
|
||||
TAB.getInstance().getPlaceholderManager().getPlaceholder(placeholder).addParent(TabConstants.Placeholder.condition(name));
|
||||
Placeholder pl = TAB.getInstance().getPlaceholderManager().getPlaceholder(placeholder);
|
||||
@@ -109,8 +117,7 @@ public class Condition {
|
||||
refresh = pl.getRefresh();
|
||||
}
|
||||
}
|
||||
pm.addUsedPlaceholders(placeholdersInConditions);
|
||||
registeredConditions.put(name, this);
|
||||
TAB.getInstance().getPlaceholderManager().addUsedPlaceholders(placeholdersInConditions);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -177,7 +184,17 @@ public class Condition {
|
||||
if (registeredConditions.containsKey(string)) {
|
||||
return registeredConditions.get(string);
|
||||
} else {
|
||||
Condition c = new Condition(true, "AnonymousCondition[" + string + "]", Lists.newArrayList(string.split(";")), "true", "false");
|
||||
boolean type;
|
||||
List<String> conditions;
|
||||
if (string.contains(";")) {
|
||||
type = true;
|
||||
conditions = Arrays.asList(string.split(";"));
|
||||
} else {
|
||||
type = false;
|
||||
conditions = Arrays.asList(string.split("\\|"));
|
||||
}
|
||||
Condition c = new Condition(type, "AnonymousCondition[" + string + "]", conditions, "true", "false");
|
||||
c.finishSetup();
|
||||
TAB.getInstance().getPlaceholderManager().registerPlayerPlaceholder(TabConstants.Placeholder.condition(c.getName()), c.getRefresh(), c::getText);
|
||||
return c;
|
||||
}
|
||||
@@ -198,4 +215,13 @@ public class Condition {
|
||||
public static Map<String, Function<String, SimpleCondition>> getConditionTypes() {
|
||||
return conditionTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks all placeholders used in the condition as used and registers them.
|
||||
* Using a separate method to avoid premature registration of nested conditional placeholders
|
||||
* before they are registered properly.
|
||||
*/
|
||||
public static void finishSetups() {
|
||||
registeredConditions.values().forEach(Condition::finishSetup);
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,7 @@ import me.neznamy.tab.shared.features.nametags.NameTag;
|
||||
import me.neznamy.tab.shared.features.nametags.unlimited.ProxyNameTagX;
|
||||
import me.neznamy.tab.shared.features.redis.RedisPlayer;
|
||||
import me.neznamy.tab.shared.features.redis.RedisSupport;
|
||||
import me.neznamy.tab.shared.features.sorting.Sorting;
|
||||
import me.neznamy.tab.shared.permission.LuckPerms;
|
||||
import me.neznamy.tab.shared.permission.PermissionPlugin;
|
||||
import me.neznamy.tab.shared.permission.VaultBridge;
|
||||
@@ -106,6 +107,7 @@ public abstract class ProxyPlatform extends Platform {
|
||||
TAB tab = TAB.getInstance();
|
||||
new UniversalPlaceholderRegistry().registerPlaceholders(tab.getPlaceholderManager());
|
||||
if (tab.getConfiguration().getConfig().getBoolean("scoreboard-teams.enabled", true)) {
|
||||
tab.getFeatureManager().registerFeature(TabConstants.Feature.SORTING, new Sorting());
|
||||
if (tab.getConfiguration().getConfig().getBoolean("scoreboard-teams.unlimited-nametag-mode.enabled", false)) {
|
||||
tab.getFeatureManager().registerFeature(TabConstants.Feature.UNLIMITED_NAME_TAGS, new ProxyNameTagX());
|
||||
} else {
|
||||
@@ -123,9 +125,4 @@ public abstract class ProxyPlatform extends Platform {
|
||||
tab.getPlaceholderManager().setTabExpansion(new ProxyTabExpansion());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getConfigName() {
|
||||
return "proxyconfig.yml";
|
||||
}
|
||||
}
|
||||
@@ -4,10 +4,24 @@ import me.neznamy.tab.api.TabPlayer;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.shared.features.TabExpansion;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
public class ProxyTabExpansion implements TabExpansion {
|
||||
|
||||
/** Map holding all values for all players for resending on server switch */
|
||||
private final Map<TabPlayer, Map<String, String>> values = new WeakHashMap<>();
|
||||
|
||||
@Override
|
||||
public void setValue(TabPlayer player, String key, String value) {
|
||||
values.computeIfAbsent(player, p -> new HashMap<>()).put(key, value);
|
||||
((ProxyPlatform)TAB.getInstance().getPlatform()).getPluginMessageHandler().sendMessage(player, "Expansion", key, value);
|
||||
}
|
||||
|
||||
public void resendAllValues(TabPlayer player) {
|
||||
for (Map.Entry<String, String> entry : values.computeIfAbsent(player, p -> new HashMap<>()).entrySet()) {
|
||||
((ProxyPlatform)TAB.getInstance().getPlatform()).getPluginMessageHandler().sendMessage(player, "Expansion", entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -60,10 +60,11 @@ public abstract class ProxyTabPlayer extends ITabPlayer {
|
||||
* joined, containing all plugin configuration data.
|
||||
*/
|
||||
public void sendJoinPluginMessage() {
|
||||
ProxyTabExpansion expansion = (ProxyTabExpansion) TAB.getInstance().getPlaceholderManager().getTabExpansion();
|
||||
List<Object> args = Lists.newArrayList("PlayerJoin", getVersion().getNetworkId(),
|
||||
TAB.getInstance().getGroupManager().getPlugin() instanceof VaultBridge && !TAB.getInstance().getGroupManager().isGroupsByPermissions(),
|
||||
TAB.getInstance().getFeatureManager().isFeatureEnabled(TabConstants.Feature.PET_FIX),
|
||||
TAB.getInstance().getPlaceholderManager().getTabExpansion() != null);
|
||||
expansion != null);
|
||||
ProxyPlatform platform = (ProxyPlatform) TAB.getInstance().getPlatform();
|
||||
Map<String, Integer> placeholders = platform.getBridgePlaceholders();
|
||||
args.add(placeholders.size());
|
||||
@@ -90,6 +91,9 @@ public abstract class ProxyTabPlayer extends ITabPlayer {
|
||||
}
|
||||
}
|
||||
((ProxyPlatform)TAB.getInstance().getPlatform()).getPluginMessageHandler().sendMessage(this, args.toArray());
|
||||
if (expansion != null) {
|
||||
expansion.resendAllValues(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -107,11 +107,6 @@ time:
|
||||
- '&7> Date &b%date% &7<'
|
||||
- '&7>> Date &b%date% &7<<'
|
||||
- '&7>>> Date &b%date% &7<<<'
|
||||
ping-tps:
|
||||
change-interval: 5000
|
||||
texts:
|
||||
- '&aPing: &2&n%ping%&r &ams'
|
||||
- '&bServer TPS: &8%tps%'
|
||||
barcolors:
|
||||
change-interval: 1000
|
||||
texts:
|
||||
|
||||
+62
-34
@@ -19,16 +19,20 @@ header-footer:
|
||||
- "&7&l Used memory: %memory-used% MB / %memory-max% MB"
|
||||
- ""
|
||||
- "&7Visit our webpage %animation:web%"
|
||||
per-world:
|
||||
world1:
|
||||
header:
|
||||
- "an example of world with custom"
|
||||
footer:
|
||||
- "header/footer and prefix/suffix"
|
||||
world2;world3:
|
||||
header:
|
||||
- "This is a shared header for"
|
||||
- "world2 and world3"
|
||||
per-server:
|
||||
server1:
|
||||
header:
|
||||
- "an example of server with custom"
|
||||
footer:
|
||||
- "header/footer and prefix/suffix"
|
||||
server2;server3:
|
||||
header:
|
||||
- "This is a shared header for"
|
||||
- "server2 and server3"
|
||||
- "an example of server with custom header"
|
||||
|
||||
# https://github.com/NEZNAMY/TAB/wiki/Feature-guide:-Tablist-name-formatting
|
||||
tablist-name-formatting:
|
||||
@@ -83,25 +87,6 @@ yellow-number-in-tablist:
|
||||
disable-in-servers:
|
||||
- disabledserver
|
||||
|
||||
# https://github.com/NEZNAMY/TAB/wiki/Feature-guide:-Global-playerlist
|
||||
global-playerlist:
|
||||
enabled: false
|
||||
display-others-as-spectators: false
|
||||
display-vanished-players-as-spectators: true
|
||||
isolate-unlisted-servers: false
|
||||
update-latency: false
|
||||
fill-profile-key: false
|
||||
spy-servers:
|
||||
- spyserver1
|
||||
- spyserver2
|
||||
server-groups:
|
||||
lobbies:
|
||||
- lobby1
|
||||
- lobby2
|
||||
group2:
|
||||
- server1
|
||||
- server2
|
||||
|
||||
# https://github.com/NEZNAMY/TAB/wiki/Feature-guide:-Belowname
|
||||
belowname-objective:
|
||||
enabled: false
|
||||
@@ -199,16 +184,13 @@ placeholder-output-replacements:
|
||||
"%essentials_vanished%":
|
||||
"yes": "&7| Vanished"
|
||||
"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%": ""
|
||||
"%vault-prefix%":
|
||||
"%vault-prefix%" : ""
|
||||
"%vault-suffix%":
|
||||
"%vault-suffix%" : ""
|
||||
true: " &o[AFK]&r"
|
||||
false: ""
|
||||
"%afk%": "" # if attempting to use bukkit-only placeholder on bungeecord
|
||||
"%essentials_nickname%":
|
||||
"%essentials_nickname%": "%player%" # placeholder did not parse correctly, show real name instead
|
||||
|
||||
# https://github.com/NEZNAMY/TAB/wiki/Feature-guide:-Conditional-placeholders
|
||||
conditions:
|
||||
@@ -223,6 +205,7 @@ placeholderapi-refresh-intervals:
|
||||
server:
|
||||
"%server_uptime%": 1000
|
||||
"%server_tps_1_colored%": 1000
|
||||
"%server_unique_joins%": 5000
|
||||
player:
|
||||
"%player_health%": 200
|
||||
"%player_ping%": 1000
|
||||
@@ -253,4 +236,49 @@ mysql:
|
||||
username: user
|
||||
password: password
|
||||
|
||||
########################################################################
|
||||
# BUKKIT ONLY - THE FOLLOWING SECTION IS ONLY FOR BACKEND INSTALLATION #
|
||||
########################################################################
|
||||
|
||||
# https://github.com/NEZNAMY/TAB/wiki/Feature-guide:-Per-world-playerlist
|
||||
per-world-playerlist:
|
||||
enabled: false
|
||||
# players with tab.staff will always see all players
|
||||
allow-bypass-permission: false
|
||||
# players in these worlds will always see all players
|
||||
ignore-effect-in-worlds:
|
||||
- ignoredworld
|
||||
- build
|
||||
shared-playerlist-world-groups:
|
||||
lobby:
|
||||
- lobby1
|
||||
- lobby2
|
||||
minigames:
|
||||
- paintball
|
||||
- bedwars
|
||||
|
||||
#####################################################################
|
||||
# PROXY ONLY - THE FOLLOWING SECTION IS ONLY FOR PROXY INSTALLATION #
|
||||
#####################################################################
|
||||
|
||||
# https://github.com/NEZNAMY/TAB/wiki/Feature-guide:-Global-playerlist
|
||||
global-playerlist:
|
||||
enabled: false
|
||||
display-others-as-spectators: false
|
||||
display-vanished-players-as-spectators: true
|
||||
isolate-unlisted-servers: false
|
||||
update-latency: false
|
||||
fill-profile-key: false
|
||||
spy-servers:
|
||||
- spyserver1
|
||||
- spyserver2
|
||||
server-groups:
|
||||
lobbies:
|
||||
- lobby1
|
||||
- lobby2
|
||||
group2:
|
||||
- server1
|
||||
- server2
|
||||
|
||||
# Take permissions and groups from backend server instead of proxy
|
||||
use-bukkit-permissions-manager: false
|
||||
@@ -1,9 +1,6 @@
|
||||
Owner:
|
||||
tabprefix: "&0&l[&a&lOwner&0&l] &a"
|
||||
tagprefix: "&2&lOwner &a"
|
||||
Admin:
|
||||
tabprefix: "&0&l[&4&lAdmin&0&l] &1"
|
||||
tagprefix: "&4&lAdmin &a"
|
||||
#Owner:
|
||||
# tabprefix: "&0&l[&a&lOwner&0&l] &a"
|
||||
# tagprefix: "&2&lOwner &a"
|
||||
Player:
|
||||
tabprefix: "&0&l[&7&lPlayer&0&l] &3"
|
||||
tagprefix: "&2&lPlayer &3"
|
||||
@@ -15,12 +12,12 @@ example_group:
|
||||
|
||||
# default settings for all groups, all groups will take properties from this section unless player's primary group overrides a specific setting
|
||||
_DEFAULT_:
|
||||
tabprefix: "%vault-prefix%"
|
||||
tagprefix: "%vault-prefix%"
|
||||
tabprefix: "%luckperms-prefix%"
|
||||
tagprefix: "%luckperms-prefix%"
|
||||
customtabname: "%essentials_nickname%"
|
||||
customtagname: "%essentials_nickname%" # don't forget to enable unlimited nametag mode to make this one work
|
||||
tabsuffix: "%vault-suffix%%afk%"
|
||||
tagsuffix: "%vault-suffix%%afk%"
|
||||
tabsuffix: "%luckperms-suffix%%afk%"
|
||||
tagsuffix: "%luckperms-suffix%%afk%"
|
||||
|
||||
per-world:
|
||||
world1:
|
||||
|
||||
@@ -14,12 +14,10 @@ import me.neznamy.tab.api.protocol.PacketPlayOutPlayerInfo.PlayerInfoData;
|
||||
import me.neznamy.tab.api.util.Preconditions;
|
||||
import me.neznamy.tab.shared.TAB;
|
||||
import me.neznamy.tab.shared.proxy.ProxyTabPlayer;
|
||||
import net.kyori.adventure.audience.MessageType;
|
||||
import net.kyori.adventure.bossbar.BossBar;
|
||||
import net.kyori.adventure.bossbar.BossBar.Color;
|
||||
import net.kyori.adventure.bossbar.BossBar.Flag;
|
||||
import net.kyori.adventure.bossbar.BossBar.Overlay;
|
||||
import net.kyori.adventure.identity.Identity;
|
||||
import net.kyori.adventure.text.Component;
|
||||
|
||||
import java.util.*;
|
||||
@@ -83,10 +81,11 @@ public class VelocityTabPlayer extends ProxyTabPlayer {
|
||||
* Packet request to handle
|
||||
*/
|
||||
private void handle(PacketPlayOutChat packet) {
|
||||
Component message = Main.getInstance().convertComponent(packet.getMessage(), getVersion());
|
||||
if (packet.getType() == ChatMessageType.GAME_INFO) {
|
||||
getPlayer().sendActionBar(Main.getInstance().convertComponent(packet.getMessage(), getVersion()));
|
||||
getPlayer().sendActionBar(message);
|
||||
} else {
|
||||
getPlayer().sendMessage(Identity.nil(), Main.getInstance().convertComponent(packet.getMessage(), getVersion()), MessageType.valueOf(packet.getType().name()));
|
||||
getPlayer().sendMessage(message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,32 +108,38 @@ public class VelocityTabPlayer extends ProxyTabPlayer {
|
||||
*/
|
||||
private void handle(PacketPlayOutPlayerInfo packet) {
|
||||
for (PlayerInfoData data : packet.getEntries()) {
|
||||
switch (packet.getAction()) {
|
||||
case ADD_PLAYER:
|
||||
if (getPlayer().getTabList().containsEntry(data.getUniqueId())) continue;
|
||||
getPlayer().getTabList().addEntry(TabListEntry.builder()
|
||||
.tabList(getPlayer().getTabList())
|
||||
.displayName(Main.getInstance().convertComponent(data.getDisplayName(), getVersion()))
|
||||
.gameMode(data.getGameMode().ordinal()-1)
|
||||
.profile(new GameProfile(data.getUniqueId(), data.getName(), data.getSkin() == null ? new ArrayList<>() :
|
||||
Collections.singletonList(new Property("textures", data.getSkin().getValue(), data.getSkin().getSignature()))))
|
||||
.latency(data.getLatency())
|
||||
.build());
|
||||
break;
|
||||
case REMOVE_PLAYER:
|
||||
getPlayer().getTabList().removeEntry(data.getUniqueId());
|
||||
break;
|
||||
case UPDATE_DISPLAY_NAME:
|
||||
getEntry(data.getUniqueId()).setDisplayName(Main.getInstance().convertComponent(data.getDisplayName(), getVersion()));
|
||||
break;
|
||||
case UPDATE_LATENCY:
|
||||
getEntry(data.getUniqueId()).setLatency(data.getLatency());
|
||||
break;
|
||||
case UPDATE_GAME_MODE:
|
||||
getEntry(data.getUniqueId()).setGameMode(data.getGameMode().ordinal()-1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
for (PacketPlayOutPlayerInfo.EnumPlayerInfoAction action : packet.getActions()) {
|
||||
switch (action) {
|
||||
case ADD_PLAYER:
|
||||
if (getPlayer().getTabList().containsEntry(data.getUniqueId())) continue;
|
||||
getPlayer().getTabList().addEntry(TabListEntry.builder()
|
||||
.tabList(getPlayer().getTabList())
|
||||
.displayName(Main.getInstance().convertComponent(data.getDisplayName(), getVersion()))
|
||||
.gameMode(data.getGameMode().ordinal()-1)
|
||||
.profile(new GameProfile(data.getUniqueId(), data.getName(), data.getSkin() == null ? new ArrayList<>() :
|
||||
Collections.singletonList(new Property("textures", data.getSkin().getValue(), data.getSkin().getSignature()))))
|
||||
.latency(data.getLatency())
|
||||
.build());
|
||||
break;
|
||||
case REMOVE_PLAYER:
|
||||
getPlayer().getTabList().removeEntry(data.getUniqueId());
|
||||
break;
|
||||
case UPDATE_DISPLAY_NAME:
|
||||
getEntry(data.getUniqueId()).setDisplayName(Main.getInstance().convertComponent(data.getDisplayName(), getVersion()));
|
||||
break;
|
||||
case UPDATE_LATENCY:
|
||||
getEntry(data.getUniqueId()).setLatency(data.getLatency());
|
||||
break;
|
||||
case UPDATE_GAME_MODE:
|
||||
getEntry(data.getUniqueId()).setGameMode(data.getGameMode().ordinal()-1);
|
||||
break;
|
||||
case UPDATE_LISTED:
|
||||
getEntry(data.getUniqueId()).setListed(data.isListed());
|
||||
break;
|
||||
case INITIALIZE_CHAT: // not supported yet //TODO
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -323,17 +328,17 @@ public class VelocityTabPlayer extends ProxyTabPlayer {
|
||||
|
||||
@Override
|
||||
public int getGamemode() {
|
||||
return 0; //shrug
|
||||
return getEntry(getTablistUUID()).getGameMode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getProfilePublicKey() {
|
||||
try {
|
||||
return getPlayer().getIdentifiedKey();
|
||||
} catch (NoSuchMethodError e) {
|
||||
//3.1.1 or lower
|
||||
return null;
|
||||
}
|
||||
return getPlayer().getIdentifiedKey();
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID getChatSessionId() {
|
||||
return null; // not supported on velocity
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in new issue
Block a user