Unity Networking(UNet)函数时序统计和分析

发表于2017-03-06
评论2 3.7k浏览

很多开发人员对UNet知识其实了解的并不是很多,为了让大家可以更加严谨地编写UNet相关的业务逻辑代码,下面就给大家介绍下Unity Networking函数时序统计和分析,希望对大家有帮助。

 

背景和概述

Unity Networking是官方自Unity5.1以来推出的新网络通信解决方案。UNet是非官方但更民间更精简的叫法。

本文需要读者有基础的UNet知识。

了解UNet时序,可以更好更严谨地编写UNet相关的业务逻辑代码。
本文针对UNetHLAPI进行时序统计和分析。
本文可作为工具文档,需要时可进行时序查阅。

在有时序统计的基础上,本文再参考Unity Networking 5.3源代码Bitbucket网站可能需要翻墙)进行整合分析,可以帮助了解底层发生的具体逻辑。

当前将Unity(就算是Headless)运行在Linux服务器上,会出现一定的性能问题。联系咨询过Unity内部开发同学Ian和一位和蔼大胖子,获知Headless所剔除的功能模块并不多,仅仅是最终不提交(也不能提交)到GPUDSP而已。原话是“Modulizationis hard”“Shouldnot run Unity on the server”
所以当前,应避免粗暴地将Unity运行在关键服务器上。

·        应从业务层着手剔除Headless模式下所启用的业务功能(如模型、渲染、物理、音效等)

·        Unity运行于非关键服务器(比如用于外挂分析,等)是可能可行的

·        Unity无状态地运行,多关键服务器(比如用于战斗)共享该Unity服务器,是有成功案例的

·        但粗暴地每一局游戏都在服务器运行一个Unity进程是欠妥的

可惜的是,UNet的默认思路正是最后一种。由于Ian并非UNetTeam的开发同学,所以其并不十分了解将于Unity5.4(但被delay了)的ServerLibrary所完成的功能。但一种推测是,ServerLibrary正是为了避免将Unity运行于服务器,而是提供UNetUnity的基础功能(Math等),让我们服务器同学利用UNet接口,重新实现逻辑。

测试方法

测试Unity版本为5.3.1。运行平台是OSX
测试NetworkManager通过NBNetworkManager继承并override掉关键函数;测试PlayerPrefab名字为NBPlayer。通过在这个Prefab加上测试脚本TestNetworkBehaviour进行日志输出。
通过分析日志,可以统计UNet函数的时序。


函数时序概括

以下为关键函数的罗列,以供快速查询之用。
如需可细看下一章节的详细文档及分析。

DedicatedServer情况

NetworkManager

NetworkBehaviour

Server初始化阶段

Server初始化阶段

Awake()

Start()

OnStartServer()

ServerChangeScene()

OnServerSceneChanged()

Client初始化阶段

Client初始化阶段

OnServerConnect()

OnServerReady()

Player初始化阶段

Player初始化阶段

OnServerAddPlayer()

Awake()

OnEnable()

OnStartServer()

OnRebuildObservers()

OnSerialize()(多次)

Start()

Player运转阶段

Player运转阶段

FixedUpdate()(多次)

Update()(多次)

OnSerialize()(多次)

Player销毁阶段

Player销毁阶段

OnDisable()

OnDestroy()

OnServerDisconnect

Server销毁阶段

Server销毁阶段

OnStopServer()

Remote Client情况

NetworkManager

NetworkBehaviour

Client初始化阶段

Client初始化阶段

Awake()

Start()

OnStartClient()

OnClientConnect()

OnClientSceneChanged()

Player初始化阶段

Player初始化阶段

Awake()

OnEnable()

OnDeserialize()

PreStartClient()

OnStartClient()

OnStartLocalPlayer()

OnStartAuthority()
(后面运转阶段也可能调到)

OnDeserialize()(多次)

Start()

Player运转阶段

Player运转阶段

FixedUpdate()(多次)

Update()(多次)

OnDeserialize()(多次)

Player销毁阶段

Player销毁阶段

OnNetworkDestroy()

OnDisable()

OnNetworkDestroy()

Client销毁阶段

Client销毁阶段

OnStopClient()

Host情况

NetworkManager

NetworkBehaviour

Host初始化阶段

Host初始化阶段

Awake()

Start()

OnStartHost()

OnStartServer()

ServerChangeScene()

OnServerConnect()
LocalClient混杂进来的Server函数)

OnStartClient()
LocalClient混杂进来的Client函数)

OnClientConnect()
LocalClient混杂进来的Client函数)

OnServerSceneChanged()

OnClientSceneChanged()
LocalClient混杂进来的Client函数)

OnServerReady()
LocalClient混杂进来的Server函数)

OnServerAddPlayer()
LocalClient混杂进来的Server函数)

OnServerConnect()

OnServerReady()

Player初始化阶段

Player初始化阶段

OnServerAddPlayer()

Awake()

OnEnable()

OnStartServer()

PreStartClient()

OnStartClient()

OnRebuildObservers()

OnSerialize()(多次)

OnSetLocalVisibility()

Start()

Player运转阶段

Player运转阶段

FixedUpdate()(多次)

Update()(多次)

OnSerialize()(多次)

Player销毁阶段

Player销毁阶段

OnNetworkDestroy()

OnDisable()

OnDestroy()

OnServerDisconnect

Host销毁阶段

Host销毁阶段

OnStopHost()

OnStopServer()

ServerChangeScene()
LocalClient混杂进来的Server函数)

OnStopClient()
LocalClient混杂进来的Client函数)


函数时序的详细文档及分析

以下为严格按照时间次序进行罗列的UNet函数时序,附上官方文档。重要地方也结合源码进行解释。

DedicatedServer情况

DedicatedServerServer初始化阶段

NetworkManager.Awake()
NetworkManager
目前的Awake()(被不好地设计)为非virtual的私有方法。所以子类应注意不能再定义Awake(),否则将hide掉基类的Awake()

NetworkManager.Start()

NetworkManager (NewBorn.NBNetworkManager).Start()

NetworkManager.OnStartServer()

public void OnStartServer();
Description
This hook is invoked when a server is started - including when a host isstarted.
StartServer has multiple signatures, but they all cause this hook to be called.

