득이공간

[네트웍 멀티플레이 프레임웍의 이해] 4장. 움직임 리플리케이션 본문

GP/UE5

[네트웍 멀티플레이 프레임웍의 이해] 4장. 움직임 리플리케이션

쟁득 2024. 7. 12. 19:54
해당 게시물은 이득우 교수님의 '네트웍 멀티플레이 프레임웍의 이해' 강의를 수강하며
학습한 내용을 개인적으로 정리한 글입니다.

📌 목차 - 4장. 움직임 리플리케이션

4-1. 움직임 리플리케이션

4-2. 물리 움직임 리플리케이션

4-3. 캐릭터 무브먼트의 확장


📌 4-1. 움직임 리플리케이션

1. 네트웍 멀티플레이에서 안정적으로 캐릭터 움직임을 동기화하는 플로우의 이해
2. 움직임 리플리케이션에 관련된 언리얼 소스코드 분석
3. 움직임 리플리케이션을 디버깅하는 방법의 학습

 

  • 이번 강의에서 학습할 내용
    • 움직임 리플리케이션: 캐릭터
  • 캐릭터 움직임의 리플리케이션 플로우
    • 클라이언트의 입력 정보를 서버로 보내고 서버에서 확인 후 수정을 거침
  • Autonomous Proxy 클라이언트의 진행
    • [ReplicateMoveToServer]
    • 클라이언트 캐릭터의 움직임을 보관하는 네트웍용 클라이언트 데이터 생성
    • 클라이언트의 데이터에 저장된 움직임 중에 참고할 중요한 움직임 기록 (OldMove)
    • 현재 틱의 움직임을 기록하는 신규 움직임 생성 (NewMove)
    • 입력을 처리하기 전의 각종 초기화 상태를 저장 (ex. StartLocation)
    • 필요시 최종 움직임과 현재 움직임을 병합 시도
    • 클라이언트 로컬에서의 움직임 진행 (PerformMovement)
    • 신규 움직임에 움직임 결과 상태를 저장 (ex. SavedLocation)
    • 신규 움직임을 클라이언트 데이터에 추가
    • ServerMove 함수를 호출해 OldMove와 NewMove를 서버에 전송
  • 클라이언트가 호출하는 서버 RPC
    • [ServerMove]
    • 클라이언트의 최종 움직임 정보를 서버에 보내는 함수
      • 타임스탬프: 움직임에 대한 시간 정보
      • 가속 정보: 입력으로 발생된 최종 가속 정보를 작은 사이즈로 인코딩
      • 위치 정보: 캐릭터의 최종 위치 정보. 캐릭터가 베이스(예) 플랫폼) 위에 있는 경우는 상대 위치를 사용
      • 플래그: 특수한 움직임(점프, 웅크리기)에 대한 정보
      • 회전 정보: 압축된 회전 정보 (Yaw 회전 중심으로 저장)
      • 본 정보: 스켈레탈 메시 컴포넌트인 경우, 기준이 되는 본 정보
      • 무브먼트 모드 정보: 캐릭터 컴포넌트의 무브먼트 모드 정보
  • 서버의 처리
    • [ServerMove_Implementation]
    • 서버 캐릭터의 움직임을 보관하는 네트웍용 서버 데이터 생성
    • 클라이언트로부터 받은 타임스탬프 값을 검증
      • 타임 스탬프 값을 다양한 방법으로 검증
      • 상당한 시간 차가 감지되면, 해킹 방지를 위해 서버 틱으로 제한함
      • 네트웍 매니저 설정의 보상 비율을 사용해 클라이언트와 서버 시간을 서서히 균등화시킴
    • 압축된 가속, 회전 데이터를 디코딩하고 클라이언트와 서버의 타임 스탬프 정보를 기록
    • MoveAutonomous 함수를 호출해 서버 캐릭터를 이동시킴
    • 클라이언트와의 차이를 비교하고 에러를 수정함
      • 떨어지는 상황, 착지할 때의 상황에 따라 허용 가능 범위 내에서 클라이언트 데이터를 신뢰함
      • 상당한 시간 차가 감지되면, 수정 정보를 기록함(PendingAdjustment)
  • 서버가 호출하는 클라이언트 RPC
    • [ClientAdjustPosition]
    • 클라이언트에게 수정할 위치 정보를 알려주는 함수
    • 중복 없이 서버 틱의 마지막에서 수정이 필요할 때만 전송함
      • 타임 스탬프: 클라이언트의 타임 스탬프 값
      • 델타 타임: 서버의 델타 타임
      • 무브먼트 모드 정보: 압축된 캐릭터 컴포넌트의 무브먼트 모드 정보
      • 새로운 속도: 수정할 새로운 속도 정보
      • 새로운 위치: 수정할 새로운 위치 정보
      • 새로운 회전: 수정할 새로운 회전 정보
      • 새로운 베이스와 베이스 본 이름: 수정할 베이스에 대한 정보
  • 클라이언트의 수정 처리
    • [ClientAdjustPosition_Implementation]
    • 타임 스탬프 값을 통해 서버로부터 확인받은 움직임 정보를 기록 (LastAckedMove)
    • 서버에서 전달받은 위치로 루트 컴포넌트(캐릭터)의 위치를 변경
    • 서버에서 전달받은 속도로 무브먼트 컴포넌트의 속도를 수정
    • 베이스 정보와 위치를 수정
    • 서버에 의해 클라이언트 위치가 업데이트되었다고 기록 (bUpdatePosition)
      • 서버의 수정 정보를 바탕으로 MoveAutonomous 함수를 호출해 클라이언트에서 남은 움직임을 재생함
  • 움직임 리플리케이션의 디버깅
    • LogNetPlayerMovement=VeryVerbose 로 설정
    • 서버에서의 오차 발생 시 드로우 디버그
      • 전달받은 클라이언트 위치를 붉은색으로 표시
      • 서버에서 움직인 위치를 녹색으로 표시
    • 오차를 전달받은 클라이언트에서의 드로우 디버그
      • 클라이언트가 지정했던 위치를 붉은색으로 표시
      • 서버가 수정해준 위치를 녹색으로 표시
      • 수정은 발생했지만 서버와 클라이언트 위치가 거의 동일한 경우에는 노란색으로 표시
    • ~ p.NetShowCorrections 1

