[未知之域]简单网络通信包装类(SimpleNetworkWrapper)——简单地进行网络通信 - 编程开发 - Minecraft(我的世界)中文论坛 -.html

[未知之域]简单网络通信包装类(SimpleNetworkWrapper)——简单地进行网络通信 - 编程开发 - Minecraft(我的世界)中文论坛 -

Minecraft(我的世界)中文论坛

 找回密码
 注册(register)

!header_login!

只需一步,立刻登录

查看: 8056|回复: 9
打印 上一主题 下一主题

[Mod开发教程] [未知之域]简单网络通信包装类(SimpleNetworkWrapper)——简单地进行网络通信

[复制链接]
耗子 当前离线
积分
14092
帖子
主题
精华
贡献
爱心
钻石
人气
下界之星
最后登录
1970-1-1
注册时间
2012-2-18
查看详细资料

来自:广西

跳转到指定楼层
楼主
发表于 2017-7-27 19:09:43 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

您尚未登录,立即登录享受更好的浏览体验!

您需要 登录 才可以下载或查看,没有帐号?注册(register)

x
本帖最后由 耗子 于 2018-8-3 11:13 编辑

简单网络通信包装类(SimpleNetworkWrapper)——简单地进行网络通信

在实际开发过程中,我们常常需要用到网络通信。用到网络通信的地方有很多,例如按下按键释放技能,同步玩家属性,监听图形界面按钮按下,让客户端播放特效等等。那么怎么样进行网络通信呢?

简单网络通信包装类 SimpleNetworkWrapper

为了方便的进行网络通信,Forge提供一个简单的网络通信包装类——SimpleNetworkWrapper。这个类位于net.minecraftforge.fml.common.network.simpleimpl包下。

那么,怎么使用这个类呢?首先我们需要获取一个SimpleNetworkWrapper对象。

  1. NetworkRegistry.INSTANCE.newSimpleChannel(channel);
复制代码

在此解释一下channel(频道)参数,该参数是一个字符串(String),表示网络通信频道名,只有在相同的频道,数据才能互相传输。

以上代码可以获取到一个SimpleNetworkWrapper对象,然后我们将这个对象储存至一个静态字段中以便在模组的任何地方调用,比如这样:

  1. @Mod(modid = ChinaCraft.MODID, name = ChinaCraft.NAME, version = ChinaCraft.VERSION)
  2. public final class ChinaCraft {
  3.     public static final String MODID = "chinacraft";
  4.     public static final String NAME = "ChinaCraft 2";
  5.     public static final String VERSION = "0.0.1";

  6.     private static SimpleNetworkWrapper network;

  7.     @EventHandler
  8.     public void init(FMLInitializationEvent event) {
  9.         network = NetworkRegistry.INSTANCE.newSimpleChannel(MODID);
  10.     }

  11.     public static SimpleNetworkWrapper getNetwork() {
  12.         return network;
  13.     }
  14. }
复制代码

这样,我们就可以使用ChinaCraft.getNetwork()方法在模组的任何地方调用SimpleNetworkWrapper对象了。

消息类和消息处理类

接下来,我们开始编写我们的消息类和消息处理类。消息类需要实现IMessage接口,该类必须要有一个无参构造方法,并且需要实现fromBytes和toBytes方法。

  1. public class RedPacketMessage implements IMessage {

  2.     public RedPacketMessage() {} //必须要有一个无参构造方法

  3.     @Override
  4.     public void fromBytes(ByteBuf buf) {} //将字节流转换为信息

  5.     @Override
  6.     public void toBytes(ByteBuf buf) {} //将信息转换为字节流
  7. }
复制代码

可以看到,fromBytes和toBytes方法都有一个ByteBuf类型的参数,ByteBuf类中提供了很多read和write方法,那么我们该如何使用呢?举个例子:

  1. public class RedPacketMessage implements IMessage {

  2.     private String sender;

  3.     public RedPacketMessage() {}

  4.     public RedPacketMessage(String sender) {
  5.         this.sender = sender;
  6.     }

  7.     @Override
  8.     public void fromBytes(ByteBuf buf) {
  9.         char chars[] = new char[buf.readInt()]; //读取字符串长度
  10.         for(int i=0;i<chars.length;i++) //读取字符
  11.             chars = buf.readChar();
  12.         sender = String.valueOf(chars); //创建字符串对象
  13.     }

  14.     @Override
  15.     public void toBytes(ByteBuf buf) {
  16.         buf.writeInt(sender.length()); //写入字符串长度
  17.         for(char c:sender.toCharArray()) //写入字符串
  18.             buf.writeChar(c);
  19.     }
复制代码

提示:可以看到ByteBuf类有些不方便使用,所以可以使用MC实现的PacketBuffer类和Forge提供的ByteBufUtils类。
接下来,我们需要为这个消息编写一个处理类,来处理收到的消息,消息处理类需要实现IMessageHandler接口,并且需要实现onMessage方法。此外,该接口还是一个泛型接口,拥有两个泛型形参REQ extends IMessage和REPLY extends IMessage,其中REQ表示收到的消息类,REPLY表示回复的消息类。

  1. public class RedPacketMessageHandler implements IMessageHandler<RedPacketMessage, IMessage> {

  2.         @Override
  3.         public IMessage onMessage(RedPacketMessage message, MessageContext ctx) {
  4.             return null; //当你不需要回复消息时,可以将REPLY填写为IMessage,并且返回null;
  5.         }
  6. }
复制代码

接下来,我们需要将消息类和消息处理类注册到SimpleNetworkWrapper对象中。

  1. network.registerMessage(handler,message,id,side);
复制代码

解释一下registerMessage方法的四个参数,第一个参数handler需要一个IMessageHandler对象,第二个参数message则是对应的消息类的类对象,第三个参数id表示该消息的id,范围为0~255,且不得重复,第四个参数side表示收到消息的对象,Side.SERVER表示消息由客户端发送,服务器接收,Side.CLIENT表示消息由服务端发送,客户端接收。

发送消息

那么,注册好了以后我们怎么发送消息呢?SimpleNetworkWrapper类实现了五个发送方法,分别有不同的作用。

  1.     /**
  2.      * 发送消息给所有玩家(服务端调用该方法)
  3.      */
  4.     public void sendToAll(IMessage message)

  5.     /**
  6.      * 发送消息到指定玩家(服务端调用该方法)
  7.      */
  8.     public void sendTo(IMessage message, EntityPlayerMP player)

  9.     /**
  10.      * 发送消息到指定范围内的所有玩家(服务端调用该方法)
  11.      */
  12.     public void sendToAllAround(IMessage message, NetworkRegistry.TargetPoint point)

  13.     /**
  14.      * 发送消息到指定世界内的所有玩家(服务端调用该方法)
  15.      */
  16.     public void sendToDimension(IMessage message, int dimensionId)

  17.     /**
  18.      * 发送消息到服务器(客户端调用该方法)
  19.      */
  20.     public void sendToServer(IMessage message)
复制代码

例如:

  1. ChinaCraft.getNetwork().sendToServer(new RedPacketMessage());
复制代码

ByteBufUtils优化的字符串处理

  1. public class RedPacketMessage implements IMessage {

  2.     private String sender;

  3.     public RedPacketMessage() {}

  4.     public RedPacketMessage(String sender) {
  5.         this.sender = sender;
  6.     }

  7.     @Override
  8.     public void fromBytes(ByteBuf buf) {
  9.         sender = ByteBufUtils.readUTF8String(buf);
  10.     }

  11.     @Override
  12.     public void toBytes(ByteBuf buf) {
  13.         ByteBufUtils.writeUTF8String(buf,sender);
  14.     }
复制代码

本篇教程到这就结束了,感谢您的阅读。
本教程来自ChinaCraft2代码详解——大型模组开发笔记    Github

欢迎各位支持作者,以编写和翻译更多优秀教程。


来自群组: Unknown Domain

评分

参与人数 6人气 +12金粒 +15收起 理由
1257375501+ 2MCBBS有你更精彩~
lrsoft+ 2神乎其技,不服不行!
yd52013+ 2MCBBS有你更精彩~
Ir.Nep+ 2神乎其技,不服不行!
清晨w+ 1+ 15MCBBS有你更精彩~
a8105+ 3虽不明,但觉厉

查看全部评分

帖子永久链接: 

Minecraft中文论坛 - 论坛版权1、本主题所有言论和图片纯属会员个人意见,与本论坛立场无关
2、本站所有主题由该帖子作者发表,该帖子作者享有帖子相关版权
3、其他单位或个人使用、转载或引用本文时必须同时征得该帖子作者的同意
4、帖子作者须承担一切因本文发表而直接或间接导致的民事或刑事法律责任
5、本帖若有内容转载自其它媒体,不代表本站赞同其观点和对其真实性负责
6、若本帖涉及任何版权问题,请立即告知本站,本站将及时予以删除并致以最深的歉意
7、Minecraft(我的世界)中文论坛管理员和版主有权不事先通知发贴者而删除本文

3TUSK 当前离线
积分
8157
帖子
主题
精华
贡献
爱心
钻石
人气
下界之星
最后登录
1970-1-1
注册时间
2013-3-8
查看详细资料

来自:山东

沙发
发表于 2017-7-28 12:58:01 | 只看该作者

  1.     @Override
  2.     public void fromBytes(ByteBuf buf) {} //将字节码转换为信息

  3.     @Override
  4.     public void toBytes(ByteBuf buf) {} //将信息转换为字节码
复制代码


字节码?字节流?是不是有一点歧义?
(第一眼看到字节码时,我还以为我看到的是bytecode... 仔细一看发觉不对。)

Anyhow, nice work
回复

使用道具 举报

耗子 当前离线
积分
14092
帖子
主题
精华
贡献
爱心
钻石
人气
下界之星
最后登录
1970-1-1
注册时间
2012-2-18
查看详细资料

来自:广西

板凳
 楼主| 发表于 2017-7-28 13:19:43 | 只看该作者
u.s.knowledge 发表于 2017-7-28 12:58
字节码?字节流?是不是有一点歧义?
(第一眼看到字节码时,我还以为我看到的是bytecode... 仔细一看发 ...

确实在这里揣摩了一段时间,不知道用啥好,感谢您的建议
回复

使用道具 举报

godone 当前离线
积分
88
帖子
主题
精华
贡献
爱心
钻石
人气
下界之星
最后登录
1970-1-1
注册时间
2018-7-17
查看详细资料

来自:安徽

地板
发表于 2018-12-7 10:58:08 | 只看该作者
mark 刚好看到
回复

使用道具 举报

Lovely_Penguin 当前离线
积分
201
帖子
主题
精华
贡献
爱心
钻石
人气
下界之星
最后登录
1970-1-1
注册时间
2018-6-15
查看详细资料

来自:辽宁

5#
发表于 2018-12-8 20:36:12 | 只看该作者
膜拜大佬
太棒了
回复

使用道具 举报

lrsoft 当前离线
积分
3333
帖子
主题
精华
贡献
爱心
钻石
人气
下界之星
最后登录
1970-1-1
注册时间
2014-5-20
查看详细资料

来自:广东

6#
发表于 2018-12-19 21:57:28 | 只看该作者
registerMessage里前两个参数handler和message是类不是对象吧
回复

使用道具 举报

耗子 当前离线
积分
14092
帖子
主题
精华
贡献
爱心
钻石
人气
下界之星
最后登录
1970-1-1
注册时间
2012-2-18
查看详细资料

来自:陕西

7#
 楼主| 发表于 2018-12-19 22:52:54 | 只看该作者
lrsoft 发表于 2018-12-19 21:57
registerMessage里前两个参数handler和message是类不是对象吧

registerMessage方法有两个,声明不同罢了
回复

使用道具 举报

155746899 当前离线
积分
780
帖子
主题
精华
贡献
爱心
钻石
人气
下界之星
最后登录
1970-1-1
注册时间
2017-2-11
查看详细资料

来自:河北

8#
发表于 2019-2-13 13:39:08 | 只看该作者
很棒的帖子
回复

使用道具 举报

Clemens_Mine 当前离线
积分
1081
帖子
主题
精华
贡献
爱心
钻石
人气
下界之星
最后登录
1970-1-1
注册时间
2018-8-14
查看详细资料

来自:江苏

9#
发表于 2019-2-13 18:51:09 | 只看该作者
感谢楼主分享资源!
回复

使用道具 举报

minecraft65536 当前离线
积分
2062
帖子
主题
精华
贡献
爱心
钻石
人气
下界之星
最后登录
1970-1-1
注册时间
2016-1-29
查看详细资料

来自:北京

10#
发表于 2019-3-7 22:26:09 | 只看该作者
我来补充两点:
①要注意读取包字节流时和写入包字节流时要注意不同数据的读取次序要一样
②NBT标签可以直接传送:
  1. //写入NBT到字节流
  2. ByteBufUtils.writeTag(buf, nbt);
  3. //从字节流读取NBT
  4. NBTTagCompound nbt = ByteBufUtils.readTag(buf);
复制代码
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册(register)

本版积分规则

Archiver|小黑屋|Mcbbs.net ( 京ICP备15023768号-1 ) | 京公网安备 11010502037624号 | 手机版

GMT+8, 2022-10-1 01:24 , Processed in 0.648057 second(s), Total 25, Slave 24 queries, Release: Build.2022.09.29 1359, Gzip On, Redis On.

"Minecraft"以及"我的世界"为美国微软公司的商标 本站与微软公司没有从属关系

© 2010-2022 我的世界中文论坛 版权所有 本站内原创内容版权属于其原创作者,除作者或版规特别声明外未经许可不得转载