일반 게임 접속을 통하지 않고 RPC를 통해 서버와 접촉해 가벼운 상호작용을 제공하는 Actor
Project에 맞는 상호작용, 로직, 정보 요청을 위한 Custom Class 확장을 권장
특수한 경우에 내장 Class를 그대로 사용 하기도 함.
OnlineBeacon
대표적인 사용 예시는 다음과 같다.
서비스 품질 정보 요청
Client가 참여하고자 하는 Game의 Slot 예약
Player 이름 목록
진행 중인 Game의 진행 시간 및 점수
AOnlineBeacon
AOnlineBeaconHost, AOnlineBeaconClient의 BaseClass
AOnlineBeaconHost
별도의 NetDriver를 사용해 Remote Client에서 들어오는 OnlineBeacon Access를 Listen.
Access를 받으면 등록된 OnlineBeaconHostObject 인스턴스를 대상으로 일치하는 Client를 탐색, 해당 Object에 Access를 넘겨준다.
이 Class는 파생 Class를 만들 필요가 없다.
Client와 등록된 OnlineBeaconHostObject 사이의 초기 접속만 관리하기 때문이다.
AOnlineBeaconClient
Host에 접속하여 실제 RPC를 생성
하나는 Client에서 생성
다른 하나는 Server의 OnlineBeaconHost에 등록된 적합한 OnlineBeaconHostObject에 의해 생성
GetBeaconType 함수를 사용해 적합한 Host Object Class의 Register Instance에 일치시킨다.
이 방식은 일반적으로 Server가 Spawn하고 Client에 Replicate하는 Actor Spawning 방식과 다르다.
하지만 Client Object와 Server Object 사이에 접속이 이루어진 후, 어느 한 쪽이 다른 쪽에 RPC를 할 수 있게 되면서 Object Replicate가 정상적으로 이루어지게 되며, Server Actor는 Property Replicate와 관련해 Authority를 가지게 된다.
OnConnected와 OnFailure 함수를 통해 접속 시 RPC를 호출하거나, 접속 실패 처리를 할 수 있다.
Beacon에서 요구하는 Client쪽 작업이 필요할 시 이 Class에서 구현되어야 한다.
AOnlineBeaconHostObject
OnlineBeaconClient Class와 짝을 이루도록 만들어져야 하는 Class
Client의 GetBeaconType() 함수의 반환값과, BeaconTypeName에 저장된 값을 일치 시켜 짝을 이룬다.
OnlineBeaconHost에 Access를 요구하는 OnlineBeaconClient에 대응하는 OnlineBeaconHostObject가 탐지 되면, OnlineBeaconHostObject::SpawnBeaconActor를 통해 OnlineBeaconClient의 사본을 Spawn
SpawnBeaconActor로 ClientBeaconActorClass 변수를 사용해 Sapwn 할 Actor Class를 결정
이 CleintBeaconActorClass가 짝을 이룬 OnlineBeaconClient Class로 설정 되어야 함.
Spawn 된 OnlineBeaconClient에서 SetBeaconOwner도 호출해야 Client와 통신을 할 수 있다.
위의 기능들은 대부분 BaseClass에서 이루어지기 때문에 Override 할 필요가 없다.
PartyBeacon
Party 기반 매치메이킹을 위해 특별히 설계된 클래스
Multiplay Game에서 파티 형성 및 GameSession 접속을 관리
PartyBeaconClient
Server에 있는 PartyBeaconHost와 통신해 Party 매치메이킹을 요청
Server에 Party 정보 전송
성공 여부를 받아 처리하는 Client Interface
PartyBeaconHost
Server에서 각 Party의 요청에 따라 GameSession 할당
PartyBeaconState
현재 Party의 상태와 Session의 예약 정보를 관리
Party 크기
Session에 접속된 Party 수
가능한 최대 Party 수
Server로부터 예약 요청 처리에 필요한 정보들을 제공
SpectatorBeacon
관전자 모드를 위한 특수 구성 요소
Multiplayer Game에서 관전자가 게임을 관찰할수 있도록 한다.
관전자가 Server에 효율적으로 접속하고, 게임 진행을 관찰할 수 있게하는 과정을 관리
SpectatorBeaconClient
Client에서 관전자가 GameServer에 접속 요청을 할 때 사용
Server의 SpectatorBeaconHost와 통신해 관전 가능한 세션을 요청, 입장 승인 여부를 확인
일반적으로 Replicate되는 Actor들은 매 Tick마다 해당 Actor가 Replicate될지 말지 판단을 한다.
게임이 클수록, 동시접속자가 많을수록 CPU 병목현상이 발생하기 쉬워짐
Replication Graph는 Actor 단위의 Replicate 판단 여부를 Node 단위로 묶어서 비용을 감소시킨다.
동작 방식
기본적인 동작 방식은 이전의 Actor Replicate와 크게 다르지 않다.
특정 공간 안의 Actor를 별도로 관리(Spatial Partitioning)
대상 클라이언트로부터 먼 거리의 Actor를 제외 (Relevancy Culling)
Replicate 빈도 관리 (Frequency Control)
ReplicationGraphNode
동일한 조건으로 Replicate 되어야 할 Actor를 하나로 묶어주는 단위
BaseClass인 UReplicationGraphNode는 Pure Virtual Function이 있어서 반드시 이를 상속 받은 Class를 써야 한다.
최소 아래 함수들은 반드시 Implement 되어야 한다.
/** Override this function to initialize the per-class data for replication */
//Initialize UReplicationGraph::GlobalActorReplicationInfoMap.
virtual void InitGlobalActorClassSettings();
/** Override this function to init/configure your project's Global Graph */
//Instantiate new UGraphNodes via ::CreateNewNode. Use ::AddGlobalGraphNode if they are global (for all connections).
virtual void InitGlobalGraphNodes();
//Route actor spawning/despawning to the right node. (Or your nodes can gather the actors themselves)
virtual void RouteAddNetworkActorToNodes(const FNewReplicatedActorInfo& ActorInfo, FGlobalActorReplicationInfo& GlobalInfo);
virtual void RouteRemoveNetworkActorToNodes(const FNewReplicatedActorInfo& ActorInfo);
/** Override this function to init/configure graph for a specific connection. Note they do not all have to be unique: connections can share nodes (e.g, 2 nodes for 2 teams) */
//Initialize per-connection nodes (or associate shared nodes with them via ::AddConnectionGraphNode)
virtual void InitConnectionGraphNodes(UNetReplicationGraphConnection* ConnectionManager);
Node 안에 별도의 Child Node를 가질 수 있다.
ReplicationGraphNode_ActorList
간단한 Actor 목록을 관리
복잡한 Frequency나 Relevancy 로직 없이 관리 된다.
소규모 목록에서 사용할 때 유용
ReplicationGraphNode_ActorListFrequencyBuckets
Replicate 빈도에 따라 Actor들을 Bucket 단위로 관리
다양한 간격으로 업데이트가 필요한 Actor를 관리할 때 유용
ReplicationGraphNode_AlwaysRelevant
위치, 상태와 관계 없이 모든 Client에게 항상 Replicate 되어야 하는 경우
GameMode, Controller, GameState와 같은 GamePlay에 주요한 Actor에게 적합
ReplicationGraphNode_AlwaysRelevant_ForConnection
AlwaysRelevant와 유사하지만 그 대상을 특정 Client에게만 제한할 수 있다.
특정 Player에게 필수적인 Actor를 Replicate할 때 적합
ReplicationGraphNode_ConnectionDormancyNode
비활성화 될 여지가 있는 Actor들에 적합
또는 배경의 Actor와 같이 업데이트를 제한하여 자원을 최적화 하는데 적합
ReplicationGraphNode_DormancyNode
Actor가 활성화 될 때 모든 Client에 Replicate되어야 하는 경우
간헐적으로 활성화 되는 Actor들에게 유용
ReplicationGraphNode_DynamicSpatialFrequency
공간적 조건에 따라 Replicate 빈도를 동적으로 조절
Player의 이동이나 게임 내 Event로 인해 Relevancy가 자주 변경되는 환경에 이상적
ReplicationGraphNode_GridSpatialization2D
World를 Grid로 나누고, Grid 위치에 따라 Replicate를 관리
넓은 오픈월드 게임에서 플레이어 주변 Actor만 업데이트하여 네트워크 트래픽 최적화
ReplicationGraphNode_TearOff_ForConnnection
Tear Off(서버에서 어느정도 분리된 상태)된 Actor들을 관리
해당 Actor들을 새로운 Client에 적절하게 Replicate 되도록 보장
Actor가 급격하게 변경되는 빠른 페이스의 액션이나 파괴 시나리오에서 사용됨.
ReplicationGraph
Replication Driver의 기능을 확장한 Class
다수의 ReplicationGraphNode를 관리한다.
작업 방식
Node 추가
기존에 만들었던 ReplicationGraphNode를 InitGlobalGraphNodes에서 생성, 추가한다.
RouteAddNetworkActorToNodes에서 등록된 Node를 통해 NotifyAddNetworkActor로 Actor 등록
void UReplicationGraph::AddNetworkActor(AActor* Actor)
{
LLM_SCOPE_BYTAG(NetRepGraph);
QUICK_SCOPE_CYCLE_COUNTER(UReplicationGraph_AddNetworkActor);
if (IsActorValidForReplicationGather(Actor) == false)
{
return;
}
if (NetDriver && !NetDriver->ShouldReplicateActor(Actor))
{
return;
}
bool bWasAlreadyThere = false;
ActiveNetworkActors.Add(Actor, &bWasAlreadyThere);
if (bWasAlreadyThere)
{
// Guarding against double adds
return;
}
ensureMsgf(!Actor->bNetTemporary, TEXT("ReplicationGraph does not support bNetTemporary. Actor: %s has bNetTemporary set."), *Actor->GetPathName());
// Create global rep info
FGlobalActorReplicationInfo& GlobalInfo = GlobalActorReplicationInfoMap.Get(Actor);
GlobalInfo.bWantsToBeDormant = Actor->NetDormancy > DORM_Awake;
RouteAddNetworkActorToNodes(FNewReplicatedActorInfo(Actor), GlobalInfo);
}
void UReplicationGraph::RouteAddNetworkActorToNodes(const FNewReplicatedActorInfo& ActorInfo, FGlobalActorReplicationInfo& GlobalInfo)
{
// The base implementation just routes to every global node. Subclasses will want a more direct routing function where possible.
for (UReplicationGraphNode* Node : GlobalGraphNodes)
{
Node->NotifyAddNetworkActor(ActorInfo);
}
}
Node 탐색
매 Tick마다 ServerReplicateActors를 호출
함수 내부에서 조건에 맞는 Node를 FNewReplicatedActorInfo로 검색
/** This is the struct we use to push new replication actors into the graph. "New" doesn't mean "newly spawned" it means "new to the graph". FIXME: Please suggest a better name! */
struct FNewReplicatedActorInfo
{
explicit FNewReplicatedActorInfo(const FActorRepListType& InActor) : Actor(InActor), Class(InActor->GetClass())
{
StreamingLevelName = GetStreamingLevelNameOfActor(Actor);
}
explicit FNewReplicatedActorInfo(const FActorRepListType& InActor, FName OverrideLevelName)
: Actor(InActor)
, StreamingLevelName(OverrideLevelName)
, Class(InActor->GetClass())
{
}
AActor* GetActor() const { return Actor; }
REPLICATIONGRAPH_API static FName GetStreamingLevelNameOfActor(const AActor* Actor);
FActorRepListType Actor;
FName StreamingLevelName;
UClass* Class;
};
설정 방법
ini 파일 설정
Project의 Default.ini에서 아래와 같이 ReplicationDriverClassName 추가