This is an old revision of the document!
添加一个方块实体
介绍
BlockEntity主要用于在块内存储数据。 在创建一个之前,您需要一个 Block。 本教程将介绍BlockEntity类的创建及其注册。
创建一个方块实体
最简单的方块实体仅扩展BlockEntity
,并使用默认构造函数。 这是完全有效的,但不会给予方块任何特殊功能。
public class DemoBlockEntity extends BlockEntity { public DemoBlockEntity() { super(ExampleMod.DEMO_BLOCK_ENTITY); } }
下面将向您展示如何创建ExampleMod.DEMO_BLOCK_ENTITY
字段。
您可以简单地向此准系统类添加变量,或实现诸如Tickable
和Inventory
之类的接口以添加更多功能。Tickable
提供了一个单独的tick()
方法,该方法将会在世界加载的每一刻调用一次。而Inventory
则允许您的BlockEntity与自动化进行交互,例如漏斗——稍后可能会有专门针对此接口的单独教程。
注册你的方块实体
一旦创建了BlockEntity
类,您将需要对其进行注册以使其起作用。 此过程的第一步是创建一个BlockEntityType
,它将Block
和BlockEntity
链接在一起。 假设您的Block
已创建并保存到本地变量DEMO_BLOCK
,则将在下面的行中创建匹配的BlockEntityType
。 modid:demo
应替换为您的Mod ID和您要在其下注册BlockEntity
的名称。
BlockEntityType
应在您的onInitialize
方法中注册,以确保它在正确的时候被注册。
public static BlockEntityType<DemoBlockEntity> DEMO_BLOCK_ENTITY; @Override public void onInitialize() { DEMO_BLOCK_ENTITY = Registry.register(Registry.BLOCK_ENTITY_TYPE, "modid:demo", BlockEntityType.Builder.create(DemoBlockEntity::new, DEMO_BLOCK).build(null)); }
将方块实体连接到方块
一旦创建并注册了BlockEntityType
,就可以在Block
类中简单地实现BlockEntityProvider
。每次放置方块,就会产生对应的方块实体。
public class MyBlock extends Block implements BlockEntityProvider { [...] @Override public BlockEntity createBlockEntity(BlockView blockView) { return new DemoBlockEntity(); } }
序列化数据
如果要将任何数据存储在BlockEntity
中,则需要保存并加载,或者仅在加载BlockEntity
时保留,并且只要您返回到它。幸运的是,保存和加载非常简单——只需要覆盖toTag()
和fromTag()
即可。
toTag()
返回一个CompoundTag
,其中应包含BlockEntity
中的所有数据。如果您需要将BlockEntity
数据与客户端同步,则此数据将保存到磁盘并通过数据包发送。调用toTag
的默认实现非常重要,因为它将“标识数据(Identifying data)(位置和ID)
保存到标签中。否则,您尝试保存的所有其他数据都将丢失,因为它与位置和BlockEntityType
不相关。知道了这一点,下面的示例演示了如何将BlockEntity
中的整数保存到标签中。在此示例中,整数保存在键number
下——您可以将其替换为任何字符串,但是标签中的每个键只能有一个条目(entry),并且需要记住该键以便以后检索数据。
public class DemoBlockEntity extends BlockEntity { // 储存数字的当前值 private int number = 7; public DemoBlockEntity() { super(ExampleMod.DEMO_BLOCK_ENTITY); } // 序列化方块实体 @Override public CompoundTag toTag(CompoundTag tag) { super.toTag(tag); // Save the current value of the number to the tag tag.putInt("number", number); return tag; } }
为了以后检索数据,您还需要覆盖fromTag
。 此方法与toTag
相反-不会将数据保存到CompoundTag
,而是为您提供了之前保存的标签,使您可以检索所需的任何数据。 与toTag
一样,必须调用super.fromTag
,并且您将需要使用相同的键来检索保存的数据。 要检索我们之前保存的号码,请参见下面的示例。
// 取消序列化方块实体 @Override public void fromTag(BlockState state, CompoundTag tag) { super.fromTag(state, tag); number = tag.getInt("number"); }
一旦实现了toTag
和fromTag
方法,您只需要确保在正确的时间调用它们即可。每当您的BlockEntity
数据发生更改并需要保存时,请调用markDirty()
。这会通过标记方块所在的区块为dirty,在世界下次保存时强制调用toTag
方法。原则上,只要改变了BlockEntity
类中的任何一个自定义变量,就只需要简单调用markDirty
。
如果您需要将某些BlockEntity
数据同步到客户端,出于渲染等目的,则应从Fabric API中实现BlockEntityClientSerializable
。此类提供了fromClientTag
和toClientTag
方法,其作用与前面讨论的fromTag
和toTag
方法基本相同,只是专门用于发送和接收客户端上的数据。
Overview
现在,您应该拥有自己的BlockEntity
,可以按照各种方式扩展它以适应您的需求。 您注册了BlockEntityType
,并用它来将Block
和BlockEntity
类连接在一起。 然后,您在Block
类中实现了BlockEntityProvider
,并使用该接口提供了新BlockEntity
的实例。 最后,您学习了如何将数据保存到BlockEntity
中,以及如何检索以备后用。