📌 4-2. 물리 움직임 리플리케이션

1. 액터의 물리적인 움직임을 리플리케이션하는 플로우와 소스 코드의 이해
2. Simulate Proxy로 동작하는 캐릭터에서 움직임을 처리하는 방식의 이해

 

  • 이번 강의에서 학습할 내용
    • 움직임 리플리케이션: 물리
  • 액터의 리플리케이션 플로우
    • 프로퍼티 리플리케이션을 사용해 움직임 정보를 전송하고, 클라이언트는 받을 때마다 이를 적용함
  • 움직임 리플리케이션을 위한 서버의 준비
    • [ReplicatedMovement]
    • 서버에서 SimulatedProxy로 보내는 움직임 정보를 기록한 멤버 변수
    • OnRep_ReplicatedMovement로 이벤트 함수 호출함
    • 일반 움직임과 물리 움직임의 리플리케이션을 모두 처리하는 용도로 활용됨
    • FRepMovement 구조체의 주요 멤버 변수
      • 위치와 회전: 컴포넌트의 현재 위치와 회전
      • 데이터 정밀도 설정: 위치, 회전, 속도의 데이터 정밀도. 끊김 현상이 보이지 않을 만큼 최소로 설정
      • 물리 시뮬레이션 여부 플래그: 물리 시뮬레이션으로 복제할지를 지정
      • 이동 속도: 컴포넌트의 이동 속도
      • 각 속도: 컴포넌트의 각 속도. 물리 시뮬레이션 진행시에만 사용
      • 서버 프레임: 서버에서의 물리 프레임
  • 물리 움직임의 기록
    • [FRigidBodyState]
    • 액터의 물리 상태를 기록하는 구조체
    • 다음과 같은 멤버 변수로 구성되어 있음
      • 위치: 소수점 두 자리 정밀도로 기록됨
      • 회전: 사원수 정보로 기록됨
      • 속도: 소수점 두 자리 정밀도로 기록됨
      • 각속도: 소수점 두 자리 정밀도로 기록됨
      • 플래그: 휴면 상태와 같은 특정 물리 상태를 기록하는데 사용
  • 액터 리플리케이션의 준비
    • 액터의 움직임 리플리케이션 옵션을 활성해주어야 올바로 동작함
    • [GatherCurrentMovement]
    • 현재 액터의 움직임을 ReplicatedMovement 속성으로 변환해 설정하는 함수
    • 액터의 PreReplication 함수에서 호출됨
    • 액터의 물리 움직임과 일반 움직임을 구분해 각각 처리함
    • 일반 움직임은 단순히 액터의 현재 위치, 회전, 속도 값을 ReplicatedMovement에 저장함
    • 물리 시뮬레이션의 경우 현재 월드에 설정된 물리 씬에서 해당 컴포넌트의 물리 상태를 저장함
      • 현재 컴포넌트의 물리 상태 정보를 ReplicatedMovement로 옮김 (FRigidBodyState::FillFrom)
    • 이를 통해 최종 ReplicatedMovement가 설정되어 클라이언트에 보내짐
  • 액터 움직임 정보의 수신
    • [OnRep_ReplicatedMovement]
    • ReplicatedMovement의 물리 시뮬레이션 속성(bRepPhysics) 여부에 다라 두 가지로 실행됨
    • 일반적임 움직임에 대한 처리
      • Simulated Proxy에 대해서만 처리함
      • 컴포넌트의 위치와 회전 정보를 갱신함
      • 속도 처리는 별도로 진행하지 않음
    • 물리 움직임에 대한 처리
      • ReplicatedMovement의 정보를 현재 컴포넌트의 물리 상태로 옮김 (FRigidBodyState::CopyTo)
      • 물리 리플리케이션 씬에서 컴포넌트와 일치하는 타깃을 찾아서 업데이트 (FReplicatedPhysicsTarget)
  • 물리 움직임의 동기화
    • [ApplyRigidBodyState]
    • 물리 리플리케이션의 틱에서 호출되는 함수
    • 클라이언트의 물리 상태가 서버의 물리 상태의 오차 내에 있을 때까지 계속 호출됨
    • 다음과 같은 로직으로 진행됨
      1. 서버에서 받은 최종 속도와 핑을 기반으로 클라이언트의 물리 상태를 외삽(Extrapolation)으로 예측
      2. 예측한 위치와 방향이 서버와 비교해 올바른지 체크하고 문제가 있다고 판단되면 에러 시간을 누적함
      3. 누적된 에러 시간 설정값을 넘으면 강제 조정(하드스냅)을 진행함
      4. 차이가 크지 않다면 내삽(Interpolation)을 수행해 현재 위치, 회전, 속도, 각속도를 조정
  • Simulated Proxy 클라이언트의 움직임 진행
    • [SimulatedTick]
    • Simulated Proxy의 캐릭터가 처리하는 캐릭터의 움직임
    • 캐릭터가 Simulated Proxy인 경우 캐릭터만의 추가적인 작업을 수행함 (SimulateMovement)
    • 시뮬레이션으로 캡슐을 이동시킨 후 메시의 움직임을 부드럽게 보간함 (SmoothClientPosition)

