Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

1.5 release #90

Open
wants to merge 51 commits into
base: main
Choose a base branch
from
Open
Changes from 1 commit
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
227c9b1
5.2 Update + SaveSlot refactor [1/X]
muit Sep 16, 2023
dbdc119
Removed presets
muit Sep 18, 2023
1690194
Refactored blueprint actions
muit Sep 20, 2023
58c5e29
Small changes to defautl settings and names
muit Sep 21, 2023
98abc63
Performance improvements & tasks refactor
muit Sep 28, 2023
565759a
Multiple fixes to filters
muit Sep 29, 2023
d2cd853
Merge branch 'feature/saveslot-refactor' of https://github.com/PipeRi…
muit Sep 29, 2023
7458d76
Added subsystem records
muit Oct 3, 2023
826b72a
Moved tasks to correct folder, removed SlotIds
muit Oct 3, 2023
dc5a439
Merge pull request #88 from PipeRift/feature/saveslot-refactor
muit Oct 3, 2023
61973b3
Merge branch 'develop' into feature/save-subsystems
muit Oct 3, 2023
06b6076
Refactor async serialization
muit Oct 3, 2023
a394234
Refactored PreloadAllSlots
muit Oct 3, 2023
3e41ae6
Refactored Deleting Slots
muit Oct 3, 2023
6651239
Save thumbnail in SaveSlot
muit Oct 4, 2023
ceea8f8
Refactor Save & Load async files
muit Oct 4, 2023
ae10031
Merge pull request #89 from PipeRift/feature/refactor-multithreading
muit Oct 4, 2023
dd3916e
Merge remote-tracking branch 'origin/develop' into feature/save-subsy…
muit Oct 4, 2023
3d54441
Save Subsystems
muit Oct 4, 2023
dbeb3d4
Ignore SKEL classes in editor for filters
muit Oct 4, 2023
74c7485
Load subsystems
muit Oct 4, 2023
235dd76
Merge pull request #91 from PipeRift/feature/save-subsystems
muit Oct 4, 2023
4d51a7c
Removed unneccesary code
muit Oct 4, 2023
3e4118b
Cleaned includes
muit Oct 5, 2023
6c9ac88
Simplified filters, fixed slot details
muit Oct 5, 2023
7c18d6a
Cleaned serialization functions
muit Oct 6, 2023
f95e5a1
Fixed level filter pin
muit Oct 6, 2023
166a480
Merge pull request #93 from PipeRift/hotfix/fix-level-filter-pin
muit Oct 6, 2023
4a9c518
Added player records and serialization
muit Oct 9, 2023
bb2a486
Merge pull request #94 from PipeRift/feature/player-serialization
muit Oct 9, 2023
73fe72e
[CICD] Preliminar build script
muit Oct 9, 2023
11a1bd8
Update build.yml
muit Oct 9, 2023
e3280ca
[CICD] Update build.yml
muit Oct 9, 2023
ed56901
Update build.yml
muit Oct 9, 2023
e3362f7
[CICD] Update build.yml
muit Oct 9, 2023
02a865a
Build fixes
muit Oct 9, 2023
13c410f
Merge branch 'develop' into feature/github-cicd
muit Oct 9, 2023
1dad616
[CICD] use Python 3
muit Oct 9, 2023
8898606
[CICD] Update build.yml
muit Oct 10, 2023
2f37f7b
Merge branch 'feature/github-cicd' into develop
muit Oct 11, 2023
685e198
Fixes for Linux builds
muit Oct 11, 2023
6de677d
Build fixes for Windows
muit Oct 11, 2023
f4c9e64
Fixed includes for Windows builds
muit Oct 11, 2023
f61aeb3
Removed unused include
muit Oct 11, 2023
12c9b1e
Added missing include
muit Oct 11, 2023
e0dbc93
Merge branch 'develop' into feature/github-cicd
muit Oct 12, 2023
5945f80
[CICD] Enable cache
muit Oct 12, 2023
e51fb79
Merge pull request #97 from PipeRift/feature/github-cicd
muit Oct 12, 2023
015f1c2
Small fix
muit Oct 17, 2023
208c325
Re-enabled events
muit Oct 31, 2023
af71e19
Fixed incorrect UPARAM and re-enabled events
muit Dec 7, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Refactor Save & Load async files
muit committed Oct 4, 2023
commit ceea8f87df16170a41e3d7f1bbd66858e75ef4da
2 changes: 1 addition & 1 deletion Source/SaveExtension/Private/Misc/SlotHelpers.cpp
Original file line number Diff line number Diff line change
@@ -10,7 +10,7 @@ void FSlotHelpers::FindSlotFileNames(TArray<FString>& FoundSlots)
{
FFindSlotVisitor Visitor{FoundSlots};
FPlatformFileManager::Get().GetPlatformFile().IterateDirectory(
*FSaveFileHelpers::GetSaveFolder(), Visitor);
*FSEFileHelpers::GetSaveFolder(), Visitor);
}

