From 9a1ca643590caab854af6d9fa6dcd26520efbbe1 Mon Sep 17 00:00:00 2001 From: Fabian Stoll <6150977+FabianStoll@users.noreply.github.com> Date: Tue, 3 Dec 2024 16:05:43 +0100 Subject: [PATCH] [MTT-8924] - Convert Boss Room from Lobby and Relay packages to Multiplayer Services SDK (#892) * refactorings to support Multiplayer SDK session creation & joining by session code * feat: upgrade MPS SDK to 1.0.0 * feat: first batch conversion from Lobbies API to Multiplayer Services SDK * feat: update exception handling * fix: reintroduce client and host starting logic via NetworkManager when connecting via IP * fix: don't add user to local session when leaving the session * fix: don't create a locked session * fix: create session logic * feat: rename lobby to session in char selection prefab * chore: batch renaming from lobby to session * fix: change rate limits * chore: remove obsolete comments * fix: prefab references * feat: upgrade project version to 6000.0.24f1 and auto-upgrade packages * feat: auto-upgrade project settings and package assets * feat: auto-upgrade assets * feat: upgrade project version to 6000.0.25f1 * feat: replace ParallelSync with Multiplayer Play Mode * fix: failing test * feat: update Netcode for GameObjects to version 2.0.0 * chore: update README * chore: changelog * chore: add MPPM to changelog * test: add yamato test for U6 * fix: only test Unity 6 * fix: update ubuntu version for yamato * fix: update iOS image * Added a release mode configuration for iOS jobs * Update CHANGELOG.md Co-authored-by: Fernando Cortez * fix: remove unneeded asset * fix: show IET popup on startup * fix: remove warnings about deprecated methods * feat: remove deprecated vscode package * fix: add services package again after merge * chore: changelog * chore: readme changes * fix: remove lobby and relay again They were accidentally added with the merge * fix: reset connection state when joining a session failed * chore: comment fix * chore: whitespace fixes * chore: another whitespace fix * fix: revert tabs in comments that were added by auto-cleanup * review: remove redundant async * review: fix docs link * review: no need to unblock UI here * review: remove unused fields * review: remove todo * review: remove unused method * review: specify MPS SDK version and PR number * review: update README.md Co-authored-by: Fernando Cortez * review: update changelog of package * fix: whitespaces * review: remove unneeded callback * review: change readme * review: remove log * review: split method for session joining * fix: newline at end of file --------- Co-authored-by: Fernando Cortez Co-authored-by: Frank Luong --- Assets/Prefabs/UI/MainMenu UI Canvas.prefab | 144 ++++- .../UI/{LobbyUI.prefab => SessionUI.prefab} | 172 +++--- ...byUI.prefab.meta => SessionUI.prefab.meta} | 0 Assets/Scenes/CharSelect.unity | 4 +- Assets/Scenes/MainMenu.unity | 4 +- .../ApplicationController.cs | 48 +- .../ConnectionManagement/ConnectionManager.cs | 8 +- .../ConnectionManagement/ConnectionMethod.cs | 98 +--- .../ConnectionState/ClientConnectedState.cs | 8 +- .../ConnectionState/ClientConnectingState.cs | 13 +- .../ClientReconnectingState.cs | 4 +- .../ConnectionState/ConnectionState.cs | 4 +- .../ConnectionState/HostingState.cs | 12 +- .../ConnectionState/OfflineState.cs | 16 +- .../ConnectionState/StartingHostState.cs | 20 +- ...Unity.BossRoom.ConnectionManagement.asmdef | 5 +- .../GameState/ClientCharSelectState.cs | 122 ++-- .../Gameplay/GameState/ClientMainMenuState.cs | 44 +- .../GameState/NetworkCharSelection.cs | 22 +- .../GameState/ServerCharSelectState.cs | 98 ++-- .../Gameplay/UI/Lobby/LobbyListItemUI.cs | 34 -- Assets/Scripts/Gameplay/UI/RoomNameBox.cs | 26 +- .../Gameplay/UI/{Lobby.meta => Session.meta} | 0 .../SessionCreationUI.cs} | 8 +- .../SessionCreationUI.cs.meta} | 0 .../SessionJoiningUI.cs} | 74 +-- .../SessionJoiningUI.cs.meta} | 0 .../Gameplay/UI/Session/SessionListItemUI.cs | 36 ++ .../SessionListItemUI.cs.meta} | 0 .../SessionUIMediator.cs} | 169 +++--- .../SessionUIMediator.cs.meta} | 0 .../Gameplay/UI/UICharSelectPlayerSeat.cs | 2 +- .../Gameplay/UI/UnityServicesUIHandler.cs | 43 +- .../Gameplay/Unity.BossRoom.Gameplay.asmdef | 4 +- .../Messages/UnityServiceErrorMessage.cs | 2 +- .../Lobbies/LobbyAPIInterface.cs | 138 ----- .../Lobbies/LobbyServiceFacade.cs | 550 ------------------ .../UnityServices/Lobbies/LocalLobby.cs | 274 --------- .../Messages/LobbyListFetchedMessage.cs | 14 - .../{Lobbies.meta => Sessions.meta} | 0 .../UnityServices/Sessions/LocalSession.cs | 221 +++++++ .../LocalSession.cs.meta} | 0 .../LocalSessionUser.cs} | 254 ++++---- .../LocalSessionUser.cs.meta} | 0 .../{Lobbies => Sessions}/Messages.meta | 0 .../Messages/SessionListFetchedMessage.cs | 15 + .../SessionListFetchedMessage.cs.meta} | 0 .../Sessions/MultiplayerServicesFacade.cs | 467 +++++++++++++++ .../MultiplayerServicesFacade.cs.meta} | 0 .../Sessions/MultiplayerServicesInterface.cs | 106 ++++ .../MultiplayerServicesInterface.cs.meta} | 0 .../Unity.BossRoom.UnityServices.asmdef | 5 +- .../Runtime/ConnectionManagementTests.cs | 10 +- CHANGELOG.md | 1 + .../CHANGELOG.md | 6 + .../Utilities/Net/UnityRelayUtilities.cs | 82 --- .../Utilities/Net/UnityRelayUtilities.cs.meta | 3 - .../package.json | 3 +- Packages/manifest.json | 3 +- Packages/packages-lock.json | 58 +- README.md | 18 +- 61 files changed, 1644 insertions(+), 1828 deletions(-) rename Assets/Prefabs/UI/{LobbyUI.prefab => SessionUI.prefab} (98%) rename Assets/Prefabs/UI/{LobbyUI.prefab.meta => SessionUI.prefab.meta} (100%) delete mode 100644 Assets/Scripts/Gameplay/UI/Lobby/LobbyListItemUI.cs rename Assets/Scripts/Gameplay/UI/{Lobby.meta => Session.meta} (100%) rename Assets/Scripts/Gameplay/UI/{Lobby/LobbyCreationUI.cs => Session/SessionCreationUI.cs} (74%) rename Assets/Scripts/Gameplay/UI/{Lobby/LobbyCreationUI.cs.meta => Session/SessionCreationUI.cs.meta} (100%) rename Assets/Scripts/Gameplay/UI/{Lobby/LobbyJoiningUI.cs => Session/SessionJoiningUI.cs} (53%) rename Assets/Scripts/Gameplay/UI/{Lobby/LobbyJoiningUI.cs.meta => Session/SessionJoiningUI.cs.meta} (100%) create mode 100644 Assets/Scripts/Gameplay/UI/Session/SessionListItemUI.cs rename Assets/Scripts/Gameplay/UI/{Lobby/LobbyListItemUI.cs.meta => Session/SessionListItemUI.cs.meta} (100%) rename Assets/Scripts/Gameplay/UI/{Lobby/LobbyUIMediator.cs => Session/SessionUIMediator.cs} (50%) rename Assets/Scripts/Gameplay/UI/{Lobby/LobbyUIMediator.cs.meta => Session/SessionUIMediator.cs.meta} (100%) delete mode 100644 Assets/Scripts/UnityServices/Lobbies/LobbyAPIInterface.cs delete mode 100644 Assets/Scripts/UnityServices/Lobbies/LobbyServiceFacade.cs delete mode 100644 Assets/Scripts/UnityServices/Lobbies/LocalLobby.cs delete mode 100644 Assets/Scripts/UnityServices/Lobbies/Messages/LobbyListFetchedMessage.cs rename Assets/Scripts/UnityServices/{Lobbies.meta => Sessions.meta} (100%) create mode 100644 Assets/Scripts/UnityServices/Sessions/LocalSession.cs rename Assets/Scripts/UnityServices/{Lobbies/LocalLobby.cs.meta => Sessions/LocalSession.cs.meta} (100%) rename Assets/Scripts/UnityServices/{Lobbies/LocalLobbyUser.cs => Sessions/LocalSessionUser.cs} (74%) rename Assets/Scripts/UnityServices/{Lobbies/LocalLobbyUser.cs.meta => Sessions/LocalSessionUser.cs.meta} (100%) rename Assets/Scripts/UnityServices/{Lobbies => Sessions}/Messages.meta (100%) create mode 100644 Assets/Scripts/UnityServices/Sessions/Messages/SessionListFetchedMessage.cs rename Assets/Scripts/UnityServices/{Lobbies/Messages/LobbyListFetchedMessage.cs.meta => Sessions/Messages/SessionListFetchedMessage.cs.meta} (100%) create mode 100644 Assets/Scripts/UnityServices/Sessions/MultiplayerServicesFacade.cs rename Assets/Scripts/UnityServices/{Lobbies/LobbyServiceFacade.cs.meta => Sessions/MultiplayerServicesFacade.cs.meta} (100%) create mode 100644 Assets/Scripts/UnityServices/Sessions/MultiplayerServicesInterface.cs rename Assets/Scripts/UnityServices/{Lobbies/LobbyAPIInterface.cs.meta => Sessions/MultiplayerServicesInterface.cs.meta} (100%) delete mode 100644 Packages/com.unity.multiplayer.samples.coop/Utilities/Net/UnityRelayUtilities.cs delete mode 100644 Packages/com.unity.multiplayer.samples.coop/Utilities/Net/UnityRelayUtilities.cs.meta diff --git a/Assets/Prefabs/UI/MainMenu UI Canvas.prefab b/Assets/Prefabs/UI/MainMenu UI Canvas.prefab index fc24b1b5a..76ffd5a41 100644 --- a/Assets/Prefabs/UI/MainMenu UI Canvas.prefab +++ b/Assets/Prefabs/UI/MainMenu UI Canvas.prefab @@ -359,15 +359,17 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_enableWordWrapping: 1 + m_TextWrappingMode: 1 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 + m_ActiveFontFeatures: 00000000 m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 + m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -480,6 +482,10 @@ PrefabInstance: propertyPath: m_fontSizeMax value: 58 objectReference: {fileID: 0} + - target: {fileID: 7721113380232533813, guid: addf3685293c35d48a673397c748f116, type: 3} + propertyPath: 'm_ActiveFontFeatures.Array.data[0]' + value: 1801810542 + objectReference: {fileID: 0} - target: {fileID: 7721113380319664578, guid: addf3685293c35d48a673397c748f116, type: 3} propertyPath: m_Name value: IP Start Button @@ -736,6 +742,18 @@ PrefabInstance: serializedVersion: 3 m_TransformParent: {fileID: 6068325059450104507} m_Modifications: + - target: {fileID: 301174889687357229, guid: 1bc4508935e434eb4867c367b55cca50, type: 3} + propertyPath: 'm_ActiveFontFeatures.Array.data[0]' + value: 1801810542 + objectReference: {fileID: 0} + - target: {fileID: 709593810350336946, guid: 1bc4508935e434eb4867c367b55cca50, type: 3} + propertyPath: 'm_ActiveFontFeatures.Array.data[0]' + value: 1801810542 + objectReference: {fileID: 0} + - target: {fileID: 785373375347833033, guid: 1bc4508935e434eb4867c367b55cca50, type: 3} + propertyPath: 'm_ActiveFontFeatures.Array.data[0]' + value: 1801810542 + objectReference: {fileID: 0} - target: {fileID: 792957857740898001, guid: 1bc4508935e434eb4867c367b55cca50, type: 3} propertyPath: m_AnchorMax.y value: 0 @@ -772,6 +790,14 @@ PrefabInstance: propertyPath: m_AnchoredPosition.y value: 0 objectReference: {fileID: 0} + - target: {fileID: 1131054124500818674, guid: 1bc4508935e434eb4867c367b55cca50, type: 3} + propertyPath: 'm_ActiveFontFeatures.Array.data[0]' + value: 1801810542 + objectReference: {fileID: 0} + - target: {fileID: 1583053172819472216, guid: 1bc4508935e434eb4867c367b55cca50, type: 3} + propertyPath: 'm_ActiveFontFeatures.Array.data[0]' + value: 1801810542 + objectReference: {fileID: 0} - target: {fileID: 2234904744820987572, guid: 1bc4508935e434eb4867c367b55cca50, type: 3} propertyPath: m_AnchorMax.x value: 0 @@ -812,6 +838,14 @@ PrefabInstance: propertyPath: m_AnchoredPosition.y value: 0 objectReference: {fileID: 0} + - target: {fileID: 3422802895906220296, guid: 1bc4508935e434eb4867c367b55cca50, type: 3} + propertyPath: 'm_ActiveFontFeatures.Array.data[0]' + value: 1801810542 + objectReference: {fileID: 0} + - target: {fileID: 3523563153346996873, guid: 1bc4508935e434eb4867c367b55cca50, type: 3} + propertyPath: 'm_ActiveFontFeatures.Array.data[0]' + value: 1801810542 + objectReference: {fileID: 0} - target: {fileID: 3632019498769524828, guid: 1bc4508935e434eb4867c367b55cca50, type: 3} propertyPath: m_AnchorMax.y value: 0 @@ -852,6 +886,18 @@ PrefabInstance: propertyPath: m_AnchoredPosition.y value: 0 objectReference: {fileID: 0} + - target: {fileID: 4777870063691261607, guid: 1bc4508935e434eb4867c367b55cca50, type: 3} + propertyPath: 'm_ActiveFontFeatures.Array.data[0]' + value: 1801810542 + objectReference: {fileID: 0} + - target: {fileID: 4805371756271124143, guid: 1bc4508935e434eb4867c367b55cca50, type: 3} + propertyPath: 'm_ActiveFontFeatures.Array.data[0]' + value: 1801810542 + objectReference: {fileID: 0} + - target: {fileID: 5031063074198282838, guid: 1bc4508935e434eb4867c367b55cca50, type: 3} + propertyPath: 'm_ActiveFontFeatures.Array.data[0]' + value: 1801810542 + objectReference: {fileID: 0} - target: {fileID: 5843186486647850782, guid: 1bc4508935e434eb4867c367b55cca50, type: 3} propertyPath: m_AnchorMax.y value: 0 @@ -868,6 +914,10 @@ PrefabInstance: propertyPath: m_AnchoredPosition.y value: 0 objectReference: {fileID: 0} + - target: {fileID: 6243726003260939195, guid: 1bc4508935e434eb4867c367b55cca50, type: 3} + propertyPath: 'm_ActiveFontFeatures.Array.data[0]' + value: 1801810542 + objectReference: {fileID: 0} - target: {fileID: 6403041760458951094, guid: 1bc4508935e434eb4867c367b55cca50, type: 3} propertyPath: m_AnchorMax.y value: 0 @@ -886,7 +936,7 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 6702871171647363808, guid: 1bc4508935e434eb4867c367b55cca50, type: 3} propertyPath: m_Name - value: LobbyPopup + value: SessionPopup objectReference: {fileID: 0} - target: {fileID: 6702871171647363811, guid: 1bc4508935e434eb4867c367b55cca50, type: 3} propertyPath: m_Pivot.x @@ -992,6 +1042,10 @@ PrefabInstance: propertyPath: m_AnchoredPosition.y value: 0 objectReference: {fileID: 0} + - target: {fileID: 7486709167611836872, guid: 1bc4508935e434eb4867c367b55cca50, type: 3} + propertyPath: 'm_ActiveFontFeatures.Array.data[0]' + value: 1801810542 + objectReference: {fileID: 0} - target: {fileID: 7579639325911904033, guid: 1bc4508935e434eb4867c367b55cca50, type: 3} propertyPath: m_AnchorMax.y value: 0 @@ -1012,6 +1066,10 @@ PrefabInstance: propertyPath: m_AnchoredPosition.y value: 0 objectReference: {fileID: 0} + - target: {fileID: 7676773602323508701, guid: 1bc4508935e434eb4867c367b55cca50, type: 3} + propertyPath: 'm_ActiveFontFeatures.Array.data[0]' + value: 1801810542 + objectReference: {fileID: 0} - target: {fileID: 7878795380521772600, guid: 1bc4508935e434eb4867c367b55cca50, type: 3} propertyPath: m_AnchorMax.y value: 0 @@ -1028,6 +1086,10 @@ PrefabInstance: propertyPath: m_AnchoredPosition.y value: 0 objectReference: {fileID: 0} + - target: {fileID: 8349060408152716834, guid: 1bc4508935e434eb4867c367b55cca50, type: 3} + propertyPath: 'm_ActiveFontFeatures.Array.data[0]' + value: 1801810542 + objectReference: {fileID: 0} m_RemovedComponents: [] m_RemovedGameObjects: [] m_AddedGameObjects: [] @@ -1058,9 +1120,13 @@ PrefabInstance: propertyPath: m_fontSizeMax value: 58 objectReference: {fileID: 0} + - target: {fileID: 7721113380232533813, guid: addf3685293c35d48a673397c748f116, type: 3} + propertyPath: 'm_ActiveFontFeatures.Array.data[0]' + value: 1801810542 + objectReference: {fileID: 0} - target: {fileID: 7721113380319664578, guid: addf3685293c35d48a673397c748f116, type: 3} propertyPath: m_Name - value: Lobby Start Button + value: Session Start Button objectReference: {fileID: 0} - target: {fileID: 7721113380319664578, guid: addf3685293c35d48a673397c748f116, type: 3} propertyPath: m_IsActive @@ -1222,6 +1288,10 @@ PrefabInstance: serializedVersion: 3 m_TransformParent: {fileID: 6068325059450104507} m_Modifications: + - target: {fileID: 635758218034301578, guid: 0c512555bac5ad3428012496621d5f4c, type: 3} + propertyPath: 'm_ActiveFontFeatures.Array.data[0]' + value: 1801810542 + objectReference: {fileID: 0} - target: {fileID: 2425020540045722527, guid: 0c512555bac5ad3428012496621d5f4c, type: 3} propertyPath: m_IPHostingUI value: @@ -1250,6 +1320,10 @@ PrefabInstance: propertyPath: m_JoinTabButtonTabBlockerTinter value: objectReference: {fileID: 0} + - target: {fileID: 2632516940462403808, guid: 0c512555bac5ad3428012496621d5f4c, type: 3} + propertyPath: 'm_ActiveFontFeatures.Array.data[0]' + value: 1801810542 + objectReference: {fileID: 0} - target: {fileID: 2837639234489633647, guid: 0c512555bac5ad3428012496621d5f4c, type: 3} propertyPath: m_AnchorMax.y value: 0 @@ -1406,6 +1480,14 @@ PrefabInstance: propertyPath: m_AnchoredPosition.y value: 0 objectReference: {fileID: 0} + - target: {fileID: 6221418847513183700, guid: 0c512555bac5ad3428012496621d5f4c, type: 3} + propertyPath: 'm_ActiveFontFeatures.Array.data[0]' + value: 1801810542 + objectReference: {fileID: 0} + - target: {fileID: 8477078941156091232, guid: 0c512555bac5ad3428012496621d5f4c, type: 3} + propertyPath: 'm_ActiveFontFeatures.Array.data[0]' + value: 1801810542 + objectReference: {fileID: 0} - target: {fileID: 8636502446461490653, guid: 0c512555bac5ad3428012496621d5f4c, type: 3} propertyPath: m_AnchorMax.x value: 0 @@ -1436,6 +1518,10 @@ PrefabInstance: serializedVersion: 3 m_TransformParent: {fileID: 6068325059450104507} m_Modifications: + - target: {fileID: 142567138735162684, guid: 4c4e3a02e746c204bb859d2a53a865e3, type: 3} + propertyPath: 'm_ActiveFontFeatures.Array.data[0]' + value: 1801810542 + objectReference: {fileID: 0} - target: {fileID: 305241932145850641, guid: 4c4e3a02e746c204bb859d2a53a865e3, type: 3} propertyPath: m_AnchorMax.y value: 0 @@ -1456,14 +1542,46 @@ PrefabInstance: propertyPath: m_AnchoredPosition.y value: 0 objectReference: {fileID: 0} + - target: {fileID: 420772079678045107, guid: 4c4e3a02e746c204bb859d2a53a865e3, type: 3} + propertyPath: 'm_ActiveFontFeatures.Array.data[0]' + value: 1801810542 + objectReference: {fileID: 0} - target: {fileID: 496999993872493682, guid: 4c4e3a02e746c204bb859d2a53a865e3, type: 3} propertyPath: m_fontSize value: 50 objectReference: {fileID: 0} + - target: {fileID: 496999993872493682, guid: 4c4e3a02e746c204bb859d2a53a865e3, type: 3} + propertyPath: 'm_ActiveFontFeatures.Array.data[0]' + value: 1801810542 + objectReference: {fileID: 0} + - target: {fileID: 1198809863901728126, guid: 4c4e3a02e746c204bb859d2a53a865e3, type: 3} + propertyPath: 'm_ActiveFontFeatures.Array.data[0]' + value: 1801810542 + objectReference: {fileID: 0} - target: {fileID: 1724952364805774005, guid: 4c4e3a02e746c204bb859d2a53a865e3, type: 3} propertyPath: m_fontSize value: 33 objectReference: {fileID: 0} + - target: {fileID: 1724952364805774005, guid: 4c4e3a02e746c204bb859d2a53a865e3, type: 3} + propertyPath: 'm_ActiveFontFeatures.Array.data[0]' + value: 1801810542 + objectReference: {fileID: 0} + - target: {fileID: 1887385345636018689, guid: 4c4e3a02e746c204bb859d2a53a865e3, type: 3} + propertyPath: 'm_ActiveFontFeatures.Array.data[0]' + value: 1801810542 + objectReference: {fileID: 0} + - target: {fileID: 1958720994042495195, guid: 4c4e3a02e746c204bb859d2a53a865e3, type: 3} + propertyPath: 'm_ActiveFontFeatures.Array.data[0]' + value: 1801810542 + objectReference: {fileID: 0} + - target: {fileID: 2267455651107791764, guid: 4c4e3a02e746c204bb859d2a53a865e3, type: 3} + propertyPath: 'm_ActiveFontFeatures.Array.data[0]' + value: 1801810542 + objectReference: {fileID: 0} + - target: {fileID: 3449200610800142136, guid: 4c4e3a02e746c204bb859d2a53a865e3, type: 3} + propertyPath: 'm_ActiveFontFeatures.Array.data[0]' + value: 1801810542 + objectReference: {fileID: 0} - target: {fileID: 4453893802180558433, guid: 4c4e3a02e746c204bb859d2a53a865e3, type: 3} propertyPath: m_AnchoredPosition.y value: 58 @@ -1472,6 +1590,10 @@ PrefabInstance: propertyPath: m_fontSize value: 33 objectReference: {fileID: 0} + - target: {fileID: 5306707511080244411, guid: 4c4e3a02e746c204bb859d2a53a865e3, type: 3} + propertyPath: 'm_ActiveFontFeatures.Array.data[0]' + value: 1801810542 + objectReference: {fileID: 0} - target: {fileID: 5924530127146065184, guid: 4c4e3a02e746c204bb859d2a53a865e3, type: 3} propertyPath: m_Name value: IPPopup @@ -1560,10 +1682,18 @@ PrefabInstance: propertyPath: m_LocalEulerAnglesHint.z value: 0 objectReference: {fileID: 0} + - target: {fileID: 6456862980627209339, guid: 4c4e3a02e746c204bb859d2a53a865e3, type: 3} + propertyPath: 'm_ActiveFontFeatures.Array.data[0]' + value: 1801810542 + objectReference: {fileID: 0} - target: {fileID: 7328528642576607773, guid: 4c4e3a02e746c204bb859d2a53a865e3, type: 3} propertyPath: m_fontSize value: 50 objectReference: {fileID: 0} + - target: {fileID: 7328528642576607773, guid: 4c4e3a02e746c204bb859d2a53a865e3, type: 3} + propertyPath: 'm_ActiveFontFeatures.Array.data[0]' + value: 1801810542 + objectReference: {fileID: 0} - target: {fileID: 7353534715922753761, guid: 4c4e3a02e746c204bb859d2a53a865e3, type: 3} propertyPath: m_AnchorMax.y value: 0 @@ -1604,6 +1734,10 @@ PrefabInstance: propertyPath: m_AnchoredPosition.y value: 0 objectReference: {fileID: 0} + - target: {fileID: 8122071153592056310, guid: 4c4e3a02e746c204bb859d2a53a865e3, type: 3} + propertyPath: 'm_ActiveFontFeatures.Array.data[0]' + value: 1801810542 + objectReference: {fileID: 0} m_RemovedComponents: [] m_RemovedGameObjects: [] m_AddedGameObjects: [] @@ -1634,6 +1768,10 @@ PrefabInstance: propertyPath: m_fontSizeMax value: 58 objectReference: {fileID: 0} + - target: {fileID: 7721113380232533813, guid: addf3685293c35d48a673397c748f116, type: 3} + propertyPath: 'm_ActiveFontFeatures.Array.data[0]' + value: 1801810542 + objectReference: {fileID: 0} - target: {fileID: 7721113380319664578, guid: addf3685293c35d48a673397c748f116, type: 3} propertyPath: m_Name value: Profile Button diff --git a/Assets/Prefabs/UI/LobbyUI.prefab b/Assets/Prefabs/UI/SessionUI.prefab similarity index 98% rename from Assets/Prefabs/UI/LobbyUI.prefab rename to Assets/Prefabs/UI/SessionUI.prefab index 8f465cab9..8574296e7 100644 --- a/Assets/Prefabs/UI/LobbyUI.prefab +++ b/Assets/Prefabs/UI/SessionUI.prefab @@ -35,7 +35,6 @@ RectTransform: - {fileID: 2975638553292857375} - {fileID: 860301207315940462} m_Father: {fileID: 2670926649685416499} - m_RootOrder: 3 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 1, y: 0} @@ -100,7 +99,6 @@ RectTransform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 282255004005152861} - m_RootOrder: 1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 180} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 1, y: 1} @@ -191,7 +189,6 @@ RectTransform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 6702871171647363811} - m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 1, y: 0} @@ -249,7 +246,7 @@ GameObject: - component: {fileID: 8582247561407215177} - component: {fileID: 4897371851934052143} m_Layer: 5 - m_Name: Lobby Name Input Field + m_Name: Session Name Input Field m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 @@ -270,7 +267,6 @@ RectTransform: - {fileID: 829917324121296096} - {fileID: 720719179126197865} m_Father: {fileID: 2963858370021784928} - m_RootOrder: 3 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.5, y: 0.5} m_AnchorMax: {x: 0.5, y: 0.5} @@ -428,7 +424,6 @@ RectTransform: m_Children: - {fileID: 192539373152864728} m_Father: {fileID: 7760409132803330506} - m_RootOrder: 4 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 0, y: 0} @@ -541,7 +536,7 @@ GameObject: - component: {fileID: 5370165130166260100} - component: {fileID: 2349919044805767479} m_Layer: 5 - m_Name: LobbyCreationUI + m_Name: SessionCreationUI m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 @@ -565,7 +560,6 @@ RectTransform: - {fileID: 3851624040064246431} - {fileID: 4250182236641786634} m_Father: {fileID: 244032492905947229} - m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 1, y: 1} @@ -584,7 +578,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: a2f076764a76c434dbd08324243a9f2c, type: 3} m_Name: m_EditorClassIdentifier: - m_LobbyNameInputField: {fileID: 4897371851934052143} + m_SessionNameInputField: {fileID: 4897371851934052143} m_LoadingIndicatorObject: {fileID: 6560854408492732499} m_IsPrivate: {fileID: 8780206513702589119} m_CanvasGroup: {fileID: 2349919044805767479} @@ -631,7 +625,6 @@ RectTransform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 3521129445966426109} - m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 0, y: 0} @@ -709,15 +702,17 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_enableWordWrapping: 1 + m_TextWrappingMode: 1 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 + m_ActiveFontFeatures: 6e72656b m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 + m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -766,7 +761,6 @@ RectTransform: - {fileID: 2963858370021784928} - {fileID: 2670926649685416499} m_Father: {fileID: 6702871171647363811} - m_RootOrder: 4 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 1, y: 1} @@ -804,7 +798,6 @@ RectTransform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 3851624040064246431} - m_RootOrder: 1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 1, y: 1} @@ -887,7 +880,6 @@ RectTransform: - {fileID: 4703333743537879339} - {fileID: 5883034356418507601} m_Father: {fileID: 7760409132803330506} - m_RootOrder: 3 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 0, y: 0} @@ -1048,7 +1040,6 @@ RectTransform: - {fileID: 8655946376249523884} - {fileID: 4128780992227299448} m_Father: {fileID: 7721874466928087582} - m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 1} m_AnchorMax: {x: 0, y: 1} @@ -1139,7 +1130,7 @@ MonoBehaviour: m_Calls: - m_Target: {fileID: 1722388064424237406} m_TargetAssemblyTypeName: BossRoom.Scripts.Client.UI.LobbyUIMediator, Unity.Multiplayer.Samples.BossRoom.Client - m_MethodName: ToggleJoinLobbyUI + m_MethodName: ToggleJoinSessionUI m_Mode: 1 m_Arguments: m_ObjectArgument: {fileID: 0} @@ -1180,7 +1171,6 @@ RectTransform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 282255004005152861} - m_RootOrder: 2 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 1, y: 1} @@ -1215,7 +1205,7 @@ MonoBehaviour: m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_text: 'Create Lobby + m_text: 'Create Session ' m_isRightToLeft: 0 @@ -1260,15 +1250,17 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_enableWordWrapping: 1 + m_TextWrappingMode: 1 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 + m_ActiveFontFeatures: 6e72656b m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 + m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -1317,7 +1309,6 @@ RectTransform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 4996778416574021528} - m_RootOrder: 2 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 1, y: 1} @@ -1352,7 +1343,7 @@ MonoBehaviour: m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_text: Lobby List + m_text: Session List m_isRightToLeft: 0 m_fontAsset: {fileID: 11400000, guid: 1a8c97d4cbe5134499b26527f8609c7e, type: 2} m_sharedMaterial: {fileID: -466885322316925189, guid: 1a8c97d4cbe5134499b26527f8609c7e, type: 2} @@ -1395,15 +1386,17 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_enableWordWrapping: 1 + m_TextWrappingMode: 1 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 + m_ActiveFontFeatures: 6e72656b m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 + m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -1453,7 +1446,6 @@ RectTransform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 4996778416574021528} - m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 1, y: 1} @@ -1544,7 +1536,6 @@ RectTransform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 2975638553292857375} - m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 1, y: 1} @@ -1592,7 +1583,7 @@ MonoBehaviour: m_HorizontalOverflow: 0 m_VerticalOverflow: 0 m_LineSpacing: 1 - m_Text: Enter lobby code... + m_Text: Enter join code... --- !u!1 &3284084329833472941 GameObject: m_ObjectHideFlags: 0 @@ -1626,7 +1617,6 @@ RectTransform: - {fileID: 4996778416574021528} - {fileID: 282255004005152861} m_Father: {fileID: 6702871171647363811} - m_RootOrder: 3 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 1} m_AnchorMax: {x: 1, y: 1} @@ -1707,7 +1697,6 @@ RectTransform: - {fileID: 4078412745237413509} - {fileID: 2417806726195885171} m_Father: {fileID: 7721874466928087582} - m_RootOrder: 1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 1} m_AnchorMax: {x: 0, y: 1} @@ -1798,7 +1787,7 @@ MonoBehaviour: m_Calls: - m_Target: {fileID: 1722388064424237406} m_TargetAssemblyTypeName: BossRoom.Scripts.Client.UI.LobbyUIMediator, Unity.Multiplayer.Samples.BossRoom.Client - m_MethodName: ToggleCreateLobbyUI + m_MethodName: ToggleCreateSessionUI m_Mode: 1 m_Arguments: m_ObjectArgument: {fileID: 0} @@ -1839,7 +1828,6 @@ RectTransform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 860301207315940462} - m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 1, y: 1} @@ -1917,15 +1905,17 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_enableWordWrapping: 1 + m_TextWrappingMode: 1 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 + m_ActiveFontFeatures: 6e72656b m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 + m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -1974,7 +1964,6 @@ RectTransform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 6263258808166174538} - m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 1, y: 1} @@ -2052,15 +2041,17 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_enableWordWrapping: 1 + m_TextWrappingMode: 1 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 + m_ActiveFontFeatures: 6e72656b m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 + m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -2109,7 +2100,6 @@ RectTransform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 6263258808166174538} - m_RootOrder: 2 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0.5} m_AnchorMax: {x: 0, y: 0.5} @@ -2185,7 +2175,6 @@ RectTransform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 2975638553292857375} - m_RootOrder: 1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 1, y: 1} @@ -2264,7 +2253,6 @@ RectTransform: m_Children: - {fileID: 2234904744820987572} m_Father: {fileID: 514912694380149792} - m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 1, y: 1} @@ -2303,7 +2291,6 @@ RectTransform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 3521129445966426109} - m_RootOrder: 2 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 0, y: 0} @@ -2436,7 +2423,6 @@ RectTransform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 282255004005152861} - m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 1, y: 1} @@ -2528,7 +2514,6 @@ RectTransform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 6702871171647363811} - m_RootOrder: 5 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 1, y: 1} m_AnchorMax: {x: 1, y: 1} @@ -2666,7 +2651,6 @@ RectTransform: - {fileID: 5444621218174688333} - {fileID: 3902557823681792741} m_Father: {fileID: 5226752220064165541} - m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 1, y: 1} @@ -2741,7 +2725,9 @@ Canvas: m_OverrideSorting: 0 m_OverridePixelPerfect: 0 m_SortingBucketNormalizedSize: 0 + m_VertexColorAlwaysGammaSpace: 0 m_AdditionalShaderChannelsFlag: 25 + m_UpdateRectTransformForStandalone: 0 m_SortingLayerID: 0 m_SortingOrder: 0 m_TargetDisplay: 0 @@ -2793,7 +2779,6 @@ RectTransform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 3521129445966426109} - m_RootOrder: 1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 0, y: 0} @@ -2871,15 +2856,17 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_enableWordWrapping: 1 + m_TextWrappingMode: 1 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 + m_ActiveFontFeatures: 6e72656b m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 + m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -2929,7 +2916,6 @@ RectTransform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 7760409132803330506} - m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 0, y: 0} @@ -3061,7 +3047,6 @@ RectTransform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 6702871171647363811} - m_RootOrder: 1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 1, y: 1} @@ -3137,7 +3122,6 @@ RectTransform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 2670926649685416499} - m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 1} m_AnchorMax: {x: 1, y: 1} @@ -3194,7 +3178,7 @@ GameObject: - component: {fileID: 5318024624199095249} - component: {fileID: 785373375347833033} m_Layer: 5 - m_Name: EmptyLobbyList (TMP) + m_Name: EmptySessionList (TMP) m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 @@ -3213,7 +3197,6 @@ RectTransform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 9204749279882807884} - m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.5, y: 0.5} m_AnchorMax: {x: 0.5, y: 0.5} @@ -3248,7 +3231,7 @@ MonoBehaviour: m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_text: no lobbies + m_text: no sessions m_isRightToLeft: 0 m_fontAsset: {fileID: 11400000, guid: 1a8c97d4cbe5134499b26527f8609c7e, type: 2} m_sharedMaterial: {fileID: -466885322316925189, guid: 1a8c97d4cbe5134499b26527f8609c7e, type: 2} @@ -3291,15 +3274,17 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_enableWordWrapping: 1 + m_TextWrappingMode: 1 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 + m_ActiveFontFeatures: 6e72656b m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 + m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -3348,7 +3333,6 @@ RectTransform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 3632019498769524828} - m_RootOrder: 2 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 0, y: 0} @@ -3426,15 +3410,17 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_enableWordWrapping: 1 + m_TextWrappingMode: 1 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 + m_ActiveFontFeatures: 6e72656b m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 + m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -3465,7 +3451,7 @@ GameObject: - component: {fileID: 2752597813987140551} - component: {fileID: 8736528447829798099} m_Layer: 5 - m_Name: Create Lobby Button + m_Name: Create Session Button m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 @@ -3485,7 +3471,6 @@ RectTransform: m_Children: - {fileID: 8681644285067859282} m_Father: {fileID: 2963858370021784928} - m_RootOrder: 4 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.5, y: 0.5} m_AnchorMax: {x: 0.5, y: 0.5} @@ -3617,7 +3602,6 @@ RectTransform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 3632019498769524828} - m_RootOrder: 1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 0, y: 0} @@ -3695,15 +3679,17 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_enableWordWrapping: 1 + m_TextWrappingMode: 1 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 + m_ActiveFontFeatures: 6e72656b m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 + m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -3752,7 +3738,6 @@ RectTransform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 6263258808166174538} - m_RootOrder: 1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0.5} m_AnchorMax: {x: 0, y: 0.5} @@ -3828,7 +3813,6 @@ RectTransform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 2963858370021784928} - m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 1} m_AnchorMax: {x: 1, y: 1} @@ -3904,7 +3888,6 @@ RectTransform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 3851624040064246431} - m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 1, y: 1} @@ -3952,7 +3935,7 @@ MonoBehaviour: m_HorizontalOverflow: 0 m_VerticalOverflow: 0 m_LineSpacing: 1 - m_Text: Enter your lobby name... + m_Text: Enter your Session name... --- !u!1 &6616621817421405779 GameObject: m_ObjectHideFlags: 0 @@ -3964,7 +3947,7 @@ GameObject: - component: {fileID: 6263258808166174538} - component: {fileID: 8780206513702589119} m_Layer: 5 - m_Name: Private Lobby Toggle + m_Name: Private Session Toggle m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 @@ -3986,7 +3969,6 @@ RectTransform: - {fileID: 1076487188656558799} - {fileID: 3606018944305289553} m_Father: {fileID: 2963858370021784928} - m_RootOrder: 2 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.5, y: 0.5} m_AnchorMax: {x: 0.5, y: 0.5} @@ -4055,7 +4037,7 @@ GameObject: - component: {fileID: 6702871171647363810} - component: {fileID: 6889764071769254414} m_Layer: 5 - m_Name: LobbyUI + m_Name: SessionUI m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 @@ -4081,7 +4063,6 @@ RectTransform: - {fileID: 4279823075853654326} - {fileID: 1176249261847584693} m_Father: {fileID: 0} - m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 1, y: 1} @@ -4101,8 +4082,8 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: m_CanvasGroup: {fileID: 6889764071769254414} - m_LobbyJoiningUI: {fileID: 3432713757992463987} - m_LobbyCreationUI: {fileID: 5370165130166260100} + m_SessionJoiningUI: {fileID: 3432713757992463987} + m_SessionCreationUI: {fileID: 5370165130166260100} m_JoinToggleHighlight: {fileID: 6752777071945805011} m_JoinToggleTabBlocker: {fileID: 4806072236846957327} m_CreateToggleHighlight: {fileID: 4585101913867269799} @@ -4171,7 +4152,7 @@ GameObject: - component: {fileID: 3432713757992463987} - component: {fileID: 5782144806807453527} m_Layer: 5 - m_Name: LobbyJoiningUI + m_Name: SessionJoiningUI m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 @@ -4194,7 +4175,6 @@ RectTransform: - {fileID: 5226752220064165541} - {fileID: 7760409132803330506} m_Father: {fileID: 244032492905947229} - m_RootOrder: 1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 1, y: 1} @@ -4213,11 +4193,11 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 5badc8e4e5a84afeae84746e5199ebaf, type: 3} m_Name: m_EditorClassIdentifier: - m_LobbyListItemPrototype: {fileID: 6844302749700945984} + m_SessionListItemPrototype: {fileID: 6844302749700945984} m_JoinCodeField: {fileID: 8248007993983070476} m_CanvasGroup: {fileID: 5782144806807453527} - m_EmptyLobbyListLabel: {fileID: 785373375347833033} - m_JoinLobbyButton: {fileID: 2758534323255991562} + m_EmptySessionListLabel: {fileID: 785373375347833033} + m_JoinSessionButton: {fileID: 2758534323255991562} --- !u!225 &5782144806807453527 CanvasGroup: m_ObjectHideFlags: 0 @@ -4261,7 +4241,6 @@ RectTransform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 2963858370021784928} - m_RootOrder: 1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 1} m_AnchorMax: {x: 1, y: 1} @@ -4296,7 +4275,7 @@ MonoBehaviour: m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_text: 'Create a new lobby... + m_text: 'Create a new Session... ' m_isRightToLeft: 0 @@ -4341,15 +4320,17 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_enableWordWrapping: 0 + m_TextWrappingMode: 0 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 + m_ActiveFontFeatures: 6e72656b m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 + m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -4400,7 +4381,6 @@ RectTransform: m_Children: - {fileID: 7349595981541475631} m_Father: {fileID: 5226752220064165541} - m_RootOrder: 1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 1, y: 0} m_AnchorMax: {x: 1, y: 1} @@ -4506,7 +4486,7 @@ GameObject: - component: {fileID: 453327300698636041} - component: {fileID: 3771175507069267251} m_Layer: 5 - m_Name: LobbyList + m_Name: SessionList m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 @@ -4526,7 +4506,6 @@ RectTransform: m_Children: - {fileID: 3632019498769524828} m_Father: {fileID: 9204749279882807884} - m_RootOrder: 1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 1} m_AnchorMax: {x: 1, y: 1} @@ -4604,7 +4583,6 @@ RectTransform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 6403041760458951094} - m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 1, y: 1} @@ -4682,15 +4660,17 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_enableWordWrapping: 1 + m_TextWrappingMode: 1 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 + m_ActiveFontFeatures: 6e72656b m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 + m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -4719,7 +4699,7 @@ GameObject: - component: {fileID: 5226752220064165541} - component: {fileID: 8781373074404198200} m_Layer: 5 - m_Name: LobbiesPanel + m_Name: SessionsPanel m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 @@ -4740,7 +4720,6 @@ RectTransform: - {fileID: 9204749279882807884} - {fileID: 514912694380149792} m_Father: {fileID: 2670926649685416499} - m_RootOrder: 2 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 1, y: 1} @@ -4810,7 +4789,6 @@ RectTransform: m_Children: - {fileID: 5472588618955582370} m_Father: {fileID: 7760409132803330506} - m_RootOrder: 2 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 0, y: 0} @@ -4942,7 +4920,6 @@ RectTransform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 4250182236641786634} - m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 1, y: 1} @@ -5020,15 +4997,17 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_enableWordWrapping: 1 + m_TextWrappingMode: 1 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 + m_ActiveFontFeatures: 6e72656b m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 + m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -5077,7 +5056,6 @@ RectTransform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 2670926649685416499} - m_RootOrder: 1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 1} m_AnchorMax: {x: 1, y: 1} @@ -5112,7 +5090,7 @@ MonoBehaviour: m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_text: Join an existing lobby... + m_text: Join an existing Session... m_isRightToLeft: 0 m_fontAsset: {fileID: 11400000, guid: 9641ce046d2227445b9684161a165f68, type: 2} m_sharedMaterial: {fileID: -4106257185398102161, guid: 9641ce046d2227445b9684161a165f68, type: 2} @@ -5155,15 +5133,17 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_enableWordWrapping: 0 + m_TextWrappingMode: 0 m_wordWrappingRatios: 0.4 m_overflowMode: 0 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 + m_ActiveFontFeatures: 6e72656b m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 + m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -5214,7 +5194,6 @@ RectTransform: - {fileID: 792957857740898001} - {fileID: 7210379632491551496} m_Father: {fileID: 6702871171647363811} - m_RootOrder: 2 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 1, y: 0} @@ -5278,7 +5257,6 @@ RectTransform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 3632019498769524828} - m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 0, y: 0} @@ -5356,15 +5334,17 @@ MonoBehaviour: m_lineSpacingMax: 0 m_paragraphSpacing: 0 m_charWidthMaxAdj: 0 - m_enableWordWrapping: 1 + m_TextWrappingMode: 1 m_wordWrappingRatios: 0.4 m_overflowMode: 1 m_linkedTextComponent: {fileID: 0} parentLinkedComponent: {fileID: 0} m_enableKerning: 1 + m_ActiveFontFeatures: 6e72656b m_enableExtraPadding: 0 checkPaddingRequired: 0 m_isRichText: 1 + m_EmojiFallbackSupport: 1 m_parseCtrlCharacters: 1 m_isOrthographic: 1 m_isCullingEnabled: 0 @@ -5413,7 +5393,6 @@ RectTransform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 7349595981541475631} - m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 0, y: 0} @@ -5468,7 +5447,7 @@ GameObject: m_Component: - component: {fileID: 9087430833360061411} m_Layer: 5 - m_Name: LobbyTypeContainer_TK + m_Name: SessionTypeContainer_TK m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 @@ -5487,7 +5466,6 @@ RectTransform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 7760409132803330506} - m_RootOrder: 1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 1} m_AnchorMax: {x: 0, y: 1} @@ -5509,7 +5487,7 @@ GameObject: - component: {fileID: 6432751663401761397} - component: {fileID: 4034168928220429643} m_Layer: 5 - m_Name: LobbyListItemUI Prototype + m_Name: SessionListItemUI Prototype m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 @@ -5531,7 +5509,6 @@ RectTransform: - {fileID: 7878795380521772600} - {fileID: 4492811537154015470} m_Father: {fileID: 3902557823681792741} - m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 0, y: 0} @@ -5550,8 +5527,8 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 83ebc4f31452e4fc1b11263aed913c99, type: 3} m_Name: m_EditorClassIdentifier: - m_lobbyNameText: {fileID: 1583053172819472216} - m_lobbyCountText: {fileID: 1131054124500818674} + m_SessionNameText: {fileID: 1583053172819472216} + m_SessionCountText: {fileID: 1131054124500818674} --- !u!222 &1731687845091873337 CanvasRenderer: m_ObjectHideFlags: 0 @@ -5704,7 +5681,6 @@ RectTransform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 4996778416574021528} - m_RootOrder: 1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 180} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 1, y: 1} @@ -5769,6 +5745,7 @@ PrefabInstance: m_ObjectHideFlags: 0 serializedVersion: 2 m_Modification: + serializedVersion: 3 m_TransformParent: {fileID: 6702871171647363811} m_Modifications: - target: {fileID: 921942742702944666, guid: 996cbd343fa869b408f74acb84aed786, type: 3} @@ -5860,6 +5837,9 @@ PrefabInstance: value: LoadingSpinner objectReference: {fileID: 0} m_RemovedComponents: [] + m_RemovedGameObjects: [] + m_AddedGameObjects: [] + m_AddedComponents: [] m_SourcePrefab: {fileID: 100100000, guid: 996cbd343fa869b408f74acb84aed786, type: 3} --- !u!224 &1176249261847584693 stripped RectTransform: diff --git a/Assets/Prefabs/UI/LobbyUI.prefab.meta b/Assets/Prefabs/UI/SessionUI.prefab.meta similarity index 100% rename from Assets/Prefabs/UI/LobbyUI.prefab.meta rename to Assets/Prefabs/UI/SessionUI.prefab.meta diff --git a/Assets/Scenes/CharSelect.unity b/Assets/Scenes/CharSelect.unity index 927dab2cd..58e1d0c64 100644 --- a/Assets/Scenes/CharSelect.unity +++ b/Assets/Scenes/CharSelect.unity @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fe57cffed60d9bfe7f42257a90c3d6a2240755dcaa4e10ae0c745f6fb4aecd66 -size 45820 +oid sha256:d8d33954123e1f21d88d8267ebc8097362995bab0f724e32de5226bc7c941054 +size 49148 diff --git a/Assets/Scenes/MainMenu.unity b/Assets/Scenes/MainMenu.unity index f08b37c04..6204ba89b 100644 --- a/Assets/Scenes/MainMenu.unity +++ b/Assets/Scenes/MainMenu.unity @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2f42f44e58e165cddd54ae1a554ec6e13212353e3fbc04756771b9e70f3cf371 -size 71441 +oid sha256:79bf90e92970834821bfae7eccf2c13845b8f72e544136af41739edd694ca63a +size 72535 diff --git a/Assets/Scripts/ApplicationLifecycle/ApplicationController.cs b/Assets/Scripts/ApplicationLifecycle/ApplicationController.cs index 499701fc2..772b880b0 100644 --- a/Assets/Scripts/ApplicationLifecycle/ApplicationController.cs +++ b/Assets/Scripts/ApplicationLifecycle/ApplicationController.cs @@ -7,7 +7,7 @@ using Unity.BossRoom.Infrastructure; using Unity.BossRoom.UnityServices; using Unity.BossRoom.UnityServices.Auth; -using Unity.BossRoom.UnityServices.Lobbies; +using Unity.BossRoom.UnityServices.Sessions; using Unity.BossRoom.Utils; using Unity.Netcode; using UnityEngine; @@ -29,8 +29,8 @@ public class ApplicationController : LifetimeScope [SerializeField] NetworkManager m_NetworkManager; - LocalLobby m_LocalLobby; - LobbyServiceFacade m_LobbyServiceFacade; + LocalSession m_LocalSession; + MultiplayerServicesFacade m_MultiplayerServicesFacade; IDisposable m_Subscriptions; @@ -41,47 +41,47 @@ protected override void Configure(IContainerBuilder builder) builder.RegisterComponent(m_ConnectionManager); builder.RegisterComponent(m_NetworkManager); - //the following singletons represent the local representations of the lobby that we're in and the user that we are - //they can persist longer than the lifetime of the UI in MainMenu where we set up the lobby that we create or join - builder.Register(Lifetime.Singleton); - builder.Register(Lifetime.Singleton); + // The following singletons represent the local representations of the Session that we're in and the user that we are + // They can persist longer than the lifetime of the UI in MainMenu where we set up the Session that we create or join + builder.Register(Lifetime.Singleton); + builder.Register(Lifetime.Singleton); builder.Register(Lifetime.Singleton); builder.Register(Lifetime.Singleton); - //these message channels are essential and persist for the lifetime of the lobby and relay services + // These message channels are essential and persist for the lifetime of the Session and relay services // Registering as instance to prevent code stripping on iOS builder.RegisterInstance(new MessageChannel()).AsImplementedInterfaces(); builder.RegisterInstance(new MessageChannel()).AsImplementedInterfaces(); builder.RegisterInstance(new MessageChannel()).AsImplementedInterfaces(); builder.RegisterInstance(new MessageChannel()).AsImplementedInterfaces(); - //these message channels are essential and persist for the lifetime of the lobby and relay services - //they are networked so that the clients can subscribe to those messages that are published by the server + // These message channels are essential and persist for the lifetime of the Session and relay services + // They are networked so that the clients can subscribe to those messages that are published by the server builder.RegisterComponent(new NetworkedMessageChannel()).AsImplementedInterfaces(); builder.RegisterComponent(new NetworkedMessageChannel()).AsImplementedInterfaces(); #if UNITY_EDITOR || DEVELOPMENT_BUILD builder.RegisterComponent(new NetworkedMessageChannel()).AsImplementedInterfaces(); #endif - //this message channel is essential and persists for the lifetime of the lobby and relay services + // This message channel is essential and persists for the lifetime of the Session and relay services builder.RegisterInstance(new MessageChannel()).AsImplementedInterfaces(); - //buffered message channels hold the latest received message in buffer and pass to any new subscribers - builder.RegisterInstance(new BufferedMessageChannel()).AsImplementedInterfaces(); + // Buffered message channels hold the latest received message in buffer and pass to any new subscribers + builder.RegisterInstance(new BufferedMessageChannel()).AsImplementedInterfaces(); - //all the lobby service stuff, bound here so that it persists through scene loads + // All the Session service stuff, bound here so that it persists through scene loads builder.Register(Lifetime.Singleton); //a manager entity that allows us to do anonymous authentication with unity services - //LobbyServiceFacade is registered as entrypoint because it wants a callback after container is built to do it's initialization - builder.RegisterEntryPoint(Lifetime.Singleton).AsSelf(); + // MultiplayerServicesFacade is registered as entrypoint because it wants a callback after container is built to do it's initialization + builder.RegisterEntryPoint(Lifetime.Singleton).AsSelf(); } private void Start() { - m_LocalLobby = Container.Resolve(); - m_LobbyServiceFacade = Container.Resolve(); + m_LocalSession = Container.Resolve(); + m_MultiplayerServicesFacade = Container.Resolve(); var quitApplicationSub = Container.Resolve>(); @@ -103,24 +103,24 @@ protected override void OnDestroy() m_Subscriptions.Dispose(); } - if (m_LobbyServiceFacade != null) + if (m_MultiplayerServicesFacade != null) { - m_LobbyServiceFacade.EndTracking(); + m_MultiplayerServicesFacade.EndTracking(); } base.OnDestroy(); } /// - /// In builds, if we are in a lobby and try to send a Leave request on application quit, it won't go through if we're quitting on the same frame. + /// In builds, if we are in a Session and try to send a Leave request on application quit, it won't go through if we're quitting on the same frame. /// So, we need to delay just briefly to let the request happen (though we don't need to wait for the result). /// private IEnumerator LeaveBeforeQuit() { - // We want to quit anyways, so if anything happens while trying to leave the Lobby, log the exception then carry on + // We want to quit anyways, so if anything happens while trying to leave the Session, log the exception then carry on try { - m_LobbyServiceFacade.EndTracking(); + m_MultiplayerServicesFacade.EndTracking(); } catch (Exception e) { @@ -135,7 +135,7 @@ private bool OnWantToQuit() { Application.wantsToQuit -= OnWantToQuit; - var canQuit = m_LocalLobby != null && string.IsNullOrEmpty(m_LocalLobby.LobbyID); + var canQuit = m_LocalSession != null && string.IsNullOrEmpty(m_LocalSession.SessionID); if (!canQuit) { StartCoroutine(LeaveBeforeQuit()); diff --git a/Assets/Scripts/ConnectionManagement/ConnectionManager.cs b/Assets/Scripts/ConnectionManagement/ConnectionManager.cs index 22068b375..d1e98e7b0 100644 --- a/Assets/Scripts/ConnectionManagement/ConnectionManager.cs +++ b/Assets/Scripts/ConnectionManagement/ConnectionManager.cs @@ -153,9 +153,9 @@ void OnServerStopped(bool _) // we don't need this parameter as the ConnectionSt m_CurrentState.OnServerStopped(); } - public void StartClientLobby(string playerName) + public void StartClientSession(string playerName) { - m_CurrentState.StartClientLobby(playerName); + m_CurrentState.StartClientSession(playerName); } public void StartClientIp(string playerName, string ipaddress, int port) @@ -163,9 +163,9 @@ public void StartClientIp(string playerName, string ipaddress, int port) m_CurrentState.StartClientIP(playerName, ipaddress, port); } - public void StartHostLobby(string playerName) + public void StartHostSession(string playerName) { - m_CurrentState.StartHostLobby(playerName); + m_CurrentState.StartHostSession(playerName); } public void StartHostIp(string playerName, string ipaddress, int port) diff --git a/Assets/Scripts/ConnectionManagement/ConnectionMethod.cs b/Assets/Scripts/ConnectionManagement/ConnectionMethod.cs index 3a0b6087d..3ccffda8c 100644 --- a/Assets/Scripts/ConnectionManagement/ConnectionMethod.cs +++ b/Assets/Scripts/ConnectionManagement/ConnectionMethod.cs @@ -1,19 +1,16 @@ -using System; using System.Threading.Tasks; -using Unity.BossRoom.UnityServices.Lobbies; +using Unity.BossRoom.UnityServices.Sessions; using Unity.BossRoom.Utils; using Unity.Netcode.Transports.UTP; -using Unity.Networking.Transport.Relay; using Unity.Services.Authentication; using Unity.Services.Core; -using Unity.Services.Relay; -using Unity.Services.Relay.Models; using UnityEngine; namespace Unity.BossRoom.ConnectionManagement { /// - /// ConnectionMethod contains all setup needed to setup NGO to be ready to start a connection, either host or client side. + /// ConnectionMethod contains all setup needed to setup NGO to be ready to start a connection, either host or client + /// side. /// Please override this abstract class to add a new transport or way of connecting. /// public abstract class ConnectionMethodBase @@ -21,20 +18,18 @@ public abstract class ConnectionMethodBase protected ConnectionManager m_ConnectionManager; readonly ProfileManager m_ProfileManager; protected readonly string m_PlayerName; - protected const string k_DtlsConnType = "dtls"; /// /// Setup the host connection prior to starting the NetworkManager /// /// - public abstract Task SetupHostConnectionAsync(); - + public abstract void SetupHostConnection(); /// /// Setup the client connection prior to starting the NetworkManager /// /// - public abstract Task SetupClientConnectionAsync(); + public abstract void SetupClientConnection(); /// /// Setup the client for reconnection prior to reconnecting @@ -54,7 +49,7 @@ public ConnectionMethodBase(ConnectionManager connectionManager, ProfileManager protected void SetConnectionPayload(string playerId, string playerName) { - var payload = JsonUtility.ToJson(new ConnectionPayload() + var payload = JsonUtility.ToJson(new ConnectionPayload { playerId = playerId, playerName = playerName, @@ -100,7 +95,7 @@ public ConnectionMethodIP(string ip, ushort port, ConnectionManager connectionMa m_ConnectionManager = connectionManager; } - public override async Task SetupClientConnectionAsync() + public override void SetupClientConnection() { SetConnectionPayload(GetPlayerId(), m_PlayerName); var utp = (UnityTransport)m_ConnectionManager.NetworkManager.NetworkConfig.NetworkTransport; @@ -113,7 +108,7 @@ public override async Task SetupClientConnectionAsync() return (true, true); } - public override async Task SetupHostConnectionAsync() + public override void SetupHostConnection() { SetConnectionPayload(GetPlayerId(), m_PlayerName); // Need to set connection payload for host as well, as host is a client too var utp = (UnityTransport)m_ConnectionManager.NetworkManager.NetworkConfig.NetworkTransport; @@ -122,90 +117,51 @@ public override async Task SetupHostConnectionAsync() } /// - /// UTP's Relay connection setup using the Lobby integration + /// UTP's Relay connection setup using the Session integration /// class ConnectionMethodRelay : ConnectionMethodBase { - LobbyServiceFacade m_LobbyServiceFacade; - LocalLobby m_LocalLobby; + MultiplayerServicesFacade m_MultiplayerServicesFacade; - public ConnectionMethodRelay(LobbyServiceFacade lobbyServiceFacade, LocalLobby localLobby, ConnectionManager connectionManager, ProfileManager profileManager, string playerName) + public ConnectionMethodRelay(MultiplayerServicesFacade multiplayerServicesFacade, + ConnectionManager connectionManager, + ProfileManager profileManager, + string playerName) : base(connectionManager, profileManager, playerName) { - m_LobbyServiceFacade = lobbyServiceFacade; - m_LocalLobby = localLobby; + m_MultiplayerServicesFacade = multiplayerServicesFacade; m_ConnectionManager = connectionManager; } - public override async Task SetupClientConnectionAsync() + public override void SetupClientConnection() { - Debug.Log("Setting up Unity Relay client"); - SetConnectionPayload(GetPlayerId(), m_PlayerName); - - if (m_LobbyServiceFacade.CurrentUnityLobby == null) - { - throw new Exception("Trying to start relay while Lobby isn't set"); - } - - Debug.Log($"Setting Unity Relay client with join code {m_LocalLobby.RelayJoinCode}"); - - // Create client joining allocation from join code - var joinedAllocation = await RelayService.Instance.JoinAllocationAsync(m_LocalLobby.RelayJoinCode); - Debug.Log($"client: {joinedAllocation.ConnectionData[0]} {joinedAllocation.ConnectionData[1]}, " + - $"host: {joinedAllocation.HostConnectionData[0]} {joinedAllocation.HostConnectionData[1]}, " + - $"client: {joinedAllocation.AllocationId}"); - - await m_LobbyServiceFacade.UpdatePlayerDataAsync(joinedAllocation.AllocationId.ToString(), m_LocalLobby.RelayJoinCode); - - // Configure UTP with allocation - var utp = (UnityTransport)m_ConnectionManager.NetworkManager.NetworkConfig.NetworkTransport; - utp.SetRelayServerData(new RelayServerData(joinedAllocation, k_DtlsConnType)); } public override async Task<(bool success, bool shouldTryAgain)> SetupClientReconnectionAsync() { - if (m_LobbyServiceFacade.CurrentUnityLobby == null) + if (m_MultiplayerServicesFacade.CurrentUnitySession == null) { - Debug.Log("Lobby does not exist anymore, stopping reconnection attempts."); + Debug.Log("Session does not exist anymore, stopping reconnection attempts."); return (false, false); } - // When using Lobby with Relay, if a user is disconnected from the Relay server, the server will notify the - // Lobby service and mark the user as disconnected, but will not remove them from the lobby. They then have + // When using Session with Relay, if a user is disconnected from the Relay server, the server will notify the + // Session service and mark the user as disconnected, but will not remove them from the Session. They then have // some time to attempt to reconnect (defined by the "Disconnect removal time" parameter on the dashboard), - // after which they will be removed from the lobby completely. - // See https://docs.unity.com/lobby/reconnect-to-lobby.html - var lobby = await m_LobbyServiceFacade.ReconnectToLobbyAsync(); - var success = lobby != null; - Debug.Log(success ? "Successfully reconnected to Lobby." : "Failed to reconnect to Lobby."); - return (success, true); // return a success if reconnecting to lobby returns a lobby + // after which they will be removed from the Session completely. + // See https://docs.unity.com/ugs/en-us/manual/mps-sdk/manual/join-session#Reconnect_to_a_session + var session = await m_MultiplayerServicesFacade.ReconnectToSessionAsync(); + var success = session != null; + Debug.Log(success ? "Successfully reconnected to Session." : "Failed to reconnect to Session."); + return (success, true); // return a success if reconnecting to session returns a session } - public override async Task SetupHostConnectionAsync() + public override void SetupHostConnection() { Debug.Log("Setting up Unity Relay host"); SetConnectionPayload(GetPlayerId(), m_PlayerName); // Need to set connection payload for host as well, as host is a client too - - // Create relay allocation - Allocation hostAllocation = await RelayService.Instance.CreateAllocationAsync(m_ConnectionManager.MaxConnectedPlayers, region: null); - var joinCode = await RelayService.Instance.GetJoinCodeAsync(hostAllocation.AllocationId); - - Debug.Log($"server: connection data: {hostAllocation.ConnectionData[0]} {hostAllocation.ConnectionData[1]}, " + - $"allocation ID:{hostAllocation.AllocationId}, region:{hostAllocation.Region}"); - - m_LocalLobby.RelayJoinCode = joinCode; - - // next line enables lobby and relay services integration - await m_LobbyServiceFacade.UpdateLobbyDataAndUnlockAsync(); - await m_LobbyServiceFacade.UpdatePlayerDataAsync(hostAllocation.AllocationIdBytes.ToString(), joinCode); - - // Setup UTP with relay connection info - var utp = (UnityTransport)m_ConnectionManager.NetworkManager.NetworkConfig.NetworkTransport; - utp.SetRelayServerData(new RelayServerData(hostAllocation, k_DtlsConnType)); // This is with DTLS enabled for a secure connection - - Debug.Log($"Created relay allocation with join code {m_LocalLobby.RelayJoinCode}"); } } } diff --git a/Assets/Scripts/ConnectionManagement/ConnectionState/ClientConnectedState.cs b/Assets/Scripts/ConnectionManagement/ConnectionState/ClientConnectedState.cs index 9d4e0e0f1..0ac5e31de 100644 --- a/Assets/Scripts/ConnectionManagement/ConnectionState/ClientConnectedState.cs +++ b/Assets/Scripts/ConnectionManagement/ConnectionState/ClientConnectedState.cs @@ -1,4 +1,4 @@ -using Unity.BossRoom.UnityServices.Lobbies; +using Unity.BossRoom.UnityServices.Sessions; using UnityEngine; using VContainer; @@ -11,13 +11,13 @@ namespace Unity.BossRoom.ConnectionManagement class ClientConnectedState : OnlineState { [Inject] - protected LobbyServiceFacade m_LobbyServiceFacade; + protected MultiplayerServicesFacade m_MultiplayerServicesFacade; public override void Enter() { - if (m_LobbyServiceFacade.CurrentUnityLobby != null) + if (m_MultiplayerServicesFacade.CurrentUnitySession != null) { - m_LobbyServiceFacade.BeginTracking(); + m_MultiplayerServicesFacade.BeginTracking(); } } diff --git a/Assets/Scripts/ConnectionManagement/ConnectionState/ClientConnectingState.cs b/Assets/Scripts/ConnectionManagement/ConnectionState/ClientConnectingState.cs index fc2fd12e4..7039afae1 100644 --- a/Assets/Scripts/ConnectionManagement/ConnectionState/ClientConnectingState.cs +++ b/Assets/Scripts/ConnectionManagement/ConnectionState/ClientConnectingState.cs @@ -51,21 +51,22 @@ void StartingClientFailed() var connectStatus = JsonUtility.FromJson(disconnectReason); m_ConnectStatusPublisher.Publish(connectStatus); } + m_ConnectionManager.ChangeState(m_ConnectionManager.m_Offline); } - internal async Task ConnectClientAsync() { try { - // Setup NGO with current connection method - await m_ConnectionMethod.SetupClientConnectionAsync(); + m_ConnectionMethod.SetupClientConnection(); - // NGO's StartClient launches everything - if (!m_ConnectionManager.NetworkManager.StartClient()) + if (m_ConnectionMethod is ConnectionMethodIP) { - throw new Exception("NetworkManager StartClient failed"); + if (!m_ConnectionManager.NetworkManager.StartClient()) + { + throw new Exception("NetworkManager StartClient failed"); + } } } catch (Exception e) diff --git a/Assets/Scripts/ConnectionManagement/ConnectionState/ClientReconnectingState.cs b/Assets/Scripts/ConnectionManagement/ConnectionState/ClientReconnectingState.cs index 3b7d0397e..90f6e8c3d 100644 --- a/Assets/Scripts/ConnectionManagement/ConnectionState/ClientReconnectingState.cs +++ b/Assets/Scripts/ConnectionManagement/ConnectionState/ClientReconnectingState.cs @@ -108,8 +108,8 @@ IEnumerator ReconnectCoroutine() m_ReconnectMessagePublisher.Publish(new ReconnectMessage(m_NbAttempts, m_ConnectionManager.NbReconnectAttempts)); // If first attempt, wait some time before attempting to reconnect to give time to services to update - // (i.e. if in a Lobby and the host shuts down unexpectedly, this will give enough time for the lobby to be - // properly deleted so that we don't reconnect to an empty lobby + // (i.e. if in a Session and the host shuts down unexpectedly, this will give enough time for the Session to be + // properly deleted so that we don't reconnect to an empty Session if (m_NbAttempts == 0) { yield return new WaitForSeconds(k_TimeBeforeFirstAttempt); diff --git a/Assets/Scripts/ConnectionManagement/ConnectionState/ConnectionState.cs b/Assets/Scripts/ConnectionManagement/ConnectionState/ConnectionState.cs index eed9a87da..a7d8eecc5 100644 --- a/Assets/Scripts/ConnectionManagement/ConnectionState/ConnectionState.cs +++ b/Assets/Scripts/ConnectionManagement/ConnectionState/ConnectionState.cs @@ -28,11 +28,11 @@ public virtual void OnServerStarted() { } public virtual void StartClientIP(string playerName, string ipaddress, int port) { } - public virtual void StartClientLobby(string playerName) { } + public virtual void StartClientSession(string playerName) { } public virtual void StartHostIP(string playerName, string ipaddress, int port) { } - public virtual void StartHostLobby(string playerName) { } + public virtual void StartHostSession(string playerName) { } public virtual void OnUserRequestedShutdown() { } diff --git a/Assets/Scripts/ConnectionManagement/ConnectionState/HostingState.cs b/Assets/Scripts/ConnectionManagement/ConnectionState/HostingState.cs index b0645e21e..7227fddba 100644 --- a/Assets/Scripts/ConnectionManagement/ConnectionState/HostingState.cs +++ b/Assets/Scripts/ConnectionManagement/ConnectionState/HostingState.cs @@ -1,6 +1,6 @@ using System; using Unity.BossRoom.Infrastructure; -using Unity.BossRoom.UnityServices.Lobbies; +using Unity.BossRoom.UnityServices.Sessions; using Unity.Multiplayer.Samples.BossRoom; using Unity.Multiplayer.Samples.Utilities; using Unity.Netcode; @@ -16,7 +16,7 @@ namespace Unity.BossRoom.ConnectionManagement class HostingState : OnlineState { [Inject] - LobbyServiceFacade m_LobbyServiceFacade; + MultiplayerServicesFacade m_MultiplayerServicesFacade; [Inject] IPublisher m_ConnectionEventPublisher; @@ -29,9 +29,9 @@ public override void Enter() //may do this differently. SceneLoaderWrapper.Instance.LoadScene("CharSelect", useNetworkSceneManager: true); - if (m_LobbyServiceFacade.CurrentUnityLobby != null) + if (m_MultiplayerServicesFacade.CurrentUnitySession != null) { - m_LobbyServiceFacade.BeginTracking(); + m_MultiplayerServicesFacade.BeginTracking(); } } @@ -139,9 +139,9 @@ public override void ApprovalCheck(NetworkManager.ConnectionApprovalRequest requ response.Approved = false; response.Reason = JsonUtility.ToJson(gameReturnStatus); - if (m_LobbyServiceFacade.CurrentUnityLobby != null) + if (m_MultiplayerServicesFacade.CurrentUnitySession != null) { - m_LobbyServiceFacade.RemovePlayerFromLobbyAsync(connectionPayload.playerId); + m_MultiplayerServicesFacade.RemovePlayerFromSessionAsync(connectionPayload.playerId); } } diff --git a/Assets/Scripts/ConnectionManagement/ConnectionState/OfflineState.cs b/Assets/Scripts/ConnectionManagement/ConnectionState/OfflineState.cs index 34dc047df..cc224d872 100644 --- a/Assets/Scripts/ConnectionManagement/ConnectionState/OfflineState.cs +++ b/Assets/Scripts/ConnectionManagement/ConnectionState/OfflineState.cs @@ -1,6 +1,6 @@ using System; using Unity.BossRoom.ConnectionManagement; -using Unity.BossRoom.UnityServices.Lobbies; +using Unity.BossRoom.UnityServices.Sessions; using Unity.BossRoom.Utils; using Unity.Multiplayer.Samples.Utilities; using UnityEngine; @@ -16,17 +16,17 @@ namespace UUnity.BossRoom.ConnectionManagement class OfflineState : ConnectionState { [Inject] - LobbyServiceFacade m_LobbyServiceFacade; + MultiplayerServicesFacade m_MultiplayerServicesFacade; [Inject] ProfileManager m_ProfileManager; [Inject] - LocalLobby m_LocalLobby; + LocalSession m_LocalSession; const string k_MainMenuSceneName = "MainMenu"; public override void Enter() { - m_LobbyServiceFacade.EndTracking(); + m_MultiplayerServicesFacade.EndTracking(); m_ConnectionManager.NetworkManager.Shutdown(); if (SceneManager.GetActiveScene().name != k_MainMenuSceneName) { @@ -43,9 +43,9 @@ public override void StartClientIP(string playerName, string ipaddress, int port m_ConnectionManager.ChangeState(m_ConnectionManager.m_ClientConnecting.Configure(connectionMethod)); } - public override void StartClientLobby(string playerName) + public override void StartClientSession(string playerName) { - var connectionMethod = new ConnectionMethodRelay(m_LobbyServiceFacade, m_LocalLobby, m_ConnectionManager, m_ProfileManager, playerName); + var connectionMethod = new ConnectionMethodRelay(m_MultiplayerServicesFacade, m_ConnectionManager, m_ProfileManager, playerName); m_ConnectionManager.m_ClientReconnecting.Configure(connectionMethod); m_ConnectionManager.ChangeState(m_ConnectionManager.m_ClientConnecting.Configure(connectionMethod)); } @@ -56,9 +56,9 @@ public override void StartHostIP(string playerName, string ipaddress, int port) m_ConnectionManager.ChangeState(m_ConnectionManager.m_StartingHost.Configure(connectionMethod)); } - public override void StartHostLobby(string playerName) + public override void StartHostSession(string playerName) { - var connectionMethod = new ConnectionMethodRelay(m_LobbyServiceFacade, m_LocalLobby, m_ConnectionManager, m_ProfileManager, playerName); + var connectionMethod = new ConnectionMethodRelay(m_MultiplayerServicesFacade, m_ConnectionManager, m_ProfileManager, playerName); m_ConnectionManager.ChangeState(m_ConnectionManager.m_StartingHost.Configure(connectionMethod)); } } diff --git a/Assets/Scripts/ConnectionManagement/ConnectionState/StartingHostState.cs b/Assets/Scripts/ConnectionManagement/ConnectionState/StartingHostState.cs index 9008ade09..502e5f5cd 100644 --- a/Assets/Scripts/ConnectionManagement/ConnectionState/StartingHostState.cs +++ b/Assets/Scripts/ConnectionManagement/ConnectionState/StartingHostState.cs @@ -1,6 +1,6 @@ using System; using Unity.BossRoom.Infrastructure; -using Unity.BossRoom.UnityServices.Lobbies; +using Unity.BossRoom.UnityServices.Sessions; using Unity.Multiplayer.Samples.BossRoom; using Unity.Netcode; using UnityEngine; @@ -15,9 +15,9 @@ namespace Unity.BossRoom.ConnectionManagement class StartingHostState : OnlineState { [Inject] - LobbyServiceFacade m_LobbyServiceFacade; + MultiplayerServicesFacade m_MultiplayerServicesFacade; [Inject] - LocalLobby m_LocalLobby; + LocalSession m_LocalSession; ConnectionMethodBase m_ConnectionMethod; public StartingHostState Configure(ConnectionMethodBase baseConnectionMethod) @@ -43,6 +43,7 @@ public override void ApprovalCheck(NetworkManager.ConnectionApprovalRequest requ { var connectionData = request.Payload; var clientId = request.ClientNetworkId; + // This happens when starting as a host, before the end of the StartHost call. In that case, we simply approve ourselves. if (clientId == m_ConnectionManager.NetworkManager.LocalClientId) { @@ -63,16 +64,19 @@ public override void OnServerStopped() StartHostFailed(); } - async void StartHost() + void StartHost() { try { - await m_ConnectionMethod.SetupHostConnectionAsync(); + m_ConnectionMethod.SetupHostConnection(); - // NGO's StartHost launches everything - if (!m_ConnectionManager.NetworkManager.StartHost()) + if (m_ConnectionMethod is ConnectionMethodIP) { - StartHostFailed(); + // NGO's StartHost launches everything + if (!m_ConnectionManager.NetworkManager.StartHost()) + { + StartHostFailed(); + } } } catch (Exception) diff --git a/Assets/Scripts/ConnectionManagement/Unity.BossRoom.ConnectionManagement.asmdef b/Assets/Scripts/ConnectionManagement/Unity.BossRoom.ConnectionManagement.asmdef index 0d83eed23..38d9fd85d 100644 --- a/Assets/Scripts/ConnectionManagement/Unity.BossRoom.ConnectionManagement.asmdef +++ b/Assets/Scripts/ConnectionManagement/Unity.BossRoom.ConnectionManagement.asmdef @@ -9,10 +9,9 @@ "Unity.Services.Core", "Unity.Services.Authentication", "Unity.BossRoom.Utils", - "Unity.Services.Lobbies", "Unity.Networking.Transport", "VContainer", - "Unity.Services.Relay" + "Unity.Services.Multiplayer" ], "includePlatforms": [], "excludePlatforms": [], @@ -23,4 +22,4 @@ "defineConstraints": [], "versionDefines": [], "noEngineReferences": false -} +} \ No newline at end of file diff --git a/Assets/Scripts/Gameplay/GameState/ClientCharSelectState.cs b/Assets/Scripts/Gameplay/GameState/ClientCharSelectState.cs index 199517d27..930af4bec 100644 --- a/Assets/Scripts/Gameplay/GameState/ClientCharSelectState.cs +++ b/Assets/Scripts/Gameplay/GameState/ClientCharSelectState.cs @@ -25,7 +25,10 @@ public class ClientCharSelectState : GameStateBehaviour [SerializeField] NetcodeHooks m_NetcodeHooks; - public override GameState ActiveState { get { return GameState.CharSelect; } } + public override GameState ActiveState + { + get { return GameState.CharSelect; } + } [SerializeField] NetworkCharSelection m_NetworkCharSelection; @@ -38,9 +41,9 @@ public class ClientCharSelectState : GameStateBehaviour [Tooltip("This is triggered when the player presses the \"Ready\" button")] string m_AnimationTriggerOnCharChosen = "BeginRevive"; - [Header("Lobby Seats")] + [Header("Session Seats")] [SerializeField] - [Tooltip("Collection of 8 portrait-boxes, one for each potential lobby member")] + [Tooltip("Collection of 8 portrait-boxes, one for each potential session member")] List m_PlayerSeats; [System.Serializable] @@ -49,6 +52,7 @@ public class ColorAndIndicator public Sprite Indicator; public Color Color; } + [Tooltip("Representational information for each player")] public ColorAndIndicator[] m_IdentifiersForEachPlayerNumber; @@ -60,7 +64,7 @@ public class ColorAndIndicator [Tooltip("Text element for the Ready button")] TextMeshProUGUI m_ReadyButtonText; - [Header("UI Elements for different lobby modes")] + [Header("UI Elements for different session modes")] [SerializeField] [Tooltip("UI elements to turn on when the player hasn't chosen their seat yet. Turned off otherwise!")] List m_UIElementsForNoSeatChosen; @@ -70,8 +74,8 @@ public class ColorAndIndicator List m_UIElementsForSeatChosen; [SerializeField] - [Tooltip("UI elements to turn on when the lobby is closed (and game is about to start). Turned off otherwise!")] - List m_UIElementsForLobbyEnding; + [Tooltip("UI elements to turn on when the session is closed (and game is about to start). Turned off otherwise!")] + List m_UIElementsForSessionEnding; [SerializeField] [Tooltip("UI elements to turn on when there's been a fatal error (and the client cannot proceed). Turned off otherwise!")] @@ -95,20 +99,20 @@ public class ColorAndIndicator Dictionary m_SpawnedCharacterGraphics = new Dictionary(); /// - /// Conceptual modes or stages that the lobby can be in. We don't actually - /// bother to keep track of what LobbyMode we're in at any given time; it's just + /// Conceptual modes or stages that the session can be in. We don't actually + /// bother to keep track of what SessionMode we're in at any given time; it's just /// an abstraction that makes it easier to configure which UI elements should - /// be enabled/disabled in each stage of the lobby. + /// be enabled/disabled in each stage of the session. /// - enum LobbyMode + enum SessionMode { ChooseSeat, // "Choose your seat!" stage SeatChosen, // "Waiting for other players!" stage - LobbyEnding, // "Get ready! Game is starting!" stage + SessionEnding, // "Get ready! Game is starting!" stage FatalError, // "Fatal Error" stage } - Dictionary> m_LobbyUIElementsByMode; + Dictionary> m_SessionUIElementsByMode; [Inject] ConnectionManager m_ConnectionManager; @@ -121,12 +125,12 @@ protected override void Awake() m_NetcodeHooks.OnNetworkSpawnHook += OnNetworkSpawn; m_NetcodeHooks.OnNetworkDespawnHook += OnNetworkDespawn; - m_LobbyUIElementsByMode = new Dictionary>() + m_SessionUIElementsByMode = new Dictionary>() { - { LobbyMode.ChooseSeat, m_UIElementsForNoSeatChosen }, - { LobbyMode.SeatChosen, m_UIElementsForSeatChosen }, - { LobbyMode.LobbyEnding, m_UIElementsForLobbyEnding }, - { LobbyMode.FatalError, m_UIElementsForFatalError }, + { SessionMode.ChooseSeat, m_UIElementsForNoSeatChosen }, + { SessionMode.SeatChosen, m_UIElementsForSeatChosen }, + { SessionMode.SessionEnding, m_UIElementsForSessionEnding }, + { SessionMode.FatalError, m_UIElementsForFatalError }, }; } @@ -148,7 +152,7 @@ protected override void Start() m_PlayerSeats[i].Initialize(i); } - ConfigureUIForLobbyMode(LobbyMode.ChooseSeat); + ConfigureUIForSessionMode(SessionMode.ChooseSeat); UpdateCharacterSelection(NetworkCharSelection.SeatState.Inactive); } @@ -156,8 +160,8 @@ void OnNetworkDespawn() { if (m_NetworkCharSelection) { - m_NetworkCharSelection.IsLobbyClosed.OnValueChanged -= OnLobbyClosedChanged; - m_NetworkCharSelection.LobbyPlayers.OnListChanged -= OnLobbyPlayerStateChanged; + m_NetworkCharSelection.IsSessionClosed.OnValueChanged -= OnSessionClosedChanged; + m_NetworkCharSelection.sessionPlayers.OnListChanged -= OnSessionPlayerStateChanged; } } @@ -169,8 +173,8 @@ void OnNetworkSpawn() } else { - m_NetworkCharSelection.IsLobbyClosed.OnValueChanged += OnLobbyClosedChanged; - m_NetworkCharSelection.LobbyPlayers.OnListChanged += OnLobbyPlayerStateChanged; + m_NetworkCharSelection.IsSessionClosed.OnValueChanged += OnSessionClosedChanged; + m_NetworkCharSelection.sessionPlayers.OnListChanged += OnSessionPlayerStateChanged; } } @@ -185,24 +189,24 @@ void OnAssignedPlayerNumber(int playerNum) void UpdatePlayerCount() { - int count = m_NetworkCharSelection.LobbyPlayers.Count; + int count = m_NetworkCharSelection.sessionPlayers.Count; var pstr = (count > 1) ? "players" : "player"; m_NumPlayersText.text = "" + count + " " + pstr + " connected"; } /// - /// Called by the server when any of the seats in the lobby have changed. (Including ours!) + /// Called by the server when any of the seats in the session have changed. (Including ours!) /// - void OnLobbyPlayerStateChanged(NetworkListEvent changeEvent) + void OnSessionPlayerStateChanged(NetworkListEvent changeEvent) { UpdateSeats(); UpdatePlayerCount(); // now let's find our local player in the list and update the character/info box appropriately int localPlayerIdx = -1; - for (int i = 0; i < m_NetworkCharSelection.LobbyPlayers.Count; ++i) + for (int i = 0; i < m_NetworkCharSelection.sessionPlayers.Count; ++i) { - if (m_NetworkCharSelection.LobbyPlayers[i].ClientId == NetworkManager.Singleton.LocalClientId) + if (m_NetworkCharSelection.sessionPlayers[i].ClientId == NetworkManager.Singleton.LocalClientId) { localPlayerIdx = i; break; @@ -211,27 +215,28 @@ void OnLobbyPlayerStateChanged(NetworkListEvent /// Internal utility that sets the character-graphics and class-info box based on - /// our chosen seat. It also triggers a LobbyMode change when it notices that our seat-state + /// our chosen seat. It also triggers a SessionMode change when it notices that our seat-state /// is LockedIn. /// /// Our current seat state @@ -271,12 +276,13 @@ void UpdateCharacterSelection(NetworkCharSelection.SeatState state, int seatIdx m_ClassInfoBox.ConfigureForClass(m_NetworkCharSelection.AvatarConfiguration[seatIdx].CharacterClass); } } + if (state == NetworkCharSelection.SeatState.LockedIn && !m_HasLocalPlayerLockedIn) { // the local player has locked in their seat choice! Rearrange the UI appropriately // the character should act excited m_CurrentCharacterGraphicsAnimator.SetTrigger(m_AnimationTriggerOnCharChosen); - ConfigureUIForLobbyMode(m_NetworkCharSelection.IsLobbyClosed.Value ? LobbyMode.LobbyEnding : LobbyMode.SeatChosen); + ConfigureUIForSessionMode(m_NetworkCharSelection.IsSessionClosed.Value ? SessionMode.SessionEnding : SessionMode.SeatChosen); m_HasLocalPlayerLockedIn = true; } else if (m_HasLocalPlayerLockedIn && state == NetworkCharSelection.SeatState.Active) @@ -284,7 +290,7 @@ void UpdateCharacterSelection(NetworkCharSelection.SeatState state, int seatIdx // reset character seats if locked in choice was unselected if (m_HasLocalPlayerLockedIn) { - ConfigureUIForLobbyMode(LobbyMode.ChooseSeat); + ConfigureUIForSessionMode(SessionMode.ChooseSeat); m_ClassInfoBox.SetLockedIn(false); m_HasLocalPlayerLockedIn = false; } @@ -297,7 +303,7 @@ void UpdateCharacterSelection(NetworkCharSelection.SeatState state, int seatIdx } /// - /// Internal utility that sets the graphics for the eight lobby-seats (based on their current networked state) + /// Internal utility that sets the graphics for the eight session-seats (based on their current networked state) /// void UpdateSeats() { @@ -305,8 +311,8 @@ void UpdateSeats() // Once they have chosen their class (by "locking in" their seat), other players in that seat are kicked out. // But until a seat is locked in, we need to display each seat as being used by the latest player to choose it. // So we go through all players and figure out who should visually be shown as sitting in that seat. - NetworkCharSelection.LobbyPlayerState[] curSeats = new NetworkCharSelection.LobbyPlayerState[m_PlayerSeats.Count]; - foreach (NetworkCharSelection.LobbyPlayerState playerState in m_NetworkCharSelection.LobbyPlayers) + NetworkCharSelection.SessionPlayerState[] curSeats = new NetworkCharSelection.SessionPlayerState[m_PlayerSeats.Count]; + foreach (NetworkCharSelection.SessionPlayerState playerState in m_NetworkCharSelection.sessionPlayers) { if (playerState.SeatIdx == -1 || playerState.SeatState == NetworkCharSelection.SeatState.Inactive) continue; // this player isn't seated at all! @@ -326,37 +332,37 @@ void UpdateSeats() } /// - /// Called by the server when the lobby closes (because all players are seated and locked in) + /// Called by the server when the session closes (because all players are seated and locked in) /// - void OnLobbyClosedChanged(bool wasLobbyClosed, bool isLobbyClosed) + void OnSessionClosedChanged(bool wasSessionClosed, bool isSessionClosed) { - if (isLobbyClosed) + if (isSessionClosed) { - ConfigureUIForLobbyMode(LobbyMode.LobbyEnding); + ConfigureUIForSessionMode(SessionMode.SessionEnding); } else { if (m_LastSeatSelected == -1) { - ConfigureUIForLobbyMode(LobbyMode.ChooseSeat); + ConfigureUIForSessionMode(SessionMode.ChooseSeat); } else { - ConfigureUIForLobbyMode(LobbyMode.SeatChosen); + ConfigureUIForSessionMode(SessionMode.SeatChosen); m_ClassInfoBox.ConfigureForClass(m_NetworkCharSelection.AvatarConfiguration[m_LastSeatSelected].CharacterClass); } } } /// - /// Turns on the UI elements for a specified "lobby mode", and turns off UI elements for all other modes. - /// It can also disable/enable the lobby seats and the "Ready" button if they are inappropriate for the + /// Turns on the UI elements for a specified "session mode", and turns off UI elements for all other modes. + /// It can also disable/enable the session seats and the "Ready" button if they are inappropriate for the /// given mode. /// - void ConfigureUIForLobbyMode(LobbyMode mode) + void ConfigureUIForSessionMode(SessionMode mode) { // first the easy bit: turn off all the inappropriate ui elements, and turn the appropriate ones on! - foreach (var list in m_LobbyUIElementsByMode.Values) + foreach (var list in m_SessionUIElementsByMode.Values) { foreach (var uiElement in list) { @@ -364,36 +370,38 @@ void ConfigureUIForLobbyMode(LobbyMode mode) } } - foreach (var uiElement in m_LobbyUIElementsByMode[mode]) + foreach (var uiElement in m_SessionUIElementsByMode[mode]) { uiElement.SetActive(true); } - // that finishes the easy bit. Next, each lobby mode might also need to configure the lobby seats and class-info box. + // that finishes the easy bit. Next, each session mode might also need to configure the session seats and class-info box. bool isSeatsDisabledInThisMode = false; switch (mode) { - case LobbyMode.ChooseSeat: + case SessionMode.ChooseSeat: if (m_LastSeatSelected == -1) { if (m_CurrentCharacterGraphics) { m_CurrentCharacterGraphics.gameObject.SetActive(false); } + m_ClassInfoBox.ConfigureForNoSelection(); } + m_ReadyButtonText.text = "READY!"; break; - case LobbyMode.SeatChosen: + case SessionMode.SeatChosen: isSeatsDisabledInThisMode = true; m_ClassInfoBox.SetLockedIn(true); m_ReadyButtonText.text = "UNREADY"; break; - case LobbyMode.FatalError: + case SessionMode.FatalError: isSeatsDisabledInThisMode = true; m_ClassInfoBox.ConfigureForNoSelection(); break; - case LobbyMode.LobbyEnding: + case SessionMode.SessionEnding: isSeatsDisabledInThisMode = true; m_ClassInfoBox.ConfigureForNoSelection(); break; @@ -405,7 +413,6 @@ void ConfigureUIForLobbyMode(LobbyMode mode) // disable interaction if seat is already locked or all seats disabled seat.SetDisableInteraction(seat.IsLocked() || isSeatsDisabledInThisMode); } - } /// @@ -442,6 +449,5 @@ GameObject GetCharacterGraphics(Avatar avatar) return characterGraphics; } - } } diff --git a/Assets/Scripts/Gameplay/GameState/ClientMainMenuState.cs b/Assets/Scripts/Gameplay/GameState/ClientMainMenuState.cs index 53da328ae..1f0444f1e 100644 --- a/Assets/Scripts/Gameplay/GameState/ClientMainMenuState.cs +++ b/Assets/Scripts/Gameplay/GameState/ClientMainMenuState.cs @@ -2,10 +2,9 @@ using Unity.BossRoom.Gameplay.Configuration; using Unity.BossRoom.Gameplay.UI; using Unity.BossRoom.UnityServices.Auth; -using Unity.BossRoom.UnityServices.Lobbies; +using Unity.BossRoom.UnityServices.Sessions; using Unity.BossRoom.Utils; using Unity.Services.Authentication; -using Unity.Services.Core; using UnityEngine; using UnityEngine.UI; using VContainer; @@ -27,11 +26,11 @@ public class ClientMainMenuState : GameStateBehaviour [SerializeField] NameGenerationData m_NameGenerationData; [SerializeField] - LobbyUIMediator m_LobbyUIMediator; + SessionUIMediator m_SessionUIMediator; [SerializeField] IPUIMediator m_IPUIMediator; [SerializeField] - Button m_LobbyButton; + Button m_SessionButton; [SerializeField] GameObject m_SignInSpinner; [SerializeField] @@ -42,9 +41,9 @@ public class ClientMainMenuState : GameStateBehaviour [Inject] AuthenticationServiceFacade m_AuthServiceFacade; [Inject] - LocalLobbyUser m_LocalUser; + LocalSessionUser m_LocalUser; [Inject] - LocalLobby m_LocalLobby; + LocalSession m_LocalSession; [Inject] ProfileManager m_ProfileManager; @@ -52,8 +51,8 @@ protected override void Awake() { base.Awake(); - m_LobbyButton.interactable = false; - m_LobbyUIMediator.Hide(); + m_SessionButton.interactable = false; + m_SessionUIMediator.Hide(); if (string.IsNullOrEmpty(Application.cloudProjectId)) { @@ -68,7 +67,7 @@ protected override void Configure(IContainerBuilder builder) { base.Configure(builder); builder.RegisterComponent(m_NameGenerationData); - builder.RegisterComponent(m_LobbyUIMediator); + builder.RegisterComponent(m_SessionUIMediator); builder.RegisterComponent(m_IPUIMediator); } @@ -91,23 +90,18 @@ private async void TrySignIn() private void OnAuthSignIn() { - m_LobbyButton.interactable = true; + m_SessionButton.interactable = true; m_UGSSetupTooltipDetector.enabled = false; m_SignInSpinner.SetActive(false); Debug.Log($"Signed in. Unity Player ID {AuthenticationService.Instance.PlayerId}"); - - m_LocalUser.ID = AuthenticationService.Instance.PlayerId; - - // The local LobbyUser object will be hooked into UI before the LocalLobby is populated during lobby join, so the LocalLobby must know about it already when that happens. - m_LocalLobby.AddUser(m_LocalUser); } private void OnSignInFailed() { - if (m_LobbyButton) + if (m_SessionButton) { - m_LobbyButton.interactable = false; + m_SessionButton.interactable = false; m_UGSSetupTooltipDetector.enabled = true; } @@ -125,30 +119,30 @@ protected override void OnDestroy() async void OnProfileChanged() { - m_LobbyButton.interactable = false; + m_SessionButton.interactable = false; m_SignInSpinner.SetActive(true); await m_AuthServiceFacade.SwitchProfileAndReSignInAsync(m_ProfileManager.Profile); - m_LobbyButton.interactable = true; + m_SessionButton.interactable = true; m_SignInSpinner.SetActive(false); Debug.Log($"Signed in. Unity Player ID {AuthenticationService.Instance.PlayerId}"); - // Updating LocalUser and LocalLobby - m_LocalLobby.RemoveUser(m_LocalUser); + // Updating LocalUser and LocalSession + m_LocalSession.RemoveUser(m_LocalUser); m_LocalUser.ID = AuthenticationService.Instance.PlayerId; - m_LocalLobby.AddUser(m_LocalUser); + m_LocalSession.AddUser(m_LocalUser); } public void OnStartClicked() { - m_LobbyUIMediator.ToggleJoinLobbyUI(); - m_LobbyUIMediator.Show(); + m_SessionUIMediator.ToggleJoinSessionUI(); + m_SessionUIMediator.Show(); } public void OnDirectIPClicked() { - m_LobbyUIMediator.Hide(); + m_SessionUIMediator.Hide(); m_IPUIMediator.Show(); } diff --git a/Assets/Scripts/Gameplay/GameState/NetworkCharSelection.cs b/Assets/Scripts/Gameplay/GameState/NetworkCharSelection.cs index ddc399019..b3d0f1d2d 100644 --- a/Assets/Scripts/Gameplay/GameState/NetworkCharSelection.cs +++ b/Assets/Scripts/Gameplay/GameState/NetworkCharSelection.cs @@ -18,7 +18,7 @@ public enum SeatState : byte } /// - /// Describes one of the players in the lobby, and their current character-select status. + /// Describes one of the players in the session, and their current character-select status. /// /// /// Putting FixedString inside an INetworkSerializeByMemcpy struct is not recommended because it will lose the @@ -26,7 +26,7 @@ public enum SeatState : byte /// or through INetworkSerializable will use 4 bytes of bandwidth, but inside an INetworkSerializeByMemcpy, that /// same empty value would consume 132 bytes of bandwidth. /// - public struct LobbyPlayerState : INetworkSerializable, IEquatable + public struct SessionPlayerState : INetworkSerializable, IEquatable { public ulong ClientId; @@ -39,7 +39,7 @@ public struct LobbyPlayerState : INetworkSerializable, IEquatable(BufferSerializer serializer) where T : IReade serializer.SerializeValue(ref LastChangeTime); } - public bool Equals(LobbyPlayerState other) + public bool Equals(SessionPlayerState other) { return ClientId == other.ClientId && m_PlayerName.Equals(other.m_PlayerName) && @@ -78,27 +78,27 @@ public bool Equals(LobbyPlayerState other) } } - private NetworkList m_LobbyPlayers; + private NetworkList m_SessionPlayers; public Avatar[] AvatarConfiguration; private void Awake() { - m_LobbyPlayers = new NetworkList(); + m_SessionPlayers = new NetworkList(); } /// - /// Current state of all players in the lobby. + /// Current state of all players in the session. /// - public NetworkList LobbyPlayers => m_LobbyPlayers; + public NetworkList sessionPlayers => m_SessionPlayers; /// - /// When this becomes true, the lobby is closed and in process of terminating (switching to gameplay). + /// When this becomes true, the session is closed and in process of terminating (switching to gameplay). /// - public NetworkVariable IsLobbyClosed { get; } = new NetworkVariable(false); + public NetworkVariable IsSessionClosed { get; } = new NetworkVariable(false); /// - /// Server notification when a client requests a different lobby-seat, or locks in their seat choice + /// Server notification when a client requests a different session-seat, or locks in their seat choice /// public event Action OnClientChangedSeat; diff --git a/Assets/Scripts/Gameplay/GameState/ServerCharSelectState.cs b/Assets/Scripts/Gameplay/GameState/ServerCharSelectState.cs index 3d7847167..3bdbc56f8 100644 --- a/Assets/Scripts/Gameplay/GameState/ServerCharSelectState.cs +++ b/Assets/Scripts/Gameplay/GameState/ServerCharSelectState.cs @@ -23,7 +23,7 @@ public class ServerCharSelectState : GameStateBehaviour public override GameState ActiveState => GameState.CharSelect; public NetworkCharSelection networkCharSelection { get; private set; } - Coroutine m_WaitToEndLobbyCoroutine; + Coroutine m_WaitToEndSessionCoroutine; [Inject] ConnectionManager m_ConnectionManager; @@ -50,13 +50,13 @@ protected override void OnDestroy() void OnClientChangedSeat(ulong clientId, int newSeatIdx, bool lockedIn) { - int idx = FindLobbyPlayerIdx(clientId); + int idx = FindSessionPlayerIdx(clientId); if (idx == -1) { - throw new Exception($"OnClientChangedSeat: client ID {clientId} is not a lobby player and cannot change seats! Shouldn't be here!"); + throw new Exception($"OnClientChangedSeat: client ID {clientId} is not a Session player and cannot change seats! Shouldn't be here!"); } - if (networkCharSelection.IsLobbyClosed.Value) + if (networkCharSelection.IsSessionClosed.Value) { // The user tried to change their class after everything was locked in... too late! Discard this choice return; @@ -70,15 +70,15 @@ void OnClientChangedSeat(ulong clientId, int newSeatIdx, bool lockedIn) else { // see if someone has already locked-in that seat! If so, too late... discard this choice - foreach (NetworkCharSelection.LobbyPlayerState playerInfo in networkCharSelection.LobbyPlayers) + foreach (NetworkCharSelection.SessionPlayerState playerInfo in networkCharSelection.sessionPlayers) { if (playerInfo.ClientId != clientId && playerInfo.SeatIdx == newSeatIdx && playerInfo.SeatState == NetworkCharSelection.SeatState.LockedIn) { // somebody already locked this choice in. Stop! // Instead of granting lock request, change this player to Inactive state. - networkCharSelection.LobbyPlayers[idx] = new NetworkCharSelection.LobbyPlayerState(clientId, - networkCharSelection.LobbyPlayers[idx].PlayerName, - networkCharSelection.LobbyPlayers[idx].PlayerNumber, + networkCharSelection.sessionPlayers[idx] = new NetworkCharSelection.SessionPlayerState(clientId, + networkCharSelection.sessionPlayers[idx].PlayerName, + networkCharSelection.sessionPlayers[idx].PlayerNumber, NetworkCharSelection.SeatState.Inactive); // then early out @@ -87,9 +87,9 @@ void OnClientChangedSeat(ulong clientId, int newSeatIdx, bool lockedIn) } } - networkCharSelection.LobbyPlayers[idx] = new NetworkCharSelection.LobbyPlayerState(clientId, - networkCharSelection.LobbyPlayers[idx].PlayerName, - networkCharSelection.LobbyPlayers[idx].PlayerNumber, + networkCharSelection.sessionPlayers[idx] = new NetworkCharSelection.SessionPlayerState(clientId, + networkCharSelection.sessionPlayers[idx].PlayerName, + networkCharSelection.sessionPlayers[idx].PlayerNumber, lockedIn ? NetworkCharSelection.SeatState.LockedIn : NetworkCharSelection.SeatState.Active, newSeatIdx, Time.time); @@ -98,31 +98,31 @@ void OnClientChangedSeat(ulong clientId, int newSeatIdx, bool lockedIn) { // to help the clients visually keep track of who's in what seat, we'll "kick out" any other players // who were also in that seat. (Those players didn't click "Ready!" fast enough, somebody else took their seat!) - for (int i = 0; i < networkCharSelection.LobbyPlayers.Count; ++i) + for (int i = 0; i < networkCharSelection.sessionPlayers.Count; ++i) { - if (networkCharSelection.LobbyPlayers[i].SeatIdx == newSeatIdx && i != idx) + if (networkCharSelection.sessionPlayers[i].SeatIdx == newSeatIdx && i != idx) { // change this player to Inactive state. - networkCharSelection.LobbyPlayers[i] = new NetworkCharSelection.LobbyPlayerState( - networkCharSelection.LobbyPlayers[i].ClientId, - networkCharSelection.LobbyPlayers[i].PlayerName, - networkCharSelection.LobbyPlayers[i].PlayerNumber, + networkCharSelection.sessionPlayers[i] = new NetworkCharSelection.SessionPlayerState( + networkCharSelection.sessionPlayers[i].ClientId, + networkCharSelection.sessionPlayers[i].PlayerName, + networkCharSelection.sessionPlayers[i].PlayerNumber, NetworkCharSelection.SeatState.Inactive); } } } - CloseLobbyIfReady(); + CloseSessionIfReady(); } /// - /// Returns the index of a client in the master LobbyPlayer list, or -1 if not found + /// Returns the index of a client in the master SessionPlayer list, or -1 if not found /// - int FindLobbyPlayerIdx(ulong clientId) + int FindSessionPlayerIdx(ulong clientId) { - for (int i = 0; i < networkCharSelection.LobbyPlayers.Count; ++i) + for (int i = 0; i < networkCharSelection.sessionPlayers.Count; ++i) { - if (networkCharSelection.LobbyPlayers[i].ClientId == clientId) + if (networkCharSelection.sessionPlayers[i].ClientId == clientId) return i; } return -1; @@ -130,41 +130,41 @@ int FindLobbyPlayerIdx(ulong clientId) /// /// Looks through all our connections and sees if everyone has locked in their choice; - /// if so, we lock in the whole lobby, save state, and begin the transition to gameplay + /// if so, we lock in the whole Session, save state, and begin the transition to gameplay /// - void CloseLobbyIfReady() + void CloseSessionIfReady() { - foreach (NetworkCharSelection.LobbyPlayerState playerInfo in networkCharSelection.LobbyPlayers) + foreach (NetworkCharSelection.SessionPlayerState playerInfo in networkCharSelection.sessionPlayers) { if (playerInfo.SeatState != NetworkCharSelection.SeatState.LockedIn) return; // nope, at least one player isn't locked in yet! } // everybody's ready at the same time! Lock it down! - networkCharSelection.IsLobbyClosed.Value = true; + networkCharSelection.IsSessionClosed.Value = true; // remember our choices so the next scene can use the info - SaveLobbyResults(); + SaveSessionResults(); // Delay a few seconds to give the UI time to react, then switch scenes - m_WaitToEndLobbyCoroutine = StartCoroutine(WaitToEndLobby()); + m_WaitToEndSessionCoroutine = StartCoroutine(WaitToEndSession()); } /// - /// Cancels the process of closing the lobby, so that if a new player joins, they are able to chose a character. + /// Cancels the process of closing the Session, so that if a new player joins, they are able to choose a character. /// - void CancelCloseLobby() + void CancelCloseSession() { - if (m_WaitToEndLobbyCoroutine != null) + if (m_WaitToEndSessionCoroutine != null) { - StopCoroutine(m_WaitToEndLobbyCoroutine); + StopCoroutine(m_WaitToEndSessionCoroutine); } - networkCharSelection.IsLobbyClosed.Value = false; + networkCharSelection.IsSessionClosed.Value = false; } - void SaveLobbyResults() + void SaveSessionResults() { - foreach (NetworkCharSelection.LobbyPlayerState playerInfo in networkCharSelection.LobbyPlayers) + foreach (NetworkCharSelection.SessionPlayerState playerInfo in networkCharSelection.sessionPlayers) { var playerNetworkObject = NetworkManager.Singleton.SpawnManager.GetPlayerNetworkObject(playerInfo.ClientId); @@ -178,7 +178,7 @@ void SaveLobbyResults() } } - IEnumerator WaitToEndLobby() + IEnumerator WaitToEndSession() { yield return new WaitForSeconds(3); SceneLoaderWrapper.Instance.LoadScene("BossRoom", useNetworkSceneManager: true); @@ -216,7 +216,7 @@ void OnSceneEvent(SceneEvent sceneEvent) { // We need to filter out the event that are not a client has finished loading the scene if (sceneEvent.SceneEventType != SceneEventType.LoadComplete) return; - // When the client finishes loading the Lobby Map, we will need to Seat it + // When the client finishes loading the Session Map, we will need to Seat it SeatNewPlayer(sceneEvent.ClientId); } @@ -229,14 +229,14 @@ int GetAvailablePlayerNumber() return possiblePlayerNumber; } } - // we couldn't get a Player# for this person... which means the lobby is full! + // we couldn't get a Player# for this person... which means the Session is full! return -1; } bool IsPlayerNumberAvailable(int playerNumber) { bool found = false; - foreach (NetworkCharSelection.LobbyPlayerState playerState in networkCharSelection.LobbyPlayers) + foreach (NetworkCharSelection.SessionPlayerState playerState in networkCharSelection.sessionPlayers) { if (playerState.PlayerNumber == playerNumber) { @@ -250,10 +250,10 @@ bool IsPlayerNumberAvailable(int playerNumber) void SeatNewPlayer(ulong clientId) { - // If lobby is closing and waiting to start the game, cancel to allow that new player to select a character - if (networkCharSelection.IsLobbyClosed.Value) + // If Session is closing and waiting to start the game, cancel to allow that new player to select a character + if (networkCharSelection.IsSessionClosed.Value) { - CancelCloseLobby(); + CancelCloseSession(); } SessionPlayerData? sessionPlayerData = SessionManager.Instance.GetPlayerData(clientId); @@ -271,7 +271,7 @@ void SeatNewPlayer(ulong clientId) throw new Exception($"we shouldn't be here, connection approval should have refused this connection already for client ID {clientId} and player num {playerData.PlayerNumber}"); } - networkCharSelection.LobbyPlayers.Add(new NetworkCharSelection.LobbyPlayerState(clientId, playerData.PlayerName, playerData.PlayerNumber, NetworkCharSelection.SeatState.Inactive)); + networkCharSelection.sessionPlayers.Add(new NetworkCharSelection.SessionPlayerState(clientId, playerData.PlayerName, playerData.PlayerNumber, NetworkCharSelection.SeatState.Inactive)); SessionManager.Instance.SetPlayerData(clientId, playerData); } } @@ -279,19 +279,19 @@ void SeatNewPlayer(ulong clientId) void OnClientDisconnectCallback(ulong clientId) { // clear this client's PlayerNumber and any associated visuals (so other players know they're gone). - for (int i = 0; i < networkCharSelection.LobbyPlayers.Count; ++i) + for (int i = 0; i < networkCharSelection.sessionPlayers.Count; ++i) { - if (networkCharSelection.LobbyPlayers[i].ClientId == clientId) + if (networkCharSelection.sessionPlayers[i].ClientId == clientId) { - networkCharSelection.LobbyPlayers.RemoveAt(i); + networkCharSelection.sessionPlayers.RemoveAt(i); break; } } - if (!networkCharSelection.IsLobbyClosed.Value) + if (!networkCharSelection.IsSessionClosed.Value) { - // If the lobby is not already closing, close if the remaining players are all ready - CloseLobbyIfReady(); + // If the Session is not already closing, close if the remaining players are all ready + CloseSessionIfReady(); } } } diff --git a/Assets/Scripts/Gameplay/UI/Lobby/LobbyListItemUI.cs b/Assets/Scripts/Gameplay/UI/Lobby/LobbyListItemUI.cs deleted file mode 100644 index 62733cda3..000000000 --- a/Assets/Scripts/Gameplay/UI/Lobby/LobbyListItemUI.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System; -using TMPro; -using Unity.BossRoom.UnityServices.Lobbies; -using UnityEngine; -using VContainer; - -namespace Unity.BossRoom.Gameplay.UI -{ - /// - /// An individual Lobby UI in the list of available lobbies - /// - public class LobbyListItemUI : MonoBehaviour - { - [SerializeField] TextMeshProUGUI m_lobbyNameText; - [SerializeField] TextMeshProUGUI m_lobbyCountText; - - [Inject] LobbyUIMediator m_LobbyUIMediator; - - LocalLobby m_Data; - - - public void SetData(LocalLobby data) - { - m_Data = data; - m_lobbyNameText.SetText(data.LobbyName); - m_lobbyCountText.SetText($"{data.PlayerCount}/{data.MaxPlayerCount}"); - } - - public void OnClick() - { - m_LobbyUIMediator.JoinLobbyRequest(m_Data); - } - } -} diff --git a/Assets/Scripts/Gameplay/UI/RoomNameBox.cs b/Assets/Scripts/Gameplay/UI/RoomNameBox.cs index 06525f6b3..ecc4460b4 100644 --- a/Assets/Scripts/Gameplay/UI/RoomNameBox.cs +++ b/Assets/Scripts/Gameplay/UI/RoomNameBox.cs @@ -1,6 +1,6 @@ using System; using TMPro; -using Unity.BossRoom.UnityServices.Lobbies; +using Unity.BossRoom.UnityServices.Sessions; using UnityEngine; using UnityEngine.UI; using VContainer; @@ -14,32 +14,32 @@ public class RoomNameBox : MonoBehaviour [SerializeField] Button m_CopyToClipboardButton; - LocalLobby m_LocalLobby; - string m_LobbyCode; + LocalSession m_LocalSession; + string m_SessionCode; [Inject] - private void InjectDependencies(LocalLobby localLobby) + private void InjectDependencies(LocalSession localSession) { - m_LocalLobby = localLobby; - m_LocalLobby.changed += UpdateUI; + m_LocalSession = localSession; + m_LocalSession.changed += UpdateUI; } void Awake() { - UpdateUI(m_LocalLobby); + UpdateUI(m_LocalSession); } private void OnDestroy() { - m_LocalLobby.changed -= UpdateUI; + m_LocalSession.changed -= UpdateUI; } - private void UpdateUI(LocalLobby localLobby) + private void UpdateUI(LocalSession localSession) { - if (!string.IsNullOrEmpty(localLobby.LobbyCode)) + if (!string.IsNullOrEmpty(localSession.SessionCode)) { - m_LobbyCode = localLobby.LobbyCode; - m_RoomNameText.text = $"Lobby Code: {m_LobbyCode}"; + m_SessionCode = localSession.SessionCode; + m_RoomNameText.text = $"Session Code: {m_SessionCode}"; gameObject.SetActive(true); m_CopyToClipboardButton.gameObject.SetActive(true); } @@ -51,7 +51,7 @@ private void UpdateUI(LocalLobby localLobby) public void CopyToClipboard() { - GUIUtility.systemCopyBuffer = m_LobbyCode; + GUIUtility.systemCopyBuffer = m_SessionCode; } } } diff --git a/Assets/Scripts/Gameplay/UI/Lobby.meta b/Assets/Scripts/Gameplay/UI/Session.meta similarity index 100% rename from Assets/Scripts/Gameplay/UI/Lobby.meta rename to Assets/Scripts/Gameplay/UI/Session.meta diff --git a/Assets/Scripts/Gameplay/UI/Lobby/LobbyCreationUI.cs b/Assets/Scripts/Gameplay/UI/Session/SessionCreationUI.cs similarity index 74% rename from Assets/Scripts/Gameplay/UI/Lobby/LobbyCreationUI.cs rename to Assets/Scripts/Gameplay/UI/Session/SessionCreationUI.cs index 4f21410ec..17388c2ed 100644 --- a/Assets/Scripts/Gameplay/UI/Lobby/LobbyCreationUI.cs +++ b/Assets/Scripts/Gameplay/UI/Session/SessionCreationUI.cs @@ -5,13 +5,13 @@ namespace Unity.BossRoom.Gameplay.UI { - public class LobbyCreationUI : MonoBehaviour + public class SessionCreationUI : MonoBehaviour { - [SerializeField] InputField m_LobbyNameInputField; + [SerializeField] InputField m_SessionNameInputField; [SerializeField] GameObject m_LoadingIndicatorObject; [SerializeField] Toggle m_IsPrivate; [SerializeField] CanvasGroup m_CanvasGroup; - [Inject] LobbyUIMediator m_LobbyUIMediator; + [Inject] SessionUIMediator m_SessionUIMediator; void Awake() { @@ -25,7 +25,7 @@ void EnableUnityRelayUI() public void OnCreateClick() { - m_LobbyUIMediator.CreateLobbyRequest(m_LobbyNameInputField.text, m_IsPrivate.isOn); + m_SessionUIMediator.CreateSessionRequest(m_SessionNameInputField.text, m_IsPrivate.isOn); } public void Show() diff --git a/Assets/Scripts/Gameplay/UI/Lobby/LobbyCreationUI.cs.meta b/Assets/Scripts/Gameplay/UI/Session/SessionCreationUI.cs.meta similarity index 100% rename from Assets/Scripts/Gameplay/UI/Lobby/LobbyCreationUI.cs.meta rename to Assets/Scripts/Gameplay/UI/Session/SessionCreationUI.cs.meta diff --git a/Assets/Scripts/Gameplay/UI/Lobby/LobbyJoiningUI.cs b/Assets/Scripts/Gameplay/UI/Session/SessionJoiningUI.cs similarity index 53% rename from Assets/Scripts/Gameplay/UI/Lobby/LobbyJoiningUI.cs rename to Assets/Scripts/Gameplay/UI/Session/SessionJoiningUI.cs index fdff41faa..1d9757456 100644 --- a/Assets/Scripts/Gameplay/UI/Lobby/LobbyJoiningUI.cs +++ b/Assets/Scripts/Gameplay/UI/Session/SessionJoiningUI.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Text.RegularExpressions; using Unity.BossRoom.Infrastructure; -using Unity.BossRoom.UnityServices.Lobbies; +using Unity.BossRoom.UnityServices.Sessions; using UnityEngine; using UnityEngine.UI; using VContainer; @@ -10,31 +10,31 @@ namespace Unity.BossRoom.Gameplay.UI { /// - /// Handles the list of LobbyListItemUIs and ensures it stays synchronized with the lobby list from the service. + /// Handles the list of SessionListItemUIs and ensures it stays synchronized with the Session list from the service. /// - public class LobbyJoiningUI : MonoBehaviour + public class SessionJoiningUI : MonoBehaviour { [SerializeField] - LobbyListItemUI m_LobbyListItemPrototype; + SessionListItemUI m_SessionListItemPrototype; [SerializeField] InputField m_JoinCodeField; [SerializeField] CanvasGroup m_CanvasGroup; [SerializeField] - Graphic m_EmptyLobbyListLabel; + Graphic m_EmptySessionListLabel; [SerializeField] - Button m_JoinLobbyButton; + Button m_JoinSessionButton; IObjectResolver m_Container; - LobbyUIMediator m_LobbyUIMediator; + SessionUIMediator m_SessionUIMediator; UpdateRunner m_UpdateRunner; - ISubscriber m_LocalLobbiesRefreshedSub; + ISubscriber m_LocalSessionsRefreshedSub; - List m_LobbyListItems = new List(); + List m_SessionListItems = new List(); void Awake() { - m_LobbyListItemPrototype.gameObject.SetActive(false); + m_SessionListItemPrototype.gameObject.SetActive(false); } void OnDisable() @@ -47,24 +47,24 @@ void OnDisable() void OnDestroy() { - if (m_LocalLobbiesRefreshedSub != null) + if (m_LocalSessionsRefreshedSub != null) { - m_LocalLobbiesRefreshedSub.Unsubscribe(UpdateUI); + m_LocalSessionsRefreshedSub.Unsubscribe(UpdateUI); } } [Inject] void InjectDependenciesAndInitialize( IObjectResolver container, - LobbyUIMediator lobbyUIMediator, + SessionUIMediator sessionUIMediator, UpdateRunner updateRunner, - ISubscriber localLobbiesRefreshedSub) + ISubscriber localSessionsRefreshedSub) { m_Container = container; - m_LobbyUIMediator = lobbyUIMediator; + m_SessionUIMediator = sessionUIMediator; m_UpdateRunner = updateRunner; - m_LocalLobbiesRefreshedSub = localLobbiesRefreshedSub; - m_LocalLobbiesRefreshedSub.Subscribe(UpdateUI); + m_LocalSessionsRefreshedSub = localSessionsRefreshedSub; + m_LocalSessionsRefreshedSub.Subscribe(UpdateUI); } /// @@ -73,7 +73,7 @@ void InjectDependenciesAndInitialize( public void OnJoinCodeInputTextChanged() { m_JoinCodeField.text = SanitizeJoinCode(m_JoinCodeField.text); - m_JoinLobbyButton.interactable = m_JoinCodeField.text.Length > 0; + m_JoinSessionButton.interactable = m_JoinCodeField.text.Length > 0; } string SanitizeJoinCode(string dirtyString) @@ -83,59 +83,59 @@ string SanitizeJoinCode(string dirtyString) public void OnJoinButtonPressed() { - m_LobbyUIMediator.JoinLobbyWithCodeRequest(SanitizeJoinCode(m_JoinCodeField.text)); + m_SessionUIMediator.JoinSessionWithCodeRequest(SanitizeJoinCode(m_JoinCodeField.text)); } void PeriodicRefresh(float _) { //this is a soft refresh without needing to lock the UI and such - m_LobbyUIMediator.QueryLobbiesRequest(false); + m_SessionUIMediator.QuerySessionRequest(false); } public void OnRefresh() { - m_LobbyUIMediator.QueryLobbiesRequest(true); + m_SessionUIMediator.QuerySessionRequest(true); } - void UpdateUI(LobbyListFetchedMessage message) + void UpdateUI(SessionListFetchedMessage message) { - EnsureNumberOfActiveUISlots(message.LocalLobbies.Count); + EnsureNumberOfActiveUISlots(message.LocalSessions.Count); - for (var i = 0; i < message.LocalLobbies.Count; i++) + for (var i = 0; i < message.LocalSessions.Count; i++) { - var localLobby = message.LocalLobbies[i]; - m_LobbyListItems[i].SetData(localLobby); + var localSession = message.LocalSessions[i]; + m_SessionListItems[i].SetData(localSession); } - if (message.LocalLobbies.Count == 0) + if (message.LocalSessions.Count == 0) { - m_EmptyLobbyListLabel.enabled = true; + m_EmptySessionListLabel.enabled = true; } else { - m_EmptyLobbyListLabel.enabled = false; + m_EmptySessionListLabel.enabled = false; } } void EnsureNumberOfActiveUISlots(int requiredNumber) { - int delta = requiredNumber - m_LobbyListItems.Count; + int delta = requiredNumber - m_SessionListItems.Count; for (int i = 0; i < delta; i++) { - m_LobbyListItems.Add(CreateLobbyListItem()); + m_SessionListItems.Add(CreateSessionListItem()); } - for (int i = 0; i < m_LobbyListItems.Count; i++) + for (int i = 0; i < m_SessionListItems.Count; i++) { - m_LobbyListItems[i].gameObject.SetActive(i < requiredNumber); + m_SessionListItems[i].gameObject.SetActive(i < requiredNumber); } } - LobbyListItemUI CreateLobbyListItem() + SessionListItemUI CreateSessionListItem() { - var listItem = Instantiate(m_LobbyListItemPrototype.gameObject, m_LobbyListItemPrototype.transform.parent) - .GetComponent(); + var listItem = Instantiate(m_SessionListItemPrototype.gameObject, m_SessionListItemPrototype.transform.parent) + .GetComponent(); listItem.gameObject.SetActive(true); m_Container.Inject(listItem); @@ -145,7 +145,7 @@ LobbyListItemUI CreateLobbyListItem() public void OnQuickJoinClicked() { - m_LobbyUIMediator.QuickJoinRequest(); + m_SessionUIMediator.QuickJoinRequest(); } public void Show() diff --git a/Assets/Scripts/Gameplay/UI/Lobby/LobbyJoiningUI.cs.meta b/Assets/Scripts/Gameplay/UI/Session/SessionJoiningUI.cs.meta similarity index 100% rename from Assets/Scripts/Gameplay/UI/Lobby/LobbyJoiningUI.cs.meta rename to Assets/Scripts/Gameplay/UI/Session/SessionJoiningUI.cs.meta diff --git a/Assets/Scripts/Gameplay/UI/Session/SessionListItemUI.cs b/Assets/Scripts/Gameplay/UI/Session/SessionListItemUI.cs new file mode 100644 index 000000000..63804e964 --- /dev/null +++ b/Assets/Scripts/Gameplay/UI/Session/SessionListItemUI.cs @@ -0,0 +1,36 @@ +using System; +using TMPro; +using Unity.Services.Multiplayer; +using UnityEngine; +using VContainer; + +namespace Unity.BossRoom.Gameplay.UI +{ + /// + /// An individual Session UI in the list of available Sessions. + /// + public class SessionListItemUI : MonoBehaviour + { + [SerializeField] + TextMeshProUGUI m_SessionNameText; + [SerializeField] + TextMeshProUGUI m_SessionCountText; + + [Inject] + SessionUIMediator m_SessionUIMediator; + + ISessionInfo m_Data; + + public void SetData(ISessionInfo data) + { + m_Data = data; + m_SessionNameText.SetText(data.Name); + m_SessionCountText.SetText($"{data.MaxPlayers - data.AvailableSlots}/{data.MaxPlayers}"); + } + + public void OnClick() + { + m_SessionUIMediator.JoinSessionRequest(m_Data); + } + } +} diff --git a/Assets/Scripts/Gameplay/UI/Lobby/LobbyListItemUI.cs.meta b/Assets/Scripts/Gameplay/UI/Session/SessionListItemUI.cs.meta similarity index 100% rename from Assets/Scripts/Gameplay/UI/Lobby/LobbyListItemUI.cs.meta rename to Assets/Scripts/Gameplay/UI/Session/SessionListItemUI.cs.meta diff --git a/Assets/Scripts/Gameplay/UI/Lobby/LobbyUIMediator.cs b/Assets/Scripts/Gameplay/UI/Session/SessionUIMediator.cs similarity index 50% rename from Assets/Scripts/Gameplay/UI/Lobby/LobbyUIMediator.cs rename to Assets/Scripts/Gameplay/UI/Session/SessionUIMediator.cs index d79d7645b..d3d3331eb 100644 --- a/Assets/Scripts/Gameplay/UI/Lobby/LobbyUIMediator.cs +++ b/Assets/Scripts/Gameplay/UI/Session/SessionUIMediator.cs @@ -4,41 +4,54 @@ using Unity.BossRoom.ConnectionManagement; using Unity.BossRoom.Infrastructure; using Unity.BossRoom.UnityServices.Auth; -using Unity.BossRoom.UnityServices.Lobbies; +using Unity.BossRoom.UnityServices.Sessions; using Unity.Services.Core; +using Unity.Services.Multiplayer; using UnityEngine; using VContainer; namespace Unity.BossRoom.Gameplay.UI { - public class LobbyUIMediator : MonoBehaviour + public class SessionUIMediator : MonoBehaviour { - [SerializeField] CanvasGroup m_CanvasGroup; - [SerializeField] LobbyJoiningUI m_LobbyJoiningUI; - [SerializeField] LobbyCreationUI m_LobbyCreationUI; - [SerializeField] UITinter m_JoinToggleHighlight; - [SerializeField] UITinter m_JoinToggleTabBlocker; - [SerializeField] UITinter m_CreateToggleHighlight; - [SerializeField] UITinter m_CreateToggleTabBlocker; - [SerializeField] TextMeshProUGUI m_PlayerNameLabel; - [SerializeField] GameObject m_LoadingSpinner; + [SerializeField] + CanvasGroup m_CanvasGroup; + [SerializeField] + SessionJoiningUI m_SessionJoiningUI; + [SerializeField] + SessionCreationUI m_SessionCreationUI; + [SerializeField] + UITinter m_JoinToggleHighlight; + [SerializeField] + UITinter m_JoinToggleTabBlocker; + [SerializeField] + UITinter m_CreateToggleHighlight; + [SerializeField] + UITinter m_CreateToggleTabBlocker; + [SerializeField] + TextMeshProUGUI m_PlayerNameLabel; + [SerializeField] + GameObject m_LoadingSpinner; AuthenticationServiceFacade m_AuthenticationServiceFacade; - LobbyServiceFacade m_LobbyServiceFacade; - LocalLobbyUser m_LocalUser; - LocalLobby m_LocalLobby; + MultiplayerServicesFacade m_MultiplayerServicesFacade; + LocalSessionUser m_LocalUser; + LocalSession m_LocalSession; NameGenerationData m_NameGenerationData; ConnectionManager m_ConnectionManager; ISubscriber m_ConnectStatusSubscriber; - const string k_DefaultLobbyName = "no-name"; + const string k_DefaultSessionName = "no-name"; + const int k_MaxPlayers = 8; + + ISession m_Session; [Inject] void InjectDependenciesAndInitialize( AuthenticationServiceFacade authenticationServiceFacade, - LobbyServiceFacade lobbyServiceFacade, - LocalLobbyUser localUser, - LocalLobby localLobby, + MultiplayerServicesFacade multiplayerServicesFacade, + LocalSessionUser localUser, + LocalSession localSession, NameGenerationData nameGenerationData, ISubscriber connectStatusSub, ConnectionManager connectionManager @@ -47,8 +60,8 @@ ConnectionManager connectionManager m_AuthenticationServiceFacade = authenticationServiceFacade; m_NameGenerationData = nameGenerationData; m_LocalUser = localUser; - m_LobbyServiceFacade = lobbyServiceFacade; - m_LocalLobby = localLobby; + m_MultiplayerServicesFacade = multiplayerServicesFacade; + m_LocalSession = localSession; m_ConnectionManager = connectionManager; m_ConnectStatusSubscriber = connectStatusSub; RegenerateName(); @@ -66,25 +79,21 @@ void OnConnectStatus(ConnectStatus status) void OnDestroy() { - if (m_ConnectStatusSubscriber != null) - { - m_ConnectStatusSubscriber.Unsubscribe(OnConnectStatus); - } + m_ConnectStatusSubscriber?.Unsubscribe(OnConnectStatus); } - //Lobby and Relay calls done from UI - - public async void CreateLobbyRequest(string lobbyName, bool isPrivate) + // Multiplayer Services SDK calls done from UI + public async void CreateSessionRequest(string sessionName, bool isPrivate) { - // before sending request to lobby service, populate an empty lobby name, if necessary - if (string.IsNullOrEmpty(lobbyName)) + // before sending request, populate an empty session name, if necessary + if (string.IsNullOrEmpty(sessionName)) { - lobbyName = k_DefaultLobbyName; + sessionName = k_DefaultSessionName; } BlockUIWhileLoadingIsInProgress(); - bool playerIsAuthorized = await m_AuthenticationServiceFacade.EnsurePlayerIsAuthorized(); + var playerIsAuthorized = await m_AuthenticationServiceFacade.EnsurePlayerIsAuthorized(); if (!playerIsAuthorized) { @@ -92,23 +101,14 @@ public async void CreateLobbyRequest(string lobbyName, bool isPrivate) return; } - var lobbyCreationAttempt = await m_LobbyServiceFacade.TryCreateLobbyAsync(lobbyName, m_ConnectionManager.MaxConnectedPlayers, isPrivate); + m_ConnectionManager.StartHostSession(m_LocalUser.DisplayName); - if (lobbyCreationAttempt.Success) - { - m_LocalUser.IsHost = true; - m_LobbyServiceFacade.SetRemoteLobby(lobbyCreationAttempt.Lobby); + var result = await m_MultiplayerServicesFacade.TryCreateSessionAsync(sessionName, k_MaxPlayers, isPrivate); - Debug.Log($"Created lobby with ID: {m_LocalLobby.LobbyID} and code {m_LocalLobby.LobbyCode}"); - m_ConnectionManager.StartHostLobby(m_LocalUser.DisplayName); - } - else - { - UnblockUIAfterLoadingIsComplete(); - } + HandleSessionJoinResult(result); } - public async void QueryLobbiesRequest(bool blockUI) + public async void QuerySessionRequest(bool blockUI) { if (Unity.Services.Core.UnityServices.State != ServicesInitializationState.Initialized) { @@ -120,7 +120,7 @@ public async void QueryLobbiesRequest(bool blockUI) BlockUIWhileLoadingIsInProgress(); } - bool playerIsAuthorized = await m_AuthenticationServiceFacade.EnsurePlayerIsAuthorized(); + var playerIsAuthorized = await m_AuthenticationServiceFacade.EnsurePlayerIsAuthorized(); if (blockUI && !playerIsAuthorized) { @@ -128,7 +128,7 @@ public async void QueryLobbiesRequest(bool blockUI) return; } - await m_LobbyServiceFacade.RetrieveAndPublishLobbyListAsync(); + await m_MultiplayerServicesFacade.RetrieveAndPublishSessionListAsync(); if (blockUI) { @@ -136,11 +136,11 @@ public async void QueryLobbiesRequest(bool blockUI) } } - public async void JoinLobbyWithCodeRequest(string lobbyCode) + public async void JoinSessionWithCodeRequest(string sessionCode) { BlockUIWhileLoadingIsInProgress(); - bool playerIsAuthorized = await m_AuthenticationServiceFacade.EnsurePlayerIsAuthorized(); + var playerIsAuthorized = await m_AuthenticationServiceFacade.EnsurePlayerIsAuthorized(); if (!playerIsAuthorized) { @@ -148,23 +148,18 @@ public async void JoinLobbyWithCodeRequest(string lobbyCode) return; } - var result = await m_LobbyServiceFacade.TryJoinLobbyAsync(null, lobbyCode); + m_ConnectionManager.StartClientSession(m_LocalUser.DisplayName); - if (result.Success) - { - OnJoinedLobby(result.Lobby); - } - else - { - UnblockUIAfterLoadingIsComplete(); - } + var result = await m_MultiplayerServicesFacade.TryJoinSessionByCodeAsync(sessionCode); + + HandleSessionJoinResult(result); } - public async void JoinLobbyRequest(LocalLobby lobby) + public async void JoinSessionRequest(ISessionInfo sessionInfo) { BlockUIWhileLoadingIsInProgress(); - bool playerIsAuthorized = await m_AuthenticationServiceFacade.EnsurePlayerIsAuthorized(); + var playerIsAuthorized = await m_AuthenticationServiceFacade.EnsurePlayerIsAuthorized(); if (!playerIsAuthorized) { @@ -172,23 +167,18 @@ public async void JoinLobbyRequest(LocalLobby lobby) return; } - var result = await m_LobbyServiceFacade.TryJoinLobbyAsync(lobby.LobbyID, lobby.LobbyCode); + m_ConnectionManager.StartClientSession(m_LocalUser.DisplayName); - if (result.Success) - { - OnJoinedLobby(result.Lobby); - } - else - { - UnblockUIAfterLoadingIsComplete(); - } + var result = await m_MultiplayerServicesFacade.TryJoinSessionByNameAsync(sessionInfo.Id); + + HandleSessionJoinResult(result); } public async void QuickJoinRequest() { BlockUIWhileLoadingIsInProgress(); - bool playerIsAuthorized = await m_AuthenticationServiceFacade.EnsurePlayerIsAuthorized(); + var playerIsAuthorized = await m_AuthenticationServiceFacade.EnsurePlayerIsAuthorized(); if (!playerIsAuthorized) { @@ -196,24 +186,33 @@ public async void QuickJoinRequest() return; } - var result = await m_LobbyServiceFacade.TryQuickJoinLobbyAsync(); + m_ConnectionManager.StartHostSession(m_LocalUser.DisplayName); + var result = await m_MultiplayerServicesFacade.TryQuickJoinSessionAsync(); + + HandleSessionJoinResult(result); + } + + void HandleSessionJoinResult((bool Success, ISession Session) result) + { if (result.Success) { - OnJoinedLobby(result.Lobby); + OnJoinedSession(result.Session); } else { + m_ConnectionManager.RequestShutdown(); UnblockUIAfterLoadingIsComplete(); } } - void OnJoinedLobby(Unity.Services.Lobbies.Models.Lobby remoteLobby) + void OnJoinedSession(ISession remoteSession) { - m_LobbyServiceFacade.SetRemoteLobby(remoteLobby); + m_MultiplayerServicesFacade.SetRemoteSession(remoteSession); + + Debug.Log($"Joined session with ID: {m_LocalSession.SessionID}"); - Debug.Log($"Joined lobby with code: {m_LocalLobby.LobbyCode}, Internal Relay Join Code{m_LocalLobby.RelayJoinCode}"); - m_ConnectionManager.StartClientLobby(m_LocalUser.DisplayName); + m_ConnectionManager.StartClientSession(m_LocalUser.DisplayName); } //show/hide UI @@ -228,24 +227,24 @@ public void Hide() { m_CanvasGroup.alpha = 0f; m_CanvasGroup.blocksRaycasts = false; - m_LobbyCreationUI.Hide(); - m_LobbyJoiningUI.Hide(); + m_SessionCreationUI.Hide(); + m_SessionJoiningUI.Hide(); } - public void ToggleJoinLobbyUI() + public void ToggleJoinSessionUI() { - m_LobbyJoiningUI.Show(); - m_LobbyCreationUI.Hide(); + m_SessionJoiningUI.Show(); + m_SessionCreationUI.Hide(); m_JoinToggleHighlight.SetToColor(1); m_JoinToggleTabBlocker.SetToColor(1); m_CreateToggleHighlight.SetToColor(0); m_CreateToggleTabBlocker.SetToColor(0); } - public void ToggleCreateLobbyUI() + public void ToggleCreateSessionUI() { - m_LobbyJoiningUI.Hide(); - m_LobbyCreationUI.Show(); + m_SessionJoiningUI.Hide(); + m_SessionCreationUI.Show(); m_JoinToggleHighlight.SetToColor(0); m_JoinToggleTabBlocker.SetToColor(0); m_CreateToggleHighlight.SetToColor(1); @@ -266,8 +265,8 @@ void BlockUIWhileLoadingIsInProgress() void UnblockUIAfterLoadingIsComplete() { - //this callback can happen after we've already switched to a different scene - //in that case the canvas group would be null + // this callback can happen after we've already switched to a different scene + // in that case the canvas group would be null if (m_CanvasGroup != null) { m_CanvasGroup.interactable = true; diff --git a/Assets/Scripts/Gameplay/UI/Lobby/LobbyUIMediator.cs.meta b/Assets/Scripts/Gameplay/UI/Session/SessionUIMediator.cs.meta similarity index 100% rename from Assets/Scripts/Gameplay/UI/Lobby/LobbyUIMediator.cs.meta rename to Assets/Scripts/Gameplay/UI/Session/SessionUIMediator.cs.meta diff --git a/Assets/Scripts/Gameplay/UI/UICharSelectPlayerSeat.cs b/Assets/Scripts/Gameplay/UI/UICharSelectPlayerSeat.cs index d79146ac0..d04609f48 100644 --- a/Assets/Scripts/Gameplay/UI/UICharSelectPlayerSeat.cs +++ b/Assets/Scripts/Gameplay/UI/UICharSelectPlayerSeat.cs @@ -36,7 +36,7 @@ public class UICharSelectPlayerSeat : MonoBehaviour [SerializeField] private CharacterTypeEnum m_CharacterClass; - // just a way to designate which seat we are -- the leftmost seat on the lobby UI is index 0, the next one is index 1, etc. + // just a way to designate which seat we are -- the leftmost seat on the Session UI is index 0, the next one is index 1, etc. private int m_SeatIndex; // playerNumber of who is sitting in this seat right now. 0-based; e.g. this is 0 for Player 1, 1 for Player 2, etc. Meaningless when m_State is Inactive (and in that case it is set to -1 for clarity) diff --git a/Assets/Scripts/Gameplay/UI/UnityServicesUIHandler.cs b/Assets/Scripts/Gameplay/UI/UnityServicesUIHandler.cs index fba0fc336..f87c359a1 100644 --- a/Assets/Scripts/Gameplay/UI/UnityServicesUIHandler.cs +++ b/Assets/Scripts/Gameplay/UI/UnityServicesUIHandler.cs @@ -2,7 +2,7 @@ using Unity.BossRoom.Infrastructure; using Unity.BossRoom.UnityServices; using Unity.BossRoom.Utils; -using Unity.Services.Lobbies; +using Unity.Services.Multiplayer; using UnityEngine; using VContainer; @@ -29,9 +29,9 @@ void ServiceErrorHandler(UnityServiceErrorMessage error) var errorMessage = error.Message; switch (error.AffectedService) { - case UnityServiceErrorMessage.Service.Lobby: + case UnityServiceErrorMessage.Service.Session: { - HandleLobbyError(error); + HandleSessionError(error); break; } case UnityServiceErrorMessage.Service.Authentication: @@ -49,37 +49,24 @@ void ServiceErrorHandler(UnityServiceErrorMessage error) } } - void HandleLobbyError(UnityServiceErrorMessage error) + void HandleSessionError(UnityServiceErrorMessage error) { - var exception = error.OriginalException as LobbyServiceException; - if (exception != null) + if (error.OriginalException is AggregateException { InnerException: SessionException sessionException }) { - switch (exception.Reason) + switch (sessionException.Error) { - // If the error is one of the following, the player needs to know about it, so show in a popup message. Otherwise, the log in the console is sufficient. - case LobbyExceptionReason.ValidationError: - PopupManager.ShowPopupPanel("Validation Error", "Validation check failed on Lobby. Is the join code correctly formatted?"); + case SessionError.SessionNotFound: + PopupManager.ShowPopupPanel("Session Not Found", "Requested Session not found. The join code is incorrect or the Session has ended."); break; - case LobbyExceptionReason.LobbyNotFound: - PopupManager.ShowPopupPanel("Lobby Not Found", "Requested lobby not found. The join code is incorrect or the lobby has ended."); + case SessionError.NotAuthorized: + PopupManager.ShowPopupPanel("Session error", "Received HTTP error 401 Unauthorized from Session Service."); break; - case LobbyExceptionReason.LobbyConflict: - // LobbyConflict can have multiple causes. Let's add other solutions here if there's other situations that arise for this. - Debug.LogError($"Got service error {error.Message} with LobbyConflict. Possible conflict cause: Trying to play with two builds on the " + - $"same machine. Please change profile in-game or use command line arg '{ProfileManager.AuthProfileCommandLineArg} someName' to set a different auth profile.\n"); - PopupManager.ShowPopupPanel("Failed to join Lobby", "Failed to join Lobby due to a conflict. If trying to connect two local builds to the same lobby, they need to have different profiles. See logs for more details."); + case SessionError.MatchmakerAssignmentTimeout: // this can happen when using quick join + PopupManager.ShowPopupPanel("Session error", "Received HTTP error 408 Request timed out from Session Service."); break; - case LobbyExceptionReason.NoOpenLobbies: - PopupManager.ShowPopupPanel("Failed to join Lobby", "No accessible lobbies are currently available for quick-join."); - break; - case LobbyExceptionReason.LobbyFull: - PopupManager.ShowPopupPanel("Failed to join Lobby", "Lobby is full and can't accept more players."); - break; - case LobbyExceptionReason.Unauthorized: - PopupManager.ShowPopupPanel("Lobby error", "Received HTTP error 401 Unauthorized from Lobby Service."); - break; - case LobbyExceptionReason.RequestTimeOut: - PopupManager.ShowPopupPanel("Lobby error", "Received HTTP error 408 Request timed out from Lobby Service."); + case SessionError.Unknown: + default: + PopupManager.ShowPopupPanel("Unknown Error", sessionException.Message); break; } } diff --git a/Assets/Scripts/Gameplay/Unity.BossRoom.Gameplay.asmdef b/Assets/Scripts/Gameplay/Unity.BossRoom.Gameplay.asmdef index 8987372d1..2ae5c8c38 100644 --- a/Assets/Scripts/Gameplay/Unity.BossRoom.Gameplay.asmdef +++ b/Assets/Scripts/Gameplay/Unity.BossRoom.Gameplay.asmdef @@ -9,7 +9,6 @@ "Unity.Services.Core", "Unity.Services.Authentication", "Unity.Services.Relay", - "Unity.Services.Lobbies", "Unity.Networking.Transport", "Unity.BossRoom.Infrastructure", "Unity.BossRoom.UnityServices", @@ -22,7 +21,8 @@ "VContainer", "Unity.BossRoom.VisualEffects", "Unity.BossRoom.CameraUtils", - "Unity.Multiplayer.Tools.NetworkSimulator.Runtime" + "Unity.Multiplayer.Tools.NetworkSimulator.Runtime", + "Unity.Services.Multiplayer" ], "includePlatforms": [], "excludePlatforms": [], diff --git a/Assets/Scripts/UnityServices/Infrastructure/Messages/UnityServiceErrorMessage.cs b/Assets/Scripts/UnityServices/Infrastructure/Messages/UnityServiceErrorMessage.cs index f24733baa..9ce807e7c 100644 --- a/Assets/Scripts/UnityServices/Infrastructure/Messages/UnityServiceErrorMessage.cs +++ b/Assets/Scripts/UnityServices/Infrastructure/Messages/UnityServiceErrorMessage.cs @@ -7,7 +7,7 @@ public struct UnityServiceErrorMessage public enum Service { Authentication, - Lobby, + Session, } public string Title; diff --git a/Assets/Scripts/UnityServices/Lobbies/LobbyAPIInterface.cs b/Assets/Scripts/UnityServices/Lobbies/LobbyAPIInterface.cs deleted file mode 100644 index fc3e31808..000000000 --- a/Assets/Scripts/UnityServices/Lobbies/LobbyAPIInterface.cs +++ /dev/null @@ -1,138 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using Unity.Services.Lobbies; -using Unity.Services.Lobbies.Models; -using UnityEngine; - -namespace Unity.BossRoom.UnityServices.Lobbies -{ - /// - /// Wrapper for all the interactions with the Lobby API. - /// - public class LobbyAPIInterface - { - const int k_MaxLobbiesToShow = 16; // If more are necessary, consider retrieving paginated results or using filters. - - readonly List m_Filters; - readonly List m_Order; - - public LobbyAPIInterface() - { - // Filter for open lobbies only - m_Filters = new List() - { - new QueryFilter( - field: QueryFilter.FieldOptions.AvailableSlots, - op: QueryFilter.OpOptions.GT, - value: "0") - }; - - // Order by newest lobbies first - m_Order = new List() - { - new QueryOrder( - asc: false, - field: QueryOrder.FieldOptions.Created) - }; - } - - public async Task CreateLobby(string requesterUasId, string lobbyName, int maxPlayers, bool isPrivate, Dictionary hostUserData, Dictionary lobbyData) - { - CreateLobbyOptions createOptions = new CreateLobbyOptions - { - IsPrivate = isPrivate, - IsLocked = true, // locking the lobby at creation to prevent other players from joining before it is ready - Player = new Player(id: requesterUasId, data: hostUserData), - Data = lobbyData - }; - - return await LobbyService.Instance.CreateLobbyAsync(lobbyName, maxPlayers, createOptions); - } - - public async Task DeleteLobby(string lobbyId) - { - await LobbyService.Instance.DeleteLobbyAsync(lobbyId); - } - - public async Task JoinLobbyByCode(string requesterUasId, string lobbyCode, Dictionary localUserData) - { - JoinLobbyByCodeOptions joinOptions = new JoinLobbyByCodeOptions { Player = new Player(id: requesterUasId, data: localUserData) }; - return await LobbyService.Instance.JoinLobbyByCodeAsync(lobbyCode, joinOptions); - } - - public async Task JoinLobbyById(string requesterUasId, string lobbyId, Dictionary localUserData) - { - JoinLobbyByIdOptions joinOptions = new JoinLobbyByIdOptions { Player = new Player(id: requesterUasId, data: localUserData) }; - return await LobbyService.Instance.JoinLobbyByIdAsync(lobbyId, joinOptions); - } - - public async Task QuickJoinLobby(string requesterUasId, Dictionary localUserData) - { - var joinRequest = new QuickJoinLobbyOptions - { - Filter = m_Filters, - Player = new Player(id: requesterUasId, data: localUserData) - }; - - return await LobbyService.Instance.QuickJoinLobbyAsync(joinRequest); - } - - public async Task ReconnectToLobby(string lobbyId) - { - return await LobbyService.Instance.ReconnectToLobbyAsync(lobbyId); - } - - public async Task RemovePlayerFromLobby(string requesterUasId, string lobbyId) - { - try - { - await LobbyService.Instance.RemovePlayerAsync(lobbyId, requesterUasId); - } - catch (LobbyServiceException e) - when (e is { Reason: LobbyExceptionReason.PlayerNotFound }) - { - // If Player is not found, they have already left the lobby or have been kicked out. No need to throw here - } - } - - public async Task QueryAllLobbies() - { - QueryLobbiesOptions queryOptions = new QueryLobbiesOptions - { - Count = k_MaxLobbiesToShow, - Filters = m_Filters, - Order = m_Order - }; - - return await LobbyService.Instance.QueryLobbiesAsync(queryOptions); - } - - public async Task UpdateLobby(string lobbyId, Dictionary data, bool shouldLock) - { - UpdateLobbyOptions updateOptions = new UpdateLobbyOptions { Data = data, IsLocked = shouldLock }; - return await LobbyService.Instance.UpdateLobbyAsync(lobbyId, updateOptions); - } - - public async Task UpdatePlayer(string lobbyId, string playerId, Dictionary data, string allocationId, string connectionInfo) - { - UpdatePlayerOptions updateOptions = new UpdatePlayerOptions - { - Data = data, - AllocationId = allocationId, - ConnectionInfo = connectionInfo - }; - return await LobbyService.Instance.UpdatePlayerAsync(lobbyId, playerId, updateOptions); - } - - public async void SendHeartbeatPing(string lobbyId) - { - await LobbyService.Instance.SendHeartbeatPingAsync(lobbyId); - } - - public async Task SubscribeToLobby(string lobbyId, LobbyEventCallbacks eventCallbacks) - { - return await LobbyService.Instance.SubscribeToLobbyEventsAsync(lobbyId, eventCallbacks); - } - } -} diff --git a/Assets/Scripts/UnityServices/Lobbies/LobbyServiceFacade.cs b/Assets/Scripts/UnityServices/Lobbies/LobbyServiceFacade.cs deleted file mode 100644 index a07e643cc..000000000 --- a/Assets/Scripts/UnityServices/Lobbies/LobbyServiceFacade.cs +++ /dev/null @@ -1,550 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using Unity.BossRoom.Infrastructure; -using Unity.Services.Authentication; -using Unity.Services.Lobbies; -using Unity.Services.Lobbies.Models; -using Unity.Services.Wire.Internal; -using UnityEngine; -using VContainer; -using VContainer.Unity; - -namespace Unity.BossRoom.UnityServices.Lobbies -{ - /// - /// An abstraction layer between the direct calls into the Lobby API and the outcomes you actually want. - /// - public class LobbyServiceFacade : IDisposable, IStartable - { - [Inject] LifetimeScope m_ParentScope; - [Inject] UpdateRunner m_UpdateRunner; - [Inject] LocalLobby m_LocalLobby; - [Inject] LocalLobbyUser m_LocalUser; - [Inject] IPublisher m_UnityServiceErrorMessagePub; - [Inject] IPublisher m_LobbyListFetchedPub; - - const float k_HeartbeatPeriod = 8; // The heartbeat must be rate-limited to 5 calls per 30 seconds. We'll aim for longer in case periods don't align. - float m_HeartbeatTime = 0; - - LifetimeScope m_ServiceScope; - LobbyAPIInterface m_LobbyApiInterface; - - RateLimitCooldown m_RateLimitQuery; - RateLimitCooldown m_RateLimitJoin; - RateLimitCooldown m_RateLimitQuickJoin; - RateLimitCooldown m_RateLimitHost; - - public Lobby CurrentUnityLobby { get; private set; } - - ILobbyEvents m_LobbyEvents; - - bool m_IsTracking = false; - - LobbyEventConnectionState m_LobbyEventConnectionState = LobbyEventConnectionState.Unknown; - - public void Start() - { - m_ServiceScope = m_ParentScope.CreateChild(builder => - { - builder.Register(Lifetime.Singleton); - }); - - m_LobbyApiInterface = m_ServiceScope.Container.Resolve(); - - //See https://docs.unity.com/lobby/rate-limits.html - m_RateLimitQuery = new RateLimitCooldown(1f); - m_RateLimitJoin = new RateLimitCooldown(3f); - m_RateLimitQuickJoin = new RateLimitCooldown(10f); - m_RateLimitHost = new RateLimitCooldown(3f); - } - - public void Dispose() - { - EndTracking(); - if (m_ServiceScope != null) - { - m_ServiceScope.Dispose(); - } - } - - public void SetRemoteLobby(Lobby lobby) - { - CurrentUnityLobby = lobby; - m_LocalLobby.ApplyRemoteData(lobby); - } - - /// - /// Initiates tracking of joined lobby's events. The host also starts sending heartbeat pings here. - /// - public void BeginTracking() - { - if (!m_IsTracking) - { - m_IsTracking = true; - SubscribeToJoinedLobbyAsync(); - - // Only the host sends heartbeat pings to the service to keep the lobby alive - if (m_LocalUser.IsHost) - { - m_HeartbeatTime = 0; - m_UpdateRunner.Subscribe(DoLobbyHeartbeat, 1.5f); - } - } - } - - /// - /// Ends tracking of joined lobby's events and leaves or deletes the lobby. The host also stops sending heartbeat pings here. - /// - public void EndTracking() - { - if (m_IsTracking) - { - m_IsTracking = false; - UnsubscribeToJoinedLobbyAsync(); - - // Only the host sends heartbeat pings to the service to keep the lobby alive - if (m_LocalUser.IsHost) - { - m_UpdateRunner.Unsubscribe(DoLobbyHeartbeat); - } - } - - if (CurrentUnityLobby != null) - { - if (m_LocalUser.IsHost) - { - DeleteLobbyAsync(); - } - else - { - LeaveLobbyAsync(); - } - } - } - - /// - /// Attempt to create a new lobby and then join it. - /// - public async Task<(bool Success, Lobby Lobby)> TryCreateLobbyAsync(string lobbyName, int maxPlayers, bool isPrivate) - { - if (!m_RateLimitHost.CanCall) - { - Debug.LogWarning("Create Lobby hit the rate limit."); - return (false, null); - } - - try - { - var lobby = await m_LobbyApiInterface.CreateLobby(AuthenticationService.Instance.PlayerId, lobbyName, maxPlayers, isPrivate, m_LocalUser.GetDataForUnityServices(), null); - return (true, lobby); - } - catch (LobbyServiceException e) - { - if (e.Reason == LobbyExceptionReason.RateLimited) - { - m_RateLimitHost.PutOnCooldown(); - } - else - { - PublishError(e); - } - } - - return (false, null); - } - - /// - /// Attempt to join an existing lobby. Will try to join via code, if code is null - will try to join via ID. - /// - public async Task<(bool Success, Lobby Lobby)> TryJoinLobbyAsync(string lobbyId, string lobbyCode) - { - if (!m_RateLimitJoin.CanCall || - (lobbyId == null && lobbyCode == null)) - { - Debug.LogWarning("Join Lobby hit the rate limit."); - return (false, null); - } - - try - { - if (!string.IsNullOrEmpty(lobbyCode)) - { - var lobby = await m_LobbyApiInterface.JoinLobbyByCode(AuthenticationService.Instance.PlayerId, lobbyCode, m_LocalUser.GetDataForUnityServices()); - return (true, lobby); - } - else - { - var lobby = await m_LobbyApiInterface.JoinLobbyById(AuthenticationService.Instance.PlayerId, lobbyId, m_LocalUser.GetDataForUnityServices()); - return (true, lobby); - } - } - catch (LobbyServiceException e) - { - if (e.Reason == LobbyExceptionReason.RateLimited) - { - m_RateLimitJoin.PutOnCooldown(); - } - else - { - PublishError(e); - } - } - - return (false, null); - } - - /// - /// Attempt to join the first lobby among the available lobbies that match the filtered onlineMode. - /// - public async Task<(bool Success, Lobby Lobby)> TryQuickJoinLobbyAsync() - { - if (!m_RateLimitQuickJoin.CanCall) - { - Debug.LogWarning("Quick Join Lobby hit the rate limit."); - return (false, null); - } - - try - { - var lobby = await m_LobbyApiInterface.QuickJoinLobby(AuthenticationService.Instance.PlayerId, m_LocalUser.GetDataForUnityServices()); - return (true, lobby); - } - catch (LobbyServiceException e) - { - if (e.Reason == LobbyExceptionReason.RateLimited) - { - m_RateLimitQuickJoin.PutOnCooldown(); - } - else - { - PublishError(e); - } - } - - return (false, null); - } - - void ResetLobby() - { - CurrentUnityLobby = null; - if (m_LocalUser != null) - { - m_LocalUser.ResetState(); - } - if (m_LocalLobby != null) - { - m_LocalLobby.Reset(m_LocalUser); - } - - // no need to disconnect Netcode, it should already be handled by Netcode's callback to disconnect - } - - void OnLobbyChanges(ILobbyChanges changes) - { - if (changes.LobbyDeleted) - { - Debug.Log("Lobby deleted"); - ResetLobby(); - EndTracking(); - } - else - { - Debug.Log("Lobby updated"); - changes.ApplyToLobby(CurrentUnityLobby); - m_LocalLobby.ApplyRemoteData(CurrentUnityLobby); - - // as client, check if host is still in lobby - if (!m_LocalUser.IsHost) - { - foreach (var lobbyUser in m_LocalLobby.LobbyUsers) - { - if (lobbyUser.Value.IsHost) - { - return; - } - } - - m_UnityServiceErrorMessagePub.Publish(new UnityServiceErrorMessage("Host left the lobby", "Disconnecting.", UnityServiceErrorMessage.Service.Lobby)); - EndTracking(); - // no need to disconnect Netcode, it should already be handled by Netcode's callback to disconnect - } - } - } - - void OnKickedFromLobby() - { - Debug.Log("Kicked from Lobby"); - ResetLobby(); - EndTracking(); - } - - void OnLobbyEventConnectionStateChanged(LobbyEventConnectionState lobbyEventConnectionState) - { - m_LobbyEventConnectionState = lobbyEventConnectionState; - Debug.Log($"LobbyEventConnectionState changed to {lobbyEventConnectionState}"); - } - - async void SubscribeToJoinedLobbyAsync() - { - var lobbyEventCallbacks = new LobbyEventCallbacks(); - lobbyEventCallbacks.LobbyChanged += OnLobbyChanges; - lobbyEventCallbacks.KickedFromLobby += OnKickedFromLobby; - lobbyEventCallbacks.LobbyEventConnectionStateChanged += OnLobbyEventConnectionStateChanged; - // The LobbyEventCallbacks object created here will now be managed by the Lobby SDK. The callbacks will be - // unsubscribed from when we call UnsubscribeAsync on the ILobbyEvents object we receive and store here. - m_LobbyEvents = await m_LobbyApiInterface.SubscribeToLobby(m_LocalLobby.LobbyID, lobbyEventCallbacks); - } - - async void UnsubscribeToJoinedLobbyAsync() - { - if (m_LobbyEvents != null && m_LobbyEventConnectionState != LobbyEventConnectionState.Unsubscribed) - { -#if UNITY_EDITOR - try - { - await m_LobbyEvents.UnsubscribeAsync(); - } - catch (WebSocketException e) - { - // This exception occurs in the editor when exiting play mode without first leaving the lobby. - // This is because Wire closes the websocket internally when exiting playmode in the editor. - Debug.Log(e.Message); - } -#else - await m_LobbyEvents.UnsubscribeAsync(); -#endif - } - } - - /// - /// Used for getting the list of all active lobbies, without needing full info for each. - /// - public async Task RetrieveAndPublishLobbyListAsync() - { - if (!m_RateLimitQuery.CanCall) - { - Debug.LogWarning("Retrieve Lobby list hit the rate limit. Will try again soon..."); - return; - } - - try - { - var response = await m_LobbyApiInterface.QueryAllLobbies(); - m_LobbyListFetchedPub.Publish(new LobbyListFetchedMessage(LocalLobby.CreateLocalLobbies(response))); - } - catch (LobbyServiceException e) - { - if (e.Reason == LobbyExceptionReason.RateLimited) - { - m_RateLimitQuery.PutOnCooldown(); - } - else - { - PublishError(e); - } - } - } - - public async Task ReconnectToLobbyAsync() - { - try - { - return await m_LobbyApiInterface.ReconnectToLobby(m_LocalLobby.LobbyID); - } - catch (LobbyServiceException e) - { - // If Lobby is not found and if we are not the host, it has already been deleted. No need to publish the error here. - if (e.Reason != LobbyExceptionReason.LobbyNotFound && !m_LocalUser.IsHost) - { - PublishError(e); - } - } - - return null; - } - - /// - /// Attempt to leave a lobby - /// - async void LeaveLobbyAsync() - { - string uasId = AuthenticationService.Instance.PlayerId; - try - { - await m_LobbyApiInterface.RemovePlayerFromLobby(uasId, m_LocalLobby.LobbyID); - } - catch (LobbyServiceException e) - { - // If Lobby is not found and if we are not the host, it has already been deleted. No need to publish the error here. - if (e.Reason != LobbyExceptionReason.LobbyNotFound && !m_LocalUser.IsHost) - { - PublishError(e); - } - } - finally - { - ResetLobby(); - } - - } - - public async void RemovePlayerFromLobbyAsync(string uasId) - { - if (m_LocalUser.IsHost) - { - try - { - await m_LobbyApiInterface.RemovePlayerFromLobby(uasId, m_LocalLobby.LobbyID); - } - catch (LobbyServiceException e) - { - PublishError(e); - } - } - else - { - Debug.LogError("Only the host can remove other players from the lobby."); - } - } - - async void DeleteLobbyAsync() - { - if (m_LocalUser.IsHost) - { - try - { - await m_LobbyApiInterface.DeleteLobby(m_LocalLobby.LobbyID); - } - catch (LobbyServiceException e) - { - PublishError(e); - } - finally - { - ResetLobby(); - } - } - else - { - Debug.LogError("Only the host can delete a lobby."); - } - } - - /// - /// Attempt to push a set of key-value pairs associated with the local player which will overwrite any existing - /// data for these keys. Lobby can be provided info about Relay (or any other remote allocation) so it can add - /// automatic disconnect handling. - /// - public async Task UpdatePlayerDataAsync(string allocationId, string connectionInfo) - { - if (!m_RateLimitQuery.CanCall) - { - return; - } - - try - { - var result = await m_LobbyApiInterface.UpdatePlayer(CurrentUnityLobby.Id, AuthenticationService.Instance.PlayerId, m_LocalUser.GetDataForUnityServices(), allocationId, connectionInfo); - - if (result != null) - { - CurrentUnityLobby = result; // Store the most up-to-date lobby now since we have it, instead of waiting for the next heartbeat. - } - } - catch (LobbyServiceException e) - { - if (e.Reason == LobbyExceptionReason.RateLimited) - { - m_RateLimitQuery.PutOnCooldown(); - } - else if (e.Reason != LobbyExceptionReason.LobbyNotFound && !m_LocalUser.IsHost) // If Lobby is not found and if we are not the host, it has already been deleted. No need to publish the error here. - { - PublishError(e); - } - } - } - - /// - /// Attempt to update the set of key-value pairs associated with a given lobby and unlocks it so clients can see it. - /// - public async Task UpdateLobbyDataAndUnlockAsync() - { - if (!m_RateLimitQuery.CanCall) - { - return; - } - - var localData = m_LocalLobby.GetDataForUnityServices(); - - var dataCurr = CurrentUnityLobby.Data; - if (dataCurr == null) - { - dataCurr = new Dictionary(); - } - - foreach (var dataNew in localData) - { - if (dataCurr.ContainsKey(dataNew.Key)) - { - dataCurr[dataNew.Key] = dataNew.Value; - } - else - { - dataCurr.Add(dataNew.Key, dataNew.Value); - } - } - - try - { - var result = await m_LobbyApiInterface.UpdateLobby(CurrentUnityLobby.Id, dataCurr, shouldLock: false); - - if (result != null) - { - CurrentUnityLobby = result; - } - } - catch (LobbyServiceException e) - { - if (e.Reason == LobbyExceptionReason.RateLimited) - { - m_RateLimitQuery.PutOnCooldown(); - } - else - { - PublishError(e); - } - } - } - - /// - /// Lobby requires a periodic ping to detect rooms that are still active, in order to mitigate "zombie" lobbies. - /// - void DoLobbyHeartbeat(float dt) - { - m_HeartbeatTime += dt; - if (m_HeartbeatTime > k_HeartbeatPeriod) - { - m_HeartbeatTime -= k_HeartbeatPeriod; - try - { - m_LobbyApiInterface.SendHeartbeatPing(CurrentUnityLobby.Id); - } - catch (LobbyServiceException e) - { - // If Lobby is not found and if we are not the host, it has already been deleted. No need to publish the error here. - if (e.Reason != LobbyExceptionReason.LobbyNotFound && !m_LocalUser.IsHost) - { - PublishError(e); - } - } - } - } - - void PublishError(LobbyServiceException e) - { - var reason = e.InnerException == null ? e.Message : $"{e.Message} ({e.InnerException.Message})"; // Lobby error type, then HTTP error type. - m_UnityServiceErrorMessagePub.Publish(new UnityServiceErrorMessage("Lobby Error", reason, UnityServiceErrorMessage.Service.Lobby, e)); - } - } -} diff --git a/Assets/Scripts/UnityServices/Lobbies/LocalLobby.cs b/Assets/Scripts/UnityServices/Lobbies/LocalLobby.cs deleted file mode 100644 index 2008e6af9..000000000 --- a/Assets/Scripts/UnityServices/Lobbies/LocalLobby.cs +++ /dev/null @@ -1,274 +0,0 @@ -using System; -using System.Collections.Generic; -using Unity.Services.Lobbies.Models; -using UnityEngine; - -namespace Unity.BossRoom.UnityServices.Lobbies -{ - /// - /// A local wrapper around a lobby's remote data, with additional functionality for providing that data to UI elements and tracking local player objects. - /// - [Serializable] - public sealed class LocalLobby - { - public event Action changed; - - /// - /// Create a list of new LocalLobbies from the result of a lobby list query. - /// - public static List CreateLocalLobbies(QueryResponse response) - { - var retLst = new List(); - foreach (var lobby in response.Results) - { - retLst.Add(Create(lobby)); - } - return retLst; - } - - public static LocalLobby Create(Lobby lobby) - { - var data = new LocalLobby(); - data.ApplyRemoteData(lobby); - return data; - } - - Dictionary m_LobbyUsers = new Dictionary(); - public Dictionary LobbyUsers => m_LobbyUsers; - - public struct LobbyData - { - public string LobbyID { get; set; } - public string LobbyCode { get; set; } - public string RelayJoinCode { get; set; } - public string LobbyName { get; set; } - public bool Private { get; set; } - public int MaxPlayerCount { get; set; } - - public LobbyData(LobbyData existing) - { - LobbyID = existing.LobbyID; - LobbyCode = existing.LobbyCode; - RelayJoinCode = existing.RelayJoinCode; - LobbyName = existing.LobbyName; - Private = existing.Private; - MaxPlayerCount = existing.MaxPlayerCount; - } - - public LobbyData(string lobbyCode) - { - LobbyID = null; - LobbyCode = lobbyCode; - RelayJoinCode = null; - LobbyName = null; - Private = false; - MaxPlayerCount = -1; - } - } - - LobbyData m_Data; - public LobbyData Data => new LobbyData(m_Data); - - public void AddUser(LocalLobbyUser user) - { - if (!m_LobbyUsers.ContainsKey(user.ID)) - { - DoAddUser(user); - OnChanged(); - } - } - - void DoAddUser(LocalLobbyUser user) - { - m_LobbyUsers.Add(user.ID, user); - user.changed += OnChangedUser; - } - - public void RemoveUser(LocalLobbyUser user) - { - DoRemoveUser(user); - OnChanged(); - } - - void DoRemoveUser(LocalLobbyUser user) - { - if (!m_LobbyUsers.ContainsKey(user.ID)) - { - Debug.LogWarning($"Player {user.DisplayName}({user.ID}) does not exist in lobby: {LobbyID}"); - return; - } - - m_LobbyUsers.Remove(user.ID); - user.changed -= OnChangedUser; - } - - void OnChangedUser(LocalLobbyUser user) - { - OnChanged(); - } - - void OnChanged() - { - changed?.Invoke(this); - } - - public string LobbyID - { - get => m_Data.LobbyID; - set - { - m_Data.LobbyID = value; - OnChanged(); - } - } - - public string LobbyCode - { - get => m_Data.LobbyCode; - set - { - m_Data.LobbyCode = value; - OnChanged(); - } - } - - public string RelayJoinCode - { - get => m_Data.RelayJoinCode; - set - { - m_Data.RelayJoinCode = value; - OnChanged(); - } - } - - public string LobbyName - { - get => m_Data.LobbyName; - set - { - m_Data.LobbyName = value; - OnChanged(); - } - } - - public bool Private - { - get => m_Data.Private; - set - { - m_Data.Private = value; - OnChanged(); - } - } - - public int PlayerCount => m_LobbyUsers.Count; - - public int MaxPlayerCount - { - get => m_Data.MaxPlayerCount; - set - { - m_Data.MaxPlayerCount = value; - OnChanged(); - } - } - - public void CopyDataFrom(LobbyData data, Dictionary currUsers) - { - m_Data = data; - - if (currUsers == null) - { - m_LobbyUsers = new Dictionary(); - } - else - { - List toRemove = new List(); - foreach (var oldUser in m_LobbyUsers) - { - if (currUsers.ContainsKey(oldUser.Key)) - { - oldUser.Value.CopyDataFrom(currUsers[oldUser.Key]); - } - else - { - toRemove.Add(oldUser.Value); - } - } - - foreach (var remove in toRemove) - { - DoRemoveUser(remove); - } - - foreach (var currUser in currUsers) - { - if (!m_LobbyUsers.ContainsKey(currUser.Key)) - { - DoAddUser(currUser.Value); - } - } - } - - OnChanged(); - } - - public Dictionary GetDataForUnityServices() => - new Dictionary() - { - {"RelayJoinCode", new DataObject(DataObject.VisibilityOptions.Public, RelayJoinCode)} - }; - - public void ApplyRemoteData(Lobby lobby) - { - var info = new LobbyData(); // Technically, this is largely redundant after the first assignment, but it won't do any harm to assign it again. - info.LobbyID = lobby.Id; - info.LobbyCode = lobby.LobbyCode; - info.Private = lobby.IsPrivate; - info.LobbyName = lobby.Name; - info.MaxPlayerCount = lobby.MaxPlayers; - - if (lobby.Data != null) - { - info.RelayJoinCode = lobby.Data.ContainsKey("RelayJoinCode") ? lobby.Data["RelayJoinCode"].Value : null; // By providing RelayCode through the lobby data with Member visibility, we ensure a client is connected to the lobby before they could attempt a relay connection, preventing timing issues between them. - } - else - { - info.RelayJoinCode = null; - } - - var lobbyUsers = new Dictionary(); - foreach (var player in lobby.Players) - { - if (player.Data != null) - { - if (LobbyUsers.ContainsKey(player.Id)) - { - lobbyUsers.Add(player.Id, LobbyUsers[player.Id]); - continue; - } - } - - // If the player isn't connected to Relay, get the most recent data that the lobby knows. - // (If we haven't seen this player yet, a new local representation of the player will have already been added by the LocalLobby.) - var incomingData = new LocalLobbyUser - { - IsHost = lobby.HostId.Equals(player.Id), - DisplayName = player.Data != null && player.Data.ContainsKey("DisplayName") ? player.Data["DisplayName"].Value : default, - ID = player.Id - }; - - lobbyUsers.Add(incomingData.ID, incomingData); - } - - CopyDataFrom(info, lobbyUsers); - } - - public void Reset(LocalLobbyUser localUser) - { - CopyDataFrom(new LobbyData(), new Dictionary()); - AddUser(localUser); - } - } -} diff --git a/Assets/Scripts/UnityServices/Lobbies/Messages/LobbyListFetchedMessage.cs b/Assets/Scripts/UnityServices/Lobbies/Messages/LobbyListFetchedMessage.cs deleted file mode 100644 index e1879e015..000000000 --- a/Assets/Scripts/UnityServices/Lobbies/Messages/LobbyListFetchedMessage.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Collections.Generic; - -namespace Unity.BossRoom.UnityServices.Lobbies -{ - public struct LobbyListFetchedMessage - { - public readonly IReadOnlyList LocalLobbies; - - public LobbyListFetchedMessage(List localLobbies) - { - LocalLobbies = localLobbies; - } - } -} diff --git a/Assets/Scripts/UnityServices/Lobbies.meta b/Assets/Scripts/UnityServices/Sessions.meta similarity index 100% rename from Assets/Scripts/UnityServices/Lobbies.meta rename to Assets/Scripts/UnityServices/Sessions.meta diff --git a/Assets/Scripts/UnityServices/Sessions/LocalSession.cs b/Assets/Scripts/UnityServices/Sessions/LocalSession.cs new file mode 100644 index 000000000..58de13f0a --- /dev/null +++ b/Assets/Scripts/UnityServices/Sessions/LocalSession.cs @@ -0,0 +1,221 @@ +using System; +using System.Collections.Generic; +using Unity.Services.Multiplayer; +using UnityEngine; + +namespace Unity.BossRoom.UnityServices.Sessions +{ + /// + /// A local wrapper around a session's remote data, with additional functionality for providing that data to UI + /// elements and tracking local player objects. + /// + [Serializable] + public sealed class LocalSession + { + Dictionary m_SessionUsers = new(); + public Dictionary sessionUsers => m_SessionUsers; + + SessionData m_Data; + + public event Action changed; + + public string SessionID + { + get => m_Data.SessionID; + set + { + m_Data.SessionID = value; + OnChanged(); + } + } + + public string SessionCode + { + get => m_Data.SessionCode; + set + { + m_Data.SessionCode = value; + OnChanged(); + } + } + + public string RelayJoinCode + { + get => m_Data.RelayJoinCode; + set + { + m_Data.RelayJoinCode = value; + OnChanged(); + } + } + + public struct SessionData + { + public string SessionID { get; set; } + public string SessionCode { get; set; } + public string RelayJoinCode { get; set; } + public string SessionName { get; set; } + public bool Private { get; set; } + public int MaxPlayerCount { get; set; } + + public SessionData(SessionData existing) + { + SessionID = existing.SessionID; + SessionCode = existing.SessionCode; + RelayJoinCode = existing.RelayJoinCode; + SessionName = existing.SessionName; + Private = existing.Private; + MaxPlayerCount = existing.MaxPlayerCount; + } + + public SessionData(string sessionCode) + { + SessionID = null; + SessionCode = sessionCode; + RelayJoinCode = null; + SessionName = null; + Private = false; + MaxPlayerCount = -1; + } + } + + public void AddUser(LocalSessionUser user) + { + if (!m_SessionUsers.ContainsKey(user.ID)) + { + DoAddUser(user); + OnChanged(); + } + } + + void DoAddUser(LocalSessionUser user) + { + m_SessionUsers.Add(user.ID, user); + user.changed += OnChangedUser; + } + + public void RemoveUser(LocalSessionUser user) + { + DoRemoveUser(user); + OnChanged(); + } + + void DoRemoveUser(LocalSessionUser user) + { + if (!m_SessionUsers.ContainsKey(user.ID)) + { + Debug.LogWarning($"Player {user.DisplayName}({user.ID}) does not exist in session: {SessionID}"); + return; + } + + m_SessionUsers.Remove(user.ID); + user.changed -= OnChangedUser; + } + + void OnChangedUser(LocalSessionUser user) + { + OnChanged(); + } + + void OnChanged() + { + changed?.Invoke(this); + } + + public void CopyDataFrom(SessionData data, Dictionary currUsers) + { + m_Data = data; + + if (currUsers == null) + { + m_SessionUsers = new Dictionary(); + } + else + { + List toRemove = new List(); + foreach (var oldUser in m_SessionUsers) + { + if (currUsers.ContainsKey(oldUser.Key)) + { + oldUser.Value.CopyDataFrom(currUsers[oldUser.Key]); + } + else + { + toRemove.Add(oldUser.Value); + } + } + + foreach (var remove in toRemove) + { + DoRemoveUser(remove); + } + + foreach (var currUser in currUsers) + { + if (!m_SessionUsers.ContainsKey(currUser.Key)) + { + DoAddUser(currUser.Value); + } + } + } + + OnChanged(); + } + + public Dictionary GetDataForUnityServices() => + new() + { + { "RelayJoinCode", new SessionProperty(RelayJoinCode) } + }; + + public void ApplyRemoteData(ISession session) + { + var info = new SessionData(); // Technically, this is largely redundant after the first assignment, but it won't do any harm to assign it again. + info.SessionID = session.Id; + info.SessionName = session.Name; + info.MaxPlayerCount = session.MaxPlayers; + info.SessionCode = session.Code; + info.Private = session.IsPrivate; + + if (session.Properties != null) + { + info.RelayJoinCode = session.Properties.TryGetValue("RelayJoinCode", out var property) ? property.Value : null; // By providing RelayCode through the session properties with Member visibility, we ensure a client is connected to the session before they could attempt a relay connection, preventing timing issues between them. + } + else + { + info.RelayJoinCode = null; + } + + var localSessionUsers = new Dictionary(); + foreach (var player in session.Players) + { + if (player.Properties != null) + { + if (localSessionUsers.ContainsKey(player.Id)) + { + localSessionUsers.Add(player.Id, localSessionUsers[player.Id]); + continue; + } + } + + // If the player isn't connected to Relay, get the most recent data that the session knows. + // (If we haven't seen this player yet, a new local representation of the player will have already been added by the LocalSession.) + var incomingData = new LocalSessionUser + { + IsHost = session.Host.Equals(player.Id), + DisplayName = player.Properties != null && player.Properties.TryGetValue("DisplayName", out var property) ? property.Value : default, + ID = player.Id + }; + + localSessionUsers.Add(incomingData.ID, incomingData); + } + + CopyDataFrom(info, localSessionUsers); + } + + public void Reset() + { + CopyDataFrom(new SessionData(), new Dictionary()); + } + } +} diff --git a/Assets/Scripts/UnityServices/Lobbies/LocalLobby.cs.meta b/Assets/Scripts/UnityServices/Sessions/LocalSession.cs.meta similarity index 100% rename from Assets/Scripts/UnityServices/Lobbies/LocalLobby.cs.meta rename to Assets/Scripts/UnityServices/Sessions/LocalSession.cs.meta diff --git a/Assets/Scripts/UnityServices/Lobbies/LocalLobbyUser.cs b/Assets/Scripts/UnityServices/Sessions/LocalSessionUser.cs similarity index 74% rename from Assets/Scripts/UnityServices/Lobbies/LocalLobbyUser.cs rename to Assets/Scripts/UnityServices/Sessions/LocalSessionUser.cs index ec3676443..cbf700451 100644 --- a/Assets/Scripts/UnityServices/Lobbies/LocalLobbyUser.cs +++ b/Assets/Scripts/UnityServices/Sessions/LocalSessionUser.cs @@ -1,127 +1,127 @@ -using System; -using System.Collections.Generic; -using Unity.Services.Lobbies.Models; - -namespace Unity.BossRoom.UnityServices.Lobbies -{ - /// - /// Data for a local lobby user instance. This will update data and is observed to know when to push local user changes to the entire lobby. - /// - [Serializable] - public class LocalLobbyUser - { - public event Action changed; - - public LocalLobbyUser() - { - m_UserData = new UserData(isHost: false, displayName: null, id: null); - } - - public struct UserData - { - public bool IsHost { get; set; } - public string DisplayName { get; set; } - public string ID { get; set; } - - public UserData(bool isHost, string displayName, string id) - { - IsHost = isHost; - DisplayName = displayName; - ID = id; - } - } - - UserData m_UserData; - - public void ResetState() - { - m_UserData = new UserData(false, m_UserData.DisplayName, m_UserData.ID); - } - - /// - /// Used for limiting costly OnChanged actions to just the members which actually changed. - /// - [Flags] - public enum UserMembers - { - IsHost = 1, - DisplayName = 2, - ID = 4, - } - - UserMembers m_LastChanged; - - public bool IsHost - { - get { return m_UserData.IsHost; } - set - { - if (m_UserData.IsHost != value) - { - m_UserData.IsHost = value; - m_LastChanged = UserMembers.IsHost; - OnChanged(); - } - } - } - - public string DisplayName - { - get => m_UserData.DisplayName; - set - { - if (m_UserData.DisplayName != value) - { - m_UserData.DisplayName = value; - m_LastChanged = UserMembers.DisplayName; - OnChanged(); - } - } - } - - public string ID - { - get => m_UserData.ID; - set - { - if (m_UserData.ID != value) - { - m_UserData.ID = value; - m_LastChanged = UserMembers.ID; - OnChanged(); - } - } - } - - - public void CopyDataFrom(LocalLobbyUser lobby) - { - var data = lobby.m_UserData; - int lastChanged = // Set flags just for the members that will be changed. - (m_UserData.IsHost == data.IsHost ? 0 : (int)UserMembers.IsHost) | - (m_UserData.DisplayName == data.DisplayName ? 0 : (int)UserMembers.DisplayName) | - (m_UserData.ID == data.ID ? 0 : (int)UserMembers.ID); - - if (lastChanged == 0) // Ensure something actually changed. - { - return; - } - - m_UserData = data; - m_LastChanged = (UserMembers)lastChanged; - - OnChanged(); - } - - void OnChanged() - { - changed?.Invoke(this); - } - - public Dictionary GetDataForUnityServices() => - new Dictionary() - { - {"DisplayName", new PlayerDataObject(PlayerDataObject.VisibilityOptions.Member, DisplayName)}, - }; - } -} +using System; +using System.Collections.Generic; +using Unity.Services.Multiplayer; + +namespace Unity.BossRoom.UnityServices.Sessions +{ + /// + /// Data for a local session user instance. This will update data and is observed to know when to push local user + /// changes to the entire session. + /// + [Serializable] + public class LocalSessionUser + { + UserData m_UserData; + + public event Action changed; + + public LocalSessionUser() + { + m_UserData = new UserData(isHost: false, displayName: null, id: null); + } + + public struct UserData + { + public bool IsHost { get; set; } + public string DisplayName { get; set; } + public string ID { get; set; } + + public UserData(bool isHost, string displayName, string id) + { + IsHost = isHost; + DisplayName = displayName; + ID = id; + } + } + + public void ResetState() + { + m_UserData = new UserData(false, m_UserData.DisplayName, m_UserData.ID); + } + + /// + /// Used for limiting costly OnChanged actions to just the members which actually changed. + /// + [Flags] + public enum UserMembers + { + IsHost = 1, + DisplayName = 2, + ID = 4, + } + + UserMembers m_LastChanged; + + public bool IsHost + { + get => m_UserData.IsHost; + set + { + if (m_UserData.IsHost != value) + { + m_UserData.IsHost = value; + m_LastChanged = UserMembers.IsHost; + OnChanged(); + } + } + } + + public string DisplayName + { + get => m_UserData.DisplayName; + set + { + if (m_UserData.DisplayName != value) + { + m_UserData.DisplayName = value; + m_LastChanged = UserMembers.DisplayName; + OnChanged(); + } + } + } + + public string ID + { + get => m_UserData.ID; + set + { + if (m_UserData.ID != value) + { + m_UserData.ID = value; + m_LastChanged = UserMembers.ID; + OnChanged(); + } + } + } + + public void CopyDataFrom(LocalSessionUser session) + { + var data = session.m_UserData; + var lastChanged = // Set flags just for the members that will be changed. + (m_UserData.IsHost == data.IsHost ? 0 : (int)UserMembers.IsHost) | + (m_UserData.DisplayName == data.DisplayName ? 0 : (int)UserMembers.DisplayName) | + (m_UserData.ID == data.ID ? 0 : (int)UserMembers.ID); + + if (lastChanged == 0) // Ensure something actually changed. + { + return; + } + + m_UserData = data; + m_LastChanged = (UserMembers)lastChanged; + + OnChanged(); + } + + void OnChanged() + { + changed?.Invoke(this); + } + + public Dictionary GetDataForUnityServices() => + new() + { + { "DisplayName", new PlayerProperty(DisplayName, VisibilityPropertyOptions.Member) }, + }; + } +} diff --git a/Assets/Scripts/UnityServices/Lobbies/LocalLobbyUser.cs.meta b/Assets/Scripts/UnityServices/Sessions/LocalSessionUser.cs.meta similarity index 100% rename from Assets/Scripts/UnityServices/Lobbies/LocalLobbyUser.cs.meta rename to Assets/Scripts/UnityServices/Sessions/LocalSessionUser.cs.meta diff --git a/Assets/Scripts/UnityServices/Lobbies/Messages.meta b/Assets/Scripts/UnityServices/Sessions/Messages.meta similarity index 100% rename from Assets/Scripts/UnityServices/Lobbies/Messages.meta rename to Assets/Scripts/UnityServices/Sessions/Messages.meta diff --git a/Assets/Scripts/UnityServices/Sessions/Messages/SessionListFetchedMessage.cs b/Assets/Scripts/UnityServices/Sessions/Messages/SessionListFetchedMessage.cs new file mode 100644 index 000000000..753eb31fd --- /dev/null +++ b/Assets/Scripts/UnityServices/Sessions/Messages/SessionListFetchedMessage.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; +using Unity.Services.Multiplayer; + +namespace Unity.BossRoom.UnityServices.Sessions +{ + public struct SessionListFetchedMessage + { + public readonly IList LocalSessions; + + public SessionListFetchedMessage(IList localSessions) + { + LocalSessions = localSessions; + } + } +} diff --git a/Assets/Scripts/UnityServices/Lobbies/Messages/LobbyListFetchedMessage.cs.meta b/Assets/Scripts/UnityServices/Sessions/Messages/SessionListFetchedMessage.cs.meta similarity index 100% rename from Assets/Scripts/UnityServices/Lobbies/Messages/LobbyListFetchedMessage.cs.meta rename to Assets/Scripts/UnityServices/Sessions/Messages/SessionListFetchedMessage.cs.meta diff --git a/Assets/Scripts/UnityServices/Sessions/MultiplayerServicesFacade.cs b/Assets/Scripts/UnityServices/Sessions/MultiplayerServicesFacade.cs new file mode 100644 index 000000000..63c8d3584 --- /dev/null +++ b/Assets/Scripts/UnityServices/Sessions/MultiplayerServicesFacade.cs @@ -0,0 +1,467 @@ +using System; +using System.Threading.Tasks; +using Unity.BossRoom.Infrastructure; +using Unity.Services.Authentication; +using Unity.Services.Multiplayer; +using UnityEngine; +using VContainer; +using VContainer.Unity; + +namespace Unity.BossRoom.UnityServices.Sessions +{ + /// + /// An abstraction layer between the direct calls into the Multiplayer Services SDK and the outcomes you actually want. + /// + public class MultiplayerServicesFacade : IDisposable, IStartable + { + [Inject] + LifetimeScope m_ParentScope; + [Inject] + UpdateRunner m_UpdateRunner; + [Inject] + LocalSession m_LocalSession; + [Inject] + LocalSessionUser m_LocalUser; + [Inject] + IPublisher m_UnityServiceErrorMessagePub; + [Inject] + IPublisher m_SessionListFetchedPub; + + LifetimeScope m_ServiceScope; + MultiplayerServicesInterface m_MultiplayerServicesInterface; + + RateLimitCooldown m_RateLimitQuery; + RateLimitCooldown m_RateLimitJoin; + RateLimitCooldown m_RateLimitQuickJoin; + RateLimitCooldown m_RateLimitHost; + + public ISession CurrentUnitySession { get; private set; } + + bool m_IsTracking; + + SessionEventConnectionState m_SessionEventConnectionState = SessionEventConnectionState.Unknown; + + public void Start() + { + m_ServiceScope = m_ParentScope.CreateChild(builder => + { + builder.Register(Lifetime.Singleton); + }); + + m_MultiplayerServicesInterface = m_ServiceScope.Container.Resolve(); + + //See https://docs.unity.com/ugs/manual/lobby/manual/rate-limits + m_RateLimitQuery = new RateLimitCooldown(1f); + m_RateLimitJoin = new RateLimitCooldown(1f); + m_RateLimitQuickJoin = new RateLimitCooldown(1f); + m_RateLimitHost = new RateLimitCooldown(3f); + } + + public void Dispose() + { + EndTracking(); + if (m_ServiceScope != null) + { + m_ServiceScope.Dispose(); + } + } + + public void SetRemoteSession(ISession session) + { + CurrentUnitySession = session; + m_LocalSession.ApplyRemoteData(session); + } + + /// + /// Initiates tracking of joined session's events. The host also starts sending heartbeat pings here. + /// + public void BeginTracking() + { + if (!m_IsTracking) + { + m_IsTracking = true; + SubscribeToJoinedSessionAsync(); + } + } + + /// + /// Ends tracking of joined session's events and leaves or deletes the session. The host also stops sending heartbeat + /// pings here. + /// + public void EndTracking() + { + if (m_IsTracking) + { + m_IsTracking = false; + UnsubscribeFromJoinedSessionAsync(); + } + + if (CurrentUnitySession != null) + { + if (m_LocalUser.IsHost) + { + DeleteSessionAsync(); + } + else + { + LeaveSessionAsync(); + } + } + } + + /// + /// Attempt to create a new session and then join it. + /// + public async Task<(bool Success, ISession Session)> TryCreateSessionAsync(string sessionName, int maxPlayers, bool isPrivate) + { + if (!m_RateLimitHost.CanCall) + { + Debug.LogWarning("Create Session hit the rate limit."); + return (false, null); + } + + try + { + var session = await m_MultiplayerServicesInterface.CreateSession(sessionName, + maxPlayers, + isPrivate, + m_LocalUser.GetDataForUnityServices(), + null); + return (true, session); + } + catch (Exception e) + { + PublishError(e); + } + + return (false, null); + } + + /// + /// Attempt to join an existing session with a join code. + /// + public async Task<(bool Success, ISession Session)> TryJoinSessionByCodeAsync(string sessionCode) + { + if (!m_RateLimitJoin.CanCall) + { + Debug.LogWarning("Join Session hit the rate limit."); + return (false, null); + } + + if (string.IsNullOrEmpty(sessionCode)) + { + Debug.LogWarning("Cannot join a Session without a join code."); + return (false, null); + } + + Debug.Log($"Joining session with join code {sessionCode}"); + + try + { + var session = await m_MultiplayerServicesInterface.JoinSessionByCode(sessionCode, m_LocalUser.GetDataForUnityServices()); + return (true, session); + } + catch (Exception e) + { + PublishError(e); + } + + return (false, null); + } + + /// + /// Attempt to join an existing session by name. + /// + public async Task<(bool Success, ISession Session)> TryJoinSessionByNameAsync(string sessionName) + { + if (!m_RateLimitJoin.CanCall) + { + Debug.LogWarning("Join Session hit the rate limit."); + return (false, null); + } + + if (string.IsNullOrEmpty(sessionName)) + { + Debug.LogWarning("Cannot join a Session without a session name."); + return (false, null); + } + + Debug.Log($"Joining session with name {sessionName}"); + + try + { + var session = await m_MultiplayerServicesInterface.JoinSessionById(sessionName, m_LocalUser.GetDataForUnityServices()); + return (true, session); + } + catch (Exception e) + { + PublishError(e); + } + + return (false, null); + } + + /// + /// Attempt to join the first session among the available sessions that match the filtered onlineMode. + /// + public async Task<(bool Success, ISession Session)> TryQuickJoinSessionAsync() + { + if (!m_RateLimitQuickJoin.CanCall) + { + Debug.LogWarning("Quick Join Session hit the rate limit."); + return (false, null); + } + + try + { + var session = await m_MultiplayerServicesInterface.QuickJoinSession(m_LocalUser.GetDataForUnityServices()); + return (true, session); + } + catch (Exception e) + { + PublishError(e); + } + + return (false, null); + } + + void ResetSession() + { + CurrentUnitySession = null; + m_LocalUser?.ResetState(); + m_LocalSession?.Reset(); + + // no need to disconnect Netcode, it should already be handled by Netcode's callback to disconnect + } + + void SubscribeToJoinedSessionAsync() + { + CurrentUnitySession.Changed += OnSessionChanged; + CurrentUnitySession.StateChanged += OnSessionStateChanged; + CurrentUnitySession.Deleted += OnSessionDeleted; + CurrentUnitySession.PlayerJoined += OnPlayerJoined; + CurrentUnitySession.PlayerLeft += OnPlayerLeft; + CurrentUnitySession.RemovedFromSession += OnRemovedFromSession; + CurrentUnitySession.PlayerPropertiesChanged += OnPlayerPropertiesChanged; + CurrentUnitySession.SessionPropertiesChanged += OnSessionPropertiesChanged; + } + + void UnsubscribeFromJoinedSessionAsync() + { + CurrentUnitySession.Changed -= OnSessionChanged; + CurrentUnitySession.StateChanged -= OnSessionStateChanged; + CurrentUnitySession.Deleted -= OnSessionDeleted; + CurrentUnitySession.PlayerJoined -= OnPlayerJoined; + CurrentUnitySession.PlayerLeft -= OnPlayerLeft; + CurrentUnitySession.RemovedFromSession -= OnRemovedFromSession; + CurrentUnitySession.PlayerPropertiesChanged -= OnPlayerPropertiesChanged; + CurrentUnitySession.SessionPropertiesChanged -= OnSessionPropertiesChanged; + } + + void OnSessionChanged() + { + m_LocalSession.ApplyRemoteData(CurrentUnitySession); + + // as client, check if host is still in session + if (!m_LocalUser.IsHost) + { + foreach (var sessionUser in m_LocalSession.sessionUsers) + { + if (sessionUser.Value.IsHost) + { + return; + } + } + + m_UnityServiceErrorMessagePub.Publish(new UnityServiceErrorMessage("Host left the session", "Disconnecting.", UnityServiceErrorMessage.Service.Session)); + EndTracking(); + + // no need to disconnect Netcode, it should already be handled by Netcode's callback to disconnect + } + } + + void OnSessionStateChanged(SessionState sessionState) + { + switch (sessionState) + { + case SessionState.None: + break; + case SessionState.Connected: + Debug.Log("Session state changed: Session connected."); + break; + case SessionState.Disconnected: + Debug.Log("Session state changed: Session disconnected."); + break; + case SessionState.Deleted: + Debug.Log("Session state changed: Session deleted."); + break; + default: + throw new ArgumentOutOfRangeException(nameof(sessionState), sessionState, null); + } + } + + void OnSessionDeleted() + { + Debug.Log("Session deleted."); + ResetSession(); + EndTracking(); + } + + void OnPlayerJoined(string playerId) + { + Debug.Log($"Player joined: {playerId}"); + } + + void OnPlayerLeft(string playerId) + { + Debug.Log($"Player left: {playerId}"); + } + + void OnRemovedFromSession() + { + Debug.Log("Removed from Session."); + ResetSession(); + EndTracking(); + } + + void OnPlayerPropertiesChanged() + { + Debug.Log("Player properties changed."); + } + + void OnSessionPropertiesChanged() + { + Debug.Log("Session properties changed."); + } + + /// + /// Used for getting the list of all active sessions, without needing full info for each. + /// + public async Task RetrieveAndPublishSessionListAsync() + { + if (!m_RateLimitQuery.CanCall) + { + Debug.LogWarning("Retrieving the session list hit the rate limit. Will try again soon..."); + return; + } + + try + { + var queryResults = await m_MultiplayerServicesInterface.QuerySessions(); + m_SessionListFetchedPub.Publish(new SessionListFetchedMessage(queryResults.Sessions)); + } + catch (Exception e) + { + PublishError(e); + } + } + + public async Task ReconnectToSessionAsync() + { + try + { + return await m_MultiplayerServicesInterface.ReconnectToSession(m_LocalSession.SessionID); + } + catch (Exception e) + { + PublishError(e, true); + } + + return null; + } + + /// + /// Attempt to leave a session + /// + async void LeaveSessionAsync() + { + try + { + await CurrentUnitySession.LeaveAsync(); + } + catch (Exception e) + { + PublishError(e, true); + } + finally + { + ResetSession(); + } + } + + public async void RemovePlayerFromSessionAsync(string uasId) + { + if (m_LocalUser.IsHost) + { + try + { + await CurrentUnitySession.AsHost().RemovePlayerAsync(uasId); + } + catch (Exception e) + { + PublishError(e); + } + } + else + { + Debug.LogError("Only the host can remove other players from the session."); + } + } + + async void DeleteSessionAsync() + { + if (m_LocalUser.IsHost) + { + try + { + await CurrentUnitySession.AsHost().DeleteAsync(); + } + catch (Exception e) + { + PublishError(e); + } + finally + { + ResetSession(); + } + } + else + { + Debug.LogError("Only the host can delete a session."); + } + } + + void PublishError(Exception e, bool checkIfDeleted = false) + { + if (e is not AggregateException aggregateException) + { + m_UnityServiceErrorMessagePub.Publish(new UnityServiceErrorMessage("Session Error", e.Message, UnityServiceErrorMessage.Service.Session, e)); + return; + } + + if (aggregateException.InnerException is not SessionException sessionException) + { + m_UnityServiceErrorMessagePub.Publish(new UnityServiceErrorMessage("Session Error", e.Message, UnityServiceErrorMessage.Service.Session, e)); + return; + } + + // If session is not found and if we are not the host, it has already been deleted. No need to publish the error here. + if (checkIfDeleted) + { + if (sessionException.Error == SessionError.SessionNotFound && !m_LocalUser.IsHost) + { + return; + } + } + + if (sessionException.Error == SessionError.RateLimitExceeded) + { + m_RateLimitJoin.PutOnCooldown(); + return; + } + + var reason = e.InnerException == null ? e.Message : $"{e.Message} ({e.InnerException.Message})"; // Session error type, then HTTP error type. + m_UnityServiceErrorMessagePub.Publish(new UnityServiceErrorMessage("Session Error", reason, UnityServiceErrorMessage.Service.Session, e)); + } + } +} diff --git a/Assets/Scripts/UnityServices/Lobbies/LobbyServiceFacade.cs.meta b/Assets/Scripts/UnityServices/Sessions/MultiplayerServicesFacade.cs.meta similarity index 100% rename from Assets/Scripts/UnityServices/Lobbies/LobbyServiceFacade.cs.meta rename to Assets/Scripts/UnityServices/Sessions/MultiplayerServicesFacade.cs.meta diff --git a/Assets/Scripts/UnityServices/Sessions/MultiplayerServicesInterface.cs b/Assets/Scripts/UnityServices/Sessions/MultiplayerServicesInterface.cs new file mode 100644 index 000000000..c2cc9275f --- /dev/null +++ b/Assets/Scripts/UnityServices/Sessions/MultiplayerServicesInterface.cs @@ -0,0 +1,106 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Unity.Services.Multiplayer; +using UnityEngine; + +namespace Unity.BossRoom.UnityServices.Sessions +{ + /// + /// Wrapper for all the interactions with the Sessions API. + /// + public class MultiplayerServicesInterface + { + const int k_MaxSessionsToShow = 16; // If more are necessary, consider retrieving paginated results or using filters. + const int k_MaxPlayers = 8; + + readonly List m_FilterOptions; + readonly List m_SortOptions; + + public MultiplayerServicesInterface() + { + // Filter for open sessions only + m_FilterOptions = new List + { + new(FilterField.AvailableSlots, "0", FilterOperation.Greater) + }; + + // Order by newest sessions first + m_SortOptions = new List + { + new(SortOrder.Descending, SortField.CreationTime) + }; + } + + public async Task CreateSession(string sessionName, int maxPlayers, bool isPrivate, Dictionary playerProperties, Dictionary sessionProperties) + { + var sessionOptions = new SessionOptions + { + Name = sessionName, + MaxPlayers = maxPlayers, + IsPrivate = isPrivate, + IsLocked = false, + PlayerProperties = playerProperties, + SessionProperties = sessionProperties + }.WithRelayNetwork(); + + return await MultiplayerService.Instance.CreateSessionAsync(sessionOptions); + } + + public async Task JoinSessionByCode(string sessionCode, Dictionary localUserData) + { + var joinSessionOptions = new JoinSessionOptions + { + PlayerProperties = localUserData + }; + return await MultiplayerService.Instance.JoinSessionByCodeAsync(sessionCode, joinSessionOptions); + } + + public async Task JoinSessionById(string sessionId, Dictionary localUserData) + { + var joinSessionOptions = new JoinSessionOptions + { + PlayerProperties = localUserData + }; + return await MultiplayerService.Instance.JoinSessionByIdAsync(sessionId, joinSessionOptions); + } + + public async Task QuickJoinSession(Dictionary localUserData) + { + var quickJoinOptions = new QuickJoinOptions + { + Filters = m_FilterOptions, + CreateSession = true // create a Session if no matching Session was found + }; + + var sessionOptions = new SessionOptions + { + MaxPlayers = k_MaxPlayers, + PlayerProperties = localUserData + }.WithRelayNetwork(); + + return await MultiplayerService.Instance.MatchmakeSessionAsync(quickJoinOptions, sessionOptions); + } + + public async Task QuerySessions() + { + return await MultiplayerService.Instance.QuerySessionsAsync(new QuerySessionsOptions()); + } + + public async Task ReconnectToSession(string sessionId) + { + return await MultiplayerService.Instance.ReconnectToSessionAsync(sessionId); + } + + public async Task QueryAllSessions() + { + var querySessionOptions = new QuerySessionsOptions + { + Count = k_MaxSessionsToShow, + FilterOptions = m_FilterOptions, + SortOptions = m_SortOptions + }; + return await MultiplayerService.Instance.QuerySessionsAsync(querySessionOptions); + } + } +} diff --git a/Assets/Scripts/UnityServices/Lobbies/LobbyAPIInterface.cs.meta b/Assets/Scripts/UnityServices/Sessions/MultiplayerServicesInterface.cs.meta similarity index 100% rename from Assets/Scripts/UnityServices/Lobbies/LobbyAPIInterface.cs.meta rename to Assets/Scripts/UnityServices/Sessions/MultiplayerServicesInterface.cs.meta diff --git a/Assets/Scripts/UnityServices/Unity.BossRoom.UnityServices.asmdef b/Assets/Scripts/UnityServices/Unity.BossRoom.UnityServices.asmdef index b5c8c5753..4af8b2fde 100644 --- a/Assets/Scripts/UnityServices/Unity.BossRoom.UnityServices.asmdef +++ b/Assets/Scripts/UnityServices/Unity.BossRoom.UnityServices.asmdef @@ -4,11 +4,10 @@ "references": [ "Unity.Services.Core", "Unity.Services.Authentication", - "Unity.Services.Lobbies", - "Unity.Services.Relay", "Unity.Services.Wire.Internal", "Unity.BossRoom.Infrastructure", - "VContainer" + "VContainer", + "Unity.Services.Multiplayer" ], "includePlatforms": [], "excludePlatforms": [], diff --git a/Assets/Tests/Runtime/ConnectionManagementTests.cs b/Assets/Tests/Runtime/ConnectionManagementTests.cs index ec75ae46f..f617ccfd7 100644 --- a/Assets/Tests/Runtime/ConnectionManagementTests.cs +++ b/Assets/Tests/Runtime/ConnectionManagementTests.cs @@ -5,7 +5,7 @@ using Unity.BossRoom.ConnectionManagement; using Unity.BossRoom.Infrastructure; using Unity.BossRoom.UnityServices; -using Unity.BossRoom.UnityServices.Lobbies; +using Unity.BossRoom.UnityServices.Sessions; using Unity.BossRoom.Utils; using Unity.Multiplayer.Samples.Utilities; using Unity.Netcode; @@ -40,11 +40,11 @@ protected override void Configure(IContainerBuilder builder) builder.RegisterInstance(new BufferedMessageChannel()).AsImplementedInterfaces(); builder.RegisterInstance(new MessageChannel()).AsImplementedInterfaces(); builder.RegisterInstance(new MessageChannel()).AsImplementedInterfaces(); - builder.RegisterInstance(new BufferedMessageChannel()).AsImplementedInterfaces(); - builder.Register(Lifetime.Singleton); - builder.Register(Lifetime.Singleton); + builder.RegisterInstance(new BufferedMessageChannel()).AsImplementedInterfaces(); + builder.Register(Lifetime.Singleton); + builder.Register(Lifetime.Singleton); builder.Register(Lifetime.Singleton); - builder.RegisterEntryPoint(Lifetime.Singleton).AsSelf(); + builder.RegisterEntryPoint(Lifetime.Singleton).AsSelf(); } } diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c1c4b753..04dde187f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ Additional documentation and release notes are available at [Multiplayer Documen ### Changed * Upgraded Boss Room to Netcode for GameObjects v2.0.0 * Upgraded editor version to 6000.0.25f1 +* Replaced Lobby and Relay standalone packages with the Multiplayer Services package v1.0.2 and the Sessions framework (#892) ### Cleanup * Removed ParrelSync from the project diff --git a/Packages/com.unity.multiplayer.samples.coop/CHANGELOG.md b/Packages/com.unity.multiplayer.samples.coop/CHANGELOG.md index d3af25618..e06305562 100644 --- a/Packages/com.unity.multiplayer.samples.coop/CHANGELOG.md +++ b/Packages/com.unity.multiplayer.samples.coop/CHANGELOG.md @@ -1,5 +1,11 @@ # Multiplayer Samples Co-op Changelog +## [Unreleased] + +### Changed +* Replaced Lobby and Relay standalone packages with the Multiplayer Services package v1.0.2 +* Removed UnityRelayUtilities + ## [1.9.0] - 2024-04-18 ### Changed diff --git a/Packages/com.unity.multiplayer.samples.coop/Utilities/Net/UnityRelayUtilities.cs b/Packages/com.unity.multiplayer.samples.coop/Utilities/Net/UnityRelayUtilities.cs deleted file mode 100644 index f792fe1d2..000000000 --- a/Packages/com.unity.multiplayer.samples.coop/Utilities/Net/UnityRelayUtilities.cs +++ /dev/null @@ -1,82 +0,0 @@ -using System; -using System.Linq; -using System.Threading.Tasks; -using UnityEngine; -using Unity.Services.Relay; -using Unity.Services.Relay.Models; - -namespace Unity.Multiplayer.Samples.BossRoom -{ - public static class UnityRelayUtilities - { - const string k_KDtlsConnType = "dtls"; - - /// - /// Deprecated, please see updated ConnectionManager sample code for an example on how to connect to Relay - /// - /// - /// - /// - /// - /// - public static async Task<(string ipv4address, ushort port, byte[] allocationIdBytes, byte[] connectionData, byte[] key, string joinCode)> - AllocateRelayServerAndGetJoinCode(int maxConnections, string region = null) - { - Allocation allocation; - string joinCode; - - try - { - allocation = await RelayService.Instance.CreateAllocationAsync(maxConnections, region); - } - catch (Exception exception) - { - throw new Exception($"Creating allocation request has failed: \n {exception.Message}"); - } - - Debug.Log($"server: connection data: {allocation.ConnectionData[0]} {allocation.ConnectionData[1]}, allocation ID:{allocation.AllocationId}, region:{allocation.Region}"); - - try - { - joinCode = await RelayService.Instance.GetJoinCodeAsync(allocation.AllocationId); - } - catch (Exception exception) - { - throw new Exception($"Creating join code request has failed: \n {exception.Message}"); - } - - var dtlsEndpoint = allocation.ServerEndpoints.First(e => e.ConnectionType == k_KDtlsConnType); - return (dtlsEndpoint.Host, (ushort)dtlsEndpoint.Port, allocation.AllocationIdBytes, - allocation.ConnectionData, allocation.Key, joinCode); - } - - /// - /// Deprecated, please see updated ConnectionManager sample code for an example on how to connect to Relay - /// - /// - /// - /// - /// - public static async Task<(string ipv4address, ushort port, byte[] allocationIdBytes, Guid allocationId, byte[] connectionData, byte[] hostConnectionData, byte[] key)> - JoinRelayServerFromJoinCode(string joinCode) - { - JoinAllocation allocation; - try - { - allocation = await RelayService.Instance.JoinAllocationAsync(joinCode); - } - catch (Exception exception) - { - throw new Exception($"Creating join code request has failed: \n {exception.Message}"); - } - - Debug.Log($"client: {allocation.ConnectionData[0]} {allocation.ConnectionData[1]}"); - Debug.Log($"host: {allocation.HostConnectionData[0]} {allocation.HostConnectionData[1]}"); - Debug.Log($"client: {allocation.AllocationId}"); - - var dtlsEndpoint = allocation.ServerEndpoints.First(e => e.ConnectionType == k_KDtlsConnType); - return (dtlsEndpoint.Host, (ushort)dtlsEndpoint.Port, allocation.AllocationIdBytes, allocation.AllocationId, - allocation.ConnectionData, allocation.HostConnectionData, allocation.Key); - } - } -} diff --git a/Packages/com.unity.multiplayer.samples.coop/Utilities/Net/UnityRelayUtilities.cs.meta b/Packages/com.unity.multiplayer.samples.coop/Utilities/Net/UnityRelayUtilities.cs.meta deleted file mode 100644 index 5f7c5d785..000000000 --- a/Packages/com.unity.multiplayer.samples.coop/Utilities/Net/UnityRelayUtilities.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: 4022140b8f4a4975976098b76e62e4eb -timeCreated: 1629198174 \ No newline at end of file diff --git a/Packages/com.unity.multiplayer.samples.coop/package.json b/Packages/com.unity.multiplayer.samples.coop/package.json index 0faf440a9..2fb7a82da 100644 --- a/Packages/com.unity.multiplayer.samples.coop/package.json +++ b/Packages/com.unity.multiplayer.samples.coop/package.json @@ -9,7 +9,6 @@ "dependencies": { "com.unity.learn.iet-framework": "3.1.3", "com.unity.multiplayer.tools": "1.1.0", - "com.unity.netcode.gameobjects": "1.8.1", - "com.unity.services.relay": "1.0.5" + "com.unity.netcode.gameobjects": "1.8.1" } } \ No newline at end of file diff --git a/Packages/manifest.json b/Packages/manifest.json index 45cdb2e41..f7d2d8105 100644 --- a/Packages/manifest.json +++ b/Packages/manifest.json @@ -17,8 +17,7 @@ "com.unity.postprocessing": "3.4.0", "com.unity.render-pipelines.universal": "17.0.3", "com.unity.services.authentication": "3.3.3", - "com.unity.services.lobby": "1.2.2", - "com.unity.services.relay": "1.0.5", + "com.unity.services.multiplayer": "1.0.2", "com.unity.test-framework": "1.4.5", "com.unity.timeline": "1.8.7", "com.unity.toolchain.macos-x86_64-linux-x86_64": "2.0.9", diff --git a/Packages/packages-lock.json b/Packages/packages-lock.json index d4d84dbad..dee4f7402 100644 --- a/Packages/packages-lock.json +++ b/Packages/packages-lock.json @@ -144,8 +144,7 @@ "dependencies": { "com.unity.learn.iet-framework": "3.1.3", "com.unity.multiplayer.tools": "1.1.0", - "com.unity.netcode.gameobjects": "1.8.1", - "com.unity.services.relay": "1.0.5" + "com.unity.netcode.gameobjects": "1.8.1" } }, "com.unity.multiplayer.tools": { @@ -283,20 +282,37 @@ }, "url": "https://packages.unity.com" }, - "com.unity.services.lobby": { - "version": "1.2.2", + "com.unity.services.deployment": { + "version": "1.3.0", + "depth": 1, + "source": "registry", + "dependencies": { + "com.unity.services.core": "1.12.0", + "com.unity.services.deployment.api": "1.0.0" + }, + "url": "https://packages.unity.com" + }, + "com.unity.services.deployment.api": { + "version": "1.0.0", + "depth": 2, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.com" + }, + "com.unity.services.multiplayer": { + "version": "1.0.2", "depth": 0, "source": "registry", "dependencies": { - "com.unity.services.core": "1.12.5", - "com.unity.services.wire": "1.2.6", - "com.unity.nuget.newtonsoft-json": "3.0.2", + "com.unity.transport": "2.2.1", + "com.unity.collections": "2.2.1", + "com.unity.services.qos": "1.3.0", + "com.unity.services.core": "1.13.0", + "com.unity.services.wire": "1.2.7", + "com.unity.services.deployment": "1.3.0", + "com.unity.nuget.newtonsoft-json": "3.2.1", "com.unity.modules.unitywebrequest": "1.0.0", - "com.unity.services.authentication": "2.7.4", - "com.unity.modules.unitywebrequestwww": "1.0.0", - "com.unity.modules.unitywebrequestaudio": "1.0.0", - "com.unity.modules.unitywebrequesttexture": "1.0.0", - "com.unity.modules.unitywebrequestassetbundle": "1.0.0" + "com.unity.services.authentication": "3.3.3" }, "url": "https://packages.unity.com" }, @@ -313,24 +329,6 @@ }, "url": "https://packages.unity.com" }, - "com.unity.services.relay": { - "version": "1.0.5", - "depth": 0, - "source": "registry", - "dependencies": { - "com.unity.transport": "1.3.0", - "com.unity.services.qos": "1.1.0", - "com.unity.services.core": "1.4.0", - "com.unity.nuget.newtonsoft-json": "3.0.2", - "com.unity.modules.unitywebrequest": "1.0.0", - "com.unity.services.authentication": "2.0.0", - "com.unity.modules.unitywebrequestwww": "1.0.0", - "com.unity.modules.unitywebrequestaudio": "1.0.0", - "com.unity.modules.unitywebrequesttexture": "1.0.0", - "com.unity.modules.unitywebrequestassetbundle": "1.0.0" - }, - "url": "https://packages.unity.com" - }, "com.unity.services.wire": { "version": "1.2.7", "depth": 1, diff --git a/README.md b/README.md index b8ea04ed2..1dd002be2 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Boss Room is a fully functional co-op multiplayer RPG made with Unity Netcode. I # Boss Room Sample Overview -Boss Room is designed to be used in its entirety to help you explore the concepts and patterns behind a multiplayer game flow; such as character abilities, casting animations to hide latency, replicated objects, RPCs, and integration with the [Relay](https://unity.com/products/relay), [Lobby](https://unity.com/products/lobby), and [Authentication](https://unity.com/products/authentication) services. +Boss Room is designed to be used in its entirety to help you explore the concepts and patterns behind a multiplayer game flow; such as character abilities, casting animations to hide latency, replicated objects, RPCs, and integration with [Multiplayer Services sessions](https://docs.unity.com/ugs/en-us/manual/mps-sdk/manual) and [Authentication](https://unity.com/products/authentication) services. You can use the project as a reference starting point for your own Unity game or use elements individually.

@@ -135,7 +135,7 @@ Code is organized in domain-based assemblies. See the [Boss Room architecture do ### Registering the project with Unity Gaming Services (UGS) -Boss Room leverages several services from UGS to facilitate connectivity between players. To use these services inside your project, you must [create an organization](https://support.unity.com/hc/en-us/articles/208592876-How-do-I-create-a-new-Organization-) inside the Unity Dashboard, and enable the [Relay](https://docs.unity.com/relay/get-started.html) and [Lobby](https://docs.unity.com/lobby/game-lobby-sample.html) services. Otherwise, you can still use Boss Room without UGS. +Boss Room leverages several services from UGS to facilitate connectivity between players. To use these services inside your project, you must [create an organization](https://support.unity.com/hc/en-us/articles/208592876-How-do-I-create-a-new-Organization-) inside the Unity Dashboard. Otherwise, you can still use Boss Room without UGS.


## Testing multiplayer @@ -169,7 +169,7 @@ Running the game over internet currently requires setting up a relay. ### Relay Setup -- Boss Room provides an integration with [Unity Relay](https://docs-multiplayer.unity3d.com/netcode/current/relay/). You can find our Unity Relay setup guide [here](https://docs.unity.com/ugs/en-us/manual/relay/manual/get-started) +- Boss Room uses the Multiplayer Services Package to integrate [Sessions](https://docs.unity.com/ugs/en-us/manual/mps-sdk/manual) for grouping and connecting players. - Alternatively you can use Port Forwarding. The https://portforward.com/ site has guides on how to enable port forwarding on a huge number of routers. - Boss Room uses `UDP` and needs a `9998` external port to be open. @@ -230,12 +230,12 @@ Running the game over internet currently requires setting up a relay. * Session manager - [Packages/com.unity.multiplayer.samples.coop/Utilities/Net/SessionManager.cs ](Packages/com.unity.multiplayer.samples.coop/Utilities/Net/SessionManager.cs) * RTT stats - [Assets/Scripts/Utils/NetworkOverlay/NetworkStats.cs](Assets/Scripts/Utils/NetworkOverlay/NetworkStats.cs) -### Services (Lobby, Relay, etc) -* Lobby and relay - host creation - CreateLobbyRequest() in [Assets/Scripts/Gameplay/UI/Lobby/LobbyUIMediator.cs ](Assets/Scripts/Gameplay/UI/Lobby/LobbyUIMediator.cs) -* Lobby and relay - client join - JoinLobbyRequest() in [Assets/Scripts/Gameplay/UI/Lobby/LobbyUIMediator.cs ](Assets/Scripts/Gameplay/UI/Lobby/LobbyUIMediator.cs) -* Relay Join - StartClientLobby() in [Assets/Scripts/ConnectionManagement/ConnectionState/OfflineState.cs ](Assets/Scripts/ConnectionManagement/ConnectionState/OfflineState.cs) -* Relay Create - StartHostLobby() in [Assets/Scripts/ConnectionManagement/ConnectionState/OfflineState.cs ](Assets/Scripts/ConnectionManagement/ConnectionState/OfflineState.cs) -* Subscribing to LobbyEvents - SubscribeToJoinedLobby() in [Assets/Scripts/UnityServices/Lobbies/LobbyServiceFacade.cs ](Assets/Scripts/UnityServices/Lobbies/LobbyServiceFacade.cs) +### Services (Sessions and Authentication) +* Session - host creation - CreateSessionRequest() in [Assets/Scripts/Gameplay/UI/Session/SessionUIMediator.cs ](Assets/Scripts/Gameplay/UI/Session/SessionUIMediator.cs) +* Session - client join - JoinSessionRequest() in [Assets/Scripts/Gameplay/UI/Session/SessionUIMediator.cs ](Assets/Scripts/Gameplay/UI/Session/SessionUIMediator.cs) +* Session Join with Relay - StartClientSession() in [Assets/Scripts/ConnectionManagement/ConnectionState/OfflineState.cs ](Assets/Scripts/ConnectionManagement/ConnectionState/OfflineState.cs) +* Session Create with Relay - StartHostSession() in [Assets/Scripts/ConnectionManagement/ConnectionState/OfflineState.cs ](Assets/Scripts/ConnectionManagement/ConnectionState/OfflineState.cs) +* Subscribing to SessionEvents - SubscribeToJoinedSessionAsync() in [Assets/Scripts/UnityServices/Sessions/MultiplayerServicesFacade.cs ](Assets/Scripts/UnityServices/Sessions/MultiplayerServicesFacade.cs) * Authentication - EnsurePlayerIsAuthorized() in [Assets/Scripts/UnityServices/Auth/AuthenticationServiceFacade.cs ](Assets/Scripts/UnityServices/Auth/AuthenticationServiceFacade.cs) * Authentication - Profile management for local instances - GetProfile() in [Assets/Scripts/Utils/ProfileManager.cs](Assets/Scripts/Utils/ProfileManager.cs) * Profile manager for local play [Assets/Scripts/Utils/ProfileManager.cs](Assets/Scripts/Utils/ProfileManager.cs)