티스토리 뷰

  • 기존 네트워크 기법과의 차이
    • 개념 
      • Push 모델 기반
      • Replication Graph 의 경우 필터링으로 대체 됨
      • 브릿지와 리플리케이션 시스템으로 구성. 목표는 기존 Polling 기법 기반으로 수 많은 virtual call을 탐색 및 호출하는 구조를 개선하기 위함. 
    • RPC
      • 이제 무조건 RPC는 RPC 수행 대상자의 Replicated State Data가 적용된 이후에 수행된다.
  • 활성화 방법
    • PushDown 모델 활성화 필요
      • 만약 아이리스에 대해서만 활성화 하고 싶다면, 'Net.IsPushModelEnabled' 활성화하면 됨
    • // Enable iris if it is not already on by default
      if (!bUseIris)
      {
          // If we enable Iris for a single target we also need to set the TargetBuildEnvironment to unique, as other projects in the solution might want it compiled out
          BuildEnvironment = TargetBuildEnvironment.Unique;
          bUseIris = true;
      }
      
  • 구조
    • ReplicationState
      • 가장 기초적인 네트워크 Primitive 데이터이며, 사실상 리플리케이트 될 데이터를 담는다.
      • 해당 데이터를 설명하기 위해 ReplicationStateDescriptor를 하나씩 들고 있다.
    • ReplicationStateDescriptor
      • 메모리 레이아웃, 조건, 필터링, 우선순위 설정, 직렬화 방법에 대한 데이터를 들고 있다.
      • 해당 State Descriptor를 커스터마이징하여 사용하는 예시는 TestNetworkPlugin에서 볼 수 있다.
    • ReplicationFrament
      • 게임플레이 코드와 리플리케이션 시스템 사이에서 스테이트를 주고 받는 작업을 담당한다. (말로는 이해 불가, 내부 코드 분석은 아래와 같다.)
        • ReplicationFragment.h 
          • FReplicationStateOwnerCollector
          • FReplicationStateApplyContext
            • Descriptor pointer
          • 주석
            • 하나 이상의 ReplicationState를 오너와 바인딩한다. 이는 NetObject를 구성할 때 핵심이 된다.
            • 게임쪽에서 이 데이터를 추출하거나 지정할 수 있다.
    • ReplicationProtocol
      • FReplicationProtocol은 정적인 구조 정의이고,
        FReplicationInstanceProtocol은 실제 객체 인스턴스와 연결된 동적인 상태를 관리합니다.
        🔄 구조 관계 요약
        FReplicationProtocol 어떤 데이터가 복제될지 정의 (정적) FReplicationStateDescriptor 배열 포함
        FReplicationInstanceProtocol 실제 객체 인스턴스의 복제 상태 관리 (동적) FReplicationFragment* 배열 포함
        FReplicationFragment 실제 복제 상태 추적 및 직렬화 FReplicatedState 포함
        FReplicationBridge 객체 등록/해제 및 Protocol ↔ Instance 연결 FReplicationInstanceProtocol 생성 및 관리
    • NetHandle
  • 아이리스 시스템 초기화 전체흐름
    • FReplicationSystemUtil::BeginReplicationForActorsInWorldForNetDriver
    • AActor::BeginReplication
      • Call::FReplicationSystemUtil::BeginReplication 
      • Called From
        • FReplicationSystemUtil::BeginReplicationForActorsInWorldForNetDriver
        • FReplicationSystemUtil::FlushNetDormancy
    • FReplicationSystemUtil::BeginReplication
      • ForEachReplicationSystem{Call::EngineReplicationBridge::StartReplicatingActor}
    • FReplicationSystemUtil::AddDependentActor
      • ForEachReplicationSystem{Call::EngineReplicationBridge::StartReplicatingActor)
    • EngineReplicationBridge::StartReplicatingActor
    • ObjectReplicationBridge::StartReplicatingRootObject
    • ObjectReplicationBridge::StartReplicatingNetObject
      • 개별 인스턴스 프로토콜 생성 : FReplicationInstanceProtocolPtr InstanceProtocol = FReplicationProtocolManager::CreateInstanceProtocol
      • 인스턴스 프로토콜 구분자 계산 : FReplicationProtocolIdentifier ProtocolIdentifier  = FReplicationProtocolManager::CalculateProtocolIdentifier
      • 프로토콜 구분자와 아키텍쳐 타입을 이용해 프로토콜 가져옴 못 찾으면 아래에서 아에 생성함 : FReplicationProtocol* ReplicationProtocol = ProtocolManager→GetReplicationProtocol(ProtocolIdentifier, ArchetypeOrCDOUsedAsKey)
      • 넷 핸들러 구축 및 인스턴스 연결
        • FNetHandle NetHandle = FNetHandleManager::GetOrCreateNetHandle(Instance←리플리케이트할 대상을 기반으로 넷핸들러 생성)
        • FNetRefHandle RefHandle = UReplicationBridge::InternalCreateNetObject(AllocatedRefHandle, NetHandle, ReplicationProtocol)
          • AllocatedRefHandle과 프로토콜을 이용해 넷 오브젝트 생성 맟 핸들 반환 : UReplicationBridge::InternalCreateNetObject
        • 더티 트래킹을 위해 인스턴스와 인스턴스 프로토콜을 바인딩 : UReplicationBridge::InternalAttachInstanceToNetRefHandle
        • Push Model 인 경우 인스턴스에 PushId 지정 : UObjectReplicationBridge::SetNetPushIdOnInstance
  • 더티 트래킹의 전체 흐름
    • BeginReplication()  StartReplicatingActor()  FReplicationBridge가 FReplicationInstanceProtocol을 생성.
    • 이때 FReplicationFragment들이 바인딩되고, 각 Fragment는 자신의 FReplicatedState를 관리.

    2. 데이터 변경 감지 (Dirty Detection)
    • 이 함수는 각 프레임마다 호출되어 상태의 변경 여부를 감지합니다.
    • 내부적으로는 FReplicatedState의 메모리를 비교하거나, 커스텀 로직을 통해 변경 여부를 판단합니다.
    🔹 변경 감지 방식
    • 메모리 비교: 이전 상태와 현재 상태를 비교하여 변경된 바이트를 추적.
    • 커스텀 로직: PollReplicationStateChanges()를 오버라이드하여 특정 조건에서만 더티로 간주.

    3. 더티 마킹 (Dirty Marking)
    • 변경된 상태는 이 버퍼에 기록됩니다.
    •  FReplicatedState는 더티 비트 마스크를 통해 어떤 필드가 변경되었는지 추적합니다.
    🔹 FReplicationInstanceProtocol::MarkStateDirty()
    • Fragment가 변경된 상태를 감지하면 이 함수를 호출하여 해당 상태를 더티로 마킹.
    • 이후 전송 대상에 포함됨.

    4. 직렬화 및 전송
    • 더티로 마킹된 상태만 직렬화하여 네트워크 패킷에 포함.
    • FNetSerializer를 통해 필드 단위 직렬화가 수행됨.
    🔹 FReplicationProtocol::ReplicationStateDescriptors
    • 어떤 필드를 어떻게 직렬화할지 정의된 메타데이터를 기반으로 처리.

    5. 클라이언트에서 수신 및 적용
    • 수신된 패킷을 역직렬화하여 FReplicatedState에 적용.
    • FReplicationFragment::ApplyReplicatedState()를 통해 실제 객체에 반영.

    핵심 구조체 변화 요약
    고급 팁
    • IRIS는 푸쉬 모델이기 때문에, 더티 상태를 감지하지 못하면 복제가 발생하지 않습니다.
    • PollReplicationStateChanges()를 커스터마이징하면, 조건부 복제 최적화된 전송이 가능합니다.
    • FReplicationFragment는 상태를 직접 관리하므로, 커스텀 Fragment를 구현하면 더티 트래킹 로직을 세밀하게 제어할 수 있습니다.
  • FReplicatedState 변경된 필드의 값이 업데이트됨
    FReplicationStateChangeBuffer 변경된 필드의 인덱스/비트가 기록됨
    FReplicationInstanceProtocol 해당 Fragment의 상태를 더티로 마킹
    FNetSendHandler 더티 상태만 직렬화하여 전송
  • 🔹 FNetReceiveHandler::DeserializeAndApply()
  • 🔹 FNetSendHandler::SerializeAndSend()
  • 🔹 FReplicationStateChangeBuffer
  • 🔹 FReplicationFragment::PollReplicationStateChanges()
  • 1. 객체가 등록되고 초기화됨