服务器和主机
在统一网络系统中,游戏有一个服务器和多个客户端。当没有专用服务器时,其中一个客户端充当服务器的角色 - 我们将此客户端称为“主机”。
主机是同一进程中的服务器和客户端。主机使用一种特殊类型的客户端,称为LocalClient,而其他客户端是RemoteClient。LocalClient通过直接函数调用和消息队列与(本地)服务器进行通信,因为它在同一进程中。它实际上与服务器共享场景。RemoteClient通过常规网络连接与服务器通信。
网络系统的目标之一是使LocalClient和RemoteClient的代码相同,以便开发人员在大多数时候只需考虑一种类型的客户端。
实例化和产生
在Unity中,GameObject.Instantiate创建新的Unity游戏对象。但是对于网络系统,对象也必须“生成”以在网络上活动。这只能在服务器上完成,并在连接的客户端上创建对象。一旦对象被产生,实例系统使用分布式对象生命周期管理和状态同步原理。
更多细节请参见Spawning。
玩家,本地玩家和权限
在网络系统中,玩家对象是特殊的。存在与玩游戏的每个人相关联的玩家对象,并且指令被路由到该对象。每个人只能特定的调用自己控制的指令控制Player。所以有一个“我即Player”的概念。当添加玩家并且利用连接进行关联时,该玩家对象变成该玩家的客户端上的“本地玩家”对象。有一个属性isLocalPlayer设置为true,并在客户端上的对象上调用一个回调OnStartLocalPlayer()。下图显示了两个客户端及其本地播放器。
只有“我“控制的Player对象将设置isLocalPlayer标志。这可以用于过滤输入处理,处理相机附件,或做任何其他客户端上只有“你的”Player对象才能做的事情。
除了isLocalPlayer,Player对象可以有“本地权限”。这意味着玩家客户端上的Player对Player实例对象负责- 它具有权限。这是最常用在控制运动上,但也可以用于其他的事情。NetworkTransform组件理解这一点,如果设置了,将从客户端发送移动。NetworkIdentity有一个用于设置LocalPlayerAuthority的复选框。
对于非Player对象(例如敌人),没有关联的客户端,因此权限驻留在服务器上。
NetworkBehaviour上有一个属性“hasAuthority”,可用于判断对象是否具有权限。因此非Player对象在服务器上具有权限,并且具有localPlayerAuthority集的Player对象对其所有者的客户端具有权限。
非玩家对象的客户端权限
从Unity 5.2版开始,可以对非Player对象具有客户端权限。有两种方法来做到这一点。一个是使用NetworkServer.SpawnWithClientAuthority生成对象,并传递客户端的网络连接以获取所有权。另一种是使用NetworkIdentity.AssignClientAuthority与客户端的网络连接获取所有权。
向客户端分配权限会导致对象上的NetworkBehaviours调用OnStartAuthority(),属性hasAuthority将为true。在其他客户端上,hasAuthority属性仍将为false。具有客户端权限的非Player对象可以发送指令,就像Player可以。这些指令在对象的服务器实例上运行,而不是在与连接相关联的播放器上运行。
具有客户端权限的非Player对象必须在其NetworkIdentity中检查LocalPlayerAuthority。
以下示例生成一个对象,并客户端的权限分配给产生的对象。
[Command]
void CmdSpawn()
{
var go = (GameObject)Instantiate(otherPrefab, transform.position + new Vector3(0,1,0), Quaternion.identity);
NetworkServer.SpawnWithClientAuthority(go, connectionToClient);
}
网络文本属性
NetworkBehaviour类有一些属性,允许脚本随时知道网络对象的网络文本。
• isServer - 如果对象在服务器(或主机)上并且已生成,则为true。
• isClient - 如果对象在客户端上,并且由服务器创建,则为true。
• isLocalPlayer - 如果对象是此客户端的播放器对象,则为true。
• hasAuthority - 如果对象由本地进程拥有,则为true
这些属性可以在编辑器的检查器窗口中的对象的预览窗口中看到。