Server初始化函数。调用肯定比看似相似的OnStartClient()早。
注意在OnStartServer()之后,才进行网络Connect的初始化、才进行场景的切换。

NetworkManager (NewBorn.NBNetworkManager).OnStartServer()

NetworkManager.ServerChangeScene()

public void ServerChangeScene(stringnewSceneName);
Parameters
newSceneName Thename of the scene to change to. The server will change scene immediately, and amessage will be sent to connected clients to ask them to change scene also.
Description
This causes the server to switch scenes and sets the networkSceneName.
Clients that connect to this server will automatically switch to this scene.This is called autmatically if onlineScene or offlineScene are set, but it canbe called from user code to switch scenes again while the game is in progress.This automatically sets clients to be not-ready. The clients must call NetworkClient.Ready()again to participate in the new scene.

StartServer()里、OnStartServer()之后,调用ServerChangeScene()进行场景切换。之后在任意时刻,也可以手动调用它进行中途的场景切换。
ServerChangeScene()里,会发出MsgType.Scene通知当前已连接上的Client也进行场景的切换。

Battle_Demo_Official

NetworkManager (NewBorn.NBNetworkManager).ServerChangeScene()

NetworkManager.OnServerSceneChanged()

public void OnServerSceneChanged(stringsceneName);
Parameters
sceneName Thename of the new scene.
Description
Called on the server when a scene is completed loaded, when the scene load wasinitiated by the server with ServerChangeScene().

Server完成场景切换后的一个回调。
在本回调之前,Server会收集场景所有已有NetworkIdentityGameObject,并发出SpawnMessage,从而通知已连接上的Client进行Spawn

Battle_Demo_Official

NetworkManager (NewBorn.NBNetworkManager).OnServerSceneChanged()

2016-01-01T10:57:28.8472060+08:00

至此,Server的初始化阶段结束。之后(通过上面的时间10:57:28和下面的时间11:04:10就可以看出时间差),当有Client连接进Server的时候,函数流程就进入该Client的初始化阶段。

DedicatedServerClient初始化阶段

NetworkManager.OnServerConnect()

public voidOnServerConnect(Networking.NetworkConnection conn);
Parameters
conn Connectionfrom client.
Description
Called on the server when a new client connects.

新玩家新ClientServer建立连接后的回调函数。
Client
刚连接上来,第一个问题肯定是我现在在什么场景?。所以在本回调之前,Server会发出MsgType.Scene,通知客户端进行场景加载。

hostId: 0 connectionId: 1 isReady: False channel count: 2

NetworkManager (NewBorn.NBNetworkManager).OnServerConnect()

2016-01-01T11:04:10.7621350+08:00

NetworkManager.OnServerReady()

public voidOnServerReady(Networking.NetworkConnection conn);
Parameters
conn Connectionfrom client.
Description
Called on the server when a client is ready.
The default implementation of this function callsNetworkServer.SetClientReady() to continue the network setup process

Client“准备好(加载好场景,一些自定义的初始化)后,需要发送MsgType.ReadyServer
Server
收到这个Message了之后,就会调用本OnServerReady()函数。
Client
准备好了之后,接着问题是Client当前场景有什么网络对象可见和需要同步?
所以在OnServerReady()里会调用NetworkServer.SetClientReady(),进行该Client的可见性检测、并进行同步Spawn

hostId: 0 connectionId: 1 isReady: False channel count: 2

NetworkManager (NewBorn.NBNetworkManager).OnServerReady()

至此,Client已经连接好、加载好场景、同步好已有的网络对象。
所以Server将进入Player初始化阶段。

DedicatedServerPlayer初始化阶段

NetworkManager.OnServerAddPlayer()

public voidOnServerAddPlayer(Networking.NetworkConnection conn, short playerControllerId);
Parameters
conn Connectionfrom client.
playerControllerId Idof the new player.
extraMessageReader Anextra message object passed for the new player.
Description
Called on the server when a client adds a new player withClientScene.AddPlayer.
The default implementation for this function creates a new player object fromthe playerPrefab.

新连接上来的Client连接好了、场景准备好了、其他有NetworkIdentityGameObject同步好了,接下来准备为该Client准备属于它自己的Player了。
通过调用ClientScene.AddPlayer()发出MsgType.AddPlayer可以通知服务器添加属于该connectionPlayer,然后Server就响应该Message会调用OnServerAddPlayer()
用户可以在OnServerAddPlayer()自定义新建Player的逻辑,包括直接InstantiatePlayer、或者从自己的Spawn机制里取出Player、给Player修改初始化属性等。
然后,在OnServerAddPlayer()里就会调用NetworkServer.AddPlayerForConnection(),继而一系列初始化Player逻辑(生成netId、决定Observer、收集SyncVar、发送MsgType.SpawnClient),通知Client真正去创建Player

hostId: 0 connectionId: 1 isReady: True channel count: 2, 0

NetworkManager (NewBorn.NBNetworkManager).OnServerAddPlayer()

至此,PlayerPrefabServer已被Instantiate出来,继而调用

·        NetworkServer.AddPlayerForConnection()

·        NetworkServer.FinishPlayerForConnection()

·        NetworkServer.SpawnObject()

等函数,正式开始NetworkIdentity/NetworkBehaviour的函数流程。
NetworkBehaviour
NetworkIdentity是相互依存的。许多NetworkBehaviourUNet相关函数事实上都是在其配对的NetworkIdentity中被NetworkIdentity所触发调用的。

NetworkBehaviour.Awake()
留意到这次测试PlayerGameObjectinstanceID-10746

只有localPlayerAuthority=True
这个UNet配置变量是合法的。其他UNet变量都是非法的。

go.instanceID=-10746,go=NBPlayer(Clone)(UnityEngine.GameObject)

netId=0

playerControllerId=-1

connectionToClient=

connectionToServer=

isClient=False

isServer=False

localPlayerAuthority=True

hasAuthority=False

isLocalPlayer=False

NBPlayer(Clone)(MoreFun.TestNetworkBehaviour).Awake()

NetworkBehaviour.OnEnable()

go.instanceID=-10746,go=NBPlayer(Clone)(UnityEngine.GameObject)

netId=0

playerControllerId=-1

