Online Session
概述
Quantum的線上服務是建立在Photon線上基礎架構(Photon Realtime)之上的。連接到線上遊戲階段通常會經歷三個連接階段:
- 自訂驗證: Photon不提供玩家帳戶,建議使用專有或第三方驗證提供商來保護登入,並設置Photon自訂驗證。
- 遊戲伺服器連接: 在開始線上模擬之前,客戶端必須連接到Photon Cloud並使用Photon Realtime API進入一個Photon房間。
- Quantum模擬啟動序列: 在此階段,Quantum模擬被啟動並同步,同時發送客戶端配置和玩家數據。
遊戲伺服器連接
這是最簡單的連接到Photon Cloud並匹配到遊戲伺服器的方法。
C#
var connectionArguments = new MatchmakingArguments {
// The Photon application settings include information about the app.
PhotonSettings = PhotonServerSettings.Global.AppSettings,
// The plugin to request from the Photon cloud set to the Quantum plugin.
PluginName = "QuantumPlugin"
// Setting an explicit room name will try to create or join the room based on how CanOnlyJoin is set. The RoomName can be null to create a unique name on create.
RoomName = "My Room Name",
// The maximum number of clients that can connect to the room, it most cases this is equal to the max number of players in the Quantum simulation.
MaxPlayers = Input.MAX_COUNT,
// Configure if the connect request can also create rooms or if it only tries to join
CanOnlyJoin = false,
// This sets the AuthValues and should be replaced with custom authentication and setting AuthValues explicitly
UserId = Guid.NewGuid().ToString(),
};
// This line connects to the Photon cloud and performs matchmaking based on the arguments to finally enter a room.
RealtimeClient Client = await MatchmakingExtensions.ConnectToRoomAsync(connectionArguments);
將ConnectToRoomAsync()
和ReconnectToRoomAsync()
程序封裝在Try Catch
中是一個好習慣。或者讓異常傳遞到其他任務中。
C#
var client = default(RealtimeClient);
try {
client = await MatchmakingExtensions.ConnectToRoomAsync(connectionArguments);
} catch (Exception e) {
// Something unexpected happened.
// In nearly all cases it's not worth to create detailed error handling. Log out the error, show generic feedback to the user and let him/her retry.
Debug.LogException(e);
}
在 ConnectToRoomAsync() 期間拋出的異常示例:
Failed to connect and join with error 'X'
- 連接到Photon Cloud失敗,錯誤MaxPlayer must be greater or equal than 0
MaxPlayer must be less than 256
PhotonSettings must be set
TaskCanceledException
-AsyncConfig.CancellationToken
上請求了取消- ...
ReconnectToRoomAsync() 期間拋出的異常示例:
AppVersion mismatch
-ReconnectInformation.AppVersion
不同於PhotonSettings.AppVersion
UserId not set
-ReconnectInformation.UserId
為null
或空UserId mismatch
-ReconnectInformation
和AuthValues
有不同UserId
ReconnectInformation timed out
-ReconnectInformation
已過期ReconnectInformation missing
-ReconnectInformation
為null
- ...
AppSettings
要連接到Photon Cloud,需要一個名為AppSettings
的配置。在Unity專案中,可以通過全局資源訪問它:PhotonServerSettings.Instance.AppSettings
。
始終複製設置對象,以避免在Unity編輯器中意外保存對PhotonServerSettings
資源的更改。
C#
var appSettings = new AppSettings(PhotonServerSettings.Global.AppSettings);
要設置Photon AppId,請按照以下說明操作:Quantum Asteroids 教學 - 專案設定
可選的匹配參數
MatchmakingArguments
可以通過以下可選參數進行增強。
詳細了解Photon Realtime匹配,請參匹配指引。
AsyncConfig | 包含TaskFactory 和全局取消支持的異步配置。如果為null ,則使用AsyncConfig.Global 。 |
NetworkClient | 提供一個Realtime客戶端對象。如果為null ,則在匹配過程中創建一個新的客戶端對象。 |
ReconnectInformation | 使用此參數以支持在失去NetworkClient 實例後重新連接。例如在應用程式重啟後。
QuantumReconnectInformation 將信息存儲在PlayerPrefs 中。請參閱Quantum演示菜單以獲取使用示例。
|
EmptyRoomTtlInSeconds | 空房間在最後一個客戶端離開後保持開放的時間(秒)。
內部設置 RoomOptions.EmptyRoomTtl 。 |
PlayerTtlInSeconds | 斷開連接的客戶端在伺服器上被標記為非活動狀態並支持快速重新加入的時間(秒)。
內部設置 RoomOptions.PlayerTtl 。 |
AuthValues | 為Photon伺服器連接提供驗證值。與自訂驗證一起使用。
當設置 UserId 時,此字段會被創建。 |
CustomProperties | 設置房間的初始或預期房間屬性。將用於匹配的屬性名稱列為CustomLobbyProperties 。
內部設置 RoomOptions.CustomRoomProperties 。 |
CustomLobbyProperties | 指定應對大廳中的客戶端可用的自訂房間屬性名稱。這將在匹配過程中分離客戶端,並僅匹配相同的CustomProperties 鍵值對。
內部設置 RoomOptions.CustomRoomPropertiesForLobby 。 |
Lobby | 用於匹配的大廳。類型會影響過濾器的應用方式。
內部設置 EnterRoomArgs.Lobby 和JoinRandomRoomArgs.Lobby 。 |
SqlLobbyFilter | 用於過濾房間匹配的SQL查詢。對於預設類型的大廳,請改用ExpectedCustomRoomProperties。
內部設置 JoinRandomRoomArgs.SqlLobbyFilter 。 |
Ticket | 自訂伺服器簽署的匹配票證。
內部設置 EnterRoomArgs.Ticket 和JoinRandomRoomArgs.Ticket 。 |
RandomMatchingType | MatchmakingMode 會影響房間的填充方式。
FillRoom - (預設)盡快填充房間(從最舊的開始)。SerialMatching -將玩家按順序分配到可用房間,但會考慮過濾器。如果沒有過濾器,房間會均勻分配玩家。RandomMatching - 加入一個(完全)隨機的房間。預期屬性必須匹配,除此之外,可能會選擇任何可用房間。
內部設置 JoinRandomRoomArgs.MatchingType 。 |
ExpectedUsers | 預期與此客戶端一起加入房間的用戶列表。為具有MaxPlayers 值的房間保留位置。
內部設置 EnterRoomArgs.ExpectedUser 及JoinRandomRoomArgs.ExpectedUsers 。 |
CustomRoomOptions | 完全替換將從其他參數組成的EnterRoomArgs.RoomOptions 。 |
IsRoomVisible | 如果不為null ,則為RoomOptions.IsVisible 的初始值。 |
IsRoomOpen | 如果不為null ,則為RoomOptions.IsOpen 的初始值。 |
EnableCrc | 開啟時,客戶端和伺服器將為每個發送的數據包添加CRC校驗和。校驗和使雙方能夠檢測並忽略在傳輸過程中損壞的數據包。損壞的數據包與丟失的數據包影響相同:需要重新發送,增加延遲並可能導致超時。構建校驗和的處理開銷較低,但能提高發送和接收數據的完整性。由於CRC校驗失敗而被丟棄的數據包會計入PhotonPeer.PacketLossByCrc 。 |
Quantum模擬啟動序列
以下代碼片段展示了啟動線上Quantum階段的基本操作。
C#
var sessionRunnerArguments = new SessionRunner.Arguments {
// The runner factory is the glue between the Quantum.Runner and Unity
RunnerFactory = QuantumRunnerUnityFactory.DefaultFactory,
// Creates a default version of `QuantumGameStartParameters`
GameParameters = QuantumRunnerUnityFactory.CreateGameParameters,
// A secret user id that is for example used to reserved player slots to reconnect into a running session
ClientId = Client.UserId,
// The player data
RuntimeConfig = runtimeConfig,
// The session config loaded from the Unity asset tagged as `QuantumDefaultGlobal`
SessionConfig = QuantumDeterministicSessionConfigAsset.DefaultConfig,
// GameMode has to be multiplayer for online sessions
GameMode = DeterministicGameMode.Multiplayer,
// The number of player that the session is running for, in this case we use the code-generated max possible players for the Quantum simulation
PlayerCount = Input.MAX_COUNT,
// A timeout to fail the connection logic and Quantum protocol
StartGameTimeoutInSeconds = 10,
// The communicator will take over the network handling after the simulation has started
Communicator = new QuantumNetworkCommunicator(Client),
};
// This method completes when the client has successfully joined the online session
QuantumRunner runner = (QuantumRunner)await SessionRunner.StartAsync(sessionRunnerArguments);
添加和移除玩家
Quantum有一個玩家的概念。每個客戶端可以有零個或多個玩家。最初啟動Quantum線上階段時,客戶端處於觀看者狀態,直到明確添加玩家。
每個連接到遊戲的玩家都會被分配一個唯一的ID。此ID稱為PlayerRef
,通常被稱為Player
。
與Quantum 2.1不同,玩家可以隨時添加和移除。
玩家將佔用所謂的PlayerSlots
,這將始終反映一個客戶端如何管理其玩家。如果僅使用一個本地玩家槽,則為槽0
。而由該客戶端控制的第二個玩家可能具有PlayerSlot
1。例如,輸入回調CallbackPollInput
使用PlayerSlot
屬性來控制為哪個本地玩家輪詢輸入:QuantumGame.AddPlayer(Int32 playerSlot, RuntimePlayer data)
。
由於AddPlayer()
可能會向客戶後端發起HTTP請求,因此該操作在伺服器上有速率限制,不能濫用。
RuntimePlayer
Quantum沒有內置的玩家對象或玩家化身的概念。
任何與玩家相關的遊戲信息(例如角色裝備、角色等級等)由每個客戶端通過RuntimePlayer
對象傳遞到模擬中。
C#
// Will add the player to player slot 0
QuantumRunner.Default.Game.AddPlayer(runtimePlayer);
要指定確切的玩家槽,請使用QuantumGame.AddPlayer(int playerSlot, RuntimePlayer data)
,如下例所示。
C#
// Will add the player to player slot 1
QuantumRunner.Default.Game.AddPlayer(1, runtimePlayer);
PlayerConnectedSystem
為了跟踪玩家與Quantum階段的連接狀態,使用了輸入與連接標誌。PlayerConnectedSystem
自動化該過程,並在玩家連接到階段或斷開連接時通知模擬。
為了接收連接和斷開回調,必須在系統中實現ISignalOnPlayerConnected
和ISignalOnPlayerDisconnected
。
有用的本地玩家回調
還有一些有用的回調來處理本地玩家: CallbackLocalPlayerAddConfirmed
, CallbackLocalPlayerRemoveConfirmed
, CallbackLocalPlayerAddFailed
及 CallbackLocalPlayerRemoveFailed
。
C#
QuantumCallback.Subscribe(this, (CallbackLocalPlayerAddConfirmed c) => OnLocalPlayerAddConfirmed(c));
QuantumCallback.Subscribe(this, (CallbackLocalPlayerRemoveConfirmed c) => OnLocalPlayerRemoveConfirmed(c));
QuantumCallback.Subscribe(this, (CallbackLocalPlayerAddFailed c) => OnLocalPlayerAddFailed(c));
QuantumCallback.Subscribe(this, (CallbackLocalPlayerRemoveFailed c) => OnLocalPlayerRemoveFailed(c));
停止階段與斷開連接
要停止Quantum模擬,請執行QuantumRunner.ShutdownAll(bool immediate)
。僅在 不 從Quantum回調中調用時設置immediate:true
。如果在Quantum回調中調用關閉命令,則必須設置immediate:false
,以便關閉延遲到下一次Unity更新。
ShutdownAll
將銷毀QuantumRunner對象,這會觸發本地Quantum模擬停止。它還會根據StartParameters.QuitBehaviour
的設置導致連接Disconnect()
或LeaveRoom()
。
如果客戶端應優雅退出遊戲,例如清理遠程客戶端的玩家化身,則必須在模擬中實現額外邏輯。可以是客戶端發出的命令或監控玩家連接狀態(參見PlayerConnectedSystem
)。
考慮到玩家也可能關閉應用程式或直接Alt+F4退出遊戲,並不總是有機會發送優雅的斷開連接。
C#
async void Disconnect() {
// Signal all runners to shutdown and wait until each one has disconnected
await QuantumRunner.ShutdownAllAsync();
// OR just signal their shutdown
QuantumRunner.ShutdownAll();
}
插件斷開連接錯誤
當Quantum插件在客戶端啟動協議或輸入消息中遇到錯誤時,它會發送一個操作以優雅地終止連接。當這種情況發生時,客戶端會調用CallbackPluginDisconnect
回調,其中包括帶有更多詳細信息的Reason
字符串。此類錯誤不可恢復,客戶端需要重新連接並重新啟動模擬。
錯誤 #3 | 必須在發送任何協議消息或輸入消息之前請求啟動,否則僅接受'StartRequest' | 客戶端嘗試在發送啟動請求之前發送協議或輸入消息。 |
錯誤 #5 | 重複的客戶端id | 客戶端嘗試使用已經使用的ClientId 啟動遊戲。 |
錯誤 #7 | 客戶端協議版本'2.2.0.0'與伺服器協議版本'3.0.0.0'不匹配 | 客戶端嘗試使用不相容的協議版本啟動遊戲。 |
錯誤 #8 | 無效的客戶端id 'NULL' | 客戶端嘗試未指定ClientId 的情況下啟動遊戲。 |
錯誤 #9 | 伺服器拒絕客戶端 | 自訂插件拒絕客戶端加入階段。 |
錯誤 #12 | 在觀看模式下不允許操作 | 客戶端嘗試在觀看者模式下(未添加玩家)發送命令。 |
錯誤 #13 | 快照請求啟動失敗 | 客戶端延遲加入遊戲,但沒有合適的已連接玩家提供快照以加入。 |
錯誤 #16 | 玩家數據損壞 | 客戶端在協議或輸入消息反序列化期間導致插件異常。可以通過在客戶端連接上啟用數據包CRC校驗來解決此錯誤:RealtimeClient.RealtimePeer.CrcEnabled = true 。 |
錯誤 #17 | PlayerCount無效 | 客戶端以無效的玩家數量啟動線上遊戲。 |
錯誤 #19 | 未找到玩家 | 客戶端為其不擁有的PlayerSlot 發送命令。 |
錯誤 #20 | RPC數據損壞 | 添加玩家時的RuntimePlayer 對象或命令數據過大(最大24 KB)。 |
錯誤 #21 | Quantum SDK 2不支援Quantum 3 AppIds,請檢查Photon儀表板以設置正確版本 | 使用Quantum SDK 2.1的客戶端嘗試連接Quantum 3 AppId。 |
錯誤 #22 | Tick違規, type=RPC, requested=694, current=93 | 伺服器檢測到客戶端輸入或命令泛洪伺服器並斷開其連接,這意味著它在很長一段時間內發送過多未來的輸入或命令。 |
錯誤 #30 | 創建遊戲失敗異常消息 |
客戶端在創建遊戲操作期間引發異常 |
錯誤 #31 | 創建遊戲失敗Webhook錯誤消息 |
CreateGame webhook失敗。 |
錯誤 #32 | J加入遊戲失敗Webhook錯誤消息 |
JoinGame webhook失敗。 |
錯誤 #33 | 玩家數據被拒絕Webhook錯誤消息 |
添加玩家webhook失敗。 |
錯誤 #34 | 遊戲配置未加載Webhook錯誤消息 |
遊戲配置webhook失敗,斷開所有客戶端連接。 |
錯誤 #40 | 接收協議消息時捕獲異常 | 客戶端處理協議消息時引發異常,這不一定是伺服器錯誤,但客戶端狀態不可恢復,將斷開連接。 |
錯誤 #41 | 輸入緩存已滿 | 客戶端的本地增量壓縮輸入緩衝區已滿,例如在長時間斷點暫停後可能發生。此狀態對客戶端不可恢復。 |
錯誤 #42 | 通訊器未連接 | 模擬運行時連接丟失。可以通過使用Photon Realtime回調提前檢測斷開連接來避免此情況。 |
錯誤 #51 | 快照下載超時 | 伺服器無法在預設的20秒超時時間內發送所有所需的快照片段。 |
錯誤 #52 | 快照上傳超時 | 請求的夥伴快照無法在預設的10秒超時時間內上傳。 |
錯誤 #53 | 快照上傳錯誤 | 上傳的夥伴快照包含錯誤。 |
錯誤 #54 | 快照上傳斷開連接 | 由於上傳夥伴快照的客戶端斷開連接,延遲加入被中斷。 |