Network Clients and Servers
Using the Transport Layer API

主机迁移

In a multiplayer network game without a dedicated server, one of the peers in the game acts as the center of authority for the game. This peer is called the “host”. It runs a server and a “local client”, while the other peers each run a “remote client”.

If the host of a game is lost, then the game cannot continue. The host could be lost because the player left, the host process was killed or crashed, the host’s machine was shut down, or because the network connection of the host was lost.

The “Host Migration” feature allows one of the remote clients to become the new host, so that the multiplayer game can continue.

How it works

During a multiplayer game with host migration enabled, the addresses of the peers will be distributed to the peers in the game. When the host is lost, one peer can become the new host. The other peers then connect to the new host and the game can continue.

The new NetworkMigrationManager component can be dropped into a multiplayer game that uses the Unity Networking HLAPI, and it allows the game to continue with a new host after the original host is lost. Below is a screenshot of the NetworkMigrationManager in the editor inspector. It shows the current migration state.

Network Migration Manager 组件
Network Migration Manager 组件

There is a simple user interface provided by the NetworkMigrationManager, similar to the NetworkManagerHUD. This user interface is intended for testing and prototyping; a real game would implement a custom user interface for host migration, and probably custom logic - possibly choosing the new host automatically without requiring input from the user.

Network Migration Manager 原型设计 HUD
Network Migration Manager 原型设计 HUD

Even though the migration may have occurred because the old host lost connection or quite the game, it is possible for the old host of the game to rejoin the game as a client on the new host.

The state of SyncVars and SyncLists on all networked objects in the scene are maintained during a host migration. This also applies to custom serialized data for objects.

All of the player objects in the game are disabled when the host is lost. Then, when the other clients rejoin the new game on the new host, the corresponding players for those clients are re-enabled on the host, and respawned on the other clients. So no player state data is lost during a host migration.

NOTE: Only data that is available to clients will be preserved during a host migration. If there is data that is only on the server, then it will not be available to the client that becomes the new host. So any data on the host that is not stored in SyncVars or SyncLists will not be available after a host migration.

The callback function OnStartServer is invoked for all networked objects when the client becomes a new host.

On the new host, the NetworkMigrationManager uses the function BecomeNewHost to construct a networked server scene from the state in the current ClientScene.

The peers in a game with host migration enabled are identified by their connectionId on the server. When a client reconnects to the new host of a game, this connectionId is passed to the new host so that it can match this client with the client that was connected to the old host. This Id is set on the ClientScene as the “reconnectId”.

Non-Player Objects

Non-player objects with client authority are also handled by host migration. The objects owned by each client are disabled and re-enabled the same way that player objects are.

Identifying Peers

Before the host is lost, all the peers are connected to the host. They each have a unique connectionId on the host - this is called the “oldConnectionId” in the context of host migration.

When a new host is chosen and the peers reconnect to it, they supply their “oldConnectionId” to identify which peer they are. This allows the new host to match this reconnecting client to the corresponding player object.

The old host uses a special oldConnectionId of zero to reconnect - since it did not have a connection to the old host, it WAS the old host. There is a constant ClientScene.ReconnectIdHost for this.

When using the built-in user interface, the oldConnectionId is set automatically. It can be set manually using NetworkMigrationManager.Reset or ClientScene.SetReconnectId.

Host Migration Flow

  1. MachineA hosts a game with host-migration enabled

  2. MachineB starts a client and joins the game with host-migration enabled
    • MachineB is told about peers (MachineA–0, and self (MachineB)–1)
  3. MachineC starts a client and joins the game with host-migration enabled
    • MachineC is told about peers (MachineA–0, MachineB–1, and self (MachineC)–2)
  4. MachineA is lost, so the host is lost

  5. MachineB gets disconnect from host
    1. MachineB callback function is invoked on MigrationManager on client
    2. MachineB player objects for all players are disabled
    3. MachineB stay in online scene
  6. MachineB 使用实用函数来挑选新主机,选取自身作为新主机
    1. MachineB calls BecomeNewHost()
    2. MachineB 开始监听
    3. MachineB player object for self is reactivated
    4. MachineB 的玩家现在已恢复自己原来的全部游戏状态
  7. MachineC 与主机断开连接
    1. MachineC callback function is invoked on MigrationManager on client
    2. MachineC player objects for all players are disabled
    3. MachineC stay in online scene
  8. MachineC 使用实用函数来挑选新主机,选取 MachineB
    • MachineC 重新连接到新主机
  9. MachineB 接收来自 MachineC 的连接
    1. MachineC send reconnect message with oldConnectionId (instead of AddPlayer message)
    2. MigrationManager 在服务器上调用回调函数
    3. MachineB uses oldConnectionId to find the disabled player object for that player and re-adds it with ReconnectPlayerForConnection()
    4. player object is re-spawned for MachineC
    5. MachineC 的玩家现在已恢复自己原来的全部游戏状态
  10. MachineA 恢复(旧主机)
    1. MachineA uses utility function to pick the new host, picks MachineB
    2. MachineA “reconnects” to MachineB
  11. MachineB 接收来自 MachineA 的连接

  12. MachineA 以等于零的 oldConnectionId 发送重新连接消息
    1. callback function is invoked on MigrationManager on server (MachineB)
    2. MachineB uses oldConnectionId to find the disabled player object for that player and re-adds it with ReconnectPlayerForConnection()
    3. player object is re-spawned for MachineA
    4. MachineA 的玩家现在已恢复自己原来的全部游戏状态

Callback Functions

Callback functions on the NetworkHostMigrationManager

// called on client after the connection to host is lost. controls whether to switch scenes
protected virtual void OnClientDisconnectedFromHost(
    NetworkConnection conn, 
    out SceneChangeOption sceneChange)

// called on host after the host is lost. host MUST change scenes
protected virtual void OnServerHostShutdown()

// called on new host (server) when a client from the old host re-connects a player
protected virtual void OnServerReconnectPlayer(
    NetworkConnection newConnection, 
    GameObject oldPlayer, 
    int oldConnectionId, 
    short playerControllerId)

// called on new host (server) when a client from the old host re-connects a player
protected virtual void OnServerReconnectPlayer(
    NetworkConnection newConnection, 
    GameObject oldPlayer, 
    int oldConnectionId, 
    short playerControllerId, 
    NetworkReader extraMessageReader)

// called on new host (server) when a client from the old host re-connects a non-player object
protected virtual void OnServerReconnectObject(
    NetworkConnection newConnection, 
    GameObject oldObject, 
    int oldConnectionId)

// called on both host and client when the set of peers is updated
protected virtual void OnPeersUpdated(
    PeerListMessage peers)

// utility function called by the default UI on client after connection to host was lost, to pick a new host.
public virtual bool FindNewHost(
    out NetworkSystem.PeerInfoMessage newHostInfo, 
    out bool youAreNewHost)

// called when the authority of a non-player object changes
protected virtual void OnAuthorityUpdated(
    GameObject go,
    int connectionId,
    bool authorityState)

约束

Data that is only present on the server (the host) will be lost when the host is disconnected. For games to be able to perform host migration correctly, important data must be distributed to the clients, not held secretly on the server.

这种情况适用于直接连接的游戏。需要执行额外的工作才能与 Matchmaker 和 Relay Server 一起工作。

Network Clients and Servers
Using the Transport Layer API