| # | 무엇을 | 왜 |
|---|---|---|
| 1 | IMC 전환 방식 → C++ 패널 체크로 교체 | 증강창 열려도 이동/스킬 막히지 않게 |
| 2 | 증강 대기열(큐) 시스템 추가 | 증강 여러 개 쌓아두고 순서대로 처리 |
| 3 | Tab = 패널 토글, P = 디버그 적재 | 획득 시 자동 오픈 + 수동 열기/닫기 |
| 4 | 위젯 구조 개편 | 보유 아이콘 상시 표시 + 카드 영역 분리 |
| 5 | MaxStack 도달 시 카드 후보 제외 | 꽉 찬 증강은 더 이상 안 뜨게 |
| 6 | 보유 아이콘 SizeBox 적용 | 텍스처 크기와 무관하게 일정 크기 표시 |
증강창이 열리면 IMC_Augment 하나로 교체 → 게임플레이 IMC가 제거되어 이동·스킬이 막힘.
게임플레이 IMC는 항상 살아있고, 1/2/3/T 키 입력이 오면 C++에서 패널 열림 여부만 확인:
1/2/3/T 키 누름
→ Input_AugmentAction 호출
→ 패널 열려있음? NO → 그냥 무시 (게임플레이 계속)
→ 패널 열려있음? YES → 카드 선택 / 리롤 처리
IMC_Augment에 있던 1/2/3/T 매핑을 게임플레이 IMC로 이동IMC_Augment 에셋 삭제 가능NSInputBinderComponent.h/.cpp — EnterAugmentInputMode, ExitAugmentInputMode, CachedInputModeTagsBeforeAugment 삭제. Input_AugmentAction에 패널 체크 한 줄 추가.RequestOffer(PoolTag) 하나로 즉시 추첨·표시. 쌓아두는 개념 없었음.
서버에 TArray<FGameplayTag> PoolQueue (FIFO 큐)를 두고, 획득 이벤트마다 큐에 쌓음. 선택하면 하나씩 소비.
엘리트/레벨업/보물상자 → EnqueueOffer(풀태그)
→ 큐에 추가, 카운트++
→ 클라이언트 패널 자동 오픈
→ 아직 표시 중인 카드 없으면 즉시 추첨·표시
카드 선택 → Server_Choose(인덱스)
→ 증강 적용
→ 큐에서 front 제거, 카운트--
→ 큐에 남은 것 있으면 → 다음 카드 자동 표시
→ 큐 비었으면 → 카드 영역만 닫기 (패널은 유지)
bFrontRolled한 번 추첨된 카드는 재오픈해도 같은 카드가 표시됨 (무료 리롤 방지). 리롤(T키)을 눌러야만 새로 추첨.
PendingCount (대기 개수)는 오너 클라이언트에게만 레플리케이션 → UI 뱃지 갱신에 사용.
리슨서버 호스트는 OnRep가 안 불리므로 서버에서 직접 Broadcast.
| 함수 | 누가 호출 | 역할 |
|---|---|---|
EnqueueOffer(PoolTag) | 서버 트리거 (레벨업/엘리트 등) | 큐에 적재 + 자동 오픈 |
Server_EnqueueOffer | 클라이언트 트리거 (보물상자) | 서버에 적재 요청 |
Server_OpenPanel | Tab으로 열 때 | front 오퍼 표시 요청 |
Server_RerollCard | 리롤 키(T) | 강제 재추첨 |
Server_Choose(Index) | 카드 키(1/2/3) | 증강 적용 + 큐 소비 |
RequestOffer(PoolTag) → EnqueueOffer로 대체Server_RequestOffer → Server_EnqueueOffer로 대체NSAugmentSelectionComponent.h/.cppToggleAugmentationPanel() — 패널이 열려있으면 닫고, 닫혀있으면 열기.
열 때: UI 표시 + Server_OpenPanel 호출 (대기 카드 있으면 표시).
Debug_EnqueueAugmentOffer() — Normal 풀 증강 하나를 큐에 적재. 런 데이터가 없으면 자동 로드 후 적재.
실제 게임에서는 엘리트 처치/레벨업 이벤트가 EnqueueOffer를 직접 호출하게 됨.
NSPlayerController.h/.cpp — OpenAugmentationSelection/OnTestRunDataReady(기존 테스트 코드) 교체패널 열림 = 카드 표시. 닫힘 = 전부 숨김. 보유 아이콘 없음.
[NSAugmentationWidget] — Tab으로 열고 닫는 전체 패널
├─ OwnedAugmentWrapBox ← 패널 열린 동안 항상 표시 (보유 증강 아이콘들)
├─ PendingCountText ← 대기 카운트 뱃지 ("2" 등)
└─ CardSectionRoot ← 대기 > 0일 때만 표시
└─ ChoiceRootCanvas ← 카드 3장
Tab 또는 자동 오픈
→ UIManager::OpenAugmentationPanel()
→ HUDWidget::OpenAugmentationPanel()
→ NSAugmentationWidget::OpenPanel()
→ Visible, 보유 아이콘 갱신
카드 선택 완료 or 대기 0개
→ Client_CloseOffer → HandleOfferClosed
→ HideCardSection() (카드만 숨김, 패널은 유지)
Tab으로 닫기
→ UIManager::CloseAugmentationPanel()
→ NSAugmentationWidget::ClosePanel()
→ Collapsed (패널 전체 숨김)
| C++ 변수명 | BP 위젯 타입 | 역할 |
|---|---|---|
CardSectionRoot | 아무 컨테이너 (SizeBox 등) | 카드 영역 표시/숨김 토글 |
OwnedAugmentWrapBox | WrapBox | 보유 증강 아이콘들 |
PendingCountText | CommonText | 대기 카운트 뱃지 |
BindWidgetOptional— BP에 없어도 빌드/실행 됨. 없으면 해당 기능만 비활성.
| 함수 | 역할 |
|---|---|
OpenAugmentationPanel() | 패널 열기 (중복 호출 방지 포함) |
CloseAugmentationPanel() | 패널 닫기 |
IsAugmentationPanelOpen() | 패널 열림 여부 반환 (InputBinder 게이팅용) |
NSAugmentationWidget.h/.cppNSHUDWidget.h/.cppNSUIManagerSubsystem.h/.cpp보유 증강의 스택 수 (Inst.Stacks)가 Definition의 MaxStack에 도달하면, 이후 카드 추첨 시 그 증강이 후보에서 제외됨.
NSAugmentDefinition의 MaxStack 기본값 = 5
에디터에서 각 DA(Data Asset) → Meta 카테고리 → MaxStack으로 증강별 조정 가능.
주의: 기존에 만들어진 DA는 저장된 값(기본 1)을 그대로 가지고 있음.
DA 열어서 MaxStack이 1이면 한 번 선택 후 바로 사라지는 게 정상.
에디터에서 직접 5로 바꿔야 함.
NSAugmentDefinition.h — MaxStack 기본값 1 → 5NSAugmentSelectionComponent.cpp — CollectInventoryFilter에 스택 풀 수집, BuildRarityBuckets에 필터 적용SetBrushFromTexture만 하면 텍스처 원본 픽셀 크기로 표시 → 아이콘마다 크기 제각각.
각 아이콘을 SizeBox로 감싸서 OwnedIconSize(기본 48×48)로 고정.
WrapBox
└─ SizeBox (48×48 고정)
└─ Image (텍스처)
에디터에서 WBP_AugmentationWidget → Details → UI → OwnedIconSize로 크기 조정 가능.
NSAugmentationWidget.h — OwnedIconSize UPROPERTY 추가, USizeBox forward decl 추가NSAugmentationWidget.cpp — OnOwnedIconsLoaded에서 SizeBox 동적 생성RollAndPresent 제거기존에 PresentFront(일반 표시)와 RollAndPresent(리롤용 강제 재추첨) 두 함수가 따로 있었음.
→ PresentFront(bool bReroll = false) 하나로 통합.
bReroll = false (기본): 미추첨이면 추첨, 이미 추첨됐으면 캐시 재전송bReroll = true: 무조건 새로 추첨 (리롤 시 호출)CurrentOfferRarity 멤버 삭제쓰기만 하고 읽는 곳이 없던 죽은 상태. 제거.
[획득 이벤트 발생] (엘리트 처치 / 레벨업 / P키 디버그)
↓
EnqueueOffer(PoolTag) [서버]
↓
PoolQueue에 추가, PendingCount++
↓
Client_AutoOpenPanel → 패널 UI 열림
↓
PresentFront() → 카드 3장 추첨 → Client_PresentOffer
↓
HandleOfferPresented → 카드 위젯 생성 + 아이콘 비동기 로드
↓
[플레이어가 1/2/3 눌러서 선택]
↓
Input_AugmentAction → 패널 열림? → Server_Choose(Index)
↓
ApplyAugment → 보유 목록에 추가
↓
큐에 남은 것 있으면 → 다음 카드 자동 표시
큐 비었으면 → 카드 영역 숨김 (패널은 유지, 보유 아이콘만 표시)
공식문서를 읽어보면 TQueue의 용도는 lock-free linked list기반이라고 되어있는데 말그대로 멀티스레드 환경에서 안정적으로 사용할 수 있다고 한다. 하지만 우리는 게임스레드에서만 호출하므로 별로 필요가 없고, 오히려 크기에 접근을 해야하는데 큐의 특성상 크기를 반환하는 메서드가 없으므로 TArray를 큐처럼 쓰는게 낫지않을까 싶었다.