Mirror从入门到入神

2024-05-15 05:52
文章标签 入门 mirror 入神

本文主要是介绍Mirror从入门到入神,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Mirror从入门到成神

文章目录

  • Mirror从入门到成神
    • 简介
    • NetworkClient
      • RegisterPrefab
      • Connect (string address)
      • Disconnect ()
      • active
      • activeHost
    • NetworkServer
      • Spawn

简介

Mirror是一个unity网络同步框架,基于MonoBehaviour生命周期的回调的基础上进行数值的同步,将通讯方式和协议剥离,顶层业务只需关注写入读取流,具体传输协议由底层不同协议实现模块完成,使用Mirror编写网络联网游戏,需要掌握分布式编程,要习惯异步的思维,一个方法执行之后无法立刻拿到结果,可以利用协程来检查或者依托特定对象生命周期,也可以使用服务器回调的形式来做,先来看看unity原本的生命周期,关键是easy to use,国外倒是挺火的,国内没啥声响,我们团队在鉴于自己的实际情况,看重的就是一套代码管理,无需额外专职后端开发(项目小)

Unity的MonoBehavior生命周期事件包括Awake、Start、FixedUpdate、Update、LateUpdate、OnEnable、OnDisable和OnDestroy。
Mirror的NetworkManager,NetworkBehavior 图片来源于官网
在这里插入图片描述

在这里插入图片描述

在Mirror中相对本身的生命周期会多几个,可以在Mirror的官网查看详情NetworkBehaviour Callbacks

为了方便理解这里我们首先抽离一个概念,客户端(Client)和服务器(Server),在mirror中他们都是同一个项目的编译产物,在源头上是共生的,内部通过一些特定的标志来判定对应的逻辑代码是否应该执行,比如扣减用户血量,这种安全性要求较高的逻辑内容理应放置到服务器中执行,也有叫前端,后端的,我们选择mirror的原因是因为可以同项目管理,不需要额外的项目和开发人员来支撑服务端,大部分的游戏逻辑都可以公用,比如游戏功能道具啊,Server发布的时候非特殊要求的情况下使用Dedicated Server的方式进行发布,如果形象的形容是Headless无头,如果接触过爬虫的就会知道 无头浏览器的概念。及没有渲染能力的游戏客户端。

启动游戏服务端的时候有几个模式,分别是Host,Server Only,Client Only。主机模式,仅启动服务端,仅启动客户端,说白了我们把游戏逻辑写道一起,如果要完成的进行游戏,就必须同时具备Server,Client 都在线的情况。Host 启动后运行服务器代码,也运行客户端代码。Server Only仅运行服务端代码,Client仅运行客户端代码,下图为Host模式的结构性说明

在这里插入图片描述

RemoteClient表示通过网络通讯协议接入的其他客户端,Local Client在Mirror中做了特殊处理,并不会走网络协议,而是直接将数据写入一个本地队列,另外还有一些执行差异,后面会提到。这里总结下能运行完整游戏的方式

  1. 以HOST模式启动
  2. 连接其他HOST模型启动的程序
  3. 连接其他Server模式启动的程序

下图展示的是数据流的流动方向,对应Spawn出来的单位,服务器和所有客户端都会存在一个实例,由Mirror控制并将对应的数据分发给这些实例对象,其中通过NetworkIdentity的NetId来区分作为全网的唯一标识(全网指的是本局游戏类,连进Server的Client组成的网络)

在这里插入图片描述

下图展示的是Mirror 的层级构成,这个图上包含的类就是Mirror的核心类,这个图最好能背下来,有利于后续的Mirror学习, 对于只是利用Mirror完成联网游戏的改造和编写只需要知道NetworkClient向下的内容,现在来介绍下这些核心组件
在这里插入图片描述

NetworkClient

负责客户端上的和服务端的网络通讯,通常对于开发人员是不需要关注的,除非有定制化的需求

完整的api文档 这里介绍下几个可能会用到的

RegisterPrefab

该函数用于注册预制体,所有需要利用Mirror进行动态生成单位,都需要完成预制体的注册,有两种方式一种是在NetworkManager中RegisteredSpawnablePrefabs列表中添加对应的预制体,要添加成功需要该预制体存在NetworkIdentify组件,否则无法添加,也可以点击Inspector界面的PopulateSpawnablePrefabs,该功能可以自动扫描当前项目中所有添加了NetworkIdentify的预制体,能够自动将预制体添加到列表中,这里很容易犯一个小错误,如果预制体的名字一致,但是错误提示没有注册,可以检查是否是名字一样实则不同的预制体,方式二就是点在运行期间通过

RegisterPrefab (GameObject prefab, Guid newAssetId, SpawnHandlerDelegate spawnHandler, UnSpawnDelegate unspawnHandler)

该方法进行注册,需要注意的是注册的预制体需要在各个端都存在,否则注册之后会出问题。后面的SpawnHander UnSpawnDelegate 可以拦截系统的Spawn 和UnSpawn事件,找一个很容易理解的例子 Instantiate (实例化)Desotry (销毁)。客户端在收到UnSpawn默认的行为是Desotry掉,如果想要池化联网对象,就需要依靠上面的SpawnHander方法,另外该方法一个AssetId只能调用一次,不可以重复调用,如果需要替换请使用其他方法,该方法还有其他的重载,想要细致了解的化可以查看官方文档

Connect (string address)

链接远程服务器,address地址通过是一个ip,具体的端口信息在Transport.active中持有,通过这种方式可以修改端口,也就说明了Transport.active是单例的

    if (Transport.active is PortTransport portTransport){// use TryParse in case someone tries to enter non-numeric charactersportTransport.Port = ushort.Parse(port);}

根据源码具体看看这部分是怎么做的

     public static void Connect(string address){Initialize(false);AddTransportHandlers();//connectState = ConnectState.Connecting;Transport.active.ClientConnect(address);connection = new NetworkConnectionToServer();}

Transport是一个接口interface,不同的传续协议都会实现,这里我们抽一个KcpTransport看一下

在这里插入图片描述

//KcpTransport.cs#ClientConnectpublic override void ClientConnect(string address)
{client.Connect(address, Port);
}
//KcpConnect.cs#ClientConnectpublic void Connect(string address, ushort port){if (connected){Log.Warning("[KCP] Client: already connected!");return;}// resolve host name before creating peer.// fixes: https://github.com/MirrorNetworking/Mirror/issues/3361if (!Common.ResolveHostname(address, out IPAddress[] addresses)){// pass error to user callback. no need to log it manually.OnError(ErrorCode.DnsResolve, $"Failed to resolve host: {address}");OnDisconnectedCallback();return;}// create fresh peer for each new session// client doesn't need secure cookie.Reset(config);Log.Info($"[KCP] Client: connect to {address}:{port}");// create socketremoteEndPoint = new IPEndPoint(addresses[0], port);socket = new Socket(remoteEndPoint.AddressFamily, SocketType.Dgram, ProtocolType.Udp);active = true;// recv & send are called from main thread.// need to ensure this never blocks.// even a 1ms block per connection would stop us from scaling.socket.Blocking = false;// configure buffer sizesCommon.ConfigureSocketBuffers(socket, config.RecvBufferSize, config.SendBufferSize);// bind to endpoint so we can use send/recv instead of sendto/recvfrom.socket.Connect(remoteEndPoint);// immediately send a hello message to the server.// server will call OnMessage and add the new connection.// note that this still has cookie=0 until we receive the server's hello.SendHello();}

当然也可以调用Connect的其他重载

// 	Connect client to a NetworkServer by address. More...
static void 	Connect (string address)
//Connect client to a NetworkServer by Uri. More...
static void 	Connect (Uri uri)
//字如其名
static void 	ConnectHost ()

Disconnect ()

断开连接

active

在不想将MonoBehavior 改成NetworkBehavior时非常有用,使用NetworkBehavior可以在对象内使用isServer,IsClient来判断是否是服务器,还是客户端,但是这会增加带宽的负担,及时一个变量都不需要同步,所以该静态变量在全局判断时非常有用

activeHost

联网游戏存在单机模式,我们用Mirror变成完成之后使用Host模式即可将游戏变为单机模式,这里有一个技巧即可以使用 NetworkServer.dontListen = true;来不启动端口监听。因为Host模式调用远程ClientRpc时,时不会执行的,还有Spawn事件也不会执行,所以需要依靠这些判断该字段来附加执行属于Host的业务逻辑

NetworkServer

接下来看看NetworkServer,听名字就知道这个东西适合服务器相关的,这个普通开发人员也不需要关注,但是任然需要对他有所了解,如果是在不想管,那就记一个方法就行Spawn

Spawn

// 	Spawn the given game object on all clients which are ready. More...
static void 	Spawn (GameObject obj, NetworkConnection ownerConnection=null)
// 	Spawns an object and also assigns Client Authority to the specified client. More... 
static void 	Spawn (GameObject obj, GameObject ownerPlayer)
// 	Spawns an object and also assigns Client Authority to the specified client. More... 
static void 	Spawn (GameObject obj, Guid assetId, NetworkConnection ownerConnection=null)

一般使用他的流程是,在服务端上执行,首先实例化某个Prefab,Instantiate创建好GameObject obj = Instantiate(Prefab),在设置好属性位置啥的(除了transform以外其他都需要是同步属性,否则需要在客户端自行设置)然后调用NetworkServer.Spawn(obj)这样就可以把obj同步给所有端了。第二个 第三个参数是为了标识当前这个obj是属于那个客户端的,该逻辑会在Client2Server的传输模式非常有用,客户端会自行判断如果自己是owner就会同步数据给服务器,否则会直接跳过数据传输部分,服务器也会校验该对象是否允许客户端进行修改。服务器具有权威性,从游戏的数据安全角度考虑,Mirror设计了自己的鉴权逻辑,后面会说到。

Client2Server是数据传输的方向,该方向仅仅对 OwnerClient与Server之间有影响,其他关系都是客户端接收服务器的同步

ClientRpc 是一种注解,可以明确告知Mirror这是一个存在与客户端上的远程方法,Mirror会自动根据方法名调用所有客户端 对应对象的obj执行

未完待续…

这篇关于Mirror从入门到入神的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/990988

相关文章

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

数论入门整理(updating)

一、gcd lcm 基础中的基础,一般用来处理计算第一步什么的,分数化简之类。 LL gcd(LL a, LL b) { return b ? gcd(b, a % b) : a; } <pre name="code" class="cpp">LL lcm(LL a, LL b){LL c = gcd(a, b);return a / c * b;} 例题:

Java 创建图形用户界面(GUI)入门指南(Swing库 JFrame 类)概述

概述 基本概念 Java Swing 的架构 Java Swing 是一个为 Java 设计的 GUI 工具包,是 JAVA 基础类的一部分,基于 Java AWT 构建,提供了一系列轻量级、可定制的图形用户界面(GUI)组件。 与 AWT 相比,Swing 提供了许多比 AWT 更好的屏幕显示元素,更加灵活和可定制,具有更好的跨平台性能。 组件和容器 Java Swing 提供了许多

【IPV6从入门到起飞】5-1 IPV6+Home Assistant(搭建基本环境)

【IPV6从入门到起飞】5-1 IPV6+Home Assistant #搭建基本环境 1 背景2 docker下载 hass3 创建容器4 浏览器访问 hass5 手机APP远程访问hass6 更多玩法 1 背景 既然电脑可以IPV6入站,手机流量可以访问IPV6网络的服务,为什么不在电脑搭建Home Assistant(hass),来控制你的设备呢?@智能家居 @万物互联

poj 2104 and hdu 2665 划分树模板入门题

题意: 给一个数组n(1e5)个数,给一个范围(fr, to, k),求这个范围中第k大的数。 解析: 划分树入门。 bing神的模板。 坑爹的地方是把-l 看成了-1........ 一直re。 代码: poj 2104: #include <iostream>#include <cstdio>#include <cstdlib>#include <al

MySQL-CRUD入门1

文章目录 认识配置文件client节点mysql节点mysqld节点 数据的添加(Create)添加一行数据添加多行数据两种添加数据的效率对比 数据的查询(Retrieve)全列查询指定列查询查询中带有表达式关于字面量关于as重命名 临时表引入distinct去重order by 排序关于NULL 认识配置文件 在我们的MySQL服务安装好了之后, 会有一个配置文件, 也就

音视频入门基础:WAV专题(10)——FFmpeg源码中计算WAV音频文件每个packet的pts、dts的实现

一、引言 从文章《音视频入门基础:WAV专题(6)——通过FFprobe显示WAV音频文件每个数据包的信息》中我们可以知道,通过FFprobe命令可以打印WAV音频文件每个packet(也称为数据包或多媒体包)的信息,这些信息包含该packet的pts、dts: 打印出来的“pts”实际是AVPacket结构体中的成员变量pts,是以AVStream->time_base为单位的显

C语言指针入门 《C语言非常道》

C语言指针入门 《C语言非常道》 作为一个程序员,我接触 C 语言有十年了。有的朋友让我推荐 C 语言的参考书,我不敢乱推荐,尤其是国内作者写的书,往往七拼八凑,漏洞百出。 但是,李忠老师的《C语言非常道》值得一读。对了,李老师有个官网,网址是: 李忠老师官网 最棒的是,有配套的教学视频,可以试看。 试看点这里 接下来言归正传,讲解指针。以下内容很多都参考了李忠老师的《C语言非

MySQL入门到精通

一、创建数据库 CREATE DATABASE 数据库名称; 如果数据库存在,则会提示报错。 二、选择数据库 USE 数据库名称; 三、创建数据表 CREATE TABLE 数据表名称; 四、MySQL数据类型 MySQL支持多种类型,大致可以分为三类:数值、日期/时间和字符串类型 4.1 数值类型 数值类型 类型大小用途INT4Bytes整数值FLOAT4By

【QT】基础入门学习

文章目录 浅析Qt应用程序的主函数使用qDebug()函数常用快捷键Qt 编码风格信号槽连接模型实现方案 信号和槽的工作机制Qt对象树机制 浅析Qt应用程序的主函数 #include "mywindow.h"#include <QApplication>// 程序的入口int main(int argc, char *argv[]){// argc是命令行参数个数,argv是