connectionToClient=

connectionToServer=

isClient=False

isServer=False

localPlayerAuthority=True

hasAuthority=False

isLocalPlayer=False

NBPlayer(Clone)(MoreFun.TestNetworkBehaviour).OnEnable()

NetworkBehaviour.OnStartServer()

public void OnStartServer();
Description
This hook is invoked when a server is started - including when a host isstarted.
StartServer has multiple signatures, but they all cause this hook to be called.

NetworkIdentity.OnStartServer()里,

·        cacheNetworkIdentity所同GameObject的所有NetworkBehaviour

·        会生成netId给自己

·        通过NetworkServer.instance.SetLocalObjectOnServer(),更新isServer的标志位

·        调用这些NetworkBehaviourOnStartServer()函数。

所以这个时候,netIdisServer合法了。

go.instanceID=-10746,go=NBPlayer(Clone) (UnityEngine.GameObject)

netId=7

playerControllerId=0

connectionToClient=hostId: 0 connectionId: 2 isReady: True channel count: 2

connectionToServer=

isClient=False

isServer=True

localPlayerAuthority=True

hasAuthority=False

isLocalPlayer=False

NBPlayer(Clone)(MoreFun.TestNetworkBehaviour).OnStartServer()

NetworkBehaviour.OnRebuildObservers()

public boolOnRebuildObservers(HashSet observers, boolinitialize);
Parameters
observers Thenew set of observers for this object.
initialize Trueif the set of observers is being built for the first time.
Returns
bool Returntrue if this function did work.
Description
Callback used by the visibility system to (re)construct the set of observersthat can see this object.
Implementations of this callback should add network connections of players thatcan see this object to the observers set.

这个新的NetworkIdentityServer创建了,但哪些Client是其真正的观察者Observer)呢?只有这些观察者Client,才需要在他们的运行时里创建这个新NetworkIdentity及其GameObject

NetworkIdentity会调用其所有NetworkBehaviourOnRebuildObservers()
默认情况下,是当前已连接的所有Client都能观察到这个新NetworkIdentity
但如果有NetworkBehaviourOnRebuildObservers()返回了true,则以HashSetobservers里存在的连接作为Observer

