[SPIGOT-3180] BlockState.update(true,true); not re-applying special block data Created: 11/Apr/17  Updated: 13/Apr/17  Resolved: 12/Apr/17

Status: Resolved
Project: Spigot
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Bug Priority: Minor
Reporter: iPyronic Assignee: Unassigned
Resolution: Won't Fix Votes: 0
Labels: BlockState, Craftbukkit, Signs

Attachments: PNG File 2017-04-11_08.57.30.png    

 Description   

Step 1: Save the BlockState of a non-blank Sign to a variable

Step 2: Set the sign block to stone or glass or something

Step 3: Call the update method on the saved BlockState object and use the force flag

 

Result expected: The block becomes a sign again and the lines it had are restored

Result that occurs: The block becomes a sign again but is blank

 

Code used to test:

Player player = (Player)sender;
Block targetBlock = player.getLocation().getBlock().getRelative(BlockFace.NORTH,2);
targetBlock.setType(Material.SIGN_POST);
Sign newSign = (Sign)targetBlock.getState();
newSign.setLine(0, "Test Sign");
newSign.update(true,true);
sender.sendMessage(" Placed sign with text.");
new BukkitRunnable(){public void run(){
   if(targetBlock.getType()==Material.SIGN_POST){
      BlockState oldState = targetBlock.getState();
      targetBlock.setType(Material.GLASS);
      sender.sendMessage(" Overwrote sign with glass.");
      new BukkitRunnable(){public void run(){
         boolean result = oldState.update(true,true);
         sender.sendMessage(" Restored "+oldState.getClass().getSimpleName()+". Update result == "+result);
         BlockState newState = targetBlock.getState();
         if(oldState instanceof Sign && newState instanceof Sign){
            String[] oldLines = ((Sign)oldState).getLines();
            String[] newLines = ((Sign)newState).getLines();
            for(int i = 0; i < 4; i++){
               sender.sendMessage(" [Line "+(i+1)+"] old: \""+oldLines[i]+"\" new: \""+newLines[i]+"\"");
            }
         }
      }}.runTaskLater(plugin, 20*3);
   }
}}.runTaskLater(plugin, 20*3);

Additional Notes:

  • Affects other BlockState types (like chests), not just signs
  • Occurs even without using scheduled tasks
  • Might be related to SPIGOT-1511

Debug messages from example code:

 



 Comments   
Comment by blablubbabc [ 13/Apr/17 ]

Though, the description of the 'force' parameter in the update method doesn't make much sense if resetting the block state (including its tile entity data) isn't actually supported: "If force is true, it will set the type of the block to match the new state, set the state data and then return true."

And 'the block state becomes invalid' could also only have meant 'the block state does no longer represent data for the current block type'. Having the 'force' parameter exist solely for this situation is letting it appear even more that it is supposed to be able to fully reset the block's state.

But regardless of that, BlockState would be a more useful part of the API if it actually could properly restore the block's state in this case. The typical usecase would be for plugins to be able to restore blocks without having to maintain their own BlockState-like implementations.

A possible fix might be to get the current TileEntity at that position from the world, after the block type has been updated. And then copy the BlockState's data to that TileEntity, instead of using the reference to the 'old', no longer existing TileEntity. (as one can see here: https://hub.spigotmc.org/stash/projects/SPIGOT/repos/craftbukkit/browse/src/main/java/org/bukkit/craftbukkit/block/CraftSign.java#50)

I would be willing to prepare a pull request for this if you don't see an issue with this fix.

 

Comment by md_5 [ 12/Apr/17 ]

This actually isn't a supported behaviour, the Javadoc makes this clear:

 * Unlike Block, which only one object can exist per coordinate, BlockState
 * can exist multiple times for any given Block. Note that another plugin may
 * change the state of the block and you will not know, or they may change the
 * block to another type entirely, causing your BlockState to become invalid.

change the block to another type entirely, causing your BlockState to become invalid.

Comment by md_5 [ 11/Apr/17 ]

Signs should be ok with this, not sure why they aren't, but other block entities operate in a myriad of ways.
Some store data and work with this pattern, others don't and won't without breaking changes.

Generated at Tue Apr 22 06:38:50 UTC 2025 using Jira 10.3.5#10030005-sha1:190c783f2bd6c69cd5accdb70f97e48812a78d14.