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
192251USaveManager::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
448509USaveSlot* 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
456517bool USaveManager::IsSlotSaved (FName SlotName) const
@@ -530,9 +591,15 @@ void USaveManager::DeserializeStreamingLevel(ULevelStreaming* LevelStreaming)
530591
531592void 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
549616void 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+
572648void USaveManager::OnSaveBegan ()
573649{
574650 TRACE_CPUPROFILER_EVENT_SCOPE (USaveManager::OnSaveBegan);
@@ -613,7 +689,7 @@ void USaveManager::OnSaveFinished(const bool bError)
613689void 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
699775void 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 }
0 commit comments