EerieVillage/Assets/Scripts/Skills/Runtime/SkillRuntimeFactory.cs

160 lines
6.1 KiB
C#

using System.Collections.Generic;
using UnityEngine;
namespace EerieVillage.Skills
{
/// <summary>
/// SkillDataAsset 캐시 로드 + ISkillRuntime 인스턴스 생성 팩토리.
/// BT12-Dev v1 §3-3 정합.
/// - Resolve(cardId): Resources/Skills/ 에서 CardId 기준 조회
/// - Create(data): 타입 분기 후 런타임 인스턴스 반환
/// Phase 2-C에서 .asset 60종 추가 시 자동 적재.
/// </summary>
public static class SkillRuntimeFactory
{
private static Dictionary<string, SkillDataAsset> _cache;
/// <summary>
/// Resources/Skills/ 하위 SkillDataAsset 전체 캐시 적재.
/// 최초 Resolve 호출 시 자동 실행.
/// Phase 2-C .asset 추가 전까지 _cache.Count == 0 정상 상태.
/// </summary>
public static void EnsureLoaded()
{
if (_cache != null) return;
_cache = new Dictionary<string, SkillDataAsset>();
var assets = Resources.LoadAll<SkillDataAsset>("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}종 캐시 적재 완료.");
}
/// <summary>
/// cardId로 SkillDataAsset 조회. 없으면 null 반환.
/// </summary>
public static SkillDataAsset Resolve(string cardId)
{
EnsureLoaded();
if (string.IsNullOrEmpty(cardId)) return null;
return _cache.TryGetValue(cardId, out var data) ? data : null;
}
/// <summary>
/// SkillDataAsset 타입 분기 후 ISkillRuntime 인스턴스 생성.
/// BT12-Dev v1 §3-3 Factory 패턴.
/// </summary>
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
};
}
/// <summary>
/// PD 지시 2026-05-13 — 레벨업 카드 풀 영역 완성·구현 5종만 한정.
/// A02 파이어볼·A13 저주 구체·A04 번개 충격·A05 좌/우 베기·A_Laser 용염 레이저.
/// 미완성 placeholder (A01·A03·A08·A14·A15) 영역 카드 풀 제외.
/// </summary>
static readonly HashSet<string> AvailableCardIds = new HashSet<string>
{
"A02", "A13", "A04", "A05", "A_Laser",
// PD 지시 2026-05-13 Phase A — A08 저주의 화살·A12 정화의 빛 신규 추가
"A08", "A12"
};
/// <summary>
/// 레벨업 시 카드 3장 무작위 추출. Active 카테고리만. Phase 2-D 영역 BT12-MVP-A 통합.
/// PD 지시 2026-05-13 — AvailableCardIds 화이트리스트 필터 영역.
/// </summary>
public static List<ActiveSkillData> RandomDraw3()
{
EnsureLoaded();
var actives = new List<ActiveSkillData>();
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<ActiveSkillData>();
// 무작위 3장 (중복 X)
var pool = new List<ActiveSkillData>(actives);
var result = new List<ActiveSkillData>();
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;
}
/// <summary>캐시 강제 리셋 (에디터 툴·테스트용)</summary>
public static void InvalidateCache()
{
_cache = null;
}
}
// -------------------------------------------------------------------------
// Phase 2 범위 외 stub 구현체
// PassiveSkillRuntime·AwakeningSkillRuntime은 Phase 2-C 이후 정식 구현 예정.
// -------------------------------------------------------------------------
/// <summary>
/// 패시브 스킬 런타임 stub. Phase 2-C에서 정식 구현으로 교체 예정.
/// </summary>
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) { }
}
/// <summary>
/// 각성 스킬 런타임 stub. Phase 2-E에서 정식 구현으로 교체 예정.
/// </summary>
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) { }
}
}