Player interact cannot deny block use but allow place

XMLWordPrintable

    • Type: Bug
    • Resolution: Fixed
    • Priority: Minor
    • None
    • Affects Version/s: None
    • None
    • Environment:

      Tested in paper, bug is confirmed to exist in spigot

      Formerly, you could deny the two parts of PlayerInteractEvent seprately and they'd work as intended, take this plugin code as example:

      @EventHandler
      public void onPlayerInteract(PlayerInteractEvent pie) {
        if (pie.getAction() != Action.RIGHT_CLICK_BLOCK) return;
      
        pie.setCancelled(false);
        pie.setUseItemInHand(Event.Result.ALLOW);
        pie.setUseInteractedBlock(Event.Result.DENY); 
      }

      This would make it so if you right click with blocks in your hand, it would never interact with the clicked block (eg: no opening chests, no flipping trapdoors) but would always allow the block place itself. This behavior changed in 1.20.5 where now this same code, will result in no interaction with the block but also no block being placed.

      The root cause code responsible for this behavior change was introduced in spigot/craftbukkit 1.20.5
      https://hub.spigotmc.org/stash/projects/SPIGOT/repos/craftbukkit/commits/735b2d0d7f10bc3b3a816e103cc86af8cb1ec645#nms-patches%2Fnet%2Fminecraft%2Fserver%2Flevel%2FPlayerInteractManager.patch?t=316
       
      Notice that prior to this diff, the code would enuminteractionresult = ... (and set the interaction result to PASS) but let the execution continue and the code below, as long as the previous interaction wasn't SUCCESS, would do the block placing. Since it now directly returns the PASS result, it will never attempt to place the block.

      Testing for this has been conducted in 1.8 and (paper) 1.21.11 where the former works fine and the later has the described bug, but i have researched the root cause and found it to be in spigot's 1.20.5 update, and that latest version of this code in spigot still has this bug too:

      Original patch that introduced this issue: https://hub.spigotmc.org/stash/projects/SPIGOT/repos/craftbukkit/commits/735b2d0d7f10bc3b3a816e103cc86af8cb1ec645#nms-patches%2Fnet%2Fminecraft%2Fserver%2Flevel%2FPlayerInteractManager.patch?t=316
      Latest version of the code still having the same issue: https://hub.spigotmc.org/stash/projects/SPIGOT/repos/craftbukkit/browse/nms-patches/net/minecraft/server/level/ServerPlayerGameMode.patch#343

       

       

       

      A minimal patch that seems to fix this is the following (ontop of latest paper):

      diff --git a/net/minecraft/server/level/ServerPlayerGameMode.java b/net/minecraft/server/level/ServerPlayerGameMode.java
      index 84d19d79e77cec6a5d64f59fbcce703e467b2407..87bb20f74716342e504c0cecfab616dc367818b3 100755
      --- a/net/minecraft/server/level/ServerPlayerGameMode.java
      +++ b/net/minecraft/server/level/ServerPlayerGameMode.java
      @@ -526,7 +526,7 @@ public class ServerPlayerGameMode {
                   }
                   // Paper end - Fix inventory desync
                   this.player.resyncUsingItem(this.player); // Properly cancel usable items
      -            return (event.useItemInHand() != org.bukkit.event.Event.Result.ALLOW) ? InteractionResult.SUCCESS : InteractionResult.PASS;
      +            if (event.useItemInHand() != org.bukkit.event.Event.Result.ALLOW) return InteractionResult.SUCCESS; // handle useInteractedBlock and useItemInHand separately
               } else if (this.gameModeForPlayer == GameType.SPECTATOR) {
                   MenuProvider menuProvider = blockState.getMenuProvider(level, blockPos);
                   if (menuProvider != null && player.openMenu(menuProvider).isPresent()) { // Paper - Fix InventoryOpenEvent cancellation
      @@ -553,9 +553,10 @@ public class ServerPlayerGameMode {
                           }
                       }
                   }
      -
      +        } {  // handle useInteractedBlock and useItemInHand separately
                   if (!stack.isEmpty() && !this.interactResult) { // add !interactResult SPIGOT-764
                       UseOnContext useOnContext = new UseOnContext(player, hand, hitResult);
      +                ItemStack itemStack = stack.copy(); // handle useInteractedBlock and useItemInHand separately
                       InteractionResult interactionResult1;
                       if (player.hasInfiniteMaterials()) {
                           int count = stack.getCount();
      

       
      Do note: this patch results in unneeded itemstack resyncs on the client so the place is a bit weird (although that may be a paper-only thing), but the behavior serverside works as intended.
       

       

       

            Assignee:
            Unassigned
            Reporter:
            Pablete1234
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

              Created:
              Updated:
              Resolved: