GAS 어빌리티 비용 처리 & Git LFS 대역폭 절감
1. GAS 어빌리티 비용 — "조건(gate)"과 "비용(cost)"은 다르다
강공격이 무한 발동되던 원인: CanActivateAbility가 원소 게이지 ≥1칸을 조건으로만 검사하고, 정작 소모도 비용도 없었음. 리팩토링이 게이지 소모(ConsumeOldestSlot)를 잘라냈는데 스태미너 비용을 연결하지 않아 비용이 0이 된 것.
# git으로 추적한 "끊긴 지점"
git show <refactor-commit> -- GA_HeavyAttack_Base.cpp
- const FGameplayTag ConsumedElement = Gauge->ConsumeOldestSlot(); // 슬롯 1칸 소모(원래)
- ExecuteHeavyEffect(ConsumedElement);
+ ExecuteHeavyEffect(ResolveCurrentElementTag()); // 소모 없음
❌ 조건만 있고 비용 없음 → 자원이 안 줄어 무한
return IsValid(Gauge) && Gauge->HasChargedSlot(); // 게이지 1칸이면 영구 발동
✅ 비용 = 스태미너(CostGameplayEffectClass), 게이지는 조건이 아님
// CanActivateAbility: 무기 타입만 게이트
return bIsStaff == bActivateForStaff;
// BP: CostGameplayEffectClass = GE_Cost_Stamina_100 (Instant, Stamina -100)
// → Super::CanActivateAbility 안의 CheckCost가 스태미너<100이면 발동 차단
// → ActivateAbility의 CommitAbility가 실제 -100 소모
GAS 비용 메커니즘 (Lyra 정석):
CostGameplayEffectClass= Instant GE(속성 −N). 직접 차감/체크 코드 불필요.CheckCost(=CanApplyAttributeModifiers, 속성이 0 미만 되면 false) → 발동 차단을 자동 수행.CommitAbility→ 비용 GE 적용(소모). 평타류는 Activate에서 이미 호출 중이라 BP 한 줄로 끝.
자원 시스템에서 "쓸 수 있는 조건"과 "쓰면 닳는 비용"은 별개. 조건만 걸고 비용을 안 걸면 무한이 된다. GAS에선 비용은 항상
CostGameplayEffectClass로 — 게이트(CheckCost)와 소모(CommitAbility)가 한 세트로 따라온다.
2. Git LFS — 대역폭/스토리지 모델과 캐시 선배포
UE 프로젝트의 .uasset은 LFS. 머지로 부풀어 오른 브랜치를 8명이 받으면 대역폭이 얼마나 드는지 계산함.
GitHub LFS 청구 모델 (핵심):
| 동작 | 카운트되는 quota |
|---|---|
| push(업로드) | 스토리지 (대역폭 아님) |
| pull/clone/fetch(다운로드) | 대역폭 |
델타 계산 — develop 대비 신규 LFS 객체 = 팀원이 받는 양:
git lfs ls-files -l origin/develop | awk '{print $1}' | sort -u > dev # OID 집합
git lfs ls-files -l HEAD | awk '{print $1}' | sort -u > head
comm -13 dev head > new # HEAD에만 있는 신규 OID = 다운로드 델타
→ 결과: 신규 2,819개 / 1.18 GB. 나 포함 8명 중 7명이 각각 1.18 GB 다운 = 8.25 GB 대역폭(최악치). 무료 quota는 월 10 GiB → 거의 한도에 근접.
캐시 선배포로 대역폭 우회: LFS 객체는 content-addressed(OID=sha256) → 한 머신의 캐시가 다른 머신에서 그대로 유효. .git/lfs/objects에 미리 넣어두면 pull 시 캐시 히트 → 서버 다운로드 0.
# 신규 객체만 패키징 (전체 캐시 14GB X, 델타 1.13GB O)
while read o; do d="lfs_delta/${o:0:2}/${o:2:2}"; mkdir -p "$d"; \
cp ".git/lfs/objects/${o:0:2}/${o:2:2}/$o" "$d/"; done < new
# 팀원: lfs_delta/* 를 .git/lfs/objects/ 에 병합 → 그다음 git pull
- ⚠️ 순서: 캐시 seed → pull. pull 먼저 하면 git-lfs가 서버에서 받아버림(대역폭 소모).
- push는 여전히 필요(서버 스토리지/CI/신규 clone용). 캐시 배포는 대역폭 절감 보조 수단.
- 검증: 팀원이
git lfs fsck/git lfs ls-files(객체*표시)로 완전성 확인.
LFS는 다운로드만 대역폭. 대용량 자산을 여러 명이 받을 땐, 콘텐츠 주소 기반인 LFS 캐시(
.git/lfs/objects)를 사내망/드라이브로 선배포하면 서버 대역폭 0으로 끝낼 수 있다. (단 델타만 — 전체 캐시는 14배 컸음.)
3. 데이터 드리븐 vs CDO + 데드 데이터 탐지
데드 데이터 판정 = "소비처 grep". 무기 행(FRetrieveWeaponDataRow)에 인라인 SprintAttack/JumpAttack/ParryCounter가 있었지만, 어빌리티들은 전부 별도 DataAsset(UAttackComboDefinition)에서 읽고 있었음(원소 variant까지). 무기 행 인라인 필드를 읽는 코드는 0개 → 데드.
grep -rn "\.SprintAttack\|ResolveSprintVariant" Source/ # 소비처 확인 → DataAsset만 나옴
같은 개념은 한 홈에: 스태프 강공은 DT_WeaponData(데이터), 활은 GA_BowShot CDO(어빌리티)로 같은 "투사체 발사"를 서로 다른 곳에서 설정 → 무기 행의 투사체 필드가 활에선 조용히 무시됨(오설정 유발). 둘 다 동일 SpawnConfigured를 호출하면서도 데이터 출처만 갈림.
⚠️ DataTable 주의(재확인): DT에 쓰이는 USTRUCT의 UPROPERTY를 제거하면 그 DT 애셋이 안 열릴 수 있음 → 필드는 추가만, 제거 지양. 데드 필드 정리도 "제거"는 위험 절차(에디터 닫고/리빌드/로드확인) 동반.
비교 정리
| 헷갈린 것 | A | B |
|---|---|---|
| 어빌리티 | 조건(gate) = 쓸 수 있나(CheckCost·태그) | 비용(cost) = 쓰면 닳나(CommitAbility) |
| LFS quota | 스토리지 = push/보관량 | 대역폭 = download량 |
| 무브셋 데이터 | DataAsset/DataTable(공유·다수) | CDO(어빌리티 1개에 고정) |
핵심 요약
- "조건"과 "비용"은 다르다. 조건만 걸고 소모/비용을 안 걸면 자원 무한. GAS 비용은CostGameplayEffectClass(CheckCost가 차단 + CommitAbility가 소모).
- GitHub LFS는 다운로드만 대역폭, push는 스토리지. 대용량을 N명이 받으면 N배 대역폭.
- LFS 객체는 OID 기반이라 캐시(
.git/lfs/objects) 선배포로 서버 대역폭 0 가능 — 단 델타만(전체는 14배). - 데드 데이터는 소비처 grep으로 판정. 같은 개념을 DataTable·CDO 두 군데 두면 한쪽이 조용히 무시된다.
'내일배움캠프_Unreal > TIL' 카테고리의 다른 글
| 내일배움캠프_Unreal/TIL - Day 145 (260629) (0) | 2026.06.29 |
|---|---|
| 내일배움캠프_Unreal/TIL - Day 143 (260625) (0) | 2026.06.25 |
| 내일배움캠프_Unreal/TIL - Day 140 (260622) (0) | 2026.06.22 |
| 내일배움캠프_Unreal/TIL - Day 137 (260617) (0) | 2026.06.17 |
| 내일배움캠프_Unreal/TIL - Day 135 (260615) (0) | 2026.06.15 |