feat: 스킬 레지스트리 도입으로 빌드 스킬 포함 보장 및 기본 장착 구조 개편

- SkillRegistry ScriptableObject 추가: _Skill_Player_ 에셋을 자동 수집하여 빌드 포함 보장
- PlayerSkillInput에 Registry 참조 추가 및 AutoRegisterPlayerSkills 개편
  - 슬롯 0~5는 Inspector에서 디버그용 수동 설정 가능 (AutoRegister 불개입)
  - 슬롯 6(회피)에 구르기 스킬 자동 유지
  - OnValidate 호출 순서 변경: SyncLegacySkillsToLoadoutEntries → AutoRegisterPlayerSkills
- 플레이어 프리팹에 SkillRegistry 에셋 할당 (14개 플레이어 스킬 수집됨)
- 에디터 전용 EditorAllPlayerSkills 정적 프로퍼티로 전체 스킬 목록 접근 가능
This commit is contained in:
2026-04-02 10:58:23 +09:00
parent 5c2b9ccb69
commit eadf9a7bde
6 changed files with 293 additions and 12 deletions

View File

@@ -62,8 +62,12 @@ namespace Colosseum.Player
};
#endif
[Header("Skill Registry")]
[Tooltip("모든 플레이어 스킬을 관리하는 레지스트리. 참조하면 등록된 스킬이 빌드에 자동 포함됩니다.")]
[SerializeField] private SkillRegistry skillRegistry;
[Header("Skill Slots")]
[Tooltip("각 슬롯에 등록할 스킬 데이터 (6개 + 추가 슬롯)")]
[Tooltip("각 슬롯에 등록할 스킬 데이터 (6개 + 회피 슬롯). 슬롯 0~5는 디버그용으로 Inspector에서 수동 설정합니다.")]
[SerializeField] private SkillData[] skillSlots = new SkillData[ExpectedSkillSlotCount];
[Tooltip("각 슬롯의 베이스 스킬 + 젬 조합")]
[SerializeField] private SkillLoadoutEntry[] skillLoadoutEntries = new SkillLoadoutEntry[ExpectedSkillSlotCount];
@@ -155,6 +159,7 @@ namespace Colosseum.Player
EnsureSkillSlotCapacity();
EnsureSkillLoadoutCapacity();
SyncLegacySkillsToLoadoutEntries();
AutoRegisterPlayerSkills();
}
private void OnEnable()
@@ -235,6 +240,95 @@ namespace Colosseum.Player
}
}
#if UNITY_EDITOR
/// <summary>
/// Registry에서 전체 플릴이어 스킬을 자동 수집하고,
/// 회피 슬롯(index 6)에 구르기 스킬이 없으면 자동 할당합니다.
/// 슬롯 0~5는 Inspector에서 수동 설정한 값을 유지합니다.
/// </summary>
private void AutoRegisterPlayerSkills()
{
// Registry가 할당되어 있으면 전체 스킬 자동 수집
if (skillRegistry != null)
skillRegistry.AutoCollectPlayerSkills();
// 회피 슬롯(마지막 슬롯)에 구르기 자동 할당
int evadeSlotIndex = ExpectedSkillSlotCount - 1;
SkillData evadeSkill = FindEvadeSkill();
if (evadeSkill != null && skillSlots[evadeSlotIndex] != evadeSkill)
{
skillSlots[evadeSlotIndex] = evadeSkill;
skillLoadoutEntries[evadeSlotIndex].SetBaseSkill(evadeSkill);
Debug.Log($"[PlayerSkillInput] 회피 스킬 자동 장착: {evadeSkill.SkillName}", this);
}
}
/// <summary>
/// Registry 또는 에셋 폴더에서 구르기 스킬을 찾습니다.
/// </summary>
private SkillData FindEvadeSkill()
{
// 1. Registry에서 검색
if (skillRegistry != null)
{
SkillData found = skillRegistry.FindPlayerSkillByNameContains("구르기");
if (found != null)
return found;
}
// 2. 에셋 폴더에서 직접 검색 (Registry 미할당 시 폴백)
string[] guids = AssetDatabase.FindAssets("t:SkillData", new[] { "Assets/_Game/Data/Skills" });
foreach (string guid in guids)
{
string path = AssetDatabase.GUIDToAssetPath(guid);
string assetName = Path.GetFileNameWithoutExtension(path);
if (assetName.IndexOf("구르기", StringComparison.OrdinalIgnoreCase) >= 0)
return AssetDatabase.LoadAssetAtPath<SkillData>(path);
}
Debug.LogWarning("[PlayerSkillInput] 구르기 스킬을 찾을 수 없습니다.", this);
return null;
}
/// <summary>
/// 에디터에서 접근 가능한 전체 플레이어 스킬 목록 (디버그/빌드 도구용).
/// </summary>
public static IReadOnlyList<SkillData> EditorAllPlayerSkills
{
get
{
// Registry에서 수집된 스킬이 있으면 사용
string[] guids = AssetDatabase.FindAssets("t:SkillRegistry", null);
foreach (string guid in guids)
{
string path = AssetDatabase.GUIDToAssetPath(guid);
SkillRegistry registry = AssetDatabase.LoadAssetAtPath<SkillRegistry>(path);
if (registry != null && registry.PlayerSkills.Count > 0)
return registry.PlayerSkills;
}
// Registry가 없으면 직접 수집
var skills = new List<SkillData>();
string[] skillGuids = AssetDatabase.FindAssets("t:SkillData", new[] { "Assets/_Game/Data/Skills" });
foreach (string skillGuid in skillGuids)
{
string skillPath = AssetDatabase.GUIDToAssetPath(skillGuid);
string assetName = Path.GetFileNameWithoutExtension(skillPath);
if (assetName.IndexOf("_Skill_Player_", StringComparison.OrdinalIgnoreCase) >= 0)
{
SkillData skill = AssetDatabase.LoadAssetAtPath<SkillData>(skillPath);
if (skill != null)
skills.Add(skill);
}
}
return skills;
}
}
#endif
/// <summary>
/// 기존 SkillData 직렬화와 새 로드아웃 엔트리 구조를 동기화합니다.
/// </summary>