Glowing for one Person

Discussion in 'Plugin Development' started by TheLastDeamon, Mar 5, 2017.

Thread Status:
Not open for further replies.
  1. Offline

    TheLastDeamon

    I have a Question about my plugin.
    I wanted to make an Infra sight item.
    For that I wanted to give all players a Glowing effect, but that effect should only be visible for one player...
    And because I can't find any solutions, I thought I would ask here.

    Any Ideas?
     
  2. Last edited: Mar 6, 2017
  3. Offline

    TheLastDeamon

    Oh thanks... but I'm not that good with Packets could you please write how?
     
  4. Offline

    Zombie_Striker

  5. Offline

    TheLastDeamon

  6. Offline

    Zombie_Striker

    @TheLastDeamon
    If your problem has been solved, mark this thread as solved,
     
  7. Offline

    TheLastDeamon

    No I don't get it...

    ok...
    now I got this:

    Code:
    PacketPlayOutEntityEffect eff = new PacketPlayOutEntityEffect(e.getPlayer().getEntityId(), new MobEffect(MobEffectList.fromId(24), 1000, 1, true, true));
    ((CraftPlayer) e.getPlayer()).getHandle().playerConnection.sendPacket(eff);
    and I get a glowing effect!

    And besides that, I got the effect but I don't glow...

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: Mar 5, 2017
  8. @TheLastDeamon
    Good! You've worked out how to send the packet, we just need to make the packet say that everyone else has the glow effect instead of you having the glow effect. To achieve this, do the following:
    1. Iterate over all players you want to be glowing
    2. For each player, send the packet just like you did but replace your entity ID in the packet constructor (e.getPlayer.getEntityID()) with their entity ID. This is because the entity ID parameter signifies which entity the effect is being applied to. You still only send the packet to one client though, so only they will see everyone else as glowing.
    This is wrong, see below posts.
     
    Last edited: Mar 6, 2017
  9. Offline

    TheLastDeamon

    I already did that :p

    Code:
    for (Player p : Bukkit.getOnlinePlayers())
             {
               PacketPlayOutEntityEffect eff = new PacketPlayOutEntityEffect(p.getPlayer().getEntityId(), new MobEffect(MobEffectList.fromId(24), 10, 1, true, true));
               ((CraftPlayer) p).getHandle().playerConnection.sendPacket(eff);
             }
    but still noone glows.
    I just get the effect!!!

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: Mar 5, 2017
  10. @TheLastDeamon
    The first argument to this constructor is the entity ID of the player you want to apply the potion effect. Right now you are passing it the player who is supposed to see the glow. You want to pass it the ID of the player you want to make glow.

    This is wrong, see below posts.
     
    Last edited: Mar 6, 2017
  11. Offline

    TheLastDeamon

    But I'm giving it to the Player form (Player p : Bukkit.getOnlinePlayer()) ... isn't that the right?

    EDIT:
    Woops...

    Code:
    for (Player p : Bukkit.getOnlinePlayers())
             {
               PacketPlayOutEntityEffect eff = new PacketPlayOutEntityEffect(p.getPlayer().getEntityId(), new MobEffect(MobEffectList.fromId(24), 1000, 20, true, true));
               ((CraftPlayer) e.getPlayer()).getHandle().playerConnection.sendPacket(eff);
             }
    Ok here is the Whole Event...

    Code:
    @EventHandler
       public void onPlayerInteract(PlayerInteractEvent e)
       {
         if(e.getPlayer().getInventory().getItemInMainHand().getType() == Material.SPECTRAL_ARROW)
           if(e.getAction() == Action.RIGHT_CLICK_AIR || e.getAction() == Action.RIGHT_CLICK_BLOCK)
           {
             e.getPlayer().sendMessage("Click accepted!")
             for (Player p : Bukkit.getOnlinePlayers())
             {
               PacketPlayOutEntityEffect eff = new PacketPlayOutEntityEffect(p.getPlayer().getEntityId(), new MobEffect(MobEffectList.fromId(24), 1000, 20, true, true));
               ((CraftPlayer) e.getPlayer()).getHandle().playerConnection.sendPacket(eff);
             }
           }
       }
    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: Mar 5, 2017
  12. @TheLastDeamon
    Looks about right. Only thing you might want to add is a check to see if it's the player you're sending the packets to, to avoid him getting the inventory notification.

    This is wrong, see below posts.
     
    Last edited: Mar 6, 2017
  13. Offline

    TheLastDeamon

    But the Players don't glow.

    Please help me!
     
    Last edited: Mar 5, 2017
  14. @TheLastDeamon
    Looks like I was mistaken (mostly due to slightly shoddy protocol documentation). You're going to have to go down the rabbit hole of Entity Metadata. You want to set the 7th bit of the byte at index 0 to a 1 for any outgoing packets regarding the entity you want to glow. You're also going to have to intercept all metadata packets sent to avoid the bit getting reset.

    I understand if you have no clue what I mean, I'll post in this thread at a later point (probably tomorrow) with some more exact instructions on how to do this.
     
  15. Offline

    TheLastDeamon

    ur right
    and thank you

    I found that:
    Code:
    Solution found using ProtocolLib in this commit :
    https://github.com/Avatar-Realms/spigot-bending/commit/e9890ee298cf28a99073df689d3516c966429d08
    We use the usual LivingEntity.addPotionEffect() then catch its packet. If the packet is not for the right user, we remove the glow effect on it.
    
    The actual problem was that we weren't sending the right packet.
    The packet that was used was for the client player only. If we want to inform a client about other entity effects, we need to use another Packet (whose I don't remember the exact name... something like PacketEntityMetadata...),
    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: Mar 5, 2017
  16. @TheLastDeamon
    Yes, that is actually an implementation on how you would do it. Only thing you need to keep in mind for your case is that you want to listen to Player Spawn (called Named Entity Spawn for whatever reason), because that packet can also send metadata.
     
  17. Offline

    TheLastDeamon

    I don't get that.
    Why Player Spawn

    I got this:
    Code:
    PacketPlayOutEntityEffect eff = new PacketPlayOutEntityEffect(p.getEntityId(), new MobEffect(MobEffectList.fromId(24), 1000, 20, true, true));
                     EntityPlayer ep = ((CraftPlayer) p).getHandle();
                 
                     ep.setFlag(6, true);
                     ((CraftPlayer) e.getPlayer()).getHandle().playerConnection.sendPacket(eff);
    and the player blinks for everyone!
     
    Last edited: Mar 6, 2017
  18. Offline

    TheLastDeamon

    Hey Guys,

    I have a problem with a package.
    I want to make a Player glwo
    Code:
    PacketPlayOutEntityEffect eff = new PacketPlayOutEntityEffect(p.getEntityId(), new MobEffect(MobEffectList.fromId(24), 1000, 20, true, true));
    ((CraftPlayer) e.getPlayer()).getHandle().playerConnection.sendPacket(eff);
    I can see, that I'm getting the effect, but I don't glow.
    and everyone else doesn't either!

    Pls help me!
     
  19. Online

    timtower Administrator Administrator Moderator

    Merged threads.
     
  20. @TheLastDeamon
    Forget what I said in the first 4 posts - I misread the protocol documentation.

    We're going to need to use ProtocolLib to intercept outgoing Entity Metadata and Player Spawn packets (since they are the ones that contain metadata). I don't know how familiar you are with ProtocolLib, but if you aren't, look up a tutorial. Good place to start might be here.

    In these packets we'll set the 7th bit of the byte at index 0 in the DataWatcher to a 1. This will tell the client that the entity is glowing.

    First, we'll need to add ProtocolLib as a dependency to your plugin (see this page).

    Then, in you'll need to add a PacketListener (preferrably in the onEnable) using ProtocolLibrary.getProtocolManager().addPacketListener(). I recommend using PacketAdapter. Your constructor should look something like this:
    Code:java
    1. new PacketAdapter(this, PacketType.Play.Server.ENTITY_METADATA, PacketType.Play.Server.NAMED_ENTITY_SPAWN)
    and then you want to make an anonymous subclass of this PacketAdapter, and overriding the onPacketSending() method.

    In the packetSending method you want to first check if event.getPlayer() is the one you want to see the glowing players (recommend keeping said players in a Set<UUID>, and checking against it).

    Then you want to check if Bukkit.getOnlinePlayers() has a player with entity ID of event.getPacket().getIntegers().read(0) (this field is the entity ID in the packet). This is so we only get glowing players, and not mobs (entity metadata is sent for all entities).

    After that, you'll need to check the packet type (event.getPacketType()) since the metadata and spawn packets handle the datawatcher slightly differently; in the player spawn, there is a straight up reference to the watcher itself, and in metadata there is a List of datawatcher items. If the type is entity metadata, use event.getPacket().getWatchableCollectionModifier().read(0) to get the list of data watcher items, and check if any of these have index 0 (the List is unordered, so a get(0) isn't sufficient, you have to iterate over it and check if the WrappedWatchableObject#getIndex() == 0).

    If the List contains a WatchableObject with index 0, get it's value and store it in a byte. You then want to do a bitwise or on this byte with 64. This could be done with b |= 0b01000000 (b being the byte). If you don't know what this means, I'd recommend you google about Java Bitwise operators. Then we need to set the value back into the WatchableObject using WatchableObject#setValue().

    If the Packet Type is Player spawn, the process is essentially the same, only difference is that you instead get the data watcher from the packet using, event.getPacket().getDataWatcherModifier().read(0) and use WrappedDataWatcher#getByte(index) to get the byte (you can use WrappedDataWatcher#hasIndex() to check if it contains the byte). To set the byte, just do WrappedDataWatcher#setObject(index, byte).

    Here's some pseudocode for the process I explained above:
    Code:java
    1. ProtocolLibrary.getProtocolManager().addPacketListener(new PacketAdapter(this, PacketType.Play.Server.ENTITY_METADATA, PacketType.Play.Server.NAMED_ENTITY_SPAWN) {
    2. @Override
    3. void onPacketSending(Event event) {
    4. if (event.getPlayer() is a player who you want to see the glow) {
    5. if (Bukkit.getOnlinePlayers() has a player with player.getEntityId() == event.getPacket().getIntegers().read(0)) {
    6. if (event.getPacketType() == Entity Metadata) {
    7. List watchableObjectList = event.getPacket().getWatchableCollectionModifier().read(0);
    8. if (watchableObjectList has object with getIndex() == 0) {
    9. WrappedWatchableObject watchableObject = watchableObjectList.get object with index 0;
    10. byte b = watchableObject.getValue();
    11. b |= 0b01000000;
    12. watchableObject.setValue(b);
    13. }
    14. } else {
    15. WrappedDataWatcher watcher = event.getPacket().getDataWatcherModifier().read(0);
    16. if (watcher.hasIndex(0)) {
    17. byte b = watcher.getByte(0);
    18. b |= 0b01000000;
    19. watcher.setObject(0, b);
    20. }
    21. }
    22. }
    23. }
    24. }
    25. });


    You will also need to take into account if the player you want to make glow/not glow is already in range to the player you're sending packets to, as they have already received the (unedited) meta data packets. Simplest way to do this would be to do a player.hidePlayer() followed by a player.showPlayer() to get the server to send the new packets for you.
     
    Last edited: Mar 7, 2017
  21. Offline

    TheLastDeamon

    Thank you so much!!!
    But how do I activate and deactivate the glowing then?

    And what type of event would that be?
    Just java.awt.Event?
     
    Last edited: Mar 6, 2017
  22. @TheLastDeamon
    Just do a check in the onPacketSending() to see if event.getPlayer() is a player you want to have see players as glowing. One way to do this would be to keep a Set<UUID> representing all the players you want to do the effect on and doing a contains check on that.

    The Event I'm referring to is PacketEvent from ProtocolLib.

    Also, the code I posted was as mentioned pseudocode, so it is not intended to work, it's just to outline how your code should look. To get the working code, you have to read my instructions and code it yourself.
     
  23. Offline

    TheLastDeamon

    I knew that it was a pseudocode :p and Thanks!


    should it look like this?

    Code:java
    1. @Override
    2. public void onPacketSending(PacketEvent event) {
    3. for (Player player : Bukkit.getOnlinePlayers())
    4. {
    5. if (/*has a player with*/player.getEntityId() == event.getPacket().getIntegers().read(0)) {
    6. if (event.getPacketType() == PacketType.findLegacy(7)) {
    7. List<WrappedWatchableObject> watchableObjectList = event.getPacket().getWatchableCollectionModifier().read(0);
    8. for (WrappedWatchableObject metadata : watchableObjectList)
    9. {
    10. if (metadata.getIndex() == 0) {
    11. WrappedWatchableObject watchableObject = watchableObjectList.get(0); /*object with index 0 from watchableObjectList*/
    12. byte b = (byte) watchableObject.getValue();
    13. b |= 0b01000000;
    14. watchableObject.setValue(b);
    15. } else {
    16. WrappedDataWatcher watcher = event.getPacket().getDataWatcherModifier().read(0);
    17. if (watcher.hasIndex(0)) {
    18. byte b = watcher.getByte(0);
    19. b |= 0b01000000;
    20. watcher.setObject(0, b);
    21. }
    22. }
    23. }
    24. }
    25. }
    26. }
    27. }


    Now I'm getting this Error:

    Code:
    org.bukkit.plugin.UnknownDependencyException: ProtocolLib
      at org.bukkit.plugin.SimplePluginManager.loadPlugins(SimplePluginManager.java:219) [server.jar:git-Bukkit-64277ec]
      at org.bukkit.craftbukkit.v1_11_R1.CraftServer.loadPlugins(CraftServer.java:298) [server.jar:git-Bukkit-64277ec]
      at org.bukkit.craftbukkit.v1_11_R1.CraftServer.reload(CraftServer.java:727) [server.jar:git-Bukkit-64277ec]
      at org.bukkit.Bukkit.reload(Bukkit.java:549) [server.jar:git-Bukkit-64277ec]
      at org.bukkit.command.defaults.ReloadCommand.execute(ReloadCommand.java:25) [server.jar:git-Bukkit-64277ec]
      at org.bukkit.command.SimpleCommandMap.dispatch(SimpleCommandMap.java:140) [server.jar:git-Bukkit-64277ec]
      at org.bukkit.craftbukkit.v1_11_R1.CraftServer.dispatchCommand(CraftServer.java:629) [server.jar:git-Bukkit-64277ec]
      at org.bukkit.craftbukkit.v1_11_R1.CraftServer.dispatchServerCommand(CraftServer.java:615) [server.jar:git-Bukkit-64277ec]
      at net.minecraft.server.v1_11_R1.DedicatedServer.aM(DedicatedServer.java:397) [server.jar:git-Bukkit-64277ec]
      at net.minecraft.server.v1_11_R1.DedicatedServer.D(DedicatedServer.java:361) [server.jar:git-Bukkit-64277ec]
      at net.minecraft.server.v1_11_R1.MinecraftServer.C(MinecraftServer.java:650) [server.jar:git-Bukkit-64277ec]
      at net.minecraft.server.v1_11_R1.MinecraftServer.run(MinecraftServer.java:554) [server.jar:git-Bukkit-64277ec]
      at java.lang.Thread.run(Unknown Source) [?:1.8.0_91]
     
    Last edited: Mar 7, 2017
  24. @TheLastDeamon
    1. You're forgetting to check if the player the packet is being sent to (event.getPacket()) is a player you want to see the glowing effects. Right now, everyone always sees glowing players.
    2. Entity Metadata packet type = PacketType.Play.Server.ENTITY_METADATA, not PacketType.findLegacy(...)
    3. You don't need the watchableObject variable, it is getting the wrong entry (I mentioned that the List is not ordered after DataWatcher index), just use the metadata variable you already have.
    4. The else statement is misplaced. It should be an else to if (event.getPacketType() ==...) instead of if (meta.data.getIndex()...)
    You also don't have ProtocolLib installed on your server.
     
    Last edited: Mar 7, 2017
  25. Offline

    TheLastDeamon

    so is it correct now?

    Code:java
    1. ProtocolLibrary.getProtocolManager().addPacketListener(new PacketAdapter(this, PacketType.Play.Server.ENTITY_METADATA, PacketType.Play.Server.NAMED_ENTITY_SPAWN) {
    2. @Override
    3. public void onPacketSending(PacketEvent event) {
    4. for (Player player : Bukkit.getOnlinePlayers())
    5. {
    6. if (seeGlow.contains(player))
    7. {
    8. if (/*has a player with*/player.getEntityId() == event.getPacket().getIntegers().read(0)) {
    9. if (event.getPacketType() == PacketType.Play.Server.ENTITY_METADATA) {
    10. List<WrappedWatchableObject> watchableObjectList = event.getPacket().getWatchableCollectionModifier().read(0);
    11. WrappedDataWatcher watcher = event.getPacket().getDataWatcherModifier().read(0);
    12. for (WrappedWatchableObject metadata : watchableObjectList)
    13. {
    14. if (metadata.getIndex() == 0) {
    15. byte b = (byte) metadata.getValue();
    16. b |= 0b01000000;
    17. metadata.setValue(b);
    18. }
    19. if (watcher.hasIndex(0)) {
    20. byte b = watcher.getByte(0);
    21. b |= 0b01000000;
    22. watcher.setObject(0, b);
    23. }
    24. }
    25. }
    26. }
    27. }
    28. }
    29. }
    30. });
     
    Last edited: Mar 7, 2017
  26. @TheLastDeamon
    Not quite there yet, but you're getting close :)
    1. seeGlow.contains() should be done on event.getPlayer(), not the player from the for loop.
    2. The watcher code is still not in the right place, it needs to be in an else statement (including the "watcher" variable declaration) to if (event.getPacketType == PacketType....).
    If you still do not succeed, I recommend looking over the pseudocode again.
     
  27. Offline

    TheLastDeamon

    @AlvinB
    And now?

    Code:java
    1.  
    2. ProtocolLibrary.getProtocolManager().addPacketListener(new PacketAdapter(this, PacketType.Play.Server.ENTITY_METADATA, PacketType.Play.Server.NAMED_ENTITY_SPAWN) {
    3. @Override
    4. public void onPacketSending(PacketEvent event) {
    5. for (Player player : Bukkit.getOnlinePlayers())
    6. {
    7. if (seeGlow.contains(event.getPlayer()))
    8. {
    9. if (/*has a player with*/player.getEntityId() == event.getPacket().getIntegers().read(0)) {
    10. if (event.getPacketType() == PacketType.Play.Server.ENTITY_METADATA) {
    11. List<WrappedWatchableObject> watchableObjectList = event.getPacket().getWatchableCollectionModifier().read(0);
    12. for (WrappedWatchableObject metadata : watchableObjectList)
    13. {
    14. if (metadata.getIndex() == 0) {
    15. byte b = (byte) metadata.getValue();
    16. b |= 0b01000000;
    17. metadata.setValue(b);
    18. }
    19. }
    20. } else {
    21. WrappedDataWatcher watcher = event.getPacket().getDataWatcherModifier().read(0);
    22. if (watcher.hasIndex(0)) {
    23. byte b = watcher.getByte(0);
    24. b |= 0b01000000;
    25. watcher.setObject(0, b);
    26. }
    27. }
    28. }
    29. }
    30. }
    31. }
    32. });
    33.  
     
    Last edited: Mar 7, 2017
  28. Offline

    TheLastDeamon

    @AlvinB
    and how do I then use it?
     
    Last edited: Mar 7, 2017
  29. @TheLastDeamon
    Just add a player to the set and do player.hidePlayer() and player.showPlayer() on any players they can already see and you should be good to go. To remove the glow effect you do the same but remove from the set instead of adding.
     
Thread Status:
Not open for further replies.

Share This Page