refactor: FBX 애니메이션 클립 독립 .anim 추출 및 자동 등록 시스템 구축

- FBX 내장 AnimationClip을 개별 .anim 파일로 추출하는 에디터 툴 추가 (AnimationClipExtractor)
  - 스킬/보스/AnimatorController에서 참조 중인 클립만 선택적 추출
  - 추출 후 모든 참조(SkillData, BossPhaseData, AnimatorController)를 .anim으로 자동 relink
  - 추출 완료된 FBX 자동 삭제 (참조 안전성 검증 포함)
- SkillController: registeredClips를 OnValidate에서 _Player_ 이름 기반 자동 등록
- PlayerSkillInput: skillSlots를 OnValidate에서 _Skill_Player_ 이름 기반 자동 등록
- 38개 FBX 삭제, 40+개 .anim 파일로 교체 완료
This commit is contained in:
2026-04-02 11:01:50 +09:00
parent affb241e85
commit bd99283f17
172 changed files with 2243595 additions and 195561 deletions

View File

@@ -1,9 +1,16 @@
using UnityEngine;
using System;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using Unity.Netcode;
using Colosseum.Abnormalities;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace Colosseum.Skills
{
/// <summary>
@@ -38,7 +45,7 @@ namespace Colosseum.Skills
[SerializeField] private AnimationClip baseSkillClip;
[Header("네트워크 동기화")]
[Tooltip("이 SkillController가 사용하는 모든 스킬/엔드 클립 (순서대로 인덱스 부여). 서버→클라이언트 클립 동기화에 사용됩니다.")]
[Tooltip("\"_Player_\" 이름이 포함된 클립이 자동 등록됩니다. 서버→클라이언트 클립 동기화에 사용됩니다.")]
[SerializeField] private List<AnimationClip> registeredClips = new();
[Header("설정")]
@@ -100,6 +107,59 @@ namespace Colosseum.Skills
}
}
#if UNITY_EDITOR
private void OnValidate()
{
AutoRegisterPlayerClips();
}
/// <summary>
/// "_Player_"가 포함된 모든 AnimationClip을 registeredClips에 자동 등록합니다.
/// 서버→클라이언트 클립 동기화 인덱스의 일관성을 위해 이름순으로 정렬합니다.
/// </summary>
private void AutoRegisterPlayerClips()
{
string[] guids = AssetDatabase.FindAssets("t:AnimationClip", new[] { "Assets/_Game/Animations" });
var clips = new List<AnimationClip>();
foreach (string guid in guids)
{
string path = AssetDatabase.GUIDToAssetPath(guid);
string clipName = Path.GetFileNameWithoutExtension(path);
if (clipName.IndexOf("_Player_", StringComparison.OrdinalIgnoreCase) >= 0)
{
AnimationClip clip = AssetDatabase.LoadAssetAtPath<AnimationClip>(path);
if (clip != null)
clips.Add(clip);
}
}
clips.Sort((a, b) => string.Compare(a.name, b.name, StringComparison.Ordinal));
// 변경이 있는 경우만 갱신 (무한 루프 방지)
bool changed = registeredClips.Count != clips.Count;
if (!changed)
{
for (int i = 0; i < clips.Count; i++)
{
if (registeredClips[i] != clips[i])
{
changed = true;
break;
}
}
}
if (changed)
{
registeredClips.Clear();
registeredClips.AddRange(clips);
Debug.Log($"[SkillController] 자동 등록: {clips.Count}개 Player 클립", this);
}
}
#endif
private void Update()
{