Skip to content

Commit 1a34ed2

Browse files
committed
Multiple improvement and crash fixes
1 parent df2d0e2 commit 1a34ed2

16 files changed

Lines changed: 347 additions & 129 deletions

.gitlab-ci.yml

Lines changed: 0 additions & 43 deletions
This file was deleted.

Source/SaveExtension/Private/SEFileHelpers.cpp

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,7 @@ bool FSEFileHelpers::FileExists(FStringView SlotName)
336336

337337
const FString& FSEFileHelpers::GetSaveFolder()
338338
{
339-
static const FString Folder = FString::Printf(TEXT("%sSaveGames/"), *FPaths::ProjectSavedDir());
339+
static const FString Folder = FPaths::Combine(FPaths::ProjectSavedDir(), "SaveGames");
340340
return Folder;
341341
}
342342

@@ -347,8 +347,19 @@ FString FSEFileHelpers::GetSlotPath(FStringView SlotName)
347347

348348
void FSEFileHelpers::FindAllFilesSync(TArray<FString>& FoundSlots)
349349
{
350-
FSEFindSlotVisitor Visitor{FoundSlots};
351-
FPlatformFileManager::Get().GetPlatformFile().IterateDirectory(*FSEFileHelpers::GetSaveFolder(), Visitor);
350+
TArray<FString> Out;
351+
FSEFindSlotVisitor Visitor{Out};
352+
const FString SaveFolder = GetSlotPath(TEXT("SharedGameSettings"));
353+
FString PathString = IFileManager::Get().ConvertToAbsolutePathForExternalAppForRead(*SaveFolder);
354+
PathString.RemoveFromEnd("/SharedGameSettings.sav");
355+
356+
FPlatformFileManager::Get().GetPlatformFile().IterateDirectory(*PathString, Visitor);
357+
358+
FoundSlots.SetNum(Out.Num());
359+
for (int32 i = 0; i < Out.Num(); ++i)
360+
{
361+
FoundSlots[i] = Out[i];
362+
}
352363
}
353364

