Loading the catalog…
Loading the catalog…
[Outbreak Breaker] 코드 전체 정리, 구독 누수와 SetByCaller 갱신 버그 수정 오늘은 커밋을 13개 올렸다. 새 기능은 없고, 하루 종일 프로젝트 코드를 폴더 단위로 훑으면서 안 쓰는 코드를 걷어내고 주석을 달았다. 그런데 정리하다 보니 실제 버그가 몇 개 나왔다. 버그부터 적고, 구조를 바꾼 부분, 단순 정리 순으로 쓴다. 1. 버그와 누수 수정 스택된 GE가 옛날 SetByCaller 값을 들고 있던 문제 지뢰 둔화나 오라 디버프처럼 스택 제한 1 + 갱신 정책을 쓰는 GE가 있다. 이런 GE를 다시 적용하면 새 SetByCaller 값이 반영되지 않고 처음 값이 그대로 남았다. AOBEffectActor::ApplyEffectInternal 에서 적용 직후 UpdateActiveGameplayEffectSetByCallerMagnitudes 를 호출하도록 고쳤다. 핸들이 유효하지 않거나 대상 ASC가 없으면 바로 리턴하고, 무한 지속 + RemoveOnEndOverlap이면 핸들을 기억해 둔다. 지뢰 둔화 GE와 오라 GA BP의 독 GE, 공격 디버프 GE에 적용했다. 위젯 컨트롤러 델리게이트 정리 UOBEnemyWidgetController 는 적마다 FBoundEnemy (ASC, HP 핸들, MaxHP 핸들)를 저장하고, 해제할 때 Remove(Handle) 로 정확히 지운다. 풀링된 적이 같은 컨트롤러에 중복 등록되는 것도 막았다. 람다는 TWeakObjectPtr<AActor> 를 캡처한다. UOBHUDWidgetController 는 AddLambda 를 전부 AddUObject 핸들러( HandleHealthChanged , HandleExpChanged , HandleWeaponLevelChanged 등)로 바꿨다. 람다로는 RemoveAll(this) 가 안 돼서 정리할 방법이 없었다. 무기 6종 레벨 어트리뷰트를 GetWeaponLevelAttributes() 로 모았고, IsWeaponAvailable 기본값은 false로 바꿨다. WeaponComponent 구독 누수와 무기 스폰 실패 EndPlay 에서 캐릭터 공격력/공속 구독을 해제하지 않아서, 스테이지를 재시작할 때마다 구독이 누적되고 있었다. 해제를 추가했다. 풀에서 무기 액터를 못 가져왔을 때도 초기화 완료로 표시하던 문제가 있었다. 지금은 경고 로그를 남기고 재시도할 수 있는 상태로 둔다. 그 밖의 수정 ApplyUpgradeCard 뒤에 RefreshAllWeaponStats 가 호출되지 않아서 카드를 골라도 최종 스탯 캐시가 갱신되지 않던 걸 고쳤다. MaxWeaponLevel 상수도 만들고 OwnerActor null 체크 순서도 바로잡았다. 위치 캐싱 재시도( TryStartLocationCaching )가 동작하지 않던 문제를 고쳤다. FOBEnemySoundSet 에서 첫 호출 때 0번 사운드가 후보에서 빠지던 인덱스 버그를 고쳤다. 2. 구조를 바꾼 리팩터링 스테이지 타임라인 매니저 초기화할 때 DataTable 행 포인터를 캐싱해서, 매 틱 행 이름 배열을 복사하지 않는다. 랜덤 NavMesh 좌표 뽑기를 TryGetRandomNavLocation 으로 합쳤다. 캡슐 오프셋은 적 스폰에만 적용하고 아이템은 지면 좌표에 둔다. SpawnEnemyWave 에서 풀 조회를 루프 밖으로 뺐고, 실패 로그는 웨이브당 한 번만 찍는다. GameMode의 타이머 값은 StageSpawnDelay , StageUnloadDelay , WarmupDuration 상수로 뺐다. WarmupEffects 는 AdditionalWarmupEffects 로 이름을 바꾸고 풀링 액터의 워밍업 이펙트와 합쳐서 처리한다. DataTable Row 구조체 이름을 FOBEnemySpawnRow , FOBBGMScheduleRow , FOBItemSpawnTimeRow , FOBItemPoolRow 로 통일하고, 기존 에셋이 깨지지 않도록 DefaultEngine.ini 에 [CoreRedirects] StructRedirects 를 추가했다. 적 AI AOBEnemy::Tick 이 한 함수에 몰려 있어서 RotateTowardTarget , ChaseTarget , HoldAndTryAttack 세 개로 나눴다. 스턴이나 강제이동 중에는 AI 전체가 멈추는 건 그대로다. 공격에 성공하면 GetAttackDelay() 만큼, 실패하면 AttackRetryInterval 뒤에 다시 시도한다. AttackRange 멤버는 없애고 UOBEnemyAttributeSet::GetAttackRange() 를 쓰게 했다. 이제 공격 사거리도 GE로 바꿀 수 있다. EffectActor와 풀 이펙트 액터 정책별 적용 로직이 Instant, Duration, Infinite마다 복붙돼 있어서 ApplyEffectsForPolicy 하나로 합쳤다. 무한 지속 GE 핸들은 TWeakObjectPtr 로 보관하고, RemoveActiveEffects 를 새로 만들었다. 풀 이펙트 액터는 EndOverlap 없이 회수돼도 대상에게 GE가 남지 않도록, 회수 시점에 남은 GE를 제거하고 Target/Source 참조도 비운다. 무기 베이스는 회수할 때 SourceActor 도 초기화하고, 태그가 비어 있으면 부여하지 않도록 막았다. AbilitySystem OBMMC_XPGain 이 런타임에 RequestGameplayTag 로 태그를 찾던 걸 네이티브 태그 Data.Item.BountyXP 로 바꿨다. ASC는 UOBGameplayAbility 가 아닌 어빌리티를 지급하려 하면 경고만 찍고 건너뛴다. 입력 처리 순회에는 FScopedAbilityListLock 을 걸어서, 순회 중 어빌리티 목록이 바뀌어도 안전하게 했다. bUseStartupInput 옵션을 추가했다. GA_Weapon_Equip처럼 GameplayEvent로만 발동하는 어빌리티는 이걸 꺼서 입력 태그를 기록하지 않는다. 꺼두면 에디터에서 StartupInputTag 도 숨겨진다. ApplyOBCooldown 은 protected로 내렸다. 회피 어빌리티에는 ActorInfo null 체크를 넣었다. 누락돼 있던 네이티브 태그 선언 끝의 세미콜론도 채웠다. UI 서브시스템과 오디오/매니지먼트 JMUISubsystem 은 Deinitialize 에서 컨트롤러를 정리해서 구독이 해제되게 했다. 바인딩이 실패하면 캐시하지 않고 nullptr를 반환한다. 쓰지 않던 AttributeSet 탐색 코드는 지웠고, MakeWidgetControllerParams 는 MakeGASParams 로 이름을 바꿨다. 오디오 서브시스템은 bIsMusic = true 를 페이드인/재생 전에 세팅하게 했다. SoundMix/SoundClass 설정이 비어 있으면 경고를 찍고, BGM 타입이 없을 때는 타입 이름까지 로그에 남긴다. ManagementSubsystem은 bIsPaused 캐시를 없애고 IsGamePaused() 가 UGameplayStatics::IsGamePaused 를 직접 조회한다. 캐시와 실제 상태가 어긋날 여지를 없앴다. 오브젝트 풀 플러그인 액터를 만들고 대기 상태로 만드는 코드가 여러 군데 중복돼 있어서 SpawnPooledObject 와 ApplyInactiveState 로 통합했다. 사용 중이 아닌 오브젝트를 두 번 회수하는 걸 막는 가드, GetWorld null 가드, 파괴된 슬롯의 IsValid 판정도 넣었다. 3. 단순 정리 Actor, Component(Weapon/Upgrade/Effect), AttributeSet, Character, Enemy, Settings 헤더에서 쓰지 않는 멤버와 include, 오버라이드를 지웠다. 헤더에 있던 AttributeSet 함수 구현은 .cpp로 옮기고 역할 주석을 달았다. 예를 들어 GetEnemyAttackDelayMultiplier 는 1 / max(1 - 최종 공속 감소, 아주 작은 값) 으로 공격 간격 배율을 계산한다. FWeaponInputMapping 은 FOBWeaponInputMapping 으로 이름을 바꾸고 StructRedirects 를 추가했다. 무기 데이터 구조체에는 필드마다 주석을 달았다. 입력과 HUD 쪽은 InputAction 을 TObjectPtr 로 바꾸고, HUD에는 UI 서브시스템 조회 헬퍼와 null 체크를 넣었다. AnimNotifyState_OBGrantTag 에는 유효성 가드와 Super 호출을 추가했다. UEffectComponent는 컴포넌트 생성과 재생에서 중복되던 코드를 헬퍼 함수로 묶었다. 오늘 느낀 점 기능을 만들 때는 "일단 돌아가게" 짜느라 놓치던 것들이 폴더 단위로 다시 읽으니 한꺼번에 보였다. 특히 구독 누수와 SetByCaller 갱신 문제는 한동안 모르고 지나갈 뻔한 종류였다. 스테이지를 여러 번 재시작해야 드러나는 문제이고, 스택된 GE의 값이 안 바뀌는 건 수치가 조금 어긋나는 정도로만 보이기 때문이다. 풀링과 델리게이트를 많이 쓰는 구조라서, 앞으로는 새로 만드는 코드에도 "해제하는 쪽이 있는가"를 먼저 확인해야겠다. 다음에 할 것 StructRedirects 를 추가했으니 에디터를 열어서 이름이 바뀐 DataTable 에셋들이 정상적으로 로드되는지 확인 스택 GE의 SetByCaller 갱신이 인게임에서 제대로 반영되는지 확인 (지뢰 둔화, 오라 독/공격 디버프) 스테이지를 여러 번 재시작하면서 구독 누수가 사라졌는지 확인 그동안 미뤄둔 일시정지 메뉴 UI를 CommonUI + MVVM으로 옮기는 작업 일정 잡기
What RADAR observed and classified to build this opportunity. It is what the source published, not a verification that the offer is still active.
[Outbreak Breaker] 코드 전체 정리, 구독 누수와 SetByCaller 갱신 버그 수정. [Outbreak Breaker] 코드 전체 정리, 구독 누수와 SetByCaller 갱신 버그 수정 오늘은 커밋을 13개 올렸다. 새 기능은 없고, 하루 종일 프로젝트 코드를 폴더 단위로 훑으면서 안 쓰는 코드를 걷어내고 주석을 달았다. 그런데 정리하다 보니 실제 버그가 몇 개 나왔다. 버그부터 적고, 구조를 바꾼 부분, 단순 정리 순으로 쓴다. 1. 버그와 누수 수정 스택된 GE가 옛날 SetByCaller 값을 들고 있던 문제 지뢰 둔화나 오라 디버프처럼 스택 제한 1 + 갱신 정책을 쓰는 GE가 있다. 이런 GE를 다시 적용하면 새 SetByCaller 값이 반영되지 않고 처음 값이 그대로…
Open source