Uploaded image for project: 'Spigot'
  1. Spigot
  2. SPIGOT-7408

Cancelling sign block break event does not preserve sign text on client

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Unresolved
    • Icon: Minor Minor
    • None
    • None
    • This server is running CraftBukkit version dev-Spigot-64b565e-c1279f7 (MC: 1.20.1) (Implementing API version 1.20.1-R0.1-SNAPSHOT)
    • Yes

      On Spigot 1.20.1, when a plugin cancels the BlockBreakEvent for a sign block, the sign block immediately reappears, but it loses its sign content. Once the player rejoins the server, the sign content reappears.

      Tested in both survival and creative mode.

      Also tested to manually send a sign update after the BlockBreakEvent: Sending the sign update works if there is at least a delay of 2 ticks. 1 tick seems to longer be sufficient.

      Also, maybe related to this, I noticed that when the player keeps hitting the block in survival mode (without letting go of the left mouse button), the block can end up being displayed in its "damaged" state, which only resets once the player interacts with another block.

      Test plugin code:

      package de.blablubbabc.test.block.sign;
      
      import org.bukkit.Bukkit;
      import org.bukkit.Material;
      import org.bukkit.block.Block;
      import org.bukkit.block.Sign;
      import org.bukkit.block.sign.Side;
      import org.bukkit.entity.Player;
      import org.bukkit.event.EventHandler;
      import org.bukkit.event.Listener;
      import org.bukkit.event.block.Action;
      import org.bukkit.event.block.BlockBreakEvent;
      import org.bukkit.event.player.PlayerInteractEvent;
      import org.bukkit.inventory.EquipmentSlot;
      
      import de.blablubbabc.test.Test;
      
      public class SignBlockBreakTest implements Listener {
      
      	public SignBlockBreakTest() {
      		Bukkit.getPluginManager().registerEvents(this, Test.INSTANCE);
      	}
      
      	public static boolean isSign(Material material) {
      		if (material == null) return false;
      		return material.data == org.bukkit.block.data.type.Sign.class
      				|| material.data == org.bukkit.block.data.type.WallSign.class;
      	}
      
      	@EventHandler
      	public void onBlockBreak(BlockBreakEvent event) {
      		Player player = event.getPlayer();
      		if (!player.isSneaking()) return;
      
      		player.sendMessage("Cancelling block break");
      		event.setCancelled(true);
      
      		Block block = event.getBlock();
      		if (isSign(block.getType()) && Math.random() > 0.5) {
      			String[] lines = ((Sign) block.getState()).getSide(Side.FRONT).getLines();
      			player.sendMessage("Sending sign update: " + String.join(", ", lines));
      			Bukkit.getScheduler().runTaskLater(Test.INSTANCE, () -> {
      				player.sendSignChange(block.getLocation(), lines);
      			}, 2L); // Delay of 0 or 1 tick is not sufficient
      		}
      	}
      
      	@EventHandler
      	public void onPlayerInteract(PlayerInteractEvent event) {
      		if (event.getAction() != Action.RIGHT_CLICK_BLOCK) return;
      		if (event.getHand() != EquipmentSlot.HAND) return;
      
      		Player player = event.getPlayer();
      		if (!player.isSneaking()) return;
      
      		player.sendMessage("Cancelling interact");
      		event.setCancelled(true);
      
      		Block block = event.getClickedBlock();
      		if (isSign(block.getType())) {
      			player.sendMessage("Sending sign update.");
      			player.sendSignChange(block.getLocation(), new String[] { "Bla", "", "", "" });
      		}
      	}
      }
       

            Unassigned Unassigned
            blablubbabc blablubbabc
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated: