Unity3D|【游戏开发实战】教你Unity通过sproto协议与Skynet框架的服务端通信,附工程源码(Unity | Sproto | 协议 | Skynet)


文章目录

      • 一、前言
      • 二、搭建Skynet服务端
      • 三、Unity客户端
        • 1、创建Unity工程
        • 2、导入开源项目
          • 2.1、sproto-Csharp开源项目
          • 2.2、sprotodump开源项目
          • 2.3、sproto-Unity开源项目
        • 3、编写.sproto协议文件
          • 3.1、服务端协议文件:proto.lua
          • 3.2、客户端协议文件:game.sproto
        • 4、客户端.sproto文件转C#脚本
          • 4.1、安装lua
          • 4.2、sprotodump工具:sproto文件生成C#脚本
        • 5、客户端连接服务端
      • 四、客户端与服务端通信
        • 1、客户端发消息给服务端:c2s
          • 1.1、客户端部分
          • 1.2、服务端部分
          • 1.3、运行测试
        • 2、服务端发消息给客户端:s2c
          • 2.1、服务端部分
          • 2.2、客户端部分
          • 2.3、运行测试
      • 五、工程源码
      • 五、完毕

一、前言
嗨,大家好,我是新发。
最近在搞服务端Skynet框架,今天我想写一下Unity通过sproto协议与Skynet服务端通信的流程,画成图是这样子:
Unity3D|【游戏开发实战】教你Unity通过sproto协议与Skynet框架的服务端通信,附工程源码(Unity | Sproto | 协议 | Skynet)
文章图片

话不多说,我们开始吧~
二、搭建Skynet服务端
关于搭建Skynet服务端,我前两篇文章写了教程,建议先阅读我之前这两篇文章:
【游戏开发实战】手把手教你从零跑一个Skynet,详细教程,含案例讲解(服务端 | Skynet | Ubuntu)
【游戏开发实战】手把手教你在Windows上通过WSL运行Skynet,不用安装虚拟机,方便快捷(WSL | Linux | Ubuntu | Skynet | VSCode)
本文我就不过多赘述,搭建好环境后,运行Skynet,效果如下:
Unity3D|【游戏开发实战】教你Unity通过sproto协议与Skynet框架的服务端通信,附工程源码(Unity | Sproto | 协议 | Skynet)
文章图片

服务端模块架构如下:
Unity3D|【游戏开发实战】教你Unity通过sproto协议与Skynet框架的服务端通信,附工程源码(Unity | Sproto | 协议 | Skynet)
文章图片

三、Unity客户端
1、创建Unity工程 我使用的Unity版本为Unity 2021.1.7f1c1,因为这里我只演示客户端与服务端通过sproto协议通信的流程,不需要使用3D相关的功能,所以我创建的是一个2D模板的工程,工程名叫UnitySprotoDemo,如下:
Unity3D|【游戏开发实战】教你Unity通过sproto协议与Skynet框架的服务端通信,附工程源码(Unity | Sproto | 协议 | Skynet)
文章图片

2、导入开源项目 我们要在Unity中使用sproto协议进行通信,那就需要一套sproto协议的C#实现和工具。这种嘛,首选在GitHub中搜索相关的开源项目,避免不必要的重复造轮子。
关于GitHub的使用,我之前写过一篇教程,感兴趣的同学可以看看:《GitHub使用教程与常见问题解决——上传本地工程到GitHub仓库》
我找到了一套可以在Unity中使用的sprotoC#实现与工具,我们先在Unity工程的Assets文件夹中新建一个sproto文件夹,用于存放从GitHub中下载下来的sproto开源项目,
Unity3D|【游戏开发实战】教你Unity通过sproto协议与Skynet框架的服务端通信,附工程源码(Unity | Sproto | 协议 | Skynet)
文章图片

2.1、sproto-Csharp开源项目 GitHub地址:https://github.com/lvzixun/sproto-Csharp
sproto-Csharpsproto的纯C#实现。
我们先把它下载下来,放到Assets/Sproto/sproto-Csharp文件夹中,如下:
Unity3D|【游戏开发实战】教你Unity通过sproto协议与Skynet框架的服务端通信,附工程源码(Unity | Sproto | 协议 | Skynet)
文章图片

