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 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; SeedFromHeroAssetsIfNeeded(); SyncAllMirrorFlags(); SaveNow(); } public int GetDeployCount(int heroId) { InitializeIfNeeded(); int count; return deployCountsByHeroId.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 SaveNow() { if (!initialized) { return; } SyncAllMirrorFlags(); AllyHeroDeployLedgerStorage.TrySave(BuildPayload()); } private void RebuildFromPayload(AllyHeroDeployLedgerPayload payload) { deployCountsByHeroId.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); } } private void SeedFromHeroAssetsIfNeeded() { AllyHero_SO[] heroes = Resources.LoadAll(string.Empty); bool changed = false; for (int i = 0; i < heroes.Length; i++) { AllyHero_SO hero = heroes[i]; if (hero == null || hero.ally_heroID <= 0) { continue; } if (deployCountsByHeroId.ContainsKey(hero.ally_heroID)) { continue; } if (hero.ally_battleDeployCount <= 0) { continue; } deployCountsByHeroId[hero.ally_heroID] = Mathf.Max(0, hero.ally_battleDeployCount); changed = true; } if (changed && !loadedFromSave) { SaveNow(); } } 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; } if (hero.ally_battleDeployCount == count) { continue; } hero.ally_battleDeployCount = count; MarkDirty(hero); } } private AllyHeroDeployLedgerPayload BuildPayload() { AllyHeroDeployLedgerPayload payload = AllyHeroDeployLedgerStorage.CreateDefaultPayload(); foreach (KeyValuePair pair in deployCountsByHeroId) { payload.entries.Add(new AllyHeroDeployEntry { heroId = pair.Key, deployCount = Mathf.Max(0, pair.Value) }); } return payload; } private static void MarkDirty(AllyHero_SO hero) { #if UNITY_EDITOR if (hero != null) { EditorUtility.SetDirty(hero); } #endif } }