PART 6 · 강의 3/8

RPC 구현

Remote Procedure Calls로 네트워크 함수 호출

01

RPC 개요

원격 프로시저 호출의 이해

RPC(Remote Procedure Call)는 네트워크를 통해 원격으로 함수를 호출하는 메커니즘입니다. Property Replication이 "상태"를 동기화한다면, RPC는 "이벤트"를 전달합니다.

Server RPC

호출: 클라이언트

실행: 서버

플레이어 입력, 요청 처리에 사용

Client RPC

호출: 서버

실행: 소유 클라이언트

개인 알림, UI 업데이트에 사용

NetMulticast RPC

호출: 서버

실행: 모든 클라이언트 + 서버

이펙트, 사운드 재생에 사용

RPC 유형 Reliable Unreliable
Server 중요한 입력 (발사, 구매) 빈번한 업데이트 (조준 방향)
Client 중요한 알림 (사망, 보상) 피드백 (히트마커)
NetMulticast 중요한 이펙트 (사망) 장식적 이펙트 (발자국)
02

Server RPC 구현

클라이언트 → 서버 함수 호출

CombatCharacter.h UCLASS() class MYGAME_API ACombatCharacter : public ACharacter { GENERATED_BODY() public: // Reliable + WithValidation (권장) UFUNCTION(Server, Reliable, WithValidation) void Server_Fire(FVector TargetLocation); // Unreliable (빈번한 호출용) UFUNCTION(Server, Unreliable) void Server_UpdateAimRotation(FRotator AimRotation); private: UPROPERTY(Replicated) int32 CurrentAmmo; static const int32 MAX_FIRE_DISTANCE = 10000; };
CombatCharacter.cpp // Validate 함수: false 반환 시 클라이언트 연결 해제! bool ACombatCharacter::Server_Fire_Validate(FVector TargetLocation) { // 거리 검증 - 비정상적으로 먼 타겟 차단 float Distance = FVector::Dist(GetActorLocation(), TargetLocation); if (Distance > MAX_FIRE_DISTANCE) { UE_LOG(LogTemp, Warning, TEXT("Invalid fire distance: %f"), Distance); return false; // 치터 의심 → 연결 해제 } // 탄약 검증 if (CurrentAmmo <= 0) { return false; } return true; } // Implementation 함수: 실제 서버 로직 void ACombatCharacter::Server_Fire_Implementation(FVector TargetLocation) { // 서버에서만 실행되는 코드 CurrentAmmo--; // 히트 검사 FHitResult HitResult; FVector Start = GetActorLocation(); if (GetWorld()->LineTraceSingleByChannel( HitResult, Start, TargetLocation, ECC_Pawn)) { if (AActor* HitActor = HitResult.GetActor()) { float Damage = 25.0f; UGameplayStatics::ApplyDamage( HitActor, Damage, GetController(), this, nullptr); // 히트 피드백을 요청한 클라이언트에게 전송 Client_PlayHitMarker(); } } // 모든 클라이언트에게 총구 이펙트 표시 Multicast_PlayMuzzleFlash(); }
WithValidation 필수

Server RPC에는 반드시 WithValidation을 추가하세요. Validate에서 false를 반환하면 해당 클라이언트 연결이 해제되어 치터를 방지할 수 있습니다.

03

Client & Multicast RPC

서버에서 클라이언트로 함수 호출

CombatCharacter.h (계속) // Client RPC - 서버 → 특정 클라이언트 UFUNCTION(Client, Reliable) void Client_ShowDamageNumber(float DamageAmount, FVector WorldLocation); UFUNCTION(Client, Unreliable) void Client_PlayHitMarker(); // NetMulticast RPC - 서버 → 모든 클라이언트 UFUNCTION(NetMulticast, Reliable) void Multicast_PlayDeathEffect(); UFUNCTION(NetMulticast, Unreliable) void Multicast_PlayFootstepSound(FVector Location);
CombatCharacter.cpp (계속) void ACombatCharacter::Client_ShowDamageNumber_Implementation( float DamageAmount, FVector WorldLocation) { // 이 클라이언트에서만 실행 if (APlayerController* PC = Cast<APlayerController>(GetController())) { // 데미지 숫자 UI 위젯 생성 및 표시 // ... } } void ACombatCharacter::Client_PlayHitMarker_Implementation() { // 히트마커 사운드 및 UI 피드백 // Unreliable이므로 누락될 수 있음 (괜찮음) PlayHitMarkerSound(); } void ACombatCharacter::Multicast_PlayDeathEffect_Implementation() { // 서버와 모든 클라이언트에서 실행 UGameplayStatics::SpawnEmitterAtLocation( GetWorld(), DeathParticle, GetActorLocation() ); } void ACombatCharacter::Multicast_PlayFootstepSound_Implementation( FVector Location) { // Unreliable - 누락되어도 게임플레이에 영향 없음 UGameplayStatics::PlaySoundAtLocation( GetWorld(), FootstepSound, Location ); }
04

Best Practices

RPC 사용 시 주의사항

나쁜 예시 1: Tick에서 Reliable 호출

// 절대 하지 마세요! 네트워크 버퍼 과부하! void ACombatCharacter::Tick(float DeltaTime) { Server_UpdatePosition(GetActorLocation()); // Reliable }

나쁜 예시 2: Validation 없는 Server RPC

// 치터가 악용할 수 있음! UFUNCTION(Server, Reliable) // WithValidation 누락 void Server_SetHealth(float NewHealth); // 위험!

나쁜 예시 3: BeginPlay에서 RPC 호출

// 작동하지 않을 수 있음! void ACombatCharacter::BeginPlay() { Super::BeginPlay(); Server_Initialize(); // 연결이 아직 안 됐을 수 있음 }
네이밍 컨벤션

함수 이름에 RPC 유형을 접두사로 붙이면 코드 가독성이 향상됩니다:
Server_Attack(), Client_Notify(), Multicast_Effect()

SUMMARY

핵심 요약

  • Server RPC — 클라이언트 입력을 서버로 전달, WithValidation 필수
  • Client RPC — 서버에서 특정 클라이언트에게 알림
  • NetMulticast RPC — 모든 클라이언트에 이펙트/사운드 동기화
  • Reliable vs Unreliable — 중요도에 따라 선택, Tick에서 Reliable 금지
  • _Implementation — RPC 함수의 실제 로직은 이 접미사가 붙은 함수에 작성
PRACTICE

도전 과제

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

실습 1: Server RPC 구현

UFUNCTION(Server, Reliable)로 ServerRequestAttack()을 구현하세요. 클라이언트에서 공격 입력 시 서버에 RPC를 보내고, 서버에서 데미지를 계산한 후 결과를 Multicast로 전파하세요.

실습 2: Client RPC 구현

UFUNCTION(Client, Reliable)로 ClientReceiveDamage()를 구현하여, 서버가 특정 클라이언트에게 피격 알림을 보내세요. 화면 흔들림, 피격 사운드 등 로컬 피드백을 처리하세요.

심화 과제: Reliable vs Unreliable RPC 전략

중요한 게임플레이 이벤트(아이템 획득, 퀘스트 완료)는 Reliable로, 빈번한 시각 효과(발자국, 파티클)는 Unreliable+NetMulticast로 구현하세요. 네트워크 대역폭 사용량을 비교하세요.