支持蓝图修改 SaveStruct
修复载入错误的问题 [SerializeItem 不保存默认值,需要先 InitializeStruct]
This commit is contained in:
parent
7f5b1c1900
commit
5c338c968b
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -1 +0,0 @@
|
||||
#include "SaveStruct.h"
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
@ -1,10 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "SaveStruct.generated.h"
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct AUTOSAVE_API FSaveStructPtr
|
||||
{
|
||||
GENERATED_BODY()
|
||||
};
|
Reference in New Issue
Block a user