Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ProtocolManager.updateEntity​ method doesn't work in Spigot 1.17.1 #1417

Closed
Lori3f6 opened this issue Oct 17, 2021 · 6 comments
Closed

ProtocolManager.updateEntity​ method doesn't work in Spigot 1.17.1 #1417

Lori3f6 opened this issue Oct 17, 2021 · 6 comments

Comments

@Lori3f6
Copy link

Lori3f6 commented Oct 17, 2021

Describe the bug
Hello, I am using ProtocolLib to make a entity vanish from a player's client, so I send a ENTITY_DESTROY packet to a player. It works properly. Then I am going to use updateEntity​(org.bukkit.entity.Entity entity, List<org.bukkit.entity.Player> observers) method to make the entity appear on the player client again, but it changes nothing on client.

To Reproduce
I made a plug-in and run the following code. These code are expected to make all LivingEntities except Player vanishing and presenting in player's client alternatively.

import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.events.PacketContainer;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;

public class TwinkleEntities extends JavaPlugin {
    @Override
    public void onEnable() {
        var protocolManager = ProtocolLibrary.getProtocolManager();
        AtomicBoolean flag = new AtomicBoolean(false);
        getServer().getScheduler().runTaskTimer(this, () -> {
            if (getServer().getOnlinePlayers().isEmpty())
                return;

            var player = (Player) getServer().getOnlinePlayers().toArray()[0];

            if (flag.get()) {
                var vanishPacket = new PacketContainer(PacketType.Play.Server.ENTITY_DESTROY);
                var entityIDList = new ArrayList<Integer>();

                for (var entity : player.getWorld().getLivingEntities()) {
                    if (!(entity instanceof Player)) {
                        entityIDList.add(entity.getEntityId());
                    }
                }
                vanishPacket.getIntLists().write(
                        0, entityIDList
                );
                try {
                    protocolManager.sendServerPacket(player, vanishPacket);
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
                player.sendMessage("Entities vanished!");
            } else {
                for (var entity : player.getWorld().getLivingEntities()) {
                    if (!(entity instanceof Player)) {
                        protocolManager.updateEntity(entity, List.of(player));
                    }
                }
                player.sendMessage("Entities shown!");
            }

            flag.set(!flag.get());
        }, 0L, 20L);
    }
}

Expected behavior
The entity around the player twinkles between appearance and disappearance every second. But entities don't present again after vanished.

Screenshots
image.gif
This gif may shorternd by github automatically, you could see a longer version here if you want: https://global.cdn.blingwang.cn/2021/10/17/9233d3d691502.gif

Version Info
https://pastebin.mozilla.org/asyh7mqC/raw

Additional context
I don't know why the entity don't presents after disappearing. If the problem is caused by incorrect API call in my code, please don't hesitate to correct me. Thanks a lot.

Empty below.

@joehot200
Copy link

joehot200 commented Oct 17, 2021

I have also duplicated this problem with effectively the same code.

updateEntity() on 1.16 will un-hide an entity that is destroyed, 1.17 with exact same code no longer shows the entity.

public final boolean showEntity(Player observer, Entity entity) {
		try {
			validate(observer, entity);
			boolean hiddenBefore = !setVisibility(observer, entity.getEntityId(), true);
			//observer.sendMessage("Shown " + entity.getType() + " Was hidden? " + hiddenBefore);
			// Resend packets
			if (manager != null && hiddenBefore) {
				List<Player> thing = Arrays.asList(observer);
				manager.updateEntity(entity, thing);
				for (int i = 1; i <= 20; i++) { //Attempt to brute-force the issue to see if that helped, it didnt :D
				Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(TaskHandler.javaPluginClass, new Runnable() {

					@Override
					public void run() {
						manager.updateEntity(entity, thing);

					}
				}, i);
				}
			}

			return hiddenBefore;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}

@joehot200
Copy link

joehot200 commented Oct 18, 2021

I have done some testing, and you have to send a SPAWN_ENTITY_LIVING packet like this:

` //Note: It is literally midnight for me and I am going to bed, all messy bits of code have been left in
PacketContainer newPacket = new PacketContainer(SPAWN_ENTITY_LIVING);
		        newPacket.getIntegers().
		            write(0, entity.getEntityId()).
		            write(1, (int) 71). //MAKE ALL ENTITIES RABBITS. I AM THE RABBIT LORD. (Also too lazy to work out how to get correct entity IDs right now)
		            write(2, -106).
		            write(3, 338).
		            write(4, 514);
		            newPacket.getDoubles().
		            write(0, (double) entity.getLocation().getX() * 1).
		            write(1, (double) entity.getLocation().getY() * 1).
		            write(2, (double) entity.getLocation().getZ() * 1);
		            //write(3, (double) entity.getLocation().getPitch()).
		           // write(4, (double) entity.getLocation().getYaw());
		            newPacket.getUUIDs().write(0, entity.getUniqueId());
		            /*newPacket.getShorts().
		            write(0, (short) 0).
		            write(1, (short) 0).
		            write(2, (short) 0);*/
		            //newPacket.getFloat().write(0, entity.getLocation().getPitch());
		           // newPacket.getFloat().write(1, entity.getLocation().getYaw());
		        try {
		            ProtocolLibrary.getProtocolManager().sendServerPacket(observer, newPacket);
		        } catch (InvocationTargetException e) {
		            e.printStackTrace();
		        }
		    
			}`

Doing this with literally the same entity ID of the entity that was hidden will make the entity appear again to the client.

@Sentropic
Copy link

Having the same issue, also in 1.17.1

@derklaro
Copy link
Contributor

derklaro commented Mar 7, 2022

Hey,

sorry for the late response on this issue; thanks for the report! As we're changing quite a lot of code in v5.0 (see #1524 for now) I will keep this issue in mind and take a look into it when testing the new version. Might be that the issue is already resolved, will see.

@Sentropic
Copy link

Sentropic commented Mar 7, 2022

I have done some testing, and you have to send a SPAWN_ENTITY_LIVING packet like this:

` //Note: It is literally midnight for me and I am going to bed, all messy bits of code have been left in
PacketContainer newPacket = new PacketContainer(SPAWN_ENTITY_LIVING);
		        newPacket.getIntegers().
		            write(0, entity.getEntityId()).
		            write(1, (int) 71). //MAKE ALL ENTITIES RABBITS. I AM THE RABBIT LORD. (Also too lazy to work out how to get correct entity IDs right now)
		            write(2, -106).
		            write(3, 338).
		            write(4, 514);
		            newPacket.getDoubles().
		            write(0, (double) entity.getLocation().getX() * 1).
		            write(1, (double) entity.getLocation().getY() * 1).
		            write(2, (double) entity.getLocation().getZ() * 1);
		            //write(3, (double) entity.getLocation().getPitch()).
		           // write(4, (double) entity.getLocation().getYaw());
		            newPacket.getUUIDs().write(0, entity.getUniqueId());
		            /*newPacket.getShorts().
		            write(0, (short) 0).
		            write(1, (short) 0).
		            write(2, (short) 0);*/
		            //newPacket.getFloat().write(0, entity.getLocation().getPitch());
		           // newPacket.getFloat().write(1, entity.getLocation().getYaw());
		        try {
		            ProtocolLibrary.getProtocolManager().sendServerPacket(observer, newPacket);
		        } catch (InvocationTargetException e) {
		            e.printStackTrace();
		        }
		    
			}`

Doing this with literally the same entity ID of the entity that was hidden will make the entity appear again to the client.

Note that players, paintings, exp orbs and other non-living entities use different packet types, so they require different handling.

@Sentropic
Copy link

Got it, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants