using System.Collections.Generic; using UnityEngine; namespace EerieVillage.Skills { /// /// SkillDataAsset 캐시 로드 + ISkillRuntime 인스턴스 생성 팩토리. /// BT12-Dev v1 §3-3 정합. /// - Resolve(cardId): Resources/Skills/ 에서 CardId 기준 조회 /// - Create(data): 타입 분기 후 런타임 인스턴스 반환 /// Phase 2-C에서 .asset 60종 추가 시 자동 적재. /// public static class SkillRuntimeFactory { private static Dictionary _cache; /// /// Resources/Skills/ 하위 SkillDataAsset 전체 캐시 적재. /// 최초 Resolve 호출 시 자동 실행. /// Phase 2-C .asset 추가 전까지 _cache.Count == 0 정상 상태. /// public static void EnsureLoaded() { if (_cache != null) return; _cache = new Dictionary(); var assets = Resources.LoadAll("Skills"); if (assets == null) return; foreach (var a in assets) { if (a != null && !string.IsNullOrEmpty(a.CardId) && !_cache.ContainsKey(a.CardId)) { _cache[a.CardId] = a; } } Debug.Log($"[SkillRuntimeFactory] SkillDataAsset {_cache.Count}종 캐시 적재 완료."); } /// /// cardId로 SkillDataAsset 조회. 없으면 null 반환. /// public static SkillDataAsset Resolve(string cardId) { EnsureLoaded(); if (string.IsNullOrEmpty(cardId)) return null; return _cache.TryGetValue(cardId, out var data) ? data : null; } /// /// SkillDataAsset 타입 분기 후 ISkillRuntime 인스턴스 생성. /// BT12-Dev v1 §3-3 Factory 패턴. /// public static ISkillRuntime Create(SkillDataAsset data) { if (data == null) return null; return data switch { ActiveSkillData a => new ActiveSkillRuntime(a), PassiveSkillData p => new PassiveSkillRuntimeStub(p), AwakeningSkillData w => new AwakeningSkillRuntimeStub(w), _ => null }; } /// /// PD 지시 2026-05-13 — 레벨업 카드 풀 영역 완성·구현 5종만 한정. /// A02 파이어볼·A13 저주 구체·A04 번개 충격·A05 좌/우 베기·A_Laser 용염 레이저. /// 미완성 placeholder (A01·A03·A08·A14·A15) 영역 카드 풀 제외. /// static readonly HashSet AvailableCardIds = new HashSet { "A02", "A13", "A04", "A05", "A_Laser", // PD 지시 2026-05-13 Phase A — A08 저주의 화살·A12 정화의 빛 신규 추가 "A08", "A12" }; /// /// 레벨업 시 카드 3장 무작위 추출. Active 카테고리만. Phase 2-D 영역 BT12-MVP-A 통합. /// PD 지시 2026-05-13 — AvailableCardIds 화이트리스트 필터 영역. /// public static List RandomDraw3() { EnsureLoaded(); var actives = new List(); foreach (var kvp in _cache) { if (kvp.Value is ActiveSkillData ad && AvailableCardIds.Contains(ad.CardId)) actives.Add(ad); } if (actives.Count == 0) return new List(); // 무작위 3장 (중복 X) var pool = new List(actives); var result = new List(); int draw = Mathf.Min(3, pool.Count); for (int i = 0; i < draw; i++) { int idx = Random.Range(0, pool.Count); result.Add(pool[idx]); pool.RemoveAt(idx); } return result; } /// 캐시 강제 리셋 (에디터 툴·테스트용) public static void InvalidateCache() { _cache = null; } } // ------------------------------------------------------------------------- // Phase 2 범위 외 stub 구현체 // PassiveSkillRuntime·AwakeningSkillRuntime은 Phase 2-C 이후 정식 구현 예정. // ------------------------------------------------------------------------- /// /// 패시브 스킬 런타임 stub. Phase 2-C에서 정식 구현으로 교체 예정. /// internal class PassiveSkillRuntimeStub : IPassiveSkill { private readonly PassiveSkillData _data; public PassiveSkillRuntimeStub(PassiveSkillData data) { _data = data; } public SkillDataAsset Data => _data; public int StackLevel => 1; public bool IsAlwaysOn => _data.IsAlwaysOn; public void OnEquip(PlayerSkillInventory inventory) { } public void OnUnequip() { } public void Upgrade() { } public void ApplyModifier(PlayerStats stats) { } public void RemoveModifier(PlayerStats stats) { } public void OnTrigger(PassiveTriggerContext ctx) { } } /// /// 각성 스킬 런타임 stub. Phase 2-E에서 정식 구현으로 교체 예정. /// internal class AwakeningSkillRuntimeStub : IAwakeningSkill { private readonly AwakeningSkillData _data; public AwakeningSkillRuntimeStub(AwakeningSkillData data) { _data = data; } public SkillDataAsset Data => _data; public int StackLevel => 1; public ActiveSkillData OriginalActive => _data.OriginalActive; public PassiveSkillData[] RequiredPassives => _data.RequiredPassives; public AwakeningPattern Pattern => _data.Pattern; public void OnEquip(PlayerSkillInventory inventory) { } public void OnUnequip() { } public void Upgrade() { } public void Awaken(PlayerSkillInventory inventory) { } } }