액터 네트워크 휴면 상태(Network Dormancy) (AActor::NetDormancy)는 멀티플레이어 프로젝트에서 할 수 있는 가장 영향력이 강한 서버 최적화 가운데 하나로, 프레임당 수 밀리초의 서버 CPU 시간을 절약할 수 있으며, 특히 프로젝트에 자주 변경되지 않는 리플리케이트된 액터가 많은 경우 더 효과적입니다. 넷 업데이트 중에 NetDriver는 연결에 관련된 모든 리플리케이트된 액터 목록을 수집한 다음, 이러한 액터와 액터의 프로퍼티에 대한 반복작업을 통해 변경된 사항과 클라이언트에 전송해야 할 사항을 결정합니다. 액터의 네트워크 휴면 상태는 해당 액터를 연결의 수집된 액터 목록에 추가할지를 제어합니다. 휴면 상태(Dormant) 액터는 목록에 추가되지 않으며 깨어 있는(Awake) 액터, 즉 휴면 상태가 아닌 액터가 목록에 추가됩니다. 액터와 액터의 프로퍼티에 대한 반복작업은 특히 리플리케이트된 액터가 많은 프로젝트에서 비용이 많이 소모될 수 있습니다. 따라서, 네트워크 휴면 상태를 효과적으로 사용하여 리플리케이션 고려 대상 목록에서 액터를 필터링하는 것은 멀티플레이어 프로젝트 최적화에 매우 중요할 수 있습니다.
네트워크 휴면 상태 사용 방법
프로젝트에서 네트워크 휴면 상태를 효과적으로 사용하려면 다음 단계를 따릅니다.
-
액터의 생성자에서 액터의
AActor::NetDormancy를ENetDormancy::DORM_DormantAll로 설정합니다.NetDormancy = ENetDormancy::DORM_DormantAll; - 액터가 맵에 배치된 경우 액터의
AActor::NetDormancy를ENetDormancy::DORM_Initial로 설정합니다. - 휴면 상태에서는 액터가 리플리케이트되지 않습니다.
- 액터를 리플리케이트하려면 리플리케이트된 프로퍼티를 변경하기 전에
AActor::FlushNetDormancy,AActor::ForceNetUpdate또는AActor::SetNetDormancy(ENetDormancy::DORM_Awake)를 호출합니다. - 리플리케이트된 컴포넌트나 서브오브젝트의 경우, 이를 소유한 액터를 플러시하거나 깨워야만 리플리케이트된 프로퍼티를 변경할 수 있습니다.
리플리케이트된 액터가 휴면 상태로 표시된 경우, NetDriver 는 해당 연결의 수집된 액터 목록에 휴면 액터 추가를 건너뛸 수 있습니다. 그러면 액터의 리플리케이션을 고려하고 해당 프로퍼티를 비교하는 데 소요되는 시간이 절약됩니다. 휴면 상태 액터가 깨어나거나 휴면 상태가 플러시될 때까지 해당 액터는 리플리케이션 대상으로 고려되지 않으므로, 해당 액터의 리플리케이트된 프로퍼티에 대한 변경사항이 클라이언트에 전송되지 않습니다. 또한, 휴면 상태에서는 액터의 리플리케이트된 스테이트가 변경되지 않아야 한다는 점도 유의해야 합니다. 왜냐하면 액터가 깨어날 때 이러한 변경사항을 잃게 될 수 있기 때문입니다. 즉, 리플리케이트된 프로퍼티가 자주 변경되지 않는 액터가 휴면 상태 후보로 적합한 액터입니다. 폰처럼 자주 업데이트해야 하는 액터는 휴면 상태의 이점이 거의 없는데, 왜냐하면 액터의 휴면 상태 스테이트를 변경하거나 플러시하는 데 추가 오버헤드가 발생하므로 이러한 일이 너무 자주 발생하면 그냥 액터를 깨어 있는 상태로 유지하는 것보다 퍼포먼스가 떨어질 수 있기 때문입니다.
리플리케이트된 액터의 액터 채널은 휴면 상태가 되면 닫히지만, 휴면 상태의 액터는 여전히 서버와 클라이언트 양쪽에 존재합니다. 이는 동적으로 리플리케이트된 액터가 더는 연관성이 없어지면 클라이언트에서 소멸되는 액터 연관성 핸들링 방식과는 다릅니다. 휴면 상태의 액터에 대해서는 연관성을 검사하지 않으므로, Net.RepGraph.DormantDynamicActorsDestruction 콘솔 변수가 활성화된 상태로 리플리케이션 그래프를 사용하지 않는 한 휴면 상태 액터가 클라이언트에서 연관성이 없어져도 해당 클라이언트에서 소멸되지 않습니다.
액터의 네트워크 휴면 상태 변경
액터의 휴면 상태 스테이트는 해당 액터의 AActor::NetDormancy 프로퍼티에 저장됩니다. 이 프로퍼티는 AActor::SetNetDormancy 를 호출하여 변경할 수 있습니다. AActor::NetDormancy 는 퍼블릭이지만, 이 프로퍼티를 해당 액터의 생성자 외부에서 직접 설정해서는 안 됩니다. 액터의 휴면 상태를 변경하려면 AActor::SetNetDormancy 를 호출해야 하는데, 왜냐하면 이 함수가 NetDriver 에 변경사항을 알리는 작업도 처리하기 때문입니다.
네트워크 휴면 상태 스테이트
EngineTypes.h 에 정의된 ENetDormancy 열거형 클래스에 다섯 가지 휴면 상태 스테이트가 설명되어 있습니다. 아래 테이블에 이러한 휴면 상태 스테이트가 설명되어 있습니다.
| 네트워크 휴면 상태 스테이트 | 설명 |
|---|---|
DORM_Never |
이 액터는 휴면 상태가 되지 않습니다. 이는 휴면 상태 시스템에 의해 강제되지 않습니다. |
DORM_Awake |
이 액터는 휴면 상태가 아니며 리플리케이션 대상으로 고려됩니다. |
DORM_DormantPartial |
이 액터는 모든 연결이 아닌 일부 연결에 대해 휴면 상태입니다. 부분 휴면 상태는 사용하지 않는 것이 좋습니다. 부분 휴면 상태는 폐기될 예정입니다. |
DORM_Initial |
이 액터는 초기에 모든 연결에 대해 휴면 상태입니다. 초기에 맵에 배치된 액터에만 이 스테이트를 사용해야 합니다. |
DORM_DormantAll |
이 액터는 모든 연결에 대해 휴면 상태입니다. |
휴면 상태 액터 깨우기
다음의 두 가지 기본 방법으로 휴면 상태 액터를 깨울 수 있습니다.
- 넷 휴면 상태(Net Dormancy) 프로퍼티를 설정합니다.
- Flush Net Dormancy 함수를 호출합니다.
넷 휴면 상태 설정
AActor::SetNetDormancy(ENetDormancy::DORM_Awake) 를 호출하여 휴면 상태의 액터를 깨울 수 있습니다. 액터가 깨어있는 동안에는 그 액터에서 AActor::SetNetDormancy(ENetDormancy::DORM_DormantAll) 을 호출하여 다시 휴면 상태로 설정될 때까지는 정상적으로 리플리케이트됩니다. 이는 스테이셔너리 오브젝트가 이동하기 시작하는 것처럼 휴면 상태 액터가 프레임마다 변경되기 시작하는 경우에 유용합니다.
정적으로 배치된 초기에 휴면 상태였던 액터가 깨어나면, 다시 그 액터를 ENetDormancy::DORM_Initial 로 설정해서는 안 됩니다. 대신 ENetDormancy::DORM_DormantAll 을 사용해야 합니다.
넷 휴면 상태 플러시
휴면 상태의 액터에서 AActor::FlushNetDormancy 를 호출하여 휴면 상태 액터의 변경사항을 리플리케이트할 수도 있습니다. 이렇게 하면 실제로 액터의 휴면 상태 스테이트를 변경하지 않고도 액터가 관련된 모든 연결에 대해 하나 이상의 업데이트를 강제로 리플리케이트합니다. 한 가지 예외가 있는데, AActor::NetDormancy 가 ENetDormancy::DORM_Initial 로 설정된 액터에서 AActor::FlushNetDormancy 를 호출하면, AActor::FlushNetDormancy 호출에 따라 해당 액터의 휴면 상태가 ENetDormancy::DORM_DormantAll 로 변경됩니다.
넷 업데이트 강제(Force Net Update)
휴면 상태의 액터에서 AActor::ForceNetUpdate 를 호출하면 AActor::FlushNetDormancy 도 호출되고, 다음 넷 업데이트에서 해당 액터가 리플리케이션 대상으로 고려됩니다. 액터에 대해 단일 프레임에서 간헐적으로 일회성 업데이트가 발생하는 경우에 유용합니다.
액터의 휴면 상태가 플러시된 후나 액터가 깨어나고 나서 휴면 상태로 설정할 경우, 해당 액터는 즉시 휴면 상태가 되지 않으므로 여러 업데이트를 전송할 수 있습니다. 해당 액터는 그 대신 해당 액터와 액터의 서브오브젝트에 전송되어야 할 확인되지 않은 변경사항이 더 이상 없을 때까지 계속 리플리케이트합니다. 휴면 상태 이력 현상을 활성화하는 경우에도, 액터가 즉시 휴면 상태가 되지 않습니다(UActorChannel::ReadyForDormancy 및 FObjectReplicator::ReadyForDormancy 참조).
깨우기 메서드를 사용해야 하는 경우
액터의 리플리케이트된 프로퍼티를 변경하기 전에 액터에서 AActor::SetNetDormancy(ENetDormancy::DORM_Awake) 또는 AActor::FlushNetDormancy 를 호출합니다. 휴면 상태의 액터를 깨우면 해당 액터의 리플리케이트된 프로퍼티에 대한 모든 현재 값을 복사하여 변경된 프로퍼티와 리플리케이트해야 할 프로퍼티를 비교하는 데 사용되는 스테이트인, 액터의 섀도 스테이트 를 다시 초기화합니다. 이는 휴면 상태 중에 액터의 리플리케이트된 스테이트를 변경하면 안 되는 이유이기도 한데, 액터를 깨웠을 때 리플리케이션을 위해 액터의 프로퍼티를 비교할 때 이러한 변경사항이 탐지되지 않기 때문입니다.
하지만, 대부분의 경우 변경 후에 호출해도 이러한 변경사항이 예상대로 리플리케이트될 수 있습니다. 그러나 이 행동은 구현 세부 사항이므로 이 행동에 의존해서는 안 됩니다. 예를 들어, 휴면 상태 빠른 배열을 변경할 때 프로퍼티 변경 후 AActor::FlushNetDormancy 를 호출하는 것과 같은 특정한 경우에는 변경사항이 전혀 리플리케이트되지 않습니다.
블루프린트 액터의 휴면 상태
블루프린트 액터에 휴면 상태를 사용할 때, 리플리케이트된 프로퍼티를 설정하면 액터가 자동으로 AActor::FlushNetDormancy 를 호출합니다.
ActorComponent 블루프린트에서 리플리케이트된 프로퍼티를 세팅할 때는 자동으로 호출되지 않는데, 현재 이 행동이 일관성 있게 발생하도록 작업 중입니다.
휴면 상태 및 리플리케이션 그래프
리플리케이션 그래프를 사용할 때, 휴면 상태는 디폴트 NetDriver 를 사용할 때와 똑같이 작동해야 하므로, 프로젝트 코드에서 액터를 휴면 상태나 깨어난 상태로 설정하고 AActor::FlushNetDormancy 를 정상적으로 호출할 수 있습니다. 노드가 액터 목록을 수집할 때 휴면 상태의 액터를 반환하더라도 UReplicationGraph::ReplicateActorListsForConnections_Default 는 여전히 이러한 액터의 리플리케이션을 건너뜁니다.
리플리케이션 그래프 노드에는 휴면 상태 액터에 대한 특별한 핸들링이 포함될 수 있습니다. 이를 통해 노드의 휴면 상태 액터 처리 시간 및 메모리뿐 아니라 노드에서 수집한 액터 목록의 크기도 줄일 수 있습니다. 예를 들어, GridSpatialization2D 노드에는 액터가 휴면 상태이면 스태틱으로 취급하고 깨어 있는 상태이면 다이내믹으로 취급하는 휴면 상태 액터에 대한 추가 핸들링이 포함되어 있습니다. 이러한 핸들링은 가끔 그리드를 통과하여 이동할 수 있지만 그 외의 경우에는 정지 및 휴면 상태를 유지할 수도 있는 액터에 유용합니다.
네트워크 휴면 상태 디버깅
로깅
LogNetDormancy 로그 카테고리를 활성화하여 로그에서 액터의 휴면 상태의 정보를 가져올 수 있습니다. 이 카테고리의 상세도를 높이면 액터의 휴면 상태가 플러시되는 때처럼 더 자세한 정보가 기록됩니다.
콘솔 변수
아래 테이블에는 유용할 수 있는, 네트워크 휴면 상태와 관련된 몇 개의 콘솔 변수가 포함되어 있습니다.
| 콘솔 변수 | 설명 |
|---|---|
net.DormancyEnable |
모든 액터의 휴면 상태를 완전히 활성화하거나 비활성화하는 데 사용합니다. 리플리케이션 문제가 휴면 상태와 관련되어 있는지 여부를 결정할 때 유용합니다. |
net.ReuseReplicatorsForDormantObjects |
활성화하면 서버는 액터가 휴면 상태일 때 휴면 상태 오브젝트를 소멸하고 오브젝트가 깨어날 때 다시 생성하는 대신 휴면 상태 오브젝트의 이 함수 기능은 이제 내부적으로 사용되지 않습니다. 이러한 리플리케이터를 계속 사용하면 서버의 메모리 사용량이 증가합니다. 휴면 상태 액터가 많은 프로젝트의 경우, 이런 추가 메모리 사용량이 상당할 수 있습니다. 이러한 리플리케이터를 재사용하면 서브레벨에서 액터를 리플리케이트할 때 문제가 발생할 수도 있습니다. |
net.DormancyValidate |
활성화하면 휴면 상태 중에 액터의 리플리케이트된 프로퍼티가 변경되면 로그에 경고가 인쇄됩니다.
휴면 상태 유효성 검사를 활성화하면 휴면 상태 오브젝트의 리플리케이터가 재사용되는데, 이는 휴면 상태 중에 리플리케이트된 프로퍼티를 비교하는 데 이러할 리플리케이터가 필요하기 때문입니다. |
net.DormancyHysteresis |
액터 채널이 완전히 휴면 상태가 되기 전에 대기하는 시간(초)입니다. 기본값은 0으로 설정되어 있지만, 액터가 휴면 상태를 빠르게 오가는 경우 이 값을 높이면 이탈을 방지할 수도 있습니다. |
Net.RepGraph.LogNetDormancyDetails |
활성화하면 리플리케이션 그래프가 휴면 상태의 액터를 핸들링하는 방식에 대한 더 자세한 로그가 출력됩니다. |
Net.RepGraph.DormantDynamicActorsDestruction |
활성화하면 휴면 상태 액터가 연관성이 사라질 때 클라이언트에서 소멸됩니다. 이 행동을 환경설정하는 자세한 방법은 ReplicationGraph.cpp 상단의 콘솔 변수를 참조하세요. |
언리얼 엔진의 콘솔 변수에 대한 자세한 내용은 콘솔 변수 문서 페이지를 참조하세요.