This document is about: QUANTUM 2
SWITCH TO

Reconnecting

以下文檔將會闡明關於重新連線到正在運行的Quantum遊戲階段的所有方面。基本工作流程會在與Quantum SDK一起提供的示範選單範例中執行。

重新連線流程包括兩個主要部分:如何回到Photon Realtime房間以及如何進行Quantum模擬?

偵測連線中斷

最常見的連線中斷情況:

  • 以不是 DisconnectCause.DisconnectByClientLogic 原因的方式來調用IConnectionCallbacks.OnDisconnected(DisconnectCause cause)
  • 手機應用程式失去焦點
  • 應用程式重啟
  • 過早檢測信號遺失的一種自訂方法

如何為了偵錯而中斷連線

  • 在Unity編輯器中,只需點擊遊玩即可停止和啟動應用程序
  • LoadBalancingClient.SimulateConnectionLoss(true)將會停止發送與接收,然後在10秒後將會導致DisconnectCause.ClientTimeout中斷連線。
  • LoadBalancingClient.LoadBalancingPeer.StopThread()馬上會造成DisconnectCause.None的連線中斷。
  • 使用外部網路工具(例如clumsy)來阻擋遊戲伺服器埠
Clumsy:
Filter  (udp.DstPort == 5056 or udp.SrcPort == 5056) or (tcp.DstPort == 4531 or tcp.SrcPort == 4531)
Drop    100%

Photon Realtime快速重新連線

返回房間有兩種方法:

  • 透過名稱伺服器(Photon Cloud)連線,當到達主伺服器時,以新的Photon Actor加入房間(這被稱為 預設 方式)
  • 或重新連線並重新加入

C#

LoadBalancingClient.ReconnectAndRejoin()

此方法將嘗試直接連線到遊戲伺服器,並使用快取驗證資料、伺服器位址、房間名稱等重新加入房間。此資訊被快取在載入平衡客戶端物件上。

重新加入房間會分配相同的Photon Actor帳號到客戶端。

重新連線或連線到主伺服器後也可以重新加入房間:

C#

LoadBalancingClient.ReconnectToMaster()
// ..
public void IConnectionCallbacks.OnConnectedToMaster() {
    _client.OpReJoinRoom(roomName);
}

只有當客戶端尚未離開房間時,重新加入操作才有效。(請見下一節PlayerTTL)

警告:在Quantum版本2.0.x中的快速重新連線,只有當提供一個本機快照(StartParameters.InitialFrameStartParameters.FrameData)時才可用。

C#

var frameData = QuantumRunner.Default.Game.Frames.Verified.Serialize(DeterministicFrameSerializeMode.Blit);
var initialFrame = QuantumRunner.Default.Game.Frames.Verified.Number;

要求:PlayerTTL

房間內的客戶端通常是active。他們變成inactive的情形有:

  • 10秒(預設)逾時後而沒有應答伺服器
  • 在調用LoadBalancingClient.Disconnect()
  • 在調用LoadBalancingClient.OpLeaveRoom(true)

現在有兩個選項:

A) 房間運行玩家已離線的邏輯(PlayerTTL為0,預設)

B) 在運行離開房間的常式之前,玩家被標記為inactive而且PlayerTTL會保持在該狀態幾毫秒。PlayerTTL值需要在建立房間時在RoomOptions中明確的設定。通常20秒(20000毫秒)是一個很好的起始設定值。

快速重新連線將允許客戶端在他們仍然active時(在OpJoinRoom()不允許的10秒逾時之前)和 inactive(在PlayerTTL時)逾時的時候回到他們的房間 .

當客戶端成功重新加入時,調用IMatchmakingCallbacks.OnJoinedRoom()

示範選單會執行兩個選項來檢測(UIConnect.OnReconnectClicked())。

  1. 當PlayerTTL > 0時執行ReconnectAndRejoin()
  2. 當PlayerTTL == 0時執行ReconnectToMaster()後再執行OpJoinRom()

要求:RoomTTL(等待快照)

當房間檢測到所有客戶端都inactive時,它會立即關閉自己。為了防止這樣的情況發生,需要設定 RoomOptions.EmptyRoomTTL。當您的房間只有少數玩家,並且所有玩家同時出現連線問題的可能時,這動作很重要。因為需要有人在場來發送快照,這只能在與自訂伺服器外掛程式和伺服器端快照一起運行時才能可靠地運行。

考慮到這種情況:在兩名玩家的線上遊戲中,其中一名玩家正在重新連線或延遲加入,並且等待快照,而另一名玩家開始出現連線問題。將永遠不會發送快照,並且玩家會卡在等待的過程中。

簡單的解決方案是偵測遊戲開始逾時,並讓等待的玩家中斷連線。這可以通過傳送QuantumRunner.StartParameters.StartGameTimeoutInSeconds並檢查QuantumRunner.HasGameStartTimedOut,且最終執行自訂錯誤處理來完成(比如給予玩家回饋並且返回大廳使用者介面)。如UIGame.Update()所示。

要求:Photon使用者帳號

Photon Realtime:大廳與配對 | 使用者帳號與朋友

在Photon中,使用獨一無二的使用者帳號來識別玩家。要使用重新加入來返回房間的話,使用者帳號必須相同。使用者帳號最初是明確設定的,還是由Photon設定的,並不重要。

進入房間後,使用者帳號對Quantum來說並不重要,因為它使用不同的帳號來識別玩家(請見Quantum客戶端帳號的章節)。

Photon使用者帳號可以:

  1. 在連線時由客戶端設定(AuthenticationValues.UserId)
  2. 如果留空時將由Photon設定
  3. 或是被外部認證服務設定

為了完成有關Photon使用者帳號的背景資訊:

  • Photon Actor Number(也稱為執行者帳號)會識別當前房間中的玩家,並且一個房間分配一個帳號,並且僅在該路徑中有效。離開和重新加入房間的客戶端將獲得一個新的執行者帳號。成功的OpRejoinRoom()或ReconnectAndRejoin()將保留執行者帳號。Quantum提供了一種方法去回溯執行者帳號並將它們匹配給玩家Frame.PlayerToActorId(PlayerRef)。但請記住,玩家離開和加入回來(不是重新加入)時,它們可以改變。

  • Photon Nickname是一個Photon客戶端屬性,它在房間中散佈以了解更多關於其他客戶端的資訊。與Quantum無關。

可能的錯誤:重新連線和重新加入傳回錯誤

當前的連線處理程序LoadBalancingClient缺少執行重新連線的相關資料。運行您的預設連線序列,並嘗試以一般的方式加入或重新加入房間。

也請參考Reconnecting After App Restart的章節.

可能的錯誤:PlayerTTL不足

當重新加入超過PlayerTTL逾時的時候,ErrorCode.JoinFailedWithRejoinerNotFound會出現.

這也表示我們連線到主伺服器,並且可以使用OpJoinRoom()加入房間。

C#

