Paper icon indicating copy to clipboard operation
Paper copied to clipboard

Player#setSpectatorTarget does not "attach" the spectator to it's target

Open n-aspen opened this issue 1 year ago • 4 comments

Expected behavior

Using Player#setSpectatorTarget to target a player would attach the spectator's camera to the player in the same way that the spectator clicking on the player from their client would.

Observed/Actual behavior

Using Player#setSpectatorTarget to target a player teleports the spectator to the target player's location and then will teleport them again when the target player gets too far away. The spectator player isn't following the target's player camera and isn't "attached" to the player.

Steps/models to reproduce

I made a basic plugin that just runs the following code when the target player joins, which uses the Player#setSpectatorTarget method on the spectatorPlayer to target the targetPlayer.

class PlayerJoinEventListener implements Listener {
    UUID spectatorPlayer = UUID.fromString("04fbb67a-02ef-437b-be73-c04fab4f3b43");
    UUID targetPlayer = UUID.fromString("bf8b08a5-714c-4667-8f49-efce56cb7dc5");

    @EventHandler
    public void onPlayerJoin(PlayerJoinEvent event){
        if(event.getPlayer().getUniqueId().equals(targetPlayer)){
            Bukkit.getServer().getPlayer(spectatorPlayer).setSpectatorTarget(event.getPlayer());
        }
    }
}

Attached is a video of this code running with the spectatorPlayer starting in the exact same position that the targetPlayer joins into because of a previously failed spectate.

https://github.com/PaperMC/Paper/assets/16448318/f2fd9157-dab3-40de-a37c-50bc2eebcfe8

Plugin and Datapack List

Only the above mentioned test plugin

Paper version

This server is running Paper version git-Paper-423 (MC: 1.20.4) (Implementing API version 1.20.4-R0.1-SNAPSHOT) (Git: 31699ae) You are running the latest version

Other

No response

n-aspen avatar Feb 14 '24 02:02 n-aspen

I can only reproduce this directly in the PlayerJoinEvent, waiting one tick solves the problem. I suspect this is because the join event is too early and existing players have not been notified of the new player having joined (which happens a bit after the join event, until then it simply does not exist to other players), and it's the server forcing the spectator's position. Waiting one tick you ensure the spectator is told about the entity you want them to spectate and will follow them properly on the client

emilyy-dev avatar Feb 14 '24 02:02 emilyy-dev

Thank you! That makes a lot of sense, however I was able to get it working locally with a delay of 4 ticks, but when using that delay on a server with a higher ping that delay doesn't deem to be enough. Is there a way for me to tell if the spectator is attached or has been sent the entity?

n-aspen avatar Feb 14 '24 12:02 n-aspen

After testing around for some time it seems that latency is not of the matter here, delaying the action by one tick seems to always work fine when both players are within range; there is however this vanilla issue that #9350 does fix, but the issue with calling setSpectatorTarget on join has nothing to do with that, that area is pretty much WAI.

emilyy-dev avatar Feb 15 '24 02:02 emilyy-dev

Got it. I was able to fix both by periodically checking if the spectator is both within 3 blocks of and in the same dimension as the target player, but I was never able to get it to work with as short of a delay as 1 tick, so have stuck with 4 on the join event with the occasional need for the check to fix it.

It may not be ping related and instead be something to do with when/how it's being called in the actual plugin, but it's at least working and has a check for when it breaks.

n-aspen avatar Feb 15 '24 03:02 n-aspen