observers=System.Collections.Generic.HashSet`1[UnityEngine.Networking.NetworkConnection], initialize=True,

go.instanceID=-10746,go=NBPlayer(Clone)(UnityEngine.GameObject)

netId=7

playerControllerId=0

connectionToClient=hostId: 0 connectionId: 2 isReady: True channel count: 2

connectionToServer=

isClient=False

isServer=True

localPlayerAuthority=True

hasAuthority=False

isLocalPlayer=False

NBPlayer(Clone)(MoreFun.TestNetworkBehaviour).OnRebuildObservers()

NetworkBehaviour.OnSerialize()

public boolOnSerialize(Networking.NetworkWriter writer, bool initialState);
Parameters
writer Writerto use to write to the stream.
initialState Ifthis is being called to send initial state.
Returns
bool Trueif data was written.
Description
Virtual function to override to send custom serialization data.

决定了Observer、给这些Observer发送MsgType.Spawn之前,需要在Server把这个新NetworkIdentityGameObject所有同步属性进行序列化

OnSerialize()OnDeserialize()
是用于自定义NetworkBehaviour中变量的序列化和反序列化的虚函数。前者必然是只在Server被调用、后者必然是只在Client被调用。
事实上,[SyncVar]修饰的变量和SyncList变量都是通过编译时UNet将这些变量的序列化反序列化逻辑自动生成OnSerialize()OnDeserialize()中的。
所以要注意,如果你在NetworkBehaviour中显式override掉了这两个函数,则该NetworkBehaviour[SyncVar]修饰的变量和SyncList变量都需要你自行编写代码实现序列化反序列化。

serializeCount=1,writer=UnityEngine.Networking.NetworkWriter, initialState=True,

go.instanceID=-10746,go=NBPlayer(Clone)(UnityEngine.GameObject)

netId=7

playerControllerId=0

connectionToClient=hostId: 0 connectionId: 2 isReady: True channel count: 2

connectionToServer=

isClient=False

isServer=True

localPlayerAuthority=True

hasAuthority=False

isLocalPlayer=False

NBPlayer(Clone)(MoreFun.TestNetworkBehaviour).OnSerialize()

NetworkBehaviour.Start()

一帧真正开始。

go.instanceID=-10746,go=NBPlayer(Clone) (UnityEngine.GameObject)

netId=7

playerControllerId=0

connectionToClient=hostId: 0 connectionId: 2 isReady: True channel count: 2

connectionToServer=

isClient=False

isServer=True

localPlayerAuthority=True

hasAuthority=False

isLocalPlayer=False

NBPlayer(Clone) (MoreFun.TestNetworkBehaviour).Start()

至此,在DedicatedServerPlayer初始化阶段已结束。接下来是Player运转阶段。

DedicatedServerPlayer运转阶段

NetworkBehaviour.FixedUpdate()(多次)

fixedUpdateCount=22, go.instanceID=-10746,go=NBPlayer(Clone)(UnityEngine.GameObject)

netId=7

playerControllerId=0

connectionToClient=hostId: 0 connectionId: 2 isReady: True channel count: 2

connectionToServer=

isClient=False

isServer=True

localPlayerAuthority=True

hasAuthority=False

isLocalPlayer=False

NBPlayer(Clone)(MoreFun.TestNetworkBehaviour).FixedUpdate()

NetworkBehaviour.Update()(多次)

updateCount=22, go.instanceID=-10746,go=NBPlayer(Clone)(UnityEngine.GameObject)

netId=7

playerControllerId=0

connectionToClient=hostId: 0 connectionId: 2 isReady: True channel count: 2

connectionToServer=

isClient=False

isServer=True

localPlayerAuthority=True

hasAuthority=False

isLocalPlayer=False

NBPlayer(Clone) (MoreFun.TestNetworkBehaviour).Update()

NetworkBehaviour.OnSerialize()(多次)

serializeCount=16,writer=UnityEngine.Networking.NetworkWriter, initialState=False,

go.instanceID=-10746,go=NBPlayer(Clone)(UnityEngine.GameObject)

netId=7

playerControllerId=0

connectionToClient=hostId: 0 connectionId: 2 isReady: True channel count: 2

connectionToServer=

isClient=False

isServer=True

localPlayerAuthority=True

hasAuthority=False

isLocalPlayer=False

NBPlayer(Clone)(MoreFun.TestNetworkBehaviour).OnSerialize()

DedicatedServerPlayer销毁阶段

通过调用NetworkServer.Destroy(gameObject);gameObject进入销毁阶段。

NetworkBehaviour.OnDisable()

go.instanceID=-10746,go=NBPlayer(Clone) (UnityEngine.GameObject)

netId=7

playerControllerId=0

connectionToClient=hostId: 0 connectionId: 2 isReady: True channel count: 2

connectionToServer=

isClient=False

isServer=True

localPlayerAuthority=True

hasAuthority=False

isLocalPlayer=False

NBPlayer(Clone)(MoreFun.TestNetworkBehaviour).OnDisable()

NetworkBehaviour.OnDestroy()
留意到所有变量皆已非法。
留意到在Server并不会调用OnNetworkDestroy()

go.instanceID=-10746,go=NBPlayer(Clone) (UnityEngine.GameObject)

netId=0

playerControllerId=0

connectionToClient=hostId: 0 connectionId: 2 isReady: True channel count: 2

connectionToServer=

isClient=False

isServer=False

localPlayerAuthority=True

hasAuthority=False

isLocalPlayer=False

NBPlayer(Clone)(MoreFun.TestNetworkBehaviour).OnDestroy()

至此,PlayerNetworkIdentity/NetworkBehaviour流程结束。

NetworkManager.OnServerDisconnect()

public voidOnServerDisconnect(Networking.NetworkConnection conn);
Parameters
conn Connectionfrom client.
Description Called on the server when a client disconnects.

hostId: 0 connectionId: 2 isReady: False channel count: 2

NetworkManager (NewBorn.NBNetworkManager).OnServerDisconnect()

DedicatedServerServer销毁阶段

略。因为在ServerkillUnity不能及时输出日志。

至此,Player的整个DedicatedServer流程结束。


Remote Client情况

在上面已有DedicatedServer情况的前提下,RemoteClient情况将适度从简,仅针对差异性进行描述。

Remote ClientClient初始化阶段

NetworkManager.Awake()
NetworkManager
目前的Awake()(被不好地设计)为非virtual的私有方法。所以子类应注意不能再定义Awake(),否则将hide掉基类的Awake()

NetworkManager.Start()

NetworkManager (NewBorn.NBNetworkManager).Start()

NetworkManager.OnStartClient()

public voidOnStartClient(Networking.NetworkClient client);
Parameters
client TheNetworkClient object that was started.
Description
This is a hook that is invoked when the client is started.
StartClient has multiple signatures, but they all cause this hook to be called.

当调用NetworkManager.StartClient()的时候,在其内部进行连接,然后会调用OnStartClient()

UnityEngine.Networking.NetworkClient

NetworkManager (NewBorn.NBNetworkManager).OnStartClient()

Client连接成功后,第一个问题肯定是我现在在什么场景?。通过之前DedicatedServer情况的分析可知,Server会在Client连接成功后、OnServerConnect()之前通过MsgType.Scene通知客户端切换场景
所以此时之后,Client将进行场景加载并成功。

BattleStarter.Awake()(场景中本就有的GameObject

BattleStarter (NewBorn.BattleStarter).Awake()

GlobalObject.OnLevelWasLoaded()(加载场景前就DontDestroyOnLoadGameObject

GlobalObject (MoreFun.GlobalObjectComponent).OnLevelWasLoaded()

NetworkManager.OnClientConnect()

public void OnClientConnect(Networking.NetworkConnectionconn);
Parameters
conn Connectionto the server.
Description
Called on the client when connected to a server.
The default implementation of this function sets the client as ready and adds aplayer.

当场景加载成功后,才NetworkManager.FinishLoadScene()里调用OnClientConnect()
OnClientConnect()里,当没有OnlineScene或当前就是OnlineScene时,就会立刻调用ClientScene.Ready()告诉ServerClient已准备好。
所以此时的isReadyFalse

hostId: 0 connectionId: 1 isReady: False channel count: 2

NetworkManager (NewBorn.NBNetworkManager).OnClientConnect()

NetworkManager.OnClientSceneChanged()

public voidOnClientSceneChanged(Networking.NetworkConnection conn);
Parameters
conn Thenetwork connection that the scene change message arrived on.
Description
Called on clients when a scene has completed loaded, when the scene load wasinitiated by the server.
Scene changes can cause player objects to be destroyed. The defaultimplementation of OnClientSceneChanged in the NetworkManager is to add a playerobject for the connection if no player object exists.

当场景加载成功后、调用OnClientConnect()后、NetworkManager.FinishLoadScene()里继续调用OnClientSceneChanged()

OnClientSceneChanged()必然会调用ClientScene.Ready()告诉ServerClient已准备好。所以根据之前的DedicatedServer情况分析可知,Server会在OnServerReady()里会调用NetworkServer.SetClientReady(),进行该Client的可见性检测、并进行已在ServerNetworkIdentityGameObject进行反序列化和Spawn
然后,如果NetworkManager配置成AutoCreatePlayertrue,则OnClientSceneChanged()还会在本Client找不到LocalPlayer调用ClientScene.AddPlayer(0)通知Server生成本Client的玩家。

hostId: 0 connectionId: 1 isReady: False channel count: 2

NetworkManager (NewBorn.NBNetworkManager).OnClientSceneChanged()

其他PlayerGameObject的其他脚本的Awake()
因此,其他Player就会比LocalPlayer先行在本ClientSpawn出来。

go.instanceID=-64522

NBPlayer(Clone) (NewBorn.PlayerController).Awake()

BattleStarter.OnStartClient()
本身就在场景里的有NetworkIdentityGameObject也比LocalPlayer先行被Spawn出来。

BattleStarter (NewBorn.BattleStarter).OnStartClient()

至此,RemoteClientClient本身就初始化好了。
接下来,由于ClientScene.OnObjectSpawn()监听了MsgType.ObjectSpawn,所以当Server生成本ClientLocalPlayer(或者Spawn其他任意GameObject时),本Client都会进入NetworkIdentity/NetworkBehaviour的函数流程。

Remote ClientPlayer初始化阶段

NetworkBehaviour.Awake()
只有localPlayerAuthority=True这个UNet配置变量是合法的。其他UNet变量都是非法的。

go.instanceID=-65642,go=NBPlayer(Clone)(UnityEngine.GameObject)

netId=0

playerControllerId=-1

connectionToClient=

connectionToServer=

isClient=False

isServer=False

localPlayerAuthority=True

hasAuthority=False

isLocalPlayer=False

NBPlayer(Clone)(MoreFun.TestNetworkBehaviour).Awake()

NetworkBehaviour.OnEnable()

go.instanceID=-65642,go=NBPlayer(Clone)(UnityEngine.GameObject)

netId=0

playerControllerId=-1

connectionToClient=

connectionToServer=

isClient=False

isServer=False

localPlayerAuthority=True

hasAuthority=False

isLocalPlayer=False

NBPlayer(Clone) (MoreFun.TestNetworkBehaviour).OnEnable()

NetworkBehaviour.OnDeserialize()

public voidOnDeserialize([Networking.NetworkReader reader, bool initialState);
Parameters
reader Readerto read from the stream.
initialState Trueif being sent initial state.
Description
Virtual function to override to receive custom serialization data.

Server把这个新NetworkIdentityGameObject所有同步属性进行序列化会连同发送MsgType.Spawn一并下发。
所以Client接受Server的数据后也通过OnDeserialize()在本地进行反序列化。留意到这是第一次反序列化initialState=True

OnSerialize()OnDeserialize()
是用于自定义NetworkBehaviour中变量的序列化和反序列化的虚函数。前者必然是只在Server被调用、后者必然是只在Client被调用。
事实上,[SyncVar]修饰的变量和SyncList变量都是通过编译时UNet将这些变量的序列化反序列化逻辑自动生成OnSerialize()OnDeserialize()中的。
所以要注意,如果你在NetworkBehaviour中显式override掉了这两个函数,则该NetworkBehaviour[SyncVar]修饰的变量和SyncList变量都需要你自行编写代码实现序列化反序列化。

deserializeCount=1, reader=NetBuf sz:87 pos:87, initialState=True,

go.instanceID=-65642,go=NBPlayer(Clone)(UnityEngine.GameObject)

netId=0

playerControllerId=-1

connectionToClient=

connectionToServer=

isClient=False

isServer=False

localPlayerAuthority=True

hasAuthority=False

isLocalPlayer=False

NBPlayer(Clone)(MoreFun.TestNetworkBehaviour).OnDeserialize()

NetworkBehaviour.PreStartClient()

public void PreStartClient();
Description
An internal method called on client objects to resolve GameObject references.

留意到经过上一步的OnDeserialize()之后,合法变量为

·        netId=7

·        isClient=True

·        isServer=False

·        gameObject.name已经改变为跟server所给予的名字(NBPlayer7)。

·        事实上,所有SyncVar此时皆已合法。

go.instanceID=-65642,go=NBPlayer7(UnityEngine.GameObject)

netId=7

playerControllerId=-1

connectionToClient=

connectionToServer=

isClient=True

isServer=False

localPlayerAuthority=True

hasAuthority=False

isLocalPlayer=False

NBPlayer7 (MoreFun.TestNetworkBehaviour).PreStartClient()

NetworkBehaviour.OnStartClient()

public void OnStartClient();
Description
Called on every NetworkBehaviour when it is activated on a client.
Objects on the host have this function called, as there is a local client onthe host. The values of SyncVars on object are guaranteed to be initializedcorrectly with the latest state from the server when this function is called onthe client.

PreStartClient()没什么区别。当然,SyncVar已经合法。

go.instanceID=-65642,go=NBPlayer7(UnityEngine.GameObject)

netId=7

playerControllerId=-1

connectionToClient=

connectionToServer=

isClient=True

isServer=False

localPlayerAuthority=True

hasAuthority=False

isLocalPlayer=False

NBPlayer7 (MoreFun.TestNetworkBehaviour).OnStartClient()

NetworkBehaviour.OnStartLocalPlayer()

public void OnStartLocalPlayer();
Description
Called when the local player object has been set up.
This happens after OnStartClient(), as it is triggered by an ownership messagefrom the server. This is an appropriate place to activate components orfunctionality that should only be active for the local player, such as camerasand input.

在一个Client运行时中,只有一个Connection,有很多个Player。众多Player中,只有和这个Connection绑定起来的Player,才提拔为”LocalPlayer,代表的是本Client玩家的“MyPlayer”。所以,此时合法的变量就比较好理解了。
合法变量:

·        playerControllerId=0

·        connectionToServer=hostId:0 connectionId: 1 isReady: True channel count: 2

·        isLocalPlayer=True

Server发送MsgType.OwnerClient,然后Client就进行LocalPlayer的更新
注意,从源码看来。LocalPlayer可以有多个。

另,应注意,LocalPlayer“Local”,和Host模式下的LocalClient“Local”可不是同一个概念,应分清区别:

·        LocalClientLocal可理解为同机器的:是Host模式下,和Server同处于一部物理机器上的一种特殊的ClientLocalClient的并列相反概念是RemoteClientRemoteClient是指和Server处于不同物理机器上的常见Client

·        LocalPlayerLocal可理解为我自己的,不管是RemoteClient,还是LocalClient,它们都会有本客户端的自己的LocalPlayerLocalPlayer的并列相反概念是DumbPlayer(作者本人喜欢的叫法),DumbPlayer是指本客户端代表其他玩家的Player

go.instanceID=-65642,go=NBPlayer7 (UnityEngine.GameObject)

netId=7

playerControllerId=0

connectionToClient=

connectionToServer=hostId: 0 connectionId: 1 isReady: True channel count: 2

isClient=True

isServer=False

localPlayerAuthority=True

hasAuthority=True

isLocalPlayer=True

NBPlayer7 (MoreFun.TestNetworkBehaviour).OnStartLocalPlayer()

NetworkBehaviour.OnStartAuthority()

public void OnStartAuthority();
Description
This is invoked on behaviours that have authority, based on context and theLocalPlayerAuthority value on the NetworkIdentity.
This is called after OnStartServer and OnStartClient.WhenNetworkIdentity.AssignClientAuthority() is called on the server, this will becalled on the client that owns the object. When an object is spawned withNetworkServer.SpawnWithClientAuthority(), this will be called on the clientthat owns the object.

当一个NetworkIdentity配置有LocalPlayerAuthority时,此NetworkIdentity认为是可以授权给Client的。只有一个Client真正有Authority的时候,才可以在该GameObjectNetworkBehaviour中发送CommandServer
什么时候Client才真正有Authority呢?LocalPlayer都是有Authority的。另自Unity5.2开始,也允许非Player在运行时通过在Server调用NetworkIdentity.AssignClientAuthority()NetworkServer.SpawnWithClientAuthority()Authority赋予特定的Connection,即指定该ConnectionClient也拥有该非PlayerAuthority,即允许该Client也可以在该非PlayerNetworkBehaviour中发CommandServer。此时OnStartAuthority()这个函数是可以在那个时候再被调用到的。

Authority要么只有Server拥有,要么只有Client拥有。

合法变量:

·        hasAuthority=True

go.instanceID=-65642,go=NBPlayer7 (UnityEngine.GameObject)

netId=7

playerControllerId=0

connectionToClient=

connectionToServer=hostId: 0 connectionId: 1 isReady: True channel count: 2

isClient=True

isServer=False

localPlayerAuthority=True

hasAuthority=True

isLocalPlayer=True

NBPlayer7 (MoreFun.TestNetworkBehaviour).OnStartAuthority()

NetworkBehaviour.Start()
一帧真正开始。

go.instanceID=-65642,go=NBPlayer7 (UnityEngine.GameObject)

netId=7

playerControllerId=0

connectionToClient=

connectionToServer=hostId: 0 connectionId: 1 isReady: True channel count: 2

isClient=True

isServer=False

localPlayerAuthority=True

hasAuthority=True

isLocalPlayer=True

NBPlayer7 (MoreFun.TestNetworkBehaviour).Start()

至此,NetworkBehaviour的初始化阶段已结束。接下来是正常运转阶段。

Remote ClientPlayer运转阶段

NetworkBehaviour.FixedUpdate()(多次)

fixedUpdateCount=15, go.instanceID=-65642,go=NBPlayer7(UnityEngine.GameObject)

netId=7

playerControllerId=0

connectionToClient=

connectionToServer=hostId: 0 connectionId: 1 isReady: True channel count: 2

isClient=True

isServer=False

localPlayerAuthority=True

hasAuthority=True

isLocalPlayer=True

NBPlayer7 (MoreFun.TestNetworkBehaviour).FixedUpdate()

NetworkBehaviour.Update()(多次)

updateCount=4, go.instanceID=-65642,go=NBPlayer7(UnityEngine.GameObject)

netId=7

playerControllerId=0

connectionToClient=

connectionToServer=hostId: 0 connectionId: 1 isReady: True channel count: 2

isClient=True

isServer=False

localPlayerAuthority=True

hasAuthority=True

isLocalPlayer=True

NBPlayer7 (MoreFun.TestNetworkBehaviour).Update()

NetworkBehaviour.OnDeserialize()(多次)

deserializeCount=5, reader=NetBuf sz:28 pos:28, initialState=False, go.instanceID=-65642,go=NBPlayer7 (UnityEngine.GameObject)

netId=7

playerControllerId=0

connectionToClient=

connectionToServer=hostId: 0 connectionId: 1 isReady: True channel count: 2

isClient=True

isServer=False

localPlayerAuthority=True

hasAuthority=True

isLocalPlayer=True

NBPlayer7 (MoreFun.TestNetworkBehaviour).OnDeserialize()

Remote ClientPlayer销毁阶段

通过调用NetworkServer.Destroy(gameObject);gameObject进入销毁阶段。

NetworkBehaviour.OnNetworkDestroy()

public void OnNetworkDestroy();
Description
This is invoked on clients when the server has caused this object to bedestroyed.
This can be used as a hook to invoke effects or do client specific cleanup.

留意只有客户端才会被调用OnNetworkDestroy()

go.instanceID=-65642,go=NBPlayer7 (UnityEngine.GameObject)

netId=7

playerControllerId=0

connectionToClient=

connectionToServer=hostId: 0 connectionId: 1 isReady: True channel count: 2

isClient=True

isServer=False

localPlayerAuthority=True

hasAuthority=True

isLocalPlayer=True

NBPlayer7 (MoreFun.TestNetworkBehaviour).OnNetworkDestroy()

NetworkBehaviour.OnDisable()

go.instanceID=-65642,go=NBPlayer7 (UnityEngine.GameObject)

netId=7

playerControllerId=0

connectionToClient=

connectionToServer=hostId: 0 connectionId: 1 isReady: True channel count: 2

isClient=True

isServer=False

localPlayerAuthority=True

hasAuthority=True

isLocalPlayer=True

NBPlayer7 (MoreFun.TestNetworkBehaviour).OnDisable()

NetworkBehaviour.OnDestroy()

go.instanceID=-65642,go=NBPlayer7 (UnityEngine.GameObject)

netId=7

playerControllerId=0

connectionToClient=

connectionToServer=hostId: 0 connectionId: 1 isReady: True channel count: 2

isClient=True

isServer=False

localPlayerAuthority=True

hasAuthority=True

isLocalPlayer=True

NBPlayer7 (MoreFun.TestNetworkBehaviour).OnDestroy()

Remote ClientClient销毁阶段

通过点击NetworkManagerHUDStop按钮,停止RemoteClient

NetworkManager.OnStopHost()

public void OnStopHost();
Description
This hook is called when a host is stopped.

NetworkManagerHUDbugRemote Client情况点击它也调用StopHost(),所以OnStopHost()也会被错误地调用。
正式情况应忽略。

NetworkManager (NewBorn.NBNetworkManager).OnStopHost()

NetworkManager.OnStopClient()

public void OnStopClient();
Description
This hook is called when a client is stopped.

NetworkManager.StopClient()调用时,先调用NetworkManager.OnStopClient(),然后再断连接、清除GameObject、跳转到OfflineScene

NetworkManager (NewBorn.NBNetworkManager).OnStopClient()

至此,RemoteClient整个流程结束。


Host情况

在已有上面DedicatedServerRemoteClient的情况,Host情况也将适当从略。

Host初始化阶段

NetworkManager.Start()

NetworkManager (NewBorn.NBNetworkManager).Start()

NetworkManager.StartHost()

public Networking.NetworkClient StartHost();
Returns
NetworkClient Theclient object created - this is a "local client".
Description
This starts a network "host" - a server and client in the sameapplication.
The client returned from StartHost() is a special "local" client thatcommunicates to the in-process server using a message queue instead of the realnetwork. But in almost all other cases, it can be treated as a normal client.

NetworkManager (NewBorn.NBNetworkManager).StartHost()

NetworkManager.OnStartHost()

NetworkManager (NewBorn.NBNetworkManager).OnStartHost()

NetworkManager.OnStartServer()

NetworkManager (NewBorn.NBNetworkManager).OnStartServer()

NetworkManager.ServerChangeScene()

Battle_Demo_Official

NetworkManager (NewBorn.NBNetworkManager).ServerChangeScene()

NetworkManager.OnServerConnect()2次)(LocalClient混杂进来的Server函数)

hostId: -1 connectionId: 0 isReady: False channel count: 0

NetworkManager (NewBorn.NBNetworkManager).OnServerConnect()

NetworkManager.OnStartClient()LocalClient混杂进来的Client函数)

UnityEngine.Networking.LocalClient

NetworkManager (NewBorn.NBNetworkManager).OnStartClient()

NetworkManager.OnClientConnect()LocalClient混杂进来的Client函数)

hostId: -1 connectionId: 0 isReady: False channel count: 0

NetworkManager (NewBorn.NBNetworkManager).OnClientConnect()

NetworkManager.OnServerSceneChanged()

Battle_Demo_Official

NetworkManager (NewBorn.NBNetworkManager).OnServerSceneChanged()

NetworkManager.OnClientSceneChanged()LocalClient混杂进来的Client函数)

hostId: -1 connectionId: 0 isReady: False channel count: 0

NetworkManager (NewBorn.NBNetworkManager).OnClientSceneChanged()

NetworkManager.OnServerReady()LocalClient混杂进来的Server函数)

hostId: -1 connectionId: 0 isReady: False channel count: 0

NetworkManager (NewBorn.NBNetworkManager).OnServerReady()

NetworkManager.OnServerAddPlayer()LocalClient混杂进来的Server函数)

hostId: -1 connectionId: 0 isReady: True channel count: 0, 0

NetworkManager (NewBorn.NBNetworkManager).OnServerAddPlayer()

至此,HostServer初始化逻辑(混杂着LocalClient的初始化逻辑)结束。
进入Player初始化阶段。

Host情况的Player初始化阶段

NetworkManager.OnServerConnect()

hostId: 0 connectionId: 1 isReady: False channel count: 2

NetworkManager (NewBorn.NBNetworkManager).OnServerConnect()

NetworkManager.OnServerReady()

hostId: 0 connectionId: 1 isReady: False channel count: 2

NetworkManager (NewBorn.NBNetworkManager).OnServerReady()

NetworkManager.OnServerAddPlayer()

hostId: 0 connectionId: 1 isReady: True channel count: 2, 0

NetworkManager (NewBorn.NBNetworkManager).OnServerAddPlayer()

至此,开始PlayerPrefabHost已被Instantiate出来。正式开始NetworkIdentity/NetworkBehaviour的函数流程。

NetworkBehaviour.Awake()

go.instanceID=-78256,go=NBPlayer(Clone) (UnityEngine.GameObject)

netId=0

playerControllerId=-1

connectionToClient=

connectionToServer=

isClient=False

isServer=False

localPlayerAuthority=True

hasAuthority=False

isLocalPlayer=False

NBPlayer(Clone)(MoreFun.TestNetworkBehaviour).Awake()

NetworkBehaviour.OnEnable()

go.instanceID=-78256,go=NBPlayer(Clone)(UnityEngine.GameObject)

netId=0

playerControllerId=-1

connectionToClient=

connectionToServer=

isClient=False

isServer=False

localPlayerAuthority=True

hasAuthority=False

isLocalPlayer=False

NBPlayer(Clone)(MoreFun.TestNetworkBehaviour).OnEnable()

NetworkBehaviour.OnStartServer()
合法变量:

·        netId=2。由于是Host,所以不需调用OnDeserialize()。立刻确定了netId

·        isServer=True

go.instanceID=-78256,go=NBPlayer(Clone) (UnityEngine.GameObject)

netId=7

playerControllerId=0

connectionToClient=hostId: 0 connectionId: 1 isReady: True channel count: 2

connectionToServer=

isClient=False

isServer=True

localPlayerAuthority=True

hasAuthority=False

isLocalPlayer=False

NBPlayer(Clone)(MoreFun.TestNetworkBehaviour).OnStartServer()

NetworkBehaviour.PreStartClient()

go.instanceID=-78256,go=NBPlayer7 (UnityEngine.GameObject)

netId=7

playerControllerId=0

connectionToClient=hostId: 0 connectionId: 1 isReady: True channel count: 2

connectionToServer=

isClient=True

isServer=True

localPlayerAuthority=True

hasAuthority=False

isLocalPlayer=False

NBPlayer7 (MoreFun.TestNetworkBehaviour).PreStartClient()

NetworkBehaviour.OnStartClient()

go.instanceID=-78256,go=NBPlayer7 (UnityEngine.GameObject)

netId=7

playerControllerId=0

connectionToClient=hostId: 0 connectionId: 1 isReady: True channel count: 2

connectionToServer=

isClient=True

isServer=True

localPlayerAuthority=True

hasAuthority=False

isLocalPlayer=False

NBPlayer7 (MoreFun.TestNetworkBehaviour).OnStartClient()

NetworkBehaviour.OnRebuildObservers()

observers=System.Collections.Generic.HashSet`1[UnityEngine.Networking.NetworkConnection], initialize=True,

