Разрешает ли PacketPlayOutPlayerInfo отдельные пакеты для изменения имени игрока?

В настоящее время я работаю над плагином для своего собственного сервера 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 дней после публикации, будьте любезны.

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
0
61
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Проблема здесь в том, что вы меняете имя игрока, а не исходное имя игрока. Так что каждый получит эту новую информацию.

Идея заключалась в том, чтобы создать свой собственный GameProfile объект или пользовательские данные игрока, как показано в этом посте:

PacketPlayOutPlayerInfo info = new PacketPlayOutPlayerInfo();
setInfo(info, EnumPlayerInfoAction.ADD_PLAYER, info.new PlayerInfoData(prof, entity.ping, entity.playerInteractManager.getGameMode(), CraftChatMessage.fromString(name)[0]));

Я попробую это и сообщу, если это сработает, это кажется таким простым, что я удивлен, что не нашел этого раньше. Спасибо за вашу помощь !

Neyticom 04.06.2024 09:03

Все работает нормально, спасибо за помощь. Скоро я опубликую полный ответ с моим кодом.

Neyticom 04.06.2024 16:55

С помощью 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);

Надеюсь, это поможет.

Другие вопросы по теме