From e5f3c06a8b7f916cf86e341eb61ff3dc804d3d1c Mon Sep 17 00:00:00 2001 From: Eduardo Ojeda Date: Fri, 28 Jun 2024 17:38:34 +0100 Subject: [PATCH 01/10] added explanation to readme --- README.md | 237 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 237 insertions(+) diff --git a/README.md b/README.md index 9fe9e79..8b0efd2 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,15 @@ # Multiplayer Chess Sample A sample project that demonstrates how to implement a server authoritative asynchronous multiplayer game using [Unity Gaming Services](https://unity.com/solutions/gaming-services), without needing a dedicated game server. +The game utilizes a wide range of UGS products and services to implement the following multiplayer features: + +- Server authoritative turn processing +- Automatic synchronization of game state for clients +- ELO leaderboard +- Private matches using join codes +- Public matchmaking based on player ELO ratings +- Push notifications to inactive players +- **_TODO: player login to show multi-device play?_** ## Setup @@ -39,6 +48,234 @@ ugs deploy ChessCloudCode/ChessCloudCode.sln --services cloud-code-modules ugs deploy Chess/Assets/Setup/EloRatings.lb --services leaderboards ``` +## How it works + +### Starting a match using join codes + +```plantuml +@startuml +Title Services Overview +package "Game Client" { + [Client] +} + +package "Unity Cloud Services" { + [CloudCode] + Database CloudSave + [Lobby] +} + +Client <-> CloudCode +Client <-> Lobby +Client <-> CloudSave +CloudCode <-> Lobby +CloudCode <--> CloudSave +@enduml +``` + +### Starting a match through matchmaking + +Public matches can be arranged via Matchmaker. Each client contacts Matchmaker and joins the matchmaking queue by creating a ticket. The Matchmaker service retrieves the player's ELO rating from Leaderboards, and proceeds to find another ticket with a comparable rating according to the queue configuration. + +Once a ticket pair is established, Matchmaker creates a unique match ID and returns it to both clients. Both clients execute a Cloud Code function that attempts to join that match, or if it's not yet available, create it. The clients enter an intentional race condition, where the first execution will initialize the match state and the second one will simply recieve a conflict error. + +The game state is written to a Cloud Save protected custom data record with the starting configuration of the board. Such records can be read directly by game clients, but can only be updated by a server authoritative system such as Cloud Code. The match state record contains: + +- The state of the game board +- Whether one of the players has won the game +- The IDs of both players +- Whose turn is next +- The timestamp of the last move +- A history of all previous moves + +The active match ID is also written to both player's Cloud Save Data records, so that they can automatically rejoin the match whenever the game is run. + +No matter the result of their Cloud Code initialization call, both clients fetch the game state from Cloud Save and enter the match. The appropriate player is then responsible for making the first move. + +```plantuml +@startuml +Title Services Overview +package "Game Client" { + [Client] +} + +package "Unity Cloud Services" { + [CloudCode] + Database CloudSave + [Matchmaker] + [Leaderboards] +} + +Client <-> CloudCode +Client <-> Matchmaker +Client <-> CloudSave +CloudCode <-> Matchmaker +CloudCode <--> CloudSave +Matchmaker <-> Leaderboards +@enduml +``` + +```plantuml +@startuml +Title Using Matchmaker to join matches +participant "Game Client" as Client +participant CloudCode +participant Matchmaker +database CloudSave + +Client -> Matchmaker: CreateMatchTicket() +Matchmaker -> Client: Ticket ID +Matchmaker -> Leaderboards: Get player ELO rating +Leaderboards -> Matchmaker: ELO rating +Matchmaker -> Matchmaker: Find a ticket with similar ELO +== Some time later... == +alt Match found + Matchmaker -> Client: Match Found (with Match ID) + Client -> CloudCode: CreateOrJoin(MatchId) + CloudCode -> Matchmaker: Get Match Results + Matchmaker -> CloudCode : Match Results (with list of PlayerIds) + CloudCode -> CloudSave: Initialize match state + CloudSave -> CloudCode: OK + loop foreach player + CloudCode -> CloudSave: Write Match ID to Player record + CloudSave -> CloudCode: OK + end + alt the first client to call creates the match + CloudSave -> CloudCode: OK + else + CloudSave -> CloudCode: Match already exists (WriteLock fail) + end + CloudCode -> Client: OK + Client -> CloudSave: Get Match State + CloudSave -> Client: Match State +else Timeout or failed to find match + Matchmaker -> Client: Failed to find match +end +@enduml +``` +### Making a move + +Game clients cannot be trusted to update the game state directly, as malicious players could to subvert the game by using a modified game build. In order to make a move, the game client runs a Cloud Code function that is responsible for updating the game state appropriately. Only Cloud Code is ever allowed to modify the game + +The function loads the match state from Cloud Save and validates that the player is indeed the one supposed to move next and that the move is legal. It then derives the updated game state and writes it back to the Cloud Save record, updating the move history and last move timestamp as well. + +Once state has been updated, the game clients need to be notified of the change. The game clients register a callback for Player Messages on startup, so that they can be contacted by the backend when state changes. The callback is responsible for retrieving the latest state and updating the game display appropriately. As a fallback for the server-to-client notification mechanism, the clients automatically retrieve the latest state every so often. This guarantees the game interface will react to the other player's moves. + + +```plantuml +@startuml +Title Services Overview +package "Game Client" { + [Client] +} + +package "Unity Cloud Services" { + [CloudCode] + Database CloudSave + [PlayerMessages] +} + +Client <-> CloudCode +Client <-> CloudSave +CloudCode <--> CloudSave +PlayerMessages -> Client +CloudCode -> PlayerMessages +@enduml +``` + +```plantuml +@startuml +Title Player makes move +participant "Game Client" as Client +participant CloudCode +database CloudSave +participant PlayerMessages + +Client -> CloudCode: Turn/Move event +CloudCode -> CloudSave: Get Match State for Match ID +CloudSave -> CloudCode: MatchState +CloudCode -> CloudCode: Validate player identity +CloudCode -> CloudCode: Validate move against match state +alt Validation error + CloudCode -> Client: Validation Errors +else No validation errors + CloudCode -> CloudCode: Update current match state + CloudCode -> CloudCode: Update win condition + CloudCode -> CloudCode: Add move to history + CloudCode -> CloudCode: Update last move timestamp + CloudCode -> CloudCode: Update next turn player ID + CloudCode -> CloudSave: Write back match state + CloudCode -> PlayerMessages: Notify all players in match of new match state + CloudCode -> Client: OK + == asynchronously == + PlayerMessages -> Client: Notify all players in match of new match state + writelock + Client -> CloudSave: Get Match State + CloudSave -> Client: Match State +end +== game clients always poll for match state == +loop fallback in case PlayerMessages can't reach the client + Client -> CloudSave: Get Match State + CloudSave -> Client: Match State +end +@enduml +``` + +### Sending Push Notifications + +In games with potentially long turnaround times (as can be the case with chess), the players are likely to close their game client after submitting their move. Once they do they can no longer be notified of game state updates. We need a fallback mechanism to inform them that the other player has moved and they need to open the client again and react. A system-level push notification can be a good way of achieving this. + +We can use Scheduler and Triggers to periodically execute a Cloud Code function that generates the appropriate notifications to the clients. Every event Scheduler produces corresponds to a time window the Cloud Code function is reponsible for processing. + +Using the Cloud Save Queries feature, we can index the last move timestamp stored in the match state record. The Cloud Code function can then query the system for all matches where the last move happened within it's time window of responsibility. For example, let's assume that after 10 minutes without moving we consider the player has closed their game client and needs to be notified. Let's also say that Scheduler produces an event every minute that will triggers the notification function. Every time the function runs, we can query Cloud Save for all matches where the last move happened between 10 and 11 minutes ago. Once we obtain the list of matches, we can generate notifications for all the players in them. Upon recieving the notification, the player can start their game and retrieve the updated game state. + +If we include the time window lookback as a payload parameter of the Scheduled event, multiple instances can be set up to create repeat notification windows. For example, we can set up events for notifications after 10 minutes, one hour, 3 hours and 12 hours from the last move. + +```plantuml +@startuml +Title Services Overview for Push Notifications +package "Game Client" { + [Client] +} + +package "Unity Cloud Services" { + [CloudCode] + [Scheduler] + [Triggers] + component "Push Notifications Service" as PN + Database CloudSave +} + +Scheduler -> Triggers +Triggers -> CloudCode +CloudCode <--> CloudSave +CloudCode -> PN +PN -> Client +@enduml +``` + +```plantuml +@startuml +Title Notify players of turn +participant Scheduler +participant Triggers +participant CloudCode +database CloudSave +participant "Push Notifications" as PN +participant "Game Client" as Client + +Scheduler -> Triggers: Notify Players Event +note left: every minute +Triggers -> CloudCode: Execute notify script +CloudCode -> CloudSave: Find matches where last move happened\nbetween N and N+1 minutes before schedule time +CloudSave -> CloudCode: List of matches +loop for each match in result set + CloudCode -> PN: Notify active player + PN -> Client: Send push notification +end +CloudCode -> Triggers: OK +@enduml +``` + ## Credits This project uses the [Free Low Poly Chess Set](https://assetstore.unity.com/packages/3d/props/free-low-poly-chess-set-116856) asset for the board and chess pieces, and the [Gera Chess Library](https://github.com/Geras1mleo/Chess) for validating the moves made by players. From 990c033fac2961a07a6bf82828aadbc931d5c9fa Mon Sep 17 00:00:00 2001 From: Eduardo Ojeda Date: Wed, 3 Jul 2024 11:56:04 +0100 Subject: [PATCH 02/10] wip --- Chess/Assets/Scripts.meta | 8 + Chess/Assets/Scripts/Matchmaking.cs | 9 + Chess/Assets/Scripts/Matchmaking.cs.meta | 3 + Chess/Assets/{ => Scripts}/Piece.cs | 0 Chess/Assets/{ => Scripts}/Piece.cs.meta | 0 Chess/Assets/{ => Scripts}/Player.cs | 0 Chess/Assets/{ => Scripts}/Player.cs.meta | 0 Chess/Assets/Setup/ChessDemoSetup.ddef.meta | 10 ++ Chess/Packages/manifest.json | 11 +- Chess/Packages/packages-lock.json | 86 ++++++--- Chess/ProjectSettings/ProjectVersion.txt | 4 +- Chess/UserSettings/Layouts/default-2022.dwlt | 176 +++++++++---------- 12 files changed, 186 insertions(+), 121 deletions(-) create mode 100644 Chess/Assets/Scripts.meta create mode 100644 Chess/Assets/Scripts/Matchmaking.cs create mode 100644 Chess/Assets/Scripts/Matchmaking.cs.meta rename Chess/Assets/{ => Scripts}/Piece.cs (100%) rename Chess/Assets/{ => Scripts}/Piece.cs.meta (100%) rename Chess/Assets/{ => Scripts}/Player.cs (100%) rename Chess/Assets/{ => Scripts}/Player.cs.meta (100%) create mode 100644 Chess/Assets/Setup/ChessDemoSetup.ddef.meta diff --git a/Chess/Assets/Scripts.meta b/Chess/Assets/Scripts.meta new file mode 100644 index 0000000..5504211 --- /dev/null +++ b/Chess/Assets/Scripts.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 97ab97082883649c5a6151d9d37129c4 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Chess/Assets/Scripts/Matchmaking.cs b/Chess/Assets/Scripts/Matchmaking.cs new file mode 100644 index 0000000..37f0c8f --- /dev/null +++ b/Chess/Assets/Scripts/Matchmaking.cs @@ -0,0 +1,9 @@ +using UnityEngine; + +namespace ChessGame +{ + public class Matchmaking : MonoBehaviour + { + + } +} \ No newline at end of file diff --git a/Chess/Assets/Scripts/Matchmaking.cs.meta b/Chess/Assets/Scripts/Matchmaking.cs.meta new file mode 100644 index 0000000..729b7bb --- /dev/null +++ b/Chess/Assets/Scripts/Matchmaking.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: abdabbe5de74490b82c022f059e7063c +timeCreated: 1720003791 \ No newline at end of file diff --git a/Chess/Assets/Piece.cs b/Chess/Assets/Scripts/Piece.cs similarity index 100% rename from Chess/Assets/Piece.cs rename to Chess/Assets/Scripts/Piece.cs diff --git a/Chess/Assets/Piece.cs.meta b/Chess/Assets/Scripts/Piece.cs.meta similarity index 100% rename from Chess/Assets/Piece.cs.meta rename to Chess/Assets/Scripts/Piece.cs.meta diff --git a/Chess/Assets/Player.cs b/Chess/Assets/Scripts/Player.cs similarity index 100% rename from Chess/Assets/Player.cs rename to Chess/Assets/Scripts/Player.cs diff --git a/Chess/Assets/Player.cs.meta b/Chess/Assets/Scripts/Player.cs.meta similarity index 100% rename from Chess/Assets/Player.cs.meta rename to Chess/Assets/Scripts/Player.cs.meta diff --git a/Chess/Assets/Setup/ChessDemoSetup.ddef.meta b/Chess/Assets/Setup/ChessDemoSetup.ddef.meta new file mode 100644 index 0000000..b132230 --- /dev/null +++ b/Chess/Assets/Setup/ChessDemoSetup.ddef.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: decbd7a0f979a4466b4973413fbf7438 +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: a5b15f29e7cc443c3b6d62c881c2512c, type: 3} diff --git a/Chess/Packages/manifest.json b/Chess/Packages/manifest.json index 097fdaf..8241b2b 100644 --- a/Chess/Packages/manifest.json +++ b/Chess/Packages/manifest.json @@ -1,16 +1,17 @@ { "dependencies": { - "com.unity.collab-proxy": "2.0.5", + "com.unity.collab-proxy": "2.3.1", "com.unity.feature.development": "1.0.1", - "com.unity.inputsystem": "1.6.1", - "com.unity.services.lobby": "1.0.3", + "com.unity.inputsystem": "1.7.0", "com.unity.services.cloudcode": "2.5.1", "com.unity.services.deployment": "1.3.0", "com.unity.services.leaderboards": "2.0.0", + "com.unity.services.lobby": "1.1.0", + "com.unity.services.matchmaker": "1.1.4", "com.unity.textmeshpro": "3.0.6", - "com.unity.timeline": "1.7.4", + "com.unity.timeline": "1.7.6", "com.unity.ugui": "1.0.0", - "com.unity.visualscripting": "1.8.0", + "com.unity.visualscripting": "1.9.4", "com.unity.modules.ai": "1.0.0", "com.unity.modules.androidjni": "1.0.0", "com.unity.modules.animation": "1.0.0", diff --git a/Chess/Packages/packages-lock.json b/Chess/Packages/packages-lock.json index 7fa6291..3de8bbb 100644 --- a/Chess/Packages/packages-lock.json +++ b/Chess/Packages/packages-lock.json @@ -1,7 +1,7 @@ { "dependencies": { "com.unity.collab-proxy": { - "version": "2.0.5", + "version": "2.3.1", "depth": 0, "source": "registry", "dependencies": {}, @@ -26,17 +26,17 @@ "depth": 0, "source": "builtin", "dependencies": { - "com.unity.ide.visualstudio": "2.0.18", - "com.unity.ide.rider": "3.0.24", + "com.unity.ide.visualstudio": "2.0.22", + "com.unity.ide.rider": "3.0.28", "com.unity.ide.vscode": "1.2.5", "com.unity.editorcoroutines": "1.0.0", "com.unity.performance.profile-analyzer": "1.2.2", "com.unity.test-framework": "1.1.33", - "com.unity.testtools.codecoverage": "1.2.4" + "com.unity.testtools.codecoverage": "1.2.5" } }, "com.unity.ide.rider": { - "version": "3.0.24", + "version": "3.0.28", "depth": 1, "source": "registry", "dependencies": { @@ -45,7 +45,7 @@ "url": "https://packages.unity.com" }, "com.unity.ide.visualstudio": { - "version": "2.0.18", + "version": "2.0.22", "depth": 1, "source": "registry", "dependencies": { @@ -61,7 +61,7 @@ "url": "https://packages.unity.com" }, "com.unity.inputsystem": { - "version": "1.6.1", + "version": "1.7.0", "depth": 0, "source": "registry", "dependencies": { @@ -84,24 +84,24 @@ "url": "https://packages.unity.com" }, "com.unity.services.authentication": { - "version": "2.6.1", + "version": "3.1.0", "depth": 1, "source": "registry", "dependencies": { "com.unity.nuget.newtonsoft-json": "3.2.1", - "com.unity.services.core": "1.10.1", + "com.unity.services.core": "1.12.0", "com.unity.modules.unitywebrequest": "1.0.0", "com.unity.ugui": "1.0.0" }, "url": "https://packages.unity.com" }, "com.unity.services.cloudcode": { - "version": "2.4.0", + "version": "2.5.1", "depth": 0, "source": "registry", "dependencies": { - "com.unity.services.authentication": "2.2.0", - "com.unity.services.core": "1.8.1", + "com.unity.services.authentication": "3.1.0", + "com.unity.services.core": "1.12.0", "com.unity.modules.unitywebrequest": "1.0.0", "com.unity.nuget.newtonsoft-json": "3.0.2", "com.unity.services.wire": "1.1.5" @@ -109,7 +109,7 @@ "url": "https://packages.unity.com" }, "com.unity.services.core": { - "version": "1.10.1", + "version": "1.12.5", "depth": 1, "source": "registry", "dependencies": { @@ -119,40 +119,74 @@ }, "url": "https://packages.unity.com" }, - "com.unity.services.leaderboards": { + "com.unity.services.deployment": { + "version": "1.3.0", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.services.deployment.api": "1.0.0", + "com.unity.services.core": "1.12.0" + }, + "url": "https://packages.unity.com" + }, + "com.unity.services.deployment.api": { "version": "1.0.0", + "depth": 1, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.com" + }, + "com.unity.services.leaderboards": { + "version": "2.0.0", "depth": 0, "source": "registry", "dependencies": { - "com.unity.services.authentication": "2.5.0", - "com.unity.services.core": "1.9.0" + "com.unity.services.authentication": "3.1.0", + "com.unity.services.core": "1.12.0" }, "url": "https://packages.unity.com" }, "com.unity.services.lobby": { - "version": "1.0.3", + "version": "1.1.0", "depth": 0, "source": "registry", "dependencies": { - "com.unity.services.core": "1.4.0", + "com.unity.services.core": "1.8.2", "com.unity.modules.unitywebrequest": "1.0.0", "com.unity.modules.unitywebrequestassetbundle": "1.0.0", "com.unity.modules.unitywebrequestaudio": "1.0.0", "com.unity.modules.unitywebrequesttexture": "1.0.0", "com.unity.modules.unitywebrequestwww": "1.0.0", "com.unity.nuget.newtonsoft-json": "3.0.2", - "com.unity.services.authentication": "2.0.0" + "com.unity.services.authentication": "2.1.1", + "com.unity.services.wire": "1.1.8" + }, + "url": "https://packages.unity.com" + }, + "com.unity.services.matchmaker": { + "version": "1.1.4", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.services.core": "1.12.5", + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.modules.unitywebrequestassetbundle": "1.0.0", + "com.unity.modules.unitywebrequestaudio": "1.0.0", + "com.unity.modules.unitywebrequesttexture": "1.0.0", + "com.unity.modules.unitywebrequestwww": "1.0.0", + "com.unity.nuget.newtonsoft-json": "3.0.2", + "com.unity.services.authentication": "2.7.4" }, "url": "https://packages.unity.com" }, "com.unity.services.wire": { - "version": "1.1.8", + "version": "1.2.3", "depth": 1, "source": "registry", "dependencies": { - "com.unity.services.core": "1.8.1", - "com.unity.nuget.newtonsoft-json": "3.1.0", - "com.unity.services.authentication": "2.4.0" + "com.unity.services.core": "1.12.4", + "com.unity.nuget.newtonsoft-json": "3.2.1", + "com.unity.services.authentication": "2.7.2" }, "url": "https://packages.unity.com" }, @@ -175,7 +209,7 @@ "url": "https://packages.unity.com" }, "com.unity.testtools.codecoverage": { - "version": "1.2.4", + "version": "1.2.5", "depth": 1, "source": "registry", "dependencies": { @@ -194,7 +228,7 @@ "url": "https://packages.unity.com" }, "com.unity.timeline": { - "version": "1.7.4", + "version": "1.7.6", "depth": 0, "source": "registry", "dependencies": { @@ -215,7 +249,7 @@ } }, "com.unity.visualscripting": { - "version": "1.8.0", + "version": "1.9.4", "depth": 0, "source": "registry", "dependencies": { diff --git a/Chess/ProjectSettings/ProjectVersion.txt b/Chess/ProjectSettings/ProjectVersion.txt index 8927a2e..74531a5 100644 --- a/Chess/ProjectSettings/ProjectVersion.txt +++ b/Chess/ProjectSettings/ProjectVersion.txt @@ -1,2 +1,2 @@ -m_EditorVersion: 2022.3.3f1 -m_EditorVersionWithRevision: 2022.3.3f1 (7cdc2969a641) +m_EditorVersion: 2022.3.35f1 +m_EditorVersionWithRevision: 2022.3.35f1 (011206c7a712) diff --git a/Chess/UserSettings/Layouts/default-2022.dwlt b/Chess/UserSettings/Layouts/default-2022.dwlt index 813b4da..92fc41b 100644 --- a/Chess/UserSettings/Layouts/default-2022.dwlt +++ b/Chess/UserSettings/Layouts/default-2022.dwlt @@ -14,12 +14,12 @@ MonoBehaviour: m_EditorClassIdentifier: m_PixelRect: serializedVersion: 2 - x: 155.2 - y: 42 - width: 1380.8 - height: 822 + x: 0 + y: 53 + width: 2560 + height: 1301 m_ShowMode: 4 - m_Title: Console + m_Title: Scene m_RootView: {fileID: 2} m_MinSize: {x: 875, y: 300} m_MaxSize: {x: 10000, y: 10000} @@ -44,8 +44,8 @@ MonoBehaviour: serializedVersion: 2 x: 0 y: 0 - width: 1380.8 - height: 822 + width: 2560 + height: 1301 m_MinSize: {x: 875, y: 300} m_MaxSize: {x: 10000, y: 10000} m_UseTopView: 1 @@ -69,7 +69,7 @@ MonoBehaviour: serializedVersion: 2 x: 0 y: 0 - width: 1380.8 + width: 2560 height: 30 m_MinSize: {x: 0, y: 0} m_MaxSize: {x: 0, y: 0} @@ -90,8 +90,8 @@ MonoBehaviour: m_Position: serializedVersion: 2 x: 0 - y: 802 - width: 1380.8 + y: 1281 + width: 2560 height: 20 m_MinSize: {x: 0, y: 0} m_MaxSize: {x: 0, y: 0} @@ -113,12 +113,12 @@ MonoBehaviour: serializedVersion: 2 x: 0 y: 30 - width: 1380.8 - height: 772 + width: 2560 + height: 1251 m_MinSize: {x: 300, y: 100} m_MaxSize: {x: 24288, y: 16192} vertical: 0 - controlID: 66 + controlID: 40 --- !u!114 &6 MonoBehaviour: m_ObjectHideFlags: 52 @@ -138,12 +138,12 @@ MonoBehaviour: serializedVersion: 2 x: 0 y: 0 - width: 1380.8 - height: 772 + width: 2560 + height: 1251 m_MinSize: {x: 300, y: 100} m_MaxSize: {x: 24288, y: 16192} vertical: 1 - controlID: 67 + controlID: 41 --- !u!114 &7 MonoBehaviour: m_ObjectHideFlags: 52 @@ -164,12 +164,12 @@ MonoBehaviour: serializedVersion: 2 x: 0 y: 0 - width: 1380.8 - height: 370 + width: 2560 + height: 878.5 m_MinSize: {x: 300, y: 50} m_MaxSize: {x: 24288, y: 8096} vertical: 0 - controlID: 68 + controlID: 42 --- !u!114 &8 MonoBehaviour: m_ObjectHideFlags: 52 @@ -187,8 +187,8 @@ MonoBehaviour: serializedVersion: 2 x: 0 y: 0 - width: 335.2 - height: 370 + width: 616.5 + height: 878.5 m_MinSize: {x: 201, y: 221} m_MaxSize: {x: 4001, y: 4021} m_ActualView: {fileID: 13} @@ -206,23 +206,23 @@ MonoBehaviour: m_Enabled: 1 m_EditorHideFlags: 1 m_Script: {fileID: 12006, guid: 0000000000000000e000000000000000, type: 0} - m_Name: GameView + m_Name: SceneView m_EditorClassIdentifier: m_Children: [] m_Position: serializedVersion: 2 - x: 335.2 + x: 616.5 y: 0 - width: 679.2 - height: 370 + width: 1260.5 + height: 878.5 m_MinSize: {x: 202, y: 221} m_MaxSize: {x: 4002, y: 4021} - m_ActualView: {fileID: 14} + m_ActualView: {fileID: 12} m_Panes: - {fileID: 12} - {fileID: 14} - m_Selected: 1 - m_LastSelected: 0 + m_Selected: 0 + m_LastSelected: 1 --- !u!114 &10 MonoBehaviour: m_ObjectHideFlags: 52 @@ -238,10 +238,10 @@ MonoBehaviour: m_Children: [] m_Position: serializedVersion: 2 - x: 1014.4 + x: 1877 y: 0 - width: 366.40002 - height: 370 + width: 683 + height: 878.5 m_MinSize: {x: 276, y: 121} m_MaxSize: {x: 4001, y: 4021} m_ActualView: {fileID: 15} @@ -259,24 +259,24 @@ MonoBehaviour: m_Enabled: 1 m_EditorHideFlags: 1 m_Script: {fileID: 12006, guid: 0000000000000000e000000000000000, type: 0} - m_Name: ConsoleWindow + m_Name: ProjectBrowser m_EditorClassIdentifier: m_Children: [] m_Position: serializedVersion: 2 x: 0 - y: 370 - width: 1380.8 - height: 402 - m_MinSize: {x: 100, y: 121} - m_MaxSize: {x: 4000, y: 4021} - m_ActualView: {fileID: 17} + y: 878.5 + width: 2560 + height: 372.5 + m_MinSize: {x: 230, y: 271} + m_MaxSize: {x: 10000, y: 10021} + m_ActualView: {fileID: 16} m_Panes: - {fileID: 16} - {fileID: 17} - {fileID: 18} - m_Selected: 1 - m_LastSelected: 0 + m_Selected: 0 + m_LastSelected: 1 --- !u!114 &12 MonoBehaviour: m_ObjectHideFlags: 52 @@ -297,10 +297,10 @@ MonoBehaviour: m_Tooltip: m_Pos: serializedVersion: 2 - x: 435 + x: 616.5 y: 83 - width: 879.5 - height: 629.5 + width: 1258.5 + height: 857.5 m_SerializedDataModeController: m_DataMode: 0 m_PreferredDataMode: 0 @@ -706,10 +706,10 @@ MonoBehaviour: m_Tooltip: m_Pos: serializedVersion: 2 - x: 155.2 - y: 72 - width: 334.2 - height: 349 + x: 0 + y: 83 + width: 615.5 + height: 857.5 m_SerializedDataModeController: m_DataMode: 0 m_PreferredDataMode: 0 @@ -725,7 +725,7 @@ MonoBehaviour: scrollPos: {x: 0, y: 0} m_SelectedIDs: m_LastClickedID: 0 - m_ExpandedIDs: 74f1ffff + m_ExpandedIDs: 26fbffff m_RenameOverlay: m_UserAcceptedRename: 0 m_Name: @@ -769,10 +769,10 @@ MonoBehaviour: m_Tooltip: m_Pos: serializedVersion: 2 - x: 490.4 - y: 72 - width: 677.2 - height: 349 + x: 616.5 + y: 83 + width: 1258.5 + height: 857.5 m_SerializedDataModeController: m_DataMode: 0 m_PreferredDataMode: 0 @@ -789,7 +789,7 @@ MonoBehaviour: m_ShowGizmos: 0 m_TargetDisplay: 0 m_ClearColor: {r: 0, g: 0, b: 0, a: 0} - m_TargetSize: {x: 677.2, y: 328} + m_TargetSize: {x: 1258.5, y: 836.5} m_TextureFilterMode: 0 m_TextureHideFlags: 61 m_RenderIMGUI: 1 @@ -804,17 +804,17 @@ MonoBehaviour: m_VRangeLocked: 0 hZoomLockedByDefault: 0 vZoomLockedByDefault: 0 - m_HBaseRangeMin: -135.44 - m_HBaseRangeMax: 135.44 - m_VBaseRangeMin: -65.6 - m_VBaseRangeMax: 65.6 + m_HBaseRangeMin: -314.625 + m_HBaseRangeMax: 314.625 + m_VBaseRangeMin: -209.125 + m_VBaseRangeMax: 209.125 m_HAllowExceedBaseRangeMin: 1 m_HAllowExceedBaseRangeMax: 1 m_VAllowExceedBaseRangeMin: 1 m_VAllowExceedBaseRangeMax: 1 m_ScaleWithWindow: 0 - m_HSlider: 0 - m_VSlider: 0 + m_HSlider: 1 + m_VSlider: 1 m_IgnoreScrollWheelUntilClicked: 0 m_EnableMouseInput: 1 m_EnableSliderZoomHorizontal: 0 @@ -825,23 +825,23 @@ MonoBehaviour: serializedVersion: 2 x: 0 y: 21 - width: 677.2 - height: 328 + width: 1258.5 + height: 836.5 m_Scale: {x: 2.5, y: 2.5} - m_Translation: {x: 338.6, y: 164} + m_Translation: {x: 629.25, y: 418.25} m_MarginLeft: 0 m_MarginRight: 0 m_MarginTop: 0 m_MarginBottom: 0 m_LastShownAreaInsideMargins: serializedVersion: 2 - x: -135.44 - y: -65.6 - width: 270.88 - height: 131.2 + x: -251.7 + y: -167.3 + width: 503.4 + height: 334.6 m_MinimalGUI: 1 m_defaultScale: 2 - m_LastWindowPixelSize: {x: 1693, y: 872.5} + m_LastWindowPixelSize: {x: 2517, y: 1715} m_ClearInEditMode: 1 m_NoCameraWarning: 1 m_LowResolutionForAspectRatios: 01000000000000000000 @@ -867,10 +867,10 @@ MonoBehaviour: m_Tooltip: m_Pos: serializedVersion: 2 - x: 1169.6 - y: 72 - width: 365.40002 - height: 349 + x: 1877 + y: 83 + width: 682 + height: 857.5 m_SerializedDataModeController: m_DataMode: 0 m_PreferredDataMode: 0 @@ -914,10 +914,10 @@ MonoBehaviour: m_Tooltip: m_Pos: serializedVersion: 2 - x: 155.2 - y: 338.80002 - width: 1380.8 - height: 484.2 + x: 0 + y: 961.5 + width: 2560 + height: 351.5 m_SerializedDataModeController: m_DataMode: 0 m_PreferredDataMode: 0 @@ -939,7 +939,7 @@ MonoBehaviour: m_SkipHidden: 0 m_SearchArea: 1 m_Folders: - - Assets/Setup/~ChessCloudCode + - Assets m_Globs: [] m_OriginalText: m_ImportLogFlags: 0 @@ -947,16 +947,16 @@ MonoBehaviour: m_ViewMode: 1 m_StartGridSize: 64 m_LastFolders: - - Assets/Setup/~ChessCloudCode + - Assets m_LastFoldersGridSize: -1 - m_LastProjectPath: C:\dev\general\com.unity.services.samples.multiplayer-chess-cloud-code\Chess + m_LastProjectPath: /Users/eduardoojeda/dev/com.unity.services.samples.multiplayer-chess-cloud-code/Chess m_LockTracker: m_IsLocked: 0 m_FolderTreeState: - scrollPos: {x: 0, y: 81.99982} - m_SelectedIDs: ca270000 - m_LastClickedID: 10186 - m_ExpandedIDs: 00000000c6270000ca2700002669000000ca9a3bffffff7f + scrollPos: {x: 0, y: 0} + m_SelectedIDs: e86a0000 + m_LastClickedID: 27368 + m_ExpandedIDs: 00000000e86a000000ca9a3b m_RenameOverlay: m_UserAcceptedRename: 0 m_Name: @@ -984,7 +984,7 @@ MonoBehaviour: scrollPos: {x: 0, y: 0} m_SelectedIDs: m_LastClickedID: 0 - m_ExpandedIDs: + m_ExpandedIDs: 00000000e86a0000 m_RenameOverlay: m_UserAcceptedRename: 0 m_Name: @@ -1011,7 +1011,7 @@ MonoBehaviour: m_ListAreaState: m_SelectedInstanceIDs: m_LastClickedInstanceID: 0 - m_HadKeyboardFocusLastEvent: 0 + m_HadKeyboardFocusLastEvent: 1 m_ExpandedInstanceIDs: c62300005e5d000000000000 m_RenameOverlay: m_UserAcceptedRename: 0 @@ -1060,10 +1060,10 @@ MonoBehaviour: m_Tooltip: m_Pos: serializedVersion: 2 - x: 155.2 - y: 442 - width: 1380.8 - height: 381 + x: 0 + y: 537 + width: 1728 + height: 453 m_SerializedDataModeController: m_DataMode: 0 m_PreferredDataMode: 0 From 6e6f1840a386b8f9c04491f97811429cc116dbcf Mon Sep 17 00:00:00 2001 From: Todd Harding Date: Wed, 3 Jul 2024 13:27:41 +0100 Subject: [PATCH 03/10] Added matchmaker queue config --- Chess/Assets/Setup/queue.mmq | 67 +++++++++++++++++++++++++++++++ Chess/Assets/Setup/queue.mmq.meta | 7 ++++ 2 files changed, 74 insertions(+) create mode 100644 Chess/Assets/Setup/queue.mmq create mode 100644 Chess/Assets/Setup/queue.mmq.meta diff --git a/Chess/Assets/Setup/queue.mmq b/Chess/Assets/Setup/queue.mmq new file mode 100644 index 0000000..531e393 --- /dev/null +++ b/Chess/Assets/Setup/queue.mmq @@ -0,0 +1,67 @@ +{ + "$schema": "https://ugs-config-schemas.unity3d.com/v1/matchmaker/matchmaker-queue.schema.json", + "name": "default-queue", + "enabled": true, + "maxPlayersPerTicket": 2, + "defaultPool": { + "variants": [], + "name": "default-pool", + "enabled": true, + "timeoutSeconds": 90, + "matchLogic": { + "matchDefinition": { + "teams": [ + { + "name": "Team", + "teamCount": { + "min": 2, + "max": 2, + "relaxations": [] + }, + "playerCount": { + "min": 1, + "max": 2, + "relaxations": [] + }, + "teamRules": [] + } + ], + "matchRules": [ + { + "source": "Players.ExternalData.CloudSave.Skill", + "name": "skill-diff", + "type": "Difference", + "reference": 500, + "overlap": 0.0, + "enableRule": false, + "not": false, + "relaxations": [] + }, + { + "source": "Players.QosResults.Latency", + "name": "QoS", + "type": "LessThanEqual", + "reference": 100, + "overlap": 0.0, + "enableRule": false, + "not": false, + "relaxations": [ + { + "type": "ReferenceControl.Replace", + "ageType": "Oldest", + "atSeconds": 30.0, + "value": 200 + } + ] + } + ] + }, + "name": "Default Pool Rules", + "backfillEnabled": false + }, + "matchHosting": { + "type": "MatchId" + } + }, + "filteredPools": [] +} \ No newline at end of file diff --git a/Chess/Assets/Setup/queue.mmq.meta b/Chess/Assets/Setup/queue.mmq.meta new file mode 100644 index 0000000..13bd0d6 --- /dev/null +++ b/Chess/Assets/Setup/queue.mmq.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: a5b0291d3e6df45c0b4926e0b4debac3 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: From b0545ff877f7f36070720448ad0cc723c30015e3 Mon Sep 17 00:00:00 2001 From: Eduardo Ojeda Date: Fri, 5 Jul 2024 13:06:47 +0100 Subject: [PATCH 04/10] wip --- Chess/Assets/Scenes/ChessDemo.unity | 403 +++++++++++++++--- Chess/Assets/Scripts/MatchManager.cs | 31 ++ Chess/Assets/Scripts/MatchManager.cs.meta | 3 + Chess/Assets/Scripts/Matchmaking.cs | 9 - Chess/Assets/Scripts/Matchmaking.cs.meta | 3 - Chess/Assets/Scripts/Player.cs | 15 +- Chess/Assets/Setup/{queue.mmq => Default.mmq} | 30 +- .../{queue.mmq.meta => Default.mmq.meta} | 0 Chess/Packages/manifest.json | 4 +- Chess/Packages/packages-lock.json | 104 +++-- .../PackageManagerSettings.asset | 11 +- Chess/UserSettings/Layouts/default-2022.dwlt | 165 +++---- ChessCloudCode/Chess.cs | 60 ++- README.md | 2 + TODO | 14 + 15 files changed, 630 insertions(+), 224 deletions(-) create mode 100644 Chess/Assets/Scripts/MatchManager.cs create mode 100644 Chess/Assets/Scripts/MatchManager.cs.meta delete mode 100644 Chess/Assets/Scripts/Matchmaking.cs delete mode 100644 Chess/Assets/Scripts/Matchmaking.cs.meta rename Chess/Assets/Setup/{queue.mmq => Default.mmq} (61%) rename Chess/Assets/Setup/{queue.mmq.meta => Default.mmq.meta} (100%) create mode 100644 TODO diff --git a/Chess/Assets/Scenes/ChessDemo.unity b/Chess/Assets/Scenes/ChessDemo.unity index 9616806..c1b5ab6 100644 --- a/Chess/Assets/Scenes/ChessDemo.unity +++ b/Chess/Assets/Scenes/ChessDemo.unity @@ -38,7 +38,6 @@ RenderSettings: m_ReflectionIntensity: 1 m_CustomReflection: {fileID: 0} m_Sun: {fileID: 0} - m_IndirectSpecularColor: {r: 0.4465791, g: 0.49641317, b: 0.57481784, a: 1} m_UseRadianceAmbientProbe: 0 --- !u!157 &3 LightmapSettings: @@ -149,13 +148,13 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 37427375} + serializedVersion: 2 m_LocalRotation: {x: 9.553427e-16, y: 1, z: -0.000000021855694, w: -0.00000004371139} m_LocalPosition: {x: 5, y: 0.0000003059797, z: 7} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 631113155} - m_RootOrder: -1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!64 &37427377 MeshCollider: @@ -255,13 +254,13 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 48581370} + serializedVersion: 2 m_LocalRotation: {x: -0.000000021855694, y: -0, z: -0, w: 1} m_LocalPosition: {x: 5, y: 0.00000004371139, z: 1} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 631113155} - m_RootOrder: -1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!64 &48581372 MeshCollider: @@ -367,10 +366,10 @@ RectTransform: m_Children: - {fileID: 874255098} - {fileID: 744837260} + - {fileID: 129172498} - {fileID: 1693787997} - {fileID: 220347694} m_Father: {fileID: 908034760} - m_RootOrder: -1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 1, y: 1} @@ -441,13 +440,13 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 75352243} + serializedVersion: 2 m_LocalRotation: {x: -0.000000021855694, y: -0, z: -0, w: 1} m_LocalPosition: {x: 5, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 631113155} - m_RootOrder: -1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!64 &75352245 MeshCollider: @@ -547,13 +546,13 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 128748984} + serializedVersion: 2 m_LocalRotation: {x: 9.553427e-16, y: 1, z: -0.000000021855694, w: -0.00000004371139} m_LocalPosition: {x: 5, y: 0.00000026226832, z: 6} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 631113155} - m_RootOrder: -1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!64 &128748986 MeshCollider: @@ -627,6 +626,139 @@ MeshFilter: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 128748984} m_Mesh: {fileID: 4300000, guid: 1ae3b6cad3254b848942cea678f244c7, type: 3} +--- !u!1 &129172497 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 129172498} + - component: {fileID: 129172501} + - component: {fileID: 129172500} + - component: {fileID: 129172499} + m_Layer: 5 + m_Name: Find Button + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &129172498 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 129172497} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 1795115908} + m_Father: {fileID: 74450293} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 80} + m_SizeDelta: {x: 160, y: 30} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &129172499 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 129172497} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.7830189, g: 0.7830189, b: 0.7830189, a: 1} + m_PressedColor: {r: 0.6698113, g: 0.6698113, b: 0.6698113, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 129172500} + m_OnClick: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 1881174974} + m_TargetAssemblyTypeName: Player, Assembly-CSharp + m_MethodName: CreateGame + m_Mode: 1 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 +--- !u!114 &129172500 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 129172497} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 0 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &129172501 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 129172497} + m_CullTransparentMesh: 1 --- !u!1 &161468093 GameObject: m_ObjectHideFlags: 0 @@ -650,6 +782,7 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 161468093} + serializedVersion: 2 m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 3.5, y: 0, z: 3.5} m_LocalScale: {x: 1, y: 1, z: 1} @@ -657,7 +790,6 @@ Transform: m_Children: - {fileID: 631113155} m_Father: {fileID: 0} - m_RootOrder: 1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &200233927 GameObject: @@ -685,13 +817,13 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 200233927} + serializedVersion: 2 m_LocalRotation: {x: 9.553427e-16, y: 1, z: -0.000000021855694, w: -0.00000004371139} m_LocalPosition: {x: 1, y: 0.00000026226832, z: 6} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 631113155} - m_RootOrder: -1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!64 &200233929 MeshCollider: @@ -791,13 +923,13 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 213516277} + serializedVersion: 2 m_LocalRotation: {x: 9.553427e-16, y: 1, z: -0.000000021855694, w: -0.00000004371139} m_LocalPosition: {x: 3, y: 0.00000026226832, z: 6} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 631113155} - m_RootOrder: -1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!64 &213516279 MeshCollider: @@ -902,7 +1034,6 @@ RectTransform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 74450293} - m_RootOrder: -1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.5, y: 0.5} m_AnchorMax: {x: 0.5, y: 0.5} @@ -1037,7 +1168,6 @@ RectTransform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 874255098} - m_RootOrder: -1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 1, y: 1} @@ -1167,13 +1297,13 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 307732244} + serializedVersion: 2 m_LocalRotation: {x: 9.553427e-16, y: 1, z: -0.000000021855694, w: -0.00000004371139} m_LocalPosition: {x: 4, y: 0.0000003059797, z: 7} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 631113155} - m_RootOrder: -1 m_LocalEulerAnglesHint: {x: 0, y: 180, z: 0} --- !u!64 &307732246 MeshCollider: @@ -1279,7 +1409,6 @@ RectTransform: - {fileID: 2038119199} - {fileID: 1112684033} m_Father: {fileID: 1693787997} - m_RootOrder: -1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 1, y: 1} @@ -1326,13 +1455,13 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 325610623} + serializedVersion: 2 m_LocalRotation: {x: -0.000000021855694, y: -0, z: -0, w: 1} m_LocalPosition: {x: 2, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 631113155} - m_RootOrder: -1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!64 &325610625 MeshCollider: @@ -1432,13 +1561,13 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 414792898} + serializedVersion: 2 m_LocalRotation: {x: 9.553427e-16, y: 1, z: -0.000000021855694, w: -0.00000004371139} m_LocalPosition: {x: 1, y: 0.0000003059797, z: 7} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 631113155} - m_RootOrder: -1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!64 &414792900 MeshCollider: @@ -1538,13 +1667,13 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 449874633} + serializedVersion: 2 m_LocalRotation: {x: -0.000000021855694, y: -0, z: -0, w: 1} m_LocalPosition: {x: 4, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 631113155} - m_RootOrder: -1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!64 &449874635 MeshCollider: @@ -1654,13 +1783,13 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 656049610} + serializedVersion: 2 m_LocalRotation: {x: -0.000000021855694, y: -0, z: -0, w: 1} m_LocalPosition: {x: 6, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 631113155} - m_RootOrder: -1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!64 &656049612 MeshCollider: @@ -1760,13 +1889,13 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 682251755} + serializedVersion: 2 m_LocalRotation: {x: -0.000000021855694, y: -0, z: -0, w: 1} m_LocalPosition: {x: 7, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 631113155} - m_RootOrder: -1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!64 &682251757 MeshCollider: @@ -1866,13 +1995,13 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 725736685} + serializedVersion: 2 m_LocalRotation: {x: -0.000000021855694, y: -0, z: -0, w: 1} m_LocalPosition: {x: 6, y: 0.00000004371139, z: 1} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 631113155} - m_RootOrder: -1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!64 &725736687 MeshCollider: @@ -1979,11 +2108,10 @@ RectTransform: m_Children: - {fileID: 1234927403} m_Father: {fileID: 74450293} - m_RootOrder: -1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.5, y: 0.5} m_AnchorMax: {x: 0.5, y: 0.5} - m_AnchoredPosition: {x: 0, y: 89} + m_AnchoredPosition: {x: 0, y: -10} m_SizeDelta: {x: 160, y: 30} m_Pivot: {x: 0.5, y: 0.5} --- !u!114 &744837261 @@ -2092,7 +2220,7 @@ GameObject: - component: {fileID: 756768991} - component: {fileID: 756768990} m_Layer: 5 - m_Name: Lobby Code Text (TMP) + m_Name: Join Code Text (TMP) m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 @@ -2111,7 +2239,6 @@ RectTransform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 1544248098} - m_RootOrder: -1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.6906753, y: 0.88533866} m_AnchorMax: {x: 0.9801624, y: 0.97137696} @@ -2138,7 +2265,7 @@ MonoBehaviour: m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_text: + m_text: m_isRightToLeft: 0 m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} @@ -2301,13 +2428,13 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 807870249} + serializedVersion: 2 m_LocalRotation: {x: 0.10938167, y: 0.8754261, z: -0.40821788, w: 0.23456976} m_LocalPosition: {x: 0, y: 3, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} - m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 50, y: 150, z: 0} --- !u!1 &874255097 GameObject: @@ -2342,7 +2469,6 @@ RectTransform: m_Children: - {fileID: 287442523} m_Father: {fileID: 74450293} - m_RootOrder: -1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.5, y: 0.5} m_AnchorMax: {x: 0.5, y: 0.5} @@ -2540,7 +2666,6 @@ RectTransform: - {fileID: 74450293} - {fileID: 1544248098} m_Father: {fileID: 0} - m_RootOrder: 4 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 0, y: 0} @@ -2573,13 +2698,13 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 912573191} + serializedVersion: 2 m_LocalRotation: {x: 9.553427e-16, y: 1, z: -0.000000021855694, w: -0.00000004371139} m_LocalPosition: {x: 0, y: 0.00000026226832, z: 6} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 631113155} - m_RootOrder: -1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!64 &912573193 MeshCollider: @@ -2679,13 +2804,13 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 918073342} + serializedVersion: 2 m_LocalRotation: {x: 9.553427e-16, y: 1, z: -0.000000021855694, w: -0.00000004371139} m_LocalPosition: {x: 0, y: 0.0000003059797, z: 7} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 631113155} - m_RootOrder: -1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!64 &918073344 MeshCollider: @@ -2790,7 +2915,6 @@ RectTransform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 1676727204} - m_RootOrder: -1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 1, y: 1} @@ -2917,6 +3041,7 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1035193158} + serializedVersion: 2 m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 3.5, y: 0, z: 3.5} m_LocalScale: {x: 1, y: 1, z: 1} @@ -2924,7 +3049,6 @@ Transform: m_Children: - {fileID: 1974944745} m_Father: {fileID: 0} - m_RootOrder: 2 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &1112684032 GameObject: @@ -2957,7 +3081,6 @@ RectTransform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 312391764} - m_RootOrder: -1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 1, y: 1} @@ -3087,13 +3210,13 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1117633118} + serializedVersion: 2 m_LocalRotation: {x: 9.553427e-16, y: 1, z: -0.000000021855694, w: -0.00000004371139} m_LocalPosition: {x: 2, y: 0.0000003059797, z: 7} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 631113155} - m_RootOrder: -1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!64 &1117633120 MeshCollider: @@ -3257,13 +3380,13 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1170277842} + serializedVersion: 2 m_LocalRotation: {x: -0.000000021855694, y: -0, z: -0, w: 1} m_LocalPosition: {x: 0, y: 0.00000004371139, z: 1} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 631113155} - m_RootOrder: -1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!64 &1170277844 MeshCollider: @@ -3368,7 +3491,6 @@ RectTransform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 744837260} - m_RootOrder: -1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 1, y: 1} @@ -3498,13 +3620,13 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1242490634} + serializedVersion: 2 m_LocalRotation: {x: 9.553427e-16, y: 1, z: -0.000000021855694, w: -0.00000004371139} m_LocalPosition: {x: 4, y: 0.00000026226832, z: 6} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 631113155} - m_RootOrder: -1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!64 &1242490636 MeshCollider: @@ -3609,7 +3731,6 @@ RectTransform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 1544248098} - m_RootOrder: -1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.03543989, y: 0.8981307} m_AnchorMax: {x: 0.48631966, y: 0.9604123} @@ -3880,13 +4001,13 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1393921725} + serializedVersion: 2 m_LocalRotation: {x: -0.000000021855694, y: -0, z: -0, w: 1} m_LocalPosition: {x: 1, y: 0.00000004371139, z: 1} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 631113155} - m_RootOrder: -1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!64 &1393921727 MeshCollider: @@ -3991,11 +4112,10 @@ RectTransform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 1544248098} - m_RootOrder: -1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.030859973, y: 0.014654879} m_AnchorMax: {x: 0.48631966, y: 0.08413721} - m_AnchoredPosition: {x: -1.5, y: -2} + m_AnchoredPosition: {x: -1.5, y: -2.000061} m_SizeDelta: {x: 1, y: 2} m_Pivot: {x: 0.5, y: 0.5} --- !u!114 &1522302540 @@ -4132,7 +4252,6 @@ RectTransform: - {fileID: 2130390096} - {fileID: 1676727204} m_Father: {fileID: 908034760} - m_RootOrder: -1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 1, y: 1} @@ -4208,7 +4327,6 @@ RectTransform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 1544248098} - m_RootOrder: -1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.030859973, y: 0.08413721} m_AnchorMax: {x: 0.48631966, y: 0.15730974} @@ -4338,13 +4456,13 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1586274340} + serializedVersion: 2 m_LocalRotation: {x: -0.000000021855694, y: -0, z: -0, w: 1} m_LocalPosition: {x: 3, y: 0.00000004371139, z: 1} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 631113155} - m_RootOrder: -1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!64 &1586274342 MeshCollider: @@ -4444,13 +4562,13 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1622118773} + serializedVersion: 2 m_LocalRotation: {x: -0.000000021855694, y: -0, z: -0, w: 1} m_LocalPosition: {x: 3, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 631113155} - m_RootOrder: -1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!64 &1622118775 MeshCollider: @@ -4557,7 +4675,6 @@ RectTransform: m_Children: - {fileID: 991883428} m_Father: {fileID: 1544248098} - m_RootOrder: -1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.030859973, y: 0.202} m_AnchorMax: {x: 0.18878047, y: 0.25} @@ -4671,7 +4788,7 @@ GameObject: - component: {fileID: 1693787999} - component: {fileID: 1693787998} m_Layer: 5 - m_Name: Lobby Code Input + m_Name: Join Code Input m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 @@ -4691,7 +4808,6 @@ RectTransform: m_Children: - {fileID: 312391764} m_Father: {fileID: 74450293} - m_RootOrder: -1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.5, y: 0.5} m_AnchorMax: {x: 0.5, y: 0.5} @@ -4860,13 +4976,13 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1738690013} + serializedVersion: 2 m_LocalRotation: {x: -0.000000021855694, y: -0, z: -0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 631113155} - m_RootOrder: -1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!64 &1738690015 MeshCollider: @@ -4966,13 +5082,13 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1758319147} + serializedVersion: 2 m_LocalRotation: {x: 9.553427e-16, y: 1, z: -0.000000021855694, w: -0.00000004371139} m_LocalPosition: {x: 2, y: 0.00000026226832, z: 6} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 631113155} - m_RootOrder: -1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!64 &1758319149 MeshCollider: @@ -5072,13 +5188,13 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1777222571} + serializedVersion: 2 m_LocalRotation: {x: 9.553427e-16, y: 1, z: -0.000000021855694, w: -0.00000004371139} m_LocalPosition: {x: 3, y: 0.0000003059797, z: 7} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 631113155} - m_RootOrder: -1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!64 &1777222573 MeshCollider: @@ -5152,6 +5268,140 @@ MeshFilter: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1777222571} m_Mesh: {fileID: 4300000, guid: 8d213db23e89f6b4fa3d427f07a32b13, type: 3} +--- !u!1 &1795115907 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1795115908} + - component: {fileID: 1795115910} + - component: {fileID: 1795115909} + m_Layer: 5 + m_Name: Text (TMP) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1795115908 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1795115907} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 129172498} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1795115909 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1795115907} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_text: Find Game + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4281479730 + m_fontColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_enableVertexGradient: 0 + m_colorMode: 3 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_StyleSheet: {fileID: 0} + m_TextStyleHashCode: -1183493901 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 24 + m_fontSizeBase: 24 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 0 + m_HorizontalAlignment: 2 + m_VerticalAlignment: 512 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 1 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 1 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_IsTextObjectScaleStatic: 0 + m_VertexBufferAutoSizeReduction: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_hasFontAssetChanged: 0 + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!222 &1795115910 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1795115907} + m_CullTransparentMesh: 1 --- !u!1 &1835524139 GameObject: m_ObjectHideFlags: 0 @@ -5222,13 +5472,13 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1835524139} + serializedVersion: 2 m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} - m_RootOrder: 5 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &1881174973 GameObject: @@ -5241,6 +5491,7 @@ GameObject: - component: {fileID: 1881174975} - component: {fileID: 1881174974} - component: {fileID: 1881174976} + - component: {fileID: 1881174977} m_Layer: 0 m_Name: Player m_TagString: Untagged @@ -5262,8 +5513,8 @@ MonoBehaviour: m_EditorClassIdentifier: playerCamera: {fileID: 1974944749} cameraPivot: {fileID: 1035193158} - lobbyInputCodeText: {fileID: 1112684034} - lobbyCodeText: {fileID: 756768990} + joinCodeInput: {fileID: 0} + joinCodeDisplayText: {fileID: 0} playerNameText: {fileID: 1546221354} playerEloText: {fileID: 1522302540} opponentNameText: {fileID: 1266149770} @@ -5279,13 +5530,13 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1881174973} + serializedVersion: 2 m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 2.246233, y: -2.1321354, z: -0.3700037} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} - m_RootOrder: 3 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!114 &1881174976 MonoBehaviour: @@ -5381,6 +5632,18 @@ MonoBehaviour: m_DefaultActionMap: Player m_SplitScreenIndex: -1 m_Camera: {fileID: 1974944749} +--- !u!114 &1881174977 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1881174973} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: abdabbe5de74490b82c022f059e7063c, type: 3} + m_Name: + m_EditorClassIdentifier: --- !u!1 &1941642356 GameObject: m_ObjectHideFlags: 0 @@ -5407,13 +5670,13 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1941642356} + serializedVersion: 2 m_LocalRotation: {x: 9.553427e-16, y: 1, z: -0.000000021855694, w: -0.00000004371139} m_LocalPosition: {x: 6, y: 0.0000003059797, z: 7} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 631113155} - m_RootOrder: -1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!64 &1941642358 MeshCollider: @@ -5513,13 +5776,13 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1974944744} + serializedVersion: 2 m_LocalRotation: {x: 0.5, y: 0, z: 0, w: 0.8660254} m_LocalPosition: {x: 0, y: 15, z: -9.5} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 1035193159} - m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 60, y: 0, z: 0} --- !u!81 &1974944747 AudioListener: @@ -5614,13 +5877,13 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1977734249} + serializedVersion: 2 m_LocalRotation: {x: 9.553427e-16, y: 1, z: -0.000000021855694, w: -0.00000004371139} m_LocalPosition: {x: 7, y: 0.0000003059797, z: 7} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 631113155} - m_RootOrder: -1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!64 &1977734251 MeshCollider: @@ -5720,13 +5983,13 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 2002527198} + serializedVersion: 2 m_LocalRotation: {x: -0.000000021855694, y: -0, z: -0, w: 1} m_LocalPosition: {x: 4, y: 0.00000004371139, z: 1} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 631113155} - m_RootOrder: -1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!64 &2002527200 MeshCollider: @@ -5826,13 +6089,13 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 2025034869} + serializedVersion: 2 m_LocalRotation: {x: 9.553427e-16, y: 1, z: -0.000000021855694, w: -0.00000004371139} m_LocalPosition: {x: 6, y: 0.00000026226832, z: 6} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 631113155} - m_RootOrder: -1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!64 &2025034871 MeshCollider: @@ -5932,13 +6195,13 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 2033846001} + serializedVersion: 2 m_LocalRotation: {x: -0.000000021855694, y: -0, z: -0, w: 1} m_LocalPosition: {x: 1, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 631113155} - m_RootOrder: -1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!64 &2033846003 MeshCollider: @@ -6044,7 +6307,6 @@ RectTransform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 312391764} - m_RootOrder: -1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 1, y: 1} @@ -6091,7 +6353,7 @@ MonoBehaviour: m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_text: Enter lobby code... + m_text: Enter join code... m_isRightToLeft: 0 m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} @@ -6194,13 +6456,13 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 2065325157} + serializedVersion: 2 m_LocalRotation: {x: -0.000000021855694, y: -0, z: -0, w: 1} m_LocalPosition: {x: 7, y: 0.00000004371139, z: 1} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 631113155} - m_RootOrder: -1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!64 &2065325159 MeshCollider: @@ -6300,13 +6562,13 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 2073016748} + serializedVersion: 2 m_LocalRotation: {x: -0.000000021855694, y: -0, z: -0, w: 1} m_LocalPosition: {x: 2, y: 0.00000004371139, z: 1} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 631113155} - m_RootOrder: -1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!64 &2073016750 MeshCollider: @@ -6406,13 +6668,13 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 2121728206} + serializedVersion: 2 m_LocalRotation: {x: 9.553427e-16, y: 1, z: -0.000000021855694, w: -0.00000004371139} m_LocalPosition: {x: 7, y: 0.00000026226832, z: 6} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 631113155} - m_RootOrder: -1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!64 &2121728208 MeshCollider: @@ -6517,7 +6779,6 @@ RectTransform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 1544248098} - m_RootOrder: -1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.03543989, y: 0.83041155} m_AnchorMax: {x: 0.48631966, y: 0.8981307} @@ -6621,3 +6882,13 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 2130390095} m_CullTransparentMesh: 1 +--- !u!1660057539 &9223372036854775807 +SceneRoots: + m_ObjectHideFlags: 0 + m_Roots: + - {fileID: 807870251} + - {fileID: 161468094} + - {fileID: 1035193159} + - {fileID: 1881174975} + - {fileID: 908034760} + - {fileID: 1835524142} diff --git a/Chess/Assets/Scripts/MatchManager.cs b/Chess/Assets/Scripts/MatchManager.cs new file mode 100644 index 0000000..6301b35 --- /dev/null +++ b/Chess/Assets/Scripts/MatchManager.cs @@ -0,0 +1,31 @@ +using System.Threading; +using Unity.Services.Multiplayer; +using UnityEngine; + +namespace DefaultNamespace +{ + public class MatchManager : MonoBehaviour + { + + + async void FindMatch() + { + var matchmakerOptions = new MatchmakerOptions + { + QueueName = "default-queue" + }; + + var sessionOptions = new SessionOptions() + { + MaxPlayers = 2, + IsPrivate = true + }; + + var matchmakerCancellationSource = new CancellationTokenSource(); + + var session = await MultiplayerService.Instance.MatchmakeSessionAsync(matchmakerOptions, sessionOptions, matchmakerCancellationSource.Token); + + //session.Id; // == matchId == lobbyId + } + } +} \ No newline at end of file diff --git a/Chess/Assets/Scripts/MatchManager.cs.meta b/Chess/Assets/Scripts/MatchManager.cs.meta new file mode 100644 index 0000000..6787147 --- /dev/null +++ b/Chess/Assets/Scripts/MatchManager.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 91ab04a1e4af4bffb3908fe5fe47d74e +timeCreated: 1720091680 \ No newline at end of file diff --git a/Chess/Assets/Scripts/Matchmaking.cs b/Chess/Assets/Scripts/Matchmaking.cs deleted file mode 100644 index 37f0c8f..0000000 --- a/Chess/Assets/Scripts/Matchmaking.cs +++ /dev/null @@ -1,9 +0,0 @@ -using UnityEngine; - -namespace ChessGame -{ - public class Matchmaking : MonoBehaviour - { - - } -} \ No newline at end of file diff --git a/Chess/Assets/Scripts/Matchmaking.cs.meta b/Chess/Assets/Scripts/Matchmaking.cs.meta deleted file mode 100644 index 729b7bb..0000000 --- a/Chess/Assets/Scripts/Matchmaking.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: abdabbe5de74490b82c022f059e7063c -timeCreated: 1720003791 \ No newline at end of file diff --git a/Chess/Assets/Scripts/Player.cs b/Chess/Assets/Scripts/Player.cs index ea12302..03375bc 100644 --- a/Chess/Assets/Scripts/Player.cs +++ b/Chess/Assets/Scripts/Player.cs @@ -12,22 +12,17 @@ using Unity.Services.Leaderboards; using Unity.Services.Leaderboards.Exceptions; using Unity.Services.Lobbies; -using Unity.Services.Lobbies.Models; using Unity.VisualScripting; using UnityEngine; -using UnityEngine.Analytics; using UnityEngine.InputSystem; -using UnityEngine.Serialization; -using UnityEngine.SocialPlatforms.Impl; -using WebSocketSharp; public class Player : MonoBehaviour { private GameObject _selectedPiece; public Camera playerCamera; public GameObject cameraPivot; - public TextMeshProUGUI lobbyInputCodeText; - public TextMeshProUGUI lobbyCodeText; + public TextMeshProUGUI joinCodeInput; + public TextMeshProUGUI joinCodeDisplayText; public TextMeshProUGUI playerNameText; public TextMeshProUGUI playerEloText; @@ -103,7 +98,7 @@ public async void CreateGame() { var hostGameResponse = await CloudCodeService.Instance.CallModuleEndpointAsync("ChessCloudCode", "HostGame"); - lobbyCodeText.text = hostGameResponse.LobbyCode; + joinCodeDisplayText.text = hostGameResponse.LobbyCode; } private void SetPov() @@ -131,11 +126,11 @@ public async void JoinLobbyByCode() try { // There's a weird no space character that gets added to the end of the lobby code, let's remove it for now - var sanitizedLobbyCode = Regex.Replace(lobbyInputCodeText.text, @"\s", "").Replace("\u200B", ""); + var sanitizedLobbyCode = Regex.Replace(joinCodeInput.text, @"\s", "").Replace("\u200B", ""); var joinGameResponse = await CloudCodeService.Instance.CallModuleEndpointAsync("ChessCloudCode", "JoinGame", new Dictionary { { "lobbyCode", sanitizedLobbyCode } }); - lobbyCodeText.text = sanitizedLobbyCode; + joinCodeDisplayText.text = sanitizedLobbyCode; OnGameStart(joinGameResponse); } diff --git a/Chess/Assets/Setup/queue.mmq b/Chess/Assets/Setup/Default.mmq similarity index 61% rename from Chess/Assets/Setup/queue.mmq rename to Chess/Assets/Setup/Default.mmq index 531e393..6b65222 100644 --- a/Chess/Assets/Setup/queue.mmq +++ b/Chess/Assets/Setup/Default.mmq @@ -19,7 +19,7 @@ "relaxations": [] }, "playerCount": { - "min": 1, + "min": 2, "max": 2, "relaxations": [] }, @@ -28,31 +28,19 @@ ], "matchRules": [ { - "source": "Players.ExternalData.CloudSave.Skill", - "name": "skill-diff", + "name": "elo-rating", + "source": "Players.CustomData.ExternalData.Leaderboard.Score", + "ExternalData": { + "Leaderboard": { + "Id": "EloRatings" + } + }, "type": "Difference", "reference": 500, "overlap": 0.0, - "enableRule": false, + "enableRule": true, "not": false, "relaxations": [] - }, - { - "source": "Players.QosResults.Latency", - "name": "QoS", - "type": "LessThanEqual", - "reference": 100, - "overlap": 0.0, - "enableRule": false, - "not": false, - "relaxations": [ - { - "type": "ReferenceControl.Replace", - "ageType": "Oldest", - "atSeconds": 30.0, - "value": 200 - } - ] } ] }, diff --git a/Chess/Assets/Setup/queue.mmq.meta b/Chess/Assets/Setup/Default.mmq.meta similarity index 100% rename from Chess/Assets/Setup/queue.mmq.meta rename to Chess/Assets/Setup/Default.mmq.meta diff --git a/Chess/Packages/manifest.json b/Chess/Packages/manifest.json index 8241b2b..4bc3667 100644 --- a/Chess/Packages/manifest.json +++ b/Chess/Packages/manifest.json @@ -2,12 +2,12 @@ "dependencies": { "com.unity.collab-proxy": "2.3.1", "com.unity.feature.development": "1.0.1", + "com.unity.ide.rider": "3.0.31", "com.unity.inputsystem": "1.7.0", "com.unity.services.cloudcode": "2.5.1", "com.unity.services.deployment": "1.3.0", "com.unity.services.leaderboards": "2.0.0", - "com.unity.services.lobby": "1.1.0", - "com.unity.services.matchmaker": "1.1.4", + "com.unity.services.multiplayer": "0.5.1", "com.unity.textmeshpro": "3.0.6", "com.unity.timeline": "1.7.6", "com.unity.ugui": "1.0.0", diff --git a/Chess/Packages/packages-lock.json b/Chess/Packages/packages-lock.json index 3de8bbb..2dd31c4 100644 --- a/Chess/Packages/packages-lock.json +++ b/Chess/Packages/packages-lock.json @@ -1,5 +1,15 @@ { "dependencies": { + "com.unity.burst": { + "version": "1.8.16", + "depth": 2, + "source": "registry", + "dependencies": { + "com.unity.mathematics": "1.2.1", + "com.unity.modules.jsonserialize": "1.0.0" + }, + "url": "https://packages.unity.com" + }, "com.unity.collab-proxy": { "version": "2.3.1", "depth": 0, @@ -7,6 +17,18 @@ "dependencies": {}, "url": "https://packages.unity.com" }, + "com.unity.collections": { + "version": "2.2.1", + "depth": 1, + "source": "registry", + "dependencies": { + "com.unity.burst": "1.8.8", + "com.unity.modules.unityanalytics": "1.0.0", + "com.unity.nuget.mono-cecil": "1.11.4", + "com.unity.test-framework.performance": "3.0.2" + }, + "url": "https://packages.unity.com" + }, "com.unity.editorcoroutines": { "version": "1.0.0", "depth": 1, @@ -16,7 +38,7 @@ }, "com.unity.ext.nunit": { "version": "1.0.6", - "depth": 2, + "depth": 1, "source": "registry", "dependencies": {}, "url": "https://packages.unity.com" @@ -36,8 +58,8 @@ } }, "com.unity.ide.rider": { - "version": "3.0.28", - "depth": 1, + "version": "3.0.31", + "depth": 0, "source": "registry", "dependencies": { "com.unity.ext.nunit": "1.0.6" @@ -69,6 +91,20 @@ }, "url": "https://packages.unity.com" }, + "com.unity.mathematics": { + "version": "1.3.1", + "depth": 2, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.com" + }, + "com.unity.nuget.mono-cecil": { + "version": "1.11.4", + "depth": 2, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.com" + }, "com.unity.nuget.newtonsoft-json": { "version": "3.2.1", "depth": 1, @@ -84,12 +120,12 @@ "url": "https://packages.unity.com" }, "com.unity.services.authentication": { - "version": "3.1.0", + "version": "3.3.3", "depth": 1, "source": "registry", "dependencies": { "com.unity.nuget.newtonsoft-json": "3.2.1", - "com.unity.services.core": "1.12.0", + "com.unity.services.core": "1.13.0", "com.unity.modules.unitywebrequest": "1.0.0", "com.unity.ugui": "1.0.0" }, @@ -109,7 +145,7 @@ "url": "https://packages.unity.com" }, "com.unity.services.core": { - "version": "1.12.5", + "version": "1.13.0", "depth": 1, "source": "registry", "dependencies": { @@ -146,36 +182,33 @@ }, "url": "https://packages.unity.com" }, - "com.unity.services.lobby": { - "version": "1.1.0", + "com.unity.services.multiplayer": { + "version": "0.5.1", "depth": 0, "source": "registry", "dependencies": { - "com.unity.services.core": "1.8.2", "com.unity.modules.unitywebrequest": "1.0.0", - "com.unity.modules.unitywebrequestassetbundle": "1.0.0", - "com.unity.modules.unitywebrequestaudio": "1.0.0", - "com.unity.modules.unitywebrequesttexture": "1.0.0", - "com.unity.modules.unitywebrequestwww": "1.0.0", - "com.unity.nuget.newtonsoft-json": "3.0.2", - "com.unity.services.authentication": "2.1.1", - "com.unity.services.wire": "1.1.8" + "com.unity.nuget.newtonsoft-json": "3.2.1", + "com.unity.services.authentication": "3.3.3", + "com.unity.services.core": "1.13.0", + "com.unity.services.qos": "1.3.0", + "com.unity.services.wire": "1.2.3", + "com.unity.transport": "2.2.1", + "com.unity.collections": "2.2.1", + "com.unity.services.deployment": "1.3.0" }, "url": "https://packages.unity.com" }, - "com.unity.services.matchmaker": { - "version": "1.1.4", - "depth": 0, + "com.unity.services.qos": { + "version": "1.3.0", + "depth": 1, "source": "registry", "dependencies": { - "com.unity.services.core": "1.12.5", + "com.unity.services.core": "1.12.4", "com.unity.modules.unitywebrequest": "1.0.0", - "com.unity.modules.unitywebrequestassetbundle": "1.0.0", - "com.unity.modules.unitywebrequestaudio": "1.0.0", - "com.unity.modules.unitywebrequesttexture": "1.0.0", - "com.unity.modules.unitywebrequestwww": "1.0.0", "com.unity.nuget.newtonsoft-json": "3.0.2", - "com.unity.services.authentication": "2.7.4" + "com.unity.services.authentication": "2.0.0", + "com.unity.collections": "1.2.4" }, "url": "https://packages.unity.com" }, @@ -208,6 +241,16 @@ }, "url": "https://packages.unity.com" }, + "com.unity.test-framework.performance": { + "version": "3.0.2", + "depth": 2, + "source": "registry", + "dependencies": { + "com.unity.test-framework": "1.1.31", + "com.unity.modules.jsonserialize": "1.0.0" + }, + "url": "https://packages.unity.com" + }, "com.unity.testtools.codecoverage": { "version": "1.2.5", "depth": 1, @@ -239,6 +282,17 @@ }, "url": "https://packages.unity.com" }, + "com.unity.transport": { + "version": "2.2.1", + "depth": 1, + "source": "registry", + "dependencies": { + "com.unity.collections": "2.2.1", + "com.unity.burst": "1.8.8", + "com.unity.mathematics": "1.3.1" + }, + "url": "https://packages.unity.com" + }, "com.unity.ugui": { "version": "1.0.0", "depth": 0, diff --git a/Chess/ProjectSettings/PackageManagerSettings.asset b/Chess/ProjectSettings/PackageManagerSettings.asset index 112a053..18fde15 100644 --- a/Chess/ProjectSettings/PackageManagerSettings.asset +++ b/Chess/ProjectSettings/PackageManagerSettings.asset @@ -12,12 +12,12 @@ MonoBehaviour: m_Script: {fileID: 13964, guid: 0000000000000000e000000000000000, type: 0} m_Name: m_EditorClassIdentifier: - m_EnablePreReleasePackages: 0 - m_EnablePackageDependencies: 0 + m_EnablePreReleasePackages: 1 m_AdvancedSettingsExpanded: 1 m_ScopedRegistriesSettingsExpanded: 1 m_SeeAllPackageVersions: 0 - oneTimeWarningShown: 0 + m_DismissPreviewPackagesInUse: 0 + oneTimeWarningShown: 1 m_Registries: - m_Id: main m_Name: @@ -25,11 +25,12 @@ MonoBehaviour: m_Scopes: [] m_IsDefault: 1 m_Capabilities: 7 + m_ConfigSource: 0 m_UserSelectedRegistryName: m_UserAddingNewScopedRegistry: 0 m_RegistryInfoDraft: m_Modified: 0 m_ErrorMessage: - m_UserModificationsInstanceId: -830 - m_OriginalInstanceId: -832 + m_UserModificationsInstanceId: -834 + m_OriginalInstanceId: -836 m_LoadAssets: 0 diff --git a/Chess/UserSettings/Layouts/default-2022.dwlt b/Chess/UserSettings/Layouts/default-2022.dwlt index 92fc41b..a991505 100644 --- a/Chess/UserSettings/Layouts/default-2022.dwlt +++ b/Chess/UserSettings/Layouts/default-2022.dwlt @@ -15,15 +15,15 @@ MonoBehaviour: m_PixelRect: serializedVersion: 2 x: 0 - y: 53 - width: 2560 - height: 1301 + y: 389 + width: 1728 + height: 965 m_ShowMode: 4 - m_Title: Scene + m_Title: Hierarchy m_RootView: {fileID: 2} m_MinSize: {x: 875, y: 300} m_MaxSize: {x: 10000, y: 10000} - m_Maximized: 1 + m_Maximized: 0 --- !u!114 &2 MonoBehaviour: m_ObjectHideFlags: 52 @@ -44,8 +44,8 @@ MonoBehaviour: serializedVersion: 2 x: 0 y: 0 - width: 2560 - height: 1301 + width: 1728 + height: 965 m_MinSize: {x: 875, y: 300} m_MaxSize: {x: 10000, y: 10000} m_UseTopView: 1 @@ -69,7 +69,7 @@ MonoBehaviour: serializedVersion: 2 x: 0 y: 0 - width: 2560 + width: 1728 height: 30 m_MinSize: {x: 0, y: 0} m_MaxSize: {x: 0, y: 0} @@ -90,8 +90,8 @@ MonoBehaviour: m_Position: serializedVersion: 2 x: 0 - y: 1281 - width: 2560 + y: 945 + width: 1728 height: 20 m_MinSize: {x: 0, y: 0} m_MaxSize: {x: 0, y: 0} @@ -113,12 +113,13 @@ MonoBehaviour: serializedVersion: 2 x: 0 y: 30 - width: 2560 - height: 1251 + width: 1728 + height: 915 m_MinSize: {x: 300, y: 100} m_MaxSize: {x: 24288, y: 16192} vertical: 0 - controlID: 40 + controlID: 95 + draggingID: 0 --- !u!114 &6 MonoBehaviour: m_ObjectHideFlags: 52 @@ -138,12 +139,13 @@ MonoBehaviour: serializedVersion: 2 x: 0 y: 0 - width: 2560 - height: 1251 + width: 1728 + height: 915 m_MinSize: {x: 300, y: 100} m_MaxSize: {x: 24288, y: 16192} vertical: 1 - controlID: 41 + controlID: 96 + draggingID: 0 --- !u!114 &7 MonoBehaviour: m_ObjectHideFlags: 52 @@ -164,12 +166,13 @@ MonoBehaviour: serializedVersion: 2 x: 0 y: 0 - width: 2560 - height: 878.5 + width: 1728 + height: 582.5 m_MinSize: {x: 300, y: 50} m_MaxSize: {x: 24288, y: 8096} vertical: 0 - controlID: 42 + controlID: 97 + draggingID: 0 --- !u!114 &8 MonoBehaviour: m_ObjectHideFlags: 52 @@ -187,8 +190,8 @@ MonoBehaviour: serializedVersion: 2 x: 0 y: 0 - width: 616.5 - height: 878.5 + width: 333 + height: 582.5 m_MinSize: {x: 201, y: 221} m_MaxSize: {x: 4001, y: 4021} m_ActualView: {fileID: 13} @@ -206,23 +209,23 @@ MonoBehaviour: m_Enabled: 1 m_EditorHideFlags: 1 m_Script: {fileID: 12006, guid: 0000000000000000e000000000000000, type: 0} - m_Name: SceneView + m_Name: GameView m_EditorClassIdentifier: m_Children: [] m_Position: serializedVersion: 2 - x: 616.5 + x: 333 y: 0 - width: 1260.5 - height: 878.5 + width: 934 + height: 582.5 m_MinSize: {x: 202, y: 221} m_MaxSize: {x: 4002, y: 4021} - m_ActualView: {fileID: 12} + m_ActualView: {fileID: 14} m_Panes: - {fileID: 12} - {fileID: 14} - m_Selected: 0 - m_LastSelected: 1 + m_Selected: 1 + m_LastSelected: 0 --- !u!114 &10 MonoBehaviour: m_ObjectHideFlags: 52 @@ -238,10 +241,10 @@ MonoBehaviour: m_Children: [] m_Position: serializedVersion: 2 - x: 1877 + x: 1267 y: 0 - width: 683 - height: 878.5 + width: 461 + height: 582.5 m_MinSize: {x: 276, y: 121} m_MaxSize: {x: 4001, y: 4021} m_ActualView: {fileID: 15} @@ -265,9 +268,9 @@ MonoBehaviour: m_Position: serializedVersion: 2 x: 0 - y: 878.5 - width: 2560 - height: 372.5 + y: 582.5 + width: 1728 + height: 332.5 m_MinSize: {x: 230, y: 271} m_MaxSize: {x: 10000, y: 10021} m_ActualView: {fileID: 16} @@ -607,9 +610,9 @@ MonoBehaviour: m_PlayAudio: 0 m_AudioPlay: 0 m_Position: - m_Target: {x: 3.4999995, y: 0.5846951, z: 3.5000005} + m_Target: {x: 629.25, y: 418.25, z: 0} speed: 2 - m_Value: {x: 3.4999995, y: 0.5846951, z: 3.5000005} + m_Value: {x: 629.25, y: 418.25, z: 0} m_RenderMode: 0 m_CameraMode: drawMode: 0 @@ -655,13 +658,13 @@ MonoBehaviour: m_GridAxis: 1 m_gridOpacity: 0.5 m_Rotation: - m_Target: {x: -0.08717229, y: 0.89959055, z: -0.21045254, w: -0.3726226} + m_Target: {x: -0.019748883, y: -0.07731066, z: 0.0015315096, w: -0.9968112} speed: 2 - m_Value: {x: -0.08717229, y: 0.89959055, z: -0.21045254, w: -0.3726226} + m_Value: {x: -0.019748883, y: -0.07731066, z: 0.0015315096, w: -0.9968112} m_Size: - m_Target: 7.161525 + m_Target: 474.22858 speed: 2 - m_Value: 7.161525 + m_Value: 474.22858 m_Ortho: m_Target: 0 speed: 2 @@ -707,9 +710,9 @@ MonoBehaviour: m_Pos: serializedVersion: 2 x: 0 - y: 83 - width: 615.5 - height: 857.5 + y: 419 + width: 332 + height: 561.5 m_SerializedDataModeController: m_DataMode: 0 m_PreferredDataMode: 0 @@ -769,10 +772,10 @@ MonoBehaviour: m_Tooltip: m_Pos: serializedVersion: 2 - x: 616.5 - y: 83 - width: 1258.5 - height: 857.5 + x: 333 + y: 419 + width: 932 + height: 561.5 m_SerializedDataModeController: m_DataMode: 0 m_PreferredDataMode: 0 @@ -789,7 +792,7 @@ MonoBehaviour: m_ShowGizmos: 0 m_TargetDisplay: 0 m_ClearColor: {r: 0, g: 0, b: 0, a: 0} - m_TargetSize: {x: 1258.5, y: 836.5} + m_TargetSize: {x: 932, y: 540.5} m_TextureFilterMode: 0 m_TextureHideFlags: 61 m_RenderIMGUI: 1 @@ -804,17 +807,17 @@ MonoBehaviour: m_VRangeLocked: 0 hZoomLockedByDefault: 0 vZoomLockedByDefault: 0 - m_HBaseRangeMin: -314.625 - m_HBaseRangeMax: 314.625 - m_VBaseRangeMin: -209.125 - m_VBaseRangeMax: 209.125 + m_HBaseRangeMin: -233 + m_HBaseRangeMax: 233 + m_VBaseRangeMin: -135.125 + m_VBaseRangeMax: 135.125 m_HAllowExceedBaseRangeMin: 1 m_HAllowExceedBaseRangeMax: 1 m_VAllowExceedBaseRangeMin: 1 m_VAllowExceedBaseRangeMax: 1 m_ScaleWithWindow: 0 - m_HSlider: 1 - m_VSlider: 1 + m_HSlider: 0 + m_VSlider: 0 m_IgnoreScrollWheelUntilClicked: 0 m_EnableMouseInput: 1 m_EnableSliderZoomHorizontal: 0 @@ -825,23 +828,23 @@ MonoBehaviour: serializedVersion: 2 x: 0 y: 21 - width: 1258.5 - height: 836.5 - m_Scale: {x: 2.5, y: 2.5} - m_Translation: {x: 629.25, y: 418.25} + width: 932 + height: 540.5 + m_Scale: {x: 2, y: 2} + m_Translation: {x: 466, y: 270.25} m_MarginLeft: 0 m_MarginRight: 0 m_MarginTop: 0 m_MarginBottom: 0 m_LastShownAreaInsideMargins: serializedVersion: 2 - x: -251.7 - y: -167.3 - width: 503.4 - height: 334.6 + x: -233 + y: -135.125 + width: 466 + height: 270.25 m_MinimalGUI: 1 m_defaultScale: 2 - m_LastWindowPixelSize: {x: 2517, y: 1715} + m_LastWindowPixelSize: {x: 1864, y: 1123} m_ClearInEditMode: 1 m_NoCameraWarning: 1 m_LowResolutionForAspectRatios: 01000000000000000000 @@ -867,10 +870,10 @@ MonoBehaviour: m_Tooltip: m_Pos: serializedVersion: 2 - x: 1877 - y: 83 - width: 682 - height: 857.5 + x: 1267 + y: 419 + width: 460 + height: 561.5 m_SerializedDataModeController: m_DataMode: 0 m_PreferredDataMode: 0 @@ -915,9 +918,9 @@ MonoBehaviour: m_Pos: serializedVersion: 2 x: 0 - y: 961.5 - width: 2560 - height: 351.5 + y: 1001.5 + width: 1728 + height: 311.5 m_SerializedDataModeController: m_DataMode: 0 m_PreferredDataMode: 0 @@ -939,7 +942,7 @@ MonoBehaviour: m_SkipHidden: 0 m_SearchArea: 1 m_Folders: - - Assets + - Assets/Scripts m_Globs: [] m_OriginalText: m_ImportLogFlags: 0 @@ -947,16 +950,16 @@ MonoBehaviour: m_ViewMode: 1 m_StartGridSize: 64 m_LastFolders: - - Assets + - Assets/Scripts m_LastFoldersGridSize: -1 m_LastProjectPath: /Users/eduardoojeda/dev/com.unity.services.samples.multiplayer-chess-cloud-code/Chess m_LockTracker: m_IsLocked: 0 m_FolderTreeState: scrollPos: {x: 0, y: 0} - m_SelectedIDs: e86a0000 - m_LastClickedID: 27368 - m_ExpandedIDs: 00000000e86a000000ca9a3b + m_SelectedIDs: ec6c0000 + m_LastClickedID: 27884 + m_ExpandedIDs: 00000000e26c000000ca9a3b m_RenameOverlay: m_UserAcceptedRename: 0 m_Name: @@ -984,7 +987,7 @@ MonoBehaviour: scrollPos: {x: 0, y: 0} m_SelectedIDs: m_LastClickedID: 0 - m_ExpandedIDs: 00000000e86a0000 + m_ExpandedIDs: 00000000e26c0000 m_RenameOverlay: m_UserAcceptedRename: 0 m_Name: @@ -1011,7 +1014,7 @@ MonoBehaviour: m_ListAreaState: m_SelectedInstanceIDs: m_LastClickedInstanceID: 0 - m_HadKeyboardFocusLastEvent: 1 + m_HadKeyboardFocusLastEvent: 0 m_ExpandedInstanceIDs: c62300005e5d000000000000 m_RenameOverlay: m_UserAcceptedRename: 0 @@ -1028,7 +1031,7 @@ MonoBehaviour: m_IsRenaming: 0 m_OriginalEventType: 11 m_IsRenamingFilename: 1 - m_ClientGUIView: {fileID: 11} + m_ClientGUIView: {fileID: 0} m_CreateAssetUtility: m_EndAction: {fileID: 0} m_InstanceID: 0 @@ -1061,9 +1064,9 @@ MonoBehaviour: m_Pos: serializedVersion: 2 x: 0 - y: 537 - width: 1728 - height: 453 + y: 961.5 + width: 2560 + height: 351.5 m_SerializedDataModeController: m_DataMode: 0 m_PreferredDataMode: 0 diff --git a/ChessCloudCode/Chess.cs b/ChessCloudCode/Chess.cs index 383f658..800aeab 100644 --- a/ChessCloudCode/Chess.cs +++ b/ChessCloudCode/Chess.cs @@ -1,4 +1,5 @@ -using Newtonsoft.Json; +using System.Formats.Asn1; +using Newtonsoft.Json; using Unity.Services.CloudCode.Apis; using Unity.Services.CloudCode.Core; using Unity.Services.CloudSave.Model; @@ -6,6 +7,8 @@ using Microsoft.Extensions.Logging; using Unity.Services.Leaderboards.Model; using Unity.Services.Lobby.Model; +using Unity.Services.Matchmaker.Model; +using Player = Unity.Services.Lobby.Model.Player; namespace ChessCloudCode; @@ -14,6 +17,11 @@ public class Chess private const string LeaderboardId = "EloRatings"; private const int KValue = 30; private const int StartingElo = 1500; + private enum MatchState + { + InProgress, + Ended + } private readonly IGameApiClient _gameApiClient; private readonly IPushClient _pushClient; @@ -28,6 +36,54 @@ public Chess(IGameApiClient gameApiClient, IPushClient pushClient, ILogger(){ + new("board", chessBoard.ToFen()), + new("whitePlayerId", players[0].Id), + new("blackPlayerId", players[1].Id), + new("turnCounter", 1), + new("matchState", MatchState.InProgress.ToString()) + })); + + Parallel.ForEach(players, async player => + { + await _gameApiClient.CloudSaveData.SetItemAsync(context, context.ServiceToken, context.ProjectId, + player.Id, + new SetItemBody("currentMatchId", matchId)); + }); + } + + // TODO replace this by a proper call to the generated Matchmaker SDK once an OpenAPI spec is available that supports MatchmakingResults + private async Task GetMatchmakingResults(IExecutionContext context, string matchId) + { + var client = new HttpClient(); + var url = + $"https://matchmaker.services.api.unity.com/v2alpha1/projects/{context.ProjectId}/matches/{matchId}/matchmaking-results"; + + var response = await client.GetAsync(url); + response.EnsureSuccessStatusCode(); + var content = await response.Content.ReadAsStringAsync(); + + return JsonConvert.DeserializeObject(content); + } + [CloudCodeFunction("HostGame")] public async Task HostGame(IExecutionContext context) { @@ -46,7 +102,7 @@ await _gameApiClient.CloudSaveData.SetCustomItemBatchAsync(context, context.Serv LobbyCode = lobbyResult.Data.LobbyCode, }; } - + [CloudCodeFunction("JoinGame")] public async Task JoinGame(IExecutionContext context, string lobbyCode) { diff --git a/README.md b/README.md index 8b0efd2..298c86a 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,8 @@ The game utilizes a wide range of UGS products and services to implement the fol ## Setup +**_TODO: do we need to explain how to create a Service Account and which permissions to give it?_** + To run the chess sample, import the Chess folder as a Unity project, open and run the `ChessDemo.unity` scene. For this sample to work, you first need to publish your Cloud Code Module and Leaderboard via the Deployment Window. diff --git a/TODO b/TODO new file mode 100644 index 0000000..5a5a6b5 --- /dev/null +++ b/TODO @@ -0,0 +1,14 @@ +- Users need to create an SA as well, we should document that + - The SA need a bunch of specific permissions + + +- We need to use the MatchId config type for MM, but creating it is not suppoerted on uDash + - uDash does seem to support display for the queuetype, but it says "Relay" which is not necessarily true + + +- We can create that MM queue type via UGS CLI, though it's not documented + - It wants to list fleets anyway even if we don't use them, SA requires that permission + + +- The session concept could be implemented in a Session microservice instead of in an SDK, making it available to all (non-MWU, Cloud Code, etc) and allowing us to change behavior without shipping a new SDK + - The client facing interface on the SDK can stay the same \ No newline at end of file From c0c02fed43f62d1a443e7e6f37f70db6bd926983 Mon Sep 17 00:00:00 2001 From: Todd Harding Date: Wed, 17 Jul 2024 17:13:37 +0100 Subject: [PATCH 05/10] Added more joining and update logic to client and cloud code scripts --- Chess/Assets/CloudCode.meta | 8 + .../CloudCode/GeneratedModuleBindings.meta | 8 + .../ChessCloudCode.meta | 8 + .../ChessCloudCode.BoardUpdateResponse.cs | 17 ++ ...ChessCloudCode.BoardUpdateResponse.cs.meta | 11 ++ .../ChessCloudCode.HostGameResponse.cs | 15 ++ .../ChessCloudCode.HostGameResponse.cs.meta | 11 ++ .../ChessCloudCode.InitializeMatchResponse.cs | 15 ++ ...sCloudCode.InitializeMatchResponse.cs.meta | 11 ++ .../ChessCloudCode.JoinGameResponse.cs | 18 ++ .../ChessCloudCode.JoinGameResponse.cs.meta | 11 ++ .../ChessCloudCode/ChessCloudCodeBindings.cs | 71 ++++++++ .../ChessCloudCodeBindings.cs.meta | 11 ++ ...ervices.CloudCode.GeneratedBindings.asmdef | 8 + ...es.CloudCode.GeneratedBindings.asmdef.meta | 7 + Chess/Assets/Scenes/ChessDemo.unity | 49 +++++- Chess/Assets/Scripts/Match.cs | 44 +++++ Chess/Assets/Scripts/Match.cs.meta | 3 + Chess/Assets/Scripts/MatchLoader.cs | 60 +++++++ Chess/Assets/Scripts/MatchLoader.cs.meta | 3 + Chess/Assets/Scripts/Player.cs | 158 ++++++++++++++---- Chess/Packages/manifest.json | 3 +- Chess/Packages/packages-lock.json | 18 +- ChessCloudCode/Chess.cs | 157 ++++++++++------- ChessCloudCode/ChessCloudCode.csproj | 2 +- 25 files changed, 624 insertions(+), 103 deletions(-) create mode 100644 Chess/Assets/CloudCode.meta create mode 100644 Chess/Assets/CloudCode/GeneratedModuleBindings.meta create mode 100644 Chess/Assets/CloudCode/GeneratedModuleBindings/ChessCloudCode.meta create mode 100644 Chess/Assets/CloudCode/GeneratedModuleBindings/ChessCloudCode/ChessCloudCode.BoardUpdateResponse.cs create mode 100644 Chess/Assets/CloudCode/GeneratedModuleBindings/ChessCloudCode/ChessCloudCode.BoardUpdateResponse.cs.meta create mode 100644 Chess/Assets/CloudCode/GeneratedModuleBindings/ChessCloudCode/ChessCloudCode.HostGameResponse.cs create mode 100644 Chess/Assets/CloudCode/GeneratedModuleBindings/ChessCloudCode/ChessCloudCode.HostGameResponse.cs.meta create mode 100644 Chess/Assets/CloudCode/GeneratedModuleBindings/ChessCloudCode/ChessCloudCode.InitializeMatchResponse.cs create mode 100644 Chess/Assets/CloudCode/GeneratedModuleBindings/ChessCloudCode/ChessCloudCode.InitializeMatchResponse.cs.meta create mode 100644 Chess/Assets/CloudCode/GeneratedModuleBindings/ChessCloudCode/ChessCloudCode.JoinGameResponse.cs create mode 100644 Chess/Assets/CloudCode/GeneratedModuleBindings/ChessCloudCode/ChessCloudCode.JoinGameResponse.cs.meta create mode 100644 Chess/Assets/CloudCode/GeneratedModuleBindings/ChessCloudCode/ChessCloudCodeBindings.cs create mode 100644 Chess/Assets/CloudCode/GeneratedModuleBindings/ChessCloudCode/ChessCloudCodeBindings.cs.meta create mode 100644 Chess/Assets/CloudCode/GeneratedModuleBindings/Unity.Services.CloudCode.GeneratedBindings.asmdef create mode 100644 Chess/Assets/CloudCode/GeneratedModuleBindings/Unity.Services.CloudCode.GeneratedBindings.asmdef.meta create mode 100644 Chess/Assets/Scripts/Match.cs create mode 100644 Chess/Assets/Scripts/Match.cs.meta create mode 100644 Chess/Assets/Scripts/MatchLoader.cs create mode 100644 Chess/Assets/Scripts/MatchLoader.cs.meta diff --git a/Chess/Assets/CloudCode.meta b/Chess/Assets/CloudCode.meta new file mode 100644 index 0000000..ff759ff --- /dev/null +++ b/Chess/Assets/CloudCode.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f5e90cdc32ff448ae9a8b43b1b48d3c7 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Chess/Assets/CloudCode/GeneratedModuleBindings.meta b/Chess/Assets/CloudCode/GeneratedModuleBindings.meta new file mode 100644 index 0000000..e13bc29 --- /dev/null +++ b/Chess/Assets/CloudCode/GeneratedModuleBindings.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3ef92cf66747449309636e576705cf27 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Chess/Assets/CloudCode/GeneratedModuleBindings/ChessCloudCode.meta b/Chess/Assets/CloudCode/GeneratedModuleBindings/ChessCloudCode.meta new file mode 100644 index 0000000..5809ef9 --- /dev/null +++ b/Chess/Assets/CloudCode/GeneratedModuleBindings/ChessCloudCode.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f736288850806402ab00ebe4c71fce22 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Chess/Assets/CloudCode/GeneratedModuleBindings/ChessCloudCode/ChessCloudCode.BoardUpdateResponse.cs b/Chess/Assets/CloudCode/GeneratedModuleBindings/ChessCloudCode/ChessCloudCode.BoardUpdateResponse.cs new file mode 100644 index 0000000..4c503ed --- /dev/null +++ b/Chess/Assets/CloudCode/GeneratedModuleBindings/ChessCloudCode/ChessCloudCode.BoardUpdateResponse.cs @@ -0,0 +1,17 @@ +// This file was generated by Cloud Code Bindings Generator. Modifications will be lost upon regeneration. +using UnityEngine.Scripting; + +namespace Unity.Services.CloudCode.GeneratedBindings.ChessCloudCode +{ + public partial class BoardUpdateResponse + { + public string Board; + public bool GameOver; + public string EndgameType; + + [Preserve] + public BoardUpdateResponse () + { + } + } +} \ No newline at end of file diff --git a/Chess/Assets/CloudCode/GeneratedModuleBindings/ChessCloudCode/ChessCloudCode.BoardUpdateResponse.cs.meta b/Chess/Assets/CloudCode/GeneratedModuleBindings/ChessCloudCode/ChessCloudCode.BoardUpdateResponse.cs.meta new file mode 100644 index 0000000..da152e8 --- /dev/null +++ b/Chess/Assets/CloudCode/GeneratedModuleBindings/ChessCloudCode/ChessCloudCode.BoardUpdateResponse.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a48f1f362fea6423c8ea04e8b7ac6583 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Chess/Assets/CloudCode/GeneratedModuleBindings/ChessCloudCode/ChessCloudCode.HostGameResponse.cs b/Chess/Assets/CloudCode/GeneratedModuleBindings/ChessCloudCode/ChessCloudCode.HostGameResponse.cs new file mode 100644 index 0000000..46dd0eb --- /dev/null +++ b/Chess/Assets/CloudCode/GeneratedModuleBindings/ChessCloudCode/ChessCloudCode.HostGameResponse.cs @@ -0,0 +1,15 @@ +// This file was generated by Cloud Code Bindings Generator. Modifications will be lost upon regeneration. +using UnityEngine.Scripting; + +namespace Unity.Services.CloudCode.GeneratedBindings.ChessCloudCode +{ + public partial class HostGameResponse + { + public string LobbyCode; + + [Preserve] + public HostGameResponse () + { + } + } +} \ No newline at end of file diff --git a/Chess/Assets/CloudCode/GeneratedModuleBindings/ChessCloudCode/ChessCloudCode.HostGameResponse.cs.meta b/Chess/Assets/CloudCode/GeneratedModuleBindings/ChessCloudCode/ChessCloudCode.HostGameResponse.cs.meta new file mode 100644 index 0000000..c004f6b --- /dev/null +++ b/Chess/Assets/CloudCode/GeneratedModuleBindings/ChessCloudCode/ChessCloudCode.HostGameResponse.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8c39f0250eb8045b1b04cbce5a4bd360 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Chess/Assets/CloudCode/GeneratedModuleBindings/ChessCloudCode/ChessCloudCode.InitializeMatchResponse.cs b/Chess/Assets/CloudCode/GeneratedModuleBindings/ChessCloudCode/ChessCloudCode.InitializeMatchResponse.cs new file mode 100644 index 0000000..702db72 --- /dev/null +++ b/Chess/Assets/CloudCode/GeneratedModuleBindings/ChessCloudCode/ChessCloudCode.InitializeMatchResponse.cs @@ -0,0 +1,15 @@ +// This file was generated by Cloud Code Bindings Generator. Modifications will be lost upon regeneration. +using UnityEngine.Scripting; + +namespace Unity.Services.CloudCode.GeneratedBindings.ChessCloudCode +{ + public partial class InitializeMatchResponse + { + public string Status; + + [Preserve] + public InitializeMatchResponse () + { + } + } +} \ No newline at end of file diff --git a/Chess/Assets/CloudCode/GeneratedModuleBindings/ChessCloudCode/ChessCloudCode.InitializeMatchResponse.cs.meta b/Chess/Assets/CloudCode/GeneratedModuleBindings/ChessCloudCode/ChessCloudCode.InitializeMatchResponse.cs.meta new file mode 100644 index 0000000..9b41b82 --- /dev/null +++ b/Chess/Assets/CloudCode/GeneratedModuleBindings/ChessCloudCode/ChessCloudCode.InitializeMatchResponse.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: cab8ea60655094b72ab6085003003dc6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Chess/Assets/CloudCode/GeneratedModuleBindings/ChessCloudCode/ChessCloudCode.JoinGameResponse.cs b/Chess/Assets/CloudCode/GeneratedModuleBindings/ChessCloudCode/ChessCloudCode.JoinGameResponse.cs new file mode 100644 index 0000000..cf0fd72 --- /dev/null +++ b/Chess/Assets/CloudCode/GeneratedModuleBindings/ChessCloudCode/ChessCloudCode.JoinGameResponse.cs @@ -0,0 +1,18 @@ +// This file was generated by Cloud Code Bindings Generator. Modifications will be lost upon regeneration. +using UnityEngine.Scripting; + +namespace Unity.Services.CloudCode.GeneratedBindings.ChessCloudCode +{ + public partial class JoinGameResponse + { + public string Session; + public string Board; + public string OpponentId; + public bool IsWhite; + + [Preserve] + public JoinGameResponse () + { + } + } +} \ No newline at end of file diff --git a/Chess/Assets/CloudCode/GeneratedModuleBindings/ChessCloudCode/ChessCloudCode.JoinGameResponse.cs.meta b/Chess/Assets/CloudCode/GeneratedModuleBindings/ChessCloudCode/ChessCloudCode.JoinGameResponse.cs.meta new file mode 100644 index 0000000..c2d0b19 --- /dev/null +++ b/Chess/Assets/CloudCode/GeneratedModuleBindings/ChessCloudCode/ChessCloudCode.JoinGameResponse.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d9370fb3f1abd45858d626bd89da7e4d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Chess/Assets/CloudCode/GeneratedModuleBindings/ChessCloudCode/ChessCloudCodeBindings.cs b/Chess/Assets/CloudCode/GeneratedModuleBindings/ChessCloudCode/ChessCloudCodeBindings.cs new file mode 100644 index 0000000..c692ea9 --- /dev/null +++ b/Chess/Assets/CloudCode/GeneratedModuleBindings/ChessCloudCode/ChessCloudCodeBindings.cs @@ -0,0 +1,71 @@ +// This file was generated by Cloud Code Bindings Generator. Modifications will be lost upon regeneration. +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Unity.Services.CloudCode.GeneratedBindings +{ + public class ChessCloudCodeBindings + { + readonly ICloudCodeService k_Service; + public ChessCloudCodeBindings(ICloudCodeService service) + { + k_Service = service; + } + + public async Task InitializeMatch(string sessionId) + { + return await k_Service.CallModuleEndpointAsync( + "ChessCloudCode", + "InitializeMatch", + new Dictionary() + { + {"sessionId", sessionId}, + }); + } + + public async Task HostGame() + { + return await k_Service.CallModuleEndpointAsync( + "ChessCloudCode", + "HostGame", + new Dictionary() + { + }); + } + + public async Task JoinGame(string lobbyCode) + { + return await k_Service.CallModuleEndpointAsync( + "ChessCloudCode", + "JoinGame", + new Dictionary() + { + {"lobbyCode", lobbyCode}, + }); + } + + public async Task MakeMove(string session, string fromPosition, string toPosition) + { + return await k_Service.CallModuleEndpointAsync( + "ChessCloudCode", + "MakeMove", + new Dictionary() + { + {"session", session}, + {"fromPosition", fromPosition}, + {"toPosition", toPosition}, + }); + } + + public async Task Resign(string session) + { + return await k_Service.CallModuleEndpointAsync( + "ChessCloudCode", + "Resign", + new Dictionary() + { + {"session", session}, + }); + } + } +} diff --git a/Chess/Assets/CloudCode/GeneratedModuleBindings/ChessCloudCode/ChessCloudCodeBindings.cs.meta b/Chess/Assets/CloudCode/GeneratedModuleBindings/ChessCloudCode/ChessCloudCodeBindings.cs.meta new file mode 100644 index 0000000..1ae1741 --- /dev/null +++ b/Chess/Assets/CloudCode/GeneratedModuleBindings/ChessCloudCode/ChessCloudCodeBindings.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 972629e1fd7254cc7af1433ce0d60ea4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Chess/Assets/CloudCode/GeneratedModuleBindings/Unity.Services.CloudCode.GeneratedBindings.asmdef b/Chess/Assets/CloudCode/GeneratedModuleBindings/Unity.Services.CloudCode.GeneratedBindings.asmdef new file mode 100644 index 0000000..24c33d2 --- /dev/null +++ b/Chess/Assets/CloudCode/GeneratedModuleBindings/Unity.Services.CloudCode.GeneratedBindings.asmdef @@ -0,0 +1,8 @@ +{ + "name": "Unity.Services.CloudCode.GeneratedBindings", + "rootNamespace": "Unity.Services.CloudCode.GeneratedBindings", + "autoReferenced": true, + "references": [ + "Unity.Services.CloudCode" + ] +} diff --git a/Chess/Assets/CloudCode/GeneratedModuleBindings/Unity.Services.CloudCode.GeneratedBindings.asmdef.meta b/Chess/Assets/CloudCode/GeneratedModuleBindings/Unity.Services.CloudCode.GeneratedBindings.asmdef.meta new file mode 100644 index 0000000..fbc44ad --- /dev/null +++ b/Chess/Assets/CloudCode/GeneratedModuleBindings/Unity.Services.CloudCode.GeneratedBindings.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 93d45b41dbb4e439696042a09f9b368a +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Chess/Assets/Scenes/ChessDemo.unity b/Chess/Assets/Scenes/ChessDemo.unity index c1b5ab6..defdc82 100644 --- a/Chess/Assets/Scenes/ChessDemo.unity +++ b/Chess/Assets/Scenes/ChessDemo.unity @@ -711,7 +711,7 @@ MonoBehaviour: m_Calls: - m_Target: {fileID: 1881174974} m_TargetAssemblyTypeName: Player, Assembly-CSharp - m_MethodName: CreateGame + m_MethodName: FindMatch m_Mode: 1 m_Arguments: m_ObjectArgument: {fileID: 0} @@ -1747,6 +1747,50 @@ MeshFilter: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 449874633} m_Mesh: {fileID: 4300000, guid: 0d4dc18442ed9d14698239a5a964f27f, type: 3} +--- !u!1 &519999539 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 519999541} + - component: {fileID: 519999540} + m_Layer: 0 + m_Name: MatchManager + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &519999540 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 519999539} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 91ab04a1e4af4bffb3908fe5fe47d74e, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!4 &519999541 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 519999539} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 3.4999995, y: 0.5846951, z: 3.5000005} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &631113151 stripped GameObject: m_CorrespondingSourceObject: {fileID: 1857998089916902, guid: 5b856ec4f8f8cb84f861f8f8a026c288, type: 3} @@ -5641,7 +5685,7 @@ MonoBehaviour: m_GameObject: {fileID: 1881174973} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: abdabbe5de74490b82c022f059e7063c, type: 3} + m_Script: {fileID: 11500000, guid: 91ab04a1e4af4bffb3908fe5fe47d74e, type: 3} m_Name: m_EditorClassIdentifier: --- !u!1 &1941642356 @@ -6892,3 +6936,4 @@ SceneRoots: - {fileID: 1881174975} - {fileID: 908034760} - {fileID: 1835524142} + - {fileID: 519999541} diff --git a/Chess/Assets/Scripts/Match.cs b/Chess/Assets/Scripts/Match.cs new file mode 100644 index 0000000..a00bfa8 --- /dev/null +++ b/Chess/Assets/Scripts/Match.cs @@ -0,0 +1,44 @@ +using System; + +public class Match +{ + public string Board { get; set; } + public string WhitePlayerId { get; set; } + public string BlackPlayerId { get; set; } + public int TurnCounter { get; set; } + public string MatchState { get; set; } + public long MatchCreatedAt { get; set; } + + public Match(string board, string whitePlayerId, string blackPlayerId, int turnCounter, string matchState, + long matchCreatedAt) + { + Board = board; + WhitePlayerId = whitePlayerId; + BlackPlayerId = blackPlayerId; + TurnCounter = turnCounter; + MatchState = matchState; + MatchCreatedAt = matchCreatedAt; + } + + public override string ToString() + { + return + $"Board: {Board}, WhitePlayerId: {WhitePlayerId}, BlackPlayerId: {BlackPlayerId}, TurnCounter: {TurnCounter}, MatchState: {MatchState}, MatchCreatedAt: {MatchCreatedAt}"; + } + + public override bool Equals(object obj) + { + if (obj == null || GetType() != obj.GetType()) + { + return false; + } + + Match m = (Match)obj; + return (Board == m.Board) && (WhitePlayerId == m.WhitePlayerId) && (BlackPlayerId == m.BlackPlayerId) && (TurnCounter == m.TurnCounter) && (MatchState == m.MatchState) && (MatchCreatedAt == m.MatchCreatedAt); + } + + public override int GetHashCode() + { + return Tuple.Create(Board, WhitePlayerId, BlackPlayerId, TurnCounter, MatchState, MatchCreatedAt).GetHashCode(); + } +} \ No newline at end of file diff --git a/Chess/Assets/Scripts/Match.cs.meta b/Chess/Assets/Scripts/Match.cs.meta new file mode 100644 index 0000000..0507b0e --- /dev/null +++ b/Chess/Assets/Scripts/Match.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 586c6b397c4248fa92346bb02177d9ad +timeCreated: 1721225881 \ No newline at end of file diff --git a/Chess/Assets/Scripts/MatchLoader.cs b/Chess/Assets/Scripts/MatchLoader.cs new file mode 100644 index 0000000..c51c525 --- /dev/null +++ b/Chess/Assets/Scripts/MatchLoader.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Unity.Services.CloudSave; +using Unity.Services.CloudSave.Models; + +public static class MatchLoader +{ + public static async Task LoadMatchDataAsync(string matchId) + { + var keys = new HashSet + { + "board", + "whitePlayerId", + "blackPlayerId", + "turnCounter", + "matchState", + "matchCreatedAt" + }; + + try + { + var data = await CloudSaveService.Instance.Data.Custom.LoadAsync(matchId, keys); + var match = MapToMatch(data); + return match; + } + catch (CloudSaveValidationException ex) + { + Console.WriteLine($"CloudSaveValidationException: {ex.Message}"); + throw; + } + catch (CloudSaveRateLimitedException ex) + { + Console.WriteLine($"CloudSaveRateLimitedException: {ex.Message}"); + throw; + } + catch (CloudSaveException ex) + { + Console.WriteLine($"CloudSaveException: {ex.Reason}, {ex.Message}"); + throw; + } + catch (Exception ex) + { + Console.WriteLine($"Unexpected error: {ex.Message}"); + throw; + } + } + + private static Match MapToMatch(Dictionary data) + { + return new Match( + data["board"].Value.ToString(), + data["whitePlayerId"].Value.ToString(), + data["blackPlayerId"].Value.ToString(), + Convert.ToInt32(data["turnCounter"].Value), + data["matchState"].Value.ToString(), + Convert.ToInt64(data["matchCreatedAt"].Value) + ); + } +} \ No newline at end of file diff --git a/Chess/Assets/Scripts/MatchLoader.cs.meta b/Chess/Assets/Scripts/MatchLoader.cs.meta new file mode 100644 index 0000000..279ccce --- /dev/null +++ b/Chess/Assets/Scripts/MatchLoader.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: b081b8791677499598153017bbf676c8 +timeCreated: 1721227265 \ No newline at end of file diff --git a/Chess/Assets/Scripts/Player.cs b/Chess/Assets/Scripts/Player.cs index 03375bc..5cd74b6 100644 --- a/Chess/Assets/Scripts/Player.cs +++ b/Chess/Assets/Scripts/Player.cs @@ -2,16 +2,20 @@ using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; +using System.Threading; using System.Threading.Tasks; using Newtonsoft.Json; using TMPro; using Unity.Services.Authentication; using Unity.Services.CloudCode; +using Unity.Services.CloudCode.GeneratedBindings; using Unity.Services.CloudCode.Subscriptions; +using Unity.Services.CloudSave; using Unity.Services.Core; using Unity.Services.Leaderboards; using Unity.Services.Leaderboards.Exceptions; using Unity.Services.Lobbies; +using Unity.Services.Multiplayer; using Unity.VisualScripting; using UnityEngine; using UnityEngine.InputSystem; @@ -23,7 +27,7 @@ public class Player : MonoBehaviour public GameObject cameraPivot; public TextMeshProUGUI joinCodeInput; public TextMeshProUGUI joinCodeDisplayText; - + public TextMeshProUGUI playerNameText; public TextMeshProUGUI playerEloText; public TextMeshProUGUI opponentNameText; @@ -33,27 +37,32 @@ public class Player : MonoBehaviour public GameObject uiPanel; public TextMeshProUGUI resultText; public GameObject board; - + + public ISession Session; + private ChessCloudCodeBindings _chessCloudCodeBindings; + public Match Match; + private readonly Dictionary _prefabs = new(); private const string StartingBoard = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"; private bool _gameStarted; private bool _isWhite; private string _currentSession; - private readonly Color32 _selectedColor = new (84, 84, 255, 255); + private readonly Color32 _selectedColor = new(84, 84, 255, 255); private readonly Color32 _lightColor = new(223, 210, 194, 255); - private readonly Color32 _darkColor = new (84, 84, 84, 255); - + private readonly Color32 _darkColor = new(84, 84, 84, 255); + private async void Start() { await UnityServices.InitializeAsync(); await AuthenticationService.Instance.SignInAnonymouslyAsync(); - await SubscribeToPlayerMessages(); + // await SubscribeToPlayerMessages(); SyncBoard(StartingBoard); InitializePlayer(); + _chessCloudCodeBindings = new ChessCloudCodeBindings(CloudCodeService.Instance); resignButton.SetActive(false); } - + private async Task InitializePlayer() { try @@ -79,7 +88,7 @@ private async Task InitializePlayer() private async Task RefreshPlayerInfo() { var response = await LeaderboardsService.Instance.GetPlayerScoreAsync("EloRatings"); - + playerEloText.text = "Rating: " + Math.Round(response?.Score ?? 1500); playerNameText.text = response.PlayerName; } @@ -87,7 +96,9 @@ private async Task RefreshPlayerInfo() private async Task SetOpponentInfo(string opponentId) { Debug.Log($"Setting opponent info"); - var response = await LeaderboardsService.Instance.GetScoresByPlayerIdsAsync("EloRatings", new List(){opponentId}); + var response = + await LeaderboardsService.Instance.GetScoresByPlayerIdsAsync("EloRatings", + new List() { opponentId }); var opponent = response?.Results?.FirstOrDefault(); Debug.Log($"Setting opponent info {opponent?.PlayerId}"); opponentEloText.text = "Rating: " + Math.Round(opponent?.Score ?? 1500); @@ -96,8 +107,9 @@ private async Task SetOpponentInfo(string opponentId) public async void CreateGame() { - var hostGameResponse = await CloudCodeService.Instance.CallModuleEndpointAsync("ChessCloudCode", "HostGame"); - + var hostGameResponse = + await CloudCodeService.Instance.CallModuleEndpointAsync("ChessCloudCode", "HostGame"); + joinCodeDisplayText.text = hostGameResponse.LobbyCode; } @@ -111,7 +123,8 @@ public async void Resign() { try { - var boardUpdate = await CloudCodeService.Instance.CallModuleEndpointAsync("ChessCloudCode", "Resign", + var boardUpdate = await CloudCodeService.Instance.CallModuleEndpointAsync( + "ChessCloudCode", "Resign", new Dictionary { { "session", _currentSession } }); OnBoardUpdate(boardUpdate); } @@ -120,18 +133,19 @@ public async void Resign() Debug.LogException(exception); } } - + public async void JoinLobbyByCode() { try { // There's a weird no space character that gets added to the end of the lobby code, let's remove it for now var sanitizedLobbyCode = Regex.Replace(joinCodeInput.text, @"\s", "").Replace("\u200B", ""); - - var joinGameResponse = await CloudCodeService.Instance.CallModuleEndpointAsync("ChessCloudCode", "JoinGame", + + var joinGameResponse = await CloudCodeService.Instance.CallModuleEndpointAsync( + "ChessCloudCode", "JoinGame", new Dictionary { { "lobbyCode", sanitizedLobbyCode } }); joinCodeDisplayText.text = sanitizedLobbyCode; - + OnGameStart(joinGameResponse); } catch (LobbyServiceException exception) @@ -149,6 +163,7 @@ private void SyncBoard(string fen) { Destroy(child.gameObject); } + foreach (var piece in boardState) { var pieceType = char.ToLower(piece.Value) switch @@ -164,12 +179,12 @@ private void SyncBoard(string fen) var prefabName = pieceType + (char.IsUpper(piece.Value) ? "Light" : "Dark"); if (!_prefabs.ContainsKey(prefabName)) { - _prefabs[prefabName] = Resources.Load($"{pieceType}/Prefabs/{prefabName}"); + _prefabs[prefabName] = Resources.Load($"{pieceType}/Prefabs/{prefabName}"); } - + var newObject = Instantiate(_prefabs[prefabName], board.transform); newObject.GameObject().transform.position = new Vector3(piece.Key.Item1, 0, piece.Key.Item2); - newObject.GameObject().transform.rotation = Quaternion.Euler(0, char.IsLower(piece.Value)? 180 : 0, 0); + newObject.GameObject().transform.rotation = Quaternion.Euler(0, char.IsLower(piece.Value) ? 180 : 0, 0); } } catch (CloudCodeException exception) @@ -182,11 +197,11 @@ private async void MakeMove(GameObject piece, Vector3 toPos) { if (piece == null) return; var result = await CloudCodeService.Instance.CallModuleEndpointAsync( - "ChessCloudCode", + "ChessCloudCode", "MakeMove", new Dictionary { - { "session", _currentSession }, + { "session", _currentSession }, { "fromPosition", PosToFen(piece.transform.position) }, { "toPosition", PosToFen(toPos) } }); @@ -236,7 +251,8 @@ private Task SubscribeToPlayerMessages() OnGameStart(opponentJoinedMessage); break; default: - Debug.Log($"Got unsupported player Message: {JsonConvert.SerializeObject(@event, Formatting.Indented)}"); + Debug.Log( + $"Got unsupported player Message: {JsonConvert.SerializeObject(@event, Formatting.Indented)}"); break; } }; @@ -245,12 +261,10 @@ private Task SubscribeToPlayerMessages() if (@event == EventConnectionState.Subscribed && _currentSession != null && _gameStarted) { } + Debug.Log($"Got player subscription ConnectionStateChanged: {@event.ToString()}"); }; - callbacks.Kicked += () => - { - Debug.Log($"Got player subscription Kicked"); - }; + callbacks.Kicked += () => { Debug.Log($"Got player subscription Kicked"); }; callbacks.Error += @event => { Debug.Log($"Got player subscription Error: {JsonConvert.SerializeObject(@event, Formatting.Indented)}"); @@ -275,12 +289,12 @@ public void PlayerInteract(InputAction.CallbackContext context) else if (gameObject.name.Contains("Light") == _isWhite) { SelectPiece(hitInfo.transform.gameObject); - Debug.Log($"Piece selected: {_selectedPiece.name}"); + Debug.Log($"Piece selected: {_selectedPiece.name}"); } } else { - SelectPiece(null); + SelectPiece(null); } } @@ -291,6 +305,7 @@ private void SelectPiece(GameObject piece) ChangeMaterialColor(_selectedPiece, _selectedPiece.name.Contains("Light") ? _lightColor : _darkColor); } + _selectedPiece = piece; if (_selectedPiece == null) return; ChangeMaterialColor(_selectedPiece, _selectedColor); @@ -321,6 +336,7 @@ private static Dictionary, char> FenToDict(string fen) x += 1; } } + x = 0; y -= 1; } @@ -328,17 +344,93 @@ private static Dictionary, char> FenToDict(string fen) return coordinatesDict; } + public async void FindMatch() + { + var matchmakerOptions = new MatchmakerOptions + { + QueueName = "default-queue" + }; + + var sessionOptions = new SessionOptions() + { + MaxPlayers = 2, + IsPrivate = true + }; + + var matchmakerCancellationSource = new CancellationTokenSource(); + + Session = await MultiplayerService.Instance.MatchmakeSessionAsync(matchmakerOptions, sessionOptions, + matchmakerCancellationSource.Token); + Session.Changed += OnSessionChanged; + } + + private async void OnSessionChanged() + { + if (Session.PlayerCount == Session.MaxPlayers && !_gameStarted) + { + if (this.Match == null) + { + var match = await _chessCloudCodeBindings.InitializeMatch(Session.Id); + if (match.Status == "OK") + { + SyncMatch(); + } + } + } + else if (_gameStarted) + { + SyncMatch(); + } + } + + public async Task SyncMatch() + { + // Get Match Id from cloud save + var playerData = + await CloudSaveService.Instance.Data.Player.LoadAsync(new HashSet { "currentMatchId" }); + + if (!playerData.ContainsKey("currentMatchId")) + { + Debug.Log("no `currentMatchId` stored on Player in Cloud Save"); + // TODO throw exception? + } + + // Get match from cloud save + var matchId = playerData["currentMatchId"]; + var matchData = await MatchLoader.LoadMatchDataAsync(matchId.Value.GetAs()); + + // Update local match state + UpdateMatchState(matchData); + } + + private async Task UpdateMatchState(Match matchData) + { + var thisPlayerId = AuthenticationService.Instance.PlayerId; + if (this.Match == null) + { + await InitializePlayer(); + var opponentId = thisPlayerId == matchData.WhitePlayerId + ? matchData.BlackPlayerId + : matchData.WhitePlayerId; + await SetOpponentInfo(opponentId); + } + + this.Match = matchData; + this._isWhite = this.Match.WhitePlayerId == thisPlayerId; + SyncBoard(this.Match.Board); + } + private void ChangeMaterialColor(GameObject obj, Color newColor) { var selectedRenderer = obj.GetComponent(); selectedRenderer.material.color = newColor; } - + public class HostGameResponse { public string LobbyCode { get; set; } - } - + } + public class BoardUpdateResponse { public string Board { get; set; } @@ -347,7 +439,7 @@ public class BoardUpdateResponse } public class JoinGameResponse - { + { public string Session { get; set; } public string Board { get; set; } public string OpponentId { get; set; } @@ -358,4 +450,4 @@ private string PosToFen(Vector3 pos) { return (char)(pos.x + 97) + ((char)pos.z + 1).ToString(); } -} +} \ No newline at end of file diff --git a/Chess/Packages/manifest.json b/Chess/Packages/manifest.json index 4bc3667..d6a9499 100644 --- a/Chess/Packages/manifest.json +++ b/Chess/Packages/manifest.json @@ -4,7 +4,8 @@ "com.unity.feature.development": "1.0.1", "com.unity.ide.rider": "3.0.31", "com.unity.inputsystem": "1.7.0", - "com.unity.services.cloudcode": "2.5.1", + "com.unity.services.cloudcode": "2.7.1", + "com.unity.services.cloudsave": "3.2.0", "com.unity.services.deployment": "1.3.0", "com.unity.services.leaderboards": "2.0.0", "com.unity.services.multiplayer": "0.5.1", diff --git a/Chess/Packages/packages-lock.json b/Chess/Packages/packages-lock.json index 2dd31c4..b05b411 100644 --- a/Chess/Packages/packages-lock.json +++ b/Chess/Packages/packages-lock.json @@ -132,15 +132,25 @@ "url": "https://packages.unity.com" }, "com.unity.services.cloudcode": { - "version": "2.5.1", + "version": "2.7.1", "depth": 0, "source": "registry", "dependencies": { - "com.unity.services.authentication": "3.1.0", - "com.unity.services.core": "1.12.0", + "com.unity.services.authentication": "3.3.3", + "com.unity.services.core": "1.13.0", "com.unity.modules.unitywebrequest": "1.0.0", "com.unity.nuget.newtonsoft-json": "3.0.2", - "com.unity.services.wire": "1.1.5" + "com.unity.services.wire": "1.2.3" + }, + "url": "https://packages.unity.com" + }, + "com.unity.services.cloudsave": { + "version": "3.2.0", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.services.authentication": "3.3.1", + "com.unity.services.core": "1.12.5" }, "url": "https://packages.unity.com" }, diff --git a/ChessCloudCode/Chess.cs b/ChessCloudCode/Chess.cs index 800aeab..b2e7953 100644 --- a/ChessCloudCode/Chess.cs +++ b/ChessCloudCode/Chess.cs @@ -1,4 +1,5 @@ using System.Formats.Asn1; +using System.Net; using Newtonsoft.Json; using Unity.Services.CloudCode.Apis; using Unity.Services.CloudCode.Core; @@ -17,12 +18,13 @@ public class Chess private const string LeaderboardId = "EloRatings"; private const int KValue = 30; private const int StartingElo = 1500; + private enum MatchState { InProgress, Ended } - + private readonly IGameApiClient _gameApiClient; private readonly IPushClient _pushClient; private readonly ILogger _logger; @@ -36,54 +38,72 @@ public Chess(IGameApiClient gameApiClient, IPushClient pushClient, ILogger InitializeMatch(IExecutionContext context, string sessionId) { - var matchmakingResults = await GetMatchmakingResults(context, matchId); + //var matchmakingResults = await GetMatchmakingResults(context, sessionId); + var matchmakingResults = + await _gameApiClient.MatchmakerMatches.GetMatchmakingResultsAsync(context, context.ServiceToken, sessionId, + context.ProjectId); if (matchmakingResults == null) { - throw new Exception("Matchmaking results not found"); + return new InitializeMatchResponse() { Status = "Matchmaking results not found" }; } - - var players = matchmakingResults?.MatchProperties.Players; - if (players == null || players.Count != 2) + + var players = matchmakingResults.Data.MatchProperties.Players; + if (players.Count != 2) { - throw new Exception("Matchmaking results do not contain two players"); + return new InitializeMatchResponse() { Status = "Matchmaking results do not contain two players" }; } - + var chessBoard = new ChessBoard(); - await _gameApiClient.CloudSaveData.SetCustomItemBatchAsync(context, context.ServiceToken, context.ProjectId, - matchId, - new SetItemBatchBody(new List(){ + var csResponse = await _gameApiClient.CloudSaveData.SetCustomItemBatchAsync(context, context.ServiceToken, + context.ProjectId, + sessionId, + new SetItemBatchBody(new List() + { new("board", chessBoard.ToFen()), new("whitePlayerId", players[0].Id), new("blackPlayerId", players[1].Id), new("turnCounter", 1), - new("matchState", MatchState.InProgress.ToString()) + new("matchState", MatchState.InProgress.ToString()), + new("createdAt", DateTimeOffset.UtcNow.ToUnixTimeSeconds()), + new("updatedAt", DateTimeOffset.UtcNow.ToUnixTimeSeconds()) })); + + if (csResponse.StatusCode != HttpStatusCode.OK) + { + return new InitializeMatchResponse() + { Status = $"Error creating match state in Cloud Save\nError: {csResponse.ErrorText}" }; + } + + List errors = new List(); Parallel.ForEach(players, async player => { - await _gameApiClient.CloudSaveData.SetItemAsync(context, context.ServiceToken, context.ProjectId, + var csPlayerResponse = await _gameApiClient.CloudSaveData.SetItemAsync(context, context.ServiceToken, + context.ProjectId, player.Id, - new SetItemBody("currentMatchId", matchId)); + new SetItemBody("currentMatchId", sessionId)); + + if (csPlayerResponse.StatusCode != HttpStatusCode.OK) + { + errors.Add(csPlayerResponse.ErrorText); + } }); - } - // TODO replace this by a proper call to the generated Matchmaker SDK once an OpenAPI spec is available that supports MatchmakingResults - private async Task GetMatchmakingResults(IExecutionContext context, string matchId) - { - var client = new HttpClient(); - var url = - $"https://matchmaker.services.api.unity.com/v2alpha1/projects/{context.ProjectId}/matches/{matchId}/matchmaking-results"; - - var response = await client.GetAsync(url); - response.EnsureSuccessStatusCode(); - var content = await response.Content.ReadAsStringAsync(); - - return JsonConvert.DeserializeObject(content); + if (errors.Count > 0) + { + return new InitializeMatchResponse() + { Status = $"Error setting player state\nErrors: {String.Join("\n", errors)}" }; + } + + return new InitializeMatchResponse() { Status = "OK" }; } - + + // TODO rename [CloudCodeFunction("HostGame")] public async Task HostGame(IExecutionContext context) { @@ -92,7 +112,8 @@ public async Task HostGame(IExecutionContext context) var chessBoard = new ChessBoard(); await _gameApiClient.CloudSaveData.SetCustomItemBatchAsync(context, context.ServiceToken, context.ProjectId, lobbyResult.Data.Id, - new SetItemBatchBody(new List(){ + new SetItemBatchBody(new List() + { new("board", chessBoard.ToFen()), new("whitePlayerId", context.PlayerId) })); @@ -102,7 +123,7 @@ await _gameApiClient.CloudSaveData.SetCustomItemBatchAsync(context, context.Serv LobbyCode = lobbyResult.Data.LobbyCode, }; } - + [CloudCodeFunction("JoinGame")] public async Task JoinGame(IExecutionContext context, string lobbyCode) { @@ -116,7 +137,8 @@ public async Task JoinGame(IExecutionContext context, string l { _logger.LogError($"{e.Message} | {e.GetType().Name}"); var lobbyIds = _gameApiClient.Lobby.GetJoinedLobbiesAsync(context, context.AccessToken); - var lobbyResponse = await _gameApiClient.Lobby.GetLobbyAsync(context, context.AccessToken, lobbyIds.Result.Data.First()); + var lobbyResponse = + await _gameApiClient.Lobby.GetLobbyAsync(context, context.AccessToken, lobbyIds.Result.Data.First()); return await Rejoin(context, lobbyResponse.Data); } } @@ -165,22 +187,24 @@ await _gameApiClient.CloudSaveData.GetCustomItemsAsync(context, context.ServiceT lobby.Id, new List { "board", "whitePlayerId", "blackPlayerId" }); var chessBoard = ChessBoard.LoadFromFen(saveResponse.Data.Results.Find(r => r.Key == "board").Value.ToString()); - var opponentId = lobby.Players.Select(p => p.Id).First(id => id != context.PlayerId);; + var opponentId = lobby.Players.Select(p => p.Id).First(id => id != context.PlayerId); + ; var whitePlayer = saveResponse.Data.Results.Find(r => r.Key == "whitePlayerId").Value.ToString(); - + var playerIsWhite = whitePlayer == context.PlayerId; - + return new JoinGameResponse() { Session = lobby.Id, Board = chessBoard.ToFen(), OpponentId = opponentId, - IsWhite = playerIsWhite + IsWhite = playerIsWhite }; } [CloudCodeFunction("MakeMove")] - public async Task MakeMove(IExecutionContext context, string session, string fromPosition, string toPosition) + public async Task MakeMove(IExecutionContext context, string session, string fromPosition, + string toPosition) { var saveResponse = await _gameApiClient.CloudSaveData.GetCustomItemsAsync(context, context.ServiceToken, context.ProjectId, @@ -189,16 +213,16 @@ await _gameApiClient.CloudSaveData.GetCustomItemsAsync(context, context.ServiceT var chessBoard = ChessBoard.LoadFromFen(saveResponse.Data.Results.Find(r => r.Key == "board").Value.ToString()); var whitePlayer = saveResponse.Data.Results.Find(r => r.Key == "whitePlayerId").Value.ToString(); var blackPlayer = saveResponse.Data.Results.Find(r => r.Key == "blackPlayerId").Value.ToString(); - + var playerIsWhite = whitePlayer == context.PlayerId; var playerColour = context.PlayerId switch { - var value when value == whitePlayer => PieceColor.White, + var value when value == whitePlayer => PieceColor.White, var value when value == blackPlayer => PieceColor.Black, _ => throw new Exception("Player is not in the game") }; - + // Check if it is the moving player's turn if (chessBoard.Turn != playerColour) { @@ -211,7 +235,7 @@ await _gameApiClient.CloudSaveData.GetCustomItemsAsync(context, context.ServiceT { throw new Exception($"Invalid move from {fromPosition} to {toPosition}"); } - + // Make the move chessBoard.Move(new Move(fromPosition, toPosition)); @@ -221,7 +245,7 @@ await _gameApiClient.CloudSaveData.SetCustomItemAsync(context, context.ServiceTo new SetItemBody("board", chessBoard.ToFen())); var opponentId = playerIsWhite ? blackPlayer : whitePlayer; - + if (chessBoard.IsEndGame) { var playerScore = playerColour == chessBoard.EndGame.WonSide ? 1 : @@ -231,14 +255,15 @@ await UpdateElos( opponentId, playerScore); } - + var boardUpdatedResponse = new BoardUpdateResponse { - Board = chessBoard.ToFen(), - GameOver = chessBoard.IsEndGame, + Board = chessBoard.ToFen(), + GameOver = chessBoard.IsEndGame, EndgameType = chessBoard.EndGame?.EndgameType.ToString() }; - await _pushClient.SendPlayerMessageAsync(context, JsonConvert.SerializeObject(boardUpdatedResponse), "boardUpdated", + await _pushClient.SendPlayerMessageAsync(context, JsonConvert.SerializeObject(boardUpdatedResponse), + "boardUpdated", opponentId); return boardUpdatedResponse; } @@ -247,11 +272,11 @@ public async Task UpdateElos(IExecutionContext context, string opponentId, doubl { var projectId = Guid.Parse(context.ProjectId); var elos = await _gameApiClient.Leaderboards.GetLeaderboardScoresByPlayerIdsAsync(context, context.ServiceToken, - projectId, LeaderboardId, - new LeaderboardPlayerIds(new List() {context.PlayerId, opponentId})); + projectId, LeaderboardId, false, + new LeaderboardPlayerIds(new List() { context.PlayerId, opponentId })); var playerElo = elos.Data?.Results?.Find(r => r.PlayerId == context.PlayerId)?.Score ?? StartingElo; var opponentElo = elos.Data?.Results?.Find(r => r.PlayerId == opponentId)?.Score ?? StartingElo; - + var expectedScore = 1 / (1 + Math.Pow(10, (opponentElo - playerElo) / 400)); var eloChange = KValue * (playerScore - expectedScore); var playerNewElo = playerElo + eloChange; @@ -260,10 +285,12 @@ public async Task UpdateElos(IExecutionContext context, string opponentId, doubl _logger.LogInformation($"Updating {opponentId}'s Elo from {opponentElo} to {opponentNewElo}"); var tasks = new Task[] { - _gameApiClient.Leaderboards.AddLeaderboardPlayerScoreAsync(context, context.ServiceToken, projectId, LeaderboardId, - context.PlayerId, new LeaderboardScore(playerNewElo)), - _gameApiClient.Leaderboards.AddLeaderboardPlayerScoreAsync(context, context.ServiceToken, projectId, LeaderboardId, - opponentId, new LeaderboardScore(opponentNewElo)) + _gameApiClient.Leaderboards.AddLeaderboardPlayerScoreAsync(context, context.ServiceToken, projectId, + LeaderboardId, + context.PlayerId, new AddLeaderboardScore(playerNewElo)), + _gameApiClient.Leaderboards.AddLeaderboardPlayerScoreAsync(context, context.ServiceToken, projectId, + LeaderboardId, + opponentId, new AddLeaderboardScore(opponentNewElo)) }; await Task.WhenAll(tasks); } @@ -281,17 +308,17 @@ await _gameApiClient.CloudSaveData.GetCustomItemsAsync(context, context.ServiceT var playerColour = context.PlayerId switch { - var value when value == whitePlayer => PieceColor.White, + var value when value == whitePlayer => PieceColor.White, var value when value == blackPlayer => PieceColor.Black, _ => throw new Exception("Player is not in the game") }; - + chessBoard.Resign(playerColour); - + await _gameApiClient.CloudSaveData.SetCustomItemAsync(context, context.ServiceToken, context.ProjectId, session, new SetItemBody("board", chessBoard.ToFen())); - + var playerIsWhite = whitePlayer == context.PlayerId; var opponentId = playerIsWhite ? blackPlayer : whitePlayer; var playerScore = playerColour == chessBoard.EndGame.WonSide ? 1 : @@ -300,14 +327,15 @@ await UpdateElos( context, opponentId, playerScore); - + var boardUpdatedResponse = new BoardUpdateResponse { - Board = chessBoard.ToFen(), - GameOver = chessBoard.IsEndGame, + Board = chessBoard.ToFen(), + GameOver = chessBoard.IsEndGame, EndgameType = chessBoard.EndGame?.EndgameType.ToString() }; - await _pushClient.SendPlayerMessageAsync(context, JsonConvert.SerializeObject(boardUpdatedResponse), "boardUpdated", + await _pushClient.SendPlayerMessageAsync(context, JsonConvert.SerializeObject(boardUpdatedResponse), + "boardUpdated", opponentId); return boardUpdatedResponse; } @@ -319,13 +347,18 @@ public class HostGameResponse } public class JoinGameResponse -{ +{ public string Session { get; set; } public string Board { get; set; } public string OpponentId { get; set; } public bool IsWhite { get; set; } } +public class InitializeMatchResponse +{ + public string Status; +} + public class BoardUpdateResponse { public string Board { get; set; } diff --git a/ChessCloudCode/ChessCloudCode.csproj b/ChessCloudCode/ChessCloudCode.csproj index 612011b..8bd0c24 100644 --- a/ChessCloudCode/ChessCloudCode.csproj +++ b/ChessCloudCode/ChessCloudCode.csproj @@ -7,7 +7,7 @@ - + From 4a8d1e8aab3be4e30ca22427de5e8939a5b33ce9 Mon Sep 17 00:00:00 2001 From: Todd Harding Date: Wed, 24 Jul 2024 13:20:13 +0100 Subject: [PATCH 06/10] Matchmaking now works --- Chess/.gitignore | 2 + .../ChessCloudCode.PlayerData.cs | 16 + .../ChessCloudCode.PlayerData.cs.meta | 11 + .../ChessCloudCode/ChessCloudCodeBindings.cs | 10 + Chess/Assets/Scenes/ChessDemo.unity | 179 +- Chess/Assets/Scripts/ChessSession.cs | 13 + Chess/Assets/Scripts/ChessSession.cs.meta | 3 + Chess/Assets/Scripts/ErrorUI.cs | 59 + Chess/Assets/Scripts/ErrorUI.cs.meta | 11 + Chess/Assets/Scripts/Events.cs | 45 + Chess/Assets/Scripts/Events.cs.meta | 11 + Chess/Assets/Scripts/FindingPlayersUI.cs | 68 + Chess/Assets/Scripts/FindingPlayersUI.cs.meta | 11 + Chess/Assets/Scripts/GamePhase.cs | 10 + Chess/Assets/Scripts/GamePhase.cs.meta | 3 + Chess/Assets/Scripts/GameState.cs | 21 + Chess/Assets/Scripts/GameState.cs.meta | 3 + Chess/Assets/Scripts/Match.cs | 12 +- Chess/Assets/Scripts/MatchLoader.cs | 11 +- Chess/Assets/Scripts/MatchManager.cs | 31 - Chess/Assets/Scripts/MatchManager.cs.meta | 3 - Chess/Assets/Scripts/Player.cs | 206 ++- Chess/Assets/Setup/Default.mmq | 6 +- Chess/Assets/UI Toolkit.meta | 8 + Chess/Assets/UI Toolkit/ErrorPanel.uxml | 9 + Chess/Assets/UI Toolkit/ErrorPanel.uxml.meta | 10 + .../UI Toolkit/FindingPlayersPanel.uxml | 8 + .../UI Toolkit/FindingPlayersPanel.uxml.meta | 10 + Chess/Assets/UI Toolkit/PanelSettings.asset | 38 + .../UI Toolkit/PanelSettings.asset.meta | 8 + Chess/Assets/UI Toolkit/UnityThemes.meta | 8 + .../UnityThemes/UnityDefaultRuntimeTheme.tss | 1 + .../UnityDefaultRuntimeTheme.tss.meta | 11 + Chess/Assets/UI Toolkit/chess.uss | 51 + Chess/Assets/UI Toolkit/chess.uss.meta | 11 + Chess/Packages/manifest.json | 2 +- Chess/Packages/packages-lock.json | 10 +- Chess/UIElementsSchema/UIElements.xsd | 16 + .../Unity.Profiling.Editor.xsd | 123 ++ ...y.Services.Core.Editor.Environments.UI.xsd | 25 + ...loyment.Editor.Interface.UI.Components.xsd | 166 ++ ...s.Deployment.Editor.Interface.UI.Views.xsd | 214 +++ Chess/UIElementsSchema/Unity.UI.Builder.xsd | 975 +++++++++++ .../UnityEditor.Experimental.GraphView.xsd | 66 + .../UIElementsSchema/UnityEditor.Overlays.xsd | 50 + ...UnityEditor.PackageManager.UI.Internal.xsd | 606 +++++++ Chess/UIElementsSchema/UnityEditor.Search.xsd | 28 + .../UnityEditor.ShortcutManagement.xsd | 46 + .../UnityEditor.UIElements.Debugger.xsd | 25 + .../UnityEditor.UIElements.xsd | 567 +++++++ .../UnityEngine.UIElements.xsd | 1459 +++++++++++++++++ Chess/UserSettings/Layouts/default-2022.dwlt | 249 +-- ChessCloudCode/BoardUpdateResponse.cs | 8 + ChessCloudCode/Chess.cs | 108 +- ChessCloudCode/Helpers.cs | 20 + ChessCloudCode/HostGameResponse.cs | 6 + ChessCloudCode/InitializeMatchResponse.cs | 6 + ChessCloudCode/JoinGameResponse.cs | 9 + ChessCloudCode/Leaderboards.cs | 70 + ChessCloudCode/PlayerData.cs | 7 + ChessCloudCode/ProblemDetails.cs | 11 + 61 files changed, 5523 insertions(+), 267 deletions(-) create mode 100644 Chess/Assets/CloudCode/GeneratedModuleBindings/ChessCloudCode/ChessCloudCode.PlayerData.cs create mode 100644 Chess/Assets/CloudCode/GeneratedModuleBindings/ChessCloudCode/ChessCloudCode.PlayerData.cs.meta create mode 100644 Chess/Assets/Scripts/ChessSession.cs create mode 100644 Chess/Assets/Scripts/ChessSession.cs.meta create mode 100644 Chess/Assets/Scripts/ErrorUI.cs create mode 100644 Chess/Assets/Scripts/ErrorUI.cs.meta create mode 100644 Chess/Assets/Scripts/Events.cs create mode 100644 Chess/Assets/Scripts/Events.cs.meta create mode 100644 Chess/Assets/Scripts/FindingPlayersUI.cs create mode 100644 Chess/Assets/Scripts/FindingPlayersUI.cs.meta create mode 100644 Chess/Assets/Scripts/GamePhase.cs create mode 100644 Chess/Assets/Scripts/GamePhase.cs.meta create mode 100644 Chess/Assets/Scripts/GameState.cs create mode 100644 Chess/Assets/Scripts/GameState.cs.meta delete mode 100644 Chess/Assets/Scripts/MatchManager.cs delete mode 100644 Chess/Assets/Scripts/MatchManager.cs.meta create mode 100644 Chess/Assets/UI Toolkit.meta create mode 100644 Chess/Assets/UI Toolkit/ErrorPanel.uxml create mode 100644 Chess/Assets/UI Toolkit/ErrorPanel.uxml.meta create mode 100644 Chess/Assets/UI Toolkit/FindingPlayersPanel.uxml create mode 100644 Chess/Assets/UI Toolkit/FindingPlayersPanel.uxml.meta create mode 100644 Chess/Assets/UI Toolkit/PanelSettings.asset create mode 100644 Chess/Assets/UI Toolkit/PanelSettings.asset.meta create mode 100644 Chess/Assets/UI Toolkit/UnityThemes.meta create mode 100644 Chess/Assets/UI Toolkit/UnityThemes/UnityDefaultRuntimeTheme.tss create mode 100644 Chess/Assets/UI Toolkit/UnityThemes/UnityDefaultRuntimeTheme.tss.meta create mode 100644 Chess/Assets/UI Toolkit/chess.uss create mode 100644 Chess/Assets/UI Toolkit/chess.uss.meta create mode 100644 Chess/UIElementsSchema/UIElements.xsd create mode 100644 Chess/UIElementsSchema/Unity.Profiling.Editor.xsd create mode 100644 Chess/UIElementsSchema/Unity.Services.Core.Editor.Environments.UI.xsd create mode 100644 Chess/UIElementsSchema/Unity.Services.Deployment.Editor.Interface.UI.Components.xsd create mode 100644 Chess/UIElementsSchema/Unity.Services.Deployment.Editor.Interface.UI.Views.xsd create mode 100644 Chess/UIElementsSchema/Unity.UI.Builder.xsd create mode 100644 Chess/UIElementsSchema/UnityEditor.Experimental.GraphView.xsd create mode 100644 Chess/UIElementsSchema/UnityEditor.Overlays.xsd create mode 100644 Chess/UIElementsSchema/UnityEditor.PackageManager.UI.Internal.xsd create mode 100644 Chess/UIElementsSchema/UnityEditor.Search.xsd create mode 100644 Chess/UIElementsSchema/UnityEditor.ShortcutManagement.xsd create mode 100644 Chess/UIElementsSchema/UnityEditor.UIElements.Debugger.xsd create mode 100644 Chess/UIElementsSchema/UnityEditor.UIElements.xsd create mode 100644 Chess/UIElementsSchema/UnityEngine.UIElements.xsd create mode 100644 ChessCloudCode/BoardUpdateResponse.cs create mode 100644 ChessCloudCode/Helpers.cs create mode 100644 ChessCloudCode/HostGameResponse.cs create mode 100644 ChessCloudCode/InitializeMatchResponse.cs create mode 100644 ChessCloudCode/JoinGameResponse.cs create mode 100644 ChessCloudCode/Leaderboards.cs create mode 100644 ChessCloudCode/PlayerData.cs create mode 100644 ChessCloudCode/ProblemDetails.cs diff --git a/Chess/.gitignore b/Chess/.gitignore index 774f1a1..d5894c9 100644 --- a/Chess/.gitignore +++ b/Chess/.gitignore @@ -6,10 +6,12 @@ /[Tt]emp/ /[Oo]bj/ /[Bb]uild/ +/[Bb]uild.app/ /[Bb]uilds/ /[Ll]ogs/ /[Mm]emoryCaptures/ UserSettings/ +*DoNotShip/ # Asset meta data should only be ignored when the corresponding asset is also ignored !/**/*.meta diff --git a/Chess/Assets/CloudCode/GeneratedModuleBindings/ChessCloudCode/ChessCloudCode.PlayerData.cs b/Chess/Assets/CloudCode/GeneratedModuleBindings/ChessCloudCode/ChessCloudCode.PlayerData.cs new file mode 100644 index 0000000..784e7b2 --- /dev/null +++ b/Chess/Assets/CloudCode/GeneratedModuleBindings/ChessCloudCode/ChessCloudCode.PlayerData.cs @@ -0,0 +1,16 @@ +// This file was generated by Cloud Code Bindings Generator. Modifications will be lost upon regeneration. +using UnityEngine.Scripting; + +namespace Unity.Services.CloudCode.GeneratedBindings.ChessCloudCode +{ + public partial class PlayerData + { + public int EloScore; + public string Name; + + [Preserve] + public PlayerData () + { + } + } +} \ No newline at end of file diff --git a/Chess/Assets/CloudCode/GeneratedModuleBindings/ChessCloudCode/ChessCloudCode.PlayerData.cs.meta b/Chess/Assets/CloudCode/GeneratedModuleBindings/ChessCloudCode/ChessCloudCode.PlayerData.cs.meta new file mode 100644 index 0000000..722e870 --- /dev/null +++ b/Chess/Assets/CloudCode/GeneratedModuleBindings/ChessCloudCode/ChessCloudCode.PlayerData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e195441b110104044bc8e35a60e131cc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Chess/Assets/CloudCode/GeneratedModuleBindings/ChessCloudCode/ChessCloudCodeBindings.cs b/Chess/Assets/CloudCode/GeneratedModuleBindings/ChessCloudCode/ChessCloudCodeBindings.cs index c692ea9..fdf60ad 100644 --- a/Chess/Assets/CloudCode/GeneratedModuleBindings/ChessCloudCode/ChessCloudCodeBindings.cs +++ b/Chess/Assets/CloudCode/GeneratedModuleBindings/ChessCloudCode/ChessCloudCodeBindings.cs @@ -12,6 +12,16 @@ public ChessCloudCodeBindings(ICloudCodeService service) k_Service = service; } + public async Task PrepareAndFetchPlayerData() + { + return await k_Service.CallModuleEndpointAsync( + "ChessCloudCode", + "PrepareAndFetchPlayerData", + new Dictionary() + { + }); + } + public async Task InitializeMatch(string sessionId) { return await k_Service.CallModuleEndpointAsync( diff --git a/Chess/Assets/Scenes/ChessDemo.unity b/Chess/Assets/Scenes/ChessDemo.unity index defdc82..c00d3c7 100644 --- a/Chess/Assets/Scenes/ChessDemo.unity +++ b/Chess/Assets/Scenes/ChessDemo.unity @@ -1137,6 +1137,56 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 220347693} m_CullTransparentMesh: 1 +--- !u!1 &246826150 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 246826152} + - component: {fileID: 246826151} + m_Layer: 0 + m_Name: Events + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &246826151 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 246826150} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 8e73f24eea6434965bf89b424a5ba356, type: 3} + m_Name: + m_EditorClassIdentifier: + phaseChangeEvent: + m_PersistentCalls: + m_Calls: [] + errorAcknowledgedEvent: + m_PersistentCalls: + m_Calls: [] +--- !u!4 &246826152 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 246826150} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 690.2871, y: 423.5113, z: -0.3530747} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &287442522 GameObject: m_ObjectHideFlags: 0 @@ -1791,6 +1841,67 @@ Transform: m_Children: [] m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &578265780 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 578265782} + - component: {fileID: 578265781} + - component: {fileID: 578265783} + m_Layer: 5 + m_Name: ErrorUIDocument + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &578265781 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 578265780} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 19102, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_PanelSettings: {fileID: 11400000, guid: 0739fa41b160849b0a4faf643d633270, type: 2} + m_ParentUI: {fileID: 0} + sourceAsset: {fileID: 9197481963319205126, guid: 72d6d0cbe988d4e23b5c2a4fbec1a2b9, type: 3} + m_SortingOrder: 0 +--- !u!4 &578265782 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 578265780} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &578265783 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 578265780} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 51b82f777de27477da27398d184ad676, type: 3} + m_Name: + m_EditorClassIdentifier: --- !u!1 &631113151 stripped GameObject: m_CorrespondingSourceObject: {fileID: 1857998089916902, guid: 5b856ec4f8f8cb84f861f8f8a026c288, type: 3} @@ -4159,7 +4270,7 @@ RectTransform: m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.030859973, y: 0.014654879} m_AnchorMax: {x: 0.48631966, y: 0.08413721} - m_AnchoredPosition: {x: -1.5, y: -2.000061} + m_AnchoredPosition: {x: -1.5, y: -2.0000305} m_SizeDelta: {x: 1, y: 2} m_Pivot: {x: 0.5, y: 0.5} --- !u!114 &1522302540 @@ -4819,6 +4930,68 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1676727203} m_CullTransparentMesh: 1 +--- !u!1 &1692556258 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1692556261} + - component: {fileID: 1692556260} + - component: {fileID: 1692556259} + m_Layer: 5 + m_Name: FindingPlayersDocument + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1692556259 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1692556258} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4ae24bb34b51b4c0babf8497ec43dd8a, type: 3} + m_Name: + m_EditorClassIdentifier: + _phase: 0 +--- !u!114 &1692556260 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1692556258} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 19102, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_PanelSettings: {fileID: 11400000, guid: 0739fa41b160849b0a4faf643d633270, type: 2} + m_ParentUI: {fileID: 0} + sourceAsset: {fileID: 9197481963319205126, guid: 3f9ee94c82af6479596bfb4a8560bb48, type: 3} + m_SortingOrder: 0 +--- !u!4 &1692556261 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1692556258} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &1693787996 GameObject: m_ObjectHideFlags: 0 @@ -5563,6 +5736,7 @@ MonoBehaviour: playerEloText: {fileID: 1522302540} opponentNameText: {fileID: 1266149770} opponentEloText: {fileID: 2130390097} + errorText: {fileID: 0} resignButton: {fileID: 1676727203} uiPanel: {fileID: 74450292} resultText: {fileID: 220347695} @@ -6937,3 +7111,6 @@ SceneRoots: - {fileID: 908034760} - {fileID: 1835524142} - {fileID: 519999541} + - {fileID: 578265782} + - {fileID: 246826152} + - {fileID: 1692556261} diff --git a/Chess/Assets/Scripts/ChessSession.cs b/Chess/Assets/Scripts/ChessSession.cs new file mode 100644 index 0000000..e7614cb --- /dev/null +++ b/Chess/Assets/Scripts/ChessSession.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; +using System.Linq; +using Unity.Services.Multiplayer; + +public class ChessSession +{ + public List PlayerIds = new List(); + + public void FromSession(ISession session) + { + PlayerIds = session.Players.Select(player => player.Id).ToList(); + } +} \ No newline at end of file diff --git a/Chess/Assets/Scripts/ChessSession.cs.meta b/Chess/Assets/Scripts/ChessSession.cs.meta new file mode 100644 index 0000000..09206e8 --- /dev/null +++ b/Chess/Assets/Scripts/ChessSession.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: c47b999a7b8342138addf0a44a6c3631 +timeCreated: 1721384341 \ No newline at end of file diff --git a/Chess/Assets/Scripts/ErrorUI.cs b/Chess/Assets/Scripts/ErrorUI.cs new file mode 100644 index 0000000..851507d --- /dev/null +++ b/Chess/Assets/Scripts/ErrorUI.cs @@ -0,0 +1,59 @@ +using UnityEngine; +using UnityEngine.UIElements; + +public class ErrorUI : MonoBehaviour +{ + private VisualElement root; + private Label errorText; + private Button okButton; + + private void Awake() + { + // Load the UI document + var uiDocument = GetComponent(); + root = uiDocument.rootVisualElement; + + // Bind the UI elements + errorText = root.Q