go.instanceID=-78256,go=NBPlayer7(UnityEngine.GameObject)

netId=7

playerControllerId=0

connectionToClient=hostId: 0 connectionId: 1 isReady: True channel count: 2

connectionToServer=

isClient=True

isServer=True

localPlayerAuthority=True

hasAuthority=False

isLocalPlayer=False

NBPlayer7 (MoreFun.TestNetworkBehaviour).OnRebuildObservers()

NetworkBehaviour.OnSerialize()(多次)

serializeCount=1, writer=UnityEngine.Networking.NetworkWriter,initialState=True, go.instanceID=-78256,go=NBPlayer7 (UnityEngine.GameObject)

netId=7

playerControllerId=0

connectionToClient=hostId: 0 connectionId: 1 isReady: True channel count: 2

connectionToServer=

isClient=True

isServer=True

localPlayerAuthority=True

hasAuthority=False

isLocalPlayer=False

NBPlayer7 (MoreFun.TestNetworkBehaviour).OnSerialize()

NetworkBehaviour.OnSetLocalVisibility()

public void OnSetLocalVisibility(bool vis);
Parameters
vis Newvisibility state.
Description
Callback used by the visibility system for objects on a host.
Objects on a host (with a local client) cannot be disabled or destroyed whenthey are not visibile to the local client. So this function is called to allowcustom code to hide these objects. A typical implementation will disablerenderer components on the object. This is only called on local clients on ahost.

