NeoForge-1.20.4Mod开发教程之第一个方块实体和其数据保存

本篇教程参考为Flandre芙兰的NeoForge1.20.4Mod开发的视频,这篇教程是我边学边总结的,与其说是教程更像我的学习笔记,如有不清楚的地方,大家可以在评论区提问。在我力所能及的范围内,我都会解答的。

 

创建RubyCounter类

public class RubyCounter extends BaseEntityBlock {
     public RubyCounter() {
         super(Properties.ofFullCopy(Blocks.STONE));
    }
 ​
     @Override
     protected MapCodec<? extends BaseEntityBlock> codec() {//方块的构造说明书
         return null;
    }
 ​
     @Override
     public @Nullable BlockEntity newBlockEntity(BlockPos pos, BlockState state) {//当方块被放置时,游戏会调用这个方法来创建方块实体
         return new CounterBlockEntity(pos, state);
    }
 ​
     @Override
     public InteractionResult use(BlockState state, Level level, BlockPos pos, Player player,
                                  InteractionHand hand, BlockHitResult hit) {//右键交互逻辑
         if (!level.isClientSide) {
             var be = level.getBlockEntity(pos);//获取交互的方块实体
             if (be instanceof CounterBlockEntity counterBe) {//判断是不是CounterBlockEntity类型
                 int counter = counterBe.increase();//计数+1
                 player.sendSystemMessage(Component.literal("counter:" + counter));//Component点translatable的话,需要翻译键值
            }
        }
         return InteractionResult.SUCCESS;
    }
 ​
     @Override
     public RenderShape getRenderShape(BlockState pState) {//表示用普通的方块模型渲染
         return RenderShape.MODEL;
    }
 }

语言文件

"xxx.xxx.xxx": "计数: %d"

 

创建CounterBlockEntity类

public class CounterBlockEntity extends BlockEntity {
     private int counter = 0;
 ​
     public CounterBlockEntity(BlockPos pPos, BlockState pBlockState) {
         super(ModBlockEntities.RUBY_COUNTER_BLOCK_ENTITY.get(), pPos, pBlockState);
    }
 ​
     public int increase(){//计数
         counter ++;
         setChanged();//标记数据已修改,通知存储系统下次保存
         return counter;
    }
 ​
     @Override
     public void load(CompoundTag tag) {//反序列化:从NBT里读取 counter
         super.load(tag);
         counter = tag.getInt("counter");
    }
 ​
     @Override
     protected void saveAdditional(CompoundTag tag) {//序列化:把counter写入 NBT
         super.saveAdditional(tag);
         tag.putInt("counter", counter);
    }
 ​
 }

序列化就是把“内存里的对象/数据结构”转成可以存储或传输的格式(比如字节流、JSON、NBT)。 反序列化就是把这些格式再还原回内存里的对象。 类比:把桌上的积木搭建成果拍照保存(序列化),以后根据照片再搭回去(反序列化)。

 

创建ModBlockEntities类

public class ModBlockEntities {
 ​
     public static final DeferredRegister<BlockEntityType<?>> BLOCK_ENTITIES =//方块实体注册器
             DeferredRegister.create(Registries.BLOCK_ENTITY_TYPE, ExampleMod.MODID);
 ​
     public static final Supplier<BlockEntityType<CounterBlockEntity>> RUBY_COUNTER_BLOCK_ENTITY =
             BLOCK_ENTITIES.register("ruby_counter_block_entity", () ->
                     BlockEntityType.Builder.of(CounterBlockEntity::new,
                             ModBlocks.RUBY_COUNTER.get()).build(null));//告诉系统如何创建哪个实体,并指定哪些方块会使用这个方块实体类型。build参数用于用于旧存档升级,一般为null
 ​
     public static void register(IEventBus eventBus) {
         BLOCK_ENTITIES.register(eventBus);
    }
 }

 

类和概念介绍

BlockEntity(方块实体)是Minecraft 用来给“方块”挂载数据和逻辑的机制。它不是方块本身,而是附着在方块上的“数据容器 + 行为载体” 核心概念

方块(Block):只表示静态外观和基本行为(硬度、掉落、碰撞等),不存复杂数据;方块实体(BlockEntity):给方块增加持久化数据、复杂逻辑、定时更新、客户端渲染等能力

方块实体常见用途:

1.需要保存数据:箱子物品、熔炉进度、这里的 counter

2.需要复杂逻辑:机器加工、能量系统、计时器

3.需要特殊渲染:展示物品、动态模型

生命周期简述:

1)放置带实体的方块 → 调用 newBlockEntity 创建 BlockEntity

2)存档保存 → 调用 saveAdditional 写入 NBT

3)存档读取 → 调用 load 读回 NBT

4)区块卸载/加载时自动管理

BlockEntity类中常用方法:

load(CompoundTag tag):读取 NBT 数据(反序列化),世界/区块加载时调用

saveAdditional(CompoundTag tag):写入自定义 NBT 数据(序列化),区块保存时调用

setChanged():标记数据已修改,让系统在合适时机保存并触发同步逻辑

getUpdateTag():返回用于客户端同步的 NBT(默认会调用 saveAdditional 的结果)

getUpdatePacket():返回网络包,用于服务端把实体数据推送到客户端

onLoad():方块实体被加载到世界时调用(适合初始化)

setRemoved() / clearRemoved():控制实体被移除/恢复的状态

 

BaseEntityBlock 是Minecraft用来实现“带方块实体的方块”的基类。它相当于把BlockBlockEntity这条链打通的桥梁 它可以标记这个方块有 BlockEntity,让引擎在方块放置、加载、渲染、交互时,能正确创建并管理 BlockEntity

作用

1)创建方块实体,通过 newBlockEntity(BlockPos, BlockState),这是最关键的抽象方法,必须返回你自己的 BlockEntity

2)定义渲染形态,getRenderShape 决定用模型、实体动画或不可见。对于普通模型通常返回 RenderShape.MODEL

3)提供 codec(1.20+),codec() 返回 MapCodec,用于方块序列化/反序列化(注册表、数据驱动加载)

4)提供 tick 行为,可override getTicker 给方块实体提供 tick 更新逻辑。用于需要每 tick 更新的方块实体

常见重写方法

newBlockEntity(...):创建 BlockEntity 实例

codec():返回 MapCodec

getRenderShape(...):控制渲染方式

getTicker(...):给BlockEntity 提供 tick 更新

onRemove(...):方块被替换/破坏时处理实体清理或掉落逻辑

© 版权声明
THE END
喜欢就支持一下吧
点赞6赞赏 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容