Skip to content

Commit

Permalink
Implemented a new type of pooling. To avoid costly properlty deserial…
Browse files Browse the repository at this point in the history
…ize and set, it spawns an actor from an existing template that is in the scene
  • Loading branch information
coderespawn committed Feb 4, 2020
1 parent d817814 commit b7f707e
Show file tree
Hide file tree
Showing 13 changed files with 126 additions and 38 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ void UPrefabricatorActorFactory::LoadPrefabActorState(APrefabActor* PrefabActor)

FPrefabLoadSettings LoadSettings;
LoadSettings.bUnregisterComponentsBeforeLoading = !bIsPreviewActor;
FPrefabTools::LoadStateFromPrefabAsset(PrefabActor, LoadSettings);
FPrefabLoadStatePtr LoadState = MakeShareable(new FPrefabLoadState);
FPrefabTools::LoadStateFromPrefabAsset(PrefabActor, LoadSettings, LoadState);
if (bIsPreviewActor) {
FPrefabTools::IterateChildrenRecursive(PrefabActor, [](AActor* ChildActor) {
ChildActor->SetActorEnableCollision(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,8 @@ FReply FPrefabActorCustomization::RandomizePrefabCollection(IDetailLayoutBuilder
FPrefabLoadSettings LoadSettings;
LoadSettings.bRandomizeNestedSeed = true;
LoadSettings.Random = &Random;
FPrefabTools::LoadStateFromPrefabAsset(PrefabActor, LoadSettings);
FPrefabLoadStatePtr LoadState = MakeShareable(new FPrefabLoadState);
FPrefabTools::LoadStateFromPrefabAsset(PrefabActor, LoadSettings, LoadState);
}
}
return FReply::Handled();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,17 +90,17 @@ void FPrefabricatorEditorService::SetDetailsViewObject(UObject* InObject)
}


AActor* FPrefabricatorEditorService::SpawnActor(TSubclassOf<AActor> InActorClass, const FTransform& InTransform, ULevel* InLevel)
AActor* FPrefabricatorEditorService::SpawnActor(TSubclassOf<AActor> InActorClass, const FTransform& InTransform, ULevel* InLevel, AActor* InTemplate)
{
if (GEditor) {
if (GEditor && !InTemplate) {
UActorFactory* ActorFactory = GEditor->FindActorFactoryByClassForActorClass(UActorFactoryBoxVolume::StaticClass(), InActorClass);
if (ActorFactory) {
FAssetData AssetData(InActorClass);
return ActorFactory->CreateActor(AssetData.GetAsset(), InLevel, InTransform);
}
}

return IPrefabricatorService::SpawnActor(InActorClass, InTransform, InLevel);
return IPrefabricatorService::SpawnActor(InActorClass, InTransform, InLevel, InTemplate);
}

namespace {
Expand Down Expand Up @@ -145,3 +145,8 @@ void FPrefabricatorEditorService::EndTransaction()
PrefabEndTransaction();
}

void FPrefabricatorEditorService::RunGC()
{
CollectGarbage(GARBAGE_COLLECTION_KEEPFLAGS);
}

Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ class PREFABRICATOREDITOR_API FPrefabricatorEditorService : public IPrefabricato
virtual UPrefabricatorAsset* CreatePrefabAsset() override;
virtual FVector SnapToGrid(const FVector& InLocation) override;
virtual void SetDetailsViewObject(UObject* InObject) override;
virtual AActor* SpawnActor(TSubclassOf<AActor> InClass, const FTransform& InTransform, ULevel* InLevel) override;
virtual AActor* SpawnActor(TSubclassOf<AActor> InClass, const FTransform& InTransform, ULevel* InLevel, AActor* InTemplate) override;
virtual void BeginTransaction(const FText& Description) override;
virtual void EndTransaction() override;

virtual void RunGC() override;
};

21 changes: 14 additions & 7 deletions Source/PrefabricatorRuntime/Private/Prefab/PrefabActor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,8 @@ void APrefabActor::PostDuplicate(EDuplicateMode::Type DuplicateMode)
FPrefabLoadSettings LoadSettings;
LoadSettings.bRandomizeNestedSeed = true;
LoadSettings.Random = &Random;
FPrefabTools::LoadStateFromPrefabAsset(this, LoadSettings);
FPrefabLoadStatePtr LoadState = MakeShareable(new FPrefabLoadState);
FPrefabTools::LoadStateFromPrefabAsset(this, LoadSettings, LoadState);
}
}

