Skip to content

Commit 8650569

Browse files
committed
GameInstances now only save once, class filter baking is now x10 to x15 times faster
1 parent 865f21a commit 8650569

8 files changed

Lines changed: 78 additions & 39 deletions

File tree

Source/SaveExtension/Private/Misc/ClassFilter.cpp

Lines changed: 36 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -29,41 +29,55 @@ void FSEClassFilter::Merge(const FSEClassFilter& Other)
2929

3030
void FSEClassFilter::BakeAllowedClasses() const
3131
{
32+
TRACE_CPUPROFILER_EVENT_SCOPE(FSEClassFilter::BakeAllowedClasses);
3233
BakedAllowedClasses.Empty();
3334

3435
if(AllowedClasses.Num() <= 0)
3536
{
3637
return;
3738
}
3839

39-
for (TObjectIterator<UClass> It; It; ++It)
40+
TArray<UClass*> PotentiallyAllowedClasses;
4041
{
41-
UClass* const Class = *It;
42-
43-
// Iterate parent classes of a class
44-
const UClass* CurrentClass = Class;
45-
while (CurrentClass)
42+
TRACE_CPUPROFILER_EVENT_SCOPE(First Pass: Potential classes);
43+
for(auto& AllowedClass : AllowedClasses)
4644
{
47-
// If parent class is allowed, we are allowed.
48-
// This prevents iteration to the first allowed. May not be worth it for performance
49-
if (BakedAllowedClasses.Contains(CurrentClass))
50-
{
51-
BakedAllowedClasses.Add(Class);
52-
break;
53-
}
54-
55-
if (AllowedClasses.Contains(CurrentClass))
45+
UClass* const AllowedClassPtr = AllowedClass.Get();
46+
for (TObjectIterator<UClass> It; It; ++It)
5647
{
57-
// First parent allowed class marks it as allowed
58-
BakedAllowedClasses.Add(Class);
59-
break;
48+
UClass* const Class = *It;
49+
if (AllowedClassPtr == Class)
50+
{
51+
BakedAllowedClasses.Add(Class);
52+
}
53+
else if(Class->IsChildOf(AllowedClassPtr))
54+
{
55+
PotentiallyAllowedClasses.Add(Class);
56+
}
6057
}
61-
else if (IgnoredClasses.Contains(CurrentClass))
58+
}
59+
}
60+
{
61+
TRACE_CPUPROFILER_EVENT_SCOPE(Second Pass: Bake Classes);
62+
for (UClass* Class : PotentiallyAllowedClasses)
63+
{
64+
// Iterate parent classes of a class
65+
const UClass* CurrentClass = Class;
66+
while (CurrentClass)
6267
{
63-
// First parent ignored class marks it as not allowed
64-
break;
68+
if (AllowedClasses.Contains(CurrentClass))
69+
{
70+
// First parent allowed class marks it as allowed
71+
BakedAllowedClasses.Add(Class);
72+
break;
73+
}
74+
else if (IgnoredClasses.Contains(CurrentClass))
75+
{
76+
// First parent ignored class marks it as not allowed
77+
break;
78+
}
79+
CurrentClass = CurrentClass->GetSuperClass();
6580
}
66-
CurrentClass = CurrentClass->GetSuperClass();
6781
}
6882
}
6983
}