vis=True, go.instanceID=-78256,go=NBPlayer7 (UnityEngine.GameObject)

netId=7

playerControllerId=0

connectionToClient=hostId: 0 connectionId: 1 isReady: True channel count: 2

connectionToServer=

isClient=True

isServer=True

localPlayerAuthority=True

hasAuthority=False

isLocalPlayer=False

NBPlayer7 (MoreFun.TestNetworkBehaviour).OnSetLocalVisibility()

NetworkBehaviour.Start()

go.instanceID=-78256,go=NBPlayer7 (UnityEngine.GameObject)

netId=7

playerControllerId=0

connectionToClient=hostId: 0 connectionId: 1 isReady: True channel count: 2

connectionToServer=

isClient=True

isServer=True

localPlayerAuthority=True

hasAuthority=False

isLocalPlayer=False

NBPlayer7 (MoreFun.TestNetworkBehaviour).Start()

至此,Host情况的NetworkIdentity/NetworkBehaviour的初始化阶段已结束。接下来是正常运转阶段。

Host情况的Player运转阶段

NetworkBehaviour.FixedUpdate()(多次)

fixedUpdateCount=5,

go.instanceID=-78256,go=NBPlayer7 (UnityEngine.GameObject)

netId=7

playerControllerId=0

connectionToClient=hostId: 0 connectionId: 1 isReady: True channel count: 2

