Hi, I’m relatively new to unreal engine and I was wondering if I could get some assistance with something. I’ve seen tutorials about saving and loading data into a level using the blueprint editor. What I’ve seen usually involves loading from the save game slot. What I’m wondering is if there’s a way to prompt the user to “load game” where the user is able to select a previously saved file present in the saved file location?
There’s no native way to do that in Blueprints. But you can add this functionality very easily with a custom Blueprint node in C++. If you want to avoid using code, then another way would be to save your saves with preset predictable names such as save_01, save_02, then you could use the DoesSaveGameExist node to populate a list of existing saves through iteration (And then include a friendly save name variable in the save itself that serves as the save name the user sees in the list if needed, although that would require accessing each save which may or may not be feasible).
The below code comes from the great Rama, whose Blueprint library I recommend.
Header:
#pragma once
#include "Kismet/BlueprintFunctionLibrary.h"
#include "GetSaveFiles.generated.h"
UCLASS()
class PROJECTNAME_API UGetSaveFiles : public UBlueprintFunctionLibrary
{
GENERATED_UCLASS_BODY()
UFUNCTION(BlueprintPure, Category = SaveFunctions)
static void SaveGameObject_GetAllSaveSlotFileNames(TArray<FString>& FileNames);
};
Source:
// Code by Rama
#include "ProjectName.h"
#include "GetSaveFiles.h"
template <class FunctorType>
class PlatformFileFunctor : public IPlatformFile::FDirectoryVisitor //GenericPlatformFile.h
{
public:
virtual bool Visit(const TCHAR* FilenameOrDirectory, bool bIsDirectory) override
{
return Functor(FilenameOrDirectory, bIsDirectory);
}
PlatformFileFunctor(FunctorType&& FunctorInstance)
: Functor(MoveTemp(FunctorInstance))
{
}
private:
FunctorType Functor;
};
template <class Functor>
PlatformFileFunctor<Functor> MakeDirectoryVisitor(Functor&& FunctorInstance)
{
return PlatformFileFunctor<Functor>(MoveTemp(FunctorInstance));
}
static bool GetFiles(const FString& FullPathOfBaseDir, TArray<FString>& FilenamesOut, bool Recursive = false, const FString& FilterByExtension = "")
{
//Format File Extension, remove the "." if present
const FString FileExt = FilterByExtension.Replace(TEXT("."), TEXT("")).ToLower();
FString Str;
auto FilenamesVisitor = MakeDirectoryVisitor(
[&](const TCHAR* FilenameOrDirectory, bool bIsDirectory)
{
//Files
if (!bIsDirectory)
{
//Filter by Extension
if (FileExt != "")
{
Str = FPaths::GetCleanFilename(FilenameOrDirectory);
//Filter by Extension
if (FPaths::GetExtension(Str).ToLower() == FileExt)
{
if (Recursive)
{
FilenamesOut.Push(FilenameOrDirectory); //need whole path for recursive
}
else
{
FilenamesOut.Push(Str);
}
}
}
//Include All Filenames!
else
{
//Just the Directory
Str = FPaths::GetCleanFilename(FilenameOrDirectory);
if (Recursive)
{
FilenamesOut.Push(FilenameOrDirectory); //need whole path for recursive
}
else
{
FilenamesOut.Push(Str);
}
}
}
return true;
}
);
if (Recursive)
{
return FPlatformFileManager::Get().GetPlatformFile().IterateDirectoryRecursively(*FullPathOfBaseDir, FilenamesVisitor);
}
else
{
return FPlatformFileManager::Get().GetPlatformFile().IterateDirectory(*FullPathOfBaseDir, FilenamesVisitor);
}
}
UGetSaveFiles::UGetSaveFiles(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
}
void UGetSaveFiles::SaveGameObject_GetAllSaveSlotFileNames(TArray<FString>& FileNames)
{
FileNames.Empty();
FString Path = FPaths::ConvertRelativePathToFull(FPaths::GameSavedDir()) + "SaveGames";
GetFiles(Path, FileNames);
}
This will return an array of save names, which you could then add to a list for the user to select a save.
This is what I am doing in the below example:
Thanks so much for your help