diff --git a/Assets/Scripts/Gameplay/PlayerScoreComponent.cs b/Assets/Scripts/Gameplay/PlayerScoreComponent.cs index 7adb20b..212ee4a 100644 --- a/Assets/Scripts/Gameplay/PlayerScoreComponent.cs +++ b/Assets/Scripts/Gameplay/PlayerScoreComponent.cs @@ -6,21 +6,14 @@ public class PlayerScoreComponent : NetworkBehaviour { public int CurrentScore { get; private set; } public ServerCharacter serverCharacter; - public int m_index; - public PlayerItem playerItem; + public override void OnNetworkSpawn() { - if (IsOwner && IsClient) - { - Debug.Log($"[PlayerScoreComponent] Requesting score initialization for Player {OwnerClientId}"); - ScoreManager.Instance?.InitializePlayerScoreServerRpc(OwnerClientId,serverCharacter.uIStateDisplayHandler.m_UIState.playerName); - } - // For the server player (host), ensure the PlayerScoreComponent is registered properly - if (IsServer && OwnerClientId == NetworkManager.Singleton.LocalClientId) + if (IsServer) { + Debug.Log($"[PlayerScoreComponent] Initializing score for Player {OwnerClientId}"); ScoreManager.Instance?.InitializePlayerScoreServerRpc(OwnerClientId, serverCharacter.uIStateDisplayHandler.m_UIState.playerName); } - serverCharacter=GetComponent(); } public void UpdateScore(int newScore) @@ -35,8 +28,48 @@ public class PlayerScoreComponent : NetworkBehaviour // Update the player's score display in the UI. Debug.Log($"[PlayerScoreComponent] Updated score UI for Player {OwnerClientId}: {CurrentScore}"); } - //private void OnDestroy() - //{ - // Destroy(playerItem.gameObject); - //} } + + +//using UnityEngine; +//using Unity.Netcode; +//using Unity.BossRoom.Gameplay.GameplayObjects.Character; + +//public class PlayerScoreComponent : NetworkBehaviour +//{ +// public int CurrentScore { get; private set; } +// public ServerCharacter serverCharacter; +// public int m_index; +// public PlayerItem playerItem; +// public override void OnNetworkSpawn() +// { +// if (IsOwner && IsClient) +// { +// Debug.Log($"[PlayerScoreComponent] Requesting score initialization for Player {OwnerClientId}"); +// ScoreManager.Instance?.InitializePlayerScore(OwnerClientId,serverCharacter.uIStateDisplayHandler.m_UIState.playerName); +// } +// // For the server player (host), ensure the PlayerScoreComponent is registered properly +// if (IsServer && OwnerClientId == NetworkManager.Singleton.LocalClientId) +// { +// ScoreManager.Instance?.InitializePlayerScore(OwnerClientId, serverCharacter.uIStateDisplayHandler.m_UIState.playerName); +// } +// serverCharacter=GetComponent(); +// } + +// public void UpdateScore(int newScore) +// { +// CurrentScore = newScore; +// Debug.Log($"[PlayerScoreComponent] Player {OwnerClientId} score updated to {newScore}."); +// UpdateScoreUI(); +// } + +// private void UpdateScoreUI() +// { +// // Update the player's score display in the UI. +// Debug.Log($"[PlayerScoreComponent] Updated score UI for Player {OwnerClientId}: {CurrentScore}"); +// } +// //private void OnDestroy() +// //{ +// // Destroy(playerItem.gameObject); +// //} +//} diff --git a/Assets/Scripts/Gameplay/ScoreManager.cs b/Assets/Scripts/Gameplay/ScoreManager.cs index 488da8e..427d3c7 100644 --- a/Assets/Scripts/Gameplay/ScoreManager.cs +++ b/Assets/Scripts/Gameplay/ScoreManager.cs @@ -3,13 +3,56 @@ using System.Collections.Generic; using Unity.Multiplayer.Samples.BossRoom; using UnityEngine; using Unity.Netcode; +using Unity.Collections; public class ScoreManager : NetworkBehaviour { public static ScoreManager Instance { get; private set; } - public Dictionary playerScores = new Dictionary(); - public Dictionary playerNames = new Dictionary(); + // Use a NetworkList to store PlayerData + private NetworkList playerDataList = new NetworkList(); + + // NetworkVariable to sync scores (key: clientId, value: score) + private NetworkVariable> playerScores = + new NetworkVariable>(new SerializableDictionary()); + + [System.Serializable] + public struct PlayerData : System.IEquatable + { + public ulong ClientId; + public FixedString64Bytes Name; + + public bool Equals(PlayerData other) + { + return ClientId == other.ClientId && Name.Equals(other.Name); + } + + public override bool Equals(object obj) + { + return obj is PlayerData other && Equals(other); + } + + public override int GetHashCode() + { + unchecked + { + int hash = 17; + hash = hash * 31 + ClientId.GetHashCode(); + hash = hash * 31 + Name.GetHashCode(); + return hash; + } + } + + public static bool operator ==(PlayerData left, PlayerData right) + { + return left.Equals(right); + } + + public static bool operator !=(PlayerData left, PlayerData right) + { + return !(left == right); + } + } private void Awake() { @@ -25,76 +68,69 @@ public class ScoreManager : NetworkBehaviour { if (IsServer) { - StartCrowPenaltyCoroutineServerRpc(); + StartCrowPenaltyCoroutine(); } - } - [ServerRpc(RequireOwnership = false)] - public void InitializePlayerScoreServerRpc(ulong ownerClientId, string name) - { - if (!playerScores.ContainsKey(ownerClientId)) + if (IsClient) { - playerScores[ownerClientId] = 200; - playerNames[ownerClientId] = name; - Debug.Log($"[ScoreManager] Player {ownerClientId} initialized with a starting score of 200 and name '{name}'."); - Scoreboard.instance.ScoreBoardItemInitializer(ownerClientId, playerScores[ownerClientId], name); - UpdatePlayerScoreClientRpc(ownerClientId, 200); - } - else - { - Debug.LogWarning($"[ScoreManager] Player {ownerClientId} already initialized."); + playerDataList.OnListChanged += OnPlayerDataListChanged; + playerScores.OnValueChanged += OnPlayerScoresChanged; } } - public void UpdatePlayerScore(ulong ownerClientId, int newScore) + private void OnDestroy() { - if (playerScores.ContainsKey(ownerClientId)) - { - playerScores[ownerClientId] = newScore; - Debug.Log($"[ScoreManager] Updating Player {ownerClientId} score to {newScore}."); - UpdatePlayerScoreClientRpc(ownerClientId, newScore); - } - else + if (IsClient) { - Debug.LogWarning($"[ScoreManager] No entry found for Player {ownerClientId}. Cannot update score."); + playerDataList.OnListChanged -= OnPlayerDataListChanged; + playerScores.OnValueChanged -= OnPlayerScoresChanged; } } - [ClientRpc] - public void UpdatePlayerScoreClientRpc(ulong ownerClientId, int newScore) + [ServerRpc(RequireOwnership = false)] + public void InitializePlayerScoreServerRpc(ulong ownerClientId, string name) { - if (playerNames.ContainsKey(ownerClientId)) + if (string.IsNullOrEmpty(name)) + { + Debug.LogWarning($"[ScoreManager] Player name for Client {ownerClientId} is null or empty. Assigning default name."); + name = $"Player {ownerClientId}"; // Default name + } + + var fixedName = new FixedString64Bytes(name); // Convert to FixedString + if (!playerScores.Value.ContainsKey(ownerClientId)) { - string playerName = playerNames[ownerClientId]; - Debug.Log($"[ScoreManager] Received score update for Player {ownerClientId} (Name: {playerName}): {newScore}"); - Scoreboard.instance.ScoreBoardUpdater(playerName, newScore); + // Add initial score and name to the server-side collections + playerScores.Value[ownerClientId] = 200; + playerDataList.Add(new PlayerData { ClientId = ownerClientId, Name = fixedName }); + + Debug.Log($"[ScoreManager] Player {ownerClientId} initialized with a starting score of 200 and name '{fixedName}'."); } else { - Debug.LogWarning($"[ScoreManager] Player name not found for Player {ownerClientId}. Cannot update scoreboard."); + Debug.LogWarning($"[ScoreManager] Player {ownerClientId} already initialized."); } } public void AddPlayerScore(ulong ownerClientId, int scoreToAdd) { - if (playerScores.ContainsKey(ownerClientId)) + if (IsServer && playerScores.Value.ContainsKey(ownerClientId)) { - playerScores[ownerClientId] += scoreToAdd; - UpdatePlayerScore(ownerClientId, playerScores[ownerClientId]); + playerScores.Value[ownerClientId] += scoreToAdd; + Debug.Log($"[ScoreManager] Added {scoreToAdd} points to Player {ownerClientId}. New score: {playerScores.Value[ownerClientId]}."); } } public void SubtractPlayerScore(ulong ownerClientId, int scoreToSubtract) { - if (playerScores.ContainsKey(ownerClientId)) + if (IsServer && playerScores.Value.ContainsKey(ownerClientId)) { - int newScore = Mathf.Max(0, playerScores[ownerClientId] - scoreToSubtract); - UpdatePlayerScore(ownerClientId, newScore); + int currentScore = playerScores.Value[ownerClientId]; + playerScores.Value[ownerClientId] = Mathf.Max(0, currentScore - scoreToSubtract); + Debug.Log($"[ScoreManager] Subtracted {scoreToSubtract} points from Player {ownerClientId}. New score: {playerScores.Value[ownerClientId]}."); } } - [ServerRpc] - public void StartCrowPenaltyCoroutineServerRpc() + private void StartCrowPenaltyCoroutine() { StartCoroutine(ApplyCrowPenaltyCoroutine()); } @@ -105,27 +141,191 @@ public class ScoreManager : NetworkBehaviour while (true) { - // Create a list to store client IDs whose scores need to be updated - List clientsToModify = new List(); - - foreach (var entry in playerScores) + foreach (var entry in playerScores.Value) { ulong ownerClientId = entry.Key; - if (CrowManager.Instance != null && CrowManager.Instance.GetCurrentCrow().OwnerClientId == ownerClientId) { - clientsToModify.Add(ownerClientId); + SubtractPlayerScore(ownerClientId, 2); + Debug.Log($"[ScoreManager] Applied crow penalty to Player {ownerClientId}. New score: {playerScores.Value[ownerClientId]}."); } } - // Apply the penalties after the iteration - foreach (ulong clientId in clientsToModify) + yield return new WaitForSeconds(5f); + } + } + + private void OnPlayerDataListChanged(NetworkListEvent changeEvent) + { + if (changeEvent.Type == NetworkListEvent.EventType.Add) + { + var newData = changeEvent.Value; + string playerName = newData.Name.ToString(); // Convert FixedString to string + + Debug.Log($"[ScoreManager] Player {newData.ClientId} added with name '{playerName}' on client."); + } + } + + private void OnPlayerScoresChanged(SerializableDictionary oldValue, SerializableDictionary newValue) + { + foreach (var entry in newValue) + { + ulong clientId = entry.Key; + int score = entry.Value; + + // Manually search for the player entry in playerDataList + FixedString64Bytes playerName = default; + foreach (var playerData in playerDataList) { - SubtractPlayerScore(clientId, 2); - Debug.Log($"[ScoreManager] Applied crow penalty to Player {clientId}. New score: {playerScores[clientId]}"); + if (playerData.ClientId == clientId) + { + playerName = playerData.Name; + break; + } } - yield return new WaitForSeconds(5f); + if (!playerName.IsEmpty) + { + Debug.Log($"[ScoreManager] Score updated for Player {clientId} (Name: {playerName}): {score}"); + Scoreboard.instance.ScoreBoardUpdater(playerName.ToString(), score); + } + else + { + Debug.LogWarning($"[ScoreManager] Player name not found for Client {clientId}. Cannot update scoreboard."); + } } } } + + +//using System.Collections; +//using System.Collections.Generic; +//using Unity.Multiplayer.Samples.BossRoom; +//using UnityEngine; +//using Unity.Netcode; + +//public class ScoreManager : NetworkBehaviour +//{ +// public static ScoreManager Instance { get; private set; } + +// public Dictionary playerScores = new Dictionary(); +// public Dictionary playerNames = new Dictionary(); + +// private void Awake() +// { +// if (Instance != null && Instance != this) +// { +// Destroy(gameObject); +// return; +// } +// Instance = this; +// } + +// public override void OnNetworkSpawn() +// { +// if (IsServer) +// { +// StartCrowPenaltyCoroutine(); +// } +// } + +// //[ServerRpc(RequireOwnership = false)] +// public void InitializePlayerScore(ulong ownerClientId, string name) +// { +// if (!playerScores.ContainsKey(ownerClientId)) +// { +// playerScores[ownerClientId] = 200; +// playerNames[ownerClientId] = name; +// Debug.Log($"[ScoreManager] Player {ownerClientId} initialized with a starting score of 200 and name '{name}'."); +// Scoreboard.instance.ScoreBoardItemInitializer(ownerClientId, playerScores[ownerClientId], name); +// UpdatePlayerScoreClientRpc(ownerClientId, 200); +// } +// else +// { +// Debug.LogWarning($"[ScoreManager] Player {ownerClientId} already initialized."); +// } +// } + +// public void UpdatePlayerScore(ulong ownerClientId, int newScore) +// { +// if (playerScores.ContainsKey(ownerClientId)) +// { +// playerScores[ownerClientId] = newScore; +// Debug.Log($"[ScoreManager] Updating Player {ownerClientId} score to {newScore}."); +// UpdatePlayerScoreClientRpc(ownerClientId, newScore); +// } +// else +// { +// Debug.LogWarning($"[ScoreManager] No entry found for Player {ownerClientId}. Cannot update score."); +// } +// } + +// [ClientRpc] +// public void UpdatePlayerScoreClientRpc(ulong ownerClientId, int newScore) +// { +// if (playerNames.ContainsKey(ownerClientId)) +// { +// string playerName = playerNames[ownerClientId]; +// Debug.Log($"[ScoreManager] Received score update for Player {ownerClientId} (Name: {playerName}): {newScore}"); +// Scoreboard.instance.ScoreBoardUpdater(playerName, newScore); +// } +// else +// { +// Debug.LogWarning($"[ScoreManager] Player name not found for Player {ownerClientId}. Cannot update scoreboard."); +// } +// } + +// public void AddPlayerScore(ulong ownerClientId, int scoreToAdd) +// { +// if (playerScores.ContainsKey(ownerClientId)) +// { +// playerScores[ownerClientId] += scoreToAdd; +// UpdatePlayerScore(ownerClientId, playerScores[ownerClientId]); +// } +// } + +// public void SubtractPlayerScore(ulong ownerClientId, int scoreToSubtract) +// { +// if (playerScores.ContainsKey(ownerClientId)) +// { +// int newScore = Mathf.Max(0, playerScores[ownerClientId] - scoreToSubtract); +// UpdatePlayerScore(ownerClientId, newScore); +// } +// } + + +// public void StartCrowPenaltyCoroutine() +// { +// StartCoroutine(ApplyCrowPenaltyCoroutine()); +// } + +// private IEnumerator ApplyCrowPenaltyCoroutine() +// { +// yield return new WaitUntil(() => PlatformManager.Instance != null && PlatformManager.Instance.AreAllPlatformsOccupied()); + +// while (true) +// { +// // Create a list to store client IDs whose scores need to be updated +// List clientsToModify = new List(); + +// foreach (var entry in playerScores) +// { +// ulong ownerClientId = entry.Key; + +// if (CrowManager.Instance != null && CrowManager.Instance.GetCurrentCrow().OwnerClientId == ownerClientId) +// { +// clientsToModify.Add(ownerClientId); +// } +// } + +// // Apply the penalties after the iteration +// foreach (ulong clientId in clientsToModify) +// { +// SubtractPlayerScore(clientId, 2); +// Debug.Log($"[ScoreManager] Applied crow penalty to Player {clientId}. New score: {playerScores[clientId]}"); +// } + +// yield return new WaitForSeconds(5f); +// } +// } +//} diff --git a/Assets/Scripts/Gameplay/SerializableDictionary.cs b/Assets/Scripts/Gameplay/SerializableDictionary.cs new file mode 100644 index 0000000..8b26079 --- /dev/null +++ b/Assets/Scripts/Gameplay/SerializableDictionary.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +[Serializable] +public class SerializableDictionary : Dictionary, ISerializationCallbackReceiver +{ + [SerializeField] private List keys = new List(); + [SerializeField] private List values = new List(); + + public void OnBeforeSerialize() + { + keys.Clear(); + values.Clear(); + + foreach (var pair in this) + { + keys.Add(pair.Key); + values.Add(pair.Value); + } + } + + public void OnAfterDeserialize() + { + Clear(); + + if (keys.Count != values.Count) + throw new Exception("Key and value count mismatch!"); + + for (int i = 0; i < keys.Count; i++) + { + Add(keys[i], values[i]); + } + } +} diff --git a/Assets/Scripts/Gameplay/SerializableDictionary.cs.meta b/Assets/Scripts/Gameplay/SerializableDictionary.cs.meta new file mode 100644 index 0000000..c68ddfb --- /dev/null +++ b/Assets/Scripts/Gameplay/SerializableDictionary.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 318306cbce4e91a468e5d39c8bd4218a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: