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
Next revisionBoth sides next revision
zh_cn:tutorial:blockentity [2021/07/25 10:52] – [注册你的方块实体] solidblockzh_cn:tutorial:blockentity [2022/08/08 03:50] – [序列化数据] solidblock
Line 11: Line 11:
 <code java> <code java>
 public class DemoBlockEntity extends BlockEntity { public class DemoBlockEntity extends BlockEntity {
-   public DemoBlockEntity() { +    public DemoBlockEntity(BlockPos pos, BlockState state) { 
-      super(ExampleMod.DEMO_BLOCK_ENTITY, pos, state); +        super(ExampleMod.DEMO_BLOCK_ENTITY, pos, state); 
-   }+    }
 } }
 </code> </code>
Line 41: Line 41:
  
 <code java> <code java>
-public class MyBlock extends Block implements BlockEntityProvider {+public class DemoBlock extends Block implements BlockEntityProvider {
    
-   [...]+    [...]
    
-   @Override +    @Override 
-   public BlockEntity createBlockEntity(BlockView blockView) { +    public BlockEntity createBlockEntity(BlockPos pos, BlockState state) { 
-      return new DemoBlockEntity(); +        return new DemoBlockEntity(pos, state); 
-   }+    }
 } }
 </code> </code>
Line 54: Line 54:
 ===== 序列化数据 ===== ===== 序列化数据 =====
  
-如果要将任何数据存储在''BlockEntity''中,则需要保存并加载,或者仅在加载''BlockEntity''时保留,并且只要您返回到它。幸运的是,保存和加载非常简单——只需要覆盖''toTag()''和''fromTag()''即可。+如果要将任何数据存储在 ''BlockEntity'' 中,则需要保存并加载,或者仅在加载 ''BlockEntity'' 时保留,并且只要您返回到它。幸运的是,保存和加载非常简单——只需要覆盖 ''writeNbt()'' 和 ''readNbt()'' 即可。
  
-''toTag()''返回一个''CompoundTag'',其中应包含''BlockEntity''中的所有数据。如果您需要将''BlockEntity''数据与客户端同步,则此数据将保存到磁盘并通过数据包发送。调用''toTag''的默认实现非常重要,因为它将“标识数据(Identifying data)''(位置和ID)''保存到标签中。否则,您尝试保存的所有其他数据都将丢失,因为它与位置和''BlockEntityType''不相关。知道了这一点,下面的示例演示了如何将''BlockEntity''中的整数保存到标签中。在此示例中,整数保存在键''number''下——您可以将其替换为任何字符串,但是标签中的每个键只能有一个条目(entry),并且需要记住该键以便以后检索数据。+''writeNbt()'' 返回一个 ''NBTCompound'',其中应包含 ''BlockEntity'' 中的所有数据。如果您需要将 ''BlockEntity'' 数据与客户端同步,则此数据将保存到磁盘并通过数据包发送。调用 ''writeNbt'' 的默认实现非常重要,因为它将“标识数据(Identifying data)''(位置和ID)''保存到标签中。否则,您尝试保存的所有其他数据都将丢失,因为它与位置和 ''BlockEntityType'' 不相关。知道了这一点,下面的示例演示了如何将 ''BlockEntity'' 中的整数保存到标签中。在此示例中,整数保存在键 ''number'' 下——您可以将其替换为任何字符串,但是标签中的每个键只能有一个,并且需要记住该键以便以后检索数据。
  
 <code java> <code java>
 public class DemoBlockEntity extends BlockEntity { public class DemoBlockEntity extends BlockEntity {
  
-   // 储存数字的当前值 +    // 储存数字的当前值 
-   private int number = 7;+    private int number = 7;
        
-   public DemoBlockEntity() { +    public DemoBlockEntity(BlockPos pos, BlockState state) { 
-      super(ExampleMod.DEMO_BLOCK_ENTITY); +        super(ExampleMod.DEMO_BLOCK_ENTITY, pos, state); 
-   }+    }
        
-   // 序列化方块实体 +    // 序列化方块实体 
-   @Override +    @Override 
-   public CompoundTag toTag(CompoundTag tag) { +    public void writeNbt(NbtCompound nbt) { 
-      super.toTag(tag); +        // Save the current value of the number to the tag 
-       +        nbt.putInt("number", number); 
-      // Save the current value of the number to the tag +         
-      tag.putInt("number", number); +        super.writeNbt(nbt) 
-       +    }
-      return tag; +
-   }+
 } }
 </code> </code>
  