connectionToServer=

isClient=True

isServer=True

localPlayerAuthority=True

hasAuthority=False

isLocalPlayer=False

NBPlayer7 (MoreFun.TestNetworkBehaviour).FixedUpdate()

NetworkBehaviour.Update()(多次)

updateCount=4,

go.instanceID=-78256,go=NBPlayer7 (UnityEngine.GameObject)

netId=7

playerControllerId=0

connectionToClient=hostId: 0 connectionId: 1 isReady: True channel count: 2

connectionToServer=

isClient=True

isServer=True

localPlayerAuthority=True

hasAuthority=False

isLocalPlayer=False

NBPlayer7 (MoreFun.TestNetworkBehaviour).Update()

NetworkBehaviour.OnSerialize()(多次)

serializeCount=4,writer=UnityEngine.Networking.NetworkWriter, initialState=False, go.instanceID=-78256,go=NBPlayer7(UnityEngine.GameObject)

netId=7

playerControllerId=0

connectionToClient=hostId: 0 connectionId: 1 isReady: True channel count: 2

connectionToServer=

isClient=True

isServer=True

localPlayerAuthority=True

hasAuthority=False

isLocalPlayer=False

NBPlayer7 (MoreFun.TestNetworkBehaviour).OnSerialize()

Host情况的Player销毁阶段

