重构载入完成的回调 C++友好

支持静态回调
This commit is contained in:
_Redstone_c_ 2020-12-13 23:31:57 +08:00
parent 9e68d7f7e8
commit e29ca2d8aa
5 changed files with 177 additions and 46 deletions

View File

@ -9,23 +9,57 @@ UAutoSaveSubsystem::UAutoSaveSubsystem(const class FObjectInitializer & ObjectIn
{ {
} }
void UAutoSaveSubsystem::GetSaveStructInfosWithoutData(TArray<FSaveStructInfo>& 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<FString, TUniquePtr<FSaveStructInfo>>& Info : StructInfos) for (const TPair<FString, TUniquePtr<FSaveStructInfo>>& Info : StructInfos)
{ {
OutSaveStructInfos[Index].Filename = Info.Value->Filename; Result.Append(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;
++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 int32 UAutoSaveSubsystem::GetIdleThreadNum() const
@ -40,7 +74,7 @@ int32 UAutoSaveSubsystem::GetIdleThreadNum() const
return Result; return Result;
} }
FSaveStruct * UAutoSaveSubsystem::AddSaveStructRef(const FString& Filename, UScriptStruct * ScriptStruct, FSaveStructLoadDelegate OnLoaded) FSaveStruct * UAutoSaveSubsystem::AddSaveStructRef(const FString& Filename, UScriptStruct * ScriptStruct)
{ {
if (StructInfos.Contains(Filename)) 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 // Increase the reference count of SaveStruct by one, and then decrease it accordingly in UAutoSaveSubsystem::RemoveSaveStructRef
StructInfo->RefConut++; StructInfo->RefConut++;
if (StructInfo->State == ESaveStructState::Preload || StructInfo->State == ESaveStructState::Loading)
{
StructInfo->OnLoaded.Add(OnLoaded);
}
else
{
OnLoaded.ExecuteIfBound(Filename);
}
return (FSaveStruct*)StructInfo->Data.GetData(); return (FSaveStruct*)StructInfo->Data.GetData();
} }
@ -87,7 +112,6 @@ FSaveStruct * UAutoSaveSubsystem::AddSaveStructRef(const FString& Filename, UScr
NewStructInfo->LastSaveTime = FDateTime::Now(); NewStructInfo->LastSaveTime = FDateTime::Now();
NewStructInfo->Data.SetNumUninitialized(ScriptStruct->GetStructureSize()); NewStructInfo->Data.SetNumUninitialized(ScriptStruct->GetStructureSize());
ScriptStruct->InitializeStruct(NewStructInfo->Data.GetData()); ScriptStruct->InitializeStruct(NewStructInfo->Data.GetData());
NewStructInfo->OnLoaded.Add(OnLoaded);
} }
else else
{ {
@ -103,7 +127,6 @@ FSaveStruct * UAutoSaveSubsystem::AddSaveStructRef(const FString& Filename, UScr
NewStructInfo->LastSaveTime = FDateTime::Now(); NewStructInfo->LastSaveTime = FDateTime::Now();
NewStructInfo->Data.SetNumUninitialized(ScriptStruct->GetStructureSize()); NewStructInfo->Data.SetNumUninitialized(ScriptStruct->GetStructureSize());
ScriptStruct->InitializeStruct(NewStructInfo->Data.GetData()); ScriptStruct->InitializeStruct(NewStructInfo->Data.GetData());
NewStructInfo->OnLoaded.Add(OnLoaded);
} }
ScriptStructHooker.Add(Filename, ScriptStruct); ScriptStructHooker.Add(Filename, ScriptStruct);
@ -114,6 +137,42 @@ FSaveStruct * UAutoSaveSubsystem::AddSaveStructRef(const FString& Filename, UScr
return (FSaveStruct*)StructInfos[Filename]->Data.GetData(); 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) void UAutoSaveSubsystem::RemoveSaveStructRef(const FString& Filename)
{ {
if (StructInfos.Contains(Filename)) if (StructInfos.Contains(Filename))
@ -163,7 +222,6 @@ UAutoSaveSubsystem::FStructLoadOrSaveTask::~FStructLoadOrSaveTask()
case ESaveStructState::Loading: case ESaveStructState::Loading:
StructInfoPtr->State = ESaveStructState::Idle; StructInfoPtr->State = ESaveStructState::Idle;
StructInfoPtr->Data = DataCopy; StructInfoPtr->Data = DataCopy;
StructInfoPtr->OnLoaded.Broadcast(StructInfoPtr->Filename);
break; break;
case ESaveStructState::Saving: case ESaveStructState::Saving:
@ -317,6 +375,59 @@ void UAutoSaveSubsystem::HandleTaskDone()
} }
} }
void UAutoSaveSubsystem::HandleLoadDelegates()
{
// Delegates
{
TArray<FString> DelegatesToRemove;
for (const TPair<FString, FSaveStructLoadDelegates>& 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<FString> DynamicDelegatesToRemove;
for (const TPair<FString, FSaveStructLoadDynamicDelegates>& 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) void UAutoSaveSubsystem::Initialize(FSubsystemCollectionBase & Collection)
{ {
if (MaxThreadNum > 0) if (MaxThreadNum > 0)
@ -355,4 +466,5 @@ void UAutoSaveSubsystem::Tick(float DeltaTime)
{ {
HandleTaskDone(); HandleTaskDone();
HandleTaskStart(); HandleTaskStart();
HandleLoadDelegates();
} }

View File

@ -2,7 +2,7 @@
#include "Kismet/GameplayStatics.h" #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); UGameInstance* GameInstance = UGameplayStatics::GetGameInstance(WorldContextObject);
@ -12,7 +12,7 @@ bool UAutoSaveBlueprintLibrary::AddSaveStructRef(UObject * WorldContextObject, c
if (!AutoSaveSubsystem) return false; 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) void UAutoSaveBlueprintLibrary::RemoveSaveStructRef(UObject * WorldContextObject, const FString & Filename)

View File

@ -7,9 +7,6 @@
USTRUCT(BlueprintType) USTRUCT(BlueprintType)
struct AUTOSAVE_API FSaveStruct { GENERATED_BODY() }; 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") UENUM(BlueprintType, Category = "AutoSave")
enum class ESaveStructState : uint8 enum class ESaveStructState : uint8
{ {
@ -19,38 +16,31 @@ enum class ESaveStructState : uint8
Saving, Saving,
}; };
USTRUCT(BlueprintType)
struct AUTOSAVE_API FSaveStructInfo struct AUTOSAVE_API FSaveStructInfo
{ {
GENERATED_BODY()
UPROPERTY(BlueprintReadWrite, Category = "AutoSave")
FString Filename; FString Filename;
UPROPERTY(BlueprintReadWrite, Category = "AutoSave")
UScriptStruct* Struct; UScriptStruct* Struct;
UPROPERTY(BlueprintReadWrite, Category = "AutoSave")
ESaveStructState State; ESaveStructState State;
UPROPERTY(BlueprintReadWrite, Category = "AutoSave")
int32 RefConut; int32 RefConut;
UPROPERTY(BlueprintReadWrite, Category = "AutoSave")
int32 LastRefConut; int32 LastRefConut;
UPROPERTY(BlueprintReadWrite, Category = "AutoSave")
FDateTime LastSaveTime; FDateTime LastSaveTime;
UPROPERTY()
TArray<uint8> Data; TArray<uint8> Data;
// FSaveStruct* 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) UCLASS(Config = Engine, DefaultConfig)
class AUTOSAVE_API UAutoSaveSubsystem : public UGameInstanceSubsystem, public FTickableGameObject class AUTOSAVE_API UAutoSaveSubsystem : public UGameInstanceSubsystem, public FTickableGameObject
{ {
@ -69,13 +59,17 @@ public:
UPROPERTY(Config, EditAnywhere, Category = "AutoSave") UPROPERTY(Config, EditAnywhere, Category = "AutoSave")
FTimespan SaveWaitTime = FTimespan(ETimespan::MaxTicks); FTimespan SaveWaitTime = FTimespan(ETimespan::MaxTicks);
UFUNCTION(BlueprintCallable, Category = "AutoSave") UFUNCTION(BlueprintPure, Category = "AutoSave", meta = (DevelopmentOnly))
void GetSaveStructInfosWithoutData(TArray<FSaveStructInfo>& OutSaveStructInfos) const; FString GetSaveStructDebugString() const;
UFUNCTION(BlueprintPure, Category = "AutoSave") UFUNCTION(BlueprintPure, Category = "AutoSave")
int32 GetIdleThreadNum() const; 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); void RemoveSaveStructRef(const FString& Filename);
@ -114,6 +108,11 @@ private:
void HandleTaskDone(); void HandleTaskDone();
TMap<FString, FSaveStructLoadDelegates> LoadDelegates;
TMap<FString, FSaveStructLoadDynamicDelegates> LoadDynamicDelegates;
void HandleLoadDelegates();
private: private:
//~ Begin USubsystem Interface //~ Begin USubsystem Interface

View File

@ -14,7 +14,7 @@ class AUTOSAVE_API UAutoSaveBlueprintLibrary : public UBlueprintFunctionLibrary
public: public:
UFUNCTION(BlueprintCallable, Category = "AutoSave", meta = (WorldContext = "WorldContextObject")) 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")) UFUNCTION(BlueprintCallable, Category = "AutoSave", meta = (WorldContext = "WorldContextObject"))
static void RemoveSaveStructRef(UObject* WorldContextObject, const FString& Filename); static void RemoveSaveStructRef(UObject* WorldContextObject, const FString& Filename);

View File

@ -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) : AutoSaveSubsystem(InAutoSaveSubsystem)
, Info(nullptr) , Info(nullptr)
{ {