1. 로비 상호작용 공통: 상호작용 성공 시 로그 강화
변경 내용
AAO_LobbyInteractable::OnInteractionSuccess_BP_Implementation 에서 상호작용 흐름 전체에 로그를 촘촘하게 심었습니다.
- 공통 진입 로그 추가
AO_LOG(LogJSH, Log,
TEXT("[LobbyInteract] OnSuccess Enter | This=%s Type=%d Interactor=%s"),
*GetName(),
static_cast<int32>(InteractType),
*GetNameSafe(Interactor));
- Interactor 가 APawn 이 아닐 때, AAO_PlayerController_Lobby 를 못 찾을 때 각각 Warning 로그 추가
- 각 InteractType 분기(Ready / StartGame / InviteFriends / Wardrobe / default)에 모두 로그 추가
의도
- “로비 인터랙터를 누르면 어디까지 코드가 들어가는지” 를 한눈에 볼 수 있도록, 진입 ~ 분기 ~ RPC 호출까지 전 과정을 로깅
- 특히 패키지 게스트 환경에서 Invite/ Wardrobe 상호작용이 어디까지 도달하는지 확인하기 위해
2. Ready 상호작용: 로컬 선반영 + OnRep 공개
변경 내용
2-1. Ready 토글: 클라이언트 로컬 선반영 추가
case EAO_LobbyInteractType::Ready:
{
if (bIsHost)
{
AO_LOG(LogJSH, Log,
TEXT("[LobbyInteract] ReadyToggle: Host tried to use Ready, ignored | PC=%s"),
*GetNameSafe(PC));
return;
}
if (AAO_PlayerState* PS = PC->GetPlayerState<AAO_PlayerState>())
{
const bool bNewReady = !PS->IsLobbyReady();
// 1) 로컬 선반영
if (PC->IsLocalController())
{
AO_LOG(LogJSH, Log,
TEXT("[LobbyInteract] ReadyToggle: local predict SetLobbyReady(%d) | PC=%s"),
static_cast<int32>(bNewReady),
*GetNameSafe(PC));
PS->SetLobbyReady(bNewReady);
PS->OnRep_LobbyIsReady();
}
// 2) 실제 서버 요청
AO_LOG(LogJSH, Log,
TEXT("[LobbyInteract] ReadyToggle: call Server_SetReady(%d) | PC=%s"),
static_cast<int32>(bNewReady),
*GetNameSafe(PC));
PC->Server_SetReady(bNewReady);
}
else
{
AO_LOG(LogJSH, Warning,
TEXT("[LobbyInteract] ReadyToggle: PlayerState is null | PC=%s"),
*GetNameSafe(PC));
}
break;
}
- 기존에는 서버에서 bLobbyIsReady 를 바꾼 뒤, Replication 이 돌아오기를 기다려야 화면이 갱신됨
- 이제는 로컬 컨트롤러일 때 먼저 SetLobbyReady + OnRep_LobbyIsReady() 를 호출해서 UI를 즉시 반영
- 그 뒤에 서버에 Server_SetReady 로 “진짜 상태”를 요청
2-2. OnRep_LobbyIsReady 위치 변경
class AO_API AAO_PlayerState : public APlayerState
{
public:
// 호스트 여부 (입장 순서 0번을 호스트로 간주)
bool IsLobbyHost() const;
// 레디 상태가 복제될 때 호출
UFUNCTION()
void OnRep_LobbyIsReady();
protected:
UPROPERTY(ReplicatedUsing=OnRep_LobbyIsReady)
bool bLobbyIsReady;
...
};
- OnRep_LobbyIsReady() 선언을 protected → public 으로 끌어올려서,
로컬 예측용으로 PS->OnRep_LobbyIsReady() 를 직접 호출 가능하게 변경
의도
- Ready 버튼을 눌렀을 때 “눌렀는지 안 눌렀는지” 가 바로 보이도록, 클라이언트 화면에서 먼저 선반영
- 서버와의 최소한의 desync 를 감수하는 대신, 로비 UX를 훨씬 부드럽게 만들기 위함
- OnRep_ 을 public 으로 열어서 “UI 업데이트 로직”을 재사용 (복제/선반영 모두 같은 경로 타게)
3. Invite / Wardrobe 상호작용: 서버 경유 RPC 정리
3-1. CanInteraction 규칙 완화
case EAO_LobbyInteractType::InviteFriends:
// 모두 초대 UI 허용
return true;
- 기존: return PC->IsLocalController();
- 변경 후: 상호작용 가능 여부는 별도 로직에서 관리하고, 타입 자체는 “누구나 상호작용 가능”으로 단순화
3-2. AAO_PlayerController_Lobby RPC 재구성
서버 RPC 추가
UFUNCTION(Server, Reliable)
void Server_RequestInviteOverlay();
UFUNCTION(Server, Reliable)
void Server_RequestWardrobe();
void AAO_PlayerController_Lobby::Server_RequestInviteOverlay_Implementation()
{
AO_LOG(LogJSH, Log,
TEXT("Server_RequestInviteOverlay: Called on Server | PC=%s HasAuthority=%d IsLocal=%d"),
*GetName(),
HasAuthority() ? 1 : 0,
IsLocalController() ? 1 : 0);
Client_OpenInviteOverlay();
}
void AAO_PlayerController_Lobby::Server_RequestWardrobe_Implementation()
{
AO_LOG(LogJSH, Log,
TEXT("Server_RequestWardrobe: Called on Server | PC=%s HasAuthority=%d IsLocal=%d"),
*GetName(),
HasAuthority() ? 1 : 0,
IsLocalController() ? 1 : 0);
Client_OpenWardrobe();
}
- 상호작용은 항상 서버에서 처리하도록, 인터랙터 → 서버(PC) → 클라이언트 구조로 통일
- Wardrobe 도 패턴 동일하게 맞춰둠 (현재는 TODO 로그만 출력, 나중에 실제 UI 연결 예정)
클라이언트 RPC + 로컬 함수 분리
UFUNCTION(Client, Reliable)
void Client_OpenInviteOverlay();
UFUNCTION(Client, Reliable)
void Client_OpenWardrobe();
UFUNCTION()
void OpenInviteOverlay();
UFUNCTION()
void OpenWardrobe();
구현:
void AAO_PlayerController_Lobby::Client_OpenInviteOverlay_Implementation()
{
AO_LOG(LogJSH, Log,
TEXT("Client_OpenInviteOverlay: Called on Client | PC=%s HasAuthority=%d IsLocal=%d"),
*GetName(),
HasAuthority() ? 1 : 0,
IsLocalController() ? 1 : 0);
OpenInviteOverlay();
}
void AAO_PlayerController_Lobby::Client_OpenWardrobe_Implementation()
{
AO_LOG(LogJSH, Log,
TEXT("Client_OpenWardrobe: Called on Client | PC=%s HasAuthority=%d IsLocal=%d"),
*GetName(),
HasAuthority() ? 1 : 0,
IsLocalController() ? 1 : 0);
OpenWardrobe();
}
로컬 함수:
void AAO_PlayerController_Lobby::OpenInviteOverlay()
{
if( !IsLocalController() )
{
AO_LOG(LogJSH, Warning,
TEXT("OpenInviteOverlay: Not LocalController | PC=%s"),
*GetName());
return;
}
if( const UGameInstance* GI = GetGameInstance() )
{
if( UAO_OnlineSessionSubsystem* Sub = GI->GetSubsystem<UAO_OnlineSessionSubsystem>() )
{
AO_LOG(LogJSH, Log,
TEXT("OpenInviteOverlay: ShowInviteUI | PC=%s"),
*GetName());
Sub->ShowInviteUI();
return;
}
}
AO_LOG(LogJSH, Warning,
TEXT("OpenInviteOverlay: OnlineSessionSubsystem not found | PC=%s"),
*GetName());
}
void AAO_PlayerController_Lobby::OpenWardrobe()
{
if( !IsLocalController() )
{
AO_LOG(LogJSH, Warning,
TEXT("OpenWardrobe: Not LocalController | PC=%s"),
*GetName());
return;
}
// TODO: 실제 Wardrobe UI 열기
AO_LOG(LogJSH, Log,
TEXT("OpenWardrobe: Open wardrobe UI (TODO) | PC=%s"),
*GetName());
}
의도
- 인터랙션 → 서버 → 해당 클라 라는 기본 패턴을 Invite/Wardrobe에도 맞춰서, 나중에 권한 제어나 로직을 바꾸기 쉽게 만듦
- OpenInviteOverlay()/OpenWardrobe() 는 항상 로컬 클라에서만 UI를 열도록 IsLocalController() 체크 추가
- 게스트 패키지 환경에서 “서버까지 호출은 되는데, 어디에서 끊기는지” 를 로그로 추적 가능
4. ReadyBoard 구조체 기본값 초기화 (로그 경고 해결)
변경 내용
USTRUCT(BlueprintType)
struct FAOLobbyReadyBoardEntry
{
GENERATED_BODY()
public:
UPROPERTY(BlueprintReadWrite)
FString PlayerName = TEXT("");
UPROPERTY(BlueprintReadWrite)
bool bIsHost = false;
UPROPERTY(BlueprintReadWrite)
FString StatusLabel = TEXT("");
UPROPERTY(BlueprintReadWrite)
bool bStatusActive = false;
int32 JoinOrder = -1;
};
- BluePrintReadWrite 로 노출된 FString / bool 멤버에 직접 기본값을 부여
- 이전에 떴던 로그:
- BoolProperty FAOLobbyReadyBoardEntry::bStatusActive is not initialized properly.
를 해결하기 위한 변경
- BoolProperty FAOLobbyReadyBoardEntry::bStatusActive is not initialized properly.
의도
- USTRUCT 멤버를 Blueprint에서 생성/사용할 때, C++ 쪽 기본값이 명확하지 않으면 에디터에서 경고를 띄움
- 모든 필드에 명시적으로 초기값을 주어,
“로비에 아무도 없는 상태” 에서도 안전하게 기본 상태가 보장되도록 정리
5. 정리: 이번 변경으로 얻은 것
- 로비 인터랙션 흐름 가시성 강화
→ 어떤 상호작용이 서버/클라 어디까지 도달하는지 로그로 확인 가능 - Ready 토글 UX 개선
→ 버튼 누른 즉시 레디 아이콘/상태가 바뀌고, 서버와 동기화는 백그라운드에서 처리 - Invite / Wardrobe RPC 패턴 통일
→ 상호작용은 항상 서버를 거치고, 실제 UI 열기는 “해당 로컬 클라이언트”만 수행 - ReadyBoard 구조체 초기화 경고 제거
→ 에디터/로그에 의미 없는 경고가 사라지고, 구조체 기본 상태가 명확해짐
'언리얼 엔진 일지' 카테고리의 다른 글
| [언리얼 엔진 5.6] 전멸 판단 기반 스테이지 실패 처리 구조 구현 (0) | 2025.12.09 |
|---|---|
| [언리얼 엔진 5.6] 스테이지 연료 기반 게임 실패 처리 & 연료 인계 로직 구현 (0) | 2025.12.08 |
| [언리얼 엔진 5.6] 패키징 후 로비 상호작용에서 ‘게스트만 작동 불가’ 해결 (0) | 2025.12.04 |
| 미해결) [언리얼 엔진 5.6] 패키징 후 로비 상호작용에서 ‘게스트만 작동 불가’ 문제 분석_2 (0) | 2025.12.03 |
| 미해결) [언리얼 엔진 5.6] 패키징 후 로비 상호작용에서 ‘게스트만 작동 불가’ 문제 분석 (0) | 2025.12.02 |