ProjectDDD/Assets/_DDD/_Scripts/GameFramework/Localization/SmartStringVariables.cs
2025-08-17 21:56:34 +09:00

197 lines
7.4 KiB
C#

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<SmartStringVariables>, IManager, IEventHandler<SmartVariablesDirtyEvent>
{
private Dictionary<smartStringKey, string> _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<SmartVariablesDirtyEvent>(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<SmartVariablesDirtyEvent>(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 (가비지 최소화) ----------
/// <summary>int 변수 세팅. {key} 로 접근.</summary>
public void Set(string key, int value)
{
var v = Ensure<IntVariable>(key);
if (v.Value != value) v.Value = value;
}
/// <summary>float 변수 세팅. {key} 로 접근.</summary>
public void Set(string key, float value)
{
var v = Ensure<FloatVariable>(key);
if (Mathf.Approximately(v.Value, value) == false) v.Value = value;
}
/// <summary>bool 변수 세팅. {key} 로 접근.</summary>
public void Set(string key, bool value)
{
var v = Ensure<BoolVariable>(key);
if (v.Value != value) v.Value = value;
}
/// <summary>string 변수 세팅. {key} 로 접근.</summary>
public void Set(string key, string value)
{
var v = Ensure<StringVariable>(key);
if (string.Equals(v.Value, value) == false) v.Value = value;
}
/// <summary>
/// enum은 보통 현지화 포맷에서 문자열로 취급하는 편이 직관적입니다.
/// 필요시 IntVariable로 바꾸고 (int)(object)value 저장하는 버전도 추가 가능.
/// </summary>
public void SetEnum<TEnum>(string key, TEnum value) where TEnum : struct
{
var v = Ensure<StringVariable>(key);
string s = value.ToString();
if (string.Equals(v.Value, s) == false) v.Value = s;
}
// ---------- 유틸 ----------
/// <summary>
/// key에 해당하는 변수가 있고 타입이 일치하면 캐시 반환.
/// 없거나 타입이 다르면 교체(Add/Remove)하여 보장.
/// </summary>
private T Ensure<T>(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;
}
}
}