Expand All @@ -104,7 +105,8 @@ FName APrefabActor::GetCustomIconName() const

void APrefabActor::LoadPrefab()
{
FPrefabTools::LoadStateFromPrefabAsset(this);
FPrefabLoadStatePtr LoadState = MakeShareable(new FPrefabLoadState);
FPrefabTools::LoadStateFromPrefabAsset(this, FPrefabLoadSettings(), LoadState);
}

void APrefabActor::SavePrefab()
Expand Down Expand Up @@ -189,10 +191,11 @@ void FPrefabBuildSystem::PushCommand(FPrefabBuildSystemCommandPtr InCommand)
BuildStack.Push(InCommand);
}

FPrefabBuildSystemCommand_BuildPrefab::FPrefabBuildSystemCommand_BuildPrefab(TWeakObjectPtr<APrefabActor> InPrefab, bool bInRandomizeNestedSeed, FRandomStream* InRandom)
FPrefabBuildSystemCommand_BuildPrefab::FPrefabBuildSystemCommand_BuildPrefab(TWeakObjectPtr<APrefabActor> InPrefab, bool bInRandomizeNestedSeed, FRandomStream* InRandom, FPrefabLoadStatePtr InLoadState)
: Prefab(InPrefab)
, bRandomizeNestedSeed(bInRandomizeNestedSeed)
, Random(InRandom)
, LoadState(InLoadState)
{
}

Expand All @@ -208,7 +211,7 @@ void FPrefabBuildSystemCommand_BuildPrefab::Execute(FPrefabBuildSystem& BuildSys

{
SCOPE_CYCLE_COUNTER(STAT_Randomize_LoadPrefab);
FPrefabTools::LoadStateFromPrefabAsset(Prefab.Get(), LoadSettings);
FPrefabTools::LoadStateFromPrefabAsset(Prefab.Get(), LoadSettings, LoadState);
}

// Push a build complete notification request. Since this is a stack, it will execute after all the children are processed below
Expand All @@ -224,31 +227,35 @@ void FPrefabBuildSystemCommand_BuildPrefab::Execute(FPrefabBuildSystem& BuildSys
}
for (AActor* ChildActor : ChildActors) {
if (APrefabActor* ChildPrefab = Cast<APrefabActor>(ChildActor)) {
FPrefabBuildSystemCommandPtr ChildBuildCommand = MakeShareable(new FPrefabBuildSystemCommand_BuildPrefab(ChildPrefab, bRandomizeNestedSeed, Random));
FPrefabBuildSystemCommandPtr ChildBuildCommand = MakeShareable(new FPrefabBuildSystemCommand_BuildPrefab(ChildPrefab, bRandomizeNestedSeed, Random, LoadState));
BuildSystem.PushCommand(ChildBuildCommand);
}
}
}

/////////////////////////////////////

FPrefabBuildSystemCommand_BuildPrefabSync::FPrefabBuildSystemCommand_BuildPrefabSync(TWeakObjectPtr<APrefabActor> InPrefab, bool bInRandomizeNestedSeed, FRandomStream* InRandom)
FPrefabBuildSystemCommand_BuildPrefabSync::FPrefabBuildSystemCommand_BuildPrefabSync(TWeakObjectPtr<APrefabActor> InPrefab, bool bInRandomizeNestedSeed, FRandomStream* InRandom, FPrefabLoadStatePtr InLoadState)
: Prefab(InPrefab)
, bRandomizeNestedSeed(bInRandomizeNestedSeed)
, Random(InRandom)
, LoadState(InLoadState)
{
}

void FPrefabBuildSystemCommand_BuildPrefabSync::Execute(FPrefabBuildSystem& BuildSystem)
{
double StartTime = FPlatformTime::Seconds();
if (Prefab.IsValid()) {
Prefab->RandomizeSeed(*Random);

FPrefabLoadSettings LoadSettings;
LoadSettings.bRandomizeNestedSeed = true;
LoadSettings.Random = Random;
FPrefabTools::LoadStateFromPrefabAsset(Prefab.Get(), LoadSettings);
FPrefabTools::LoadStateFromPrefabAsset(Prefab.Get(), LoadSettings, LoadState);
}
double EndTime = FPlatformTime::Seconds();
UE_LOG(LogTemp, Warning, TEXT("Exec Time: %fs"), (EndTime - StartTime));
}

