Ломание блока с большой моделью через dummy блок

Версия Minecraft
1.26.3
API
NeoForge
55
7
3
У меня в моде есть блоки у которых модель занимает больше 1 блока, в тех местах где модель выходит за размеры основного блока я ставлю dummy блоки. Dummy все убираются при разрушении основного блока а если сломан dummy то он посылает сигнал основному блоку доломать все остальные. В креативе всё работает а в выживании если начать ломать dummy тогда его обводка начинает мигать и ничего не ломается (если сломать основной то все работает)

Код Dummy:
public class DummyBlock extends Block implements EntityBlock {
    public DummyBlock(Properties properties) {
        super(properties.noOcclusion().noLootTable());
    }

    @Override
    public @Nullable BlockEntity newBlockEntity(@NonNull BlockPos blockPos, @NonNull BlockState blockState) {
        return new DummyBlockEntity(blockPos, blockState);
    }

    //Logic start

    @Override
    public void spawnDestroyByEntityParticles(Level level, @Nullable Entity entity, @NonNull BlockPos pos, @NonNull BlockState state) {
        BlockState parent = level.getBlockState(getParentPos(level, pos));
        level.levelEvent(LevelEvent.PARTICLES_DESTROY_BLOCK, pos, getId(parent));
    }

    @Override
    protected @NonNull RenderShape getRenderShape(@NonNull BlockState state) {
        return RenderShape.INVISIBLE;
    }

    @Override
    protected VoxelShape getVisualShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
        return super.getVisualShape(state, level, pos, context);
    }

//    @Override TODO finish
//    protected @NonNull VoxelShape getShape(@NonNull BlockState state, @NonNull BlockGetter level, @NonNull BlockPos pos, @NonNull CollisionContext context) {
//        return level.getBlockState(getParentPos(level, pos)).getBlock().defaultBlockState().getShape(level, getParentPos(level, pos)).move(pos.getX() - getParentPos(level, pos).getX(), pos.getY() - getParentPos(level, pos).getY(), pos.getZ() - getParentPos(level, pos).getZ());
//    }

    @Override
    protected float getDestroyProgress(@NonNull BlockState state, @NonNull Player player, BlockGetter level, @NonNull BlockPos pos) {//TODO implement
        return level.getBlockState(getParentPos(level, pos)).getDestroyProgress(player, level, getParentPos(level, pos));
    }

    @Override
    protected @NonNull InteractionResult useWithoutItem(@NonNull BlockState state, Level level, @NonNull BlockPos pos, @NonNull Player player, BlockHitResult hitResult) {
        return level.getBlockState(getParentPos(level, pos)).useWithoutItem(level, player, hitResult.withPosition(getParentPos(level, pos)));
    }

    @Override
    protected @NonNull InteractionResult useItemOn(@NonNull ItemStack itemStack, @NonNull BlockState state, Level level, @NonNull BlockPos pos, @NonNull Player player, @NonNull InteractionHand hand, BlockHitResult hitResult) {
        return level.getBlockState(getParentPos(level, pos)).useItemOn(itemStack, level, player, hand, hitResult.withPosition(getParentPos(level, pos)));
    }

    @Override
    public boolean onDestroyedByPlayer(@NonNull BlockState state, @NonNull Level level, @NonNull BlockPos pos, @NonNull Player player, @NonNull ItemStack toolStack, boolean willHarvest, @NonNull FluidState fluid) {
        BlockPos parentPos = getParentPos(level, pos);
        if (level.getBlockState(parentPos).getBlock() instanceof BigBlock) {
            level.getBlockState(parentPos).getBlock().playerWillDestroy(level, parentPos, state, player);
            level.destroyBlock(parentPos, !player.isCreative());
        }
        level.removeBlock(pos, false);
        return false;
    }

    @Override
    public @NonNull BlockState playerWillDestroy(@NonNull Level level, @NonNull BlockPos pos, @NonNull BlockState state, @NonNull Player player) {
        return super.playerWillDestroy(level, pos, state, player);
    }

    @Override
    public void onBlockExploded(@NonNull BlockState state, ServerLevel level, @NonNull BlockPos pos, @NonNull Explosion explosion) {//TODO finish
        BigBlock.ExplosionResult result = ((BigBlock) level.getBlockState(getParentPos(level, pos)).getBlock()).dummyExploded(level, pos, explosion);
        if (result == BigBlock.ExplosionResult.DESTROY) level.getBlockState(getParentPos(level, pos)).onBlockExploded(level, pos, explosion);
    }

    public void setParentPos(BlockGetter level, BlockPos pos, BlockPos parentPos) {
        DummyBlockEntity dummyEntity = (DummyBlockEntity) level.getBlockEntity(pos);
        dummyEntity.setParent(parentPos);
    }

    public BlockPos getParentPos(BlockGetter level, BlockPos sourcePos) {
        DummyBlockEntity dummyEntity = (DummyBlockEntity) level.getBlockEntity(sourcePos);
        return dummyEntity.getParent();
    }
}

