diff --git a/Assets/Scripts/Control&Input/ItemSelectManager.cs b/Assets/Scripts/Control&Input/ItemSelectManager.cs index 1d0f1add..a34c728d 100644 --- a/Assets/Scripts/Control&Input/ItemSelectManager.cs +++ b/Assets/Scripts/Control&Input/ItemSelectManager.cs @@ -5,16 +5,12 @@ using Mirror; using UnityEngine; -internal struct ClientReadyMessage : NetworkMessage +public class ItemSelectManager : NetworkBehaviour { -} + private struct ClientReadyMessage : NetworkMessage { } -internal struct ClientNotReadyMessage : NetworkMessage -{ -} + private struct ClientNotReadyMessage : NetworkMessage { } -public class ItemSelectManager : NetworkBehaviour -{ [SerializeField] private float graceTime = 1; private List itemSelectMenus; diff --git a/Assets/Scripts/Control&Input/RPRNetworkManager.cs b/Assets/Scripts/Control&Input/RPRNetworkManager.cs index af4e8d49..e0f1fa78 100644 --- a/Assets/Scripts/Control&Input/RPRNetworkManager.cs +++ b/Assets/Scripts/Control&Input/RPRNetworkManager.cs @@ -10,6 +10,7 @@ using UnityEngine.SceneManagement; // TODO consider splitting this into match-specific state and general player metadata +// TODO also consider sticking some of the metadata onto the playermanager/playeridentity component for ease of access... public struct PlayerDetails { public uint id; @@ -41,95 +42,102 @@ public PlayerConnectedMessage(int inputID, ulong steamID = 0) public ulong steamID; } -public struct PlayerLeftMessage : NetworkMessage -{ - public PlayerLeftMessage(uint id) - { - this.id = id; - } - public uint id; +public enum PlayerType +{ + Local, + AI, + Remote } -public struct RulesetMessage : NetworkMessage +public class RPRNetworkManager : NetworkManager { - public RulesetMessage(Ruleset ruleset) + #region Messages + private struct PlayerLeftMessage : NetworkMessage { - this.ruleset = ruleset.ToNetworkRuleset(); + public PlayerLeftMessage(uint id) + { + this.id = id; + } + + public uint id; } - public NetworkRuleset ruleset; -} -public struct InitialPlayerDetailsMessage : NetworkMessage -{ - public InitialPlayerDetailsMessage(PlayerDetails details) + private struct RulesetMessage : NetworkMessage { - this.details = details; + public RulesetMessage(Ruleset ruleset) + { + this.ruleset = ruleset.ToNetworkRuleset(); + } + public NetworkRuleset ruleset; } - public PlayerDetails details; -} -public struct UpdatedPlayerDetailsMessage : NetworkMessage -{ - public UpdatedPlayerDetailsMessage(PlayerDetails details) + private struct InitialPlayerDetailsMessage : NetworkMessage { - this.details = details; + public InitialPlayerDetailsMessage(PlayerDetails details) + { + this.details = details; + } + public PlayerDetails details; } - public PlayerDetails details; -} -public struct UpdateLoadoutMessage : NetworkMessage -{ - public UpdateLoadoutMessage(uint id, string body, string barrel, string extension) + private struct UpdatedPlayerDetailsMessage : NetworkMessage { - this.id = id; - this.body = body; - this.barrel = barrel; - this.extension = extension; + public UpdatedPlayerDetailsMessage(PlayerDetails details) + { + this.details = details; + } + public PlayerDetails details; } - public uint id; - public string body; - public string barrel; - public string extension; -} - -public struct StartMatchMessage : NetworkMessage { } -public struct SpawnPlayerMessage : NetworkMessage -{ - public SpawnPlayerMessage(uint id, PlayerType type) + private struct UpdateLoadoutMessage : NetworkMessage { - this.id = id; - this.type = type; + public UpdateLoadoutMessage(uint id, string body, string barrel, string extension) + { + this.id = id; + this.body = body; + this.barrel = barrel; + this.extension = extension; + } + public uint id; + public string body; + public string barrel; + public string extension; } - public uint id; - public PlayerType type; -} + private struct StartMatchMessage : NetworkMessage { } -public struct InitializePlayerMessage : NetworkMessage -{ - public InitializePlayerMessage(uint id, Vector3 position, Quaternion rotation) + private struct ClientReadyMessage : NetworkMessage { } + + private struct AllClientsReadyMessage : NetworkMessage { } + + private struct SpawnPlayerMessage : NetworkMessage { - this.id = id; - this.position = position; - this.rotation = rotation; + public SpawnPlayerMessage(uint id) + { + this.id = id; + } + + public uint id; } - public uint id; - public Vector3 position; - public Quaternion rotation; -} + private struct InitializePlayerMessage : NetworkMessage + { + public InitializePlayerMessage(uint id, Vector3 position, Quaternion rotation) + { + this.id = id; + this.position = position; + this.rotation = rotation; + } -public enum PlayerType -{ - Local, - AI, - Remote -} + public uint id; + public Vector3 position; + public Quaternion rotation; + } + #endregion; + + #region State -public class RPRNetworkManager : NetworkManager -{ private const int FPSPlayerPrefabIndex = 0; private const int BiddingPlayerPrefabIndexOffset = 1; private const int AIFPSPlayerPrefabIndex = 2; @@ -146,6 +154,8 @@ public class RPRNetworkManager : NetworkManager private static bool isInMatch; public static bool IsInMatch => isInMatch; + private static bool allClientsAreReady; + private static Dictionary players = new(); public static int NumPlayers => players.Count; public static int NumAvailableSlots => Mathf.Max(0, MaxPlayers - players.Count); @@ -163,6 +173,7 @@ public class RPRNetworkManager : NetworkManager /// private static List connections = new(); private static Dictionary> playersForConnection = new(); + private static Dictionary readinessForConnection = new(); private static List connectedPlayers = new(); public static ReadOnlyCollection Connections; @@ -177,9 +188,14 @@ public class RPRNetworkManager : NetworkManager public GamestateEvent OnMatchStart; public GamestateEvent OnMatchEnd; + #endregion + + #region Initializing + private void ResetState() { isInMatch = false; + allClientsAreReady = false; playerIndex = 0; players = new(); playerInstances = new(); @@ -190,22 +206,24 @@ private void ResetState() connections = new(); connectedPlayers = new(); playersForConnection = new(); + readinessForConnection = new(); Connections = new(connections); } public override void OnStartServer() { NetworkServer.RegisterHandler(OnSpawnPlayerInput); - NetworkServer.RegisterHandler(OnReceiveUpdateLoadout); + NetworkServer.RegisterHandler(OnReceiveUpdatedLoadout); + NetworkServer.RegisterHandler(OnClientReady); ResetState(); } - #region Player joining public override void OnClientConnect() { base.OnClientConnect(); + NetworkClient.RegisterHandler(OnAllClientsReady); NetworkClient.RegisterHandler(OnStartMatch); NetworkClient.RegisterHandler(OnPlayerLeft); NetworkClient.RegisterHandler(OnReceivePlayerDetails); @@ -220,6 +238,10 @@ public override void OnClientConnect() ResetState(); } + #endregion + + #region Disconnecting + public override void OnServerDisconnect(NetworkConnectionToClient connection) { if (playersForConnection == null || !playersForConnection.ContainsKey(connection.connectionId)) @@ -291,6 +313,10 @@ private void OnPlayerLeft(PlayerLeftMessage message) OnPlayerRemoved?.Invoke(playerDetails); } + #endregion + + #region Network startup + public void JoinLobby(string address = "127.0.0.1") { if (NetworkServer.active) @@ -346,6 +372,10 @@ private static IEnumerator WaitAndSwitchToTrainingMode() MusicTrackManager.Singleton.SwitchTo(MusicType.Tutorial); } + #endregion + + #region Match start + // TODO custom method for leaving training mode :) // TODO handle leaving of match/lobby better @@ -369,6 +399,10 @@ private void OnStartMatch(StartMatchMessage message) LoadingScreen.Singleton.Show(FindObjectsByType(FindObjectsSortMode.None).Where(camera => camera.gameObject.activeInHierarchy && camera.enabled == true).First()); } + #endregion + + #region Joining + private void RefuseConnection(NetworkConnectionToClient connection) { // Don't refuse existing connections @@ -631,7 +665,7 @@ public void UpdateLoadout() } } - private void OnReceiveUpdateLoadout(NetworkConnectionToClient connection, UpdateLoadoutMessage message) + private void OnReceiveUpdatedLoadout(NetworkConnectionToClient connection, UpdateLoadoutMessage message) { if (!players.TryGetValue(message.id, out var playerDetails)) return; @@ -646,6 +680,7 @@ private void OnReceiveUpdateLoadout(NetworkConnectionToClient connection, Update public override void OnClientChangeScene(string newSceneName, SceneOperation sceneOperation, bool customHandling) { + allClientsAreReady = false; var originalSceneName = SceneManager.GetActiveScene().name; switch (newSceneName) { @@ -672,15 +707,43 @@ public override void OnClientChangeScene(string newSceneName, SceneOperation sce StartCoroutine(SendSpawnRequestsAfterSceneLoad(originalSceneName)); } + #endregion + + #region Start of round handshake + + private void OnClientReady(NetworkConnectionToClient connection, ClientReadyMessage _) + { + readinessForConnection[connection.connectionId] = true; + if (Connections.All(c => readinessForConnection.TryGetValue(c.connectionId, out var isReady) && isReady)) + NetworkServer.SendToAll(new AllClientsReadyMessage()); + } + + private void OnAllClientsReady(AllClientsReadyMessage _) + { + Debug.Log("yea we all ready"); + allClientsAreReady = true; + } + private IEnumerator SendSpawnRequestsAfterSceneLoad(string originalSceneName) { + readinessForConnection = new(); + allClientsAreReady = false; + while (SceneManager.GetActiveScene().name == originalSceneName) yield return null; + Debug.Log("yeah I sent msg"); + + NetworkClient.Send(new ClientReadyMessage()); + + // Wait for ready msg from clients! + while (!allClientsAreReady) + yield return null; + // Spawn players for our inputs (and bots) foreach (var id in localPlayerIds) { - NetworkClient.Send(new SpawnPlayerMessage(id, PlayerType.Local)); + NetworkClient.Send(new SpawnPlayerMessage(id)); } if (!NetworkServer.active) @@ -691,12 +754,12 @@ private IEnumerator SendSpawnRequestsAfterSceneLoad(string originalSceneName) // (perhaps you could call the spawn methods directly?) foreach (var p in players.Values.Where(p => p.type == PlayerType.AI)) { - NetworkClient.Send(new SpawnPlayerMessage(p.id, PlayerType.AI)); + NetworkClient.Send(new SpawnPlayerMessage(p.id)); } foreach (var p in players.Values.Where(p => p.type is PlayerType.Remote && !connectedPlayers.Contains(p.id))) { - NetworkClient.Send(new SpawnPlayerMessage(p.id, PlayerType.Local)); + NetworkClient.Send(new SpawnPlayerMessage(p.id)); } } @@ -892,6 +955,7 @@ private IEnumerator WaitAndInitializeFPSPlayer(InitializePlayerMessage message) } playerInstances[player.id] = player; + Debug.Log("finish init player!", player.gameObject); } #endregion diff --git a/Assets/Scripts/Gamestate/MatchController.cs b/Assets/Scripts/Gamestate/MatchController.cs index eacd7a1b..1d383679 100644 --- a/Assets/Scripts/Gamestate/MatchController.cs +++ b/Assets/Scripts/Gamestate/MatchController.cs @@ -214,6 +214,7 @@ private void LateUpdate() [Server] private void EndActiveRound() { + Debug.Log("omg nei fredrik stopp (end active round fra server)"); roundTimer.OnTimerRunCompleted -= EndActiveRound; EndActiveRoundRpc(LastRound.SummarizeRound()); } @@ -221,6 +222,7 @@ private void EndActiveRound() [ClientRpc] private void EndActiveRoundRpc(NetworkRound serverRound) { + Debug.Log("end active round client"); rounds[^1].UpdateFromSummary(serverRound); isRoundInProgress = false;