1.15.2 PlayerTeleportEvent not cancelling

Discussion in 'Spigot Plugin Development' started by ZizzyZizzy, Jan 16, 2020.

  1. I'm attempting to stop a player from left-clicking to teleport into a different player while they are in Spectator mode. Searching around I found PlayerTeleportEvent, which fires but never actually cancels.

    Code (Text):
        @EventHandler (priority = EventPriority.HIGHEST)
        public void onTeleport(PlayerTeleportEvent event)
        {
            if (event.getCause().equals(PlayerTeleportEvent.TeleportCause.SPECTATE))
            {
                event.setCancelled(true);
                event.getPlayer().sendMessage(ChatColor.RED + "No changing players in spectate mode!");
            }
        }
     
    Testing in Spectate mode, the message does appear to the player, but the teleport succeeds despite the event.setCancelled(true).

    Is this a bug, or is there something I'm missing here?
     
  2. Adding some debug, it appears the current getSpectatorTarget has already changed to the player that was clicked on when this event has fired. That explains why cancelling it doesn't work.

    That smells like a bug to me, unless there is a PlayerPreTeleportEvent.
     
  3. Try cancelling the PlayerInteractEntityEvent if the player is in spectator mode and their click target is a player. I can only imagine cancelling the teleport doesn't work because there's a bit more to changing spectator targets than a teleport. PlayerInteractEntityEvent should be fired before anything else though, therefore canceling all resulting events afterwards.
     
  4. Someone else mentioned that in an old thread on the topic. Unfortunately that function only intercepts the right-click, while changing spectator targets uses the left-click.
     
    • Useful Useful x 1
  5. Try using just PlayerInteractEvent instead.
     
  6. @Escad Yup, tried that first, actually. Cancelling it does nothing and the teleport still completes.

    Code (Text):
     if(e.getAction() == Action.LEFT_CLICK_AIR && (p.getSpectatorTarget() != null || p.getGameMode() == GameMode.SPECTATOR)){
                p.sendMessage(e.getAction().toString() + " Error - finish your interaction first!");
                e.setCancelled(true);
                return;
            }
     
  7. This code works
    Code (Java):
        @EventHandler(ignoreCancelled = true)
        public void onPlayerTeleport(PlayerTeleportEvent event) {
            if (event.getCause().equals(PlayerTeleportEvent.TeleportCause.SPECTATE)){
                Bukkit.getLogger().info("[TEST] Teleport is spectate cause");
                event.setCancelled(true);
            }else {
                Bukkit.getLogger().info("[TEST] Teleport is not spectate cause");
            }
        }
     
  8. @TheCreeperCow Strange, it does not work for me. Also, when I added getSpectatorTarget output before the setCancelled, it's showing me the name of the player that I've already been teleported to when left-clicking.

    I'm using Citizens for this. I have an NPC that the player will interact with, but I need the player to be focused on them and not be able to move, but still follow the NPC as it walks around and "talks" to them.

    I spawn in a second "dummy" NPC 4 blocks in front of the first NPC, then force the player into Spectator mode and change the spectator target to the dummy NPC. That all works perfectly, except that the player can left-click and jump into the first NPC.

    My work-around is to just force the SpectatorTarget back to the one they are supposed to be interacting with. It works fine, but sometimes there is a quick visual glitch if the client doesn't get the packet fast enough and has already started the teleport to the first NPC before being yanked back.
     
  9. Interesting side node during my testing - if I make the "dummy" NPC invisible with the hidePlayer function, my work-around stops working. This makes no sense to me, since it's supposed to just hide one player from another player.

    I wasted 2 hours with a similar side-effect of hiding the NPC. None of the vector calculations to set the correct pitch and yaw of the dummy NPC were working. The dummy NPC has to have its view adjusted so it's looking at the first NPC, since the player cannot move. If the dummy NPC was hidden, the calculations never worked.

    I resorted to a runnable hideplayer task that fired 20 ticks AFTER the pitch and yaw adjustment as a work-around, but then that breaks the ability to cancel the player teleporting into the first NPC. *sigh* can't win them all.