文章目录

  • Import
  • protogen使用方法
  • 客户端接口
  • 服务端接口
  • 数据处理
  • Example

Import

  • 下载SKFramework框架,导入到Unity中;

  • 在框架Package Manager中搜索并下载导入Socket模块;
  • Package包中包含Server服务端内容以及protogen工具,将其解压到工程外;

protogen使用方法

  • 编写的.proto文件放入proto文件夹中;

  • 打开run.bat文件,编辑编译指令;

  • 运行run.bat文件,生成后的.cs脚本在cs文件夹中,将其放入到Unity中即可;

注:.proto文件编译为.cs脚本后,该脚本一般不轻易改动。

  • 如果有大量的.proto文件需要编译,编辑编译指令可能会比较繁琐,因此可以使用自定义的工具Protogen Helper来自动创建run.bat文件。

代码如下:

using System.IO;using UnityEngine;using UnityEditor;using System.Text;using System.Diagnostics;namespace Mutiplayer{/// /// Proto通信协议类编译工具/// public class ProtogenHelper : EditorWindow{[MenuItem("Multiplayer/Protogen Helper")]public static void Open(){var window = GetWindow<ProtogenHelper>("Protogen Helper");window.maxSize = new Vector2(1000f, 60f);window.minSize = new Vector2(200f, 60f);window.Show();}//根路径private string rootPath;private const string prefsKey = "Protogen.exe Path";private void OnEnable(){rootPath = EditorPrefs.HasKey(prefsKey) " />.GetString(prefsKey) : string.Empty;}private void OnGUI(){GUILayout.Label("protogen.exe所在路径:");GUILayout.BeginHorizontal();{string path = GUILayout.TextField(rootPath);if (path != rootPath){rootPath = path;EditorPrefs.SetString(prefsKey, rootPath);}if (GUILayout.Button("Browse", GUILayout.Width(55f))){path = EditorUtility.OpenFolderPanel("选择路径", rootPath, null);if (path != rootPath){rootPath = path;EditorPrefs.SetString(prefsKey, rootPath);}}}GUILayout.EndHorizontal();if (GUILayout.Button("Create .bat")){string protoPath = rootPath + "/proto";if (!Directory.Exists(protoPath)){UnityEngine.Debug.Log($"文件夹不存在 {protoPath}");return;}string csPath = rootPath + "/cs";//如果cs文件夹不存在则创建if (!Directory.Exists(csPath)){Directory.CreateDirectory(csPath);}DirectoryInfo di = new DirectoryInfo(protoPath);//获取所有.proto文件信息FileInfo[] protos = di.GetFiles("*.proto");//使用StringBuilder拼接字符串StringBuilder sb = new StringBuilder();//遍历for (int i = 0; i < protos.Length; i++){string proto = protos[i].Name;//拼接编译指令sb.Append(rootPath + @"/protogen.exe -i:proto\" + proto + @" -o:cs\" + proto.Replace(".proto", ".cs") + "\r\n");}sb.Append("pause");//生成".bat文件"string batPath = $"{rootPath}/run.bat";File.WriteAllText(batPath, sb.ToString());//打开该文件夹Process.Start(rootPath);}}}}

客户端接口

  • Connect: 连接服务端;
/// /// 连接服务端/// /// 服务器IP地址/// 端口public void Connect(string ip, int port)
  • Send:发送数据;
/// /// 发送数据/// /// 协议public void Send(IExtensible proto)
  • Close:关闭与服务端的连接;
/// /// 关闭连接/// public void Close()

服务端接口

  • 向单个客户端发送数据;
/// /// 向客户端发送协议(单点发送)/// /// 客户端/// 协议public static void Send(Client client, IExtensible proto)
  • 向所有客户端发送数据;
/// /// 向所有客户端发送协议(广播)/// /// 协议public static void Send(IExtensible proto)
  • 向指定客户端之外的所有客户端发送数据;
/// /// 向指定客户端之外的所有客户端发送协议/// /// 协议/// 不需要发送的客户端public static void Send(IExtensible proto, Client except)
  • 关闭指定客户端的连接;
/// /// 关闭客户端连接/// /// 客户端public static void Close(Client client)

数据处理

根据解析出的协议名来调用相应的处理方法:

以上是服务端对ProtoTest类型协议的处理示例,服务端通过Send将该消息转发给所有客户端。

Example

using UnityEngine;using SK.Framework.Sockets;using System.Collections.Generic; public class Example : MonoBehaviour{private Vector2 scroll;private List<string> messages = new List<string>();private string content;private NetworkManager NetworkManager;private void OnGUI(){GUI.enabled = !NetworkManager.IsConnected;if (GUILayout.Button("Connect", GUILayout.Width(200f), GUILayout.Height(50f))){NetworkManager.Connect("127.0.0.1", 8801);}GUI.enabled = NetworkManager.IsConnected;if (GUILayout.Button("Disconnect", GUILayout.Width(200f), GUILayout.Height(50f))){NetworkManager.Close();}GUILayout.BeginVertical("Box", GUILayout.Height(200f), GUILayout.Width(300f));scroll = GUILayout.BeginScrollView(scroll);{for (int i = 0; i < messages.Count; i++){GUILayout.Label(messages[i]);}}GUILayout.EndScrollView();GUILayout.EndVertical();GUILayout.BeginHorizontal();content = GUILayout.TextField(content, GUILayout.Height(50f));if (GUILayout.Button("Send", GUILayout.Width(50f), GUILayout.Height(50f))){if (!string.IsNullOrEmpty(content)){ProtoBuf.IExtensible proto = new proto.ProtoTest.ProtoTest() { content = content };NetworkManager.Send(proto);content = string.Empty;}}GUILayout.EndHorizontal();}private void Start(){NetworkManager = GetComponent<NetworkManager>();}public void OnProtoTestEvent(proto.ProtoTest.ProtoTest protoTest){messages.Add(protoTest.content);}}

Unity Multiplayer 多人在线示例工程:https://github.com/136512892/Unity-Multiplayer