public void (IMatchmakingCallbacks.)OnJoinRoomFailed(short returnCode, string message) {
    switch (returnCode) {
        case ErrorCode.JoinFailedWithRejoinerNotFound:
            // Try to join the room without rejoining
            _client.OpJoinRoom(new EnterRoomParams { RoomName = roomName });
    break;
}

可能的錯誤:驗證權杖逾時

驗證權杖在1小時後過期。它在Quantum遊戲階段的過程中用完之前將自動重新整理(Photon Realtime:加密 | 權杖重新整理)。如果您一般遊戲階段很長久,並且您希望在大約20分鐘後支援重新連線玩家的功能,您需要處理此錯誤。解決方案是重新啟動預設連線常式並且嘗試加入回來房間。

C#

public void OnDisconnected(DisconnectCause cause) {
    switch (cause) {
        case DisconnectCause.AuthenticationTicketExpired:
        case DisconnectCause.InvalidAuthentication:
            // Restart with your default connection sequence
        break;

可能的錯誤:仍然無法連線

當然,連線仍可能受阻或發生其他錯誤。在每種情況下,都會調用IConnectionCallbacks.OnDisconnected(DisconnectCause cause)

在應用程式重新啟動後重新連線

載入平衡客戶端的物件快取了與重新加入操作相關的資料(權杖),並且在重新啟動應用程式時該資訊可能會遺失。

在這種情況下,連線必須從頭重新啟動,同時重新使用相同的 UserIdFixedRegionAppVersion。當到達主伺服器時,Rejoin()Join()回來房間。

由於遺失的連線快取,重新加入可能會失敗並顯示ErrorCode.JoinFailedFoundActiveJoiner,因為伺服器尚未暫存中斷連線(10秒逾時)。在這種情況下需要一直重試,直到重新加入成功或另一個錯誤發生。

在示範選單範例中,類別ReconnectInformation展示了如何使用與Unity玩家參照儲存和復原相關的最小可用的重新連線的資料。

重新連線的流程會被應用在 UIConnect.OnReconnectClicked()UIReconnecting.OnConnectedToMaster()裡。

將Photon UserId儲存到玩家參照時,當然可以用自訂驗證代替。

還可以在玩家參照中存儲和載入快照,這對於玩家數量非常少的遊戲來說很有趣。要將玩家參照中的二進位資料存儲為string,請使用base64編碼和解碼。

不同的主伺服器

ReconnectAndRejoin()ReconnectToMaster()都可以防止出現邊緣案件,這些案件是藉由雲端連線回來時,讓客戶端最終會位於與以前不同的主伺服器上。原因是:

  • 在一個應用程式裡有多個叢集
  • 主伺服器已經被替代(被轉出)
  • 最佳區域Ping有新結果

其他Photon Realtime主題

這些功能對於重新連線並不重要,但它們是示範選單範例的一部分,因此我們也想在這裡介紹它們。

最佳區域摘要

類別QuantumLoadBalancingClient圍繞著Photon Realtime LoadBalancingClient。這只是為了方便地快取最佳區域Ping結果。成功連線到主伺服器後,我們將它們存儲到Unity玩家參照中,並透過應用程式設定物件在下一次連線嘗試時提供它們,以加快連線到最佳區域的速度。

有時會強制執行區域Ping,但為了確保某些玩家不會被糟糕的Ping結果所困,執行無效判定可能是明智之舉,這樣玩家不會永遠被糟糕或錯誤的結果所困(例如,如果Ping高於門檻,每隔一天清除最佳區域摘要)。此外,玩家可能會前往世界的其他地方,那裡會需要新的Ping才能找到最近的區域。

應用程式版本

示範選單範例使用隨機配對來配對玩家。我們在AppSettings提供的AppVersion會將玩家基底按照相同應用程式帳號的分成不同的群組。連接同一個應用程式帳號和不同應用程式版本的玩家根本找不到對方。

這在運行多個遊戲版本時以及在開發過程中非常有用,可防止其他客戶端(有著不同的程式碼基底並且將立即取消同步遊戲)加入開發人員運行的遊戲中。

UIConnect.cs涵蓋了新增泛型應用程式版本,和擁有用於不間斷測試的私密金鑰。為每個工作區生成一次私密的應用程式版本字串(請見PhotonPrivateAppVersion.cs)。從該工作區建立的每個組建都能夠使玩家相互配對。

進一步閱讀

重新連線到一個運行中的Quantum遊戲

Quantum客戶端帳號

ClientId是一個客戶端及伺服器之間的秘密。其他客戶端永遠也不會知道它。它在開始Quantum執行器時被傳遞。

C#

public static QuantumRunner StartGame(String clientId, StartParameters param)

無論是作為新的Photon房間執行者加入還是重新加入,重新連線的客戶端都會透過其ClientId被識別,如果在此期間沒有其他玩家填補該槽,則會分配他們之前擁有的相同玩家索引給他們。簡而言之:重新連線時,玩家必須使用 相同的 ClientId

Quantum將不會讓客戶端開始遊戲階段的同時,有另一個擁有相同的ClientIdactive玩家也在房間內,並且等待中斷連線逾時(10秒):

DISCONNECTED: Error #5: Duplicate client id

這就是為什麼 ReconnectAndRejoin() 是必需的 ,以從短期連線遺失中復原。

進一步閱讀

重新開始Quantum遊戲階段

在一個中斷連線後,QuantumRunnerQuantumSession 再可用,並且必須被消除及重建。

當客戶端加入或重新加入回來運行Quantum遊戲的房間,QuantumRunner需要被重新啟動。模擬將被暫停,直到快照從另一個客戶端抵達。然後將追補及同步最新的遊戲時間。

概述:

  • 偵測中斷連線,消除Quantum執行器
  • 重新連線並且重新加入房間
  • 調用QuantumRunner.Start()來重新啟動Quantum

為了停止和消除Quantum遊戲階段,調用:

C#

QuantumRunner.ShutdownAll(true);

當您在Unity主要執行緒上時,只可以透過immediate:true調用這個方法,並且永不 從一個Quantum回調中調用。以immediate:false調用或手動延遲調用,直到它被一個Unity更新調用接取。

示範選單範例展示了如何啟動一個新遊戲,延遲加入或重新加入一個運行中的遊戲需要非常類似的流程。在UIRoom.OnShowScreen()中,我們偵測到,透過評估房間屬性,遊戲已經被啟動,並且之後立即啟動遊戲。

實體檢視及使用者介面

延遲加入及重新連線玩家對於您的遊戲建構的彈性有很高的需求。它需要支援從任何時間點來啟動遊戲,並且可能重新使用已具現化的預製件及使用者介面,同時在任何可能的時刻停止及清理遊戲。副作用是高載入時間、在新場景中有了不需要的VFX及動畫、卡在使用者介面轉換等等。

如果您希望保持EntityViewUpdaterEntityViews運作以重新使用它們,則需要手動停止它們被更新,重新配對它們到新的QuantumGame執行個體,訂閱到新的回調等等。

另一方面,處理Quantum的部分再簡單不過:關閉執行器,啟動執行器。

事件

客戶端將不會收到先前在玩家加入或重新加入前已引發的事件。遊戲檢視應該能夠透過輪詢目前的模擬狀態來完全具現化/重設其本身,並且使用未來事件/輪詢來保持本身的更新。

設定玩家資料

可選擇針對重新連線玩家來調用SetPlayerData()。它取決於您在模擬中的虛擬人偶設定邏輯是否需要這樣做。

StartParameters.QuitBehaviour

當執行Quantum關閉序列時(QuantumRunner.ShutdownAll),Quantum網路通信器類別將選擇性地執行房間離開操作,或中斷載入平衡客戶端的連線。在QuantumRunner.StartParameters上設定到QuitBehaviour.None,以讓您自行處理它。

延遲加入及好友快照

一個Quantum遊戲快照是一個獨立於平台的資料的二進位大型物件,其含有一個已驗證(已收到所有輸入)刷新後的完整的遊戲狀態。Quantum模擬可從一個快照來啟動,並且從該狀態上無縫繼續。

當模擬仍然在運行時,客戶端可以建立起自己的快照(本機快照),其他客戶端可以請求該快照(好友快照),或是可以從運行模擬的自訂伺服器外掛程式發送它。

從快照啟動或重新啟動是易於使用的,並且是Quantum提供的現成方法。否則延遲加入或重新連線客戶端必須從頭開始啟動遊戲階段並且快轉通過伺服器發送的輸入歷史,這可能會使客戶端在它被追補之前,應用程式無法使用,並且同時存儲在伺服器上的輸入歷史限制為最多10分鐘。

當任何客戶端啟動其QuantumRunner(不論客戶端啟動遊戲階段時是第一次啟動、延遲加入或重新連線),將自動啟動好友快照流程。遊戲階段將進入暫停模式DeterministicSession.IsPaused並且將請求一個快照。成功的延遲加入將記錄下列訊息:

Waiting for snapshot. Clock paused.
Detected Resync. Verified tick: 6541

首次啟動後5秒,客戶端連線時會請求好友快照。

伺服器使用載入平衡機制,來決定它將請求哪個客戶端提供好友快照,以避免單一客戶端負擔過重。

快照流程中的錯誤,將使用Disconnect訊息轉傳給客戶端(例如,快照等待狀態將在15秒後逾時):

在遊戲啟動常式時,當從快照啟動時有一些不同

  • 取代CallbackGameStarted,執行回調CallbackGameResynced
  • 在收到快照之前調用System.OnInit()

本機快照

作為一個選擇性的重新連線策略,可儲存一個最後已驗證刷新的本機快照,並且用於啟動新的QuantumRunner。當預期離線時間很少時,這個方法效用最大。本機快照一般對於頻寬更友善也更快。

指引原則

Quantum對本機快照接受時機實施嚴格限制,因為從太舊的快照啟動會破壞使用者體驗。

預設下,伺服器不接受比 10秒 更舊的本機快照,而是請求好友快照。這個流程透明地進行,而從客戶端的角度來看,唯一的區別是收到的快照的新舊時間。

對於使用者數較少的遊戲(例如1對1遊戲),沒有其他線上用客戶端可以提供好友快照的可能性很高。這些遊戲類型通常需要使用EmptyRoomTTL值,並且Quantum會將本機快照接受時間延長至**EmptyRoomTTL,但最長為兩分鐘**。

工作流程

  • 偵測中斷連線
  • 進行快照
  • 關閉Quantum執行器
  • 快速Photon重新連線
  • 以快照重新啟動Quantum

請詳讀示範選單中的重新連線序列。當中斷連線的原因不是客戶端自己中斷連線的話,UIGame.OnDisconnect建立快照。它使用10秒的逾時,在此之後將不使用快照,而從另一個客戶端/伺服器請求一個新的快照,因為追補時間將變得太長。

C#

_frameSnapshot = QuantumRunner.Default.Game.Frames.Verified.Serialize(DeterministicFrameSerializeMode.Blit);
_frameSnapshotNumber = QuantumRunner.Default.Game.Frames.Verified.Number;
_frameSnapshotTimeout = Time.time + 10.0f;

UIRoom.StartQuantumGame()中重新連線時,快照資訊設定為StartParameter

C#

var param = new QuantumRunner.StartParameters {
    FrameData    = IsRejoining ? UIGame.Instance?.FrameSnapshot : null,
    InitialFrame = IsRejoining ? (UIGame.Instance?.FrameSnapshotNumber).Value : 0,
    // ...
}

當成功時,Quantum將以已請求的刷新數來記錄這個情況:

Resetting to tick 4316
Detected Resync. Verified tick: 4316
Back to top