[1.7.2]关于单机客户端与单机服务端通信的问题

By | 2014年10月30日

众所周知Minecraft的单机版是伪服务端,服务端与客户端是隔离的,本篇文章是针对GUI与服务端通信的。

GUI是用于显示的组件隶属于客户端,所有玩家能看到的东西都是属于客户端的,而真正的后台是运行于服务端的,服务端与客户端通信基本是 依赖叫做Packet的东西来完成的。在net/minecraft/network中那些XxxPacketXxxxx.java就是这些组件了。

以按下按钮为例,在GuiScreenBook中的189行

this.mc.getNetHandler().addToSendQueue(new C17PacketCustomPayload(s, bytebuf));

这个就是GUI向服务端发送Packet请求了,表示将文本传入服务端中处理,服务端的处理还没找到,估计也是将获得的Packet中的数据保存到当前的ItemStack中。

在minecraftforge论坛逛了一圈,发现有很多种方法可以实现客户端与服务端的通信,大体分三种,一种是老式的引入接口然后注册,这个方法在1.2.5FML的时候就有了,担心Forge会腰斩就没去测试;一种的和源码的方式相近的,似乎衍生的方法非常多,但是找不到太详细可行的教程,我找到的可行的一个方法获取不到任何关于world,entity等能妥善处理请求数据的实例,只能玩玩println,于是pass;最后一种虽然有点歪门邪道,但是测试的效果非常好,于是采用之。

首先需要制作一个类,暂时命名为BlockTestMessageHandler,引入IMessage,使用自动修正之后得到两个函数分别是fromBytes和toBytes,这两个函数是负责缓存收发数据的,假设我们需要传输的数据比较杂,就使用NBTTagCompound作为收发数据的对象,如果数据单一的话可以直接使用int,String等常用对象。假设缓存的NBTTagCompound变量名为text,那两个函数改写成这样

@Override
public void fromBytes(ByteBuf buf) {
// TODO Auto-generated method stub
text = ByteBufUtils.readTag(buf); // 接收时从返回的ByteBuf取得NBTTagCompound
}
@Override
public void toBytes(ByteBuf buf) {
// TODO Auto-generated method stub
ByteBufUtils.writeTag(buf, text); // 发送时将NBTTagCompound送入ByteBuf
}

这就是负责缓存的部分,有了这个部分,还需要执行接收的部分,发送的部分在toBytes就完成了,接收部分需要创建一个Handler内部类,引入IMessageHandler<BlockTestMessageHandler, IMessage>接口,自动补齐修正之后回调的onMessage参数为(BlockTestMessageHandler message, MessageContext ctx),然后里边加入这一句
System.out.println(String.format("Received %s from %s", message.text.getString("test"), ctx.getServerHandler().playerEntity.getDisplayName()));
return null;

这句的意思就是从本体message中取得的text为NBTTagCompound,再从里边取得键为test,值的类型为String的标签(键值对),同时又能从ctx中取到了EntityPlayer,能取到EntityPlayer也就意味着能够取到World,能取到这个剩下的该干什么就干什么了。

完成了MessageHandler之后需要在主文件中对这个Handler进行注册:
在外部加上
public static SimpleNetworkWrapper network;
在preInit中加上
network = NetworkRegistry.INSTANCE.newSimpleChannel("NetworkExample");
network.registerMessage(BlockTestMessageHandler.Handler.class, BlockTestMessageHandler.class, 0, Side.SERVER);

注册好之后就可以在客户端发送数据了,发送数据的方法为mod主文件.network.sendToServer(new BlockTestMessageHandler(tag));tag就是数据的内容。

在GUI中复写按钮按下的方法(actionPerformed),再通过上述发送数据的方法就能够实现客户端通知服务端的功能了。

参考资料:http://www.minecraftforge.net/forum/index.php/topic,20135.0.html

转载请注明出处 http://www.windworkshop.net/?p=15

本文链接地址:http://blog.windworkshop.net/?p=15 »文章允许转载 ,转载请注明出处,谢谢。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据