Posted May 15, 20223 yr Hello guys, I'm trying to make a mod that adds auto miner block. To do this I created a block and a block entity that save the itemStack when a user right click on the block (the auo miner will generate item depending on the itemStack set), and I need to save this itemstack in order to keep it even after a game restart. If I understood correctly, we need to use the "saveAdditional" function in order to save some tag on the entity. The thing is, how do you trigger this function everytime a user right click on the corresponding block entity ? In my case this function is sometimes called when we right click on the block entity and sometimes it takes many seconds before the function is called. Just below it's the saveAdditional fuction I'm using in a class that extends BlockEntity. @Override protected void saveAdditional(CompoundTag pTag) { if (target != null) { System.out.println("target not null"); pTag.put("target", target.serializeNBT()); } super.saveAdditional(pTag); } Thanks
May 15, 20223 yr Author Thanks @diesieben07 for your answer. I noticed that when I apply a modification on the BlockEntity and immediately exit the game, the state of the blockEntity is not properly saved. It seems that it takes some seconds for the game to save it, but sometime it is immediately saved. Is there a way to avoid that ?
May 15, 20223 yr Author I have 2 classes : Miner (extends BaseEntityBlock) and MinerEntity (extends BlockEntity). Miner Spoiler public class Miner extends BaseEntityBlock { private Block target; private Level level; private BlockPos pos; private Timer miningTimer; public Miner() { super(BlockBehaviour.Properties.of(Material.STONE).strength(5f)); } @Override public void setPlacedBy(Level pLevel, BlockPos pPos, BlockState pState, @Nullable LivingEntity pPlacer, ItemStack pStack) { super.setPlacedBy(pLevel, pPos, pState, pPlacer, pStack); if (!pLevel.isClientSide()) { pPlacer.sendMessage(new TextComponent("Placed"), pPlacer.getUUID()); level = pLevel; pos = pPos; miningTimer = new Timer(); } } public void initialiseMining() { if (miningTimer != null) { miningTimer.cancel(); } miningTimer = new Timer(); miningLoop(); } public void mine() { Block.dropResources(target.defaultBlockState(), level, pos.above()); } public void miningLoop() { miningTimer.schedule(new TimerTask() { @Override public void run() { mine(); } }, 0, 1000); } public void cancelMining() { miningTimer.cancel(); } public Block getTarget() { return target; } public void setTarget(Block target) { this.target = target; } @Override public RenderShape getRenderShape(BlockState pState) { return RenderShape.MODEL; } @Override public void onRemove(BlockState pState, Level pLevel, BlockPos pPos, BlockState pNewState, boolean pIsMoving) { super.onRemove(pState, pLevel, pPos, pNewState, pIsMoving); } @Override public InteractionResult use(BlockState pState, Level pLevel, BlockPos pPos, Player pPlayer, InteractionHand pHand, BlockHitResult pHit) { if (!pLevel.isClientSide()) { BlockEntity entity = pLevel.getBlockEntity(pPos); if (entity instanceof MinerEntity miner) { if (!pPlayer.isCrouching()) { ItemStack nextTarget = pPlayer.getItemInHand(pHand); pPlayer.sendMessage(new TextComponent("Item in hand : " + nextTarget.getDisplayName().getString()), pPlayer.getUUID()); miner.setTarget(nextTarget); } else { ItemStack currentTarget = miner.getTarget(); if (currentTarget != null) { pPlayer.sendMessage(new TextComponent("Item set : " + currentTarget.getDisplayName().getString()), pPlayer.getUUID()); } else { pPlayer.sendMessage(new TextComponent("No Item has been set"), pPlayer.getUUID()); } } } } return InteractionResult.sidedSuccess(pLevel.isClientSide()); } @Nullable @Override public <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level pLevel, BlockState pState, BlockEntityType<T> pBlockEntityType) { return (level0, pos, state0, blockEntity) -> ((MinerEntity) blockEntity).tick(); } @Nullable @Override public BlockEntity newBlockEntity(BlockPos pPos, BlockState pState) { return new MinerEntity(pPos, pState); } } MinerEntity Spoiler public class MinerEntity extends BlockEntity { private ItemStack target; private boolean requiresUpdate; private final ItemStackHandler itemHandler = new ItemStackHandler(1) { @Override protected void onContentsChanged(int slot) { setChanged(); } }; private LazyOptional<IItemHandler> lazyItemHandler = LazyOptional.empty(); public MinerEntity(BlockPos pWorldPosition, BlockState pBlockState) { super(BlockEntitiesManager.MINER_ENTITY.get(), pWorldPosition, pBlockState); this.requiresUpdate = false; } @NotNull @Override public <T> LazyOptional<T> getCapability(@NotNull Capability<T> cap, @Nullable Direction side) { if (cap == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) { return lazyItemHandler.cast(); } return super.getCapability(cap, side); } @Override public void onLoad() { super.onLoad(); lazyItemHandler = LazyOptional.of(() -> itemHandler); } @Override public void invalidateCaps() { super.invalidateCaps(); lazyItemHandler.invalidate(); } @Override protected void saveAdditional(CompoundTag pTag) { if (target != null) { System.out.println("target not null"); pTag.put("target", target.serializeNBT()); } super.saveAdditional(pTag); } @Override public void load(CompoundTag pTag) { super.load(pTag); itemHandler.deserializeNBT(pTag.getCompound("inventory")); if (!(pTag.getCompound("target").isEmpty())) { System.out.println("Load target is not empty " + pTag.getCompound("target")); target = ItemStack.of(pTag.getCompound("target")); } } @Override public void onDataPacket(Connection net, ClientboundBlockEntityDataPacket pkt) { load(pkt.getTag()); super.onDataPacket(net, pkt); } @Override public void setRemoved() { super.setRemoved(); } @Override public ClientboundBlockEntityDataPacket getUpdatePacket() { return ClientboundBlockEntityDataPacket.create(this); } @Override public CompoundTag getUpdateTag() { return serializeNBT(); } @Override public void handleUpdateTag(CompoundTag tag) { load(tag); super.handleUpdateTag(tag); } public ItemStack getCurrentTarget() { return itemHandler.getStackInSlot(0); } public void update() { requestModelDataUpdate(); setChanged(); if (this.level != null) { this.level.setBlockAndUpdate(this.worldPosition, getBlockState()); } } public void tick() { System.out.println("ticked, requiresUpdate = " + this.requiresUpdate); if(this.requiresUpdate) { update(); this.requiresUpdate = false; } } public void drops() { SimpleContainer inventory = new SimpleContainer(itemHandler.getSlots()); for (int i = 0; i < itemHandler.getSlots(); i++) { inventory.setItem(i, itemHandler.getStackInSlot(i)); } Containers.dropContents(this.level, this.worldPosition, inventory); } public void setTarget(ItemStack target) { this.target = target; this.requiresUpdate = true; } public ItemStack getTarget() { return target; } } Everytime a user right click on Miner block, it calls MinerEntity#update. When debugging I noticed that when I call setChanged(), it takes many seconds to print "target not null" in the terminal.
May 15, 20223 yr Author @diesieben07 thanks for all your answers, it is way clear for me now. Also, I cleaned up my code and it seems to work (target is properly saved when I leave the game).
May 15, 20223 yr Author Hey just another question : In case MinerEntity needs to perform an action every 5 seconds, how do I need to proceed ?
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.