참고 자료
Actor Owner and Owning Connection
- Unreal Engine은 Server가 모든 권한을 가지는(server-authoritative) client-server model을 채용하고 있다.
- 이 model에서 client는 중앙화 된 Server에 접속하게 된다.
- Client가 Server에 접속을 하게 되면 그에 대응하는 NetConnection이 생성한다.
- 이 때 NetConnection은 PlayerController의 Owner가 된다.
- Client가 Server에서 Play를 시작하면, Player Controller은 Client가 Control 할 pawn을 possess한다.
- 이 때 PlayerController는 Pawn의 Owner가 된다.
- Actor의 Owning Connection은 Actor를 소유한 PlayerController의 Owning Connection과 연관되어 있다.
- Owner와 Owning Connection은 어느 Client에서 Replicate와 RPC를 전달해야하는지 판단한다.
용처
Actor Replication
- Actor의 변경사항을 어느 Connection에 Replicate하는지 판단이 필요.
- PlayerController와 같이 Actor를 소유한 Connection에서만 Replicate를 받는 경우에는
bOnlyRelevantToOwner 트리거가 True로 설정되어 있다.- PlayerController의 경우에는 이 플래그가 기본적으로 설정되어 있다.
Property Replication
- Owner에 따른 Property Replication 조건이 붙은 경우에 사용된다.
RPCs
- Multicast RPC가 아니라면 Client RPC가 어느 Client에 전달되어야 하는지 판단이 필요
NetRole이 ROLE_AutonomousProxy인 Actor
- 해당 Actor의 Owner가 아닌 NetConnection에 대한 Property Replication이 발생하면
Role이 ROLE_SimulatedProxy로 변경된다.
Role
/** The network role of an actor on a local/remote network context */
UENUM(BlueprintType)
enum ENetRole : int
{
/** No role at all. */
ROLE_None UMETA(DisplayName = "None"),
/** Locally simulated proxy of this actor. */
ROLE_SimulatedProxy UMETA(DisplayName = "Simulated Proxy"),
/** Locally autonomous proxy of this actor. */
ROLE_AutonomousProxy UMETA(DisplayName = "Autonomous Proxy"),
/** Authoritative control over the actor. */
ROLE_Authority UMETA(DisplayName = "Authority"),
ROLE_MAX UMETA(Hidden),
};
NetRole
ROLE_SimulatedProxy
- 수동적인(Approximate) 프록시라는 의미
- 클라이언트에서 모조(Simulated) 프록시로 동작한다.
- 기본적인 물리 동작만 Simulation하고 자체적인 판단을 하지 않는다.
ROLE_AutonomousProxy
- 능동적인(Autonomous) 프록시라는 의미
- 클라이언트에서 Simulation이 아닌 Prediction 로직을 갖는다.
ROLE_Authority
- 해당 Connection에서 Actor에 대한 완전하고 절대적인(Authoritative) 제어권을 갖는다는 뜻
Actor Role
Local Role
- 현재 자신 PC에서의 NetRole을 지칭
Remote Role
- 자신이 원격으로 연결되어 있는 PC에서의 NetRole을 지칭
Server/Client에서의 Role 값
Server
- Unreal Engine은 Replicate Actor에 대해 모든 Authority를 Server가 갖는다.
- 때문에 Server의 모든 Actor는 LocalRole이 ROLE_Authority가 된다.
- 특정 PlayerController가 Actor에 대한 Ownership을 가진 경우,
RemoteRole은 ROLE_AutonomousProxy가 된다. - 그 외의 Actor들에 대해서는 ROLE_SimulatedProxy가 된다.
Client
- 해당 Client의 Connection이 Ownership을 갖는 Actor의 경우,
Prediction이 가능하기 때문에 LocalRole이 ROLE_AutonomousProxy가 된다. - 반대로 자신이 OwnerShipe을 갖지 않는 Actor의 경우,
Simulation만이 가능하기 때문에 LocalRole이 ROLE_SimulatedProxy가 된다. - 어느 Actor든, Replicate가 되면 Authority는 Server가 가지기 때문에 RemoteRole이 ROLE_Authority가 된다.
- 단, Client에서만 존재하는 Local Actor의 경우에는 LocalRole이 ROLE_Authority,
RemoteRole이 ROLE_None이다.
Dormancy
- 가장 영향력이 강한 Network Optimize 중 하나
- Project에서 자주 Replicate 되지 않는 Actor가 많을수록 효과적이다.
- NetDriver는 Connection의 모든 Replicated Actor를 수집하고, 이를 Iterate하여 Replicate 대상을 결정한다.
- Dormancy는 특정 Actor를 Dormant 상태로 두어 NetDriver로부터 Actor가 수집되지 않도록 한다.
- Actor가 많을수록 Iterate 비용이 부담되기에 Actor 수집을 필터링하는 것은 매우 효과적이다.
사용법
- Actor의 Constructor에서 NetDormancy를 초기화
- 보통은 DORM_DormantAll로 초기화
- Actor가 Map에 배치된 경우, DORM_Initial로 초기화
- NetDormancy가 DORM_DormantAll/DORM_Initial일 때에는 Dormant 상태가 되어 Replicate가 되지 않는다.
- Dormant 상태의 Actor의 값을 변경하더라도 Awake/Flush를 하면 변경사항이 보존되지 않는다.
- Replicated Property를 변경하기 전 FlushNetDormancy/ForceNetUpdate/SetNetDormancy 함수를 호출.
- 일반적으로는 값을 변경 후 함수 호출을 해도 Replicate 될 수 있다.
- 하지만 정식 스펙 상으로는 올바른 사용법도 아니니 이를 지양해야 한다.
- 대표적으로 Fast Array의 값을 변경한 후 함수를 호출하면 변경사항이 Replicate되지 않는다.
- Replicated Property 값을 변경
- 다시 한번 강조하지만 이는 값이 자주 변경되지 않는 Replicated Actor에 적합하다.
- 너무 자주 값이 바뀌면 Dormant<->Awake/Flush 오버헤드가 발생.
- Dormancy는 Relavancy Handling과 달리 Dormant 상태가 되더라도 Server/Client 양쪽에서 Actor가 존재한다.
- Dormant Actor은 Relavancy 검증에서 제외된다.
ENetDormancy
/** Describes if an actor can enter a low network bandwidth dormant mode */
UENUM(BlueprintType)
enum ENetDormancy : int
{
/** This actor can never go network dormant. */
DORM_Never UMETA(DisplayName = "Never"),
/** This actor can go dormant, but is not currently dormant. Game code will tell it when it go dormant. */
DORM_Awake UMETA(DisplayName = "Awake"),
/** This actor wants to go fully dormant for all connections. */
DORM_DormantAll UMETA(DisplayName = "Dormant All"),
/** This actor may want to go dormant for some connections, GetNetDormancy() will be called to find out which. */
DORM_DormantPartial UMETA(DisplayName = "Dormant Partial"),
/** This actor is initially dormant for all connection if it was placed in map. */
DORM_Initial UMETA(DisplayName = "Initial"),
DORM_MAX UMETA(Hidden),
};
Awake Method
- NetDormancy 변수는 Public 접근자로 선언되어 있지만, 가급적 Awake Method 사용을 권장한다.
- 변경사항을 NetDriver에 알리는 기능이 Awake Methond에 내장되어 있다.
SetNetDormancy
/** Puts actor in dormant networking state */
UFUNCTION(BlueprintAuthorityOnly, BlueprintCallable, Category = "Networking")
ENGINE_API void SetNetDormancy(ENetDormancy NewDormancy);
void AActor::SetNetDormancy(ENetDormancy NewDormancy)
{
if (IsNetMode(NM_Client))
{
return;
}
if (IsPendingKillPending())
{
return;
}
ENetDormancy OldDormancy = NetDormancy;
NetDormancy = NewDormancy;
const bool bDormancyChanged = (OldDormancy != NewDormancy);
if (UWorld* MyWorld = GetWorld())
{
if (FWorldContext* const Context = GEngine->GetWorldContextFromWorld(MyWorld))
{
// Tell driver about change
if (bDormancyChanged)
{
for (FNamedNetDriver& Driver : Context->ActiveNetDrivers)
{
if (Driver.NetDriver != nullptr && Driver.NetDriver->ShouldReplicateActor(this))
{
Driver.NetDriver->NotifyActorDormancyChange(this, OldDormancy);
}
}
}
// If not dormant, flush actor from NetDriver's dormant list
if (NewDormancy <= DORM_Awake)
{
// Since we are coming out of dormancy, make sure we are on the network actor list
MyWorld->AddNetworkActor(this);
for (FNamedNetDriver& Driver : Context->ActiveNetDrivers)
{
if (Driver.NetDriver != nullptr && Driver.NetDriver->ShouldReplicateActor(this))
{
Driver.NetDriver->FlushActorDormancy(this);
}
}
}
}
}
}
- Dormant Actor의 NetDormancy 값을 수정해 Awake/Dormant 상태를 변경할 수 있다.
- Map에 배치된 Dormant Actor의 경우, Awake 이후 DORM_Initial 대신 DORM_DormantAll로 설정되어야 한다.
- Dormant Actor가 매 Frame마다 움직일 때 사용하면 적합하다.
FlushNetDormancy
/** Forces dormant actor to replicate but doesn't change NetDormancy state (i.e., they will go dormant again if left dormant) */
UFUNCTION(BlueprintAuthorityOnly, BlueprintCallable, Category="Networking")
ENGINE_API void FlushNetDormancy();
/** Removes the actor from the NetDriver's dormancy list: forcing at least one more update. */
void AActor::FlushNetDormancy()
{
if (IsNetMode(NM_Client) || NetDormancy <= DORM_Awake || IsPendingKillPending())
{
return;
}
QUICK_SCOPE_CYCLE_COUNTER(NET_AActor_FlushNetDormancy);
bool bWasDormInitial = false;
if (NetDormancy == DORM_Initial)
{
// No longer initially dormant
NetDormancy = DORM_DormantAll;
bWasDormInitial = true;
}
// Don't proceed with network operations if not actually set to replicate
if (!bReplicates)
{
return;
}
if (UWorld* const MyWorld = GetWorld())
{
// Add to network actors list if needed
MyWorld->AddNetworkActor(this);
if (FWorldContext* const Context = GEngine->GetWorldContextFromWorld(MyWorld))
{
for (FNamedNetDriver& Driver : Context->ActiveNetDrivers)
{
if (Driver.NetDriver != nullptr && Driver.NetDriver->ShouldReplicateActor(this))
{
Driver.NetDriver->FlushActorDormancy(this, bWasDormInitial);
}
}
}
}
}
- Dormant Actor의 변경사항을 Replicate
- Actor의 NetDormancy를 변경하지 않고도 연결된 Updates를 강제로 Replicate한다.
- 단, NetDormancy가 DORM_Initial인 Actor는 NetDormancy가 DORM_DormantAll로 변경된다.
- BP에서는 Dormant Actor의 Replicated Property를 수정하면 자동으로 FlushNetDormancy가 호출된다.
- 5.4 버전 기준, ActorComponent 한정으로 Replicated Property를 수정해도 FlushNetDormancy가 호출되지 않는다.
ForceNetUpdate
/** Force actor to be updated to clients/demo net drivers */
UFUNCTION( BlueprintCallable, Category="Networking")
ENGINE_API virtual void ForceNetUpdate();
void AActor::ForceNetUpdate()
{
UNetDriver* NetDriver = GetNetDriver();
if (GetLocalRole() == ROLE_Authority)
{
// ForceNetUpdate on the game net driver only if we are the authority...
if (NetDriver && NetDriver->GetNetMode() < ENetMode::NM_Client) // ... and not a client
{
NetDriver->ForceNetUpdate(this);
if (NetDormancy > DORM_Awake)
{
FlushNetDormancy();
}
}
}
// Even if not authority, other drivers (like the demo net driver) may need to ForceNetUpdate
if (UWorld* MyWorld = GetWorld())
{
if (FWorldContext* const Context = GEngine->GetWorldContextFromWorld(MyWorld))
{
for (FNamedNetDriver& Driver : Context->ActiveNetDrivers)
{
if (Driver.NetDriver != nullptr && Driver.NetDriver != NetDriver && Driver.NetDriver->ShouldReplicateActor(this))
{
Driver.NetDriver->ForceNetUpdate(this);
}
}
}
}
}
- FlushNetDormancy가 호출되고, 다음 NetUpdate에서 해당 Actor가 Replication 대상으로 고려된다.
- Actor가 단일 Frame에서 간헐적으로 1회성 Update를 발생하는 경우에 유용
- Actor가 Flush/Awake 된 후에 다시 Dormant 설정을 하더라도 즉시 Dormant 상태가 되지 않는다.
- 때문에 여러 Update를 전송할 수 있다.
- 해당 Actor와 SubObject에서 Replicate 되어야 할 Updates가 없을 때까지 Replicate 한다.
- 또한 DormancyHysteresis가 활성화 된 경우에도 Dormant 상태가 즉각 적용되지 않는다.
- UActorHannel::ReadyForDormancy
-
더보기
bool UActorChannel::ReadyForDormancy(bool suppressLogs) { // We need to keep replicating the Actor and its subobjects until none of them have // changes, and would otherwise go Dormant normally. if (!bIsInDormancyHysteresis) { for (auto MapIt = ReplicationMap.CreateIterator(); MapIt; ++MapIt) { if (!MapIt.Value()->ReadyForDormancy(suppressLogs)) { return false; } } } if (DormancyHysteresis > 0 && Connection && Connection->Driver) { bIsInDormancyHysteresis = true; const double TimePassed = Connection->Driver->GetElapsedTime() - LastUpdateTime; if (TimePassed < DormancyHysteresis) { return false; } } return true; }
-
- FObjectReplicator::ReadyForDormancy
-
더보기
bool FObjectReplicator::ReadyForDormancy(bool bSuppressLogs) { if (GetObject() == nullptr) { UE_LOG(LogRep, Verbose, TEXT("ReadyForDormancy: Object == nullptr")); return true; // Technically, we don't want to hold up dormancy, but the owner needs to clean us up, so we warn } // Can't go dormant until last update produced no new property updates if (!bLastUpdateEmpty) { if (!bSuppressLogs) { UE_LOG(LogRepTraffic, Verbose, TEXT(" [%d] Not ready for dormancy. bLastUpdateEmpty = false"), OwningChannel->ChIndex); } return false; } if (FSendingRepState* SendingRepState = RepState.IsValid() ? RepState->GetSendingRepState() : nullptr) { if (SendingRepState->HistoryStart != SendingRepState->HistoryEnd) { // We have change lists that haven't been acked return false; } if (SendingRepState->NumNaks > 0) { return false; } if (!SendingRepState->bOpenAckedCalled) { return false; } if (SendingRepState->PreOpenAckHistory.Num() > 0) { return false; } // Can't go dormant if there are unAckd property updates for (FPropertyRetirement& Retirement : SendingRepState->Retirement) { if (Retirement.Next != nullptr) { if (!bSuppressLogs) { UE_LOG(LogRepTraffic, Verbose, TEXT(" [%d] OutAckPacketId: %d First: %d Last: %d "), OwningChannel->ChIndex, OwningChannel->Connection->OutAckPacketId, Retirement.OutPacketIdRange.First, Retirement.OutPacketIdRange.Last); } return false; } } } return true; }
-
Awake Method를 사용해야 하는 경우
- Actor가 Awake 되면 Replicated Property의 값을 Shadow State를 Reinitialize한다.
- Shadow State는 변경된 Property와 Replicated Property를 비교하는데 사용한다.
- 때문에 Domant Actor의 Replicated Property 값을 변경 하더라도 Awake 과정에서 변경사항이 탐지되지 않는다.
Dormancy with Replication Graph
- ReplicationGraph를 사용하더라도 Dormancy는 Default NetDriver와 동일하게 동작해야 하기 때문에,
Project에서는 Actor의 Dormant/Awake 세팅과 FlushNetDormancy 호출이 동일하게 이루어진다. - ReplicationGraphNode에서 Actor List를 수집할 때 Dormant Actor가 반환되더라도 아래 함수에서 건너뛴다.
void UReplicationGraph::ReplicateActorListsForConnections_Default(UNetReplicationGraphConnection* ConnectionManager, FGatheredReplicationActorLists& GatheredReplicationListsForConnection, FNetViewerArray& Viewers)
{
//-------Skip-------//
// Skip if dormant on this connection. We want this to always be the first/quickest check.
if (ConnectionData.bDormantOnConnection)
{
DO_REPGRAPH_DETAILS(PrioritizedReplicationList.GetNextSkippedDebugDetails(Actor)->bWasDormant = true);
if (bDoCulledOnConnectionCount)
{
DormancyClassAccumulator.Increment(Actor->GetClass());
}
continue;
}
//-------Skip-------//
}
- ReplicationGraphNode는 Dormant Actor에 대한 특별한 Handling이 포함될 수 있다.
- 이를 통해 Node의 Dormant Actor 처리 시간, 메모리 뿐 아니라 Actor List의 크기도 줄일 수 있다.
- 예를 들어 ReplicationGraphNode_GridSpatialization2D의 경우,
Dormant Actor은 Static으로 취급하고 Awake Actor은 Dynamic으로 취급하는 Handling이 포함되어 있다. - 이러한 Handling은 보통은 정지 및 Dormant이지만 가끔 Grid를 통과하는 Actor에 유용하다.
Debug
Log
- LogNetDormancy 로그 카테고리를 활성화하여 Dormant 정보를 가져올 수 있다.
- 상세도를 높이면 Actor의 NetDormancy가 Flush될 때처럼 더 자세한 정보가 기록된다.
Console Command
NetPriority
- Unreal Engine의 Network Update는 Bandwidth 제한으로 모든 Actor의 Replicate를 보장하지 않는다.
- 만약 Update 용량이 Bandwidth를 초과하면 자체적인 Load Balancing을 통해 NetPriority를 할당한다.
- NetPriority가 높을수록 더 중요한 Actor이므로 더 많은 Bandwidth가 할당된다.
Actor의 NetPriority 구하기
/** Priority for this actor when checking for replication in a low bandwidth or saturated situation, higher priority means it is more likely to replicate */
UPROPERTY(Category=Replication, EditDefaultsOnly, BlueprintReadWrite)
float NetPriority;
- Actor의 Replicate 빈도 차이는 NetPriority의 비율과 일치하다.
- NetPriority가 3.0인 Actor는 1,0인 Actor보다 3배의 빈도로 Update 된다.
- 일반적으로 Actor는 1.0, Pawn과 PlayerController는 3.0의 초기값을 가진다.
Current NetPriority 구하기
/**
* Function used to prioritize actors when deciding which to replicate
* @param ViewPos Position of the viewer
* @param ViewDir Vector direction of viewer
* @param Viewer "net object" owned by the client for whom net priority is being determined (typically player controller)
* @param ViewTarget The actor that is currently being viewed/controlled by Viewer, usually a pawn
* @param InChannel Channel on which this actor is being replicated.
* @param Time Time since actor was last replicated
* @param bLowBandwidth True if low bandwidth of viewer
* @return Priority of this actor for replication, higher is more important
*/
ENGINE_API virtual float GetNetPriority(const FVector& ViewPos, const FVector& ViewDir, class AActor* Viewer, AActor* ViewTarget, UActorChannel* InChannel, float Time, bool bLowBandwidth);
/**
* Defines in NetworkDistanceConstants.h
* CLOSEPROXIMITY: 500
* NEARSIGHTTHRESHOLD: 2000
* MEDSIGHTTHREHOLD: 3162
* FARSIGHTTHRESHOLD: 8000
*/
float AActor::GetNetPriority(const FVector& ViewPos, const FVector& ViewDir, AActor* Viewer, AActor* ViewTarget, UActorChannel* InChannel, float Time, bool bLowBandwidth)
{
if (bNetUseOwnerRelevancy && Owner)
{
// If we should use our owner's priority, pass it through
return Owner->GetNetPriority(ViewPos, ViewDir, Viewer, ViewTarget, InChannel, Time, bLowBandwidth);
}
if (ViewTarget && (this == ViewTarget || GetInstigator() == ViewTarget))
{
// If we're the view target or owned by the view target, use a high priority
Time *= 4.f;
}
else if (!IsHidden() && GetRootComponent() != NULL)
{
// If this actor has a location, adjust priority based on location
FVector Dir = GetActorLocation() - ViewPos;
float DistSq = Dir.SizeSquared();
// Adjust priority based on distance and whether actor is in front of viewer
if ((ViewDir | Dir) < 0.f)
{
if (DistSq > NEARSIGHTTHRESHOLDSQUARED)
{
Time *= 0.2f;
}
else if (DistSq > CLOSEPROXIMITYSQUARED)
{
Time *= 0.4f;
}
}
else if ((DistSq < FARSIGHTTHRESHOLDSQUARED) && (FMath::Square(ViewDir | Dir) > 0.5f * DistSq))
{
// Compute the amount of distance along the ViewDir vector. Dir is not normalized
// Increase priority if we're being looked directly at
Time *= 2.f;
}
else if (DistSq > MEDSIGHTTHRESHOLDSQUARED)
{
Time *= 0.4f;
}
}
return NetPriority * Time;
}
- Base NetPriority에 Viewer와의 거리, 마지막 Replicate 이후 시간 등을 복합적으로 판단해 결정된다.
- 만약 NetPriority를 Customize하고 싶다면 이 함수를 Override해야 한다.
- 단, 이는 매우 높은 숙련도와 이해도를 요구한다.
Reference
NetRelevancy
- Level 상의 Actor들 중 Server상에서 시야 안에 들어오는 Actor들이나 Client에 영향을 Actor들만 Replicate하는 방식
- Runtime 중에 Spawn/Replicate 되는 Actor들은 Relevant 하지 않으면 Client에서 제거된다.
- 제거된 Actor의 경우에는 Client에서 더이상 보이지 않는다.
Actor의 현재 Relevancy
/**
* Checks to see if this actor is relevant for a specific network connection
*
* @param RealViewer - is the "controlling net object" associated with the client for which network relevancy is being checked (typically player controller)
* @param ViewTarget - is the Actor being used as the point of view for the RealViewer
* @param SrcLocation - is the viewing location
*
* @return bool - true if this actor is network relevant to the client associated with RealViewer
*/
ENGINE_API virtual bool IsNetRelevantFor(const AActor* RealViewer, const AActor* ViewTarget, const FVector& SrcLocation) const;
bool AActor::IsNetRelevantFor(const AActor* RealViewer, const AActor* ViewTarget, const FVector& SrcLocation) const
{
if (bAlwaysRelevant || IsOwnedBy(ViewTarget) || IsOwnedBy(RealViewer) || this == ViewTarget || ViewTarget == GetInstigator())
{
return true;
}
else if (bNetUseOwnerRelevancy && Owner)
{
return Owner->IsNetRelevantFor(RealViewer, ViewTarget, SrcLocation);
}
else if (bOnlyRelevantToOwner)
{
return false;
}
else if (RootComponent && RootComponent->GetAttachParent() && RootComponent->GetAttachParent()->GetOwner() && (Cast<USkeletalMeshComponent>(RootComponent->GetAttachParent()) || (RootComponent->GetAttachParent()->GetOwner() == Owner)))
{
return RootComponent->GetAttachParent()->GetOwner()->IsNetRelevantFor(RealViewer, ViewTarget, SrcLocation);
}
else if(IsHidden() && (!RootComponent || !RootComponent->IsCollisionEnabled()))
{
return false;
}
if (!RootComponent)
{
UE_LOG(LogNet, Warning, TEXT("Actor %s / %s has no root component in AActor::IsNetRelevantFor. (Make bAlwaysRelevant=true?)"), *GetClass()->GetName(), *GetName() );
return false;
}
return !GetDefault<AGameNetworkManager>()->bUseDistanceBasedRelevancy ||
IsWithinNetRelevancyDistance(SrcLocation);
}
- Network Driver는 IsNetRelevantFor를 통해 Actor가 각 Connection과 Relevant한지를 판단한다.
- Relevancy를 Customize하고 싶다면 이 함수를 Override해야 한다.
- 다만 Override 작업은 높은 이해도와 난이도를 요구한다.
- 참고로 Actor를 상속받은 Class 중 Pawn과 PlayerController는 위 함수를 Override하여 다른 로직으로 동작한다.
Actor Relevant 생성
/** Forces this actor to be net relevant if it is not already by default */
ENGINE_API virtual void ForceNetRelevant();
void AActor::ForceNetRelevant()
{
if ( !NeedsLoadForClient() )
{
UE_LOG(LogSpawn, Warning, TEXT("ForceNetRelevant called for actor that doesn't load on client: %s" ), *GetFullName() );
return;
}
if (RemoteRole == ROLE_None)
{
SetReplicates(true);
bAlwaysRelevant = true;
if (NetUpdateFrequency == 0.f)
{
NetUpdateFrequency = 0.1f;
}
}
ForceNetUpdate();
}
- Actor에서 ForceNetRelevant를 호출해 강제로 해당 Actor에 Relevancy를 부여할 수 있다.
Customize Relevancy Settings
- Actor를 상속받은 Class는 사진의 옵션 또는 C++에서 Relevancy Setting을 Customize 할 수 있다.
bAlwaysRelevant
- 모든 Client에서 조건 없이 Replicate 된다.
bNetUseOwnerRelevancy
- 해당 Actor의 Owner에게 Relevant 할 때에 Replicate 된다.
- 모든 Client에게 Replicate 되지 않고, Owner와 Relevant한 Client들에게만 Replicate 된다.
bOnlyRelevantToOwner
- 해당 Actor의 Owner에게 Relevant 할 때에 Owner에게만 Replicate 된다.
Reference
'UE5 > Network' 카테고리의 다른 글
[Network] Remote Procedure Calls(RPCs) (0) | 2024.06.28 |
---|---|
[Network] Property Replication (1) | 2024.06.28 |
[Network] Network Driver (0) | 2024.06.18 |
[Network] DemoNetDriver 및 Streamer (0) | 2024.06.17 |
[Network] Beacon (0) | 2024.06.17 |