Jump to content

[1.10.2] [SOLVED] Changing block state wipes out tile entity data?


Daeruin

Recommended Posts

I have a block with a tile entity. The block has several different states. In the block's onBlockActivated, when it is clicked on with a specific item, I want to change the block to a different state and set off a timer in my tile entity. I can get the timer part to work on its own, but when I change the block's state, the timer seems to be wiped out.

 

ModBlock#onBlockActivated

@Override
public boolean onBlockActivated(World world, BlockPos pos, IBlockState state, EntityPlayer player, EnumHand hand, ItemStack heldItem, EnumFacing side, float hitX, float hitY, float hitZ)
{
	if (world.isRemote)
	{
			// spawn particles
			return false;
		}
		else return true;
	}
	else
	{
		TileEntity tileEntity = world.getTileEntity(pos);
		if (heldItem != null)
		{
			if (heldItem.getItem() instanceof PrimalItemGlowingEmber && state.getValue(CAMPFIRE_STATE) == EnumCampfireState.TINDER)
			{
				if (((PrimalTileEntityCampfire) tileEntity).tinderStokeTime == 0)
				{
					((PrimalTileEntityCampfire) tileEntity).tinderStokeTime = 60;
					world.setBlockState(pos, getDefaultState().withProperty(CAMPFIRE_STATE, EnumCampfireState.TINDER_STOKED));
				}
				return false;
			}
		return true;
	}
}

 

ModTileEntity#update

public void update()
{
	if (!this.world.isRemote)
	{
		EnumCampfireState campfireState = world.getBlockState(this.pos).getValue(PrimalBlockCampfire.CAMPFIRE_STATE);
		if (this.tinderStokeTime > 0)
		{
			--this.tinderStokeTime;
		}
}

 

If I remove the "world.setBlockState..." line from onBlockActivated, the timer variable gets set and decrements correctly. As soon as I add that line back in, the variable doesn't get set correctly (or gets reset somehow). I didn't think the state of my block would have anything to do with the tile entity data.

Edited by Daeruin
Link to comment
Share on other sites

By default, mod TileEntities are replaced any time the block state changes. To change this, override TileEntity#shouldRefresh to return true when the Blocks of the old and the new IBlockStates are different.

  • Like 2

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Link to comment
Share on other sites

Did you edit your ModBlock#onBlockActivated before posting it here? Because the way it is currently would not even compile.

VANILLA MINECRAFT CLASSES ARE THE BEST RESOURCES WHEN MODDING

I will be posting 1.15.2 modding tutorials on this channel. If you want to be notified of it do the normal YouTube stuff like subscribing, ect.

Forge and vanilla BlockState generator.

Link to comment
Share on other sites

55 minutes ago, Choonster said:

By default, mod TileEntities are replaced any time the block state changes. To change this, override TileEntity#shouldRefresh to return true when the Blocks of the old and the new IBlockStates are different.

Thank you, I'll try that and let you know how it goes!

Link to comment
Share on other sites

Worked like a charm! However, I have a question about this comment in the documentation:

 

Quote

Use with caution as this will leave straggler TileEntities, or create conflicts with other TileEntities if not used properly.

What does that mean? How should I "use it properly"?

Link to comment
Share on other sites

15 minutes ago, Daeruin said:

Worked like a charm! However, I have a question about this comment in the documentation:

 

What does that mean? How should I "use it properly"?

 

Don't return false when the Block changes, otherwise your Block's TileEntity will remain after the IBlockState at its position was replaced with another.

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Link to comment
Share on other sites

I think I've got it. I should have read your earlier comment more carefully. It seems like you could either check that the old and new block from the IBlockStates are NOT the same, and return true, else return false, like this:

 

    @Override

    public boolean shouldRefresh(World world, BlockPos pos, IBlockState oldState, IBlockState newState)

    {

        if (oldState.getBlock() != newState.getBlock()) return true;

        else return false;

    }

 

Or check that the old and new block ARE the same, and return false. But don't just return false every time.

Link to comment
Share on other sites

1 hour ago, Daeruin said:

I think I've got it. I should have read your earlier comment more carefully. It seems like you could either check that the old and new block from the IBlockStates are NOT the same, and return true, else return false, like this:

 

    @Override

    public boolean shouldRefresh(World world, BlockPos pos, IBlockState oldState, IBlockState newState)

    {

        if (oldState.getBlock() != newState.getBlock()) return true;

        else return false;

    }

 

Or check that the old and new block ARE the same, and return false. But don't just return false every time.

 

That's correct.

 

When you have a method that does if (some_boolean_expression) return true; else return false;, you can simplify it to return some_boolean_expression;.

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Link to comment
Share on other sites

There might be some corner cases where your block's shouldRefresh is called when your block is not even there (or when one instance is replaced by another, depending on how your mod functions and how you might extend the block class later). Therefore, rather than just checking for a changed block, you might check whether the old and new blocks are your block (or instanceof).

The debugger is a powerful and necessary tool in any IDE, so learn how to use it. You'll be able to tell us more and get better help here if you investigate your runtime problems in the debugger before posting.

Link to comment
Share on other sites

18 hours ago, Choonster said:

When you have a method that does if (some_boolean_expression) return true; else return false;, you can simplify it to return some_boolean_expression;.

 

How . . . logical.

 

9 hours ago, jeffryfisher said:

There might be some corner cases where your block's shouldRefresh is called when your block is not even there (or when one instance is replaced by another, depending on how your mod functions and how you might extend the block class later). Therefore, rather than just checking for a changed block, you might check whether the old and new blocks are your block (or instanceof).

 

I'm not sure if those corner cases would ever apply to me, but just to be safe I changed it:

 

@Override
public boolean shouldRefresh(World world, BlockPos pos, IBlockState oldState, IBlockState newState)
{
    return !(oldState.getBlock() instanceof <myblock> && newState.getBlock() instanceof <myblock>);
}

 

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Announcements



×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.