В настоящее время я работаю над плагином для своего собственного сервера Spigot (1.8.x) и столкнулся с проблемой с PacketPlayOutPlayerInfo.
Я пытаюсь сделать так, чтобы имя игрока (над головой) отображалось разным цветом в зависимости от игрока, который его видит. По сути, я тестировал разные методы для достижения этой цели, но ни один из них не сработал.
На мой взгляд, лучший метод, который я пробовал, заключается в следующем:
(Into a PlayerJoinEvent Listener)
EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle();
GameProfile playerProfile = entityPlayer.getProfile();
Field nameField = playerProfile.getClass().getDeclaredField("name");
nameField.setAccessible(true);
nameField.set(playerProfile, ChatColor.RED + player.getName());
PlayerConnection connection = ((CraftPlayer) Bukkit.getPlayer("HeartZone")).getHandle().playerConnection;
connection.sendPacket(new PacketPlayOutPlayerInfo(EnumPlayerInfoAction.REMOVE_PLAYER, entityPlayer));
connection.sendPacket(new PacketPlayOutPlayerInfo(EnumPlayerInfoAction.ADD_PLAYER, entityPlayer));
Частично это работает, потому что я вижу свое имя красным, но каждый онлайн-игрок может видеть мое имя красным, а это не то, что я ищу.
Я попытался удалить следующий код:
PlayerConnection connection = ((CraftPlayer) Bukkit.getPlayer("HeartZone")).getHandle().playerConnection;
connection.sendPacket(new PacketPlayOutPlayerInfo(EnumPlayerInfoAction.REMOVE_PLAYER, entityPlayer));
connection.sendPacket(new PacketPlayOutPlayerInfo(EnumPlayerInfoAction.ADD_PLAYER, entityPlayer));
И результат тот же. Итак, действительно ли PacketPlayOutPlayerInfo работает и полезен?
Наконец, я попробовал добавить:
nameField.set(playerProfile, ChatColor.stripColor(player.getName()));
Но цвет нормальный (сбрасывается) для всех игроков, которые меня видят, как будто nameField.set(GameProfile, String) сам вызывает пакеты.
Обновлено: я искал и тестировал код в течение 2 дней после публикации, будьте любезны.




Проблема здесь в том, что вы меняете имя игрока, а не исходное имя игрока. Так что каждый получит эту новую информацию.
Идея заключалась в том, чтобы создать свой собственный GameProfile объект или пользовательские данные игрока, как показано в этом посте:
PacketPlayOutPlayerInfo info = new PacketPlayOutPlayerInfo(); setInfo(info, EnumPlayerInfoAction.ADD_PLAYER, info.new PlayerInfoData(prof, entity.ping, entity.playerInteractManager.getGameMode(), CraftChatMessage.fromString(name)[0]));
Все работает нормально, спасибо за помощь. Скоро я опубликую полный ответ с моим кодом.
С помощью Elikill58 и на основе его ответа я наконец нашел способ заставить эту функциональность работать следующим образом.
Как сделать так, чтобы имя игрока выглядело по-разному для каждого игрока: (проверено в версии 1.8)
// First, you have to allow the player entity name field to be changed
Player target = *your way to get a Player*;
String originalName = target.getName();
EntityPlayer entityPlayer = ((CraftPlayer) target).getHandle();
GameProfile playerProfile = entityPlayer.getProfile();
Field nameField = playerProfile.getClass().getDeclaredField("name");
nameField.setAccessible(true);
// All the following code can be sent in a Queue (java.util)
// to avoid name issues if you have to send a lot of packets
// in a short time.
// Then, you can change the player's name situationally
// In my usage, I used the Factions plugin API to change the player name
// with the ally/enemy/neutral/truce color
String customName = *Player name with the modifications you like*;
// And for each player who needs to see the custom name :
connection.sendPacket(new PacketPlayOutPlayerInfo(
PacketPlayOutPlayerInfo.EnumPlayerInfoAction.REMOVE_PLAYER,
entityPlayer
));
connection.sendPacket(new PacketPlayOutEntityDestroy(entityPlayer.getId()));
nameField.set(playerProfile, customName);
connection.sendPacket(new PacketPlayOutPlayerInfo(
PacketPlayOutPlayerInfo.EnumPlayerInfoAction.ADD_PLAYER,
entityPlayer
));
connection.sendPacket(new PacketPlayOutNamedEntitySpawn(entityPlayer));
// Finally, don't forget to reset the player's name to the default
nameField.set(playerProfile, originalName);
Надеюсь, это поможет.
Я попробую это и сообщу, если это сработает, это кажется таким простым, что я удивлен, что не нашел этого раньше. Спасибо за вашу помощь !