- SkillData: skillClip/endClip 단일 필드를 animationClips 리스트로 통합
- Data_Skill_ 접두사 애셋 이름과 Anim_{key}_{순서} 클립을 자동 매칭
- 레거시 skillClip/endClip 데이터 자동 마이그레이션
- SkillController: 클립 시퀀스 내 순차 재생 로직 (TryPlayNextClipInSequence)
- baseSkillClip을 컨트롤러 Skill state에서 OnValidate로 자동 발견
- waitingForEndAnimation / IsInEndAnimation 제거
- BuildSimulationEngine: 전체 클립 duration 합산 및 모든 클립 OnEffect 이벤트 파싱
- PlayerAbnormalityVerificationRunner: GetSkillDuration 전체 클립 길이 합산으로 변경
- EnemyBase: IsInEndAnimation 참조 제거
- AnimationClipExtractor: animationClips 리스트 기반 relink/collect로 변경
- AnimationClipSkillDataMatcher: 클립 변경 시 관련 SkillData 자동 갱신 (AssetPostprocessor)
- BaseSkillClipAssigner: 모든 컨트롤러의 Skill state에 base clip 일괄 할당 에디터 메뉴
- pre-commit hook: Anim_ 네이밍 규칙에 {순서} 패턴 추가 및 Anim_↔Data_Skill_ 매칭 검증
102 lines
3.1 KiB
C#
102 lines
3.1 KiB
C#
using System;
|
|
|
|
using UnityEditor;
|
|
|
|
using Colosseum.Skills;
|
|
|
|
namespace Colosseum.Editor
|
|
{
|
|
/// <summary>
|
|
/// Animations 폴더 내 애니메이션 클립이 변경(생성/수정/삭제/이동)되면
|
|
/// 관련 SkillData의 애니메이션 클립 목록을 자동 갱신합니다.
|
|
/// </summary>
|
|
public class AnimationClipSkillDataMatcher : AssetPostprocessor
|
|
{
|
|
private const string AnimationsFolderPath = "Assets/_Game/Animations";
|
|
|
|
private static void OnPostprocessAllAssets(
|
|
string[] importedAssets,
|
|
string[] deletedAssets,
|
|
string[] movedAssets,
|
|
string[] movedFromAssetPaths)
|
|
{
|
|
bool hasAnimationChange = false;
|
|
|
|
for (int i = 0; i < importedAssets.Length; i++)
|
|
{
|
|
if (IsAnimationClipPath(importedAssets[i]))
|
|
{
|
|
hasAnimationChange = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!hasAnimationChange)
|
|
{
|
|
for (int i = 0; i < deletedAssets.Length; i++)
|
|
{
|
|
if (IsAnimationClipPath(deletedAssets[i]))
|
|
{
|
|
hasAnimationChange = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!hasAnimationChange)
|
|
{
|
|
for (int i = 0; i < movedAssets.Length; i++)
|
|
{
|
|
if (IsAnimationClipPath(movedAssets[i]) || IsAnimationClipPath(movedFromAssetPaths[i]))
|
|
{
|
|
hasAnimationChange = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!hasAnimationChange)
|
|
return;
|
|
|
|
RefreshAllSkillDataClips();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 지정한 경로가 Animations 폴더 내의 애니메이션 클립인지 확인합니다.
|
|
/// </summary>
|
|
private static bool IsAnimationClipPath(string assetPath)
|
|
{
|
|
return assetPath != null
|
|
&& assetPath.StartsWith(AnimationsFolderPath)
|
|
&& assetPath.EndsWith(".anim", StringComparison.OrdinalIgnoreCase);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 모든 SkillData의 애니메이션 클립 목록을 갱신합니다.
|
|
/// </summary>
|
|
private static void RefreshAllSkillDataClips()
|
|
{
|
|
string[] skillGuids = AssetDatabase.FindAssets("t:SkillData");
|
|
int refreshedCount = 0;
|
|
|
|
for (int i = 0; i < skillGuids.Length; i++)
|
|
{
|
|
string path = AssetDatabase.GUIDToAssetPath(skillGuids[i]);
|
|
SkillData skillData = AssetDatabase.LoadAssetAtPath<SkillData>(path);
|
|
if (skillData == null) continue;
|
|
|
|
int clipCountBefore = skillData.AnimationClips.Count;
|
|
skillData.RefreshAnimationClips();
|
|
|
|
if (skillData.AnimationClips.Count != clipCountBefore)
|
|
refreshedCount++;
|
|
}
|
|
|
|
if (refreshedCount > 0)
|
|
{
|
|
AssetDatabase.SaveAssets();
|
|
}
|
|
}
|
|
}
|
|
}
|