User Tools

Site Tools


zh_cn:tutorial:blockentity

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
zh_cn:tutorial:blockentity [2024/08/27 02:14] solidblockzh_cn:tutorial:blockentity [2025/04/01 12:20] (current) – [方块实体刻] solidblock
Line 30: Line 30:
     [...]     [...]
          
-    public static final DemoBlock DEMO_BLOCK = register("demo_block", new DemoBlock(AbstractBlock.Settings.create()));+    // 对于 1.21.2 之前的版本 
 +    // public static final DemoBlock DEMO_BLOCK = register("demo_block", new DemoBlock(AbstractBlock.Settings.create())); 
 +     
 +    // 对于 1.21.2 及之后的版本 
 +    public static final DemoBlock DEMO_BLOCK = register("demo_block", DemoBlock::new, AbstractBlock.Settings.create());
          
     [...]     [...]
Line 44: Line 48:
   public static final BlockEntityType<DemoBlockEntity> DEMO_BLOCK = register(   public static final BlockEntityType<DemoBlockEntity> DEMO_BLOCK = register(
       "demo_block",       "demo_block",
-      BlockEntityType.Builder.create(DemoBlockEntity::new, TutorialBlocks.DEMO_BLOCK).build()+       
 +      // 对于 1.21.2 之前的版本,请使用 BlockEntityType.Builder。 
 +      FabricBlockEntityTypeBuilder.create(DemoBlockEntity::new, TutorialBlocks.DEMO_BLOCK).build()
   );   );
      
Line 69: Line 75:
 对于旧版本,如果无法访问 ''BlockEntityType.Builder.create'',尝试 ''FabricBlockEntityTypeBuilder.create'' 对于旧版本,如果无法访问 ''BlockEntityType.Builder.create'',尝试 ''FabricBlockEntityTypeBuilder.create''
  
-这个方块实体类型定义了只有 ''TutorialBlocks.DEMO_BLOCK'' 可以拥有这个方块实体类型。如果你想要让方块实体类型支持更多方块,只需要将其添加到 ''BlockEntityType.Builder.create'' 的参数中即可。如果方法引用 ''DemoBlockEntity::new'' 无法解析,检查 ''DemoBlockEntity'' 的构造方法的参数是否正确。+这个方块实体类型定义了只有 ''TutorialBlocks.DEMO_BLOCK'' 可以拥有这个方块实体类型。如果你想要让方块实体类型支持更多方块,只需要将其添加到 ''FabricBlockEntityTypeBuilder.create'' 的参数中即可。如果方法引用 ''DemoBlockEntity::new'' 无法解析,检查 ''DemoBlockEntity'' 的构造方法的参数是否正确。
  
 > **注意:**和其他方块一样,这个方块也需要方块模型和物品模型,可能也需要战利品表,关于如何创建请参见 [[blocks]]。对于战利品表,有[[blockentity_sync_itemstac|后续教程]]会提到如何改进战利品表表以包含方块实体数据。 > **注意:**和其他方块一样,这个方块也需要方块模型和物品模型,可能也需要战利品表,关于如何创建请参见 [[blocks]]。对于战利品表,有[[blockentity_sync_itemstac|后续教程]]会提到如何改进战利品表表以包含方块实体数据。
Line 101: Line 107:
  
 覆盖''getRenderType'' 为因为 ''BlockWithEntity'' 会默认让它不可见。 覆盖''getRenderType'' 为因为 ''BlockWithEntity'' 会默认让它不可见。
