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

相关文章

从入门到精通MySQL联合查询

《从入门到精通MySQL联合查询》:本文主要介绍从入门到精通MySQL联合查询,本文通过实例代码给大家介绍的非常详细,需要的朋友可以参考下... 目录摘要1. 多表联合查询时mysql内部原理2. 内连接3. 外连接4. 自连接5. 子查询6. 合并查询7. 插入查询结果摘要前面我们学习了数据库设计时要满

从入门到精通C++11 <chrono> 库特性

《从入门到精通C++11<chrono>库特性》chrono库是C++11中一个非常强大和实用的库,它为时间处理提供了丰富的功能和类型安全的接口,通过本文的介绍,我们了解了chrono库的基本概念... 目录一、引言1.1 为什么需要<chrono>库1.2<chrono>库的基本概念二、时间段(Durat

解析C++11 static_assert及与Boost库的关联从入门到精通

《解析C++11static_assert及与Boost库的关联从入门到精通》static_assert是C++中强大的编译时验证工具,它能够在编译阶段拦截不符合预期的类型或值,增强代码的健壮性,通... 目录一、背景知识:传统断言方法的局限性1.1 assert宏1.2 #error指令1.3 第三方解决

从入门到精通MySQL 数据库索引(实战案例)

《从入门到精通MySQL数据库索引(实战案例)》索引是数据库的目录,提升查询速度,主要类型包括BTree、Hash、全文、空间索引,需根据场景选择,建议用于高频查询、关联字段、排序等,避免重复率高或... 目录一、索引是什么?能干嘛?核心作用:二、索引的 4 种主要类型(附通俗例子)1. BTree 索引(

Redis 配置文件使用建议redis.conf 从入门到实战

《Redis配置文件使用建议redis.conf从入门到实战》Redis配置方式包括配置文件、命令行参数、运行时CONFIG命令,支持动态修改参数及持久化,常用项涉及端口、绑定、内存策略等,版本8... 目录一、Redis.conf 是什么?二、命令行方式传参(适用于测试)三、运行时动态修改配置(不重启服务

MySQL DQL从入门到精通

《MySQLDQL从入门到精通》通过DQL,我们可以从数据库中检索出所需的数据,进行各种复杂的数据分析和处理,本文将深入探讨MySQLDQL的各个方面,帮助你全面掌握这一重要技能,感兴趣的朋友跟随小... 目录一、DQL 基础:SELECT 语句入门二、数据过滤:WHERE 子句的使用三、结果排序:ORDE

Maven 配置中的 <mirror>绕过 HTTP 阻断机制的方法

《Maven配置中的<mirror>绕过HTTP阻断机制的方法》:本文主要介绍Maven配置中的<mirror>绕过HTTP阻断机制的方法,本文给大家分享问题原因及解决方案,感兴趣的朋友一... 目录一、问题场景:升级 Maven 后构建失败二、解决方案:通过 <mirror> 配置覆盖默认行为1. 配置示

Python中OpenCV与Matplotlib的图像操作入门指南

《Python中OpenCV与Matplotlib的图像操作入门指南》:本文主要介绍Python中OpenCV与Matplotlib的图像操作指南,本文通过实例代码给大家介绍的非常详细,对大家的学... 目录一、环境准备二、图像的基本操作1. 图像读取、显示与保存 使用OpenCV操作2. 像素级操作3.

POI从入门到实战轻松完成EasyExcel使用及Excel导入导出功能

《POI从入门到实战轻松完成EasyExcel使用及Excel导入导出功能》ApachePOI是一个流行的Java库,用于处理MicrosoftOffice格式文件,提供丰富API来创建、读取和修改O... 目录前言:Apache POIEasyPoiEasyExcel一、EasyExcel1.1、核心特性

Python中模块graphviz使用入门

《Python中模块graphviz使用入门》graphviz是一个用于创建和操作图形的Python库,本文主要介绍了Python中模块graphviz使用入门,具有一定的参考价值,感兴趣的可以了解一... 目录1.安装2. 基本用法2.1 输出图像格式2.2 图像style设置2.3 属性2.4 子图和聚