/////////////////////////////////////
Expand Down
46 changes: 34 additions & 12 deletions Source/PrefabricatorRuntime/Private/Prefab/PrefabTools.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ void FPrefabTools::SaveStateToPrefabAsset(APrefabActor* PrefabActor)
int32 NewItemIndex = PrefabAsset->ActorData.AddDefaulted();
FPrefabricatorActorData& ActorData = PrefabAsset->ActorData[NewItemIndex];
ActorData.PrefabItemID = ItemID;
SaveStateToPrefabAsset(ChildActor, PrefabActor, ActorData);
SaveActorState(ChildActor, PrefabActor, ActorData);
}
}
PrefabAsset->Version = (uint32)EPrefabricatorAssetVersion::LatestVersion;
Expand Down Expand Up @@ -447,7 +447,7 @@ bool FPrefabTools::ShouldForcePropertySerialization(const FName& PropertyName)
return FieldsToForceSerialize.Contains(PropertyName);
}

void FPrefabTools::SaveStateToPrefabAsset(AActor* InActor, APrefabActor* PrefabActor, FPrefabricatorActorData& OutActorData)
void FPrefabTools::SaveActorState(AActor* InActor, APrefabActor* PrefabActor, FPrefabricatorActorData& OutActorData)
{
if (!InActor) return;

Expand Down Expand Up @@ -482,7 +482,7 @@ void FPrefabTools::SaveStateToPrefabAsset(AActor* InActor, APrefabActor* PrefabA
DumpSerializedData(OutActorData);
}

void FPrefabTools::LoadStateFromPrefabAsset(AActor* InActor, const FPrefabricatorActorData& InActorData, const FPrefabLoadSettings& InSettings)
void FPrefabTools::LoadActorState(AActor* InActor, const FPrefabricatorActorData& InActorData, const FPrefabLoadSettings& InSettings)
{
if (!InActor) {
return;
Expand Down Expand Up @@ -602,7 +602,7 @@ FBox FPrefabTools::GetPrefabBounds(AActor* PrefabActor, bool bNonColliding)
return Result;
}

void FPrefabTools::LoadStateFromPrefabAsset(APrefabActor* PrefabActor, const FPrefabLoadSettings& InSettings)
void FPrefabTools::LoadStateFromPrefabAsset(APrefabActor* PrefabActor, const FPrefabLoadSettings& InSettings, FPrefabLoadStatePtr InState)
{
if (!PrefabActor) {
UE_LOG(LogPrefabTools, Error, TEXT("Invalid prefab actor reference"));
Expand Down Expand Up @@ -662,17 +662,39 @@ void FPrefabTools::LoadStateFromPrefabAsset(APrefabActor* PrefabActor, const FPr
if (!ChildActor) {
TSharedPtr<IPrefabricatorService> Service = FPrefabricatorService::Get();
if (Service.IsValid()) {
ChildActor = Service->SpawnActor(ActorClass, FTransform::Identity, PrefabActor->GetLevel());
AActor* Template = nullptr;
if (InState.IsValid()) {
TWeakObjectPtr<AActor>* SearchResult = InState->PrefabItemTemplates.Find(ActorItemData.PrefabItemID);
if (SearchResult) {
TWeakObjectPtr<AActor> ActorTemplatePtr = *SearchResult;
if (ActorTemplatePtr.IsValid()) {
Template = ActorTemplatePtr.Get();
}
}
}

ChildActor = Service->SpawnActor(ActorClass, FTransform::Identity, PrefabActor->GetLevel(), Template);
if (!Template) {
LoadActorState(ChildActor, ActorItemData, InSettings);
if (InState.IsValid()) {
InState->PrefabItemTemplates.Add(ActorItemData.PrefabItemID, ChildActor);
InState->_Stat_SlowSpawns++;
}
}
else {
if (InState.IsValid()) {
InState->_Stat_FastSpawns++;
}
}
}
}
else {
if (InState.IsValid()) {
InState->_Stat_ReuseSpawns++;
}
//FActorSpawnParameters SpawnParams;
//SpawnParams.OverrideLevel = PrefabActor->GetLevel();
//ChildActor = World->SpawnActor<AActor>(ActorClass, SpawnParams);
}

if (ChildActor) {
// Load the saved data into the actor
LoadStateFromPrefabAsset(ChildActor, ActorItemData, InSettings);

ParentActors(PrefabActor, ChildActor);
AssignAssetUserData(ChildActor, ActorItemData.PrefabItemID, PrefabActor);

Expand All @@ -694,7 +716,7 @@ void FPrefabTools::LoadStateFromPrefabAsset(APrefabActor* PrefabActor, const FPr
ChildPrefab->Seed = FPrefabTools::GetRandomSeed(*InSettings.Random);
}
if (InSettings.bSynchronousBuild) {
LoadStateFromPrefabAsset(ChildPrefab, InSettings);
LoadStateFromPrefabAsset(ChildPrefab, InSettings, InState);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
#include "GameFramework/Actor.h"
#include "Math/RandomStream.h"
#include "UObject/ConstructorHelpers.h"
#include "Prefab/PrefabTools.h"
#include "Utils/PrefabricatorService.h"

APrefabRandomizer::APrefabRandomizer(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
Expand Down Expand Up @@ -42,6 +44,16 @@ void APrefabRandomizer::Tick(float DeltaSeconds)
if (NumRemaining == 0) {
OnRandomizationComplete.Broadcast();
BuildSystem = nullptr;

// Run GC in the editor
TSharedPtr<IPrefabricatorService> Service = FPrefabricatorService::Get();
if (Service.IsValid()) {
Service->RunGC();
}

if (LoadState.IsValid()) {
UE_LOG(LogTemp, Log, TEXT("Slow[%d], Fast[%d], Reuse[%d]"), LoadState->_Stat_SlowSpawns, LoadState->_Stat_FastSpawns, LoadState->_Stat_ReuseSpawns);
}
}
}
}
Expand Down Expand Up @@ -111,13 +123,15 @@ void APrefabRandomizer::Randomize(int32 InSeed)
}

BuildSystem = MakeShareable(new FPrefabBuildSystem(MaxBuildTimePerFrame));
LoadState = bUseOptimizedPooling ? MakeShareable(new FPrefabLoadState) : nullptr;

for (APrefabActor* TopLevelPrefab : TopLevelPrefabs) {
FPrefabBuildSystemCommandPtr BuildCommand;
if (bFastSyncBuild) {
BuildCommand = MakeShareable(new FPrefabBuildSystemCommand_BuildPrefabSync(TopLevelPrefab, true, &Random));
BuildCommand = MakeShareable(new FPrefabBuildSystemCommand_BuildPrefabSync(TopLevelPrefab, true, &Random, LoadState));
}
else {
BuildCommand = MakeShareable(new FPrefabBuildSystemCommand_BuildPrefab(TopLevelPrefab, true, &Random));
BuildCommand = MakeShareable(new FPrefabBuildSystemCommand_BuildPrefab(TopLevelPrefab, true, &Random, LoadState));
}

BuildSystem->PushCommand(BuildCommand);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ void UPrefabricatorBlueprintLibrary::RandomizePrefab(APrefabActor* PrefabActor,
FPrefabLoadSettings LoadSettings;
LoadSettings.bRandomizeNestedSeed = true;
LoadSettings.Random = &InRandom;
FPrefabTools::LoadStateFromPrefabAsset(PrefabActor, LoadSettings);
FPrefabLoadStatePtr LoadState = MakeShareable(new FPrefabLoadState);
FPrefabTools::LoadStateFromPrefabAsset(PrefabActor, LoadSettings, LoadState);
}

void UPrefabricatorBlueprintLibrary::GetAllAttachedActors(AActor* Prefab, TArray<AActor*>& AttachedActors)
Expand Down
21 changes: 19 additions & 2 deletions Source/PrefabricatorRuntime/Private/Utils/PrefabricatorService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,33 @@ void FPrefabricatorService::Set(TSharedPtr<IPrefabricatorService> InInstance)


/////////////////////////// IPrefabricatorService ///////////////////////////
AActor* IPrefabricatorService::SpawnActor(TSubclassOf<AActor> InClass, const FTransform& InTransform, ULevel* InLevel)
AActor* IPrefabricatorService::SpawnActor(TSubclassOf<AActor> InClass, const FTransform& InTransform, ULevel* InLevel, AActor* InTemplate)
{
if (!InClass || !InLevel) {
return nullptr;
}

TArray<AActor*> AttachedToTemplate;
if (InTemplate) {
InTemplate->GetAttachedActors(AttachedToTemplate);
for (AActor* TemplateChild : AttachedToTemplate) {
TemplateChild->DetachFromActor(FDetachmentTransformRules(EDetachmentRule::KeepWorld, false));
}
}

FActorSpawnParameters SpawnParams;
SpawnParams.OverrideLevel = InLevel;
SpawnParams.Template = InTemplate;
UWorld* World = InLevel->GetWorld();
return World->SpawnActor<AActor>(InClass, InTransform, SpawnParams);
AActor* Actor = World->SpawnActor<AActor>(InClass, InTransform, SpawnParams);
TSharedPtr<IPrefabricatorService> Service = FPrefabricatorService::Get();
if (Actor && InTemplate && Service.IsValid()) {
// Attach the template children back
for (AActor* TemplateChild : AttachedToTemplate) {
Service->ParentActors(InTemplate, TemplateChild);
}
}
return Actor;
}

/////////////////////////// FPrefabricatorRuntimeService ///////////////////////////
Expand Down
7 changes: 5 additions & 2 deletions Source/PrefabricatorRuntime/Public/Prefab/PrefabActor.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ class PREFABRICATORRUNTIME_API APrefabActor : public AActor {
/////////////////////////////// BuildSystem ///////////////////////////////

class FPrefabBuildSystem;
typedef TSharedPtr<struct FPrefabLoadState> FPrefabLoadStatePtr;

class PREFABRICATORRUNTIME_API FPrefabBuildSystemCommand {
public:
Expand All @@ -66,26 +67,28 @@ typedef TSharedPtr<FPrefabBuildSystemCommand> FPrefabBuildSystemCommandPtr;

class PREFABRICATORRUNTIME_API FPrefabBuildSystemCommand_BuildPrefab : public FPrefabBuildSystemCommand {
public:
FPrefabBuildSystemCommand_BuildPrefab(TWeakObjectPtr<APrefabActor> InPrefab, bool bInRandomizeNestedSeed, FRandomStream* InRandom);
FPrefabBuildSystemCommand_BuildPrefab(TWeakObjectPtr<APrefabActor> InPrefab, bool bInRandomizeNestedSeed, FRandomStream* InRandom, FPrefabLoadStatePtr InLoadState);

virtual void Execute(FPrefabBuildSystem& BuildSystem) override;

private:
TWeakObjectPtr<APrefabActor> Prefab;
bool bRandomizeNestedSeed = false;
FRandomStream* Random = nullptr;
FPrefabLoadStatePtr LoadState;
};

class PREFABRICATORRUNTIME_API FPrefabBuildSystemCommand_BuildPrefabSync : public FPrefabBuildSystemCommand {
public:
FPrefabBuildSystemCommand_BuildPrefabSync(TWeakObjectPtr<APrefabActor> InPrefab, bool bInRandomizeNestedSeed, FRandomStream* InRandom);
FPrefabBuildSystemCommand_BuildPrefabSync(TWeakObjectPtr<APrefabActor> InPrefab, bool bInRandomizeNestedSeed, FRandomStream* InRandom, FPrefabLoadStatePtr InLoadState);

virtual void Execute(FPrefabBuildSystem& BuildSystem) override;

private:
TWeakObjectPtr<APrefabActor> Prefab;
bool bRandomizeNestedSeed = false;
FRandomStream* Random = nullptr;
FPrefabLoadStatePtr LoadState;
};

class PREFABRICATORRUNTIME_API FPrefabBuildSystemCommand_NotifyBuildComplete : public FPrefabBuildSystemCommand {
Expand Down
Loading

0 comments on commit b7f707e

Please sign in to comment.