Unity【Multiplayer 多人在线】服务端、客户端通用架构的使用指南

news2024/11/23 19:34:48

文章目录

  • 🚩 Import
  • 🚀 protogen使用方法
  • 🪐 客户端接口
  • 🌈 服务端接口
  • 🧭 数据处理
  • 🎨 Example


🚩 Import

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

SKFramework

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

Server和protogen

🚀 protogen使用方法

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

proto文件

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

编译指令

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

编译成功

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

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

Protogen Helper

代码如下:

using System.IO;
using UnityEngine;
using UnityEditor;
using System.Text;
using System.Diagnostics;

namespace Mutiplayer
{
    /// <summary>
    /// Proto通信协议类编译工具
    /// </summary>
    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) ? EditorPrefs.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($"<color=red>文件夹不存在</color> {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: 连接服务端;
/// <summary>
/// 连接服务端
/// </summary>
/// <param name="ip">服务器IP地址</param>
/// <param name="port">端口</param>
public void Connect(string ip, int port)
  • Send:发送数据;
/// <summary>
/// 发送数据
/// </summary>
/// <param name="proto">协议</param>
public void Send(IExtensible proto)
  • Close:关闭与服务端的连接;
/// <summary>
/// 关闭连接
/// </summary>
public void Close()

🌈 服务端接口

  • 向单个客户端发送数据;
/// <summary>
/// 向客户端发送协议(单点发送)
/// </summary>
/// <param name="client">客户端</param>
/// <param name="proto">协议</param>
public static void Send(Client client, IExtensible proto)
  • 向所有客户端发送数据;
/// <summary>
/// 向所有客户端发送协议(广播)
/// </summary>
/// <param name="proto">协议</param>
public static void Send(IExtensible proto)
  • 向指定客户端之外的所有客户端发送数据;
/// <summary>
/// 向指定客户端之外的所有客户端发送协议
/// </summary>
/// <param name="proto">协议</param>
/// <param name="except">不需要发送的客户端</param>
public static void Send(IExtensible proto, Client except)
  • 关闭指定客户端的连接;
/// <summary>
/// 关闭客户端连接
/// </summary>
/// <param name="client">客户端</param>
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);
    }
}

Example

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/66224.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

osgEarth示例分析——osgearth_colorfilter

前言 osgearth_colorfilter颜色过滤器示例。本示例中&#xff0c;主要展示了6种颜色过滤器的使用&#xff0c;分别是:HSLColorFilter、RGBColorFilter、CMYKColorFilter、BrightnessContrastColorFilter、GammaColorFilter、ChromaKeyColorFilter。 执行命令 // 一条命令是一…

Docker日常运维小技巧

一、故障定位 1、查看容器内部 https 请求响应时间 docker exec -t $(docker ps -f nameblog_web -q) curl -H X-Forwarded-Proto:https \-w %{time_total} -o /dev/null -s localhost 2、查看容器日志 docker logs --tail 50 --follow --timestamps mediawiki_web_1 3、删…

深圳SMT贴片行业MES系统解决方案~MES系统服务商~先达智控

随着我国工业的迅速发展&#xff0c;所有电子行业都离不开SMT贴片生产&#xff0c;SMT贴片生产是电子行业的至关重要的一道工业环节&#xff0c;我国作为一个工业制造大国&#xff0c;有着完备的SMT现代产业体系。SMT贴片领域是我国支柱性产业其一&#xff0c;SMT贴片产品涵盖工…

【JavaWeb开发-Servlet】day01-使用TomCat实现本地web部署

目录 1、准备java web开发环境 &#xff08;1&#xff09;下载javaJDK&#xff08;推荐使用JDK1.8&#xff0c;企业常用且稳定&#xff09; &#xff08;2&#xff09;下载TomCat服务器 2、创建web服务器TomCat (1)创建一个项目文件夹 (2)在文件夹中新建一个记事本并编以下…

算法大神左程云耗尽5年心血分享程序员代码面试指南第2版文档

前言 学习是一种基础性的能力。然而&#xff0c;“吾生也有涯&#xff0c;而知也无涯。”&#xff0c;如果学习不注意方法&#xff0c;则会“以有涯随无涯&#xff0c;殆矣”。 学习就像吃饭睡觉一样&#xff0c;是人的一种本能&#xff0c;人人都有学习的能力。我们在刚出生…

移动WEB开发之rem布局--苏宁首页案例制作(技术方案1)

案例&#xff1a;苏宁网移动端首页 访问地址&#xff1a;苏宁易购(Suning.com)-家电家装成套购&#xff0c;专注服务省心购&#xff01; 1. 技术选型 方案&#xff1a;我们采取单独制作移动页面方案 技术&#xff1a;布局采取rem适配布局&#xff08;less rem 媒体查询&am…

用 TensorFlow.js 在浏览器中训练一个计算机视觉模型(手写数字分类器)

文章目录Building a CNN in JavaScriptUsing Callbacks for VisualizationTraining with the MNIST DatasetRunning Inference on Images in TensorFlow.jsReferences我们在《在浏览器中运行 TensorFlow.js 来训练模型并给出预测结果&#xff08;Iris 数据集&#xff09;》中已…

数字源表如何测试MOS管?