通过调用NetworkServer.Destroy(gameObject);gameObject进入销毁阶段。

NetworkBehaviour.OnNetworkDestroy()

go.instanceID=-78256,go=NBPlayer7 (UnityEngine.GameObject)

netId=7

playerControllerId=0

connectionToClient=hostId: 0 connectionId: 1 isReady: True channel count: 2

connectionToServer=

isClient=True

isServer=True

localPlayerAuthority=True

hasAuthority=False

isLocalPlayer=False

NBPlayer7 (MoreFun.TestNetworkBehaviour).OnNetworkDestroy()

NetworkBehaviour.OnDisable()

go.instanceID=-78256,go=NBPlayer7 (UnityEngine.GameObject)

netId=7

playerControllerId=0

connectionToClient=hostId: 0 connectionId: 1 isReady: True channel count: 2

connectionToServer=

isClient=True

isServer=False

localPlayerAuthority=True

hasAuthority=False

isLocalPlayer=False

NBPlayer7 (MoreFun.TestNetworkBehaviour).OnDisable()

NetworkBehaviour.OnDestroy()

go.instanceID=-78256,go=NBPlayer7 (UnityEngine.GameObject)

netId=0

playerControllerId=0

connectionToClient=hostId: 0 connectionId: 1 isReady: True channel count: 2

connectionToServer=

isClient=True

isServer=False

localPlayerAuthority=True

hasAuthority=False

isLocalPlayer=False

NBPlayer7 (MoreFun.TestNetworkBehaviour).OnDestroy()

NetworkManager.OnServerDisconnect()

hostId: 0 connectionId: 1 isReady: False channel count: 2

NetworkManager (NewBorn.NBNetworkManager).OnServerDisconnect()

至此,Host情况的Player流程结束。

Host销毁流程

NetworkManager.OnStopHost()

NetworkManager (NewBorn.NBNetworkManager).OnStopHost()

NetworkManager.OnStopServer()

NetworkManager (NewBorn.NBNetworkManager).OnStopServer()

NetworkManager.ServerChangeScene()

BattleOffline

NetworkManager (NewBorn.NBNetworkManager).ServerChangeScene()

NetworkManager.OnStopClient()

NetworkManager (NewBorn.NBNetworkManager).OnStopClient()

至此,Host情况全部流程结束。

 

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引