-为了以后检索数据,您还需要覆盖''fromTag''。 此方法与''toTag''相反-不会将数据保存到''CompoundTag'',而是提供了之前保存的标签,使您可以检索所需的任何数据。 与''toTag''一样,必须调用''super.fromTag'',并且您将需要使用相同的键来检索保存的数据。 要检索我们之前保存的号码,请参见下面的示例。+为了以后检索数据,您还需要覆盖 ''readNBT''。 此方法与 ''writeNBT'' 相反——不会将数据保存到 ''NBTCompound'',而是您已经有了之前保存的标签,使您可以检索所需的任何数据。与 ''writeNbt'' 一样,必须调用 ''super.readNbt'',并且您将需要使用相同的键来检索保存的数据。要检索我们之前保存的数字,请参见下面的示例。
  
 <code java> <code java>
-// 取消序列化方块实体+// 序列化方块实体
 @Override @Override
-public void fromTag(BlockState state, CompoundTag tag) { +public void readNbt(NbtCompound nbt) { 
-   super.fromTag(state, tag); +    super.readNbt(nbt); 
-   number = tag.getInt("number");+     
 +    number = nbt.getInt("number");
 } }
 </code> </code>
  
-一旦实现了''toTag''和''fromTag''方法,您只需要确保在正确的时调用它们即可。每当您的''BlockEntity''数据发生更改并需要保存时,请调用''markDirty()''。这会通过标记方块所在的区块为dirty,在世界下次保存时强制调用''toTag''方法。原则上,只要改变了''BlockEntity''类中的任何一个自定义变量,就只需要简单调用''markDirty''+一旦实现了 ''writeNbt'' 和 ''readNbt'' 方法,您只需要确保在合适的时调用即可。每当您的 ''BlockEntity'' 数据发生更改并需要保存时,请调用 ''markDirty()''。这会方块所在的区块标记为dirty,在世界下次保存时强制调用 ''writeNbt'' 方法。原则上,只要改变了 ''BlockEntity'' 类中的任何一个自定义变量,就只需要简单调用 ''markDirty''
  
-如果您需要将某些''BlockEntity''数据同步到客户端,于渲染等目的,则应从Fabric API中实现''BlockEntityClientSerializable''此类提供了''fromClientTag''和''toClientTag''方法,其作用与前面讨论的''fromTag''和''toTag''方法基本相同,只是专门用于发送和接收客户端上的数据。 +===== 将服务器数据同步至客户端 ===== 
-===== Overview =====+数据通常是在服务器世界读取的。有时候你需要将所有或者部分数据同步到客户端,比如用于渲染。
  
-现在,您应该拥有自己的''BlockEntity'',可以按照各种方式扩展以适应您的需求。 您注册了''BlockEntityType'',并用它来将''Block''和''BlockEntity''类连接在一起。 然后,您在''Block''类中实现了''BlockEntityProvider'',并使用该接口提供了新''BlockEntity''的实例。 最后,您学习了如何将数据保存到''BlockEntity''中,以及如何检索以备后用。+对于 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);''来触发数据的同步。 
 +===== 方块实体刻 ===== 
 +1.17 添加了静态的刻,然后你就可以实现 ''Tickable'' 接口。对于需要计划刻的方块,你只需要使用 ''Block'' 中的 ''getTicker'',链接回到 ''Block Entity''。参考下面关于刻的一个常见的实现。 
 + 
 +在你的 ''Block'' 类中: 
 +<code java> 
 +public class DemoBlock extends BlockWithEntity { 
 +    [...] 
 +    @Override 
 +    public BlockRenderType getRenderType(BlockState state) { 
 +        // 由于继承了BlockWithEntity,这个默认为INVISIBLE,所以我们需要更改它! 
 +        return BlockRenderType.MODEL; 
 +    } 
 +    @Override 
 +    public <T extends BlockEntity> BlockEntityTicker<T> getTicker(World world, BlockState state, BlockEntityType<T> type) { 
 +        return checkType(type, ExampleMod.DEMO_BLOCK_ENTITY, (world1, pos, state1, be) -> DemoBlockEntity.tick(world1, pos, state1, be)); 
 +    } 
 +</code> 
 +在你的 ''Block Entity'' 中: 
 +<code java> 
 +public class DemoBlockEntity extends BlockEntity { 
 +    public DemoBlockEntity(BlockPos pos, BlockState state) { 
 +        super(ExampleMod.DEMO_BLOCK_ENTITY, pos, state); 
 +    } 
 +    public static void tick(World world, BlockPos pos, BlockState state, DemoBlockEntity be) { 
 +        [...] 
 +    } 
 +
 +</code> 
 + 
 +===== 概览 ===== 
 + 
 +现在,您应该拥有自己的 ''BlockEntity''可以各种方式扩展以适应您的需求。 您注册了 ''BlockEntityType'',并用它来将 ''Block'' 和 ''BlockEntity'' 类连接在一起。 然后,您在 ''Block'' 类中实现了 ''BlockEntityProvider'',并使用该接口提供了新 ''BlockEntity'' 的实例。 最后,您学习了如何将数据保存到 ''BlockEntity'' 中,以及如何检索以备后用。
zh_cn/tutorial/blockentity.txt · Last modified: 2023/09/03 01:37 by wjz_p