Код основного блока:
public abstract class BigBlock extends BaseEntityBlock {
    protected BlockPos[] dummyPositions = new BlockPos[0];

    public BigBlock(Properties properties) {
        super(properties);
    }

    @Override
    public @Nullable BlockState getStateForPlacement(@NonNull BlockPlaceContext context) {
        for (BlockPos dummy : dummyPositions) {
            if (!context.getLevel().getBlockState(blockPosWithOffset(context.getClickedPos(), dummy)).isAir()) return null;
        }
        return super.getStateForPlacement(context);
    }

    @Override
    public void setPlacedBy(@NonNull Level level, @NonNull BlockPos pos, @NonNull BlockState state, @Nullable LivingEntity by, @NonNull ItemStack itemStack) {
        super.setPlacedBy(level, pos, state, by, itemStack);
        placeDummies(level, pos);
    }

    @Override
    public @NonNull BlockState playerWillDestroy(@NonNull Level level, @NonNull BlockPos pos, @NonNull BlockState state, @NonNull Player player) {
        removeDummies(level, pos);
        return super.playerWillDestroy(level, pos, state, player);
    }

    @Override
    public void onBlockExploded(@NonNull BlockState state, @NonNull ServerLevel level, @NonNull BlockPos pos, @NonNull Explosion explosion) {
        removeDummies(level, pos);
        super.onBlockExploded(state, level, pos, explosion);
    }

    protected void placeDummies(Level level, BlockPos pos) {
        if (level.isClientSide()) return;
        for (BlockPos dummy : dummyPositions) {
            BlockPos withOffset = blockPosWithOffset(pos, dummy);
            level.setBlock(withOffset, TechBlocks.DUMMY.get().defaultBlockState(), 3);
            ((DummyBlock) level.getBlockState(withOffset).getBlock()).setParentPos(level, withOffset, pos);
        }
    }

    protected void removeDummies(Level level, BlockPos pos) {
        for (BlockPos dummy : dummyPositions) {
            if (level.getBlockState(blockPosWithOffset(pos, dummy)).is(TechBlocks.DUMMY)) {
                level.levelEvent(LevelEvent.PARTICLES_DESTROY_BLOCK, blockPosWithOffset(pos, dummy), getId(level.getBlockState(blockPosWithOffset(pos, dummy))));
                level.removeBlock(blockPosWithOffset(pos, dummy), false);
            }
        }
    }

    protected void setDummyPositions(BlockPos... positions) {
        dummyPositions = new BlockPos[positions.length];
        System.arraycopy(positions, 0, dummyPositions, 0, positions.length);
    }

    public abstract ExplosionResult dummyExploded(Level level, BlockPos dummyPos, Explosion explosion);

    protected BlockPos blockPosWithOffset(BlockPos pos, BlockPos offset) {
        return new BlockPos(pos.getX() + offset.getX(), pos.getY() + offset.getY(), pos.getZ() + offset.getZ());
    }

    public enum ExplosionResult {
        DESTROY,
        CHANGE_MODEL
    }
Подскажите, где смотреть или что исправить
 
Например документация к блок-энтити.

Можно и так:

DummyBlockEntity:
public class DummyBlockEntity extends BlockEntity {
    private @Nullable BlockPos parent;

    public DummyBlockEntity(BlockPos pos, BlockState state) {
        super(TechBlockEntities.DUMMY.get(), pos, state);
    }

    public @Nullable BlockPos getParent() { return parent; }

    public void setParent(BlockPos parent) {
        this.parent = parent;
        setChanged();
        if (level != null && !level.isClientSide()) {
            level.sendBlockUpdated(worldPosition, getBlockState(), getBlockState(), Block.UPDATE_CLIENTS);
        }
    }

    @Override
    protected void saveAdditional(ValueOutput output) {
        super.saveAdditional(output);
        output.storeNullable("parent", BlockPos.CODEC, parent);
    }

    @Override
    protected void loadAdditional(ValueInput input) {
        super.loadAdditional(input);
        parent = input.read("parent", BlockPos.CODEC).orElse(null);
    }

    @Override
    public CompoundTag getUpdateTag(HolderLookup.Provider registries) {
        return saveWithoutMetadata(registries); // данные для клиента при загрузке чанка
    }

    @Override
    public Packet<ClientGamePacketListener> getUpdatePacket() {
        return ClientboundBlockEntityDataPacket.create(this);     // пакет, который уходит после sendBlockUpdated
    }
}
 
Назад
Сверху