This document is about: QUANTUM 2
SWITCH TO

Online Session

概述

Quantum線上服務被組建在一般Photon線上基礎結構(Photon Realtime)之上。連接到一個線上遊戲階段通常需要經過三個連接階段:

  1. 自訂驗證: Photon並不提供玩家帳號,並且建議使用專屬或第三方驗證提供商和設定來保護登入Photon自訂驗證
  2. 遊戲伺服器連結: 在開始線上模擬之前,客戶端必須要連接到Photon雲端,並且使用Photon Realtime程式庫來進入一個房間。 以下在來自SDK的DemoMenu中,以及在官方Photon Realtime文檔中說明這個過程,其包含初步的隨機配對過程Photon配對及大廳
  3. Quantum模擬開始序列: 在這個階段,開始Quantum模擬,發送客戶端配置資料,並且加入以及在客戶端之間同步Quantum遊戲階段。

如何開始一個Quantum線上遊戲階段

此圖表展示了典型的連接工作流程,以概述開始、重新開始及停止一個線上Quantum遊戲所需要的連接處理。

Starting Online Session: Connection Sequence
S開始線上遊戲階段:以Photon連接

進一步閱讀

示範選單

DemoMenu(包含在SDK中)展示了完整的過程。為了更好地了解如何進行,個別的使用者介面類別(UIConnectUIConnectingUIReconnectingUIRoomUIGame)應該被視為一個狀態機器。可以看見與上圖的相似之處。

  • 玩家按下一個按鍵,以連接到Photon雲端,並且使用隨機配對來最終加入一個Photon房間。
  • 在等待其他玩家之後,按下一個按鈕來表示遊戲開始,各個玩家將開始他們的Quantum遊戲階段。
  • 玩家可以按下取消連接,停止Unity編輯器或重新開始應用程式,之後使用重新連接按鍵,以回到相同的遊戲階段。
Demo Menu
示範選單流程圖表

使用者介面連接

有一些額外的功能可以讓示範選單成為一個容易上手的方便的開發工具,但也會使得程式碼更難讀取。舉例而言如RegionDropdownAppVersionDropdown

區域下拉式清單

這是一個可指令碼的資產(Photon/QuantumDemo/Menu/Resources/PhotonRegions.asset),其含有一組可透過下拉式清單選擇的區域,以在運行選單時快速更改區域。LastSelectedRegion被保存於PlayerPrefs之中。

應用程式版本下拉式清單

AppVersion(其在連接時在AppSettings上設定)是一個方法,以在執行配對時分離使用者。這可以用於使用同樣的應用程式帳號但也正在測試/開發的即時遊戲。執行方式涵蓋了兩種案例:

  • 開發者可以在他們自己的機器上運行應用程式好幾次,並且不想要任何其他人加入他們的遊戲。為了達到這個目的,建議使用Private AppVersion,其使用一個儲存在Photon/QuantumDemo/Menu/Resources/PhotonPrivateAppVersion.asset(從版本控制中排除)之中的Guid。只有在他們的機器上組建的組建可以一起遊玩。
  • 為了一個焦點測試或QA測試,玩家應該加入特定群組。列於Photon/QuantumDemo/Menu/Resources/PhotonAppVersions.asset之中的名稱將在選單的下拉式列表中成為可選。

應用程式設定

為了連接到Photon雲端,需要稱為AppSettings的組態。在Quantum整合中,這通常透過一個單一模式來存取: PhotonServerSettings.Instance.AppSettings,其當然可以和插入資料的另一種方法進行交換。

請注意,設定物件被複製。否則在儲存更改到資產時會有一個風險。

C#

var appSettings = PhotonServerSettings.CloneAppSettings(PhotonServerSettings.Instance.AppSettings);

Quantum載入平衡客戶端

連結類別QuantumLoadBalancingClient的一個instananceUIMain.Client中被儲存為一個靜態參照。使用者介面開發有很多不同的風格,這裡的單一以及狀態機器是最簡單的方法,並且應該挑戰開發者,去更改選單工作流程,成為他們建立使用者介面的流程方式。

QuantumLoadBalancingClient的存在是為了更方便地指派一個Nickname,並且快取BestRegionSummaryFromStorage(區域偵測結果)到PlayerPrefs。為了開始Quantum,只需要被繼承的類別是LoadBalancingClient

連接使用設定

示範選單並不使用任何驗證過程,取而代之的,將只是連接到Photon雲端,其將針對客戶端來生成一個使用者帳號。

ConnectUsingSettings()將使用所提及的由區域所強化的AppSettings,以及應用程式版本選取項目,以連接到Photon主伺服器。使用HideScreen()UIConnecting.ShowScreen()來發布狀態進展。

C#

if (UIMain.Client.ConnectUsingSettings(appSettings, Username.text)) {
    HideScreen();
    UIConnecting.ShowScreen();
}

在重新連結已點擊上

範例展示了三種重新連結的案例:

  • 連結物件(UIMain.Client)是有效的,並且PlayerTtlInSeconds已被設定

客戶端可能仍然被視為線上,在這種情況下,它可以嘗試使用UIMain.Client.ReconnectAndRejoin()進行「快速連結」。不需要在此檢查PlayerTtlInSeconds,重新連結必須在伺服器從房間移除剩餘客戶端之前的10秒逾時之內進行,並且不可能再進行快速重新連結。

ReconnectAndRejoin()將客戶端傳輸回他們的原始房間。

  • 連結物件(UIMain.Client)是有效的,但是客戶端已經離線超過10秒鐘(或PlayerTtlInSeconds

客戶端將重新連接到主伺服器UIMain.Client.ReconnectToMaster(),並且從那裡加入回到房間(在ReconnectInformation上儲存房間資訊)。

  • 連結物件遺失,大概是因為一個應用程式重新開始

重新連接的資料使用ReconnectInformation來儲存在Unity的PlayerPrefs之中。快取的相關資料是RoomNameRegionAppVersionUserId(如果自訂驗證以任何方式再次運行,則不是),以及最後的Timeout:當被儲存的資料不值得重新連接的時候。

UIMain.ClientAppSettings被重新組態,然後到主伺服器的連結被打開,並且執行一個重新加入或加入。當使用者帳號是相同時,才會進行重新連接。

C#

if (UIMain.Client == null && ReconnectInformation.Instance.IsValid) {
    UIMain.Client = new QuantumLoadBalancingClient(PhotonServerSettings.Instance.AppSettings.Protocol);
    UIMain.Client.UserId = ReconnectInformation.Instance.UserId;

    var appSettings = PhotonServerSettings.CloneAppSettings(PhotonServerSettings.Instance.AppSettings);
    appSettings.FixedRegion = ReconnectInformation.Instance.Region;
    appSettings.AppVersion = ReconnectInformation.Instance.AppVersion;

    if (UIMain.Client.ConnectUsingSettings(appSettings, LastUsername)) {
        HideScreen();
        UIReconnecting.ShowScreen();
    }
}
進一步閱讀

使用者介面連接

狀態將接聽Photon連結回調IConnectionCallbacksIMatchmakingCallbacks,以推進連結並且執行錯誤處理。

在已連接到主伺服器上

當成功連接到主伺服器,將立刻初始化隨機配對,並且建立一個OpJoinRandomRoomParams物件。在這個實例中,使用CustomRoomProperties來交涉地圖選擇,其可以在進入遊戲房間之後被更改。

  • RoomOptions.IsVisible意思是房間開放配對
  • RoomOptions.MaxPlayers一般而言反映了與Quantum玩家同樣的數量
  • RoomOptions.Plugins必須是new string[] { "QuantumPlugin" }
  • RoomOptions.PlayerTtl
  • RoomOptions.EmptyRoomTtl反映了Photon伺服器設定上的設定

C#

var joinRandomParams = new OpJoinRandomRoomParams();
_enterRoomParams = new EnterRoomParams();
_enterRoomParams.RoomOptions = new RoomOptions();
_enterRoomParams.RoomOptions.IsVisible  = true;
_enterRoomParams.RoomOptions.MaxPlayers = Input.MAX_COUNT;
_enterRoomParams.RoomOptions.Plugins    = new string[] { "QuantumPlugin" };
_enterRoomParams.RoomOptions.CustomRoomProperties = new Hashtable {
    { "HIDE-ROOM", false },
    { "MAP-GUID", defaultMapGuid },
};
_enterRoomParams.RoomOptions.PlayerTtl = PhotonServerSettings.Instance.PlayerTtlInSeconds * 1000;
_enterRoomParams.RoomOptions.EmptyRoomTtl = PhotonServerSettings.Instance.EmptyRoomTtlInSeconds * 1000;

if (!UIMain.Client.OpJoinRandomOrCreateRoom(joinRandomParams, _enterRoomParams)) {
    UIMain.Client.Disconnect();
}

OpJoinRandomOrCreateRoom()初始化了隨機配對及到遊戲伺服器的連結。

在加入隨機已失敗上

一個降低ErrorCode.NoRandomMatchFound的方法是建立一個新的房間。

在已加入房間上

當成功地加入一個房間後,狀態推進到UIRoom

其他錯誤回調報告及展示一個對話,其取消連接客戶端並且將玩家返回到主選單。

使用者介面重新連接

在已連接到主伺服器上

當運行ReconnectAndRejoin()時,將跳過這個,並且直接地調用OnJoinedRoom()

在其他重新連接的案例中,有兩種可能的路徑:

  • UIMain.Client.OpJoinRoom()
  • UIMain.Client.OpRejoinRoom()

不同之處在於,Rejoin需要客戶端在伺服器上仍然被認為是活躍的(基於10秒鐘逾時及額外的PlayerTTL)。兩者在OnJoinRoomFailed()中都有錯誤處理。

在已加入房間上

成功,以UIRoom狀態繼續。

在加入房間已失敗上()

有兩個非常常見的錯誤需要處理:

  • ErrorCode.JoinFailedFoundActiveJoiner: 嘗試join,但是在房間中客戶端仍然被標記為活躍中(伺服器不知道它取消連接)。處理方式:在10秒鐘結束之後重新嘗試。
  • ErrorCode.JoinFailedWithRejoinerNotFound: 嘗試rejoin,但是房間中客戶端沒有被標記為活躍中。處理方式:正常地加入。

使用者介面房間

除了配對及連結回調以外,使用者介面房間接聽IInRoomCallbacksIOnEventCallback

這是Quantum模擬之前的狀態,其中客戶端已經在Photon房間之中。範例使用房間屬性,以與一些遊戲組態通信,比如地圖選擇。只有主客戶端可以更改設定。

為了開始一個Quantum遊戲階段,通常需要一個RuntimeConfig,其包含針對各個遊戲的自訂設定。預設下,它可以在Menu.scene中被更改(選單 > 運行階段組態)。

開始遊戲

範例使用Photon通信工具OpRaiseEvent(UIMain.PhotonEventCode.StartGame),以通信遊戲的開始,其接著在OnEvent()中由所有客戶端分派。

C#

    public void OnEvent(EventData photonEvent) {
      switch (photonEvent.Code) {
        case (byte)UIMain.PhotonEventCode.StartGame:

針對在開始之後來的,或重新加入的客戶端,遊戲已經開始的資訊被儲存在房間屬性中:

C#

var ht = new ExitGames.Client.Photon.Hashtable {{"STARTED", true}};
UIMain.Client.CurrentRoom.SetCustomProperties(ht);

所有回到房間的客戶端,首先檢查遊戲是否已經開始。

C#

UIMain.Client.CurrentRoom.CustomProperties.TryGetValue("MAP-GUID", out mapGuidValue)
UIMain.Client.CurrentRoom.CustomProperties.TryGetValue("STARTED",  out var started))

StartQuantumGame()中完成開始或重新開始Quantum遊戲階段。

最初使用FromByteArray(ToByteArray())來複製運行階段組態,以避免意外地在來源上撰寫,並且一個地圖Guid被設定。

C#

var config = RuntimeConfigContainer != null ? RuntimeConfig.FromByteArray(RuntimeConfig.ToByteArray(RuntimeConfigContainer.Config)) : new RuntimeConfig();
config.Map.Id = mapGuid;

組態StartParameters。當作為一個觀察員加入時,有不同的設定,並且針對重新加入者,有一個可被發送的可選的本機快照(錄製在使用者遊戲中發生)。

C#

var param = new QuantumRunner.StartParameters {
RuntimeConfig             = config,
DeterministicConfig       = DeterministicSessionConfigAsset.Instance.Config,
ReplayProvider            = null,
GameMode                  = Spectate ? Photon.Deterministic.DeterministicGameMode.Spectating : Photon.Deterministic.DeterministicGameMode.Multiplayer,
FrameData                 = IsRejoining ? UIGame.Instance?.FrameSnapshot : null,
InitialFrame              = IsRejoining ? (UIGame.Instance?.FrameSnapshotNumber).Value : 0,
PlayerCount               = UIMain.Client.CurrentRoom.MaxPlayers,
LocalPlayerCount          = Spectate ? 0 : 1,
RecordingFlags            = RecordingFlags.None,
NetworkClient             = UIMain.Client,
StartGameTimeoutInSeconds = 10.0f
};

用來開始Quantum遊戲的clientId通常是Photon UserId。為了被指派到相同的Quantum玩家槽,重新連接玩家時必須保持相同。為了測試的目的,位於選單場景(Menu > UICanvas > Menu > IdProvider)的ClientIdProvider指令碼可被組態,以使用不同的來源。

C#

var clientId = ClientIdProvider.CreateClientId(IdProvider, UIMain.Client);
QuantumRunner.StartGame(clientId, param);

在調用QuantumRunner.StartGame()之後,自動執行Quantum開始序列。它也將觸發在SimulationConfig中組態的地圖場景載入。示範選單狀態轉換到UIGame

使用者介面遊戲

遊戲使用者介面處理:

  • 顯示及接聽一個取消連結按鍵
  • OnDisconnected()回調上錄製快照
  • 透過調用QuantumRunner.ShutdownAll(true),在取消連接的時候停止Quantum模擬

測試取消連接

OnLeaveClicked()之中,更改UIMain.Client.Disconnect()到其他,以在網路執行緒中模擬稍微更自然的取消連接或例外狀況。

C#

public void OnLeaveClicked() {
    UIMain.Client.Disconnect();
    // Debugging: use these instead of UIMain.Client.Disconnect()
    //UIMain.Client.SimulateConnectionLoss(true);
    //UIMain.Client.LoadBalancingPeer.StopThread();
}

Quantum開始序列

在調用QuantumRunner.StartGame()之後發生什麼?以下圖表視覺化通訊協定及回調的順序。

開始一個Quantum線上遊戲階段

客戶端加入伺服器遊戲階段,並且被選擇來上傳DeterministicConfigRuntimeConfig(可以透過運行企業Quantum伺服器,在伺服器上被授權覆寫)。伺服器使用它第一個收到的組態,並且推進到模擬開始,同時下游已接受的組態到所有客戶端。

在客戶端上,叫用GameStarted回調,之後在所有系統上OnInit()

客戶端選擇性地運行SetPlayerData(),以上傳他們的RuntimePlayer資料,其又由伺服器返回,從而為每個人產生OnPlayerDataSet信號。

Online Session: Start Sequence
線上遊戲階段:開始序列

重新連接到一個Quantum線上遊戲階段

在重新連接或延遲加入序列時,如果一個快照必須被發送到客戶端,則通訊協定更改。閱讀重新連接操作手冊,以取得更多關於快照時機的細節。

對於好友快照,另一個客戶端負責上傳一個最近的快照。同時,重新連接的客戶端收到成功開始的信號,並且OnInit()將針對系統來運行。當已經接收快照,執行GameResynced回調,並且輸入正在進來以追上最後的"second"。

如果需要的話,SetPlayerData()可以再次被叫用。

Online Session: Restart Sequence
O線上遊戲階段:重新開始序列

進一步閱讀

停止遊戲階段並且取消連接

為了本機地停止Quantum模擬,運行QuantumRunner.ShutdownAll(bool immediate)。當它 沒有 從一個Quantum回調中被調用時,只設定immediate:true。當設定到false,關機將延遲到下一次Unity更新。

ShutdownAll將消除Quantum執行器物件,其觸發本機Quantum模擬被停止。它也將導致一個連結Disconnect()LeaveRoom(),這取決於哪個被設定為StartParameters.QuitBehaviour

如果客戶端應該優雅地退出遊戲,舉例而言為遠端客戶端清理玩家虛擬人偶,則必須執行額外的邏輯到模擬中。一個客戶端發出的命令或監視玩家連接的狀態(請參見PlayerConnectedSystem)。

考慮到玩家也關閉他們的應用程式或Alt+F4,他們的遊戲可能不會總是有個機會來發送一個優雅的取消連接。

Back to top