PART 4 - 강의 2/3
Server Reconciliation
서버의 이동 검증과 클라이언트 보정 메커니즘
01
ServerMove 처리
서버에서 클라이언트 이동 검증
C++
// 서버에서 이동 처리
void UMyCharacterMovement::ServerMove_Implementation(
float TimeStamp,
FVector_NetQuantize InAccel,
FVector_NetQuantize ClientLoc,
uint8 CompressedMoveFlags,
uint8 ClientRoll,
uint32 View,
UPrimitiveComponent* ClientMovementBase,
FName ClientBaseBoneName,
uint8 ClientMovementMode)
{
// 1. 타임스탬프로 델타 타임 계산
float DeltaTime = GetServerMoveDeltaTime(TimeStamp, ...);
// 2. 클라이언트 입력으로 서버에서 이동 재현
MoveAutonomous(TimeStamp, DeltaTime, CompressedMoveFlags, InAccel);
// 3. 위치 비교
const float ErrorTolerance = GetNetworkSafetyMargin();
FVector ServerLocation = UpdatedComponent->GetComponentLocation();
if ((ServerLocation - ClientLoc).SizeSquared() >
FMath::Square(ErrorTolerance))
{
// 보정 필요
PendingAdjustment.NewLoc = ServerLocation;
PendingAdjustment.NewVel = Velocity;
PendingAdjustment.bAckGoodMove = false;
}
else
{
// 클라이언트 이동 승인
PendingAdjustment.bAckGoodMove = true;
}
}
02
ClientAdjustPosition
클라이언트 위치 보정
C++
// CMC 주요 네트워크 함수
class UCharacterMovementComponent
{
// 클라이언트 -> 서버 이동 전송
UFUNCTION(Server, Unreliable, WithValidation)
void ServerMove(float TimeStamp, ...);
// 서버 -> 클라이언트 보정
UFUNCTION(Client, Unreliable)
void ClientAdjustPosition(
float TimeStamp,
FVector NewLoc,
FVector NewVel,
UPrimitiveComponent* NewBase, ...);
// 서버 -> 클라이언트 승인 (위치 보정 불필요)
UFUNCTION(Client, Unreliable)
void ClientAckGoodMove(float TimeStamp);
};
보정 발생 시 클라이언트 동작
- 위치 강제 설정 - 서버가 보낸 NewLoc으로 이동
- SavedMoves 정리 - 보정된 타임스탬프 이전의 Move 제거
- 재시뮬레이션 - 남은 SavedMoves로 이후 이동 재계산
03
오차 허용 범위 설정
NetworkSafetyMargin과 튜닝
C++
// 기본 오차 허용 범위
// MaxClientSmoothingDeltaTime: 기본 1.0f
// MAXCLIENTUPDATEINTERVAL: 기본 0.25초
// 커스텀 허용 범위 설정
float UMyCharacterMovement::GetNetworkSafetyMargin() const
{
// 기본값: MaxSpeed * 0.1초 정도
return FMath::Max(10.f, GetMaxSpeed() * 0.1f);
}
튜닝 주의사항
허용 범위가 너무 작으면 잦은 보정으로 캐릭터가 떨리고, 너무 크면 치트 감지가 어렵습니다. 게임의 최대 속도와 네트워크 환경에 맞게 조절하세요.
04
보정 스무딩 기법
보정 시 시각적 끊김 최소화
SmoothCorrection 설정
C++
// CMC의 스무딩 설정
UMyCharacterMovement::UMyCharacterMovement()
{
// 보정 스무딩 시간 (기본 0.2초)
NetworkSmoothingMode = ENetworkSmoothingMode::Exponential;
NetworkSimulatedSmoothLocationTime = 0.1f;
NetworkSimulatedSmoothRotationTime = 0.05f;
// 보정 허용 최대 거리 (이 이상이면 텔레포트)
NetworkLargeClientCorrectionDistance = 300.f;
// 서버 이동 재시뮬레이션 최대 횟수
MaxServerMovesToReplay = 64;
}
스무딩 모드
- Linear - 선형 보간, 단순하지만 자연스러움이 떨어짐
- Exponential - 지수 보간, 가장 자연스러운 결과 (권장)
- Replay - 이동 입력을 재생하여 보정, 가장 정확
디버깅 팁
콘솔 명령어 p.NetShowCorrections 1로 보정 발생 위치를 시각화하고, p.NetCorrectionLifetime 5로 시각화 지속 시간을 설정하세요. 잦은 보정은 ErrorTolerance 값 조정이 필요합니다.
SUMMARY
핵심 요약
- ServerMove - 클라이언트 입력을 서버에서 재시뮬레이션
- 위치 비교 - ErrorTolerance 초과 시 보정 트리거
- ClientAdjustPosition - 서버 위치로 강제 이동
- 재시뮬레이션 - 보정 후 남은 SavedMoves로 이동 재계산
PRACTICE
도전 과제
배운 내용을 직접 실습해보세요
실습 1: 보정 시각화
p.NetShowCorrections 1 명령어로 보정 발생 지점을 시각화하세요. 200ms 인위적 지연(NetEmulation)을 추가하고 다양한 이동 패턴에서 보정 빈도를 관찰해보세요.
실습 2: ErrorTolerance 튜닝
GetNetworkSafetyMargin()을 오버라이드하여 이동 속도에 비례하는 동적 ErrorTolerance를 구현하세요. 걷기(10), 달리기(30), 대시(50) 상태별로 다른 허용 범위를 설정해보세요.
심화 과제
NetworkSmoothingMode를 Linear, Exponential, Replay 각각으로 설정하고 200ms 지연 환경에서 체감 품질을 비교하세요. 또한 NetworkLargeClientCorrectionDistance를 조정하여 텔레포트 임계값과 스무딩의 최적 균형점을 찾아보세요.