354365
UObject* FSEFileHelpers::DeserializeObject(

Source/SaveExtension/Private/SaveManager.cpp

Lines changed: 86 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <EngineUtils.h>
1818
#include <GameDelegates.h>
1919
#include <GameFramework/GameModeBase.h>
20+
#include <GameFramework/PlayerState.h>
2021
#include <HighResScreenshot.h>
2122
#include <Kismet/GameplayStatics.h>
2223
#include <LatentActions.h>
@@ -188,6 +189,64 @@ class FSaveGameAction : public FPendingLatentAction
188189

189190
// END Async Actions
190191

192+
void USaveManager::ResetSelectedSave()
193+
{
194+
AutoLoadSlot = nullptr;
195+
}
196+
197+
void USaveManager::ContinueGame()
198+
{
199+
AutoLoadSlot = ActiveSlot;
200+
LoadSlot(AutoLoadSlot->Name);
201+
}
202+
203+
bool USaveManager::CanContinueGame(const APlayerState* PlayerState) const
204+
{
205+
return ActiveSlot != nullptr && ActiveSlot->GetData() != nullptr &&
206+
ActiveSlot->GetData()->FindPlayerRecord(PlayerState->GetUniqueId()) !=
207+
nullptr; // && level matches the play level
208+
}
209+
210+
bool USaveManager::HasActiveSaveForPlayer(const APlayerState* PlayerState) const
211+
{
212+
if (AutoLoadSlot)
213+
{
214+
return AutoLoadSlot->GetData()->FindPlayerRecord(PlayerState->GetUniqueId()) != nullptr;
215+
}
216+
return false;
217+
}
218+
219+
void USaveManager::HandlePlayerAdded(APlayerState* PlayerState)
220+
{
221+
if (PlayerState && AutoLoadSlot)
222+
{
223+
AutoLoadSlot->ComponentFilter.BakeAllowedClasses();
224+
if (const FPlayerRecord* PlayerRecord =
225+
AutoLoadSlot->GetData()->FindPlayerRecord(PlayerState->GetUniqueId()))
226+
{
227+
SERecords::DeserializePlayer(PlayerState, *PlayerRecord, AutoLoadSlot->ComponentFilter);
228+
}
229+
}
230+
if (!PlayerState->GetPawn() && AutoLoadSlot)
231+
{
232+
APlayerController* PC = Cast<APlayerController>(PlayerState->GetOwner());
233+
PC->OnPossessedPawnChanged.AddUniqueDynamic(this, &USaveManager::HandlePawnAdded);
234+
}
235+
}
236+
237+
void USaveManager::HandlePawnAdded(APawn* OldPawn, APawn* NewPawn)
238+
{
239+
if (NewPawn && AutoLoadSlot)
240+
{
241+
if (const FPlayerRecord* PlayerRecord =
242+
AutoLoadSlot->GetData()->FindPlayerRecord(NewPawn->GetPlayerState()->GetUniqueId()))
243+
{
244+
SERecords::DeserializeActor(NewPawn, PlayerRecord->Pawn, AutoLoadSlot->ComponentFilter);
245+
APlayerController* PC = Cast<APlayerController>(NewPawn->GetController());
246+
PC->OnPossessedPawnChanged.RemoveAll(this);
247+
}
248+
}
249+
}
191250

192251
USaveManager::USaveManager() : Super() {}
193252

@@ -200,6 +259,8 @@ void USaveManager::Initialize(FSubsystemCollectionBase& Collection)
200259
FCoreUObjectDelegates::PreLoadMap.AddUObject(this, &USaveManager::OnMapLoadStarted);
201260
FCoreUObjectDelegates::PostLoadMapWithWorld.AddUObject(this, &USaveManager::OnMapLoadFinished);
202261

262+
// TODO: Allow loading on start the most recent slot
263+
// PreloadAllSlotsSync(LoadedSlots, true);
203264
AssureActiveSlot();
204265
if (ActiveSlot && ActiveSlot->bLoadOnStart)
205266
{
@@ -447,10 +508,10 @@ void USaveManager::BPDeleteAllSlots(ESEContinue& Result, struct FLatentActionInf
447508

448509
USaveSlot* USaveManager::PreloadSlot(FName SlotName)
449510
{
450-
USaveSlot* Slot = nullptr;
511+
PreloadedSlot = nullptr;
451512
const FString NameStr = SlotName.ToString();
452-
Slot = FSEFileHelpers::LoadFileSync(NameStr, nullptr, true, this);
453-
return Slot;
513+
PreloadedSlot = FSEFileHelpers::LoadFileSync(NameStr, nullptr, true, this);
514+
return PreloadedSlot;
454515
}
455516

456517
bool USaveManager::IsSlotSaved(FName SlotName) const
@@ -530,9 +591,15 @@ void USaveManager::DeserializeStreamingLevel(ULevelStreaming* LevelStreaming)
530591

531592
void USaveManager::FinishTask(FSEDataTask* Task)
532593
{
533-
Tasks.RemoveAll([Task](auto& TaskPtr) {
534-
return TaskPtr.Get() == Task;
535-
});
594+
for (int32 TaskIndex = 0; TaskIndex < Tasks.Num(); ++TaskIndex)
595+
{
596+
if (Tasks[TaskIndex].Get() == Task)
597+
{
598+
FinishedTasks.Add(TUniquePtr<FSEDataTask>(Tasks[TaskIndex].Release()));
599+
Tasks.RemoveAt(TaskIndex);
600+
break;
601+
}
602+
}
536603

537604
// Start next task
538605
if (Tasks.Num() > 0)
@@ -548,6 +615,7 @@ bool USaveManager::IsLoading() const
548615

549616
void USaveManager::Tick(float DeltaTime)
550617
{
618+
FinishedTasks.Reset();
551619
if (Tasks.Num())
552620
{
553621
FSEDataTask* Task = Tasks[0].Get();
@@ -569,6 +637,14 @@ void USaveManager::UnsubscribeFromEvents(const TScriptInterface<ISaveExtensionIn
569637
SubscribedInterfaces.Remove(Interface);
570638
}
571639

640+
bool USaveManager::IsSubscribedToEvents(const UObject* InterfaceObject) const
641+
{
642+
return SubscribedInterfaces.ContainsByPredicate(
643+
[InterfaceObject](const TScriptInterface<ISaveExtensionInterface>& TestedObject) {
644+
return InterfaceObject && TestedObject.GetObject() == InterfaceObject;
645+
});
646+
}
647+
572648
void USaveManager::OnSaveBegan()
573649
{
574650
TRACE_CPUPROFILER_EVENT_SCOPE(USaveManager::OnSaveBegan);
@@ -613,7 +689,7 @@ void USaveManager::OnSaveFinished(const bool bError)
613689
void USaveManager::OnLoadBegan()
614690
{
615691
TRACE_CPUPROFILER_EVENT_SCOPE(USaveManager::OnLoadBegan);
616-
692+
617693
FSELevelFilter Filter;
618694
IterateSubscribedInterfaces([&Filter](auto* Object) {
619695
check(Object->template Implements<USaveExtensionInterface>());
@@ -675,7 +751,7 @@ UWorld* USaveManager::GetWorld() const
675751
return GetGameInstance()->GetWorld();
676752
}
677753

678-
inline void USaveManager::BPSaveSlot(const USaveSlot* Slot, bool bScreenshot, const FScreenshotSize Size,
754+
void USaveManager::BPSaveSlot(const USaveSlot* Slot, bool bScreenshot, const FScreenshotSize Size,
679755
ESEContinueOrFail& Result, struct FLatentActionInfo LatentInfo, bool bOverrideIfNeeded)
680756
{
681757
if (!Slot)
@@ -698,9 +774,9 @@ void USaveManager::BPLoadSlot(const USaveSlot* Slot, ESEContinueOrFail& Result,
698774

699775
void USaveManager::IterateSubscribedInterfaces(TFunction<void(UObject*)>&& Callback)
700776
{
701-
for (const TScriptInterface<ISaveExtensionInterface>& Interface : SubscribedInterfaces)
777+
for (int32 i = 0; i < SubscribedInterfaces.Num(); ++i)
702778
{
703-
if (UObject* const Object = Interface.GetObject())
779+
if (UObject* const Object = SubscribedInterfaces[i].GetObject())
704780
{
705781
Callback(Object);
706782
}

Source/SaveExtension/Private/SaveSlotData.cpp

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,26 @@ void USaveSlotData::Serialize(FArchive& Ar)
1616
Ar << GameInstance;
1717
RootLevel.Serialize(Ar);
1818
Ar << SubLevels;
19+
20+
uint8 NumPlayers = Players.Num();
21+
Ar << NumPlayers;
22+
if (Ar.IsSaving())
23+
{
24+
for (int32 i = 0; i < NumPlayers; ++i)
25+
{
26+
Players[i].Serialize(Ar);
27+
}
28+
}
29+
if (Ar.IsLoading())
30+
{
31+
Players.Empty(NumPlayers);
32+
for (int32 i = 0; i < NumPlayers; ++i)
33+
{
34+
FPlayerRecord PlayerRecord;
35+
PlayerRecord.Serialize(Ar);
36+
Players.Add(PlayerRecord);
37+
}
38+
}
1939
}
2040

2141
void USaveSlotData::CleanRecords(bool bKeepSublevels)
@@ -32,13 +52,14 @@ void USaveSlotData::CleanRecords(bool bKeepSublevels)
3252

3353
FPlayerRecord& USaveSlotData::FindOrAddPlayerRecord(const FUniqueNetIdRepl& UniqueId)
3454
{
35-
return Players[Players.AddUnique(FPlayerRecord(UniqueId))];
55+
return Players[Players.AddUnique(FPlayerRecord(UniqueId.ToString()))];
3656
}
3757

3858
FPlayerRecord* USaveSlotData::FindPlayerRecord(const FUniqueNetIdRepl& UniqueId)
3959
{
40-
const int32 Index = Players.IndexOfByPredicate([&UniqueId](const FPlayerRecord& Record) {
41-
return Record.UniqueId == UniqueId;
60+
const FString UniqueIdStr = UniqueId.ToString();
61+
const int32 Index = Players.IndexOfByPredicate([&UniqueIdStr](const FPlayerRecord& Record) {
62+
return Record.UniqueId == UniqueIdStr;
4263
});
4364
if (Index != INDEX_NONE)
4465
{
@@ -59,7 +80,8 @@ bool USaveSlotData::FindPlayerRecord(const FUniqueNetIdRepl& UniqueId, FPlayerRe
5980

6081
bool USaveSlotData::RemovePlayerRecord(const FUniqueNetIdRepl& UniqueId)
6182
{
62-
return Players.RemoveAll([&UniqueId](const FPlayerRecord& Record) {
63-
return Record.UniqueId == UniqueId;
83+
const FString UniqueIdStr = UniqueId.ToString();
84+
return Players.RemoveAll([&UniqueIdStr](const FPlayerRecord& Record) {
85+
return Record.UniqueId == UniqueIdStr;
6486
}) > 0;
6587
}

0 commit comments

Comments
 (0)