PART 9 - 강의 3/3
파티 동기화
로비/인게임 파티 관리와 진행 상황 동기화
01
파티 시스템 개요
코옵 게임의 파티 관리
파티 시스템 흐름
┌─────────────────────────────────────────────────────────────┐
│ 파티 시스템 흐름 │
├─────────────────────────────────────────────────────────────┤
│ │
│ [메인 메뉴] │
│ │ │
│ v │
│ [파티 생성/참여] ←──────────────────────────┐ │
│ │ │ │
│ v │ │
│ [파티 로비] │ │
│ - 멤버 목록 │ │
│ - 준비 상태 │ │
│ - 설정 (난이도, 맵 등) │ │
│ │ │ │
│ v │ │
│ [게임 시작] ───────────────────────────────── │
│ │ │ │
│ v │ │
│ [인게임] │ │
│ - 실시간 동기화 │ │
│ - 진행 상황 공유 │ │
│ │ │ │
│ v │ │
│ [게임 종료] → [결과 화면] → [파티 로비로 복귀] │
│ │
└─────────────────────────────────────────────────────────────┘
02
파티 데이터 구조
동기화할 파티 정보
C++
// 파티 멤버 정보
USTRUCT(BlueprintType)
struct FPartyMember
{
GENERATED_BODY()
UPROPERTY(BlueprintReadOnly)
FUniqueNetIdRepl PlayerId;
UPROPERTY(BlueprintReadOnly)
FString DisplayName;
UPROPERTY(BlueprintReadOnly)
bool bIsReady = false;
UPROPERTY(BlueprintReadOnly)
bool bIsLeader = false;
UPROPERTY(BlueprintReadOnly)
FString SelectedCharacter;
UPROPERTY(BlueprintReadOnly)
int32 PlayerLevel = 1;
};
// 파티 설정
USTRUCT(BlueprintType)
struct FPartySettings
{
GENERATED_BODY()
UPROPERTY(BlueprintReadWrite)
FString SelectedMap;
UPROPERTY(BlueprintReadWrite)
EDifficulty Difficulty = EDifficulty::Normal;
UPROPERTY(BlueprintReadWrite)
bool bIsPrivate = false;
UPROPERTY(BlueprintReadWrite)
int32 MaxPlayers = 4;
};
// 파티 상태 (복제됨)
UCLASS()
class APartyState : public AInfo
{
GENERATED_BODY()
public:
UPROPERTY(ReplicatedUsing=OnRep_Members)
TArray<FPartyMember> Members;
UPROPERTY(ReplicatedUsing=OnRep_Settings)
FPartySettings Settings;
UPROPERTY(Replicated)
FUniqueNetIdRepl LeaderId;
UFUNCTION()
void OnRep_Members();
UFUNCTION()
void OnRep_Settings();
virtual void GetLifetimeReplicatedProps(...) const override;
};
03
EOS 로비 활용
게임 외 파티 동기화
C++
// EOS 로비로 파티 생성
void UMyPartySubsystem::CreateParty()
{
IOnlineSubsystem* OSS = IOnlineSubsystem::Get("EOS");
IOnlineLobbyPtr Lobby = OSS->GetLobbyInterface();
FOnlineSchemaLobbySettings LobbySettings;
LobbySettings.Set("PartyType", "Coop");
LobbySettings.Set("MaxMembers", 4);
LobbySettings.Set("IsPublic", false);
Lobby->CreateLobby(
LocalUserId,
LobbySettings,
FOnLobbyCreated::CreateUObject(
this, &UMyPartySubsystem::OnPartyCreated));
}
// 멤버 속성 업데이트
void UMyPartySubsystem::SetReady(bool bReady)
{
IOnlineLobbyPtr Lobby =
IOnlineSubsystem::Get("EOS")->GetLobbyInterface();
// 내 멤버 속성 업데이트
FOnlineSchemaMemberAttributes MemberAttrs;
MemberAttrs.Set("IsReady", bReady);
MemberAttrs.Set("SelectedCharacter", SelectedCharacterName);
Lobby->UpdateMemberAttributes(
LocalUserId,
CurrentLobbyId,
MemberAttrs,
FOnLobbyMemberAttributesUpdated::CreateLambda(
[this](const FOnlineError& Error)
{
if (!Error.WasSuccessful())
{
UE_LOG(LogParty, Warning,
TEXT("Failed to update ready state"));
}
}));
}
// 로비 변경 알림 수신
void UMyPartySubsystem::OnLobbyUpdated(
const FUniqueNetId& LobbyId)
{
IOnlineLobbyPtr Lobby =
IOnlineSubsystem::Get("EOS")->GetLobbyInterface();
// 최신 로비 정보 조회
TSharedPtr<const FOnlineLobby> LobbyInfo =
Lobby->GetLobby(LocalUserId, LobbyId);
if (LobbyInfo.IsValid())
{
// UI 업데이트
RefreshPartyUI(LobbyInfo);
// 모두 준비 완료 체크
CheckAllReady(LobbyInfo);
}
}
04
인게임 진행 동기화
코옵 퀘스트/진행 상황 공유
C++
// 파티 공유 퀘스트 진행 상황
UCLASS()
class ACoopGameState : public AGameStateBase
{
GENERATED_BODY()
public:
// 파티 공유 퀘스트
UPROPERTY(ReplicatedUsing=OnRep_SharedQuests)
TArray<FSharedQuestProgress> SharedQuests;
// 파티 인벤토리 (선택적)
UPROPERTY(Replicated)
TArray<FItemData> SharedInventory;
// 파티 골드/자원
UPROPERTY(Replicated)
int32 SharedCurrency = 0;
UFUNCTION()
void OnRep_SharedQuests();
};
USTRUCT()
struct FSharedQuestProgress
{
GENERATED_BODY()
UPROPERTY()
FName QuestId;
UPROPERTY()
int32 CurrentObjective = 0;
UPROPERTY()
TMap<FName, int32> ObjectiveProgress; // 킬 카운트 등
};
// 서버에서 퀘스트 진행 업데이트
void ACoopGameState::UpdateQuestProgress(
FName QuestId,
FName ObjectiveId,
int32 Progress)
{
if (!HasAuthority())
return;
// 퀘스트 찾기 또는 생성
FSharedQuestProgress* Quest = SharedQuests.FindByPredicate(
[QuestId](const FSharedQuestProgress& Q)
{
return Q.QuestId == QuestId;
});
if (Quest)
{
Quest->ObjectiveProgress.FindOrAdd(ObjectiveId) += Progress;
// 모든 클라이언트에게 알림
MulticastQuestProgressUpdate(QuestId, ObjectiveId, Progress);
}
}
UFUNCTION(NetMulticast, Reliable)
void ACoopGameState::MulticastQuestProgressUpdate(
FName QuestId,
FName ObjectiveId,
int32 Progress)
{
// UI 알림 표시
if (APlayerController* PC = GetWorld()->GetFirstPlayerController())
{
if (AMyHUD* HUD = PC->GetHUD<AMyHUD>())
{
HUD->ShowQuestProgress(QuestId, ObjectiveId, Progress);
}
}
}
공유 vs 개인 진행
코옵 게임에서 어떤 진행 상황을 공유할지 결정하세요. 퀘스트 목표는 보통 공유하지만, 경험치나 개인 아이템은 개별 처리하는 경우가 많습니다.
SUMMARY
핵심 요약
- 파티 로비 - EOS Lobby로 게임 외 파티 관리
- 멤버 속성 - 준비 상태, 캐릭터 선택 등 실시간 동기화
- 공유 진행 - GameState에서 파티 공유 데이터 복제
- MulticastRPC - 진행 상황 변경 알림
COMPLETE
코스 완료
축하합니다!
UE5 Networking Deep Dive 전체 커리큘럼을 완료했습니다. 이 과정에서 학습한 내용:
- Replication 아키텍처와 Actor Channel
- Replication Graph와 Iris 시스템
- Client-Side Prediction과 Server Reconciliation
- Server-Side Rewind와 Lag Compensation
- Dedicated Server와 대규모 확장
- EOS 통합과 크로스플레이
- 네트워크 보안과 안티치트
- 코옵 시스템과 파티 동기화
PRACTICE
도전 과제
배운 내용을 직접 실습해보세요
실습 1: 파티 시스템 기초
EOS Lobby를 사용하여 파티 생성(CreateLobby), 초대(InviteFriend), 참가(JoinLobby)를 구현하세요. 로비 멤버 목록을 UMG 위젯으로 표시하세요.
실습 2: 파티 상태 동기화
EOS Lobby의 Attribute를 사용하여 파티 리더, 준비 상태, 선택한 캐릭터 등의 데이터를 실시간 동기화하세요. OnLobbyMemberStatusReceived 콜백으로 UI를 업데이트하세요.
심화 과제
파티 리더가 매치메이킹을 시작하면 전체 파티원이 함께 같은 세션에 참가하는 파티 매치메이킹 시스템을 구현하세요. 파티원 중 한 명이 연결에 실패하면 전체 파티가 대기열로 복귀하는 예외 처리를 포함하세요.