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

BlockState.update() only updates TileEntity if the state already holds the correct TileEntity

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Fixed
    • Icon: Minor Minor
    • None
    • None

      Keep in mind that I'm using a "Sign" just to demonstrate the bug,
      but it is the same for all blocks with TileEnitities like Chests, Banners, etc.

      I have provided a solution to fix it inside Craftbukkit at the end of the description.
      Shouldn't be much to do.

      Example Code

      public void createSign(Block block)
      {
      	block.setType(Material.SIGN_POST);
      	Sign sign = (Sign)block.getState();
      	sign.setLine(0, "test");
      	sign.update();
      }
      
      public void testBug(Block block)
      {
      	//create a sign with "test" in first line	
      	createSign(block);
      	
      	//now remember the block state, so we can restore changes to the block later on
      	BlockState state = block.getState();
      	
      	//a wild minecrafter appears and replaces the sign with another block (e.g. dirt)
      	block.setType(Material.DIRT);
      	
      	//now some time has passed and we want to FORCE restore the old state.
      	state.update(true);
      	
      	//The sign and it's orientation got restored (due to material id and data byte getting force-set)
      	//But, alas, the signs text did NOT!
      	
      	
      	/*
      	 * WORKAROUND in USER-CODE
      	 */
      
      	//we can workaround this quite easily in user-code:
      	//I figured out the text is actually updated in the source code (CraftSign.java),
      	//but it seems like it isn't displayed.
      	//This is because the old TileEntity saved in the BlockState gets updated, and not the one created by the block-change.
      	
      	//So what we have to do is either use the new blockstate and call:
      	state.update(true);
      	Sign new_state = (Sign)block.getState();
      	new_state.setLine(0, old_state.getLine(0));
      	//repeat this for all the data saved in the TileEntity (e.g. Skulls have a orientation)
      	//and finally:
      	new_state.update();
      }
      

      FIX in Craftbukkit:

      My suggestion to fix this is to also update the newly created tile entity
      when a blockstate gets force-updated via update(true);

      Example for CraftSign.java. would have to be repeated for all TileEntity-BlockStates:

      /**
       * CODE COPIED from current craftbukkit-build
       */
      @Override
      public boolean update(boolean force, boolean applyPhysics) {
      	boolean result = super.update(force, applyPhysics);
      
      	if (result) {
      		//FIX -- HERE
      		if (force)
      		{
      			//update the internal tile-entity to the one created by minecraft
      			sign = ...;
      		}
      		//FIX END
      		
      		IChatBaseComponent[] newLines = sanitizeLines(lines);
      		System.arraycopy(newLines, 0, sign.lines, 0, 4);
      		sign.update();
      	}
      
      	return result;
      }
      

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

              Created:
              Updated:
              Resolved: