You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
Merging using //UE5/Main_to_//UE5/Release-Engine-Staging @14384769
autoresolved files #rb none [CL 14384911 by Marcus Wassmer in ue5-main branch]
This commit is contained in:
@@ -113,8 +113,10 @@ float CVar_RepGraph_OutOfRangeDistanceCheckRatio = 0.5f;
|
||||
static FAutoConsoleVariableRef CVarRepGraphOutOfRangeDistanceCheckRatio(TEXT("Net.RepGraph.OutOfRangeDistanceCheckRatio"), CVar_RepGraph_OutOfRangeDistanceCheckRatio,
|
||||
TEXT("The ratio of DestructInfoMaxDistance that gives the distance traveled before we reevaluate the out of range destroyed actors list"), ECVF_Default);
|
||||
|
||||
static TAutoConsoleVariable<float> CVar_ForceConnectionViewerPriority(TEXT("Net.RepGraph.ForceConnectionViewerPriority"), 1,
|
||||
TEXT("Force the connection's player controller and viewing pawn as topmost priority."));
|
||||
int32 CVar_RepGraph_DormancyNode_DisconnectedBehavior = 1;
|
||||
static FAutoConsoleVariableRef CVarRepGraphDormancyNodeDisconnectedBehavior(TEXT("Net.RepGraph.DormancyNodeDisconnectedBehavior"), CVar_RepGraph_DormancyNode_DisconnectedBehavior, TEXT("This changes how the dormancy node deals with disconnected clients. 0 = ignore. 1 = skip the disconnected client nodes. 2 = lazily destroy the disconnected client nodes"), ECVF_Default);
|
||||
|
||||
static TAutoConsoleVariable<float> CVar_ForceConnectionViewerPriority(TEXT("Net.RepGraph.ForceConnectionViewerPriority"), 1, TEXT("Force the connection's player controller and viewing pawn as topmost priority."));
|
||||
|
||||
REPGRAPH_DEVCVAR_SHIPCONST(int32, "Net.RepGraph.LogNetDormancyDetails", CVar_RepGraph_LogNetDormancyDetails, 0, "Logs actors that are removed from the replication graph/nodes.");
|
||||
REPGRAPH_DEVCVAR_SHIPCONST(int32, "Net.RepGraph.LogActorRemove", CVar_RepGraph_LogActorRemove, 0, "Logs actors that are removed from the replication graph/nodes.");
|
||||
@@ -627,14 +629,19 @@ void UReplicationGraph::RemoveNetworkActor(AActor* Actor)
|
||||
|
||||
GlobalActorReplicationInfoMap.Remove(Actor);
|
||||
|
||||
for (UNetReplicationGraphConnection* ConnectionManager : Connections)
|
||||
{
|
||||
ConnectionManager->ActorInfoMap.RemoveActor(Actor);
|
||||
QUICK_SCOPE_CYCLE_COUNTER(UReplicationGraph_RemoveNetworkActor_FromConnectionsMap);
|
||||
|
||||
for (UNetReplicationGraphConnection* ConnectionManager : Connections)
|
||||
{
|
||||
ConnectionManager->ActorInfoMap.RemoveActor(Actor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UReplicationGraph::RouteRemoveNetworkActorToNodes(const FNewReplicatedActorInfo& ActorInfo)
|
||||
{
|
||||
QUICK_SCOPE_CYCLE_COUNTER(UReplicationGraph_RouteRemoveNetworkActorToNodes);
|
||||
// The base implementation just routes to every global node. Subclasses will want a more direct routing function where possible.
|
||||
for (UReplicationGraphNode* Node : GlobalGraphNodes)
|
||||
{
|
||||
@@ -898,8 +905,6 @@ int32 UReplicationGraph::ServerReplicateActors(float DeltaSeconds)
|
||||
// For Each Connection
|
||||
// -------------------------------------------------------
|
||||
|
||||
FGatheredReplicationActorLists GatheredReplicationListsForConnection;
|
||||
|
||||
// Total number of children processed, added to all the connections later for stat tracking purposes.
|
||||
int32 NumChildrenConnectionsProcessed = 0;
|
||||
|
||||
@@ -979,7 +984,7 @@ int32 UReplicationGraph::ServerReplicateActors(float DeltaSeconds)
|
||||
// GATHER list of ReplicationLists for this connection
|
||||
// --------------------------------------------------------------------------------------------------------------
|
||||
|
||||
GatheredReplicationListsForConnection.Reset();
|
||||
FGatheredReplicationActorLists GatheredReplicationListsForConnection;
|
||||
|
||||
TSet<FName> AllVisibleLevelNames;
|
||||
ConnectionManager->GetClientVisibleLevelNames(AllVisibleLevelNames);
|
||||
@@ -1175,7 +1180,8 @@ void UReplicationGraph::ReplicateActorListsForConnections_Default(UNetReplicatio
|
||||
const float MaxDistanceScaling = PrioritizationConstants.MaxDistanceScaling;
|
||||
const uint32 MaxFramesSinceLastRep = PrioritizationConstants.MaxFramesSinceLastRep;
|
||||
|
||||
for (FActorRepListRawView& List : GatheredReplicationListsForConnection.GetLists(EActorRepListTypeFlags::Default))
|
||||
const TArray<FActorRepListConstView>& GatheredLists = GatheredReplicationListsForConnection.GetLists(EActorRepListTypeFlags::Default);
|
||||
for (const FActorRepListConstView& List : GatheredLists)
|
||||
{
|
||||
// Add actors from gathered list
|
||||
NumGatheredActorsOnConnection += List.Num();
|
||||
@@ -1487,10 +1493,10 @@ void UReplicationGraph::ReplicateActorListsForConnections_FastShared(UNetReplica
|
||||
// This really isn't ideal. We want to have better ways of tracking and limiting network traffic. This feels pretty hacky in implementation but conceptually is good.
|
||||
FScopedQueuedBits ScopedQueuedBits(NetConnection->QueuedBits, TotalBitsWritten);
|
||||
|
||||
TArray< FActorRepListRawView>& GatheredLists = GatheredReplicationListsForConnection.GetLists(EActorRepListTypeFlags::FastShared);
|
||||
const TArray<FActorRepListConstView>& GatheredLists = GatheredReplicationListsForConnection.GetLists(EActorRepListTypeFlags::FastShared);
|
||||
for (int32 ListIdx = 0; ListIdx < GatheredLists.Num(); ++ListIdx)
|
||||
{
|
||||
FActorRepListRawView& List = GatheredLists[(ListIdx + FrameNum) % GatheredLists.Num()];
|
||||
const FActorRepListConstView& List = GatheredLists[(ListIdx + FrameNum) % GatheredLists.Num()];
|
||||
for (int32 i = 0; i < List.Num(); ++i)
|
||||
{
|
||||
// Round robin through the list over multiple frames. We want to avoid sorting this list based on 'time since last rep'. This is a good balance
|
||||
@@ -1772,8 +1778,6 @@ int64 UReplicationGraph::ReplicateSingleActor(AActor* Actor, FConnectionReplicat
|
||||
|
||||
const bool bWantsToGoDormant = GlobalActorInfo.bWantsToBeDormant;
|
||||
|
||||
const FActorRepListRefView& DependentActorList = GlobalActorInfo.GetDependentActorList();
|
||||
|
||||
bool bOpenActorChannel = (ActorInfo.Channel == nullptr);
|
||||
|
||||
if (bOpenActorChannel)
|
||||
@@ -1837,7 +1841,8 @@ int64 UReplicationGraph::ReplicateSingleActor(AActor* Actor, FConnectionReplicat
|
||||
// ----------------------------
|
||||
// Dependent actors
|
||||
// ----------------------------
|
||||
if (DependentActorList.IsValid())
|
||||
const FGlobalActorReplicationInfo::FDependantListType& DependentActorList = GlobalActorInfo.GetDependentActorList();
|
||||
if (DependentActorList.Num() > 0)
|
||||
{
|
||||
RG_QUICK_SCOPE_CYCLE_COUNTER(NET_ReplicateActors_DependentActors);
|
||||
|
||||
@@ -1896,9 +1901,9 @@ void UReplicationGraph::HandleStarvedActorList(const FPrioritizedRepList& List,
|
||||
// Update dependent actor's timeout frame
|
||||
FGlobalActorReplicationInfo& GlobalActorInfo = GlobalActorReplicationInfoMap.Get(RepItem.Actor);
|
||||
|
||||
const FActorRepListRefView& DependentActorList = GlobalActorInfo.GetDependentActorList();
|
||||
const FGlobalActorReplicationInfo::FDependantListType& DependentActorList = GlobalActorInfo.GetDependentActorList();
|
||||
|
||||
if (DependentActorList.IsValid())
|
||||
if (DependentActorList.Num() > 0)
|
||||
{
|
||||
const uint32 CloseFrameNum = ActorInfo.ActorChannelCloseFrameNum;
|
||||
for (AActor* DependentActor : DependentActorList)
|
||||
@@ -2092,14 +2097,18 @@ bool UReplicationGraph::ProcessRemoteFunction(class AActor* Actor, UFunction* Fu
|
||||
if (ShouldOpenChannel)
|
||||
{
|
||||
// We are within range, we will open a channel now for this actor and call the RPC on it
|
||||
ConnectionActorInfo.Channel = (UActorChannel *)NetConnection->CreateChannelByName( NAME_Actor, EChannelCreateFlags::OpenedLocally );
|
||||
ConnectionActorInfo.Channel->SetChannelActor(Actor, ESetChannelActorFlags::None);
|
||||
ConnectionActorInfo.Channel = (UActorChannel*)NetConnection->CreateChannelByName(NAME_Actor, EChannelCreateFlags::OpenedLocally);
|
||||
|
||||
// Update timeout frame name. We would run into problems if we open the channel, queue a bunch, and then it timeouts before RepGraph replicates properties.
|
||||
UpdateActorChannelCloseFrameNum(Actor, ConnectionActorInfo, GlobalInfo, ReplicationGraphFrame+1 /** Plus one to error on safe side. RepFrame num will be incremented in the next tick */, NetConnection );
|
||||
if (ConnectionActorInfo.Channel)
|
||||
{
|
||||
ConnectionActorInfo.Channel->SetChannelActor(Actor, ESetChannelActorFlags::None);
|
||||
|
||||
// If this actor is dormant on the connection, we will force a flushnetdormancy call.
|
||||
ForceFlushNetDormancy |= ConnectionActorInfo.bDormantOnConnection;
|
||||
// Update timeout frame name. We would run into problems if we open the channel, queue a bunch, and then it timeouts before RepGraph replicates properties.
|
||||
UpdateActorChannelCloseFrameNum(Actor, ConnectionActorInfo, GlobalInfo, ReplicationGraphFrame+1 /** Plus one to error on safe side. RepFrame num will be incremented in the next tick */, NetConnection );
|
||||
|
||||
// If this actor is dormant on the connection, we will force a flushnetdormancy call.
|
||||
ForceFlushNetDormancy |= ConnectionActorInfo.bDormantOnConnection;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2738,7 +2747,7 @@ void UReplicationGraphNode::NotifyResetAllNetworkActors()
|
||||
}
|
||||
}
|
||||
|
||||
void UReplicationGraphNode::RemoveChildNode(UReplicationGraphNode* ChildNode, UReplicationGraphNode::NodeOrdering NodeOrder)
|
||||
bool UReplicationGraphNode::RemoveChildNode(UReplicationGraphNode* ChildNode, UReplicationGraphNode::NodeOrdering NodeOrder)
|
||||
{
|
||||
ensure(ChildNode != nullptr);
|
||||
|
||||
@@ -2757,6 +2766,8 @@ void UReplicationGraphNode::RemoveChildNode(UReplicationGraphNode* ChildNode, UR
|
||||
{
|
||||
ChildNode->TearDown();
|
||||
}
|
||||
|
||||
return Removed > 0;
|
||||
}
|
||||
|
||||
void UReplicationGraphNode::CleanChildNodes(UReplicationGraphNode::NodeOrdering NodeOrder)
|
||||
@@ -2813,7 +2824,7 @@ bool FStreamingLevelActorListCollection::RemoveActor(const FNewReplicatedActorIn
|
||||
{
|
||||
if (StreamingList.StreamingLevelName == ActorInfo.StreamingLevelName)
|
||||
{
|
||||
bRemovedSomething = StreamingList.ReplicationActorList.Remove(ActorInfo.Actor);
|
||||
bRemovedSomething = StreamingList.ReplicationActorList.RemoveSlow(ActorInfo.Actor);
|
||||
if (!bRemovedSomething && bWarnIfNotFound)
|
||||
{
|
||||
UE_LOG(LogReplicationGraph, Warning, TEXT("Attempted to remove %s from list %s but it was not found. (StreamingLevelName == %s)"), *GetActorRepListTypeDebugString(ActorInfo.Actor), *GetPathNameSafe(Outer), *ActorInfo.StreamingLevelName.ToString() );
|
||||
@@ -2925,7 +2936,7 @@ bool UReplicationGraphNode_ActorList::NotifyRemoveNetworkActor(const FNewReplica
|
||||
|
||||
if (ActorInfo.StreamingLevelName == NAME_None)
|
||||
{
|
||||
bRemovedSomething = ReplicationActorList.Remove(ActorInfo.Actor);
|
||||
bRemovedSomething = ReplicationActorList.RemoveSlow(ActorInfo.Actor);
|
||||
|
||||
UE_CLOG(!bRemovedSomething && bWarnIfNotFound, LogReplicationGraph, Warning, TEXT("Attempted to remove %s from list %s but it was not found. (StreamingLevelName == NAME_None)"), *GetActorRepListTypeDebugString(ActorInfo.Actor), *GetFullName());
|
||||
|
||||
@@ -3066,7 +3077,7 @@ bool UReplicationGraphNode_ActorListFrequencyBuckets::NotifyRemoveNetworkActor(c
|
||||
bool bFound = false;
|
||||
for (FActorRepListRefView& List : NonStreamingCollection)
|
||||
{
|
||||
if (List.Remove(ActorInfo.Actor))
|
||||
if (List.RemoveSlow(ActorInfo.Actor))
|
||||
{
|
||||
bRemovedSomething = true;
|
||||
TotalNumNonStreamingActors--;
|
||||
@@ -3824,7 +3835,6 @@ void UReplicationGraphNode_ConnectionDormancyNode::ConditionalGatherDormantActor
|
||||
ConnectionList.RemoveAtSwap(idx);
|
||||
if (RemovedList)
|
||||
{
|
||||
RemovedList->PrepareForWrite();
|
||||
RemovedList->Add(Actor);
|
||||
}
|
||||
|
||||
@@ -3897,7 +3907,6 @@ void UReplicationGraphNode_ConnectionDormancyNode::NotifyActorDormancyFlush(FAct
|
||||
FStreamingLevelActorListCollection::FStreamingLevelActors* RemoveList = RemovedStreamingLevelActorListCollection.StreamingLevelLists.FindByKey(ActorInfo.StreamingLevelName);
|
||||
if (RemoveList)
|
||||
{
|
||||
RemoveList->ReplicationActorList.PrepareForWrite();
|
||||
RemoveList->ReplicationActorList.RemoveFast(Actor);
|
||||
}
|
||||
}
|
||||
@@ -3922,10 +3931,8 @@ void UReplicationGraphNode_ConnectionDormancyNode::OnClientVisibleLevelNameAdd(F
|
||||
UE_CLOG(CVar_RepGraph_LogNetDormancyDetails, LogReplicationGraph, Display, TEXT(" CurrentAddList: %s"), *AddList->ReplicationActorList.BuildDebugString());
|
||||
UE_CLOG(CVar_RepGraph_LogNetDormancyDetails, LogReplicationGraph, Display, TEXT(" RemoveList: %s"), *RemoveList->ReplicationActorList.BuildDebugString());
|
||||
|
||||
AddList->ReplicationActorList.PrepareForWrite();
|
||||
AddList->ReplicationActorList.AppendContentsFrom(RemoveList->ReplicationActorList);
|
||||
|
||||
RemoveList->ReplicationActorList.PrepareForWrite();
|
||||
RemoveList->ReplicationActorList.Reset();
|
||||
}
|
||||
|
||||
@@ -3953,6 +3960,40 @@ void UReplicationGraphNode_ConnectionDormancyNode::NotifyResetAllNetworkActors()
|
||||
|
||||
float UReplicationGraphNode_DormancyNode::MaxZForConnection = WORLD_MAX;
|
||||
|
||||
void UReplicationGraphNode_DormancyNode::CallFunctionOnValidConnectionNodes(FConnectionDormancyNodeFunction Function)
|
||||
{
|
||||
enum class DisconnectedClientNodeBehavior
|
||||
{
|
||||
AlwaysValid = 0, // Keep calling functions on disconnected client nodes (previous behavior)
|
||||
Deactivate = 1, // Deactivate the nodes by ignoring them. (wastes memory but doesn't incur a costly destruction)
|
||||
Destroy = 2, // Destroy the nodes immediately (one time cpu hit)
|
||||
};
|
||||
const DisconnectedClientNodeBehavior DisconnectedClientBehavior = (DisconnectedClientNodeBehavior)CVar_RepGraph_DormancyNode_DisconnectedBehavior;
|
||||
|
||||
QUICK_SCOPE_CYCLE_COUNTER(UReplicationGraphNode_DormancyNode_ConnectionLoop);
|
||||
for (FConnectionDormancyNodeMap::TIterator It = ConnectionNodes.CreateIterator(); It; ++It)
|
||||
{
|
||||
const FRepGraphConnectionKey RepGraphConnection = It.Key();
|
||||
const bool bIsActiveConnection = (DisconnectedClientBehavior == DisconnectedClientNodeBehavior::AlwaysValid) || (RepGraphConnection.ResolveObjectPtr() != nullptr);
|
||||
if (bIsActiveConnection)
|
||||
{
|
||||
Function(It.Value());
|
||||
}
|
||||
else if (DisconnectedClientBehavior == DisconnectedClientNodeBehavior::Destroy)
|
||||
{
|
||||
// The connection is now invalid. Destroy it's corresponding node
|
||||
UReplicationGraphNode_ConnectionDormancyNode* ConnectionNodeToDestroy = It.Value();
|
||||
|
||||
bool bWasRemoved = RemoveChildNode(ConnectionNodeToDestroy, UReplicationGraphNode::NodeOrdering::IgnoreOrdering);
|
||||
ensureMsgf(bWasRemoved, TEXT("DormancyNode did not find %s in it's child node."), *ConnectionNodeToDestroy->GetName());
|
||||
|
||||
//TODO: Release the ActorList in the Node ?
|
||||
|
||||
It.RemoveCurrent();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UReplicationGraphNode_DormancyNode::NotifyResetAllNetworkActors()
|
||||
{
|
||||
if (GraphGlobals.IsValid())
|
||||
@@ -3968,14 +4009,11 @@ void UReplicationGraphNode_DormancyNode::NotifyResetAllNetworkActors()
|
||||
// Dump our global actor list
|
||||
Super::NotifyResetAllNetworkActors();
|
||||
|
||||
// Reset the per connection nodes
|
||||
for (auto& MapIt : ConnectionNodes)
|
||||
auto ResetAllActorsFunction = [](UReplicationGraphNode_ConnectionDormancyNode* ConnectionNode)
|
||||
{
|
||||
if (MapIt.Value)
|
||||
{
|
||||
MapIt.Value->NotifyResetAllNetworkActors();
|
||||
}
|
||||
}
|
||||
ConnectionNode->NotifyResetAllNetworkActors();
|
||||
};
|
||||
CallFunctionOnValidConnectionNodes(ResetAllActorsFunction);
|
||||
}
|
||||
|
||||
void UReplicationGraphNode_DormancyNode::AddDormantActor(const FNewReplicatedActorInfo& ActorInfo, FGlobalActorReplicationInfo& GlobalInfo)
|
||||
@@ -3986,12 +4024,12 @@ void UReplicationGraphNode_DormancyNode::AddDormantActor(const FNewReplicatedAct
|
||||
|
||||
UE_CLOG(CVar_RepGraph_LogNetDormancyDetails > 0 && ConnectionNodes.Num() > 0, LogReplicationGraph, Display, TEXT("GRAPH_DORMANCY: AddDormantActor %s on %s. Adding to %d connection nodes."), *ActorInfo.Actor->GetPathName(), *GetName(), ConnectionNodes.Num());
|
||||
|
||||
for (auto& MapIt : ConnectionNodes)
|
||||
auto AddActorFunction = [ActorInfo](UReplicationGraphNode_ConnectionDormancyNode* ConnectionNode)
|
||||
{
|
||||
QUICK_SCOPE_CYCLE_COUNTER(ConnectionDormancyNode_NotifyAddNetworkActor);
|
||||
UReplicationGraphNode_ConnectionDormancyNode* Node = MapIt.Value;
|
||||
Node->NotifyAddNetworkActor(ActorInfo);
|
||||
}
|
||||
QUICK_SCOPE_CYCLE_COUNTER(ConnectionDormancyNode_NotifyAddNetworkActor);
|
||||
ConnectionNode->NotifyAddNetworkActor(ActorInfo);
|
||||
};
|
||||
CallFunctionOnValidConnectionNodes(AddActorFunction);
|
||||
|
||||
// Tell us if this guy flushes net dormancy so we force him back on connection lists
|
||||
GlobalInfo.Events.DormancyFlush.AddUObject(this, &UReplicationGraphNode_DormancyNode::OnActorDormancyFlush);
|
||||
@@ -4004,15 +4042,15 @@ void UReplicationGraphNode_DormancyNode::RemoveDormantActor(const FNewReplicated
|
||||
UE_CLOG(CVar_RepGraph_LogActorRemove>0, LogReplicationGraph, Display, TEXT("UReplicationGraphNode_DormancyNode::RemoveDormantActor %s on %s. (%d connection nodes). ChildNodes: %d"), *GetNameSafe(ActorInfo.Actor), *GetPathName(), ConnectionNodes.Num(), AllChildNodes.Num());
|
||||
|
||||
Super::RemoveNetworkActorFast(ActorInfo);
|
||||
|
||||
|
||||
ActorRepInfo.Events.DormancyFlush.RemoveAll(this);
|
||||
|
||||
// Update any connection specific nodes
|
||||
for (auto& MapIt : ConnectionNodes)
|
||||
auto RemoveActorFunction = [ActorInfo](UReplicationGraphNode_ConnectionDormancyNode* ConnectionNode)
|
||||
{
|
||||
UReplicationGraphNode_ConnectionDormancyNode* Node = MapIt.Value;
|
||||
Node->NotifyRemoveNetworkActor(ActorInfo, false); // Don't warn if not found, the node may have removed the actor itself. Not worth the extra bookkeeping to skip the call.
|
||||
}
|
||||
// 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, false);
|
||||
};
|
||||
CallFunctionOnValidConnectionNodes(RemoveActorFunction);
|
||||
}
|
||||
|
||||
void UReplicationGraphNode_DormancyNode::GatherActorListsForConnection(const FConnectionGatherActorListParameters& Params)
|
||||
@@ -4038,29 +4076,27 @@ void UReplicationGraphNode_DormancyNode::GatherActorListsForConnection(const FCo
|
||||
|
||||
UReplicationGraphNode_ConnectionDormancyNode* UReplicationGraphNode_DormancyNode::GetExistingConnectionNode(const FConnectionGatherActorListParameters& Params)
|
||||
{
|
||||
UReplicationGraphNode_ConnectionDormancyNode** ConnectionNodeItem = ConnectionNodes.Find(&Params.ConnectionManager);
|
||||
UReplicationGraphNode_ConnectionDormancyNode** ConnectionNodeItem = ConnectionNodes.Find(FRepGraphConnectionKey(&Params.ConnectionManager));
|
||||
return ConnectionNodeItem == nullptr ? nullptr : *ConnectionNodeItem;
|
||||
}
|
||||
|
||||
UReplicationGraphNode_ConnectionDormancyNode* UReplicationGraphNode_DormancyNode::GetConnectionNode(const FConnectionGatherActorListParameters& Params)
|
||||
{
|
||||
UReplicationGraphNode_ConnectionDormancyNode** NodePtrPtr = ConnectionNodes.Find(&Params.ConnectionManager);
|
||||
UReplicationGraphNode_ConnectionDormancyNode* ConnectionNode = nullptr;
|
||||
if (!NodePtrPtr)
|
||||
FRepGraphConnectionKey RepGraphConnection(&Params.ConnectionManager);
|
||||
UReplicationGraphNode_ConnectionDormancyNode** NodePtrPtr = ConnectionNodes.Find(RepGraphConnection);
|
||||
UReplicationGraphNode_ConnectionDormancyNode* ConnectionNode = NodePtrPtr != nullptr ? *NodePtrPtr : nullptr;
|
||||
|
||||
if (ConnectionNode == nullptr)
|
||||
{
|
||||
// We dont have a per-connection node for this connection, so create one and copy over contents
|
||||
ConnectionNode = CreateChildNode<UReplicationGraphNode_ConnectionDormancyNode>();
|
||||
ConnectionNodes.Add(&Params.ConnectionManager) = ConnectionNode;
|
||||
ConnectionNodes.Add(RepGraphConnection) = ConnectionNode;
|
||||
|
||||
// Copy our master lists to the connection node
|
||||
ConnectionNode->DeepCopyActorListsFrom(this);
|
||||
|
||||
UE_CLOG(CVar_RepGraph_LogNetDormancyDetails > 0, LogReplicationGraph, Display, TEXT("GRAPH_DORMANCY: First time seeing connection %s in node %s. Created ConnectionDormancyNode %s."), *Params.ConnectionManager.GetName(), *GetName(), *ConnectionNode->GetName());
|
||||
}
|
||||
else
|
||||
{
|
||||
ConnectionNode = *NodePtrPtr;
|
||||
}
|
||||
|
||||
return ConnectionNode;
|
||||
}
|
||||
@@ -4089,11 +4125,11 @@ void UReplicationGraphNode_DormancyNode::OnActorDormancyFlush(FActorRepListType
|
||||
|
||||
UE_CLOG(CVar_RepGraph_LogNetDormancyDetails > 0 && ConnectionNodes.Num() > 0, LogReplicationGraph, Display, TEXT("GRAPH_DORMANCY: Actor %s Flushed Dormancy. %s. Refreshing all %d connection nodes."), *Actor->GetPathName(), *GetName(), ConnectionNodes.Num());
|
||||
|
||||
for (auto& MapIt : ConnectionNodes)
|
||||
auto DormancyFlushFunction = [Actor](UReplicationGraphNode_ConnectionDormancyNode* ConnectionNode)
|
||||
{
|
||||
UReplicationGraphNode_ConnectionDormancyNode* Node = MapIt.Value;
|
||||
Node->NotifyActorDormancyFlush(Actor);
|
||||
}
|
||||
ConnectionNode->NotifyActorDormancyFlush(Actor);
|
||||
};
|
||||
CallFunctionOnValidConnectionNodes(DormancyFlushFunction);
|
||||
}
|
||||
|
||||
void UReplicationGraphNode_DormancyNode::ConditionalGatherDormantDynamicActors(FActorRepListRefView& RepList, const FConnectionGatherActorListParameters& Params, FActorRepListRefView* RemovedList, bool bEnforceReplistUniqueness)
|
||||
@@ -4106,7 +4142,7 @@ void UReplicationGraphNode_DormancyNode::ConditionalGatherDormantDynamicActors(F
|
||||
{
|
||||
if (Info->bDormantOnConnection)
|
||||
{
|
||||
if (RemovedList && RemovedList->IsValid() && RemovedList->Contains(Actor))
|
||||
if (RemovedList && RemovedList->Contains(Actor))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -4124,7 +4160,6 @@ void UReplicationGraphNode_DormancyNode::ConditionalGatherDormantDynamicActors(F
|
||||
}
|
||||
}
|
||||
|
||||
RepList.PrepareForWrite();
|
||||
RepList.ConditionalAdd(Actor);
|
||||
}
|
||||
}
|
||||
@@ -5221,7 +5256,7 @@ void UReplicationGraphNode_GridSpatialization2D::GatherActorListsForConnection(c
|
||||
}
|
||||
|
||||
// Now process the previous dormant list to handle destruction
|
||||
if (bCellHasChanged && PrevDormantActorList.IsValid())
|
||||
if (bCellHasChanged)
|
||||
{
|
||||
// any previous dormant actors not in the current node dormant list
|
||||
for (FActorRepListType& Actor : PrevDormantActorList)
|
||||
|
||||
+1
-2
@@ -718,7 +718,6 @@ FAutoConsoleCommandWithWorldAndArgs NetRepGraphSetCellSize(TEXT("Net.RepGraph.Sp
|
||||
FAutoConsoleCommand RepDriverListsAddTestmd(TEXT("Net.RepGraph.Lists.AddTest"), TEXT(""), FConsoleCommandWithArgsDelegate::CreateLambda([](const TArray< FString >& Args)
|
||||
{
|
||||
static FActorRepListRefView List;
|
||||
List.PrepareForWrite(true);
|
||||
|
||||
int32 Num = 1;
|
||||
if (Args.Num() > 0 )
|
||||
@@ -1055,7 +1054,7 @@ void UReplicationGraphNode::LogNode(FReplicationGraphDebugInfo& DebugInfo, const
|
||||
|
||||
void LogActorRepList(FReplicationGraphDebugInfo& DebugInfo, FString Prefix, const FActorRepListRefView& List)
|
||||
{
|
||||
if (List.IsValid() == false || List.Num() <= 0)
|
||||
if (List.Num() <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -192,6 +192,7 @@ private:
|
||||
FPool* Pool = PoolTable.FindByPredicate([&ExpectedMaxSize](const FPool& InPool) { return ExpectedMaxSize <= InPool.ListSize; });
|
||||
if (!Pool)
|
||||
{
|
||||
QUICK_SCOPE_CYCLE_COUNTER(RepList_Pool_Allocation);
|
||||
if (!ForPreAllocation)
|
||||
{
|
||||
UE_LOG(LogReplicationGraph, Warning, TEXT("No pool big enough for requested list size %d. Creating a new pool. (You may want to preallocate a pool of this size or investigate why this size is needed)"), ExpectedMaxSize);
|
||||
@@ -225,53 +226,6 @@ void FActorRepList::Release()
|
||||
}
|
||||
}
|
||||
|
||||
void FActorRepListRefView::RequestNewList(int32 NewSize, bool CopyExistingContent)
|
||||
{
|
||||
QUICK_SCOPE_CYCLE_COUNTER(RepList_RequestNewList);
|
||||
FActorRepList* NewList = &GActorListAllocator.RequestList(NewSize > 0 ? NewSize : InitialListSize);
|
||||
if (CopyExistingContent)
|
||||
{
|
||||
FMemory::Memcpy((uint8*)NewList->Data, (uint8*)CachedData, CachedNum * sizeof(FActorRepListType) );
|
||||
NewList->Num = CachedNum;
|
||||
}
|
||||
else
|
||||
{
|
||||
repCheck(NewList->Num == 0);
|
||||
CachedNum = 0;
|
||||
}
|
||||
RepList = NewList;
|
||||
CachedData = RepList->Data;
|
||||
CachedMax = RepList->Max;
|
||||
}
|
||||
|
||||
void FActorRepListRefView::CopyContentsFrom(const FActorRepListRefView& Source)
|
||||
{
|
||||
const int32 NewNum = Source.CachedNum;
|
||||
|
||||
FActorRepList* NewList = &GActorListAllocator.RequestList(Source.Num());
|
||||
FMemory::Memcpy((uint8*)NewList->Data, (uint8*)Source.CachedData, NewNum * sizeof(FActorRepListType) );
|
||||
NewList->Num = NewNum;
|
||||
|
||||
RepList = NewList;
|
||||
|
||||
CachedData = NewList->Data;
|
||||
CachedMax = NewList->Max;
|
||||
CachedNum = NewNum;
|
||||
}
|
||||
|
||||
void FActorRepListRefView::AppendContentsFrom(const FActorRepListRefView& Source)
|
||||
{
|
||||
const int32 NewNum = CachedNum + Source.CachedNum;
|
||||
if (NewNum > CachedMax)
|
||||
{
|
||||
RequestNewList(NewNum, true);
|
||||
}
|
||||
|
||||
FMemory::Memcpy((uint8*)&CachedData[CachedNum], (uint8*)Source.CachedData, Source.CachedNum * sizeof(FActorRepListType));
|
||||
RepList->Num = NewNum;
|
||||
CachedNum = NewNum;
|
||||
}
|
||||
|
||||
bool FActorRepListRefView::VerifyContents_Slow() const
|
||||
{
|
||||
for (FActorRepListType Actor : *this)
|
||||
@@ -294,6 +248,20 @@ bool FActorRepListRefView::VerifyContents_Slow() const
|
||||
return true;
|
||||
}
|
||||
|
||||
FString FActorRepListRefView::BuildDebugString() const
|
||||
{
|
||||
FString Str;
|
||||
if (Num() > 0)
|
||||
{
|
||||
Str += GetActorRepListTypeDebugString(RepList[0]);
|
||||
for (int32 i = 1; i < Num(); ++i)
|
||||
{
|
||||
Str += TEXT(", ") + GetActorRepListTypeDebugString(RepList[i]);
|
||||
}
|
||||
}
|
||||
return Str;
|
||||
}
|
||||
|
||||
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
|
||||
void PrintRepListStats(int32 mode)
|
||||
{
|
||||
@@ -475,22 +443,26 @@ void FGlobalActorReplicationInfoMap::AddDependentActor(AActor* Parent, AActor* C
|
||||
bool bChildIsAlreadyDependant(false);
|
||||
if (FGlobalActorReplicationInfo* ParentInfo = Find(Parent))
|
||||
{
|
||||
bChildIsAlreadyDependant = ParentInfo->DependentActorList.IsValid() && ParentInfo->DependentActorList.Contains(Child);
|
||||
bChildIsAlreadyDependant = ParentInfo->DependentActorList.Find(Child) != INDEX_NONE;
|
||||
if (bChildIsAlreadyDependant == false)
|
||||
{
|
||||
ParentInfo->DependentActorList.PrepareForWrite();
|
||||
ParentInfo->DependentActorList.ConditionalAdd(Child);
|
||||
if (IsActorValidForReplicationGather(Child))
|
||||
{
|
||||
ParentInfo->DependentActorList.Add(Child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool bChildHadParentAlready(false);
|
||||
if (FGlobalActorReplicationInfo* ChildInfo = Find(Child))
|
||||
{
|
||||
bChildHadParentAlready = ChildInfo->ParentActorList.IsValid() && ChildInfo->ParentActorList.Contains(Parent);
|
||||
bChildHadParentAlready = ChildInfo->ParentActorList.Find(Parent) != INDEX_NONE;
|
||||
if (bChildHadParentAlready == false)
|
||||
{
|
||||
ChildInfo->ParentActorList.PrepareForWrite();
|
||||
ChildInfo->ParentActorList.ConditionalAdd(Parent);
|
||||
if (IsActorValidForReplicationGather(Parent))
|
||||
{
|
||||
ChildInfo->ParentActorList.Add(Parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -125,8 +125,8 @@ public:
|
||||
KeepOrder, // Use slower removal but keep the node order intact
|
||||
};
|
||||
|
||||
/** Remove a child node from our list and flag it for destruction */
|
||||
void RemoveChildNode(UReplicationGraphNode* OutChildNode, UReplicationGraphNode::NodeOrdering NodeOrder=UReplicationGraphNode::NodeOrdering::IgnoreOrdering);
|
||||
/** Remove a child node from our list and flag it for destruction. Returns if the node was found or not */
|
||||
bool RemoveChildNode(UReplicationGraphNode* OutChildNode, UReplicationGraphNode::NodeOrdering NodeOrder=UReplicationGraphNode::NodeOrdering::IgnoreOrdering);
|
||||
|
||||
/** Remove all null and about to be destroyed nodes from our list */
|
||||
void CleanChildNodes(UReplicationGraphNode::NodeOrdering NodeOrder);
|
||||
@@ -445,7 +445,20 @@ public:
|
||||
|
||||
private:
|
||||
|
||||
TMap<UNetReplicationGraphConnection*, UReplicationGraphNode_ConnectionDormancyNode*> ConnectionNodes;
|
||||
/** Function called on every ConnectionDormancyNode in our list */
|
||||
typedef TFunction<void(UReplicationGraphNode_ConnectionDormancyNode*)> FConnectionDormancyNodeFunction;
|
||||
|
||||
/**
|
||||
* Iterates over all ConnectionDormancyNodes and calls the function on those still valid.
|
||||
* If a RepGraphConnection was torn down since the last iteration, it removes and destroys the ConnectionDormancyNode associated with the Connection.
|
||||
*/
|
||||
void CallFunctionOnValidConnectionNodes(FConnectionDormancyNodeFunction Function);
|
||||
|
||||
private:
|
||||
|
||||
typedef TObjectKey<UNetReplicationGraphConnection> FRepGraphConnectionKey;
|
||||
typedef TSortedMap<FRepGraphConnectionKey, UReplicationGraphNode_ConnectionDormancyNode*> FConnectionDormancyNodeMap;
|
||||
FConnectionDormancyNodeMap ConnectionNodes;
|
||||
};
|
||||
|
||||
UCLASS()
|
||||
|
||||
@@ -73,6 +73,7 @@ enum class EActorRepListTypeFlags : uint8
|
||||
{
|
||||
Default = 0,
|
||||
FastShared = 1,
|
||||
Max, // Always keep last
|
||||
};
|
||||
|
||||
// Tests if an actor is valid for replication: not pending kill, etc. Says nothing about wanting to replicate or should replicate, etc.
|
||||
@@ -209,56 +210,50 @@ struct TActorRepListViewBase
|
||||
return Str;
|
||||
}
|
||||
|
||||
FActorRepListType* begin() const { return RepList->Data; }
|
||||
FActorRepListType* end() const { return RepList->Data + RepList->Num; }
|
||||
|
||||
private:
|
||||
|
||||
FORCEINLINE friend FActorRepListType* begin(const TActorRepListViewBase<PointerType>& View) { return View.RepList->Data; }
|
||||
FORCEINLINE friend FActorRepListType* end(const TActorRepListViewBase<PointerType>& View) { return View.RepList->Data + View.RepList->Num; }
|
||||
};
|
||||
|
||||
/** A view that maintains ownership/(ref counting) to an actor replication list. */
|
||||
struct REPLICATIONGRAPH_API FActorRepListRefView : public TActorRepListViewBase<TRefCountPtr<FActorRepList>>
|
||||
/**
|
||||
* Holds a list of replicated actors that can be added/removed to.
|
||||
*/
|
||||
struct REPLICATIONGRAPH_API FActorRepListRefView
|
||||
{
|
||||
/** Ideally, use Reset to set the initial size of the list. But if nothing is set, the first list we request will be of this size */
|
||||
enum { InitialListSize = 4 } ;
|
||||
|
||||
FActorRepListRefView() { }
|
||||
FActorRepListRefView(FActorRepList& InRepList) { RepList = &InRepList; }
|
||||
FORCEINLINE FActorRepListType& operator[](int32 idx) const { repCheck(RepList); repCheck(RepList->Max > idx); return RepList->Data[idx]; }
|
||||
|
||||
/** Initializes a new list for a given ExpectedMaxSize. Best practice is to call this once to get a good initial size to avoid reallocations/copying. Passing 0 will preserve the current size (if current size is also 0, InitialListSize is used) */
|
||||
void Reset(int32 ExpectedMaxSize=0)
|
||||
FActorRepListRefView()
|
||||
{
|
||||
if (RepList && RepList->RefCount == 1 && RepList->Max >= ExpectedMaxSize)
|
||||
}
|
||||
|
||||
UE_DEPRECATED(4.27, "This constructor is deprecated since the class does not hold FActorRepList's anymore. ")
|
||||
FActorRepListRefView(FActorRepList& InRepList)
|
||||
{
|
||||
RepList.Reserve(InRepList.Num);
|
||||
for (int32 i = 0; i < InRepList.Num; ++i)
|
||||
{
|
||||
// We can keep using this list
|
||||
RepList->Num = 0;
|
||||
CachedNum = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We must request a new list for this size
|
||||
RequestNewList(ExpectedMaxSize > 0 ? ExpectedMaxSize : CachedNum, false);
|
||||
RepList.Add(InRepList.Data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/** Prepares the list for modifications. If this list is shared by other RefViews, then you will get a new underlying list to reference. ResetContent determines if the content is cleared or not (regardless of refcount/new list) */
|
||||
/** Empties the array but does not deallocate the internal memory. Will be resized if the specified max size is bigger than the current max. */
|
||||
void Reset(int32 ExpectedMaxSize=0)
|
||||
{
|
||||
RepList.Reset(ExpectedMaxSize);
|
||||
}
|
||||
|
||||
/** Preallocate the array so it can hold the specified size */
|
||||
void Reserve(int32 Size)
|
||||
{
|
||||
RepList.Reserve(Size);
|
||||
}
|
||||
|
||||
UE_DEPRECATED(4.27, "PrepareForWrite is not needed before calling operations on the RepList anymore. Use Reserve or Reset if you want to preallocate the array to a specific size")
|
||||
void PrepareForWrite(bool bResetContent=false)
|
||||
{
|
||||
if (RepList == nullptr)
|
||||
{
|
||||
RequestNewList(InitialListSize, false);
|
||||
}
|
||||
else if (RepList->RefCount > 1)
|
||||
{
|
||||
// This list we are viewing is shared by others, so request a new one
|
||||
RequestNewList(CachedNum, !bResetContent);
|
||||
}
|
||||
else if(bResetContent)
|
||||
{
|
||||
// We already have our own list but need to reset back to 0
|
||||
RepList->Num = 0;
|
||||
CachedNum = 0;
|
||||
}
|
||||
// empty
|
||||
}
|
||||
|
||||
bool ConditionalAdd(const FActorRepListType& NewElement)
|
||||
@@ -273,83 +268,137 @@ struct REPLICATIONGRAPH_API FActorRepListRefView : public TActorRepListViewBase<
|
||||
|
||||
void Add(const FActorRepListType& NewElement)
|
||||
{
|
||||
repCheckf(RepList != nullptr, TEXT("Invalid RepList when calling add new element to a list. Call ::PrepareForWrite or ::Reset before writing!"));
|
||||
repCheckf(RepList->RefCount == 1, TEXT("Attempting to add new element to a list with >1 RefCount (%d). Call ::PrepareForWrite before writing!"), RepList->RefCount);
|
||||
if (CachedNum == CachedMax)
|
||||
{
|
||||
// We can't add more to the list we are referencing, we need to get a new list and copy the contents over. This is transparent to the caller.
|
||||
RequestNewList(CachedMax+1, true);
|
||||
}
|
||||
|
||||
CachedData[CachedNum++] = NewElement;
|
||||
RepList->Num++;
|
||||
RepList.Add(NewElement);
|
||||
}
|
||||
|
||||
UE_DEPRECATED(4.27, "Remove has been deprecated in favor of RemoveSlow/RemoveFast. RemoveFast is the default recommendation unless you need the list order to be stable or are removing elements inside a RangedFor iteration loop.")
|
||||
bool Remove(const FActorRepListType& ElementToRemove)
|
||||
{
|
||||
int32 idx = IndexOf(ElementToRemove);
|
||||
if (idx >= 0)
|
||||
{
|
||||
RemoveAtImpl(idx);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return RemoveSlow(ElementToRemove);
|
||||
}
|
||||
|
||||
/** Removes the element quickly but changes the list order */
|
||||
bool RemoveFast(const FActorRepListType& ElementToRemove)
|
||||
{
|
||||
int32 idx = IndexOf(ElementToRemove);
|
||||
if (idx >= 0)
|
||||
{
|
||||
RemoveAtSwap(idx);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return RepList.RemoveSingleSwap(ElementToRemove) > 0;
|
||||
}
|
||||
|
||||
/** Removes the element but keeps the order intact. Generally not recommended for large lists. */
|
||||
bool RemoveSlow(const FActorRepListType& ElementToRemove)
|
||||
{
|
||||
return RepList.RemoveSingle(ElementToRemove) > 0;
|
||||
}
|
||||
|
||||
void RemoveAtSwap(int32 idx)
|
||||
{
|
||||
repCheck(RepList && Num() > idx);
|
||||
CachedData[idx] = CachedData[CachedNum-1];
|
||||
CachedNum--;
|
||||
RepList->Num--;
|
||||
RepList.RemoveAtSwap(idx);
|
||||
}
|
||||
|
||||
void CopyContentsFrom(const FActorRepListRefView& Source)
|
||||
{
|
||||
RepList = Source.RepList;
|
||||
}
|
||||
|
||||
void AppendContentsFrom(const FActorRepListRefView& Source)
|
||||
{
|
||||
RepList.Append(Source.RepList);
|
||||
}
|
||||
|
||||
void CopyContentsFrom(const FActorRepListRefView& Source);
|
||||
void AppendContentsFrom(const FActorRepListRefView& Source);
|
||||
bool VerifyContents_Slow() const;
|
||||
|
||||
int32 Num() const { return CachedNum; }
|
||||
/** Add contents to TArray/TSet. this is intended for debugging/ease of use */
|
||||
void AppendToTArray(TArray<FActorRepListType>& OutArray) const
|
||||
{
|
||||
OutArray.Append(RepList);
|
||||
}
|
||||
void AppendToTSet(TSet<FActorRepListType>& OutSet) const
|
||||
{
|
||||
OutSet.Append(RepList);
|
||||
}
|
||||
|
||||
FString BuildDebugString() const;
|
||||
|
||||
/**
|
||||
* Base view functions.
|
||||
*/
|
||||
|
||||
FActorRepListType& operator[](int32 idx) { return RepList[idx]; }
|
||||
const FActorRepListType& operator[](int32 idx) const { return RepList[idx]; }
|
||||
|
||||
TArray<FActorRepListType>::RangedForIteratorType begin() { return RepList.begin(); }
|
||||
TArray<FActorRepListType>::RangedForConstIteratorType begin() const { return RepList.begin(); }
|
||||
TArray<FActorRepListType>::RangedForIteratorType end() { return RepList.end(); }
|
||||
TArray<FActorRepListType>::RangedForConstIteratorType end() const { return RepList.end(); }
|
||||
|
||||
UE_DEPRECATED(4.27, "IsValid is deprecated now that you don't need to call PrepareForWrite before doing operations on the list. Use IsEmpty() if you need to skip doing operations on empty lists")
|
||||
bool IsValid() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IsEmpty() const
|
||||
{
|
||||
return RepList.Num() <= 0;
|
||||
}
|
||||
|
||||
int32 Num() const
|
||||
{
|
||||
return RepList.Num();
|
||||
}
|
||||
|
||||
/** Resets the container and returns the memory it held */
|
||||
void ResetToNull()
|
||||
{
|
||||
RepList.Empty();
|
||||
}
|
||||
|
||||
int32 IndexOf(const FActorRepListType& Value) const
|
||||
{
|
||||
return RepList.IndexOfByKey(Value);
|
||||
}
|
||||
|
||||
bool Contains(const FActorRepListType& Value) const
|
||||
{
|
||||
return RepList.Contains(Value);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
/** Cached data from our FActorRepList to avoid looking it up each time */
|
||||
FActorRepListType* CachedData = nullptr;
|
||||
int32 CachedNum = 0;
|
||||
int32 CachedMax = 0;
|
||||
TArray<FActorRepListType> RepList;
|
||||
};
|
||||
|
||||
void RequestNewList(int32 NewSize, bool bCopyExistingContent);
|
||||
/**
|
||||
* Gives temporary read-only access to a FActorRepListRefView by holding a reference to it.
|
||||
*/
|
||||
struct REPLICATIONGRAPH_API FActorRepListConstView
|
||||
{
|
||||
FActorRepListConstView(const FActorRepListRefView& InListReferenced) :
|
||||
ListReferenced(InListReferenced)
|
||||
{}
|
||||
|
||||
void RemoveAtImpl(int32 Index)
|
||||
FActorRepListType operator[](int32 idx) const
|
||||
{
|
||||
repCheck(RepList && Num() > Index);
|
||||
int32 NumToMove = CachedNum - Index - 1;
|
||||
if (NumToMove)
|
||||
{
|
||||
FMemory::Memmove((void*)(&CachedData[Index]), (void*)(&CachedData[Index + 1]), NumToMove * sizeof(FActorRepListType));
|
||||
}
|
||||
|
||||
CachedNum--;
|
||||
RepList->Num--;
|
||||
return ListReferenced[idx];
|
||||
}
|
||||
|
||||
int32 Num() const
|
||||
{
|
||||
return ListReferenced.Num();
|
||||
}
|
||||
|
||||
TArray<FActorRepListType>::RangedForConstIteratorType begin() const { return ListReferenced.begin(); }
|
||||
TArray<FActorRepListType>::RangedForConstIteratorType end() const { return ListReferenced.end(); }
|
||||
|
||||
private:
|
||||
const FActorRepListRefView& ListReferenced;
|
||||
};
|
||||
|
||||
/** A read only, non owning (ref counting) view to an actor replication list: essentially a raw pointer and the category of the list. These are only created *from* FActorRepListRefView */
|
||||
struct REPLICATIONGRAPH_API FActorRepListRawView : public TActorRepListViewBase<FActorRepList*>
|
||||
|
||||
struct UE_DEPRECATED(4.27, "Replace this struct with the new FActorRepListConstView struct.") FActorRepListRawView : public TActorRepListViewBase<FActorRepList*>
|
||||
{
|
||||
/** Standard ctor: make raw view from ref view */
|
||||
FActorRepListRawView(const FActorRepListRefView& Source) { RepList = Source.RepList.GetReference(); }
|
||||
FActorRepListRefView ToRefView() const { return FActorRepListRefView(*RepList); }
|
||||
REPLICATIONGRAPH_API FActorRepListRawView(const FActorRepListRefView& Source) { /*deprecated*/ }
|
||||
};
|
||||
|
||||
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
|
||||
@@ -522,16 +571,17 @@ struct FGlobalActorReplicationInfo
|
||||
}
|
||||
}
|
||||
|
||||
const FActorRepListRefView& GetDependentActorList() { return DependentActorList; }
|
||||
typedef TArray<FActorRepListType> FDependantListType;
|
||||
const FGlobalActorReplicationInfo::FDependantListType& GetDependentActorList() { return DependentActorList; }
|
||||
|
||||
friend struct FGlobalActorReplicationInfoMap;
|
||||
|
||||
private:
|
||||
/** When this actor replicates, we replicate these actors immediately afterwards (they are not gathered/prioritized/etc) */
|
||||
FActorRepListRefView DependentActorList;
|
||||
FDependantListType DependentActorList;
|
||||
|
||||
/** When this actor is added to the dependent list of a parent, track the parent here */
|
||||
FActorRepListRefView ParentActorList;
|
||||
FDependantListType ParentActorList;
|
||||
};
|
||||
|
||||
/** Templatd struct for mapping UClasses to some data type. The main things this provides is that if a UClass* was not explicitly added, it will climb the class heirachy and find the best match (and then store this for faster lookup next time) */
|
||||
@@ -718,28 +768,34 @@ struct FGlobalActorReplicationInfoMap
|
||||
}
|
||||
|
||||
/** Removes actor data from map */
|
||||
int32 Remove(const FActorRepListType& Actor)
|
||||
int32 Remove(const FActorRepListType& RemovedActor)
|
||||
{
|
||||
if (FGlobalActorReplicationInfo* ActorInfo = Find(Actor))
|
||||
// Clean the references to the removed actor from his dependency chain.
|
||||
if (FGlobalActorReplicationInfo* RemovedActorInfo = Find(RemovedActor))
|
||||
{
|
||||
if (ActorInfo->DependentActorList.IsValid())
|
||||
// Remove child dependents
|
||||
for (AActor* ChildActor : RemovedActorInfo->DependentActorList)
|
||||
{
|
||||
for (AActor* ChildActor : ActorInfo->DependentActorList)
|
||||
if (FGlobalActorReplicationInfo* ChildInfo = Find(ChildActor))
|
||||
{
|
||||
RemoveDependentActor(Actor, ChildActor);
|
||||
ChildInfo->ParentActorList.RemoveSingleSwap(RemovedActor);
|
||||
}
|
||||
}
|
||||
|
||||
if (ActorInfo->ParentActorList.IsValid())
|
||||
// Remove parent dependents
|
||||
for (AActor* ParentActor : RemovedActorInfo->ParentActorList)
|
||||
{
|
||||
for (AActor* ParentActor : ActorInfo->ParentActorList)
|
||||
if (FGlobalActorReplicationInfo* ParentInfo = Find(ParentActor))
|
||||
{
|
||||
RemoveDependentActor(ParentActor, Actor);
|
||||
ParentInfo->DependentActorList.RemoveSingleSwap(RemovedActor);
|
||||
}
|
||||
}
|
||||
|
||||
RemovedActorInfo->DependentActorList.Reset();
|
||||
RemovedActorInfo->ParentActorList.Reset();
|
||||
}
|
||||
|
||||
return ActorMap.Remove(Actor);
|
||||
return ActorMap.Remove(RemovedActor);
|
||||
}
|
||||
|
||||
/** Returns ClassInfo for a given class. */
|
||||
@@ -785,14 +841,12 @@ struct FGlobalActorReplicationInfoMap
|
||||
{
|
||||
if (FGlobalActorReplicationInfo* ParentInfo = Find(Parent))
|
||||
{
|
||||
ParentInfo->DependentActorList.PrepareForWrite();
|
||||
ParentInfo->DependentActorList.Remove(Child);
|
||||
ParentInfo->DependentActorList.RemoveSingleSwap(Child);
|
||||
}
|
||||
|
||||
if (FGlobalActorReplicationInfo* ChildInfo = Find(Child))
|
||||
{
|
||||
ChildInfo->ParentActorList.PrepareForWrite();
|
||||
ChildInfo->ParentActorList.Remove(Parent);
|
||||
ChildInfo->ParentActorList.RemoveSingleSwap(Parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -805,33 +859,25 @@ struct FGlobalActorReplicationInfoMap
|
||||
return;
|
||||
}
|
||||
|
||||
if (MainActorInfo->ParentActorList.IsValid())
|
||||
// Remove this actor from all his parents
|
||||
for (FActorRepListType ParentActor : MainActorInfo->ParentActorList)
|
||||
{
|
||||
// Remove this actor from all his parents
|
||||
for (FActorRepListType ParentActor : MainActorInfo->ParentActorList)
|
||||
if (FGlobalActorReplicationInfo* ParentInfo = Find(ParentActor))
|
||||
{
|
||||
if (FGlobalActorReplicationInfo* ParentInfo = Find(ParentActor))
|
||||
{
|
||||
ParentInfo->DependentActorList.PrepareForWrite();
|
||||
ParentInfo->DependentActorList.Remove(MainActor);
|
||||
}
|
||||
ParentInfo->DependentActorList.RemoveSingleSwap(MainActor);
|
||||
}
|
||||
MainActorInfo->ParentActorList.Reset();
|
||||
}
|
||||
MainActorInfo->ParentActorList.Reset();
|
||||
|
||||
if (MainActorInfo->DependentActorList.IsValid())
|
||||
// Remove all dependant childs from this actor
|
||||
for (FActorRepListType ChildActor : MainActorInfo->DependentActorList)
|
||||
{
|
||||
// Remove all dependant childs from this actor
|
||||
for (FActorRepListType ChildActor : MainActorInfo->DependentActorList)
|
||||
if (FGlobalActorReplicationInfo* ChildInfo = Find(ChildActor))
|
||||
{
|
||||
if (FGlobalActorReplicationInfo* ChildInfo = Find(ChildActor))
|
||||
{
|
||||
ChildInfo->ParentActorList.PrepareForWrite();
|
||||
ChildInfo->ParentActorList.Remove(MainActor);
|
||||
}
|
||||
ChildInfo->ParentActorList.RemoveSingleSwap(MainActor);
|
||||
}
|
||||
MainActorInfo->DependentActorList.Reset();
|
||||
}
|
||||
MainActorInfo->DependentActorList.Reset();
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -1163,24 +1209,38 @@ struct REPLICATIONGRAPH_API FGatheredReplicationActorLists
|
||||
if (CVar_RepGraph_Verify)
|
||||
List.VerifyContents_Slow();
|
||||
#endif
|
||||
repCheck(List.IsValid());
|
||||
if (List.Num() > 0)
|
||||
{
|
||||
|
||||
OutReplicationLists.FindOrAdd(Flags).Emplace(FActorRepListRawView(List));
|
||||
ReplicationLists[(uint32)Flags].Emplace(FActorRepListConstView(List));
|
||||
CachedNum++;
|
||||
}
|
||||
}
|
||||
|
||||
FORCEINLINE void Reset() { OutReplicationLists.Reset(); CachedNum =0; }
|
||||
FORCEINLINE int32 NumLists() const { return CachedNum; }
|
||||
FORCEINLINE void Reset()
|
||||
{
|
||||
for (uint32 i = (uint32)EActorRepListTypeFlags::Default; i < (uint32)EActorRepListTypeFlags::Max; ++i)
|
||||
{
|
||||
ReplicationLists[i].Reset();
|
||||
}
|
||||
CachedNum=0;
|
||||
}
|
||||
FORCEINLINE int32 NumLists() const
|
||||
{
|
||||
return CachedNum;
|
||||
}
|
||||
|
||||
FORCEINLINE TArray< FActorRepListRawView>& GetLists(EActorRepListTypeFlags ListFlags) { return OutReplicationLists.FindOrAdd(ListFlags); }
|
||||
FORCEINLINE bool ContainsLists(EActorRepListTypeFlags Flags) { return OutReplicationLists.Contains(Flags); }
|
||||
FORCEINLINE const TArray<FActorRepListConstView>& GetLists(EActorRepListTypeFlags ListFlags) const
|
||||
{
|
||||
return ReplicationLists[(uint32)ListFlags];
|
||||
}
|
||||
FORCEINLINE bool ContainsLists(EActorRepListTypeFlags Flags) const
|
||||
{
|
||||
return ReplicationLists[(uint32)Flags].Num() > 0;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
TMap<EActorRepListTypeFlags, TArray< FActorRepListRawView> > OutReplicationLists;
|
||||
TStaticArray< TArray<FActorRepListConstView>, (uint32)EActorRepListTypeFlags::Max > ReplicationLists;
|
||||
int32 CachedNum = 0;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user