本篇教程参考为的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用来实现“带方块实体的方块”的基类。它相当于把Block和BlockEntity这条链打通的桥梁 它可以标记这个方块有 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(...):方块被替换/破坏时处理实体清理或掉落逻辑







暂无评论内容