Jump to content
View in the app

A better way to browse. Learn more.

Forge Forums

A full-screen app on your home screen with push notifications, badges and more.

To install this app on iOS and iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
To install this app on Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.

Featured Replies

Posted

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

  • 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 ?

  • 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.

  • 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.

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...

Important Information

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

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.