支持蓝图修改 SaveStruct

修复载入错误的问题 [SerializeItem 不保存默认值,需要先 InitializeStruct]
This commit is contained in:
_Redstone_c_ 2020-12-12 19:40:34 +08:00
parent 7f5b1c1900
commit 5c338c968b
6 changed files with 126 additions and 22 deletions

View File

@ -30,22 +30,30 @@ void UAutoSaveSubsystem::GetSaveStructInfosWithoutData(TArray<FSaveStructInfo>&
FSaveStruct * UAutoSaveSubsystem::AddSaveStructRef(const FString& Filename, UScriptStruct * ScriptStruct)
{
const bool bIsCppStruct = ScriptStruct->IsChildOf(FSaveStruct::StaticStruct());
const bool bIsBlueprintStruct = ScriptStruct->GetClass() == UUserDefinedStruct::StaticClass();
if (!bIsCppStruct && !bIsBlueprintStruct)
return nullptr;
if (StructInfos.Contains(Filename))
{
FSaveStructInfo* StructInfo = StructInfos[Filename].Get();
if (ScriptStruct && ScriptStruct != StructInfo->Struct)
{
UE_LOG(LogAutoSave, Warning, TEXT("The requested Save Struct '%s' type conflicts with the existing."), *Filename);
return nullptr;
}
// Increase the reference count of SaveStruct by one, and then decrease it accordingly in UAutoSaveSubsystem::RemoveSaveStructRef
StructInfo->RefConut++;
return (FSaveStruct*)StructInfo->Data.GetData();
}
if (!ScriptStruct) return nullptr;
const bool bIsCppStruct = ScriptStruct->IsChildOf(FSaveStruct::StaticStruct());
const bool bIsBlueprintStruct = ScriptStruct->GetClass() == UUserDefinedStruct::StaticClass();
if (!bIsCppStruct && !bIsBlueprintStruct)
return nullptr;
TUniquePtr<FSaveStructInfo> NewStructInfo(new FSaveStructInfo());
if (FPaths::FileExists(Filename))
@ -53,6 +61,7 @@ FSaveStruct * UAutoSaveSubsystem::AddSaveStructRef(const FString& Filename, UScr
NewStructInfo->Filename = Filename;
NewStructInfo->Struct = ScriptStruct;
NewStructInfo->Data.SetNumUninitialized(ScriptStruct->GetStructureSize());
ScriptStruct->InitializeStruct(NewStructInfo->Data.GetData());
NewStructInfo->State = ESaveStructState::Preload;
NewStructInfo->RefConut = 1;
NewStructInfo->LastRefConut = 0;
@ -112,7 +121,7 @@ UAutoSaveSubsystem::FStructLoadOrSaveTask::FStructLoadOrSaveTask(FSaveStructInfo
{
case ESaveStructState::Preload:
StructInfoPtr->State = ESaveStructState::Loading;
DataCopy.SetNumUninitialized(StructInfoPtr->Data.Num());
DataCopy = StructInfoPtr->Data;
break;
case ESaveStructState::Idle:
@ -292,12 +301,30 @@ void UAutoSaveSubsystem::Initialize(FSubsystemCollectionBase & Collection)
void UAutoSaveSubsystem::Deinitialize()
{
// Make sure the tasks are completed
for (TUniquePtr<FAsyncTask<FStructLoadOrSaveTask>>& Task : TaskThreads)
{
if (!Task) continue;
Task->EnsureCompletion();
Task = nullptr;
}
// Make sure objects are saved
for (const TPair<FString, TUniquePtr<FSaveStructInfo>>& Info : StructInfos)
{
// Skip objects that are not loaded
if (Info.Value->State == ESaveStructState::Preload) continue;
check(Info.Value->State == ESaveStructState::Idle);
if (Info.Value->RefConut > 0)
{
UE_LOG(LogAutoSave, Warning, TEXT("The subsystem deinitialize, but '%s' still has references."), *Info.Value->Filename);
}
FAsyncTask<FStructLoadOrSaveTask> Task(Info.Value.Get());
Task.StartSynchronousTask();
}
}
void UAutoSaveSubsystem::Tick(float DeltaTime)

View File

@ -1,6 +1,5 @@
#include "Blueprint/AutoSaveBlueprintLibrary.h"
#include "AutoSaveSubsystem.h"
#include "Kismet/GameplayStatics.h"
bool UAutoSaveBlueprintLibrary::AddSaveStructRef(UObject * WorldContextObject, const FString & Filename, UScriptStruct * ScriptStruct)
@ -28,3 +27,49 @@ void UAutoSaveBlueprintLibrary::RemoveSaveStructRef(UObject * WorldContextObject
AutoSaveSubsystem->RemoveSaveStructRef(Filename);
}
bool UAutoSaveBlueprintLibrary::Generic_TryGetSaveStruct(UObject * WorldContextObject, const FString & Filename, UScriptStruct * ScriptStruct, void * Value)
{
UGameInstance* GameInstance = UGameplayStatics::GetGameInstance(WorldContextObject);
if (!GameInstance) return false;
UAutoSaveSubsystem* AutoSaveSubsystem = GameInstance->GetSubsystem<UAutoSaveSubsystem>();
if (!AutoSaveSubsystem) return false;
if (!AutoSaveSubsystem->StructInfos.Contains(Filename)) return false;
FSaveStructInfo* Info = AutoSaveSubsystem->StructInfos[Filename].Get();
if (Info->State == ESaveStructState::Preload || Info->State == ESaveStructState::Loading) return false;
if (Info->Struct != ScriptStruct) return false;
ScriptStruct->CopyScriptStruct(Value, Info->Data.GetData());
return true;
}
bool UAutoSaveBlueprintLibrary::Generic_TrySetSaveStruct(UObject * WorldContextObject, const FString & Filename, UScriptStruct * ScriptStruct, void * Value)
{
UGameInstance* GameInstance = UGameplayStatics::GetGameInstance(WorldContextObject);
if (!GameInstance) return false;
UAutoSaveSubsystem* AutoSaveSubsystem = GameInstance->GetSubsystem<UAutoSaveSubsystem>();
if (!AutoSaveSubsystem) return false;
if (!AutoSaveSubsystem->StructInfos.Contains(Filename)) return false;
FSaveStructInfo* Info = AutoSaveSubsystem->StructInfos[Filename].Get();
if (Info->State == ESaveStructState::Preload || Info->State == ESaveStructState::Loading) return false;
if (Info->Struct != ScriptStruct) return false;
ScriptStruct->CopyScriptStruct(Info->Data.GetData(), Value);
return true;
}

View File

@ -1 +0,0 @@
#include "SaveStruct.h"

View File

@ -17,7 +17,7 @@ enum class ESaveStructState : uint8
};
USTRUCT(BlueprintType)
struct FSaveStructInfo
struct AUTOSAVE_API FSaveStructInfo
{
GENERATED_BODY()
@ -50,7 +50,7 @@ class AUTOSAVE_API UAutoSaveSubsystem : public UGameInstanceSubsystem, public FT
{
GENERATED_BODY()
friend struct FSaveStructPtr;
friend class UAutoSaveBlueprintLibrary;
public:
@ -65,7 +65,7 @@ public:
UFUNCTION(BlueprintCallable, Category = "AutoSave")
void GetSaveStructInfosWithoutData(TArray<FSaveStructInfo>& OutSaveStructInfos) const;
FSaveStruct* AddSaveStructRef(const FString& Filename, UScriptStruct* ScriptStruct);
FSaveStruct* AddSaveStructRef(const FString& Filename, UScriptStruct* ScriptStruct = nullptr);
void RemoveSaveStructRef(const FString& Filename);

View File

@ -1,6 +1,8 @@
#pragma once
#include "CoreMinimal.h"
#include "SaveStruct.h"
#include "AutoSaveSubsystem.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "AutoSaveBlueprintLibrary.generated.h"
@ -16,5 +18,46 @@ public:
UFUNCTION(BlueprintCallable, Category = "AutoSave", meta = (WorldContext = "WorldContextObject"))
static void RemoveSaveStructRef(UObject* WorldContextObject, const FString& Filename);
UFUNCTION(BlueprintCallable, Category = "AutoSave", meta = (WorldContext = "WorldContextObject", CustomStructureParam = "Value"), CustomThunk)
static void TryGetSaveStruct(UObject* WorldContextObject, const FString& Filename, int32& Value, bool& bSuccess) { checkNoEntry(); }
static bool Generic_TryGetSaveStruct(UObject* WorldContextObject, const FString& Filename, UScriptStruct* ScriptStruct, void* Value);
DECLARE_FUNCTION(execTryGetSaveStruct)
{
P_GET_OBJECT(UObject, WorldContextObject);
P_GET_PROPERTY_REF(FStrProperty, Filename);
Stack.Step(Stack.Object, nullptr);
void* StructPtr = Stack.MostRecentPropertyAddress;
FStructProperty* StructProperty = CastField<FStructProperty>(Stack.MostRecentProperty);
P_GET_UBOOL_REF(bSuccess);
P_FINISH;
P_NATIVE_BEGIN;
bSuccess = Generic_TryGetSaveStruct(WorldContextObject, Filename, StructProperty ? StructProperty->Struct : nullptr, StructPtr);
P_NATIVE_END;
}
UFUNCTION(BlueprintCallable, Category = "AutoSave", meta = (WorldContext = "WorldContextObject", CustomStructureParam = "Value"), CustomThunk)
static void TrySetSaveStruct(UObject* WorldContextObject, const FString& Filename, const int32& Value, bool& bSuccess) { checkNoEntry(); }
static bool Generic_TrySetSaveStruct(UObject* WorldContextObject, const FString& Filename, UScriptStruct* ScriptStruct, void* Value);
DECLARE_FUNCTION(execTrySetSaveStruct)
{
P_GET_OBJECT(UObject, WorldContextObject);
P_GET_PROPERTY_REF(FStrProperty, Filename);
Stack.Step(Stack.Object, nullptr);
void* StructPtr = Stack.MostRecentPropertyAddress;
FStructProperty* StructProperty = CastField<FStructProperty>(Stack.MostRecentProperty);
P_GET_UBOOL_REF(bSuccess);
P_FINISH;
P_NATIVE_BEGIN;
bSuccess = Generic_TrySetSaveStruct(WorldContextObject, Filename, StructProperty ? StructProperty->Struct : nullptr, StructPtr);
P_NATIVE_END;
}
};

View File

@ -1,10 +0,0 @@
#pragma once
#include "CoreMinimal.h"
#include "SaveStruct.generated.h"
USTRUCT(BlueprintType)
struct AUTOSAVE_API FSaveStructPtr
{
GENERATED_BODY()
};