From e29ca2d8aabfc08f2f09e69e4e715df3a0a3d0ca Mon Sep 17 00:00:00 2001 From: _Redstone_c_ <2824517378@qq.com> Date: Sun, 13 Dec 2020 23:31:57 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E6=9E=84=E8=BD=BD=E5=85=A5=E5=AE=8C?= =?UTF-8?q?=E6=88=90=E7=9A=84=E5=9B=9E=E8=B0=83=20C++=E5=8F=8B=E5=A5=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 支持静态回调 --- Source/AutoSave/Private/AutoSaveSubsystem.cpp | 158 +++++++++++++++--- .../Blueprint/AutoSaveBlueprintLibrary.cpp | 4 +- Source/AutoSave/Public/AutoSaveSubsystem.h | 37 ++-- .../Blueprint/AutoSaveBlueprintLibrary.h | 2 +- Source/AutoSave/Public/SaveStruct.h | 22 ++- 5 files changed, 177 insertions(+), 46 deletions(-) diff --git a/Source/AutoSave/Private/AutoSaveSubsystem.cpp b/Source/AutoSave/Private/AutoSaveSubsystem.cpp index 39fb6d6..9f464f4 100644 --- a/Source/AutoSave/Private/AutoSaveSubsystem.cpp +++ b/Source/AutoSave/Private/AutoSaveSubsystem.cpp @@ -9,23 +9,57 @@ UAutoSaveSubsystem::UAutoSaveSubsystem(const class FObjectInitializer & ObjectIn { } -void UAutoSaveSubsystem::GetSaveStructInfosWithoutData(TArray& OutSaveStructInfos) const +FString UAutoSaveSubsystem::GetSaveStructDebugString() const { - OutSaveStructInfos.SetNum(StructInfos.Num()); + FString Result; - int32 Index = 0; +#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) for (const TPair>& Info : StructInfos) { - OutSaveStructInfos[Index].Filename = Info.Value->Filename; - OutSaveStructInfos[Index].Struct = Info.Value->Struct; - OutSaveStructInfos[Index].State = Info.Value->State; - OutSaveStructInfos[Index].RefConut = Info.Value->RefConut; - OutSaveStructInfos[Index].LastRefConut = Info.Value->LastRefConut; - OutSaveStructInfos[Index].LastSaveTime = Info.Value->LastSaveTime; + Result.Append(Info.Value->Filename); - ++Index; + Result.Append(TEXT(" - ")); + + Result.Append(Info.Value->Struct->GetName()); + + Result.Append(TEXT(" - ")); + + switch (Info.Value->State) + { + case ESaveStructState::Preload: + Result.Append(TEXT("Preload")); + break; + case ESaveStructState::Loading: + Result.Append(TEXT("Loading")); + break; + case ESaveStructState::Idle: + Result.Append(TEXT("Idle")); + break; + case ESaveStructState::Saving: + Result.Append(TEXT("Saving")); + break; + default: checkNoEntry(); + } + + Result.Append(TEXT(" - ")); + + Result.Append(FString::Printf(TEXT("%d"), Info.Value->RefConut)); + + Result.Append(TEXT(" - ")); + + Result.Append(FString::Printf(TEXT("%d"), Info.Value->LastRefConut)); + + Result.Append(TEXT(" - ")); + + Result.Append(FString::Printf(TEXT("%f"), (FDateTime::Now() - Info.Value->LastSaveTime).GetTotalSeconds())); + + Result.Append(TEXT("\n")); } + +#endif + + return Result; } int32 UAutoSaveSubsystem::GetIdleThreadNum() const @@ -40,7 +74,7 @@ int32 UAutoSaveSubsystem::GetIdleThreadNum() const return Result; } -FSaveStruct * UAutoSaveSubsystem::AddSaveStructRef(const FString& Filename, UScriptStruct * ScriptStruct, FSaveStructLoadDelegate OnLoaded) +FSaveStruct * UAutoSaveSubsystem::AddSaveStructRef(const FString& Filename, UScriptStruct * ScriptStruct) { if (StructInfos.Contains(Filename)) { @@ -55,15 +89,6 @@ FSaveStruct * UAutoSaveSubsystem::AddSaveStructRef(const FString& Filename, UScr // Increase the reference count of SaveStruct by one, and then decrease it accordingly in UAutoSaveSubsystem::RemoveSaveStructRef StructInfo->RefConut++; - if (StructInfo->State == ESaveStructState::Preload || StructInfo->State == ESaveStructState::Loading) - { - StructInfo->OnLoaded.Add(OnLoaded); - } - else - { - OnLoaded.ExecuteIfBound(Filename); - } - return (FSaveStruct*)StructInfo->Data.GetData(); } @@ -87,7 +112,6 @@ FSaveStruct * UAutoSaveSubsystem::AddSaveStructRef(const FString& Filename, UScr NewStructInfo->LastSaveTime = FDateTime::Now(); NewStructInfo->Data.SetNumUninitialized(ScriptStruct->GetStructureSize()); ScriptStruct->InitializeStruct(NewStructInfo->Data.GetData()); - NewStructInfo->OnLoaded.Add(OnLoaded); } else { @@ -103,7 +127,6 @@ FSaveStruct * UAutoSaveSubsystem::AddSaveStructRef(const FString& Filename, UScr NewStructInfo->LastSaveTime = FDateTime::Now(); NewStructInfo->Data.SetNumUninitialized(ScriptStruct->GetStructureSize()); ScriptStruct->InitializeStruct(NewStructInfo->Data.GetData()); - NewStructInfo->OnLoaded.Add(OnLoaded); } ScriptStructHooker.Add(Filename, ScriptStruct); @@ -114,6 +137,42 @@ FSaveStruct * UAutoSaveSubsystem::AddSaveStructRef(const FString& Filename, UScr return (FSaveStruct*)StructInfos[Filename]->Data.GetData(); } +FSaveStruct * UAutoSaveSubsystem::AddSaveStructRef(const FString & Filename, UScriptStruct * ScriptStruct, FSaveStructLoadDelegate LoadCallback) +{ + FSaveStruct* Result = AddSaveStructRef(Filename, ScriptStruct); + + if (!LoadCallback.IsBound()) return Result; + + if (!Result) return nullptr; + + if (!LoadDelegates.Contains(Filename)) + { + LoadDelegates.Add(Filename); + } + + LoadDelegates[Filename].Add(LoadCallback); + + return Result; +} + +FSaveStruct * UAutoSaveSubsystem::AddSaveStructRef(const FString & Filename, UScriptStruct * ScriptStruct, FSaveStructLoadDynamicDelegate LoadCallback) +{ + FSaveStruct* Result = AddSaveStructRef(Filename, ScriptStruct); + + if (!LoadCallback.IsBound()) return Result; + + if (!Result) return nullptr; + + if (!LoadDynamicDelegates.Contains(Filename)) + { + LoadDynamicDelegates.Add(Filename); + } + + LoadDynamicDelegates[Filename].Add(LoadCallback); + + return Result; +} + void UAutoSaveSubsystem::RemoveSaveStructRef(const FString& Filename) { if (StructInfos.Contains(Filename)) @@ -163,7 +222,6 @@ UAutoSaveSubsystem::FStructLoadOrSaveTask::~FStructLoadOrSaveTask() case ESaveStructState::Loading: StructInfoPtr->State = ESaveStructState::Idle; StructInfoPtr->Data = DataCopy; - StructInfoPtr->OnLoaded.Broadcast(StructInfoPtr->Filename); break; case ESaveStructState::Saving: @@ -317,6 +375,59 @@ void UAutoSaveSubsystem::HandleTaskDone() } } +void UAutoSaveSubsystem::HandleLoadDelegates() +{ + // Delegates + { + TArray DelegatesToRemove; + + for (const TPair& Delegates : LoadDelegates) + { + if (!StructInfos.Contains(Delegates.Key)) + { + DelegatesToRemove.Add(Delegates.Key); + continue; + } + + if (StructInfos[Delegates.Key]->State == ESaveStructState::Idle || StructInfos[Delegates.Key]->State == ESaveStructState::Saving) + { + Delegates.Value.Broadcast(Delegates.Key); + DelegatesToRemove.Add(Delegates.Key); + } + } + + for (const FString& Filename : DelegatesToRemove) + { + LoadDelegates.Remove(Filename); + } + } + + // DynamicDelegates + { + TArray DynamicDelegatesToRemove; + + for (const TPair& Delegates : LoadDynamicDelegates) + { + if (!StructInfos.Contains(Delegates.Key)) + { + DynamicDelegatesToRemove.Add(Delegates.Key); + continue; + } + + if (StructInfos[Delegates.Key]->State == ESaveStructState::Idle || StructInfos[Delegates.Key]->State == ESaveStructState::Saving) + { + Delegates.Value.Broadcast(Delegates.Key); + DynamicDelegatesToRemove.Add(Delegates.Key); + } + } + + for (const FString& Filename : DynamicDelegatesToRemove) + { + LoadDynamicDelegates.Remove(Filename); + } + } +} + void UAutoSaveSubsystem::Initialize(FSubsystemCollectionBase & Collection) { if (MaxThreadNum > 0) @@ -355,4 +466,5 @@ void UAutoSaveSubsystem::Tick(float DeltaTime) { HandleTaskDone(); HandleTaskStart(); + HandleLoadDelegates(); } diff --git a/Source/AutoSave/Private/Blueprint/AutoSaveBlueprintLibrary.cpp b/Source/AutoSave/Private/Blueprint/AutoSaveBlueprintLibrary.cpp index 1069546..10ec084 100644 --- a/Source/AutoSave/Private/Blueprint/AutoSaveBlueprintLibrary.cpp +++ b/Source/AutoSave/Private/Blueprint/AutoSaveBlueprintLibrary.cpp @@ -2,7 +2,7 @@ #include "Kismet/GameplayStatics.h" -bool UAutoSaveBlueprintLibrary::AddSaveStructRef(UObject * WorldContextObject, const FString & Filename, UScriptStruct * ScriptStruct, FSaveStructLoadDelegate OnLoaded) +bool UAutoSaveBlueprintLibrary::AddSaveStructRef(UObject * WorldContextObject, const FString & Filename, UScriptStruct * ScriptStruct, FSaveStructLoadDynamicDelegate LoadCallback) { UGameInstance* GameInstance = UGameplayStatics::GetGameInstance(WorldContextObject); @@ -12,7 +12,7 @@ bool UAutoSaveBlueprintLibrary::AddSaveStructRef(UObject * WorldContextObject, c if (!AutoSaveSubsystem) return false; - return AutoSaveSubsystem->AddSaveStructRef(Filename, ScriptStruct, OnLoaded) != nullptr; + return AutoSaveSubsystem->AddSaveStructRef(Filename, ScriptStruct, LoadCallback) != nullptr; } void UAutoSaveBlueprintLibrary::RemoveSaveStructRef(UObject * WorldContextObject, const FString & Filename) diff --git a/Source/AutoSave/Public/AutoSaveSubsystem.h b/Source/AutoSave/Public/AutoSaveSubsystem.h index 5b023d4..51894ce 100644 --- a/Source/AutoSave/Public/AutoSaveSubsystem.h +++ b/Source/AutoSave/Public/AutoSaveSubsystem.h @@ -7,9 +7,6 @@ USTRUCT(BlueprintType) struct AUTOSAVE_API FSaveStruct { GENERATED_BODY() }; -DECLARE_DYNAMIC_DELEGATE_OneParam(FSaveStructLoadDelegate, const FString&, Filename); -DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FSaveStructLoadDelegates, const FString&, Filename); - UENUM(BlueprintType, Category = "AutoSave") enum class ESaveStructState : uint8 { @@ -19,38 +16,31 @@ enum class ESaveStructState : uint8 Saving, }; -USTRUCT(BlueprintType) struct AUTOSAVE_API FSaveStructInfo { - GENERATED_BODY() - - UPROPERTY(BlueprintReadWrite, Category = "AutoSave") FString Filename; - UPROPERTY(BlueprintReadWrite, Category = "AutoSave") UScriptStruct* Struct; - UPROPERTY(BlueprintReadWrite, Category = "AutoSave") ESaveStructState State; - UPROPERTY(BlueprintReadWrite, Category = "AutoSave") int32 RefConut; - UPROPERTY(BlueprintReadWrite, Category = "AutoSave") int32 LastRefConut; - UPROPERTY(BlueprintReadWrite, Category = "AutoSave") FDateTime LastSaveTime; - UPROPERTY() TArray Data; // FSaveStruct* Data; - UPROPERTY() - FSaveStructLoadDelegates OnLoaded; - }; +DECLARE_DELEGATE_OneParam(FSaveStructLoadDelegate, const FString&); +DECLARE_MULTICAST_DELEGATE_OneParam(FSaveStructLoadDelegates, const FString&); + +DECLARE_DYNAMIC_DELEGATE_OneParam(FSaveStructLoadDynamicDelegate, const FString&, Filename); +DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FSaveStructLoadDynamicDelegates, const FString&, Filename); + UCLASS(Config = Engine, DefaultConfig) class AUTOSAVE_API UAutoSaveSubsystem : public UGameInstanceSubsystem, public FTickableGameObject { @@ -69,13 +59,17 @@ public: UPROPERTY(Config, EditAnywhere, Category = "AutoSave") FTimespan SaveWaitTime = FTimespan(ETimespan::MaxTicks); - UFUNCTION(BlueprintCallable, Category = "AutoSave") - void GetSaveStructInfosWithoutData(TArray& OutSaveStructInfos) const; + UFUNCTION(BlueprintPure, Category = "AutoSave", meta = (DevelopmentOnly)) + FString GetSaveStructDebugString() const; UFUNCTION(BlueprintPure, Category = "AutoSave") int32 GetIdleThreadNum() const; - FSaveStruct* AddSaveStructRef(const FString& Filename, UScriptStruct* ScriptStruct = nullptr, FSaveStructLoadDelegate OnLoaded = FSaveStructLoadDelegate()); + FSaveStruct* AddSaveStructRef(const FString& Filename, UScriptStruct* ScriptStruct = nullptr); + + FSaveStruct* AddSaveStructRef(const FString& Filename, UScriptStruct* ScriptStruct, FSaveStructLoadDelegate LoadCallback); + + FSaveStruct* AddSaveStructRef(const FString& Filename, UScriptStruct* ScriptStruct, FSaveStructLoadDynamicDelegate LoadCallback); void RemoveSaveStructRef(const FString& Filename); @@ -114,6 +108,11 @@ private: void HandleTaskDone(); + TMap LoadDelegates; + TMap LoadDynamicDelegates; + + void HandleLoadDelegates(); + private: //~ Begin USubsystem Interface diff --git a/Source/AutoSave/Public/Blueprint/AutoSaveBlueprintLibrary.h b/Source/AutoSave/Public/Blueprint/AutoSaveBlueprintLibrary.h index 4c2bed8..73f1e00 100644 --- a/Source/AutoSave/Public/Blueprint/AutoSaveBlueprintLibrary.h +++ b/Source/AutoSave/Public/Blueprint/AutoSaveBlueprintLibrary.h @@ -14,7 +14,7 @@ class AUTOSAVE_API UAutoSaveBlueprintLibrary : public UBlueprintFunctionLibrary public: UFUNCTION(BlueprintCallable, Category = "AutoSave", meta = (WorldContext = "WorldContextObject")) - static bool AddSaveStructRef(UObject* WorldContextObject, const FString& Filename, UScriptStruct* ScriptStruct, FSaveStructLoadDelegate OnLoaded); + static bool AddSaveStructRef(UObject* WorldContextObject, const FString& Filename, UScriptStruct* ScriptStruct, FSaveStructLoadDynamicDelegate LoadCallback); UFUNCTION(BlueprintCallable, Category = "AutoSave", meta = (WorldContext = "WorldContextObject")) static void RemoveSaveStructRef(UObject* WorldContextObject, const FString& Filename); diff --git a/Source/AutoSave/Public/SaveStruct.h b/Source/AutoSave/Public/SaveStruct.h index 33cca7f..580633f 100644 --- a/Source/AutoSave/Public/SaveStruct.h +++ b/Source/AutoSave/Public/SaveStruct.h @@ -19,7 +19,27 @@ public: { } - FORCEINLINE FSaveStructPtr(UAutoSaveSubsystem* InAutoSaveSubsystem, const FString& Filename, FSaveStructLoadDelegate OnLoaded = FSaveStructLoadDelegate()) + FORCEINLINE FSaveStructPtr(UAutoSaveSubsystem* InAutoSaveSubsystem, const FString& Filename) + : AutoSaveSubsystem(InAutoSaveSubsystem) + , Info(nullptr) + { + if (AutoSaveSubsystem->AddSaveStructRef(Filename, SaveStructType::StaticStruct())) + { + Info = AutoSaveSubsystem->StructInfos[Filename].Get(); + } + } + + FORCEINLINE FSaveStructPtr(UAutoSaveSubsystem* InAutoSaveSubsystem, const FString& Filename, FSaveStructLoadDelegate OnLoaded) + : AutoSaveSubsystem(InAutoSaveSubsystem) + , Info(nullptr) + { + if (AutoSaveSubsystem->AddSaveStructRef(Filename, SaveStructType::StaticStruct(), OnLoaded)) + { + Info = AutoSaveSubsystem->StructInfos[Filename].Get(); + } + } + + FORCEINLINE FSaveStructPtr(UAutoSaveSubsystem* InAutoSaveSubsystem, const FString& Filename, FSaveStructLoadDynamicDelegate OnLoaded) : AutoSaveSubsystem(InAutoSaveSubsystem) , Info(nullptr) {