bool FSlotHelpers::FFindSlotVisitor::Visit(const TCHAR* FilenameOrDirectory, bool bIsDirectory)
48 changes: 0 additions & 48 deletions Source/SaveExtension/Private/Multithreading/LoadFileTask.cpp

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
// Copyright 2015-2024 Piperift. All Rights Reserved.

#include "SaveFileHelpers.h"
#include "SEFileHelpers.h"

#include "Multithreading/SaveFileTask.h"
#include "Serialization/SEArchive.h"
#include "SaveSlot.h"
#include "SaveSlotData.h"
@@ -14,10 +13,14 @@
#include <Serialization/MemoryWriter.h>
#include <UObject/Package.h>
#include <UObject/UObjectGlobals.h>
#include <Tasks/Pipe.h>


static const int SE_SAVEGAME_FILE_TYPE_TAG = 0x0001; // "sAvG"

UE::Tasks::FPipe BackendPipe{ TEXT("SaveExtensionPipe") };


struct FSaveGameFileVersion
{
enum Type
@@ -210,21 +213,17 @@ void FSaveFile::SerializeData(USaveSlotData* SlotData)
SlotData->Serialize(Ar);
}

bool FSaveFileHelpers::SaveFile(FStringView SlotName, USaveSlot* Slot, const bool bUseCompression)
bool FSEFileHelpers::SaveFileSync(USaveSlot* Slot, FStringView OverrideSlotName, const bool bUseCompression)
{
TRACE_CPUPROFILER_EVENT_SCOPE(FSaveFileHelpers::SaveFile);

if (SlotName.IsEmpty())
{
return false;
}
TRACE_CPUPROFILER_EVENT_SCOPE(FSEFileHelpers::SaveFileSync);

if (!ensureMsgf(Slot, TEXT("Slot object must be valid")) ||
!ensureMsgf(Slot->GetData(), TEXT("Slot Data object must be valid")))
{
return false;
}

FString SlotName = OverrideSlotName.IsEmpty()? Slot->Name.ToString() : FString{OverrideSlotName};
FScopedFileWriter FileWriter(GetSlotPath(SlotName));
if (FileWriter.IsValid())
{
@@ -237,19 +236,31 @@ bool FSaveFileHelpers::SaveFile(FStringView SlotName, USaveSlot* Slot, const boo
return false;
}

bool FSaveFileHelpers::LoadFile(FStringView SlotName, USaveSlot*& Slot, bool bLoadData, const UObject* Outer)
UE::Tasks::TTask<bool> FSEFileHelpers::SaveFile(USaveSlot* Slot, FString OverrideSlotName, const bool bUseCompression)
{
return BackendPipe.Launch(TEXT("SaveFile"), [Slot, OverrideSlotName, bUseCompression]() {
return SaveFileSync(Slot, OverrideSlotName, bUseCompression);
});
}


USaveSlot* FSEFileHelpers::LoadFileSync(FStringView SlotName, USaveSlot* SlotHint, bool bLoadData, const USaveManager* Manager)
{
TRACE_CPUPROFILER_EVENT_SCOPE(FSaveFileHelpers::LoadFile);
TRACE_CPUPROFILER_EVENT_SCOPE(FSEFileHelpers::LoadFileSync);
if (SlotName.IsEmpty() && SlotHint)
{
SlotName = SlotHint->Name.ToString();
}

FScopedFileReader Reader(GetSlotPath(SlotName));
if (Reader.IsValid())
{
FSaveFile File{};
File.Read(Reader, !bLoadData);

USaveSlot* Slot;
{
TRACE_CPUPROFILER_EVENT_SCOPE(DeserializeInfo)
Slot = Cast<USaveSlot>(DeserializeObject(Slot, File.ClassName, Outer, File.Bytes));
Slot = Cast<USaveSlot>(DeserializeObject(SlotHint, File.ClassName, Manager, File.Bytes));
}
if (bLoadData)
{
@@ -258,38 +269,51 @@ bool FSaveFileHelpers::LoadFile(FStringView SlotName, USaveSlot*& Slot, bool bLo
DeserializeObject(Slot->GetData(), File.DataClassName, Slot, File.DataBytes))
);
}
return true;
return Slot;
}
return false;
return nullptr;
}

bool FSaveFileHelpers::DeleteFile(FStringView SlotName)
UE::Tasks::TTask<USaveSlot*> FSEFileHelpers::LoadFile(FString SlotName, USaveSlot* SlotHint, bool bLoadData, const USaveManager* Manager)
{
return BackendPipe.Launch(TEXT("LoadFile"), [SlotName, SlotHint, bLoadData, Manager]()
{
USaveSlot* Slot = LoadFileSync(SlotName, SlotHint, bLoadData, Manager);
// In case we create the slot from async loading thread
if (Slot)
{
Slot->ClearInternalFlags(EInternalObjectFlags::Async);
if (IsValid(Slot->GetData()))
{
Slot->GetData()->ClearInternalFlags(EInternalObjectFlags::Async);
}
}
return Slot;
});
}

bool FSEFileHelpers::DeleteFile(FStringView SlotName)
{
return IFileManager::Get().Delete(*GetSlotPath(SlotName), true, false, true);
}

bool FSaveFileHelpers::FileExists(FStringView SlotName)
bool FSEFileHelpers::FileExists(FStringView SlotName)
{
return IFileManager::Get().FileSize(*GetSlotPath(SlotName)) >= 0;
}

const FString& FSaveFileHelpers::GetSaveFolder()
const FString& FSEFileHelpers::GetSaveFolder()
{
static const FString Folder = FString::Printf(TEXT("%sSaveGames/"), *FPaths::ProjectSavedDir());
return Folder;
}

FString FSaveFileHelpers::GetSlotPath(FStringView SlotName)
FString FSEFileHelpers::GetSlotPath(FStringView SlotName)
{
return GetSaveFolder() / FString::Printf(TEXT("%s.sav"), SlotName.GetData());
}

FString FSaveFileHelpers::GetThumbnailPath(FStringView SlotName)
{
return GetSaveFolder() / FString::Printf(TEXT("%s.png"), SlotName.GetData());
}

UObject* FSaveFileHelpers::DeserializeObject(UObject* Hint, FStringView ClassName, const UObject* Outer, const TArray<uint8>& Bytes)
UObject* FSEFileHelpers::DeserializeObject(UObject* Hint, FStringView ClassName, const UObject* Outer, const TArray<uint8>& Bytes)
{
UObject* Object = Hint;

@@ -325,3 +349,8 @@ UObject* FSaveFileHelpers::DeserializeObject(UObject* Hint, FStringView ClassNam
Object->Serialize(Ar);
return Object;
}

UE::Tasks::FPipe& FSEFileHelpers::GetPipe()
{
return BackendPipe;
}
39 changes: 15 additions & 24 deletions Source/SaveExtension/Private/SaveManager.cpp
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@

#include "SaveManager.h"

#include "SaveFileHelpers.h"
#include "SEFileHelpers.h"
#include "SaveSettings.h"
#include "Serialization/SEDataTask_LoadLevel.h"
#include "Serialization/SEDataTask_SaveLevel.h"
@@ -23,8 +23,6 @@
#include <Tasks/Pipe.h>


UE::Tasks::FPipe BackendPipe{ TEXT("SaveExtensionPipe") };

// From SaveGameSystem.cpp
void OnAsyncComplete(TFunction<void()> Callback)
{
@@ -212,7 +210,7 @@ void USaveManager::Deinitialize()
{
Super::Deinitialize();

BackendPipe.WaitUntilEmpty();
FSEFileHelpers::GetPipe().WaitUntilEmpty();

if (GetActiveSlot()->bSaveOnClose)
SaveActiveSlot();
@@ -264,20 +262,19 @@ bool USaveManager::LoadSlot(FName SlotName, FOnGameLoaded OnLoaded)

void USaveManager::PreloadAllSlots(FSEOnAllSlotsPreloaded Callback, bool bSortByRecent)
{
BackendPipe.Launch(UE_SOURCE_LOCATION, [this, Callback, bSortByRecent]()
FSEFileHelpers::GetPipe().Launch(UE_SOURCE_LOCATION, [this, Callback, bSortByRecent]()
{
TArray<USaveSlot*> Slots;
PreloadAllSlotsSync(Slots, bSortByRecent);

for (auto& Slot : Slots)
{
Slot->ClearInternalFlags(EInternalObjectFlags::Async);
}

if (Callback)
{
OnAsyncComplete([Slots = MoveTemp(Slots), Callback]()
{
for(auto* Slot : Slots)
{
Slot->ClearInternalFlags(EInternalObjectFlags::Async);
}
Callback(Slots);
});
}
@@ -294,7 +291,7 @@ void USaveManager::PreloadAllSlotsSync(TArray<USaveSlot*>& Slots, bool bSortByRe
for (const FString& FileName : FileNames)
{
// Load all files
FScopedFileReader Reader(FSaveFileHelpers::GetSlotPath(FileName));
FScopedFileReader Reader(FSEFileHelpers::GetSlotPath(FileName));
if (Reader.IsValid())
{
LoadedFiles.AddDefaulted_GetRef()
@@ -306,7 +303,7 @@ void USaveManager::PreloadAllSlotsSync(TArray<USaveSlot*>& Slots, bool bSortByRe
for (const auto& File : LoadedFiles)
{
auto* Slot = Cast<USaveSlot>(
FSaveFileHelpers::DeserializeObject(nullptr, File.ClassName, this, File.Bytes));
FSEFileHelpers::DeserializeObject(nullptr, File.ClassName, this, File.Bytes));
if (Slot)
{
Slots.Add(Slot);
@@ -324,15 +321,12 @@ void USaveManager::PreloadAllSlotsSync(TArray<USaveSlot*>& Slots, bool bSortByRe
bool USaveManager::DeleteSlotByNameSync(FName SlotName)
{
const FString NameStr = SlotName.ToString();
const FString ScreenshotPath = FSaveFileHelpers::GetThumbnailPath(NameStr);
bool bIsDeleteSlotSuccess = FSaveFileHelpers::DeleteFile(NameStr);
bool bIsDeleteScreenshotSuccess = IFileManager::Get().Delete(*ScreenshotPath, true);
return bIsDeleteSlotSuccess || bIsDeleteScreenshotSuccess;
return FSEFileHelpers::DeleteFile(NameStr);
}

void USaveManager::DeleteSlotByName(FName SlotName)
{
BackendPipe.Launch(UE_SOURCE_LOCATION, [this, SlotName]()
FSEFileHelpers::GetPipe().Launch(UE_SOURCE_LOCATION, [this, SlotName]()
{
DeleteSlotByNameSync(SlotName);
});
@@ -346,17 +340,14 @@ int32 USaveManager::DeleteAllSlotsSync()
int32 Count = 0;
for (const FString& SlotName : FoundSlots)
{
const FString ScreenshotPath = FSaveFileHelpers::GetThumbnailPath(SlotName);
bool bIsDeleteSlotSuccess = FSaveFileHelpers::DeleteFile(SlotName);
bool bIsDeleteScreenshotSuccess = IFileManager::Get().Delete(*ScreenshotPath, true);
Count += bIsDeleteSlotSuccess || bIsDeleteScreenshotSuccess;
Count += FSEFileHelpers::DeleteFile(SlotName);
}
return Count;
}

void USaveManager::DeleteAllSlots(FSEOnAllSlotsDeleted Callback)
{
BackendPipe.Launch(UE_SOURCE_LOCATION, [this, Callback]()
FSEFileHelpers::GetPipe().Launch(UE_SOURCE_LOCATION, [this, Callback]()
{
const int32 Count = DeleteAllSlotsSync();
if (Callback)
@@ -436,13 +427,13 @@ USaveSlot* USaveManager::PreloadSlot(FName SlotName)
{
USaveSlot* Slot = nullptr;
const FString NameStr = SlotName.ToString();
FSaveFileHelpers::LoadFile(NameStr, Slot, true, this);
Slot = FSEFileHelpers::LoadFileSync(NameStr, nullptr, true, this);
return Slot;
}

bool USaveManager::IsSlotSaved(FName SlotName) const
{
return FSaveFileHelpers::FileExists(SlotName.ToString());
return FSEFileHelpers::FileExists(SlotName.ToString());
}

bool USaveManager::CanLoadOrSave()
6 changes: 3 additions & 3 deletions Source/SaveExtension/Private/SaveSlot.cpp
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@

#include "SaveSlot.h"

#include "SaveFileHelpers.h"
#include "SEFileHelpers.h"

#include <Engine/Engine.h>
#include <Engine/GameViewportClient.h>
@@ -112,12 +112,12 @@ bool USaveSlot::IsFrameSplitSave() const
FrameSplittedSerialization == ESEAsyncMode::SaveAndLoadAsync);
}

bool USaveSlot::IsMTFilesLoad() const
bool USaveSlot::ShouldLoadFileAsync() const
{
return MultithreadedFiles == ESEAsyncMode::LoadAsync ||
MultithreadedFiles == ESEAsyncMode::SaveAndLoadAsync;
}
bool USaveSlot::IsMTFilesSave() const
bool USaveSlot::ShouldSaveFileAsync() const
{
return MultithreadedFiles == ESEAsyncMode::SaveAsync ||
MultithreadedFiles == ESEAsyncMode::SaveAndLoadAsync;
Loading