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 [2022/01/28 07:01] – [Receiving a packet on the game client] solidblockzh_cn:tutorial:networking [2024/04/15 02:16] (current) solidblock
Line 139: Line 139:
 要读取游戏客户端上的方块坐标,你可以使用 ''PacketByteBuf.readBlockPos()'' 要读取游戏客户端上的方块坐标,你可以使用 ''PacketByteBuf.readBlockPos()''
  
-You should read all data from the packet on the network thread before scheduling a task to occur on the client thread. You will get errors related to the ref count if you try to read data on the client thread. If you must read data on the client thread, you need to ''retain()'' the data and then read it on the client thread. If you do ''retain()'' the data, make sure you ''release()'' the data when you no longer need it. 
 你应该先从网络线程上的数据包中读取所有数据然后再在客户端线程上安排任务。如果你尝试在客户端线程上读取数据,将收到与 ref count 有关的错误。如果一定要在客户端线程上读取数据,则需要 ''retain()''(保留)这些数据,然后在客户端线程上读取。如果你 '' retain()'' 了数据,请确保在不再需要时 ''release()''(释放)数据。 你应该先从网络线程上的数据包中读取所有数据然后再在客户端线程上安排任务。如果你尝试在客户端线程上读取数据,将收到与 ref count 有关的错误。如果一定要在客户端线程上读取数据,则需要 ''retain()''(保留)这些数据,然后在客户端线程上读取。如果你 '' retain()'' 了数据,请确保在不再需要时 ''release()''(释放)数据。
  
Line 155: Line 154:
 </code> </code>
  
-==== Sending packets to the server and receiving packets on the server ====+==== 向服务器发送数据包并在服务器上接收数据包 ====
  
-Sending packets to a server and receiving a packet on the server is very similar to how you would on the client. However, there are a few key differences.+将数据包发送到服务器并在服务器上接收数据包与在客户端上的操作非常相似。但是,有一些关键的区别。
  
