using System.Collections.Generic; using UnityEngine; #if UNITY_EDITOR using UnityEditor; #endif public sealed class AllyHeroDeployLedger : MonoBehaviour { public static AllyHeroDeployLedger Instance { get; private set; } private readonly Dictionary deployCountsByHeroId = new Dictionary(); private readonly Dictionary finishCountsByHeroId = new Dictionary(); private readonly Dictionary mvpCountsByHeroId = new Dictionary(); private bool initialized; private bool loadedFromSave; [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] private static void Bootstrap() { EnsureInstance(); } public static AllyHeroDeployLedger EnsureInstance() { if (Instance != null) { return Instance; } GameObject host = new GameObject("__runtime_ally_deploy_bridge"); host.hideFlags = HideFlags.HideInHierarchy | HideFlags.HideInInspector; DontDestroyOnLoad(host); Instance = host.AddComponent(); return Instance; } private void Awake() { if (Instance != null && Instance != this) { Destroy(gameObject); return; } Instance = this; DontDestroyOnLoad(gameObject); InitializeIfNeeded(); } private void OnApplicationPause(bool pauseStatus) { if (pauseStatus) { SaveNow(); } } private void OnApplicationQuit() { SaveNow(); } public void InitializeIfNeeded() { if (initialized) { return; } AllyHeroDeployLedgerPayload payload; loadedFromSave = AllyHeroDeployLedgerStorage.TryLoad(out payload); RebuildFromPayload(payload); initialized = true; SyncAllMirrorFlags(); SaveNow(); } public int GetDeployCount(int heroId) { InitializeIfNeeded(); int count; return deployCountsByHeroId.TryGetValue(heroId, out count) ? count : 0; } public int GetFinishCount(int heroId) { InitializeIfNeeded(); int count; return finishCountsByHeroId.TryGetValue(heroId, out count) ? count : 0; } public int GetMvpCount(int heroId) { InitializeIfNeeded(); int count; return mvpCountsByHeroId.TryGetValue(heroId, out count) ? count : 0; } public void IncrementDeployCount(AllyHero_SO hero, int amount = 1) { if (hero == null || hero.ally_heroID <= 0 || amount <= 0) { return; } InitializeIfNeeded(); int current = GetDeployCount(hero.ally_heroID); long next = (long)current + amount; deployCountsByHeroId[hero.ally_heroID] = next > int.MaxValue ? int.MaxValue : (int)next; hero.ally_battleDeployCount = deployCountsByHeroId[hero.ally_heroID]; MarkDirty(hero); SaveNow(); } public void IncrementFinishCount(AllyHero_SO hero, int amount = 1) { if (hero == null || hero.ally_heroID <= 0 || amount <= 0) { return; } InitializeIfNeeded(); int current = GetFinishCount(hero.ally_heroID); long next = (long)current + amount; finishCountsByHeroId[hero.ally_heroID] = next > int.MaxValue ? int.MaxValue : (int)next; hero.ally_finishCount = finishCountsByHeroId[hero.ally_heroID]; MarkDirty(hero); SaveNow(); } public void IncrementMvpCount(AllyHero_SO hero, int amount = 1) { if (hero == null || hero.ally_heroID <= 0 || amount <= 0) { return; } InitializeIfNeeded(); int current = GetMvpCount(hero.ally_heroID); long next = (long)current + amount; mvpCountsByHeroId[hero.ally_heroID] = next > int.MaxValue ? int.MaxValue : (int)next; hero.ally_mvpCount = mvpCountsByHeroId[hero.ally_heroID]; MarkDirty(hero); SaveNow(); } public void SaveNow() { if (!initialized) { return; } SyncAllMirrorFlags(); AllyHeroDeployLedgerStorage.TrySave(BuildPayload()); } private void RebuildFromPayload(AllyHeroDeployLedgerPayload payload) { deployCountsByHeroId.Clear(); finishCountsByHeroId.Clear(); mvpCountsByHeroId.Clear(); if (payload == null || payload.entries == null) { return; } for (int i = 0; i < payload.entries.Count; i++) { AllyHeroDeployEntry entry = payload.entries[i]; if (entry == null || entry.heroId <= 0) { continue; } deployCountsByHeroId[entry.heroId] = Mathf.Max(0, entry.deployCount); finishCountsByHeroId[entry.heroId] = Mathf.Max(0, entry.finishCount); mvpCountsByHeroId[entry.heroId] = Mathf.Max(0, entry.mvpCount); } } private void SyncAllMirrorFlags() { AllyHero_SO[] heroes = Resources.LoadAll(string.Empty); for (int i = 0; i < heroes.Length; i++) { AllyHero_SO hero = heroes[i]; if (hero == null || hero.ally_heroID <= 0) { continue; } int count; if (!deployCountsByHeroId.TryGetValue(hero.ally_heroID, out count)) { count = 0; } int finishCount; if (!finishCountsByHeroId.TryGetValue(hero.ally_heroID, out finishCount)) { finishCount = 0; } int mvpCount; if (!mvpCountsByHeroId.TryGetValue(hero.ally_heroID, out mvpCount)) { mvpCount = 0; } bool changed = false; if (hero.ally_battleDeployCount != count) { hero.ally_battleDeployCount = count; changed = true; } if (hero.ally_finishCount != finishCount) { hero.ally_finishCount = finishCount; changed = true; } if (hero.ally_mvpCount != mvpCount) { hero.ally_mvpCount = mvpCount; changed = true; } if (changed) { MarkDirty(hero); } } } private AllyHeroDeployLedgerPayload BuildPayload() { AllyHeroDeployLedgerPayload payload = AllyHeroDeployLedgerStorage.CreateDefaultPayload(); HashSet allHeroIds = new HashSet(); foreach (KeyValuePair pair in deployCountsByHeroId) { allHeroIds.Add(pair.Key); } foreach (KeyValuePair pair in finishCountsByHeroId) { allHeroIds.Add(pair.Key); } foreach (KeyValuePair pair in mvpCountsByHeroId) { allHeroIds.Add(pair.Key); } foreach (int heroId in allHeroIds) { payload.entries.Add(new AllyHeroDeployEntry { heroId = heroId, deployCount = Mathf.Max(0, GetDeployCount(heroId)), finishCount = Mathf.Max(0, GetFinishCount(heroId)), mvpCount = Mathf.Max(0, GetMvpCount(heroId)) }); } return payload; } private static void MarkDirty(AllyHero_SO hero) { #if UNITY_EDITOR if (!Application.isPlaying && hero != null) { EditorUtility.SetDirty(hero); } #endif } }