Skip to content
This repository has been archived by the owner on Jan 18, 2022. It is now read-only.

Commit

Permalink
Bugfix/singleton resumption quickfix (#967)
Browse files Browse the repository at this point in the history
* Work around for singleton actors not linking correctly when reconnecting server workers

* Handle singleton linking before GSM checkout

* Change log and warning escalation
  • Loading branch information
m-samiec authored May 23, 2019
1 parent df3770c commit 06e8936
Show file tree
Hide file tree
Showing 5 changed files with 41 additions and 3 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Reliable RPC checking no longer breaks compatibility between development and shipping builds.
- Fixed an issue with schema name collisions.
- Running Schema (Full Scan) now clears generated schema files first.
- Singletons authority and state resumes correct when reconnecting servers to snapshot.

### External contributors:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,17 @@ USpatialActorChannel* UGlobalStateManager::AddSingleton(AActor* SingletonActor)
return Channel;
}

void UGlobalStateManager::RegisterSingletonChannel(AActor* SingletonActor, USpatialActorChannel* SingletonChannel)
{
TPair<AActor*, USpatialActorChannel*>& ActorChannelPair = NetDriver->SingletonActorChannels.FindOrAdd(SingletonActor->GetClass());

check(ActorChannelPair.Key == nullptr || ActorChannelPair.Key == SingletonActor);
check(ActorChannelPair.Value == nullptr || ActorChannelPair.Value == SingletonChannel);

ActorChannelPair.Key = SingletonActor;
ActorChannelPair.Value = SingletonChannel;
}

void UGlobalStateManager::ExecuteInitialSingletonActorReplication()
{
for (auto& ClassToActorChannel : NetDriver->SingletonActorChannels)
Expand Down
29 changes: 26 additions & 3 deletions SpatialGDK/Source/SpatialGDK/Private/Interop/SpatialReceiver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "Engine/Engine.h"
#include "Engine/World.h"
#include "GameFramework/PlayerController.h"
#include "Kismet/GameplayStatics.h"
#include "TimerManager.h"

#include "EngineClasses/SpatialFastArrayNetSerialize.h"
Expand Down Expand Up @@ -465,6 +466,11 @@ void USpatialReceiver::ReceiveActor(Worker_EntityId EntityId)
EntityActor->DispatchBeginPlay();
}

if (EntityActor->GetClass()->HasAnySpatialClassFlags(SPATIALCLASS_Singleton))
{
GlobalStateManager->RegisterSingletonChannel(EntityActor, Channel);
}

EntityActor->UpdateOverlaps();
}
}
Expand Down Expand Up @@ -676,9 +682,7 @@ AActor* USpatialReceiver::CreateActor(UnrealMetadata* UnrealMetadataComp, SpawnD
// Initial Singleton Actor replication is handled with GlobalStateManager::LinkExistingSingletonActors
if (NetDriver->IsServer() && ActorClass->HasAnySpatialClassFlags(SPATIALCLASS_Singleton))
{
// If GSM doesn't know of this entity id, queue up data for that entity id, and resolve it when the actor is created - UNR-734
// If the GSM does know of this entity id, we could just create the actor instead - UNR-735
return nullptr;
return FindSingletonActor(ActorClass);
}

// If we're checking out a player controller, spawn it via "USpatialNetDriver::AcceptNewPlayer"
Expand Down Expand Up @@ -1275,6 +1279,25 @@ TWeakObjectPtr<USpatialActorChannel> USpatialReceiver::PopPendingActorRequest(Wo
return Channel;
}

AActor* USpatialReceiver::FindSingletonActor(UClass* SingletonClass)
{
TArray<AActor*> FoundActors;
UGameplayStatics::GetAllActorsOfClass(NetDriver->World, SingletonClass, FoundActors);

// There should be only one singleton actor per class
if (FoundActors.Num() == 1)
{
return FoundActors[0];
}
else
{
UE_LOG(LogSpatialReceiver, Error, TEXT("Found incorrect number (%d) of singleton actors (%s)"),
FoundActors.Num(), *SingletonClass->GetName());
}

return nullptr;
}

void USpatialReceiver::ProcessQueuedResolvedObjects()
{
for (TPair<UObject*, FUnrealObjectRef>& It : ResolvedObjectQueue)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ class SPATIALGDK_API UGlobalStateManager : public UObject
bool HasAuthority();

USpatialActorChannel* AddSingleton(AActor* SingletonActor);
void RegisterSingletonChannel(AActor* SingletonActor, USpatialActorChannel* SingletonChannel);

Worker_EntityId GlobalStateManagerEntityId;

Expand Down
2 changes: 2 additions & 0 deletions SpatialGDK/Source/SpatialGDK/Public/Interop/SpatialReceiver.h
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,8 @@ class USpatialReceiver : public UObject
void UpdateShadowData(Worker_EntityId EntityId);
TWeakObjectPtr<USpatialActorChannel> PopPendingActorRequest(Worker_RequestId RequestId);

AActor* FindSingletonActor(UClass* SingletonClass);

public:
TMap<FUnrealObjectRef, TSet<FChannelObjectPair>> IncomingRefsMap;

Expand Down

0 comments on commit 06e8936

Please sign in to comment.