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:
@@ -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()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user