PIE 멀티 환경에서 재화 드랍 시스템을 빠르게 테스트할 수 있는 콘솔 치트명령 구현
NSRunGameMode에 UFUNCTION(Exec) 함수를 만들고 콘솔(~)에서 호출해도 아무일도 일어나지 않음, 기존 로그만 출력되는 현상
언리얼 콘솔 Exec 명령의 라우팅체인은
LocalPlayer -> PlayerController -> Pawn -> HUD -> PlayerCameraManager -> PlayerInput -> CheatManager -> GameInstance
콘솔(~) Exec 명령은 GameMode로 라우팅되지 않는다는 사실, GameMode는 이 체인에 없음 그래서 Debug_SpawnCurrency를 쳐도 함수 자체가 호출되지 않는문제였다.
CheatManager쪽으로 가기로 했다. 추후에 다른 테스트 할때도 사용할 수 있지 않을까해서
그래서 CheatManager에서 Exec함수를 정의, NSPlayerController 생성자에서 CheatClass = UNSCheatManager::StaticClass()로 등록
호스트 콘솔에서는 Debug_SpawnCurrency가 정상 실행 되지만, 클라 콘솔에서는 명령 자체를 인식 못함.
UCheatManager는 엔진 기본 동작상 서버/스탠드얼론에서만 생성됨 (APlayerController::AddCheats가 NetMode != NM_Client 조건으로 가드됨), 순수 클라 PlayerController에는 CheatManager가 아예 생성되지 않아서 Exec 명령을 인식하지 못했음
NSPlayerController::BeginPlay에서 로컬 컨트롤러인 경우 EnabledCheats()를 명시적으로 호출, 이 함수가 내부적으로 AddCheats(true)를 실행하여 클라에도 CheatManager를 강제 생성
void ANSPlayerController::BeginPlay()
{
...
// 테스트용 임시 코드 - 드롭 테이블 연동 후 삭제
EnableCheats();
...
}
CheatManager가 클라에서도 인식된 뒤, 클라 콘솔에서 Debug_SpawnCurrency를 실행하면 호스트 캐릭터위치에 재화가 생성되지 않음, 클라 캐릭터 위치에만 생성됨
RegisterDrop은 HasServerAuthority()가드가 있어 서버 권한에서만 실행됨. CheatManager는 클라 로컬에서 동작하므로 클라의 GetPlayerControllerIterator()는 로컬 컨트롤러만 보고, 드랍도 서버에 반영되지 않았음
CheatManager에서 드랍 로직을 직접 실행하지 않고, ServerRPC를 통해 반드시 서버 권한에서 실행되도록 설계
클라 콘솔 입력
-> UNSCheatManager::Debug_SpawnCurrency() (클라 로컬)
-> ANSPlayerController::Server_DebugSpawnCurrency() (Server RPC -> 서버로 전송)
-> 서버에서 모든 PlayerController순회 -> RegisterDrop
-> 각 CurrencyReplicationProxy -> Client RPC -> 각 클라에서 LocalPickup 스폰
Debug_SpawnCurrency 하나로 셋 다 드랍했더니 임시재화만 메시가 보이고, 공통/스킬은 줍기 로그는 떠도 메시가 안 보임
치트가 셋 다 Grade1로 등록했는데, UNSCurrencyVisualData의 행 조회(FindVisual)는 CurrencyType + Grade 둘 다 일치해야 함. 설계상 임시재화만 등급(Grade1~)을 쓰고 공통/스킬은 Grade::None 이라, FindVisual(Common, Grade1)은 매칭 행이 없어 nullptr → 메시 미설정
치트를 타입별로 분리(Debug_SpawnTemp / Debug_SpawnCommon / Debug_SpawnSkill)하고, 공통/스킬은 ENSCurrencyGrade::None으로 등록. → VisualData 조회 키와 일치
임시재화는 복제되는 Wallet에 들어가 HUD에 실시간 반영되지만, 공통/스킬재화는 서버 전용 PendingPermanent TMap에만 쌓여 클라가 볼 수 없음
AddRunPermanent에서 Pending 누적 + AddToWallet로 복제 경로에도 미러. 진실 원본은 Pending 유지. 커밋 로직 무변경커밋 = 런 종료(게임오버) 시점이라, A의 단점이던 "커밋 후 Wallet 정리"가 무의미해짐(어차피 런 경계에서 리셋/파괴). Pending·Wallet은 같은 함수에서 같은 양을 더하므로 드리프트 불가, 진실 원본(Pending)을 안 건드리는 게 가장 좋아보였음
Seamless Travel구조라서 PlayerState가 무조건 초기화된다는 보장이없어서 지갑을 추가적으로 초기화해주는 함수를 만들었다.
[호스트/클라 콘솔] Debug_SpawnCurrency
→ UNSCheatManager::Debug_SpawnCurrency()
→ ANSPlayerController::Server_DebugSpawnCurrency() ← Server RPC
→ UNSCurrencyDropSubsystem::RegisterDrop() × N명 (서버)
→ ANSCurrencyReplicationProxy::SendSpawnEvent() × N명
→ Client_SpawnCurrency() × N명 ← Client RPC
→ ANSLocalCurrencyPickup 각자 로컬 스폰
관련 파일:
| 파일 | 역할 |
|---|---|
Core/Cheat/NSCheatManager.h/.cpp | Exec 치트 정의 |
Core/PlayerController/NSPlayerController.h/.cpp | CheatClass 등록, Server RPC 구현, EnableCheats |
System/Subsystem/NSCurrencyDropSubsystem.cpp | RegisterDrop (서버 권한 전용) |
Progression/Currency/NSCurrencyReplicationProxy.cpp | Client RPC로 각 클라에 이벤트 전달 |
Progression/Currency/NSLocalCurrencyPickup.cpp | 클라 로컬 픽업 액터 |
Core/Cheat/NSCheatManager.h/.cpp — 전체NSPlayerController — Server_DebugSpawnCurrency 선언/구현, EnableCheats() 호출, 관련 인클루드NSPlayerController::BeginPlay — EnableCheats() 한 줄UNSCurrencyDropSubsystem: 서버 전용 드랍 레지스트리ANSCurrencyReplicationProxy: 플레이어당 1개, owner-only 복제로 Wallet 변경 전달ANSLocalCurrencyPickup: 클라 로컬 비주얼 액터 (서버 비존재)UNSCurrencyWalletComponent: FastArraySerializer 기반 지갑 (키: FGameplayTag)PlayerState ServerRPC: 오버랩 시 서버 Wallet 적립CommitRunPermanent(Multiplier) (클리어 1.0 / 전멸 0.5)ProgressComponent에 영구 재화 저장 및 HUD 연동GameMode에 Proxy 세팅 연결UNSCheatManager 추가 (재화 강제 지급 콘솔 커맨드)ProjectileManagerComponent + ReplicationProxy + ProjectileVisual) 패턴을 그대로 미러링한 구조UNSCurrencyDropTable)는 별도 담당자 작업 예정OpenRunEndVote 경로)은 아직 미연결 — 허브 복귀 확정 시점에 연결 필요