- 
-===== 序列化数据 ===== 
- 
-如果您想在 ''BlockEntity'' 存储任何数据,必须保存和加载它,否则数据只会在''BlockEntity''被加载时保持,而且每次你重进游戏时会重置。幸运的是,保存和加载非常简单——只需要覆盖 ''writeNbt()'' 和 ''readNbt()'' 即可。 
- 
-''writeNbt()'' 将会修改其参数 ''nbt'' 的内容,这个 ''nbt'' 包含了方块实体中的所有数据。该方法通常不会修改方块实体本身。方块实体数据将会存储在磁盘中,并且如果您需要将 ''BlockEntity'' 数据与客户端同步,则会通过封包发送。调用 ''super.writeNbt()'' 非常重要,因为方块实体的坐标及其方块实体类型 id 保存到 nbt 中。否则,您尝试保存的所有其他数据都将丢失,因为它与位置和 ''BlockEntityType'' 不相关。 
- 
-知道了这一点,下面的示例演示了如何将 ''BlockEntity'' 中的整数保存到标签中。在此示例中,整数保存在键 ''number'' 下——您可以将其替换为任何字符串,但是标签中的每个键只能有一个项,并且需要记住该键以便以后读取数据。 
- 
-<code java> 
-public class DemoBlockEntity extends BlockEntity { 
- 
-    // 储存数字的当前值 
-    private int number = 7; 
-    
-    public DemoBlockEntity(BlockPos pos, BlockState state) { 
-        super(ExampleMod.DEMO_BLOCK_ENTITY, pos, state); 
-    } 
-    
-    // 序列化方块实体 
-    @Override 
-    public void writeNbt(NbtCompound nbt, RegistryWrapper.WrapperLookup wrapper) { 
-        // 将数字的当前值保存到 nbt 
-        nbt.putInt("number", number); 
- 
-        super.writeNbt(nbt, wrapper); 
-    } 
-} 
-</code> 
- 
-为了以后读取数据,您还需要覆盖 ''readNBT''。此方法与 ''writeNBT'' 相反——不会将数据保存到 ''NBTCompound'',而是您已经有了之前保存的 nbt 数据,使您可以检索所需的任何数据。该方法会修改方块实体本身,不会修改这个 ''nbt'' 参数。与 ''writeNbt'' 一样,必须调用 ''super.readNbt'',并且您将需要使用相同的键来检索保存的数据。要检索我们之前保存的数字,请参见下面的示例。 
- 
-<code java> 
-    // 反序列化方块实体 
-    @Override 
-    public void readNbt(NbtCompound nbt, RegistryWrapper.WrapperLookup wrapper) { 
-        super.readNbt(nbt, wrapper); 
-         
-        number = nbt.getInt("number"); 
-    } 
-</code> 
- 
-一旦实现了 ''writeNbt'' 和 ''readNbt'' 方法,您只需要确保在合适的时候调用即可。每当您的 ''BlockEntity'' 数据发生更改并需要保存时,请调用 ''markDirty()''。这会将方块所在的区块标记为dirty,在世界下次保存时强制调用 ''writeNbt'' 方法。原则上,只要修改了 ''BlockEntity'' 类中的任何一个自定义变量,就只需要简单调用 ''markDirty'',否则当你退出并重进世界后,这个方块实体依然会是没有修改过的。 
- 
-===== 将服务器数据同步至客户端 ===== 
-数据通常是在服务器世界读取的。大多数数据都是客户端不需要知道的,例如客户端并不需要知道箱子和熔炉里面有什么,除非打开它。但对于某些方块实体,例如告示牌和旗帜,你需要将所有或者部分数据告知客户端,比如用于渲染。 
- 
-对于 1.17.1 及以下版本,请实现 Fabric API 中的 ''BlockEntityClientSerializable''。此接口提供了 ''fromClientTag'' 和 ''toClientTag'' 方法,其作用与前面讨论的 ''readNbt'' 和 ''writeNbt'' 方法基本相同,只是专门用于发送和接收客户端上的数据。你可以简单地在 ''fromClientTag'' 和 ''toClientTag'' 两个方法中调用 ''readNbt'' 和 ''writeNbt'' 
- 
-对于 1.18 及以上版本,请覆盖 ''toUpdatePacket'' 和 ''toInitialChunkDataNbt'' 
-<code java> 
-  @Nullable 
-  @Override 
-  public Packet<ClientPlayPacketListener> toUpdatePacket() { 
-    return BlockEntityUpdateS2CPacket.create(this); 
-  } 
-  
-  @Override 
-  public NbtCompound toInitialChunkDataNbt() { 
-    return createNbt(); 
-  } 
-</code> 
-**警告**: 需要调用 ''world.updateListeners(pos, state, state, Block.NOTIFY_LISTENERS);'' 来触发数据的同步,否则客户端不会知道方块实体已经改变。 
  
 ===== 方块实体刻 ===== ===== 方块实体刻 =====
Line 182: Line 125:
 在你的 ''BlockEntity'' 类中: 在你的 ''BlockEntity'' 类中:
 <code java DemoBlockEntity.java> <code java DemoBlockEntity.java>
-public class DemoBlockEntity extends BlockEntity {+public class DemoBlockEntity extends BlockEntity implements BlockEntityTicker<DemoBlockEntity> {
     [...]     [...]
          
-    public static void tick(World world, BlockPos pos, BlockState state, DemoBlockEntity be) {+    @Override 
 +    public static void tick(World world, BlockPos pos, BlockState state, DemoBlockEntity blockEntity) {
         [...]         [...]
     }     }
zh_cn/tutorial/blockentity.1724724881.txt.gz · Last modified: 2024/08/27 02:14 by solidblock