using System; using System.Collections; using System.Collections.Generic; using UnityEngine; public class AchievementManager : MonoBehaviour { public static AchievementManager Instance { get; private set; } [Header("成就列表")] public List allAchievements = new List(); private Dictionary achievementProgress = new Dictionary(); private Dictionary sessionIncrement = new Dictionary(); private const string GUEST_ACHIEVEMENTS = "guest_achievements_data"; private bool isInitialized = false; public bool IsInitialized => isInitialized; private static readonly BuiltInAchievementDefinition[] BuiltInAchievements = { new BuiltInAchievementDefinition("first_room", "初次探索", "完成1个房间", 1, AchievementType.CompleteRooms, 20), new BuiltInAchievementDefinition("first_correct_answer", "答题新星", "答对1道题目", 1, AchievementType.AnswerCorrect, 20) }; private void Awake() { if (Instance == null) { Instance = this; DontDestroyOnLoad(gameObject); } else { Destroy(gameObject); } } private void Start() { StartCoroutine(WaitAndLoadAchievements()); } IEnumerator WaitAndLoadAchievements() { while (LoginManager.Instance == null) { yield return null; } while (!LoginManager.Instance.isLoggedIn && !LoginManager.Instance.IsGuest()) { yield return null; } yield return new WaitForSeconds(0.1f); LoadAchievements(); } public void LoadAchievements() { achievementProgress.Clear(); sessionIncrement.Clear(); isInitialized = false; bool isGuest = LoginManager.Instance == null || LoginManager.Instance.IsGuest(); Debug.Log($"加载成就数据,是否游客模式: {isGuest}"); if (isGuest) { LoadGuestAchievements(); InitializeMissingAchievements(); isInitialized = true; } else { LoadServerAchievements(); } } void LoadGuestAchievements() { string json = PlayerPrefs.GetString(GUEST_ACHIEVEMENTS, ""); if (!string.IsNullOrEmpty(json)) { AchievementSaveData saveData = JsonUtility.FromJson(json); if (saveData != null && saveData.achievements != null) { foreach (var data in saveData.achievements) { achievementProgress[data.achievementId] = data; } Debug.Log($"游客成就数据已加载,共 {saveData.achievements.Count} 个"); } } else { Debug.Log("未找到游客成就数据,将使用初始数据"); } } void LoadServerAchievements() { if (NetworkManager.Instance == null) { Debug.LogWarning("NetworkManager未初始化,无法加载在线成就"); InitializeMissingAchievements(); isInitialized = true; return; } NetworkManager.Instance.GetAchievements( response => { if (response.success && response.data != null && response.data.Length > 0) { foreach (var serverData in response.data) { AchievementData data = new AchievementData { achievementId = serverData.achievementId, currentValue = serverData.currentValue, isUnlocked = serverData.isUnlocked }; achievementProgress[data.achievementId] = data; } Debug.Log($"在线成就数据已加载,共 {response.data.Length} 个"); } else { Debug.Log("服务器无成就数据,将初始化新数据"); } InitializeMissingAchievements(); isInitialized = true; }, error => { Debug.LogWarning($"加载在线成就失败: {error}"); InitializeMissingAchievements(); isInitialized = true; } ); } void InitializeMissingAchievements() { int newCount = 0; foreach (var achievementSO in allAchievements) { if (!achievementProgress.ContainsKey(achievementSO.achievementId)) { AchievementData data = new AchievementData { achievementId = achievementSO.achievementId, achievementName = achievementSO.achievementName, description = achievementSO.description, targetValue = achievementSO.targetValue, currentValue = 0, isUnlocked = false, icon = achievementSO.icon, reward = achievementSO.reward }; achievementProgress[data.achievementId] = data; newCount++; } else { AchievementData data = achievementProgress[achievementSO.achievementId]; data.achievementName = achievementSO.achievementName; data.description = achievementSO.description; data.targetValue = achievementSO.targetValue; data.icon = achievementSO.icon; data.reward = achievementSO.reward; } } Debug.Log($"成就初始化完成,共 {achievementProgress.Count} 个成就,新增 {newCount} 个"); } void EnsureBuiltInAchievements(ref int newCount) { foreach (var builtInAchievement in BuiltInAchievements) { Sprite fallbackIcon = FindReusableIcon(builtInAchievement.achievementType); if (!achievementProgress.ContainsKey(builtInAchievement.achievementId)) { achievementProgress[builtInAchievement.achievementId] = builtInAchievement.ToData(fallbackIcon); newCount++; } else { builtInAchievement.Refresh(achievementProgress[builtInAchievement.achievementId], fallbackIcon); } } } Sprite FindReusableIcon(AchievementType achievementType) { Sprite fallbackIcon = null; foreach (var achievementSO in allAchievements) { if (achievementSO == null || achievementSO.icon == null) { continue; } if (achievementSO.achievementType == achievementType) { return achievementSO.icon; } if (fallbackIcon == null) { fallbackIcon = achievementSO.icon; } } return fallbackIcon; } public void UpdateAchievement(AchievementType type, int value) { if (value <= 0) { return; } if (!sessionIncrement.ContainsKey(type)) { sessionIncrement[type] = 0; } sessionIncrement[type] += value; Debug.Log($"成就 {type} 本局增量: {value}, 累计本局: {sessionIncrement[type]}"); int ignoredNewCount = 0; EnsureBuiltInAchievements(ref ignoredNewCount); HashSet updatedIds = new HashSet(); foreach (var achievementSO in allAchievements) { if (achievementSO.achievementType == type) { if (updatedIds.Contains(achievementSO.achievementId)) { continue; } updatedIds.Add(achievementSO.achievementId); if (achievementProgress.ContainsKey(achievementSO.achievementId)) { AchievementData data = achievementProgress[achievementSO.achievementId]; if (!data.isUnlocked) { data.currentValue += value; if (data.currentValue >= data.targetValue) { data.currentValue = data.targetValue; data.isUnlocked = true; Debug.Log($"成就解锁:{data.achievementName}"); } } } } } foreach (var builtInAchievement in BuiltInAchievements) { if (builtInAchievement.achievementType != type || updatedIds.Contains(builtInAchievement.achievementId)) { continue; } updatedIds.Add(builtInAchievement.achievementId); UpdateAchievementData(builtInAchievement.achievementId, value); } } public void SetAchievementProgress(AchievementType type, int value) { int ignoredNewCount = 0; EnsureBuiltInAchievements(ref ignoredNewCount); HashSet updatedIds = new HashSet(); foreach (var achievementSO in allAchievements) { if (achievementSO.achievementType == type) { if (updatedIds.Contains(achievementSO.achievementId)) { continue; } updatedIds.Add(achievementSO.achievementId); if (achievementProgress.ContainsKey(achievementSO.achievementId)) { AchievementData data = achievementProgress[achievementSO.achievementId]; if (!data.isUnlocked) { data.currentValue = value; if (data.currentValue >= data.targetValue) { data.currentValue = data.targetValue; data.isUnlocked = true; Debug.Log($"成就解锁:{data.achievementName}"); } } } } } foreach (var builtInAchievement in BuiltInAchievements) { if (builtInAchievement.achievementType != type || updatedIds.Contains(builtInAchievement.achievementId)) { continue; } updatedIds.Add(builtInAchievement.achievementId); SetAchievementData(builtInAchievement.achievementId, value); } } public int GetAccumulatedValue(AchievementType type) { int total = 0; foreach (var achievementSO in allAchievements) { if (achievementSO.achievementType == type) { if (achievementProgress.ContainsKey(achievementSO.achievementId)) { total = Mathf.Max(total, achievementProgress[achievementSO.achievementId].currentValue); } } } return total; } void UpdateAchievementData(string achievementId, int value) { if (!achievementProgress.ContainsKey(achievementId)) { return; } AchievementData data = achievementProgress[achievementId]; if (data.isUnlocked) { return; } data.currentValue += value; if (data.currentValue >= data.targetValue) { data.currentValue = data.targetValue; data.isUnlocked = true; Debug.Log($"成就解锁:{data.achievementName}"); } } void SetAchievementData(string achievementId, int value) { if (!achievementProgress.ContainsKey(achievementId)) { return; } AchievementData data = achievementProgress[achievementId]; if (data.isUnlocked) { return; } data.currentValue = value; if (data.currentValue >= data.targetValue) { data.currentValue = data.targetValue; data.isUnlocked = true; Debug.Log($"成就解锁:{data.achievementName}"); } } public List GetAllAchievements() { int ignoredNewCount = 0; EnsureBuiltInAchievements(ref ignoredNewCount); return new List(achievementProgress.Values); } public int GetUnlockedCount() { int count = 0; foreach (var data in achievementProgress.Values) { if (data.isUnlocked) count++; } return count; } public int GetTotalCount() { return achievementProgress.Count; } public void SaveAchievements() { bool isGuest = LoginManager.Instance == null || LoginManager.Instance.IsGuest(); if (isGuest) { SaveGuestAchievements(); } else { SaveServerAchievements(); } } void SaveServerAchievements() { if (NetworkManager.Instance == null) { Debug.LogWarning("NetworkManager未初始化,无法保存在线成就"); return; } List syncItems = new List(); foreach (var data in achievementProgress.Values) { syncItems.Add(new AchievementSyncItem { achievementId = data.achievementId, currentValue = data.currentValue, isUnlocked = data.isUnlocked }); } AchievementSyncRequest request = new AchievementSyncRequest { achievements = syncItems.ToArray() }; NetworkManager.Instance.SyncAchievements(request, response => { if (response.success) { Debug.Log($"在线成就同步成功!共 {syncItems.Count} 个成就"); sessionIncrement.Clear(); } else { Debug.LogWarning($"在线成就同步失败: {response.message}"); } }, error => { Debug.LogWarning($"在线成就同步请求失败: {error}"); } ); } public void SaveGuestAchievements() { AchievementSaveData saveData = new AchievementSaveData { achievements = new List(achievementProgress.Values) }; string json = JsonUtility.ToJson(saveData); PlayerPrefs.SetString(GUEST_ACHIEVEMENTS, json); PlayerPrefs.Save(); sessionIncrement.Clear(); Debug.Log("游客成就数据已保存到本地"); } public void ResetAchievements() { achievementProgress.Clear(); sessionIncrement.Clear(); bool isGuest = LoginManager.Instance == null || LoginManager.Instance.IsGuest(); if (isGuest) { PlayerPrefs.DeleteKey(GUEST_ACHIEVEMENTS); PlayerPrefs.Save(); } InitializeMissingAchievements(); Debug.Log("成就已重置"); } public void SyncToServer() { if (LoginManager.Instance == null || LoginManager.Instance.IsGuest()) { Debug.Log("游客模式,不同步成就到服务器"); return; } SaveServerAchievements(); } } [Serializable] public class AchievementSaveData { public List achievements; } public class BuiltInAchievementDefinition { public string achievementId; public string achievementName; public string description; public int targetValue; public AchievementType achievementType; public int reward; public BuiltInAchievementDefinition(string achievementId, string achievementName, string description, int targetValue, AchievementType achievementType, int reward) { this.achievementId = achievementId; this.achievementName = achievementName; this.description = description; this.targetValue = targetValue; this.achievementType = achievementType; this.reward = reward; } public AchievementData ToData(Sprite icon) { return new AchievementData { achievementId = achievementId, achievementName = achievementName, description = description, targetValue = targetValue, currentValue = 0, isUnlocked = false, icon = icon, reward = reward }; } public void Refresh(AchievementData data, Sprite icon) { data.achievementName = achievementName; data.description = description; data.targetValue = targetValue; data.icon = icon; data.reward = reward; } }