Add some optional handling of replicated actor outer changes on servers.

-Only supports dynamically spawned actors, not placed actors
-UNetDriver::NotifyActorRenamed now has a PreviousOuter parameter
-Net driver notifies any ReplicationDriver (replication graph) of actor renames
-ReplicationGraph APIs added to update internal actor level tracking (this can be toggled with the cvar Net.RepGraph.HandleDynamicActorRename)
-Added cvar net.CleanUpRenamedDynamicActors that will tell clients to destroy an actor if the server moves it to a level that's not currently visible on the client (disabled by default to preserve current behavior)

#jira UE-201875
#rb LouisPhilippe.Seguin
[FYI] Todd.Eckert, Jon.Sourbeer

[CL 32491240 by ryan gerleve in 5.4 branch]
This commit is contained in:
ryan gerleve
2024-03-25 19:07:44 -04:00
parent e502ebc530
commit 00aca8b9e6
13 changed files with 483 additions and 13 deletions
@@ -143,6 +143,32 @@ void UBasicReplicationGraph::RouteRemoveNetworkActorToNodes(const FNewReplicated
}
}
void UBasicReplicationGraph::RouteRenameNetworkActorToNodes(const FRenamedReplicatedActorInfo& ActorInfo)
{
#if WITH_GAMEPLAY_DEBUGGER
if (ActorInfo.NewActorInfo.Actor->IsA(AGameplayDebuggerCategoryReplicator::StaticClass()))
{
return;
}
#endif
if (ActorInfo.NewActorInfo.Actor->bAlwaysRelevant)
{
AlwaysRelevantNode->NotifyActorRenamed(ActorInfo);
}
else if (ActorInfo.NewActorInfo.Actor->bOnlyRelevantToOwner)
{
if (UReplicationGraphNode* Node = ActorInfo.NewActorInfo.Actor->GetNetConnection() ? GetAlwaysRelevantNodeForConnection(ActorInfo.NewActorInfo.Actor->GetNetConnection()) : nullptr)
{
Node->NotifyActorRenamed(ActorInfo);
}
}
else
{
GridNode->RenameActor_Dormancy(ActorInfo);
}
}
UReplicationGraphNode_AlwaysRelevant_ForConnection* UBasicReplicationGraph::GetAlwaysRelevantNodeForConnection(UNetConnection* Connection)
{
UReplicationGraphNode_AlwaysRelevant_ForConnection* Node = nullptr;
@@ -73,6 +73,9 @@ namespace UE::Net::Private
constexpr int32 RepGraphDormantActorsListReservedBuffer = 2048;
// TInlineAllocator's size is optimized for default DestroyDormantDynamicActorsCellTTL value
constexpr int32 RepGraphDormancyNodesInlineBufferSize = 200;
int32 CVar_RepGraph_HandleDynamicActorRename = 0;
static FAutoConsoleVariableRef CVarRepGraphHandleDynamicActorRename(TEXT("Net.RepGraph.HandleDynamicActorRename"), CVar_RepGraph_HandleDynamicActorRename, TEXT("If nonzero, when a dynamic actor's outer/level changes, repgraph will update its cached level information."));
}
int32 CVar_RepGraph_Pause = 0;
@@ -811,6 +814,17 @@ void UReplicationGraph::RouteRemoveNetworkActorToNodes(const FNewReplicatedActor
}
}
void UReplicationGraph::RouteRenameNetworkActorToNodes(const FRenamedReplicatedActorInfo& ActorInfo)
{
QUICK_SCOPE_CYCLE_COUNTER(UReplicationGraph_RouteRenameNetworkActorToNodes);
// The base implementation just routes to every global node. Subclasses will want a more direct routing function where possible.
for (UReplicationGraphNode* Node : GlobalGraphNodes)
{
Node->NotifyActorRenamed(ActorInfo);
}
}
void UReplicationGraph::ForceNetUpdate(AActor* Actor)
{
if (FGlobalActorReplicationInfo* RepInfo = GlobalActorReplicationInfoMap.Find(Actor))
@@ -967,6 +981,32 @@ void UReplicationGraph::NotifyActorDormancyChange(AActor* Actor, ENetDormancy Ol
}
}
void UReplicationGraph::NotifyActorRenamed(AActor* Actor, UObject* PreviousOuter, FName PreviousName)
{
QUICK_SCOPE_CYCLE_COUNTER(UReplicationGraph_NotifyActorRenamed);
CSV_CUSTOM_STAT(ReplicationGraph, NumActorRenames, 1, ECsvCustomStatOp::Accumulate);
if (!IsActorValidForReplication(Actor))
{
UE_LOG(LogReplicationGraph, Warning, TEXT("UReplicationGraph::NotifyActorRenamed %s. Actor invalid for replication."), *GetFullNameSafe(Actor));
return;
}
const bool bIsActorDynamic = !Actor->IsFullNameStableForNetworking();
if (UE::Net::Private::CVar_RepGraph_HandleDynamicActorRename && bIsActorDynamic)
{
ULevel* PreviousLevel = Cast<ULevel>(PreviousOuter);
FName PreviousStreamingLevelName = (PreviousLevel && PreviousLevel->IsPersistentLevel() == false) ? PreviousLevel->GetOutermost()->GetFName() : NAME_None;
// Fix up dependencies in global list
GlobalActorReplicationInfoMap.NotifyActorRenamed(Actor, PreviousStreamingLevelName);
FRenamedReplicatedActorInfo RenameInfo(Actor, PreviousStreamingLevelName);
RouteRenameNetworkActorToNodes(RenameInfo);
}
}
FORCEINLINE bool ReadyForNextReplication(FConnectionReplicationActorInfo& ConnectionData, FGlobalActorReplicationInfo& GlobalData, const uint32 FrameNum)
{
return (ConnectionData.NextReplicationFrameNum <= FrameNum || GlobalData.ForceNetUpdateFrame > ConnectionData.LastRepFrameNum);
@@ -3354,6 +3394,20 @@ bool FStreamingLevelActorListCollection::RemoveActorFast(const FNewReplicatedAct
return bRemovedSomething;
}
bool FStreamingLevelActorListCollection::RemoveActorFromLevelFast(AActor* Actor, FName LevelName)
{
bool bRemovedSomething = false;
for (FStreamingLevelActors& StreamingList : StreamingLevelLists)
{
if (StreamingList.StreamingLevelName == LevelName)
{
bRemovedSomething = StreamingList.ReplicationActorList.RemoveFast(Actor);
break;
}
}
return bRemovedSomething;
}
void FStreamingLevelActorListCollection::Reset()
{
for (FStreamingLevelActors& StreamingList : StreamingLevelLists)
@@ -3510,6 +3564,17 @@ bool UReplicationGraphNode_ActorList::NotifyRemoveNetworkActor(const FNewReplica
return bRemovedSomething;
}
bool UReplicationGraphNode_ActorList::NotifyActorRenamed(const FRenamedReplicatedActorInfo& ActorInfo, bool bWarnIfNotFound)
{
const bool bRemovedSomething = NotifyRemoveNetworkActor(ActorInfo.OldActorInfo, bWarnIfNotFound);
if (bRemovedSomething)
{
NotifyAddNetworkActor(ActorInfo.NewActorInfo);
}
return bRemovedSomething;
}
/** Removes the actor very quickly but breaks the list order */
bool UReplicationGraphNode_ActorList::RemoveNetworkActorFast(const FNewReplicatedActorInfo& ActorInfo)
{
@@ -3727,6 +3792,17 @@ bool UReplicationGraphNode_ActorListFrequencyBuckets::NotifyRemoveNetworkActor(c
return bRemovedSomething;
}
bool UReplicationGraphNode_ActorListFrequencyBuckets::NotifyActorRenamed(const FRenamedReplicatedActorInfo& ActorInfo, bool bWarnIfNotFound)
{
const bool bRemovedSomething = NotifyRemoveNetworkActor(ActorInfo.OldActorInfo, bWarnIfNotFound);
if (bRemovedSomething)
{
NotifyAddNetworkActor(ActorInfo.NewActorInfo);
}
return bRemovedSomething;
}
void UReplicationGraphNode_ActorListFrequencyBuckets::NotifyResetAllNetworkActors()
{
for (FActorRepListRefView& List : NonStreamingCollection)
@@ -4676,6 +4752,19 @@ bool UReplicationGraphNode_ConnectionDormancyNode::NotifyRemoveNetworkActor(cons
return RemovedStreamingLevelActorListCollection.RemoveActorFast(ActorInfo, this);
}
bool UReplicationGraphNode_ConnectionDormancyNode::NotifyActorRenamed(const FRenamedReplicatedActorInfo& ActorInfo, bool bWarnIfNotFound)
{
bool bMovedSomething = Super::NotifyActorRenamed(ActorInfo, bWarnIfNotFound);
const bool bRemovedSomething = RemovedStreamingLevelActorListCollection.RemoveActorFromLevelFast(ActorInfo.NewActorInfo.Actor, ActorInfo.OldActorInfo.StreamingLevelName);
if (bRemovedSomething)
{
RemovedStreamingLevelActorListCollection.AddActor(ActorInfo.NewActorInfo);
}
return bMovedSomething || bRemovedSomething;
}
void UReplicationGraphNode_ConnectionDormancyNode::NotifyResetAllNetworkActors()
{
Super::NotifyResetAllNetworkActors();
@@ -4810,6 +4899,30 @@ void UReplicationGraphNode_DormancyNode::RemoveDormantActor(const FNewReplicated
CallFunctionOnValidConnectionNodes(RemoveActorFunction);
}
void UReplicationGraphNode_DormancyNode::RenameDormantActor(const FRenamedReplicatedActorInfo& ActorInfo)
{
// Set up a FNewReplicatedActorInfo with the old level name so that the remove can find the actor
Super::RemoveNetworkActorFast(ActorInfo.OldActorInfo);
auto RemoveActorFunction = [ActorInfo](UReplicationGraphNode_ConnectionDormancyNode* ConnectionNode)
{
// Don't warn if not found, the node may have removed the actor itself. Not worth the extra bookkeeping to skip the call.
ConnectionNode->NotifyRemoveNetworkActor(ActorInfo.OldActorInfo, false);
};
CallFunctionOnValidConnectionNodes(RemoveActorFunction);
// Add using new outer
Super::NotifyAddNetworkActor(ActorInfo.NewActorInfo);
auto AddActorFunction = [&ActorInfo](UReplicationGraphNode_ConnectionDormancyNode* ConnectionNode)
{
QUICK_SCOPE_CYCLE_COUNTER(ConnectionDormancyNode_NotifyAddNetworkActor);
ConnectionNode->NotifyAddNetworkActor(ActorInfo.NewActorInfo);
};
CallFunctionOnValidConnectionNodes(AddActorFunction);
}
void UReplicationGraphNode_DormancyNode::GatherActorListsForConnection(const FConnectionGatherActorListParameters& Params)
{
#if WITH_SERVER_CODE
@@ -5019,6 +5132,23 @@ void UReplicationGraphNode_GridCell::RemoveDynamicActor(const FNewReplicatedActo
GetDynamicNode()->NotifyRemoveNetworkActor(ActorInfo);
}
void UReplicationGraphNode_GridCell::RenameStaticActor(const FRenamedReplicatedActorInfo& ActorInfo, bool bWasAddedAsDormantActor)
{
if (bWasAddedAsDormantActor)
{
GetDormancyNode()->RenameDormantActor(ActorInfo);
}
else
{
Super::NotifyActorRenamed(ActorInfo);
}
}
void UReplicationGraphNode_GridCell::RenameDynamicActor(const FRenamedReplicatedActorInfo& ActorInfo)
{
GetDynamicNode()->NotifyActorRenamed(ActorInfo);
}
void UReplicationGraphNode_GridCell::ConditionalCopyDormantActors(FActorRepListRefView& FromList, UReplicationGraphNode_DormancyNode* ToNode)
{
if (GraphGlobals.IsValid())
@@ -5137,6 +5267,12 @@ bool UReplicationGraphNode_GridSpatialization2D::NotifyRemoveNetworkActor(const
return false;
}
bool UReplicationGraphNode_GridSpatialization2D::NotifyActorRenamed(const FRenamedReplicatedActorInfo& ActorInfo, bool bWarnIfNotFound)
{
ensureAlwaysMsgf(false, TEXT("UReplicationGraphNode_GridSpatialization2D::NotifyActorRenamed should not be called directly"));
return false;
}
void UReplicationGraphNode_GridSpatialization2D::AddActor_Dormancy(const FNewReplicatedActorInfo& ActorInfo, FGlobalActorReplicationInfo& ActorRepInfo)
{
UE_CLOG(CVar_RepGraph_LogActorRemove>0, LogReplicationGraph, Display, TEXT("UReplicationGraphNode_GridSpatialization2D::AddActor_Dormancy %s on %s"), *ActorInfo.Actor->GetFullName(), *GetPathName());
@@ -5189,6 +5325,22 @@ void UReplicationGraphNode_GridSpatialization2D::RemoveActor_Dormancy(const FNew
}
}
void UReplicationGraphNode_GridSpatialization2D::RenameActor_Dormancy(const FRenamedReplicatedActorInfo& ActorInfo)
{
if (GraphGlobals.IsValid())
{
FGlobalActorReplicationInfo& ActorRepInfo = GraphGlobals->GlobalActorReplicationInfoMap->Get(ActorInfo.NewActorInfo.Actor);
if (ActorRepInfo.bWantsToBeDormant)
{
RenameActor_Static(ActorInfo);
}
else
{
RenameActor_Dynamic(ActorInfo);
}
}
}
void UReplicationGraphNode_GridSpatialization2D::AddActorInternal_Dynamic(const FNewReplicatedActorInfo& ActorInfo)
{
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
@@ -5328,6 +5480,61 @@ void UReplicationGraphNode_GridSpatialization2D::RemoveActorInternal_Static(cons
}
}
void UReplicationGraphNode_GridSpatialization2D::RenameActor_Static(const FRenamedReplicatedActorInfo& ActorInfo)
{
FCachedStaticActorInfo* StaticFoundInfo = StaticSpatializedActors.Find(ActorInfo.NewActorInfo.Actor);
if (StaticFoundInfo)
{
StaticFoundInfo->ActorInfo.StreamingLevelName = ActorInfo.NewActorInfo.StreamingLevelName;
}
else
{
UE_LOG(LogReplicationGraph, Warning, TEXT("UReplicationGraphNode_GridSpatialization2D::RenameActor_Static attempted rename %s from static list but it was not there."), *GetActorRepListTypeDebugString(ActorInfo.NewActorInfo.Actor));
FCachedDynamicActorInfo* DynamicFoundInfo = DynamicSpatializedActors.Find(ActorInfo.NewActorInfo.Actor);
if (DynamicFoundInfo)
{
DynamicFoundInfo->ActorInfo.StreamingLevelName = ActorInfo.NewActorInfo.StreamingLevelName;
UE_LOG(LogReplicationGraph, Warning, TEXT(" It was in DynamicSpatializedActors!"));
}
}
// Remove it from the actual node it should still be in. Note that even if the actor did move in between this and the last replication frame, the FGlobalActorReplicationInfo would not have been updated
FGlobalActorReplicationInfo& GlobalInfo = GraphGlobals->GlobalActorReplicationInfoMap->Get(ActorInfo.NewActorInfo.Actor);
GetGridNodesForActor(ActorInfo.NewActorInfo.Actor, GlobalInfo, GatheredNodes);
for (UReplicationGraphNode_GridCell* Node : GatheredNodes)
{
Node->RenameStaticActor(ActorInfo, GlobalInfo.bWantsToBeDormant);
}
}
void UReplicationGraphNode_GridSpatialization2D::RenameActor_Dynamic(const FRenamedReplicatedActorInfo& ActorInfo)
{
FCachedDynamicActorInfo* DynamicFoundInfo = DynamicSpatializedActors.Find(ActorInfo.NewActorInfo.Actor);
if (DynamicFoundInfo)
{
if (DynamicFoundInfo->CellInfo.IsValid())
{
GetGridNodesForActor(ActorInfo.NewActorInfo.Actor, DynamicFoundInfo->CellInfo, GatheredNodes);
for (UReplicationGraphNode_GridCell* Node : GatheredNodes)
{
Node->RenameDynamicActor(ActorInfo);
}
}
DynamicFoundInfo->ActorInfo.StreamingLevelName = ActorInfo.NewActorInfo.StreamingLevelName;
}
else
{
UE_LOG(LogReplicationGraph, Warning, TEXT("UReplicationGraphNode_GridSpatialization2D::RenameActor_Dynamic attempted rename %s from streaming dynamic list but it was not there."), *GetActorRepListTypeDebugString(ActorInfo.NewActorInfo.Actor));
FCachedStaticActorInfo* StaticFoundInfo = StaticSpatializedActors.Find(ActorInfo.NewActorInfo.Actor);
if (StaticFoundInfo)
{
StaticFoundInfo->ActorInfo.StreamingLevelName = ActorInfo.NewActorInfo.StreamingLevelName;
UE_LOG(LogReplicationGraph, Warning, TEXT(" It was in StaticSpatializedActors!"));
}
}
}
void UReplicationGraphNode_GridSpatialization2D::OnNetDormancyChange(FActorRepListType Actor, FGlobalActorReplicationInfo& GlobalInfo, ENetDormancy NewValue, ENetDormancy OldValue)
{
const bool bCurrentShouldBeStatic = NewValue > DORM_Awake;
@@ -443,6 +443,20 @@ int32 FGlobalActorReplicationInfoMap::Remove(const FActorRepListType& RemovedAct
return ActorMap.Remove(RemovedActor);
}
void FGlobalActorReplicationInfoMap::NotifyActorRenamed(AActor* Actor, FName PreviousStreamingLevelName)
{
if (FGlobalActorReplicationInfo* RenamedActorInfo = Find(Actor))
{
// Update the dependent lists of this renamed actor's parents
for (AActor* ParentActor : RenamedActorInfo->ParentActorList)
{
if (FGlobalActorReplicationInfo* ParentActorInfo = Find(ParentActor))
{
ParentActorInfo->DependentActorList.UpdateActorLevel(Actor, PreviousStreamingLevelName);
}
}
}
}
void FGlobalActorReplicationInfoMap::AddDependentActor(AActor* Parent, AActor* Child, FGlobalActorReplicationInfoMap::EWarnFlag WarnFlag)
{
@@ -697,3 +711,26 @@ void FLevelBasedActorList::CountBytes(FArchive& Ar) const
PermanentLevelActors.CountBytes(Ar);
StreamingLevelActors.CountBytes(Ar);
}
void FLevelBasedActorList::UpdateActorLevel(AActor* NetActor, FName PreviousStreamingLevelName)
{
bool bRemovedActor = false;
if (PreviousStreamingLevelName == NAME_None)
{
bRemovedActor = PermanentLevelActors.RemoveFast(NetActor);
}
else
{
bRemovedActor = StreamingLevelActors.RemoveActorFromLevelFast(NetActor, PreviousStreamingLevelName);
}
if (bRemovedActor)
{
AddNetworkActor(NetActor);
}
else
{
UE_LOG(LogReplicationGraph, Warning, TEXT("FLevelBasedActorList::UpdateActorLevel did not find existing actor %s in level lists"), *GetFullNameSafe(NetActor));
}
}
@@ -50,6 +50,10 @@ public:
virtual void RouteAddNetworkActorToNodes(const FNewReplicatedActorInfo& ActorInfo, FGlobalActorReplicationInfo& GlobalInfo) override;
virtual void RouteRemoveNetworkActorToNodes(const FNewReplicatedActorInfo& ActorInfo) override;
protected:
virtual void RouteRenameNetworkActorToNodes(const FRenamedReplicatedActorInfo& ActorInfo) override;
public:
virtual int32 ServerReplicateActors(float DeltaSeconds) override;
UPROPERTY()
@@ -80,6 +80,13 @@ public:
/** Called when a networked actor is being destroyed or no longer wants to replicate */
virtual bool NotifyRemoveNetworkActor(const FNewReplicatedActorInfo& Actor, bool bWarnIfNotFound=true) PURE_VIRTUAL(UReplicationGraphNode::NotifyRemoveNetworkActor, return false; );
/**
* If Net.RepGraph.HandleDynamicActorRename is enabled, this is called when a dynamic actor is changing its outer.
* If the node maintains level information for actors, and if replicated actors may be renamed, the implementation needs to update its level info.
* Returns true if the actor was found & updated.
*/
virtual bool NotifyActorRenamed(const FRenamedReplicatedActorInfo& Actor, bool bWarnIfNotFound=true) PURE_VIRTUAL(UReplicationGraphNode::NotifyActorRenamed, return false; );
/** Called when world changes or when all subclasses should dump any persistent data/lists about replicated actors here. (The new/next world will be set before this is called) */
virtual void NotifyResetAllNetworkActors();
@@ -187,6 +194,8 @@ public:
virtual bool NotifyRemoveNetworkActor(const FNewReplicatedActorInfo& ActorInfo, bool bWarnIfNotFound=true) override;
virtual bool NotifyActorRenamed(const FRenamedReplicatedActorInfo& ActorInfo, bool bWarnIfNotFound=true) override;
virtual void NotifyResetAllNetworkActors() override;
virtual void GatherActorListsForConnection(const FConnectionGatherActorListParameters& Params) override;
@@ -270,6 +279,8 @@ public:
virtual bool NotifyRemoveNetworkActor(const FNewReplicatedActorInfo& ActorInfo, bool bWarnIfNotFound=true) override;
virtual bool NotifyActorRenamed(const FRenamedReplicatedActorInfo& ActorInfo, bool bWarnIfNotFound=true) override;
virtual void NotifyResetAllNetworkActors() override;
virtual void GatherActorListsForConnection(const FConnectionGatherActorListParameters& Params) override;
@@ -438,6 +449,7 @@ public:
virtual void GatherActorListsForConnection(const FConnectionGatherActorListParameters& Params) override;
virtual bool NotifyRemoveNetworkActor(const FNewReplicatedActorInfo& ActorInfo, bool WarnIfNotFound) override;
virtual bool NotifyActorRenamed(const FRenamedReplicatedActorInfo& ActorInfo, bool bWarnIfNotFound=true) override;
virtual void NotifyResetAllNetworkActors() override;
virtual void VerifyActorReferencesInternal() override;
@@ -481,10 +493,12 @@ public:
virtual void NotifyAddNetworkActor(const FNewReplicatedActorInfo& ActorInfo) override { ensureMsgf(false, TEXT("UReplicationGraphNode_DormancyNode::NotifyAddNetworkActor not functional.")); }
virtual bool NotifyRemoveNetworkActor(const FNewReplicatedActorInfo& ActorInfo, bool bWarnIfNotFound=true) override { ensureMsgf(false, TEXT("UReplicationGraphNode_DormancyNode::NotifyRemoveNetworkActor not functional.")); return false; }
virtual bool NotifyActorRenamed(const FRenamedReplicatedActorInfo& ActorInfo, bool bWarnIfNotFound=true) override { ensureMsgf(false, TEXT("UReplicationGraphNode_DormancyNode::NotifyActorRenamed not functional.")); return false; }
virtual void NotifyResetAllNetworkActors() override;
void AddDormantActor(const FNewReplicatedActorInfo& ActorInfo, FGlobalActorReplicationInfo& GlobalInfo);
void RemoveDormantActor(const FNewReplicatedActorInfo& ActorInfo, FGlobalActorReplicationInfo& ActorRepInfo);
void RenameDormantActor(const FRenamedReplicatedActorInfo& ActorInfo);
virtual void GatherActorListsForConnection(const FConnectionGatherActorListParameters& Params) override;
@@ -533,6 +547,9 @@ public:
void RemoveStaticActor(const FNewReplicatedActorInfo& ActorInfo, FGlobalActorReplicationInfo& ActorRepInfo, bool bWasAddedAsDormantActor);
void RemoveDynamicActor(const FNewReplicatedActorInfo& ActorInfo);
void RenameStaticActor(const FRenamedReplicatedActorInfo& ActorInfo, bool bWasAddedAsDormantActor);
void RenameDynamicActor(const FRenamedReplicatedActorInfo& ActorInfo);
// Allow graph to override function for creating the dynamic node in the cell
TFunction<UReplicationGraphNode*(UReplicationGraphNode_GridCell* Parent)> CreateDynamicNodeOverride;
@@ -569,6 +586,7 @@ public:
virtual void NotifyAddNetworkActor(const FNewReplicatedActorInfo& Actor) override;
virtual bool NotifyRemoveNetworkActor(const FNewReplicatedActorInfo& ActorInfo, bool bWarnIfNotFound=true) override;
virtual bool NotifyActorRenamed(const FRenamedReplicatedActorInfo& Actor, bool bWarnIfNotFound=true) override;
virtual void NotifyResetAllNetworkActors() override;
virtual void PrepareForReplication() override;
virtual void GatherActorListsForConnection(const FConnectionGatherActorListParameters& Params) override;
@@ -582,7 +600,10 @@ public:
void RemoveActor_Static(const FNewReplicatedActorInfo& ActorInfo);
void RemoveActor_Dynamic(const FNewReplicatedActorInfo& ActorInfo) { RemoveActorInternal_Dynamic(ActorInfo); }
void RemoveActor_Dormancy(const FNewReplicatedActorInfo& ActorInfo);
void RenameActor_Static(const FRenamedReplicatedActorInfo& ActorInfo);
void RenameActor_Dynamic(const FRenamedReplicatedActorInfo& ActorInfo);
void RenameActor_Dormancy(const FRenamedReplicatedActorInfo& ActorInfo);
// Called if cull distance changes. Note the caller must update Global/Connection actor rep infos. This just changes cached state within this node
virtual void NotifyActorCullDistChange(AActor* Actor, FGlobalActorReplicationInfo& GlobalInfo, float OldDist);
@@ -755,6 +776,7 @@ public:
virtual void NotifyAddNetworkActor(const FNewReplicatedActorInfo& Actor) override { }
virtual bool NotifyRemoveNetworkActor(const FNewReplicatedActorInfo& ActorInfo, bool bWarnIfNotFound=true) override { return false; }
virtual bool NotifyActorRenamed(const FRenamedReplicatedActorInfo& Actor, bool bWarnIfNotFound=true) override { return false; }
virtual void NotifyResetAllNetworkActors() override { }
virtual void PrepareForReplication() override;
virtual void GatherActorListsForConnection(const FConnectionGatherActorListParameters& Params) override;
@@ -870,6 +892,7 @@ public:
virtual void NotifyAddNetworkActor(const FNewReplicatedActorInfo& ActorInfo) override { }
virtual bool NotifyRemoveNetworkActor(const FNewReplicatedActorInfo& ActorInfo, bool bWarnIfNotFound=true) override { return false; }
virtual bool NotifyActorRenamed(const FRenamedReplicatedActorInfo& Actor, bool bWarnIfNotFound=true) override { return false; }
virtual void NotifyResetAllNetworkActors() override { TearOffActors.Reset(); }
virtual void GatherActorListsForConnection(const FConnectionGatherActorListParameters& Params) override;
virtual void LogNode(FReplicationGraphDebugInfo& DebugInfo, const FString& NodeName) const override;
@@ -942,6 +965,7 @@ public:
virtual void NotifyActorFullyDormantForConnection(AActor* Actor, UNetConnection* Connection) override;
virtual void NotifyActorDormancyChange(AActor* Actor, ENetDormancy OldDormancyState) override;
virtual void NotifyDestructionInfoCreated(AActor* Actor, FActorDestructionInfo& DestructionInfo) override {}
virtual void NotifyActorRenamed(AActor* Actor, UObject* PreviousOuter, FName PreviousName) override;
virtual void SetRoleSwapOnReplicate(AActor* Actor, bool bSwapRoles) override;
virtual bool ProcessRemoteFunction(class AActor* Actor, UFunction* Function, void* Parameters, FOutParmRec* OutParms, FFrame* Stack, class UObject* SubObject) override;
virtual int32 ServerReplicateActors(float DeltaSeconds) override;
@@ -1091,6 +1115,9 @@ protected:
/** Sets the next timeout frame for the actors in the list along with their dependent actors */
void HandleStarvedActorList(const UNetReplicationGraphConnection& RepGraphConnection, const FPrioritizedRepList& List, int32 StartIdx, FPerConnectionActorInfoMap& ConnectionActorInfoMap, uint32 FrameNum);
/** Routes a rename/outer change to every global node. Subclasses will want a more direct routing function where possible. */
virtual void RouteRenameNetworkActorToNodes(const FRenamedReplicatedActorInfo& ActorInfo);
/** How long, in frames, without replicating before an actor channel is closed on a connection. This is a global value added to the individual actor's ActorChannelFrameTimeout */
uint32 GlobalActorChannelFrameNumTimeout;
@@ -7,6 +7,7 @@
#include "Net/DataBunch.h"
#include "ProfilingDebugging/CsvProfiler.h"
#include "Templates/Greater.h"
#include "UObject/Package.h"
#include "ReplicationGraphTypes.generated.h"
class AActor;
@@ -581,6 +582,13 @@ struct FNewReplicatedActorInfo
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);
@@ -590,6 +598,28 @@ struct FNewReplicatedActorInfo
UClass* Class;
};
// --------------------------------------------------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------------------------------
// RenamedReplicatedActorInfo
// --------------------------------------------------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------------------------------
/** Used to update renamed (changed outer/level) actors in the graph. */
struct FRenamedReplicatedActorInfo
{
explicit FRenamedReplicatedActorInfo(const FActorRepListType& InActor, FName InPreviousStreamingLevelName)
: NewActorInfo(InActor)
, OldActorInfo(InActor, InPreviousStreamingLevelName)
{
}
/** Info that stores the actor's new level name */
FNewReplicatedActorInfo NewActorInfo;
/** Info that stores the actor's old level name */
FNewReplicatedActorInfo OldActorInfo;
};
// --------------------------------------------------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------------------------------
// Level based actor lists
@@ -620,6 +650,12 @@ struct REPLICATIONGRAPH_API FStreamingLevelActorListCollection
*/
bool RemoveActorFast(const FNewReplicatedActorInfo& ActorInfo, UObject* Outer=nullptr);
/**
* Attempts to remove the actor from the level explicitly provided. Can be used to update the list
* if the actor's level changes (by providing the actor's previous level).
*/
bool RemoveActorFromLevelFast(AActor* Actor, FName LevelName);
void Reset();
/** Add to the Params' gather list the list of actors for levels that are visible to that connection */
@@ -698,6 +734,9 @@ struct REPLICATIONGRAPH_API FLevelBasedActorList
void CountBytes(FArchive& Ar) const;
/** Update actor to new level */
void UpdateActorLevel(AActor* NetActor, FName PreviousLevelName);
private:
FActorRepListRefView PermanentLevelActors;
@@ -887,6 +926,9 @@ struct FGlobalActorReplicationInfo
DependentActorList.Gather(ConnectionManager, OutGatheredList);
}
/** Update actor to new level */
void NotifyActorRenamed(AActor* Actor, FName PreviousLevelName);
typedef TArray<FActorRepListType> FDependantListType;
UE_DEPRECATED(5.2, "The dependent actors are exposed via GatherDependentActorLists now.")
@@ -1099,6 +1141,9 @@ struct FGlobalActorReplicationInfoMap
/** Removes actor data from map */
REPLICATIONGRAPH_API int32 Remove(const FActorRepListType& RemovedActor);
/** Update actor to new level */
void NotifyActorRenamed(AActor* Actor, FName PreviousStreamingLevelName);
/** Returns ClassInfo for a given class. */
FORCEINLINE FClassReplicationInfo& GetClassInfo(UClass* Class) { return ClassMap.GetChecked(Class); }