Source/SaveExtension/Private/Serialization/MTTask_SerializeActors.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
// FMTTask_SerializeActors
1616
void FMTTask_SerializeActors::DoWork()
1717
{
18+
TRACE_CPUPROFILER_EVENT_SCOPE(FMTTask_SerializeActors::DoWork);
1819
if (bStoreGameInstance)
1920
{
2021
SerializeGameInstance();
@@ -33,6 +34,7 @@ void FMTTask_SerializeActors::DoWork()
3334

3435
void FMTTask_SerializeActors::SerializeGameInstance()
3536
{
37+
TRACE_CPUPROFILER_EVENT_SCOPE(FMTTask_SerializeActors::SerializeGameInstance);
3638
if (UGameInstance* GameInstance = World->GetGameInstance())
3739
{
3840
FObjectRecord Record{ GameInstance };
@@ -48,6 +50,8 @@ void FMTTask_SerializeActors::SerializeGameInstance()
4850

4951
bool FMTTask_SerializeActors::SerializeActor(const AActor* Actor, FActorRecord& Record) const
5052
{
53+
TRACE_CPUPROFILER_EVENT_SCOPE(FMTTask_SerializeActors::SerializeActor);
54+
5155
//Clean the record
5256
Record = { Actor };
5357

@@ -106,9 +110,12 @@ bool FMTTask_SerializeActors::SerializeActor(const AActor* Actor, FActorRecord&
106110

107111
void FMTTask_SerializeActors::SerializeActorComponents(const AActor* Actor, FActorRecord& ActorRecord, int8 Indent /*= 0*/) const
108112
{
113+
TRACE_CPUPROFILER_EVENT_SCOPE(FMTTask_SerializeActors::SerializeActorComponents);
114+
109115
const TSet<UActorComponent*>& Components = Actor->GetComponents();
110116
for (auto* Component : Components)
111117
{
118+
TRACE_CPUPROFILER_EVENT_SCOPE(FMTTask_SerializeActors::SerializeActorComponents|Component);
112119
if (Filter.ShouldSave(Component))
113120
{
114121
FComponentRecord ComponentRecord;

Source/SaveExtension/Private/Serialization/SlotDataTask.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ USaveManager* USlotDataTask::GetManager() const
4646

4747
void USlotDataTask::BakeAllFilters()
4848
{
49+
TRACE_CPUPROFILER_EVENT_SCOPE(USlotDataTask::BakeAllFilters);
4950
SlotData->GeneralLevelFilter.BakeAllowedClasses();
5051

5152
if(SlotData->MainLevel.bOverrideGeneralFilter)

Source/SaveExtension/Private/Serialization/SlotDataTask_Loader.cpp

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,11 @@ void USlotDataTask_Loader::DeserializeLevelSync(const ULevel* Level, const ULeve
270270

271271
for (auto ActorItr = Level->Actors.CreateConstIterator(); ActorItr; ++ActorItr)
272272
{
273-
DeserializeLevel_Actor(*ActorItr, *LevelRecord, Filter);
273+
auto* Actor = *ActorItr;
274+
if (IsValid(Actor) && Filter.ShouldSave(Actor))
275+
{
276+
DeserializeLevel_Actor(Actor, *LevelRecord, Filter);
277+
}
274278
}
275279
}
276280
}
@@ -336,15 +340,17 @@ void USlotDataTask_Loader::DeserializeASyncLoop(float StartMS)
336340
// Continue Iterating actors every tick
337341
for (; CurrentActorIndex < CurrentLevelActors.Num(); ++CurrentActorIndex)
338342
{
339-
AActor* Actor{ CurrentLevelActors[CurrentActorIndex].Get() };
340-
if (Actor)
343+
AActor* const Actor{ CurrentLevelActors[CurrentActorIndex].Get() };
344+
if (IsValid(Actor) && Filter.ShouldSave(Actor))
341345
{
342346
DeserializeLevel_Actor(Actor, *LevelRecord, Filter);
343347

344348
const float CurrentMS = GetTimeMilliseconds();
345-
// If x milliseconds passed, continue on next frame
349+
// If x milliseconds passed, stop and continue on next frame
346350
if (CurrentMS - StartMS >= MaxFrameMs)
351+
{
347352
return;
353+
}
348354
}
349355
}
350356

@@ -466,14 +472,11 @@ void USlotDataTask_Loader::DeserializeLevel_Actor(AActor* const Actor, const FLe
466472
{
467473
QUICK_SCOPE_CYCLE_COUNTER(STAT_Loading_DeserializeLevel_Actor);
468474

469-
if (IsValid(Actor) && Filter.ShouldSave(Actor))
475+
// Find the record
476+
const FActorRecord* const Record = LevelRecord.Actors.FindByKey(Actor);
477+
if (Record && Record->IsValid() && Record->Class == Actor->GetClass())
470478
{
471-
// Find the record
472-
const FActorRecord* const Record = LevelRecord.Actors.FindByKey(Actor);
473-
if (Record && Record->IsValid() && Record->Class == Actor->GetClass())
474-
{
475-
DeserializeActor(Actor, *Record, Filter);
476-
}
479+
DeserializeActor(Actor, *Record, Filter);
477480
}
478481
}
479482

Source/SaveExtension/Private/Serialization/SlotDataTask_Saver.cpp

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
void USlotDataTask_Saver::OnStart()
2020
{
21+
TRACE_CPUPROFILER_EVENT_SCOPE(USlotDataTask_Saver::OnStart);
2122
USaveManager* Manager = GetManager();
2223
Manager->TryInstantiateInfo();
2324

@@ -107,6 +108,7 @@ void USlotDataTask_Saver::OnStart()
107108

108109
void USlotDataTask_Saver::Tick(float DeltaTime)
109110
{
111+
TRACE_CPUPROFILER_EVENT_SCOPE(USlotDataTask_Saver::Tick);
110112
Super::Tick(DeltaTime);
111113

112114
if (SaveTask && SaveTask->IsDone())
@@ -127,6 +129,7 @@ void USlotDataTask_Saver::Tick(float DeltaTime)
127129

128130
void USlotDataTask_Saver::OnFinish(bool bSuccess)
129131
{
132+
TRACE_CPUPROFILER_EVENT_SCOPE(USlotDataTask_Saver::OnFinish);
130133
if (bSuccess)
131134
{
132135
// Clean serialization data
@@ -158,6 +161,7 @@ void USlotDataTask_Saver::BeginDestroy()
158161

159162
void USlotDataTask_Saver::SerializeSync()
160163
{
164+
TRACE_CPUPROFILER_EVENT_SCOPE(USlotDataTask_Saver::SerializeSync);
161165
// Has Authority
162166
if (GetWorld()->GetAuthGameMode())
163167
{
@@ -168,8 +172,9 @@ void USlotDataTask_Saver::SerializeSync()
168172

169173
void USlotDataTask_Saver::SerializeWorld()
170174
{
171-
const UWorld* World = GetWorld();
175+
TRACE_CPUPROFILER_EVENT_SCOPE(USlotDataTask_Saver::SerializeWorld);
172176

177+
const UWorld* World = GetWorld();
173178
SELog(Preset, "World '" + World->GetName() + "'", FColor::Green, false, 1);
174179

175180
BakeAllFilters();
@@ -196,6 +201,7 @@ void USlotDataTask_Saver::SerializeWorld()
196201

197202
void USlotDataTask_Saver::SerializeLevelSync(const ULevel* Level, int32 AssignedTasks, const ULevelStreaming* StreamingLevel)
198203
{
204+
TRACE_CPUPROFILER_EVENT_SCOPE(USlotDataTask_Saver::SerializeLevelSync);
199205
check(IsValid(Level));
200206

201207
if (!Preset->IsMTSerializationSave())
@@ -234,16 +240,22 @@ void USlotDataTask_Saver::SerializeLevelSync(const ULevel* Level, int32 Assigned
234240
const int32 NumRemaining = ActorCount - Index;
235241
const int32 NumToSerialize = FMath::Min(NumRemaining, NumPerTask);
236242

243+
// First task saves the GameInstance
244+
bool bStoreGameInstance = Index <= 0 && SlotData->bStoreGameInstance;
237245
// Add new Task
238-
Tasks.Emplace(FMTTask_SerializeActors{
239-
GetWorld(), SlotData, &Level->Actors, Index, NumToSerialize, LevelRecord, Filter});
246+
Tasks.Emplace(FMTTask_SerializeActors
247+
{
248+
GetWorld(), SlotData, &Level->Actors, Index, NumToSerialize,
249+
bStoreGameInstance, LevelRecord, Filter
250+
});
240251

241252
Index += NumToSerialize;
242253
}
243254
}
244255

245256
void USlotDataTask_Saver::RunScheduledTasks()
246257
{
258+
TRACE_CPUPROFILER_EVENT_SCOPE(USlotDataTask_Saver::RunScheduledTasks);
247259
// Start all serialization tasks
248260
if (Tasks.Num() > 0)
249261
{
@@ -272,6 +284,7 @@ void USlotDataTask_Saver::RunScheduledTasks()
272284

273285
void USlotDataTask_Saver::SaveFile()
274286
{
287+
TRACE_CPUPROFILER_EVENT_SCOPE(USlotDataTask_Saver::SaveFile);
275288
USaveManager* Manager = GetManager();
276289

277290
SaveTask = new FAsyncTask<FSaveFileTask>(

Source/SaveExtension/Public/LevelFilter.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ struct FSELevelFilter
5353

5454
void BakeAllowedClasses() const
5555
{
56+
TRACE_CPUPROFILER_EVENT_SCOPE(FSELevelFilter::BakeAllowedClasses);
5657
ActorFilter.BakeAllowedClasses();
5758
ComponentFilter.BakeAllowedClasses();
5859
LoadActorFilter.BakeAllowedClasses();

Source/SaveExtension/Public/SavePreset.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ class SAVEEXTENSION_API USavePreset : public UObject
9090

9191
/** If true will store the game instance */
9292
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Serialization)
93-
bool bStoreGameInstance = false;
93+
bool bStoreGameInstance = true;
9494

9595
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Serialization|Actors")
9696
FSEActorClassFilter ActorFilter;

Source/SaveExtension/Public/Serialization/MTTask_SerializeActors.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,13 @@ class FMTTask_SerializeActors : public FMTTask
4343

4444
public:
4545
FMTTask_SerializeActors(const UWorld* World, USlotData* SlotData,
46-
const TArray<AActor*>* const InLevelActors, const int32 InStartIndex, const int32 InNum,
46+
const TArray<AActor*>* const InLevelActors, const int32 InStartIndex, const int32 InNum, bool bStoreGameInstance,
4747
FLevelRecord* InLevelRecord, const FSELevelFilter& Filter)
4848
: FMTTask(false, World, SlotData, Filter)
4949
, LevelActors(InLevelActors)
5050
, StartIndex(InStartIndex)
5151
, Num(InNum)
52-
, bStoreGameInstance(SlotData->bStoreGameInstance)
52+
, bStoreGameInstance(bStoreGameInstance)
5353
, LevelRecord(InLevelRecord)
5454
, LevelScriptRecord{}
5555
, ActorRecords{}

0 commit comments

Comments
 (0)