188 lines
5.3 KiB
C#

using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public class StatRegistry : MonoBehaviour
{
[Header("Auto-Discovery Settings")]
[SerializeField] private string statDefinitionsResourcesPath = "StatDefinitions";
[SerializeField] private bool autoRefreshInEditor = true;
[Header("Loaded Stats (Read-Only)")]
[SerializeField] private StatDefinition[] allStats = new StatDefinition[0];
// Singleton instance
private static StatRegistry _instance;
public static StatRegistry Instance
{
get
{
if (_instance == null)
{
_instance = FindObjectOfType<StatRegistry>();
if (_instance == null)
{
GameObject registryGO = new GameObject("StatRegistry");
_instance = registryGO.AddComponent<StatRegistry>();
DontDestroyOnLoad(registryGO);
}
}
return _instance;
}
}
// Dictionary for fast lookups
private Dictionary<string, StatDefinition> statLookup;
private bool isInitialized = false;
private void Awake()
{
// Singleton enforcement
if (_instance != null && _instance != this)
{
Destroy(gameObject);
return;
}
_instance = this;
DontDestroyOnLoad(gameObject);
Initialize();
}
[ContextMenu("Refresh Stat Definitions")]
public void RefreshStatDefinitions()
{
LoadAllStatDefinitions();
BuildLookupDictionary();
Debug.Log($"StatRegistry: Loaded {allStats.Length} stat definitions from Resources/{statDefinitionsResourcesPath}");
}
private void Initialize()
{
if (isInitialized) return;
RefreshStatDefinitions();
isInitialized = true;
}
private void LoadAllStatDefinitions()
{
// Load all StatDefinition assets from the specified Resources folder
StatDefinition[] loadedStats = Resources.LoadAll<StatDefinition>(statDefinitionsResourcesPath);
// Validate for duplicate keys
var duplicateKeys = loadedStats
.GroupBy(stat => stat.StatKey)
.Where(g => g.Count() > 1)
.Select(g => g.Key);
if (duplicateKeys.Any())
{
Debug.LogError($"StatRegistry: Duplicate stat keys found: {string.Join(", ", duplicateKeys)}");
}
// Filter out any with empty keys
allStats = loadedStats
.Where(stat => !string.IsNullOrEmpty(stat.StatKey))
.ToArray();
// Sort alphabetically for consistent ordering
System.Array.Sort(allStats, (a, b) => string.Compare(a.StatKey, b.StatKey, System.StringComparison.OrdinalIgnoreCase));
}
private void BuildLookupDictionary()
{
statLookup = new Dictionary<string, StatDefinition>();
foreach (var stat in allStats)
{
if (!statLookup.ContainsKey(stat.StatKey))
{
statLookup[stat.StatKey] = stat;
}
else
{
Debug.LogWarning($"StatRegistry: Duplicate stat key '{stat.StatKey}' ignored for asset '{stat.name}'");
}
}
}
// Public API methods
public StatDefinition GetStat(string statKey)
{
if (!isInitialized) Initialize();
return statLookup.TryGetValue(statKey, out StatDefinition stat) ? stat : null;
}
public StatDefinition[] GetAllStats()
{
if (!isInitialized) Initialize();
return allStats;
}
public StatDefinition[] GetStatsByCategory(StatCategory category)
{
if (!isInitialized) Initialize();
return allStats.Where(stat => stat.Category == category).ToArray();
}
public StatDefinition[] GetItemRollableStats()
{
if (!isInitialized) Initialize();
return allStats.Where(stat => stat.CanRollOnItems).ToArray();
}
public StatDefinition[] GetPrimaryStats()
{
if (!isInitialized) Initialize();
return allStats.Where(stat => stat.IsPrimary).ToArray();
}
public StatDefinition[] GetUIVisibleStats()
{
if (!isInitialized) Initialize();
return allStats.Where(stat => stat.ShowInUI).ToArray();
}
public bool HasStat(string statKey)
{
if (!isInitialized) Initialize();
return statLookup.ContainsKey(statKey);
}
public int GetStatCount()
{
if (!isInitialized) Initialize();
return allStats.Length;
}
// Debug/Editor methods
public void LogAllStats()
{
if (!isInitialized) Initialize();
Debug.Log($"=== StatRegistry Contents ({allStats.Length} stats) ===");
foreach (var category in System.Enum.GetValues(typeof(StatCategory)).Cast<StatCategory>())
{
var statsInCategory = GetStatsByCategory(category);
if (statsInCategory.Length > 0)
{
Debug.Log($"{category}: {string.Join(", ", statsInCategory.Select(s => s.StatKey))}");
}
}
}
#if UNITY_EDITOR
private void OnValidate()
{
// Auto-refresh in editor when settings change
if (autoRefreshInEditor && Application.isPlaying)
{
RefreshStatDefinitions();
}
}
#endif
}