MOSFET(金属—氧化物半导体场效应晶体管)是 一种利用电场效应来控制其电流大小的常见半导体器件&#xff0c;可 以 广 泛 应 用 在 模 拟 电 路 和 数 字 电 路 当 中 。 MOSFET可以由硅制作&#xff0c;也可以由石墨烯&#xff0c;碳纳米管 等材料制作&#xff0c;是材料及器件…

集成电路模拟版图入门-转行模拟版图基础学习笔记(二)

在众多IC岗位中&#xff0c;模拟版图确实属于容易入门&#xff0c;吸引来很多想要转行IC行业的朋友&#xff0c;但需要掌握的知识点和技巧并不比设计少&#xff0c;属于门槛简单&#xff0c;上手不易&#xff0c;想要自学模拟版图似乎比较困难。 之前为大家分享过移知学员的模…

(十四)笔记.net学习之RabbitMQ工作模式

RabbitMQ在.net中简单使用一、简单模式1.生产者2.消费者二、工作队列模式1.工作队列模式介绍2.生产者发送消息3.消费能力三、发布/订阅模式1.介绍2.生产者3.消费者四、Routing路由模式1.介绍2.生产着3.消费者五、topic 主题模式1.介绍2. 生产者3.消费者一、简单模式 1.生产者 …

MyBatis系列第1篇:MyBatis未出世之前我们那些痛苦的经历

这么多技术&#xff0c;为什么我们选择的是mybatis 不知道大家是否还记得使用jdbc如何操作数据库&#xff1f; 加载驱动、获取连接、拼接sql、执行sql、获取结果、解析结果、关闭数据库&#xff0c;这些操作是纯jdbc的方式必经的一些过程&#xff0c;每次操作数据库都需要写这…

三面:请设计一个虚拟DOM算法吧

一、问题剖析 这不是前几天面试官开局面试官就让我设计一个路由&#xff0c;二面过了&#xff0c;结果今天来个三面。 问你道简单的送分题&#xff1a;设计一个虚拟DOM算法&#xff1f; 好家伙&#xff0c;来吧&#xff0c;先进行问题剖析&#xff0c;谁让我们是卑微的打工人…

学习python基础知识

1、Python 基础语法 计算机组成&#xff1a;硬件、软件、计算机运行程序方式、Python 语言的特点、应用领域、Python IDE、程序注释&#xff1a;单行注释、多行注释&#xff1b;变量的作用、定义、 命名规则、变量的数据类型、查看变量类型、输入和输入函数、算术运算符、赋值…

gazebo中添加动态障碍物

文章目录gazebo 教程gazebo 添加动态障碍物gazebo添加动态障碍物插件gazebo中动态障碍物实时posegazebo 教程 gazebo github https://github.com/gazebosim/gazebo-classic/tree/gazebo9gazebo tutorials https://classic.gazebosim.org/tutorials运行一个空白环境 <sdf v…

深入了解Java中的SQL注入

深入了解Java中的SQL注入 本文以代码实例复现了Java中JDBC及Mybatis框架采用预编译和非预编译时可能存在SQL注入的几种情况&#xff0c;并给予修复建议。 JDBC 首先看第一段代码&#xff0c;使用了远古时期的JDBC并且并没有使用预编译。这种简单的字符串拼接就存在SQL注入 …

一云七芯!ZStack 祝贺上海市金融信创联合攻关基地荣获一等奖

2022年11月初&#xff0c;由上海市总工会、中共上海市经济和信息化工作委员会、上海市经济信息化委员会主办的2022上海城市数字化转型 “智慧工匠”选树、“领军先锋”评选活动信创应用竞赛决赛暨颁奖典礼中&#xff0c;“一云七芯适配验证云平台及服务解决方案”获得信创应用案…

GitHub2022年度前100的Java面试真题高频知识点汇总

前言 这是我在工作、面试中学习并总结到的一些知识点&#xff0c;都是一些比较典型的、面试常常被问到的问题。 如果你平时没有注意去总结的话&#xff0c;那么当你面试被问到的时候可能会是一脸懵圈&#xff0c;就算这个问题你知道怎么回事&#xff0c;但是你平时没有认真总…

【win11内存占用高优化】未运行程序,系统内存占用50以上

这里写自定义目录标题前言打开控制面板找到电源键功能找到快速启动选项&#xff0c;取消勾选&#xff0c;确定win X以管理员身份打开powershell输入如下命令&#xff0c;回车关闭终端完成前言 windows11在未运行任何其他程序的情况下&#xff0c;内存占用超50%&#xff0c;可…

速度收藏,Fiddler详细使用教程出炉!

目录 01、抓取不同类型接口数据 02、数据模拟以及过滤规则 03、如何模拟接口响应数据 04、使用fiddler进行评论接口测试 绵薄之力【软件测试学习资源分享】 01、抓取不同类型接口数据 查看windows本机的IP 配置fiddler 需要保证要抓取的手机与电脑保持同一网段&#xff0…

转换 FLAC、APE 无损音乐格式为 iTunes 支持导入的 M4A 格式

大家知道常见的无损音乐格式有 FLAC、APE、WAV 等这些格式。其中 FLAC (Free Lossless Audio Codec) 格式因为是免费自由的压缩编码、无损压缩&#xff0c;且受到操作系统、软件及硬件的广泛支持。所以是非常流行常见的无损音乐格式。 自 2005 年 Mac OS X v10.4 开始&#xf…