-Firstly sending a packet to the server is done through ''ClientPlayNetworking.send''. Receiving a packet on the server is similar to receiving a packet on the client, using the ''ServerPlayNetworking.registerGlobalReceiver(Identifier channelName, ChannelHandler channelHandler)'' method. The ''ChannelHandler'' for the server networking also passes the ''ServerPlayerEntity'' (player) who sent the packet through the ''player'' parameter. +首先,将数据包发送到服务器是通过 ''ClientPlayNetworking.send'' 完成的。在服务器接收数据包与在客户端接收数据包比较类似,使用 ''ServerPlayNetworking.registerGlobalReceiver(Identifier channelName, ChannelHandler channelHandler)'' 方法。用于服务器网络通信的 ''ChannelHandler'' 也会通过 ''player''参数传入发送该数据包的 ''ServerPlayerEntity''(玩家)。 
- +===== 追踪的概念以及为什么只有你看到高亮的方块 =====
-===== The concept of tracking and why you only see the highlighted block ===== +
- +
-Now that the highlighting wand properly uses networking so the dedicated server does not crash, you invite your friend back on the server to show off the highlighting wand. You use the wand and the block is highlighted on your client and the server does not crash. However, your friend does not see the highlighted block. This is intentional with the code that you already have here. To solve this issue let us take a look at the item's use code:+
  
 +现在,高亮魔杖恰当地使用了网络,因此专用服务器不会崩溃。你邀请你的朋友回到服务器上来炫耀高亮魔杖,你使用魔杖,并且该方块也在你的客户端上高亮了,并且服务器没有崩溃。但是,你的朋友没有看到高亮。这是你在此处已有的代码有意为之的。为解决此问题,看一下物品的 ''use'' 代码:
 <code java [enable_line_numbers="true"]> <code java [enable_line_numbers="true"]>
     public TypedActionResult<ItemStack> use(World world, PlayerEntity user, Hand hand) {     public TypedActionResult<ItemStack> use(World world, PlayerEntity user, Hand hand) {
-        // Verify we are processing the use action on the logical server+        // 确认我们是否是在逻辑服务器上进行操作
         if (world.isClient()) return super.use(world, user, hand);         if (world.isClient()) return super.use(world, user, hand);
  
-        // Raycast and find the block the user is facing at+        // 视线追踪并找到玩家朝向的方块
         BlockPos target = ...         BlockPos target = ...
         PacketByteBuf buf = PacketByteBufs.create();         PacketByteBuf buf = PacketByteBufs.create();
Line 180: Line 177:
 </code> </code>
  
-You may notice the item will only send the packet to the player who used the item. To fix this, we can use the utility methods in ''PlayerLookup'' to get all the players who can see the highlighted block.+你可能注意到了,该物品只会将数据包发送给使用了该物品的玩家。为解决此问题,我们可以使用 ''PlayerLookup'' 中的实用方法来获取所有可以看到高亮方块的玩家。
  
-Since we know where the highlight will occur, we can use ''PlayerLookup.tracking(ServerWorld world, BlockPos pos)'' to get a collection of all players who can see that position in the world. Then you would simply iterate through all players in the returned collection and send the packet to each player:+因为我们知道高亮会出现在哪个位置,所以我们可以使用 ''PlayerLookup.tracking(ServerWorld world, BlockPos pos)'' 来获取所有可以在世界上看到该位置的玩家的集合。然后,您只需在返回的集合中遍历所有玩家,并将数据包发送给每个玩家:
  
 <code java [enable_line_numbers="true", highlight_lines_extra="10,11,12,13"]> <code java [enable_line_numbers="true", highlight_lines_extra="10,11,12,13"]>
     public TypedActionResult<ItemStack> use(World world, PlayerEntity user, Hand hand) {     public TypedActionResult<ItemStack> use(World world, PlayerEntity user, Hand hand) {
-        // Verify we are processing the use action on the logical server+        // 确认我们是否是在逻辑服务器上进行操作
         if (world.isClient()) return super.use(world, user, hand);         if (world.isClient()) return super.use(world, user, hand);
  
-        // Raycast and find the block the user is facing at+        // 视线追踪并找到玩家朝向的方块
         BlockPos target = ...         BlockPos target = ...
         PacketByteBuf buf = PacketByteBufs.create();         PacketByteBuf buf = PacketByteBufs.create();
         buf.writeBlockPos(target);         buf.writeBlockPos(target);
  
-        // Iterate over all players tracking a position in the world and send the packet to each player+        // 迭代世界上所有追踪位置的玩家,并将数据包发送给每个玩家
         for (ServerPlayerEntity player : PlayerLookup.tracking((ServerWorld) world, target)) {         for (ServerPlayerEntity player : PlayerLookup.tracking((ServerWorld) world, target)) {
             ServerPlayNetworking.send(player, TutorialNetworkingConstants.HIGHLIGHT_PACKET_ID, buf);             ServerPlayNetworking.send(player, TutorialNetworkingConstants.HIGHLIGHT_PACKET_ID, buf);
Line 203: Line 200:
 </code> </code>
  
-After this change, when you use the wand, your friend should also see the highlighted block on their own client.+这样修改之后,当你使用魔杖时,你的朋友也应该在他们自己的客户端上看到高亮方块。
  
-====== Advanced Networking topics ======+===== Networking in 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'':
  
-The Networking system Fabric API supplies is very flexible and supports additional features other than just sending and receiving simple packetsAs some of these more advanced topics are longhere are links to their specific pages:+<code java> 
 +public record BlockHighlightPayload(BlockPos blockPos) implements CustomPayload { 
 +  public static final Id<BlockHighlightPayload> ID = CustomPayload.id("tutorial:block_highlight"); 
 +  public static final PacketCodec<PacketByteBufBlockHighlightPayload> 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()));
  
-^ Networking Topic ^ Description ^ +  @Override 
-| [[tutorial:networking:connection_events|Connection Network connection events]] | Events related to the the lifecycle of a connection to a client or server | +  public Id<? extends CustomPayload> getId() { 
-| [[tutorial:networking:channel_events|Channel registration events]] | Events related to a server of client declaring the ability to receive a packet on a channel of a specific name | +    return ID
-| [[tutorial:networking:login|Login phase networking]]| Sending requests to a client during loginand allowing delay of login for a short amount of time | +  } 
-| [[tutorial:networking:dynamic_handlers|Dynamic registration of channel handlers]]| Allowing for a connection to receive a packet with a special handler |+
 +</code>
  
 +And then, register the receiver like this:
 +<code java>
 +PayloadTypeRegistry.playS2C().register(BlockHighlightPayload.ID, BlockHighlightPayload.CODEC);
 +ClientPlayNetworking.registerGlobalReceiver(BlockHighlightPayload.ID, (payload, context) -> {
 +  context.client().execute(() -> {
 +    ClientBlockHighlighting.highlightBlock(client, target);
 +  });
 +});
 +</code>
 +
 +Now, on the server side, you can send the packet to players like this:
 +<code java>
 +    public TypedActionResult<ItemStack> use(World world, PlayerEntity user, Hand hand) {
 +        if (world.isClient()) return super.use(world, user, hand);
 +
 +        // ...
 +
 +        for (ServerPlayerEntity player : PlayerLookup.tracking((ServerWorld) world, target)) {
 +            ServerPlayNetworking.send(player, new BlockHighlightPayload(blockPos));
 +        }
 +
 +        return TypedActionResult.success(user.getHandStack(hand));
 +    }
 +</code>
zh_cn/tutorial/networking.1643353299.txt.gz · Last modified: 2022/01/28 07:01 by solidblock