主机迁移

在没有专用服务器的多人网络游戏中,游戏中的其中一位同伴充当游戏权限的中心。这个对等体被称为“主机”。它运行一个服务器和一个“本地客户端”,而其他对等端运行一个“远程客户端”。

如果游戏的主机丢失,那么游戏无法继续。主机可能会丢失,因为玩家离开,主机进程死亡或崩溃,主机的机器被关闭,或因为主机的网络连接丢失。

“主机迁移”功能允许其中一个远程客户端成为新的主机,这样多人游戏就可以继续。

怎么运行的

在启用主机迁移的多人游戏中,同伴的地址将分配给游戏中的同伴。当主机丢失时,一个对等体可以成为新的主机。其他同伴然后连接到新的主机,游戏可以继续。

新的NetworkMigrationManager组件可以放入使用Unity Networking HLAPI的多人游戏中,并且允许游戏在原始主机丢失后继续使用新主机。以下是编辑器检查器中NetworkMigrationManager的屏幕截图。它显示了当前的迁移状态。

 6.218 主机迁移  - 图1

NetworkMigrationManager提供了一个简单的用户界面,类似于NetworkManagerHUD。此用户界面用于测试和原型设计;一个真正的游戏将实现一个用于主机迁移的定制用户界面,并且可能定制逻辑 - 可能自动选择新主机而不需要来自用户的输入。

 6.218 主机迁移  - 图2

即使迁移可能是由于旧主机失去连接或相当于游戏而发生的,但旧游戏主机有可能作为新主机上的客户端重新加入游戏。

场景中所有联网对象上的SyncVarsSyncLists的状态在主机迁移期间保持不变。这也适用于对象的自定义序列化数据。

当主机丢失时,游戏中的所有玩家对象都被禁用。然后,当其他客户端重新加入新主机上的新游戏时,这些客户端的相应玩家将在主机上重新启用,并在其他客户端上重新生成。所以在主机迁移期间没有玩家状态数据丢失。

注意:只有在客户端可用的数据将在主机迁移期间保留。如果只有服务器上存在数据,则该数据将不可用于成为新主机的客户端。因此,在主机迁移后,主机上未存储在SyncVarsSyncLists中的任何数据都将不可用。

当客户端成为新主机时,将为所有联网对象调用回调函数OnStartServer

在新主机上,NetworkMigrationManager使用函数BecomeNewHost从当前ClientScene中的状态构建联网服务器场景。

启用了主机迁移的游戏中的对等方由其connectionId在服务器上标识。当客户端重新连接到游戏的新主机时,此connectionId将传递到新主机,以便它可以将此客户端与连接到旧主机的客户端相匹配。此Id在ClientScene上设置为“reconnectId”。

非玩家对象

具有客户端权限的非玩家对象也通过主机迁移进行处理。每个客户端所拥有的对象都被禁用,并以与玩家对象相同的方式重新启用。

识别同伴

在主机丢失之前,所有对等点都连接到主机。它们在主机上都有唯一的连接ID - 在主机迁移的上下文中称为“oldConnectionId”。

当选择新主机并且同级重新连接到它时,它们提供它们的“oldConnectionId”以标识它们是哪个对等体。这允许新的主机将这个重新连接的客户端匹配到相应的玩家对象。

旧主机使用零的特殊oldConnectionId重新连接 - 因为它没有与旧主机的连接,所以它是旧主机。有一个常量ClientScene.ReconnectIdHost这个。

使用内置用户界面时,oldConnectionId会自动设置。可以使用NetworkMigrationManager.ResetClientScene.SetReconnectId手动设置。

