-
Bug
-
Resolution: Unresolved
-
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", "", "", "" }); } } }