#!/bin/bash # Pre-commit hook: Unity 에셋 네이밍 컨벤션 검사 # 검사 대상: Assets/_Game/ 하위에 새로 추가(A)되거나 이름 변경(R)된 파일 # 제외: .meta 파일, Scripts/ ERRORS=() STAGED_FILES=$(git diff --cached --name-only --diff-filter=AR \ | grep "^Assets/_Game/" \ | grep -v "\.meta$" \ | grep -v "^Assets/_Game/Scripts/" \ | grep -v "Human-Custom" \ | grep -E "\.(asset|prefab|controller|fbx)$") for FILE in $STAGED_FILES; do FILENAME=$(basename "$FILE") NAME="${FILENAME%.*}" # 확장자 제거 DIR=$(dirname "$FILE") VALID=true EXPECTED="" case "$DIR" in Assets/_Game/Data/Passives/Nodes*) EXPECTED="Data_PassiveNode_{대상}_{이름} 예) Data_PassiveNode_Player_Tank_Core" echo "$NAME" | grep -qE "^Data_PassiveNode_(Player|Boss|Enemy|Common|[A-Za-z]+)_.+$" || VALID=false ;; Assets/_Game/Data/Passives/Presets*) EXPECTED="Data_PassivePreset_{대상}_{이름} 예) Data_PassivePreset_Player_Tank" echo "$NAME" | grep -qE "^Data_PassivePreset_(Player|Boss|Enemy|Common|[A-Za-z]+)_.+$" || VALID=false ;; Assets/_Game/Data/Passives*) EXPECTED="Data_PassiveTree_{대상}_{이름} / Data_PassiveCatalog_{대상}_{이름} / Data_PassivePrototypeCatalog 예) Data_PassiveTree_Player_Prototype" echo "$NAME" | grep -qE "^Data_Passive(Tree|Catalog)_(Player|Boss|Enemy|Common|[A-Za-z]+)_.+$|^Data_PassivePrototypeCatalog$" || VALID=false ;; Assets/_Game/Data/Skills/Effects*) EXPECTED="Data_SkillEffect_{대상}_{스킬명}_{순서}_{효과} 예) Data_SkillEffect_Player_베기_0_데미지" echo "$NAME" | grep -qE "^Data_SkillEffect_(Player|Boss|Enemy|Common|[A-Za-z]+)_.+_[0-9]+_.+$" || VALID=false ;; Assets/_Game/Data/Skills*) EXPECTED="Data_Skill_{대상}_{이름} 예) Data_Skill_Player_근접베기" echo "$NAME" | grep -qE "^Data_Skill_(Player|Boss|Enemy|Common|[A-Za-z]+)_.+$" || VALID=false ;; Assets/_Game/Data/Abnormalities*) EXPECTED="Data_Abnormality_{대상}_{이름} 예) Data_Abnormality_Test_버프" echo "$NAME" | grep -qE "^Data_Abnormality_.+_.+$" || VALID=false ;; Assets/_Game/Data/Weapons*) EXPECTED="Data_Weapon_{이름} 예) Data_Weapon_검" echo "$NAME" | grep -qE "^Data_Weapon_.+$" || VALID=false ;; Assets/_Game/Data/Enemies*) EXPECTED="Data_Enemy_{이름} 예) Data_Enemy_TestBoss" echo "$NAME" | grep -qE "^Data_Enemy_.+$" || VALID=false ;; Assets/_Game/Data/Patterns*) EXPECTED="Data_Pattern_{대상}_{이름} 예) Data_Pattern_TestBoss_우수2연타" echo "$NAME" | grep -qE "^Data_Pattern_.+_.+$" || VALID=false ;; Assets/_Game/Prefabs/UI*) EXPECTED="UI_{이름} 예) UI_BossHealthBar" echo "$NAME" | grep -qE "^UI_.+$" || VALID=false ;; Assets/_Game/Prefabs*) EXPECTED="Prefab_{대상}_{이름} 예) Prefab_Player_Default" echo "$NAME" | grep -qE "^Prefab_(Player|Boss|Enemy|Weapon|Common|[A-Za-z]+)_.+$" || VALID=false ;; Assets/_Game/Animations/Controllers*) EXPECTED="AC_{대상}_{이름} 예) AC_Player_Default" echo "$NAME" | grep -qE "^AC_(Player|Boss|Enemy|Common|[A-Za-z]+)_.+$" || VALID=false ;; Assets/_Game/Animations*) if echo "$NAME" | grep -qE "^Anim_Player_"; then # 플레이어: Anim_Player_{무기타입}_{스킬이름}_{순서} # 무기타입: 한손, 양손, 활, 방패, 마법, 공용 # 순서: _{숫자} (선택) EXPECTED="Anim_Player_{무기타입}_{스킬이름}_{순서} 예) Anim_Player_한손_베기_0, Anim_Player_공용_구르기_0" echo "$NAME" | grep -qE "^Anim_Player_(한손|양손|활|방패|마법|공용)_.+_[0-9]+$" || VALID=false else # 기타: Anim_{소유자}_{이름}_{순서} # 순서: _{숫자} (선택) EXPECTED="Anim_{소유자}_{이름}_{순서} 예) Anim_Drog_평타1R_0, Anim_Common_Idle" echo "$NAME" | grep -qE "^Anim_(Player|Boss|Enemy|Common|[A-Za-z]+)_.+(_[0-9]+)?$" || VALID=false fi ;; Assets/_Game/Models*) EXPECTED="Model_{대상}_{이름} 예) Model_Player_Base" echo "$NAME" | grep -qE "^Model_(Player|Boss|Enemy|Weapon|Common|[A-Za-z]+)_.+$" || VALID=false ;; Assets/_Game/AI*) EXPECTED="BT_{이름} 예) BT_TestBoss" echo "$NAME" | grep -qE "^BT_.+$" || VALID=false ;; esac if [ "$VALID" = false ]; then ERRORS+=("$FILE\n 형식: $EXPECTED") fi done if [ ${#ERRORS[@]} -gt 0 ]; then echo "" echo "❌ 네이밍 컨벤션 위반:" for ERR in "${ERRORS[@]}"; do echo -e " ✗ $ERR" done echo "" echo "파일 이름을 수정하거나, 의도적으로 건너뛰려면 git commit --no-verify 를 사용하세요." exit 1 fi # ── Anim_ ↔ Data_Skill_ 매칭 검증 ── # Anim_{key}_{순서} 클립과 Data_Skill_{key} 애셋의 key가 일치하는지 확인합니다. MISMATCH_ERRORS=() # 스테이징된 Anim_ 클립에서 key 추출 (Anim_ 접두사 제거 후 마지막 _숫자 제거) ANIM_KEYS=() STAGED_ANIMS=$(git diff --cached --name-only --diff-filter=ACDMR \ | grep "^Assets/_Game/Animations/" \ | grep "\.anim$" \ | grep -v "\.meta$") for FILE in $STAGED_ANIMS; do FILENAME=$(basename "$FILE") NAME="${FILENAME%.*}" if echo "$NAME" | grep -qE "^Anim_"; then # Anim_ 제거 → 마지막 _숫자 제거 → key KEY=$(echo "$NAME" | sed 's/^Anim_//' | sed 's/_[0-9]\+$//') if [ -n "$KEY" ]; then ANIM_KEYS+=("$KEY") fi fi done # 스테이징된 Data_Skill_ 애셋에서 key 추출 SKILL_KEYS=() STAGED_SKILLS=$(git diff --cached --name-only --diff-filter=ACDMR \ | grep "^Assets/_Game/Data/Skills/Data_Skill_" \ | grep "\.asset$" \ | grep -v "\.meta$") for FILE in $STAGED_SKILLS; do FILENAME=$(basename "$FILE") NAME="${FILENAME%.*}" KEY=$(echo "$NAME" | sed 's/^Data_Skill_//') if [ -n "$KEY" ]; then SKILL_KEYS+=("$KEY") fi done # 매칭 검증: 스테이징된 Data_Skill_에 대응하는 Anim_ 클립이 있는지 for SKILL_KEY in "${SKILL_KEYS[@]}"; do FOUND=false # 워킹 트리(스테이징 포함)에서 매칭 클립 검색 MATCHED=$(git diff --cached --name-only --diff-filter=ACDMR \ | grep "^Assets/_Game/Animations/Anim_${SKILL_KEY}_" \ | grep "\.anim$" \ | head -1) if [ -n "$MATCHED" ]; then FOUND=true fi # 워킹 트리에서 기존 클립도 확인 if [ "$FOUND" = false ]; then MATCHED=$(find Assets/_Game/Animations -name "Anim_${SKILL_KEY}_[0-9]*.anim" 2>/dev/null | head -1) if [ -n "$MATCHED" ]; then FOUND=true fi fi if [ "$FOUND" = false ]; then MISMATCH_ERRORS+=("Data_Skill_${SKILL_KEY} 에 대응하는 Anim_${SKILL_KEY}_{순서} 클립이 없습니다") fi done # 매칭 검증: 스테이징된 Anim_ 클립에 대응하는 Data_Skill_이 있는지 for ANIM_KEY in "${ANIM_KEYS[@]}"; do FOUND=false # 워킹 트리에서 매칭 스킬 검색 MATCHED=$(find Assets/_Game/Data/Skills -name "Data_Skill_${ANIM_KEY}.asset" 2>/dev/null | head -1) if [ -n "$MATCHED" ]; then FOUND=true fi # 스테이징된 파일에서도 확인 if [ "$FOUND" = false ]; then for FILE in $STAGED_SKILLS; do FILENAME=$(basename "$FILE") NAME="${FILENAME%.*}" CHECK_KEY=$(echo "$NAME" | sed 's/^Data_Skill_//') if [ "$CHECK_KEY" = "$ANIM_KEY" ]; then FOUND=true break fi done fi if [ "$FOUND" = false ]; then MISMATCH_ERRORS+=("Anim_${ANIM_KEY} 클립에 대응하는 Data_Skill_${ANIM_KEY} 애셋이 없습니다") fi done if [ ${#MISMATCH_ERRORS[@]} -gt 0 ]; then echo "" echo "❌ Anim_ ↔ Data_Skill_ 매칭 누락:" for ERR in "${MISMATCH_ERRORS[@]}"; do echo -e " ✗ $ERR" done echo "" echo "대응하는 애셋을 생성하거나, 의도적으로 건너뛰려면 git commit --no-verify 를 사용하세요." exit 1 fi exit 0