PART 8 - 강의 1/2

Server Authority 패턴

서버 권한 모델과 치트 방지 설계

01

권한 모델 비교

Server vs Client Authority

권한 모델 ┌─────────────────────────────────────────────────────────────┐ │ 권한 모델 비교 │ ├─────────────────────────────────────────────────────────────┤ │ │ │ [Server Authority] (권장) │ │ - 서버가 모든 게임 상태의 진실 │ │ - 클라이언트는 입력만 전송 │ │ - 서버가 검증 후 결과 복제 │ │ 장점: 치트 방지, 일관성 │ │ 단점: 지연 시간 체감 │ │ │ │ [Client Authority] │ │ - 클라이언트가 자신의 상태 결정 │ │ - 서버는 결과만 전달 │ │ 장점: 즉각적 반응 │ │ 단점: 치트 취약 │ │ │ │ [Hybrid] (UE5 기본) │ │ - 이동: Client Prediction + Server Reconciliation │ │ - 중요 액션: Server Authority │ │ │ └─────────────────────────────────────────────────────────────┘
UE5 기본 모델

UE5는 Server-Authoritative 모델을 기본으로 합니다. HasAuthority()가 true인 Actor(서버)만 게임 상태를 변경할 수 있습니다.

02

Server Authority 구현

중요 로직의 서버 처리

C++ // 데미지 처리 - 서버에서만 void AMyCharacter::TakeDamage(float Damage, ...) { // 클라이언트에서 호출되면 서버로 RPC if (!HasAuthority()) { // 클라이언트는 데미지 적용 불가 return; } // 서버에서만 HP 감소 CurrentHealth = FMath::Max(0.f, CurrentHealth - Damage); // HP는 복제되어 클라이언트에 전달 if (CurrentHealth <= 0.f) { ServerDie(); } } // 아이템 획득 - 서버 검증 void AMyCharacter::RequestPickupItem(AMyItem* Item) { if (IsLocallyControlled()) { // 클라이언트: 서버에 요청 ServerPickupItem(Item); } } UFUNCTION(Server, Reliable, WithValidation) void AMyCharacter::ServerPickupItem(AMyItem* Item); bool AMyCharacter::ServerPickupItem_Validate(AMyItem* Item) { // 기본 유효성 검사 return Item != nullptr; } void AMyCharacter::ServerPickupItem_Implementation(AMyItem* Item) { // 서버에서 거리 검증 float Distance = FVector::Dist( GetActorLocation(), Item->GetActorLocation()); if (Distance > MaxPickupDistance) { UE_LOG(LogNet, Warning, TEXT("Pickup rejected: too far (%.1f)"), Distance); return; } // 아이템이 이미 획득되었는지 확인 if (Item->bPickedUp) { return; } // 서버에서 아이템 획득 처리 Item->bPickedUp = true; Inventory.Add(Item->ItemData); Item->Destroy(); }
03

RPC 검증 패턴

WithValidation 활용

C++ // 스킬 사용 RPC 검증 UFUNCTION(Server, Reliable, WithValidation) void ServerUseAbility(int32 AbilityIndex, FVector TargetLocation); bool AMyCharacter::ServerUseAbility_Validate( int32 AbilityIndex, FVector TargetLocation) { // 1. 인덱스 범위 검증 if (AbilityIndex < 0 || AbilityIndex >= Abilities.Num()) { return false; // 연결 끊김! } // 2. 타겟 위치 합리성 검증 float MaxRange = Abilities[AbilityIndex].MaxRange; if (FVector::Dist(GetActorLocation(), TargetLocation) > MaxRange * 1.5f) { return false; // 명백한 치트 } return true; } void AMyCharacter::ServerUseAbility_Implementation( int32 AbilityIndex, FVector TargetLocation) { // Implementation에서 추가 검증 (연결 끊지 않음) // 쿨다운 체크 if (!Abilities[AbilityIndex].IsReady()) { UE_LOG(LogNet, Warning, TEXT("Ability on cooldown")); return; // 무시만 함 } // 마나/리소스 체크 if (CurrentMana < Abilities[AbilityIndex].ManaCost) { return; } // 시야 체크 (월핵 방지) if (!HasLineOfSightTo(TargetLocation)) { return; } // 모든 검증 통과 - 스킬 실행 ExecuteAbility(AbilityIndex, TargetLocation); }
Validate vs Implementation

Validate: false 반환 시 클라이언트 연결 끊김. 명백한 치트에만 사용.
Implementation: 요청 무시. 네트워크 지연으로 인한 정상적 불일치에 사용.

04

상태 복제 보안

민감 정보 보호

C++ void AMyCharacter::GetLifetimeReplicatedProps( TArray<FLifetimeProperty>& OutLifetimeProps) const { Super::GetLifetimeReplicatedProps(OutLifetimeProps); // 모든 클라이언트에게 복제 (공개 정보) DOREPLIFETIME(AMyCharacter, CurrentHealth); DOREPLIFETIME(AMyCharacter, TeamId); // 오너에게만 복제 (개인 정보) DOREPLIFETIME_CONDITION(AMyCharacter, Inventory, COND_OwnerOnly); DOREPLIFETIME_CONDITION(AMyCharacter, CurrentMana, COND_OwnerOnly); DOREPLIFETIME_CONDITION(AMyCharacter, QuestProgress, COND_OwnerOnly); // 서버 전용 (복제 안 함) // - 다른 플레이어의 정확한 위치 (안개 속) // - 숨겨진 아이템 정보 // - 게임 비밀 데이터 } // 적 정보 필터링 (전장의 안개) bool AMyCharacter::IsNetRelevantFor( const AActor* RealViewer, ...) const { // 같은 팀은 항상 보임 if (IsSameTeam(RealViewer)) return true; // 적은 시야 내에만 복제 return IsVisibleTo(RealViewer); }
SUMMARY

핵심 요약

  • Server Authority - 서버가 게임 상태의 유일한 진실
  • HasAuthority() - 서버에서만 중요 로직 실행
  • WithValidation - 명백한 치트 시 연결 끊기
  • COND_OwnerOnly - 민감 정보는 오너에게만 복제
PRACTICE

도전 과제

배운 내용을 직접 실습해보세요

실습 1: 서버 권위 아이템 시스템

아이템 획득/사용을 Server RPC로만 처리하고, 인벤토리 상태를 서버에서 복제하는 시스템을 구현하세요. 클라이언트에서 직접 인벤토리를 수정할 수 없도록 HasAuthority() 체크를 추가하세요.

실습 2: 서버 검증 RPC 패턴

UFUNCTION(Server, Reliable, WithValidation)으로 스킬 사용 RPC를 구현하세요. Validate에서 쿨다운, 마나, 사거리를 검증하고, Implementation에서 실제 효과를 적용하세요.

심화 과제

클라이언트 예측 + 서버 권위 하이브리드 전투 시스템을 구현하세요. 클라이언트에서 즉시 이펙트를 재생하되, 서버 검증 실패 시 롤백하는 Optimistic Execution 패턴을 적용하세요.