Compare commits

..
6 Commits
22 changed files with 113 additions and 27 deletions

No files matched your search

@@ -94,4 +94,6 @@ public interface FeatureManager {
void markObjective();
void markDisplayObjective();
TabFeature[] getValues();
}
@@ -310,4 +310,12 @@ public interface TabPlayer {
* @return player's game profile name as seen by other players
*/
String getNickname();
/**
* Returns player's chat message signing key. Returned object is a direct
* object from the server, which is different per platform.
*
* @return Player's direct chat message signing key
*/
Object getProfilePublicKey();
}
@@ -15,7 +15,7 @@ public class MiniMessageFormat implements RGBFormatter {
String format = text.replace(EnumChatFormat.RESET.getFormat(), ""); //remove &r from header/footer newline inserts
try {
return LegacyComponentSerializer.legacySection().serialize(MiniMessage.miniMessage().deserialize(format));
} catch (Exception ignored) {
} catch (Throwable ignored) {
return text;
}
}
@@ -97,6 +97,9 @@ public class PacketPlayOutPlayerInfo implements TabPacket {
/** Player's skin, null for empty skin */
private Skin skin;
/** Player's chat signing key */
private Object profilePublicKey;
/**
* Constructs new instance with given parameters. Suitable for
* {@link EnumPlayerInfoAction}.ADD_PLAYER action
@@ -113,8 +116,10 @@ public class PacketPlayOutPlayerInfo implements TabPacket {
* Player's GameMode
* @param displayName
* Player's display name
* @param profilePublicKey
* Player's chat signing key
*/
public PlayerInfoData(String name, UUID uniqueId, Skin skin, int latency, EnumGamemode gameMode, IChatBaseComponent displayName) {
public PlayerInfoData(String name, UUID uniqueId, Skin skin, int latency, EnumGamemode gameMode, IChatBaseComponent displayName, Object profilePublicKey) {
Preconditions.checkNotNull(uniqueId, "uuid");
this.name = name;
this.uniqueId = uniqueId;
@@ -122,6 +127,7 @@ public class PacketPlayOutPlayerInfo implements TabPacket {
this.latency = latency;
this.gameMode = gameMode;
this.displayName = displayName;
this.profilePublicKey = profilePublicKey;
}
/**
@@ -182,8 +188,8 @@ public class PacketPlayOutPlayerInfo implements TabPacket {
@Override
public String toString() {
return String.format("PlayerInfoData{latency=%s,gameMode=%s,displayName=%s,name=%s,uniqueId=%s,skin=%s}",
latency, gameMode, displayName, name, uniqueId, skin);
return String.format("PlayerInfoData{latency=%s,gameMode=%s,displayName=%s,name=%s,uniqueId=%s,skin=%s,profilePublicKey=%s}",
latency, gameMode, displayName, name, uniqueId, skin, profilePublicKey);
}
/**
@@ -299,6 +305,25 @@ public class PacketPlayOutPlayerInfo implements TabPacket {
public void setSkin(Skin skin) {
this.skin = skin;
}
/**
* Returns {@link #profilePublicKey}
*
* @return profilePublicKey
*/
public Object getProfilePublicKey() {
return profilePublicKey;
}
/**
* Sets {@link #profilePublicKey} to specified value
*
* @param profilePublicKey
* profilePublicKey to use
*/
public void setProfilePublicKey(Object profilePublicKey) {
this.profilePublicKey = profilePublicKey;
}
}
/**
@@ -102,7 +102,7 @@ public class BukkitPacketBuilder extends PacketBuilder {
parameters.add(data.getLatency());
parameters.add(data.getGameMode() == null ? null : nms.EnumGamemode_values[nms.EnumGamemode_values.length-EnumGamemode.VALUES.length+data.getGameMode().ordinal()]); //not_set was removed in 1.17
parameters.add(data.getDisplayName() == null ? null : toNMSComponent(data.getDisplayName(), clientVersion));
if (nms.getMinorVersion() >= 19) parameters.add(null);
if (nms.getMinorVersion() >= 19) parameters.add(data.getProfilePublicKey());
items.add(nms.newPlayerInfoData.newInstance(parameters.toArray()));
}
nms.setField(nmsPacket, nms.PacketPlayOutPlayerInfo_PLAYERS, items);
@@ -364,8 +364,9 @@ public class BukkitPacketBuilder extends PacketBuilder {
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,
(int) nms.PlayerInfoData_getLatency.invoke(nmsData), gameMode, listName));
(int) nms.PlayerInfoData_getLatency.invoke(nmsData), gameMode, listName, profilePublicKey));
}
return new PacketPlayOutPlayerInfo(action, listData);
}
@@ -289,6 +289,19 @@ public class BukkitTabPlayer extends ITabPlayer {
return getPlayer().getGameMode().getValue();
}
@Override
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);
} catch (ReflectiveOperationException e) {
TAB.getInstance().getErrorManager().printError("Failed to get profile key of " + getName(), e);
return null;
}
}
@Override
public Channel getChannel() {
try {
@@ -75,6 +75,8 @@ public class BukkitModernNMSStorage extends ModernNMSStorage {
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");
}
// Player Info
@@ -75,6 +75,8 @@ public class MojangModernNMSStorage extends ModernNMSStorage {
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");
}
// Player Info
@@ -39,6 +39,7 @@ public abstract class NMSStorage {
public Field PLAYER_CONNECTION;
public Field NETWORK_MANAGER;
public Field CHANNEL;
public Field EntityHuman_ProfilePublicKey;
public Method getHandle;
public Method sendPacket;
public Method getProfile;
@@ -129,6 +130,8 @@ public abstract class NMSStorage {
protected Class<?> EnumPlayerInfoAction;
protected Class<?> PlayerInfoData;
protected Class<?> EnumGamemode;
protected Class<?> ProfilePublicKey;
protected Class<?> ProfilePublicKey$a;
public Constructor<?> newPacketPlayOutPlayerInfo;
public Constructor<?> newPlayerInfoData;
public Field PacketPlayOutPlayerInfo_ACTION;
@@ -137,6 +140,8 @@ public abstract class NMSStorage {
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;
@@ -282,6 +287,11 @@ public abstract class NMSStorage {
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);
}
}
protected void spawnEntityLiving() throws ReflectiveOperationException {
@@ -10,6 +10,7 @@ import me.neznamy.tab.api.protocol.*;
import me.neznamy.tab.api.protocol.PacketPlayOutPlayerInfo.EnumGamemode;
import me.neznamy.tab.api.protocol.PacketPlayOutPlayerInfo.EnumPlayerInfoAction;
import me.neznamy.tab.api.protocol.PacketPlayOutPlayerInfo.PlayerInfoData;
import net.md_5.bungee.protocol.PlayerPublicKey;
import net.md_5.bungee.protocol.Property;
import net.md_5.bungee.protocol.packet.*;
import net.md_5.bungee.protocol.packet.PlayerListItem.Item;
@@ -64,6 +65,7 @@ public class BungeePacketBuilder extends PacketBuilder {
}
item.setUsername(data.getName());
item.setUuid(data.getUniqueId());
item.setPublicKey((PlayerPublicKey) data.getProfilePublicKey());
items.add(item);
}
PlayerListItem bungeePacket = new PlayerListItem();
@@ -108,7 +110,7 @@ public class BungeePacketBuilder extends PacketBuilder {
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())));
listData.add(new PlayerInfoData(i.getUsername(), i.getUuid(), skin, i.getPing(), EnumGamemode.VALUES[i.getGamemode()+1], IChatBaseComponent.deserialize(i.getDisplayName()), i.getPublicKey()));
}
return new PacketPlayOutPlayerInfo(EnumPlayerInfoAction.valueOf(item.getAction().toString().replace("GAMEMODE", "GAME_MODE")), listData);
}
@@ -8,11 +8,11 @@ import me.neznamy.tab.api.protocol.Skin;
import me.neznamy.tab.api.util.Preconditions;
import me.neznamy.tab.shared.TAB;
import me.neznamy.tab.shared.proxy.ProxyTabPlayer;
import net.md_5.bungee.api.ProxyConfig;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.protocol.DefinedPacket;
import net.md_5.bungee.protocol.Protocol;
import net.md_5.bungee.protocol.packet.LoginRequest;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
@@ -25,6 +25,7 @@ public class BungeeTabPlayer extends ProxyTabPlayer {
/** Inaccessible bungee internals */
private static Method InitialHandler_getLoginProfile;
private static Method InitialHandler_getLoginRequest;
private static Method ChannelWrapper_getHandle;
private static Method LoginResult_Property_getValue;
private static Method LoginResult_Property_getSignature;
@@ -34,13 +35,11 @@ public class BungeeTabPlayer extends ProxyTabPlayer {
private static Object directionData;
private static Method getId;
/** Rewriting offline tablist uuids coming from backend servers to online uuids on online servers */
private static boolean tablistRewriteEnabled = true;
static {
try {
Class<?> initialHandler = Class.forName("net.md_5.bungee.connection.InitialHandler");
InitialHandler_getLoginProfile = initialHandler.getMethod("getLoginProfile");
InitialHandler_getLoginRequest = initialHandler.getMethod("getLoginRequest");
Class<?> channelWrapper = Class.forName("net.md_5.bungee.netty.ChannelWrapper");
ChannelWrapper_getHandle = channelWrapper.getMethod("getHandle");
Class<?> loginResult = Class.forName("net.md_5.bungee.connection.LoginResult");
@@ -60,11 +59,6 @@ public class BungeeTabPlayer extends ProxyTabPlayer {
} catch (ReflectiveOperationException e) {
TAB.getInstance().getErrorManager().criticalError("Failed to initialize bungee internal fields", e);
}
try {
tablistRewriteEnabled = !(boolean) ProxyConfig.class.getMethod("isDisableTabListRewrite").invoke(ProxyServer.getInstance().getConfig());
} catch (ReflectiveOperationException e) {
// not Waterfall, always true on BungeeCord
}
}
/**
@@ -74,7 +68,7 @@ public class BungeeTabPlayer extends ProxyTabPlayer {
* BungeeCord player
*/
public BungeeTabPlayer(ProxiedPlayer p) {
super(p, p.getUniqueId(), p.getName(), p.getServer() != null ? p.getServer().getInfo().getName() : "-", -1, tablistRewriteEnabled);
super(p, p.getUniqueId(), p.getName(), p.getServer() != null ? p.getServer().getInfo().getName() : "-", -1, true);
try {
channel = (Channel) ChannelWrapper_getHandle.invoke(wrapperField.get(getPlayer().getPendingConnection()));
} catch (IllegalAccessException | InvocationTargetException e) {
@@ -171,6 +165,16 @@ public class BungeeTabPlayer extends ProxyTabPlayer {
}
}
@Override
public Object getProfilePublicKey() {
try {
return ((LoginRequest) InitialHandler_getLoginRequest.invoke(getPlayer().getPendingConnection())).getPublicKey();
} catch (ReflectiveOperationException e) {
TAB.getInstance().getErrorManager().printError("Failed to get profile key of " + getPlayer().getName(), e);
return null;
}
}
@Override
public void sendPluginMessage(byte[] message) {
Preconditions.checkNotNull(message, "message");
+1 -1
View File
@@ -1,5 +1,5 @@
# Project properties - we put these here so they can be modified without causing a recompile of the build scripts
projectVersion=3.1.3
projectVersion=3.1.4
# Gradle properties
org.gradle.daemon=true
+1 -1
View File
@@ -22,7 +22,7 @@ event = "3.0.0"
bukkit = "1.16.5-R0.1-SNAPSHOT"
bungeecord = "1.19-R0.1-SNAPSHOT"
krypton = "0.59.2"
velocity = "3.0.1"
velocity = "3.1.2-SNAPSHOT"
# Platform extras
placeholderapi = "2.11.1"
@@ -327,4 +327,9 @@ public class FeatureManagerImpl implements FeatureManager {
public TabFeature getFeature(String name) {
return features.get(name);
}
@Override
public TabFeature[] getValues() {
return values;
}
}
@@ -415,4 +415,8 @@ public abstract class ITabPlayer implements TabPlayer {
public void setNickname(String nickname) {
this.nickname = nickname;
}
public void setChannel(Channel channel) {
this.channel = channel;
}
}
@@ -126,7 +126,7 @@ public class GlobalPlayerList extends TabFeature {
format = playerlist.getTabFormat(p, viewer);
}
return new PacketPlayOutPlayerInfo(EnumPlayerInfoAction.ADD_PLAYER, new PlayerInfoData(p.getName(), p.getTablistUUID(), p.getSkin(),
p.getPing(), vanishedAsSpectators && p.isVanished() ? EnumGamemode.SPECTATOR : EnumGamemode.CREATIVE, format));
p.getPing(), vanishedAsSpectators && p.isVanished() ? EnumGamemode.SPECTATOR : EnumGamemode.CREATIVE, format, p.getProfilePublicKey()));
}
@Override
@@ -41,10 +41,10 @@ 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())));
list.add(new PlayerInfoData("", slot.getId(), slot.getSkin(), slot.getPing(), EnumGamemode.CREATIVE, IChatBaseComponent.optimizedComponent(p.getProperty(slot.getPropertyName()).updateAndGet()), null));
}
for (int slot : emptySlots) {
list.add(new PlayerInfoData("", manager.getUUID(slot), manager.getSkinManager().getDefaultSkin(), manager.getEmptySlotPing(), EnumGamemode.CREATIVE, new IChatBaseComponent("")));
list.add(new PlayerInfoData("", manager.getUUID(slot), manager.getSkinManager().getDefaultSkin(), manager.getEmptySlotPing(), EnumGamemode.CREATIVE, new IChatBaseComponent(""), null));
}
if (p.getVersion().getMinorVersion() < 8 || p.isBedrockPlayer()) return;
p.sendCustomPacket(new PacketPlayOutPlayerInfo(EnumPlayerInfoAction.ADD_PLAYER, list), this);
@@ -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));
data = new PlayerInfoData("", id, player.getSkin(), player.getPing(), EnumGamemode.SURVIVAL, playerlist == null ? new IChatBaseComponent(player.getName()) : playerlist.getTabFormat(player, p), null);
} else {
data = new PlayerInfoData("", id, layout.getManager().getSkinManager().getDefaultSkin(), layout.getManager().getEmptySlotPing(), EnumGamemode.SURVIVAL, new IChatBaseComponent(text));
data = new PlayerInfoData("", id, layout.getManager().getSkinManager().getDefaultSkin(), layout.getManager().getEmptySlotPing(), EnumGamemode.SURVIVAL, new IChatBaseComponent(text), null);
}
return data;
}
@@ -122,7 +122,7 @@ 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)));
disabledPlayerList ? null : IChatBaseComponent.optimizedComponent(tabFormat), null));
}
public PacketPlayOutPlayerInfo getUpdatePacket() {
@@ -53,7 +53,6 @@ public class PlayerPlaceholderImpl extends TabPlaceholder implements PlayerPlace
if (output == null) return false; //bridge placeholders, they are updated using updateValue method
String obj = getReplacements().findReplacement(String.valueOf(output));
String newValue = obj == null ? identifier : setPlaceholders(obj, p);
newValue = getReplacements().findReplacement(newValue);
//make invalid placeholders return identifier instead of nothing
if (identifier.equals(newValue) && !lastValues.containsKey(p)) {
@@ -44,7 +44,6 @@ public class ServerPlaceholderImpl extends TabPlaceholder implements ServerPlace
public boolean update() {
String obj = getReplacements().findReplacement(String.valueOf(request()));
String newValue = obj == null ? identifier : setPlaceholders(obj, null);
newValue = getReplacements().findReplacement(newValue);
//make invalid placeholders return identifier instead of nothing
if (identifier.equals(newValue) && lastValue == null) {
@@ -326,6 +326,16 @@ public class VelocityTabPlayer extends ProxyTabPlayer {
return 0; //shrug
}
@Override
public Object getProfilePublicKey() {
try {
return getPlayer().getIdentifiedKey();
} catch (NoSuchMethodError e) {
//3.1.1 or lower
return null;
}
}
@Override
public void sendPluginMessage(byte[] message) {
Preconditions.checkNotNull(message, "message");