主机迁移流程

  1. 1.MachineA托管启用主机迁移的游戏
  2. 2.MachineB启动客户端,并在启用主机迁移的情况下加入游戏
  3. MachineB被告知关于同伴(MachineA-0和自身(MachineB)-1
  4. 3.MachineC启动一个客户端并加入启用主机迁移的游戏
  5. MachineC被告知关于同伴(MachineA-0MachineB-1selfMachineC)-2
  6. 4.MachineA丢失,所以主机丢失
  7. 5.MachineB与主机断开连接
  8. 1.MachineB回调函数在客户端上的MigrationManager上调用
  9. 2.所有玩家的MachineB玩家对象都被禁用
  10. 3.MachineB留在在线场景中
  11. 6.MachineB使用效用函数来挑选新的主机,挑选自己
  12. 1.MachineB调用BecomeNewHost()
  13. 2.MachineB开始收听
  14. 3.自我的MachineB玩家对象被重新激活
  15. 4.MachineB MachineB的玩家现在回到了游戏中的状态
  16. 7.MachineC与主机断开连接
  17. 1.MachineC回调函数在客户端上的MigrationManager上调用
  18. 2.所有玩家的MachineC玩家对象都被禁用
  19. 3.MachineC停留在在线场景中
  20. 8.MachineC使用实用程序功能选择新主机,选择MachineB
  21. MachineC重新连接到新主机
  22. 9.MachineBMachineC接收连接
  23. 1.MachineC使用oldConnectionId发送重新连接消息(而不是AddPlayer消息)
  24. 2.在服务器上的MigrationManager上调用回调函数
  25. 3.MachineB使用oldConnectionId为该玩家查找禁用的玩家对象,并使用ReconnectPlayerForConnection()重新添加它,
  26. 4.玩家对象为MachineC重新生成
  27. 5.MachineC的玩家现在回到了游戏中的状态
  28. 10.MachineA恢复(旧主机)
  29. 1.MachineA使用实用程序功能选择新主机,选择MachineB
  30. 2.MachineA“重新连接”到MachineB
  31. 11.MachineBMachineA接收连接
  32. 12.MachineA发送oldConnectionId为零的重新连接消息
  33. 1.在服务器上的MigrationManagerMachineB)上调用回调函数
  34. 2.MachineB使用oldConnectionId为该玩家查找禁用的玩家对象,并使用ReconnectPlayerForConnection()重新添加它,
  35. 3.玩家对象为MachineA重新生成
  36. 4.MachineA的玩家现在重新回到了游戏中的状态

回调函数

NetworkHostMigrationManager上的回调函数

  1. // called on client after the connection to host is lost. controls whether to switch scenes
  2. protected virtual void OnClientDisconnectedFromHost(
  3. NetworkConnection conn,
  4. out SceneChangeOption sceneChange)
  5. // called on host after the host is lost. host MUST change scenes
  6. protected virtual void OnServerHostShutdown()
  7. // called on new host (server) when a client from the old host re-connects a player
  8. protected virtual void OnServerReconnectPlayer(
  9. NetworkConnection newConnection,
  10. GameObject oldPlayer,
  11. int oldConnectionId,
  12. short playerControllerId)
  13. // called on new host (server) when a client from the old host re-connects a player
  14. protected virtual void OnServerReconnectPlayer(
  15. NetworkConnection newConnection,
  16. GameObject oldPlayer,
  17. int oldConnectionId,
  18. short playerControllerId,
  19. NetworkReader extraMessageReader)
  20. // called on new host (server) when a client from the old host re-connects a non-player object
  21. protected virtual void OnServerReconnectObject(
  22. NetworkConnection newConnection,
  23. GameObject oldObject,
  24. int oldConnectionId)
  25. // called on both host and client when the set of peers is updated
  26. protected virtual void OnPeersUpdated(
  27. PeerListMessage peers)
  28. // utility function called by the default UI on client after connection to host was lost, to pick a new host.
  29. public virtual bool FindNewHost(
  30. out NetworkSystem.PeerInfoMessage newHostInfo,
  31. out bool youAreNewHost)
  32. // called when the authority of a non-player object changes
  33. protected virtual void OnAuthorityUpdated(
  34. GameObject go,
  35. int connectionId,
  36. bool authorityState)

约束

当主机断开连接时,仅存在于服务器(主机)上的数据将会丢失。为了使游戏能够正确执行主机迁移,必须将重要数据分发给客户端,而不是秘密保存在服务器上。

这适用于直接连接游戏。需要额外的工作才能与媒人和中继服务器一起工作。

?