[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: |
![]() |
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:
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. |