User Tools

Site Tools


zh_cn:tutorial:networking

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:networking [2024/04/15 02:16] solidblockzh_cn:tutorial:networking [2024/07/05 10:58] (current) solidblock
Line 1: Line 1:
 **注意:**本页已经取代旧版页面。建议使用本页描述的新的网络API。旧的页面参见[[tutorial:legacy:networking-v0|此处(英文)]]。 **注意:**本页已经取代旧版页面。建议使用本页描述的新的网络API。旧的页面参见[[tutorial:legacy:networking-v0|此处(英文)]]。
 +
 +对于 1.20.5 引入的新的网络通信 API,请参见 [[#1.20.5 中的网络通信]]。
  
 ====== 网络通信 ====== ====== 网络通信 ======
Line 41: Line 43:
 要修复崩溃,你需要了解 Minecraft 如何在客户端和专用服务器之间通信(communication)。 要修复崩溃,你需要了解 Minecraft 如何在客户端和专用服务器之间通信(communication)。
  
-[[Minecraft 的逻辑|{{tutorial:sides.png?700}}]]+[[Minecraft 的逻辑|{{tutorial:sides.png?700}}]]
  
 从上面这张图可以看到,游戏客户端和专用服务器是相互分离的系统,并使用数据包(packets,注意不是 datapack)桥接在一起。这个数据包桥(packet bridge)不仅存在于游戏客户端和专用服务器之间,还存在于您的客户端和通过 LAN 连接的另一个客户端之间。注意即使是单人游戏也有数据包桥,这是因为游戏客户端会启动一个特殊的集成服务器实例来运行游戏。下表显示了三种连接类型之间的主要区别: 从上面这张图可以看到,游戏客户端和专用服务器是相互分离的系统,并使用数据包(packets,注意不是 datapack)桥接在一起。这个数据包桥(packet bridge)不仅存在于游戏客户端和专用服务器之间,还存在于您的客户端和通过 LAN 连接的另一个客户端之间。注意即使是单人游戏也有数据包桥,这是因为游戏客户端会启动一个特殊的集成服务器实例来运行游戏。下表显示了三种连接类型之间的主要区别:
Line 72: Line 74:
 </code> </code>
  
-接下来,我们需要将数据包发送到游戏客户端。首先需要定义一个用于识别数据包的 ''Identifier''。对于本例,我们的标识符为 ''wiki_example:highlight_block''。为将数据包发送到游戏客户端,需要指定要哪个玩家的游戏客户端接收数据包。由于该操作发生在逻辑服务器上,所以可以将 ''player'' 向上强转为 ''ServerPlayerEntity''+接下来,我们需要将数据包发送到游戏客户端。首先需要定义一个用于识别数据包的 ''Identifier''。对于本例,我们的标识符为 ''tutorial:highlight_block''。为将数据包发送到游戏客户端,需要指定要哪个玩家的游戏客户端接收数据包。由于该操作发生在逻辑服务器上,所以可以将 ''player'' 向上强转为 ''ServerPlayerEntity'' 
 +<code java> 
 +public class TutorialNetworkingConstants { 
 +    // 存储数据包的 id 以便后面引用 
 +    public static final Identifier HIGHLIGHT_PACKET_ID = Identifier.of("tutorial", "highlight_block"); 
 +
 +</code>
  
 要将数据包发送到玩家,我们使用 ''ServerPlayerNetworking'' 中的一些方法。我们使用该类中的以下方法: 要将数据包发送到玩家,我们使用 ''ServerPlayerNetworking'' 中的一些方法。我们使用该类中的以下方法:
Line 81: Line 89:
 </code> </code>
  
-数据包将会被发送到此方法中的玩家。通道名称是你之前决定用来识别数据包的 ''Identifier''。''PacketByteBuf'' 用于存储数据包的数据。We will return later to writing data to the packet's payload via the buf.+数据包将会被发送到此方法中的玩家。通道名称是你之前决定用来识别数据包的 ''Identifier''。''PacketByteBuf'' 用于存储数据包的数据。然后我们返回,以通过 buf 将数据写入数据包的有效负载。
  
 由于我们没有向数据包写入任何数据,所以现在,我们将发送带有空有效负载的数据包。可以使用 ''PacketByteBufs.empty()'' 创建带有空有效负载的 buf。 由于我们没有向数据包写入任何数据,所以现在,我们将发送带有空有效负载的数据包。可以使用 ''PacketByteBufs.empty()'' 创建带有空有效负载的 buf。
Line 202: Line 210:
 这样修改之后,当你使用魔杖时,你的朋友也应该在他们自己的客户端上看到高亮方块。 这样修改之后,当你使用魔杖时,你的朋友也应该在他们自己的客户端上看到高亮方块。
  
-===== Networking in 1.20.5 ===== +===== 1.20.5 中的网络通信 ===== 
-Since 1.20.5, the logic of networking is totally rewrited. In 1.20.5, you have to define a custom ''Payload''. First, define the payload that includes a ''BlockPos'':+自 1.20.5 开始,网络通信的逻辑被大改。在 1.20.5 中,''RegistryByteBuf'' 现在用于游玩阶段网络,你需要定义一个 ''Payload''。首先,定义一个包含了 ''BlockPos'' 的 ''Payload''
  
 <code java> <code java>
 public record BlockHighlightPayload(BlockPos blockPos) implements CustomPayload { public record BlockHighlightPayload(BlockPos blockPos) implements CustomPayload {
-  public static final Id<BlockHighlightPayload> ID = CustomPayload.id("tutorial:block_highlight");+  public static final Id<BlockHighlightPayload> ID = new CustomPayload.Id<>(TutorialNetworkingConstants.HIGHLIGHT_PACKET_ID);
   public static final PacketCodec<PacketByteBuf, BlockHighlightPayload> CODEC = PacketCodec.tuple(BlockPos.PACKET_CODEC, BlockHighlightPayload::blockPos, BlockHighlightPayload::new);   public static final PacketCodec<PacketByteBuf, BlockHighlightPayload> CODEC = PacketCodec.tuple(BlockPos.PACKET_CODEC, BlockHighlightPayload::blockPos, BlockHighlightPayload::new);
-  // or you can also write like this:+  // 或者,你也可以这样写:
   // public static final PacketCodec<PacketByteBuf, BlockHighlightPayload> CODEC = PacketCodec.of((value, buf) -> buf.writeBlockPos(value.blockPos), buf -> new BlockHighlightPayload(buf.readBlockPos()));   // public static final PacketCodec<PacketByteBuf, BlockHighlightPayload> CODEC = PacketCodec.of((value, buf) -> buf.writeBlockPos(value.blockPos), buf -> new BlockHighlightPayload(buf.readBlockPos()));
  
Line 219: Line 227:
 </code> </code>
  
-And then, register the receiver like this:+然后,像这样注册 receiver
 <code java> <code java>
 PayloadTypeRegistry.playS2C().register(BlockHighlightPayload.ID, BlockHighlightPayload.CODEC); PayloadTypeRegistry.playS2C().register(BlockHighlightPayload.ID, BlockHighlightPayload.CODEC);
Line 229: Line 237:
 </code> </code>
  
-Now, on the server side, you can send the packet to players like this:+现在,在服务器一端,你可以像这样把数据包发送给玩家:
 <code java> <code java>
     public TypedActionResult<ItemStack> use(World world, PlayerEntity user, Hand hand) {     public TypedActionResult<ItemStack> use(World world, PlayerEntity user, Hand hand) {
zh_cn/tutorial/networking.1713147414.txt.gz · Last modified: 2024/04/15 02:16 by solidblock