NeoForge-1.20.4Mod开发教程之网络发包

本篇教程参考为Flandre芙兰的NeoForge1.20.4Mod开发的视频,这篇教程是我边学边总结的,与其说是教程更像我的学习笔记,如有不清楚的地方,大家可以在评论区提问。在我力所能及的范围内,我都会解答的。

 

首先我们讲一下发包的过程,具体过程如下:

                          通过本地、局域网传输或者因特网传输
 构建数据包=>序列化成字节流 ===============================> 反序列化成实例 => 实现操作

 

定义数据包

public record MyData(String message, int age) implements CustomPacketPayload {
     public static final ResourceLocation ID = new ResourceLocation(ExampleMod.MODID, "mydata");
 ​
     public MyData(final FriendlyByteBuf buf) {
         this(buf.readUtf(), buf.readInt());//反序列化
    }
 ​
     @Override
     public void write(FriendlyByteBuf buffer) {//序列化
         buffer.writeUtf(message());
         buffer.writeInt(age());
    }
 ​
     @Override
     public ResourceLocation id() {
         return ID;
    }
 ​
 }

 

S2C

这种情况是服务端发包,客户端接受并处理数据包

public class ClientPayloadHandler {
 ​
     private static final Logger LOGGER = LogManager.getLogger();//打印信息用,非必要
 ​
     private static final ClientPayloadHandler INSTANCE = new ClientPayloadHandler();
 ​
     public static ClientPayloadHandler getInstance() {
         return INSTANCE;
    }
 ​
     public void handleData(final MyData data, final PlayPayloadContext context) {
         
         //在network线程中对数据进行处理的话,代码写在这里
 ​
         context.workHandler().submitAsync(()->{
  //在Main线程里面做一些的操作的话,代码写在这里
             LOGGER.info(data.message());
 
        }).exceptionally(e -> {
 ​
             context.packetHandler().disconnect(Component.translatable("my_mod.network_disconnect",e.getMessage()));
 ​
             return null;
        });
    }
 }

handleData是我们处理数据包的方法,第一个参数就是对应数据包的类型,第二个参数是网路的上下文,包含了网络的发包人和其他信息

 

C2S

这种情况是客户端发包,服务端接受并处理数据包

public class ServerPayloadHandler {
 ​
     private static final Logger LOGGER = LogManager.getLogger();
 ​
     private static final ServerPayloadHandler INSTANCE = new ServerPayloadHandler();
 ​
     public static ServerPayloadHandler getInstance() {
         return INSTANCE;
    }
 ​
     public void handleData(final MyData data, final PlayPayloadContext context) {
 ​
 ​
         context.workHandler().submitAsync(()->{
 ​
             LOGGER.info(data.message());
 ​
        }).exceptionally(e -> {
 ​
             context.packetHandler().disconnect(Component.translatable("my_mod.network_disconnect",e.getMessage()));
 ​
             return null;
        });
    }
 }

 

网路注册

@Mod.EventBusSubscriber(modid = ExampleMod.MODID, bus = Mod.EventBusSubscriber.Bus.MOD)
 public class Networking {
     @SubscribeEvent
     public static void register(final RegisterPayloadHandlerEvent event) {
         final IPayloadRegistrar payloadRegistrar = event.registrar(ExampleMod.MODID);
         payloadRegistrar.play(MyData.ID,MyData::new,handler ->
                 handler.client(ClientPayloadHandler.getInstance()::handleData)
                        .server(ServerPayloadHandler.getInstance()::handleData));
 ​
    }
 }

在MOD总线里监听RegisterPayloadHandlerEvent,把MyData这个payload绑定到客户端/服务端处理器

payload就是“包里真正携带的数据内容”。

MyData就是payload:

message、age 是数据本体

write(…) / 构造器 MyData(FriendlyByteBuf) 负责序列化和反序列化

id()(examplemod:mydata)告诉网络层“这是什么类型的payload”

网络层负责“送快递”,payload 是“快递盒子里的东西”

 

触发

public class MessageItem extends Item {
     public MessageItem() {
         super(new Properties());
    }
 ​
 ​
     @Override
     public InteractionResultHolder<ItemStack> use(Level world, Player player, InteractionHand hand) {
         if (world.isClientSide) {
             PacketDistributor.SERVER.noArg().send(new MyData("From client",2));
        }
         if (!world.isClientSide) {
             PacketDistributor.PLAYER.with((ServerPlayer) player).send(new MyData("From server",2));
        }
         return super.use(world,player,hand);
    }
 }

 

我们通过物品的右键交互来触发网络数据包的发送

© 版权声明
THE END
喜欢就支持一下吧
点赞4赞赏 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容