using System; using System.Collections.Generic; using System.Threading.Tasks; using UnityEngine; using UnityEngine.Localization.SmartFormat.PersistentVariables; namespace DDD { [Flags] public enum SmartVariablesDomain : uint { None = 0u, RestaurantToday = 1u << 0, ChecklistTargets = 1u << 1, PlayerLevel = 1u << 2, All = 0xFFFFFFFFu, } public enum smartStringKey { None = 0, Day, AddedTodayFoodCount, AddedTodayCookwareCount, MatchedTodayMenuWithCookwareCount, ChecklistFoodCount, ChecklistCookwareCount, ChecklistMatchedMenuWithCookwareCount, } public class SmartStringVariables : Singleton, IManager, IEventHandler { private Dictionary _smartStringKeys = new() { {smartStringKey.Day, "day"}, {smartStringKey.AddedTodayFoodCount, "addedTodayFoodCount"}, {smartStringKey.AddedTodayCookwareCount, "addedTodayCookwareCount"}, {smartStringKey.MatchedTodayMenuWithCookwareCount, "matchedTodayMenuWithCookwareCount"}, {smartStringKey.ChecklistFoodCount, "checklistFoodCount"}, {smartStringKey.ChecklistCookwareCount, "checklistCookwareCount"}, {smartStringKey.ChecklistMatchedMenuWithCookwareCount, "checklistMatchedMenuWithCookwareCount"}, }; private void OnDestroy() { EventBus.Unregister(this); } public void PreInit() { } public async Task Init() { var gameLevelStateSo = GameStateSo.instance.GameLevelStateSo; var restaurantStateSo = RestaurantState.instance.ManagementState; // 예시: day 초기 세팅 (없으면 생성, 타입 다르면 교체) Set(_smartStringKeys[smartStringKey.Day], gameLevelStateSo.Level); Set(_smartStringKeys[smartStringKey.AddedTodayFoodCount], restaurantStateSo.AddedTodayFoodCount); Set(_smartStringKeys[smartStringKey.AddedTodayCookwareCount], restaurantStateSo.AddedTodayCookwareCount); Set(_smartStringKeys[smartStringKey.MatchedTodayMenuWithCookwareCount], restaurantStateSo.MatchedTodayMenuWithCookwareCount); Set(_smartStringKeys[smartStringKey.ChecklistFoodCount], restaurantStateSo.ChecklistFoodCount); Set(_smartStringKeys[smartStringKey.ChecklistCookwareCount], restaurantStateSo.ChecklistCookwareCount); Set(_smartStringKeys[smartStringKey.ChecklistMatchedMenuWithCookwareCount], restaurantStateSo.ChecklistMatchedMenuWithCookwareCount); await Task.CompletedTask; } public void PostInit() { // 도메인 단위 더티 이벤트를 구독하여 필요한 key만 갱신 EventBus.Register(this); } private RestaurantManagementStateSo GetRestaurantState() => RestaurantState.instance.ManagementState; public void Invoke(SmartVariablesDirtyEvent evt) { var flags = evt.DomainFlags; if (flags == SmartVariablesDomain.All) { RefreshAll(); return; } if ((flags & SmartVariablesDomain.RestaurantToday) != 0) { RefreshTodayMenuCounts(); } if ((flags & SmartVariablesDomain.ChecklistTargets) != 0) { RefreshChecklistTargets(); } if ((flags & SmartVariablesDomain.PlayerLevel) != 0) { RefreshDay(); } } public void RefreshTodayMenuCounts() { var state = GetRestaurantState(); Set(_smartStringKeys[smartStringKey.AddedTodayFoodCount], state.AddedTodayFoodCount); Set(_smartStringKeys[smartStringKey.AddedTodayCookwareCount], state.AddedTodayCookwareCount); Set(_smartStringKeys[smartStringKey.MatchedTodayMenuWithCookwareCount], state.MatchedTodayMenuWithCookwareCount); } public void RefreshChecklistTargets() { var state = GetRestaurantState(); Set(_smartStringKeys[smartStringKey.ChecklistFoodCount], state.ChecklistFoodCount); Set(_smartStringKeys[smartStringKey.ChecklistCookwareCount], state.ChecklistCookwareCount); Set(_smartStringKeys[smartStringKey.ChecklistMatchedMenuWithCookwareCount], state.ChecklistMatchedMenuWithCookwareCount); } public void RefreshDay() { var gameLevelStateSo = GameStateSo.instance.GameLevelStateSo; Set(_smartStringKeys[smartStringKey.Day], gameLevelStateSo.Level); } public void RefreshAll() { RefreshDay(); RefreshTodayMenuCounts(); RefreshChecklistTargets(); } // ---------- 공용 Set API (가비지 최소화) ---------- /// int 변수 세팅. {key} 로 접근. public void Set(string key, int value) { var v = Ensure(key); if (v.Value != value) v.Value = value; } /// float 변수 세팅. {key} 로 접근. public void Set(string key, float value) { var v = Ensure(key); if (Mathf.Approximately(v.Value, value) == false) v.Value = value; } /// bool 변수 세팅. {key} 로 접근. public void Set(string key, bool value) { var v = Ensure(key); if (v.Value != value) v.Value = value; } /// string 변수 세팅. {key} 로 접근. public void Set(string key, string value) { var v = Ensure(key); if (string.Equals(v.Value, value) == false) v.Value = value; } /// /// enum은 보통 현지화 포맷에서 문자열로 취급하는 편이 직관적입니다. /// 필요시 IntVariable로 바꾸고 (int)(object)value 저장하는 버전도 추가 가능. /// public void SetEnum(string key, TEnum value) where TEnum : struct { var v = Ensure(key); string s = value.ToString(); if (string.Equals(v.Value, s) == false) v.Value = s; } // ---------- 유틸 ---------- /// /// key에 해당하는 변수가 있고 타입이 일치하면 캐시 반환. /// 없거나 타입이 다르면 교체(Add/Remove)하여 보장. /// private T Ensure(string key) where T : class, IVariable, new() { if (string.IsNullOrWhiteSpace(key)) { Debug.LogError("SmartStringVariables.Ensure: key is null or empty."); return null; } var smartStringVariableGroup = GameDataSo.instance.GameLocalizationData.SmartStringVariableGroup; if (smartStringVariableGroup.TryGetValue(key, out var existing)) { if (existing is T hasType) return hasType; smartStringVariableGroup.Remove(key); // 타입 다르면 제거 후 교체 } var created = new T(); smartStringVariableGroup.Add(key, created); return (T)created; } } }