有一些测试用的代码,我们可以把它删掉,如下:
Unity3D|【游戏开发实战】教你Unity通过sproto协议与Skynet框架的服务端通信,附工程源码(Unity | Sproto | 协议 | Skynet)
文章图片

2.2、sprotodump开源项目 GitHub地址:https://hub.fastgit.org/lvzixun/sprotodump
sprotodump是将 .sproto文件转为.cs.spb.spb.go.md.lua等文件的工具,下文我会讲如何使用这个工具。
我们先把它下载下来,放到Assets/Sproto/sprotodump文件夹中,如下:
Unity3D|【游戏开发实战】教你Unity通过sproto协议与Skynet框架的服务端通信,附工程源码(Unity | Sproto | 协议 | Skynet)
文章图片

2.3、sproto-Unity开源项目 GitHub地址:https://github.com/m2q1n9/sproto-Unity
sproto-Unity封装了三个类:NetCoreNetSenderNetReceiver,下文我会讲下如何使用。
我们先把它下载下来,放到Assets/Sproto/sproto-Unity文件夹中,如下:
Unity3D|【游戏开发实战】教你Unity通过sproto协议与Skynet框架的服务端通信,附工程源码(Unity | Sproto | 协议 | Skynet)
文章图片

此时工程会报错,
Unity3D|【游戏开发实战】教你Unity通过sproto协议与Skynet框架的服务端通信,附工程源码(Unity | Sproto | 协议 | Skynet)
文章图片

这是因为我们刚刚删除了sproto-Csharp的一些代码导致的,不用担心,我们等下执行.sproto生成cs就自动解决了。
3、编写.sproto协议文件 现在我们来写协议文件,包括服务端和客户端。
3.1、服务端协议文件:proto.lua skynet框架中的examples里,已经为我们准备好了一个协议文件:proto.lua
Unity3D|【游戏开发实战】教你Unity通过sproto协议与Skynet框架的服务端通信,附工程源码(Unity | Sproto | 协议 | Skynet)
文章图片

我们改一下,把不需要的协议删掉,最终如下:
local sprotoparser = require "sprotoparser"local proto = { }proto.c2s = sprotoparser.parse [[ .package { type 0 : integer session 1 : integer }sayhello 1 { request { what 0 : string } response { error_code 0 : integer msg 1 : string } }]]proto.s2c = sprotoparser.parse [[ .package { type 0 : integer session 1 : integer }heartbeat 2 {} ]]return proto

注:由于客户端的sproto工具的不能支持c2ss2c的协议使用相同的tag,比如sayhello消息的tag1,那么heartbeat消息就不可以使用1作为tag,这里我是使用2作为heartbeattag
3.2、客户端协议文件:game.sproto 我们在Unity工程的Assets/Sproto目录中新建一个文件夹protocol,用于存放协议文件,
Unity3D|【游戏开发实战】教你Unity通过sproto协议与Skynet框架的服务端通信,附工程源码(Unity | Sproto | 协议 | Skynet)
文章图片

protocol文件夹中新建一个game.proto文件,内容如下:
.package {type 0 : integer session 1 : integer }sayhello 1 {request {what 0 : string } response {error_code 0 : integer msg 1 : string } }heartbeat 2 { }

4、客户端.sproto文件转C#脚本 接下来,我们要使用sprotodump将客户端的game.proto文件转成C#脚本。
因为sprotodump需要是用lua来执行,所以这里我们需要先安装lua环境。
4.1、安装lua lua官网:http://www.lua.org/
lua Windows版:https://github.com/rjpcomputing/luaforwindows/releases
Unity3D|【游戏开发实战】教你Unity通过sproto协议与Skynet框架的服务端通信,附工程源码(Unity | Sproto | 协议 | Skynet)
文章图片

我们下载下来然后安装即可,完整完毕后,打开终端,执行lua -v,如果能输出版本号,则说明lua环境弄好了。
Unity3D|【游戏开发实战】教你Unity通过sproto协议与Skynet框架的服务端通信,附工程源码(Unity | Sproto | 协议 | Skynet)
文章图片

4.2、sprotodump工具:sproto文件生成C#脚本 sprotodump是将 .sproto文件转为.cs.spb.spb.go.md.lua等文件的工具,我们这里是要把game.proto文件转成C#脚本。
sprotodump的使用方法如下:
usage: lua sprotodump.lua

例:
lua lua sprotodump.lua -cs game.sproto -o gamesproto.cs

我们把命令写到bat脚本中,双击执行即可,提高工作效率。
Assets/Sproto/protocol目录中创建gen_cs.bat文件,再创建一个gen_cs文件夹用于存放生成的C#脚本。
Unity3D|【游戏开发实战】教你Unity通过sproto协议与Skynet框架的服务端通信,附工程源码(Unity | Sproto | 协议 | Skynet)
文章图片

gen_cs.bat脚本内容如下,我写了详细注释,大家应该能看懂,
echo off :: 当前路径 set curdir=%~dp0 :: 进入sprotodump目录 cd /d %curdir%/../sprotodump :: 将.sproto文件转为C#脚本,存放在gen_cs文件夹中 lua ./sprotodump.lua -cs %curdir%/game.sproto -o %curdir%/gen_cs/gamesproto.cs :: 输出完成 echo sproto to cs, done :: 按任意键退出 pause

我们执行gen_cs.bat脚本时,可能会报错:
Unity3D|【游戏开发实战】教你Unity通过sproto协议与Skynet框架的服务端通信,附工程源码(Unity | Sproto | 协议 | Skynet)
文章图片

我们打开sprotodump.lua脚本,把README后面的[[]]改成[=[]=]即可,
Unity3D|【游戏开发实战】教你Unity通过sproto协议与Skynet框架的服务端通信,附工程源码(Unity | Sproto | 协议 | Skynet)
文章图片

如下:
Unity3D|【游戏开发实战】教你Unity通过sproto协议与Skynet框架的服务端通信,附工程源码(Unity | Sproto | 协议 | Skynet)
文章图片

重新执行gen_cs.bat脚本,
Unity3D|【游戏开发实战】教你Unity通过sproto协议与Skynet框架的服务端通信,附工程源码(Unity | Sproto | 协议 | Skynet)
文章图片

生成成功,可以看到gen_cs文件夹中生成了gamesproto.cs脚本,
Unity3D|【游戏开发实战】教你Unity通过sproto协议与Skynet框架的服务端通信,附工程源码(Unity | Sproto | 协议 | Skynet)
文章图片

5、客户端连接服务端 我们先新建一个Scripts文件夹,用于存放我们写的游戏逻辑脚本,
Unity3D|【游戏开发实战】教你Unity通过sproto协议与Skynet框架的服务端通信,附工程源码(Unity | Sproto | 协议 | Skynet)
文章图片

Scripts文件夹中创建一个Main.cs脚本,作为入口脚本,在Start函数中做一些初始化操作,并在Update中驱动NetCore的消息分发,
// Main.csusing UnityEngine; public class Main : MonoBehaviour {void Start() {// 初始化 NetCore.Init(); NetSender.Init(); NetReceiver.Init(); NetCore.enabled = true; } void Update() {// 驱动消息分发 NetCore.Dispatch(); } }

接着,我们就可以连接服务端了,由于是本地连接,所以IP地址使用127.0.0.1即可,端口的话,我们可以看到服务端监听的端口是8888
Unity3D|【游戏开发实战】教你Unity通过sproto协议与Skynet框架的服务端通信,附工程源码(Unity | Sproto | 协议 | Skynet)
文章图片

客户端连接服务端代码如下:
// Main.csvoid Start() { // ... // 连接服务端 NetCore.Connect("127.0.0.1", 8888, () => {// 连接结果 Debug.Log("connect result: " + NetCore.connected); }); }

我们把Main.cs脚本挂到Main Camera上,
Unity3D|【游戏开发实战】教你Unity通过sproto协议与Skynet框架的服务端通信,附工程源码(Unity | Sproto | 协议 | Skynet)
文章图片

运行Unity,可以看到输出了connect result: True,说明连接服务器成功了,
Unity3D|【游戏开发实战】教你Unity通过sproto协议与Skynet框架的服务端通信,附工程源码(Unity | Sproto | 协议 | Skynet)
文章图片

此时服务端也输出了相关日志,
Unity3D|【游戏开发实战】教你Unity通过sproto协议与Skynet框架的服务端通信,附工程源码(Unity | Sproto | 协议 | Skynet)
文章图片

四、客户端与服务端通信
1、客户端发消息给服务端:c2s 1.1、客户端部分 现在,我们让客户端给服务端发一条sayhello消息,
// Main.cs void Start() { // ... NetCore.Connect("127.0.0.1", 8888, () => {Debug.Log("connect result: " + NetCore.connected); if (NetCore.connected) {// 给服务端发送一条sayhello消息 SendSayHello(); } }); }void SendSayHello() { var req = new SprotoType.sayhello.request(); req.what = "Hi, I am Unity!"; Debug.Log("发送sayhello消息给服务端"); NetSender.Send(req, (data) => {var rsp = data as SprotoType.sayhello.response; Debug.LogFormat("服务端sayhello返回, error_code: {0}, msg: {1}", rsp.error_code, rsp.msg); }); }

1.2、服务端部分 我们给服务端的agent.lua脚本添加sayhello的响应,
function REQUEST:sayhello() print("recv client sayhello: ", self.what) return { error_code = 0, msg = "Hi, I am Skynet!" } end

如下:
Unity3D|【游戏开发实战】教你Unity通过sproto协议与Skynet框架的服务端通信,附工程源码(Unity | Sproto | 协议 | Skynet)
文章图片

1.3、运行测试 我们重新启动服务端,然后运行客户端,可以看到客户端发送了sayhello消息,并受到了服务端的返回,
Unity3D|【游戏开发实战】教你Unity通过sproto协议与Skynet框架的服务端通信,附工程源码(Unity | Sproto | 协议 | Skynet)
文章图片

我们看服务端的日志,也输出了相关日志,说明正常接收到了客户端的消息了,
Unity3D|【游戏开发实战】教你Unity通过sproto协议与Skynet框架的服务端通信,附工程源码(Unity | Sproto | 协议 | Skynet)
文章图片

2、服务端发消息给客户端:s2c 服务端每隔5秒给客户端发送一条heartbeat消息,消息定义如下:
heartbeat 2 {}

2.1、服务端部分 如下,服务端受到客户端连接后,会循环每隔5秒给客户端发送一条heartbeat消息。
Unity3D|【游戏开发实战】教你Unity通过sproto协议与Skynet框架的服务端通信,附工程源码(Unity | Sproto | 协议 | Skynet)
文章图片

注意:因为heartbeat消息没有参数,所以这里不用传其他参数,如果heartbeat的消息定义中有参数,比如这样
heartbeat 2 { request { cnt 0 : integer } }

那么发消息时传cnt参数是这样子的:
send_package(send_request("heartbeat", { cnt = 666 }))

2.2、客户端部分 客户端部分需要通过NetReceiver注册消息的响应函数,如下:
NetReceiver.AddHandler((data) => {Debug.Log("收到服务端的heartbeat消息"); return null; });

2.3、运行测试 我们重新启动服务端,然后运行客户端,可以看到客户端收到了服务端发送的heartbeat消息了,
Unity3D|【游戏开发实战】教你Unity通过sproto协议与Skynet框架的服务端通信,附工程源码(Unity | Sproto | 协议 | Skynet)
文章图片

五、工程源码
本文工程源码,我已上传到CODE CHINA,感兴趣的同学可自行下载学习,地址:
https://codechina.csdn.net/linxinfa/UnitySprotoDemo
Unity3D|【游戏开发实战】教你Unity通过sproto协议与Skynet框架的服务端通信,附工程源码(Unity | Sproto | 协议 | Skynet)
文章图片

五、完毕
【Unity3D|【游戏开发实战】教你Unity通过sproto协议与Skynet框架的服务端通信,附工程源码(Unity | Sproto | 协议 | Skynet)】好了,就先写这么多吧,关于SkynetSproto还有很多很多内容,本文只是一个入门,希望可以帮助到新手同学~
我是林新发:https://blog.csdn.net/linxinfa
原创不易,若转载请注明出处,感谢大家~
喜欢我的可以点赞、关注、收藏,如果有什么技术上的疑问,欢迎留言或私信~

    推荐阅读