Skip to content
This repository has been archived by the owner on Aug 29, 2024. It is now read-only.

Commit

Permalink
[UNR-2887] Fix: Dynamic subobjects attached near actor creation would…
Browse files Browse the repository at this point in the history
… not be able to replicate their properties (#1806)

Previously, if trying to create and attach a dynamic subobject to an actor near its creation point, the fields of the dynamic component would not replicate properly after initial creation.
The reason for this was that we were not setting component write ACLs properly for these subobjects. This was due to the change made earlier, to resolve dynamic components earlier, which caused the code trying to check if the subobject is dynamically attached to think it was not dynamically attached, since it has already been resolved. This is fixed by decoupling the writing of ACLs from the resolution of the dynamic object in `SpatialSender::CreateEntity`.

Also a drive-by fix for $lld spam in logs.
Also a drive-by fix for authority queuing not checking which component we got authority over and potentially firing component updates for objects we did not have authority over.

* Initial fix by modifying write ACLs anytime we create a component

* Replace RemoveCurrent with RemoveAtSwap

* Change back to iterator, as we need to preserve order of component updates
  • Loading branch information
mironec authored Feb 19, 2020
1 parent df7d629 commit e826a6e
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,7 @@ void USpatialReceiver::HandleActorAuthority(const Worker_AuthorityChangeOp& Op)
// TODO UNR-955 - Remove this once batch reservation of EntityIds are in.
if (Op.authority == WORKER_AUTHORITY_AUTHORITATIVE)
{
Sender->ProcessUpdatesQueuedUntilAuthority(Op.entity_id);
Sender->ProcessUpdatesQueuedUntilAuthority(Op.entity_id, Op.component_id);
}

// If we became authoritative over the position component. set our role to be ROLE_Authority
Expand Down Expand Up @@ -538,7 +538,7 @@ void USpatialReceiver::ReceiveActor(Worker_EntityId EntityId)
if (AActor* EntityActor = Cast<AActor>(PackageMap->GetObjectFromEntityId(EntityId)))
{
UE_LOG(LogSpatialReceiver, Log, TEXT("Entity for actor %s has been checked out on the worker which spawned it or is a singleton linked on this worker. "
"Entity id: $lld"), *EntityActor->GetName(), EntityId);
"Entity id: %lld"), *EntityActor->GetName(), EntityId);

// Assume SimulatedProxy until we've been delegated Authority
bool bAuthority = StaticComponentView->GetAuthority(EntityId, Position::ComponentId) == WORKER_AUTHORITY_AUTHORITATIVE;
Expand Down
32 changes: 20 additions & 12 deletions SpatialGDK/Source/SpatialGDK/Private/Interop/SpatialSender.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -292,21 +292,21 @@ Worker_RequestId USpatialSender::CreateEntity(USpatialActorChannel* Channel)
// This is a failure but there is already a log inside TryResolveNewDynamicSubbojectAndGetClassInfo
continue;
}

ForAllSchemaComponentTypes([&](ESchemaComponentType Type)
{
if (SubobjectInfo->SchemaComponents[Type] != SpatialConstants::INVALID_COMPONENT_ID)
{
ComponentWriteAcl.Add(SubobjectInfo->SchemaComponents[Type], AuthoritativeWorkerRequirementSet);
}
});
}

const FClassInfo& SubobjectInfo = ClassInfoManager->GetOrCreateClassInfoByObject(Subobject);

FRepChangeState SubobjectRepChanges = Channel->CreateInitialRepChangeState(Subobject);
FHandoverChangeState SubobjectHandoverChanges = Channel->CreateInitialHandoverChangeState(SubobjectInfo);

ForAllSchemaComponentTypes([&](ESchemaComponentType Type)
{
if (SubobjectInfo.SchemaComponents[Type] != SpatialConstants::INVALID_COMPONENT_ID)
{
ComponentWriteAcl.Add(SubobjectInfo.SchemaComponents[Type], AuthoritativeWorkerRequirementSet);
}
});

TArray<Worker_ComponentData> ActorSubobjectDatas = DataFactory.CreateComponentDatas(Subobject, SubobjectInfo, SubobjectRepChanges, SubobjectHandoverChanges);
ComponentDatas.Append(ActorSubobjectDatas);
}
Expand Down Expand Up @@ -539,15 +539,23 @@ void USpatialSender::SendComponentUpdates(UObject* Object, const FClassInfo& Inf
}

// Apply (and clean up) any updates queued, due to being sent previously when they didn't have authority.
void USpatialSender::ProcessUpdatesQueuedUntilAuthority(Worker_EntityId EntityId)
void USpatialSender::ProcessUpdatesQueuedUntilAuthority(Worker_EntityId EntityId, Worker_ComponentId ComponentId)
{
if (TArray<Worker_ComponentUpdate>* UpdatesQueuedUntilAuthority = UpdatesQueuedUntilAuthorityMap.Find(EntityId))
{
for (Worker_ComponentUpdate& Update : *UpdatesQueuedUntilAuthority)
for (auto It = UpdatesQueuedUntilAuthority->CreateIterator(); It; It++)
{
if (ComponentId == It->component_id)
{
Connection->SendComponentUpdate(EntityId, &(*It));
It.RemoveCurrent();
}
}

if (UpdatesQueuedUntilAuthority->Num() == 0)
{
Connection->SendComponentUpdate(EntityId, &Update);
UpdatesQueuedUntilAuthorityMap.Remove(EntityId);
}
UpdatesQueuedUntilAuthorityMap.Remove(EntityId);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ class SPATIALGDK_API USpatialSender : public UObject
void UpdateInterestComponent(AActor* Actor);

void ProcessOrQueueOutgoingRPC(const FUnrealObjectRef& InTargetObjectRef, SpatialGDK::RPCPayload&& InPayload);
void ProcessUpdatesQueuedUntilAuthority(Worker_EntityId EntityId);
void ProcessUpdatesQueuedUntilAuthority(Worker_EntityId EntityId, Worker_ComponentId ComponentId);

void FlushPackedRPCs();

Expand Down

0 comments on commit e826a6e

Please sign in to comment.