📌 4-3. 캐릭터 무브먼트의 확장

1. 네트웍 멀티플레이 게임을 구현하는 여러 방법의 이해
2. 캐릭터 클래스에 설정된 캐릭터 무브먼트 컴포넌트를 확장하는 방법의 학습
3. 캐릭터 무브먼트 클래스에 관련된 클래스를 확장해 새로운 움직임 기능을 추가하는 방법의 학습

 

  • 이번 강의에서 학습할 내용
    • 움직임 리플리케이션: 캐릭터
  • 네트웍 멀티플레이 텔레포트 기능을 구현하는 방법
    • 두 가지 시나리오를 생각해볼 수 있음
    1. 캐릭터 무브먼트 컴포넌트에 텔레포트 명령을 위한 RPC 혹은 프로퍼티 리플리케이션을 새롭게 설계해 추가 구현
    2. 캐릭터 무브먼트 컴포넌트가 사용하는 RPC 기능에 텔레포트 기능을 추가 선언하고, 몇몇 중요한 가상 함수를 override하여 구현
    • 1번의 경우 전체적인 캐릭터 무브먼트 컴포넌트의 설계를 바꿔야 하지만 2번은 클래스만 교체하는 것으로 간편하게 구현 가능
  • 캐릭터 무브먼트 컴포넌트가 관리하는 움직임 정보
    • 캐릭터 무브먼트 구현을 위한 움직임 클래스
      • FNetworkPredictionData_Client_Character 클래스 (클라이언트 캐릭터 데이터)
      • FSavedMove_Character 클래스 (캐릭터 움직임)
    • 캐릭터 무브먼트 컴포넌트의 구현 특징
      • 캐릭터 무브먼트 컴포넌트는 클라이언트 캐릭터 데이터의 타입을 확정하지 않음
      • 클라이언트 캐릭터 데이터 역시 캐릭터 움직임의 타입을 확정하지 않음
      • 따라서 두 클래스를 상속받아 움직임을 추가하는 것이 가능함
    • 움직임 관련 클래스를 바꾸는데 사용되는 가상 함수
      • 캐릭터 무브먼트 컴포넌트 클래스의 GetPredictionData_Client 함수
      • 클라이언트 캐릭터 데이터 클래스의 AllocateNewMove와 FreeMove 함수
  • 언리얼 오브젝트의 인자가 있는 생성자 선언
    • 모든 언리얼 오브젝트는 초기화 오브젝트 인자가 있는 생성자를 사용할 수 있음
    • 초기화 오브젝트 인자를 사용해 서브 오브젝트 클래스를 변경할 수 있음
    • 이를 사용해 새로운 캐릭터 무브먼트 클래스를 생성하지 않고, 우리가 만든 컴포넌트로 교체 가능
      • 언리얼 엔진이 지정한 캐릭터 무브먼트 컴포넌트의 이름을 사용해 해당 클래스를 찾을 수 있음
  • 신규 움직임 능력을 추가하는 방법
    • 캐릭터 움직임 클래스에서 관리하는 특별한 움직임에 대한 플래그 정보
    • 플래그 값이 변경되면 움직임 시스템에서는 이를 중요한 움직임으로 간주함
    • 기능 확장을 위해 예비 플래그를 4개 준비해두었음
    • 우리가 추가할 새로운 움직임 기능에 대한 플래그를 할당
  • 텔레포트 능력의 추가
    • 3초마다 재생 가능한 텔레포트 움직임을 구현함
    • 구현 편의를 위해 텔레포트 입력과 텔레포트 가능 여부를 플래그에 설정
      • 텔레포트 명령을 내렸는가?: FLAG_Custom_0
      • 현재 쿨타임을 포함해 텔레포트가 진행 중인가?: FLAG_Custom_1
    • 두 개의 플래그 정보를 통해 서버는 클라이언트의 상황을 수시로 전달받을 수 있음