|
@@ -0,0 +1,405 @@
|
|
|
|
+// Fill out your copyright notice in the Description page of Project Settings.
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+#include "EzAbilityInstanceData.h"
|
|
|
|
+#include "EzAbility.h"
|
|
|
|
+#include "EzAbilityLog.h"
|
|
|
|
+#include "Serialization/ObjectAndNameAsStringProxyArchive.h"
|
|
|
|
+
|
|
|
|
+namespace EzAbility
|
|
|
|
+{
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Duplicates object, and tries to covert old BP classes (REINST_*) to their newer version.
|
|
|
|
+ */
|
|
|
|
+ UObject* DuplicateNodeInstance(const UObject& Instance, UObject& InOwner)
|
|
|
|
+ {
|
|
|
|
+ const UClass* InstanceClass = Instance.GetClass();
|
|
|
|
+ if (InstanceClass->HasAnyClassFlags(CLASS_NewerVersionExists))
|
|
|
|
+ {
|
|
|
|
+ const UClass* AuthoritativeClass = InstanceClass->GetAuthoritativeClass();
|
|
|
|
+ UObject* NewInstance = NewObject<UObject>(&InOwner, AuthoritativeClass);
|
|
|
|
+
|
|
|
|
+ // Try to copy the values over using serialization
|
|
|
|
+ // FObjectAndNameAsStringProxyArchive is used to store and restore names and objects as memory writer does not support UObject references at all.
|
|
|
|
+ TArray<uint8> Data;
|
|
|
|
+ FMemoryWriter Writer(Data);
|
|
|
|
+ FObjectAndNameAsStringProxyArchive WriterProxy(Writer, /*bInLoadIfFindFails*/true);
|
|
|
|
+ UObject& NonConstInstance = const_cast<UObject&>(Instance);
|
|
|
|
+ NonConstInstance.Serialize(WriterProxy);
|
|
|
|
+
|
|
|
|
+ FMemoryReader Reader(Data);
|
|
|
|
+ FObjectAndNameAsStringProxyArchive ReaderProxy(Reader, /*bInLoadIfFindFails*/true);
|
|
|
|
+ NewInstance->Serialize(ReaderProxy);
|
|
|
|
+
|
|
|
|
+ const UEzAbility* OuterAbility = Instance.GetTypedOuter<UEzAbility>();
|
|
|
|
+
|
|
|
|
+ UE_LOG(LogEzAbility, Display, TEXT("FEzAbilityInstanceData: Duplicating '%s' with old class '%s' as '%s', potential data loss. Please resave EzAbility asset %s."),
|
|
|
|
+ *GetFullNameSafe(&Instance), *GetNameSafe(InstanceClass), *GetNameSafe(AuthoritativeClass), *GetFullNameSafe(OuterAbility));
|
|
|
|
+
|
|
|
|
+ return NewInstance;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return DuplicateObject(&Instance, &InOwner);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+// #if WITH_EDITORONLY_DATA
|
|
|
|
+// void GatherForLocalization(const FString& PathToParent, const UScriptStruct* Struct, const void* StructData, const void* DefaultStructData, FPropertyLocalizationDataGatherer& PropertyLocalizationDataGatherer, const EPropertyLocalizationGathererTextFlags GatherTextFlags)
|
|
|
|
+// {
|
|
|
|
+// const FStateTreeInstanceData* ThisInstance = static_cast<const FStateTreeInstanceData*>(StructData);
|
|
|
|
+// const FStateTreeInstanceData* DefaultInstance = static_cast<const FStateTreeInstanceData*>(DefaultStructData);
|
|
|
|
+//
|
|
|
|
+// PropertyLocalizationDataGatherer.GatherLocalizationDataFromStruct(PathToParent, Struct, StructData, DefaultStructData, GatherTextFlags);
|
|
|
|
+//
|
|
|
|
+// const uint8* DefaultInstanceMemory = nullptr;
|
|
|
|
+// if (DefaultInstance)
|
|
|
|
+// {
|
|
|
|
+// DefaultInstanceMemory = reinterpret_cast<const uint8*>(&DefaultInstance->GetStorage());
|
|
|
|
+// }
|
|
|
|
+//
|
|
|
|
+// const UScriptStruct* StructTypePtr = FStateTreeInstanceStorage::StaticStruct();
|
|
|
|
+// PropertyLocalizationDataGatherer.GatherLocalizationDataFromStructWithCallbacks(PathToParent + TEXT(".InstanceStorage"), StructTypePtr, &ThisInstance->GetStorage(), DefaultInstanceMemory, GatherTextFlags);
|
|
|
|
+// }
|
|
|
|
+//
|
|
|
|
+// void RegisterInstanceDataForLocalization()
|
|
|
|
+// {
|
|
|
|
+// { static const FAutoRegisterLocalizationDataGatheringCallback AutomaticRegistrationOfLocalizationGatherer(TBaseStructure<FStateTreeInstanceData>::Get(), &GatherForLocalization); }
|
|
|
|
+// }
|
|
|
|
+// #endif // WITH_EDITORONLY_DATA
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
+///InstanceStorage
|
|
|
|
+void FEzAbilityInstanceStorage::Reset()
|
|
|
|
+{
|
|
|
|
+ InstanceStructs.Reset();
|
|
|
|
+ TemporaryInstances.Reset();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+const UObject* FEzAbilityInstanceStorage::GetObject(const int32 Index) const
|
|
|
|
+{
|
|
|
|
+ const FEzAbilityInstanceObjectWrapper& Wrapper = InstanceStructs[Index].Get<const FEzAbilityInstanceObjectWrapper>();
|
|
|
|
+ return Wrapper.InstanceObject;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+UObject* FEzAbilityInstanceStorage::GetMutableObject(const int32 Index) const
|
|
|
|
+{
|
|
|
|
+ const FEzAbilityInstanceObjectWrapper& Wrapper = InstanceStructs[Index].Get<const FEzAbilityInstanceObjectWrapper>();
|
|
|
|
+ return Wrapper.InstanceObject;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+bool FEzAbilityInstanceStorage::AreAllInstancesValid() const
|
|
|
|
+{
|
|
|
|
+ for (FConstStructView Instance : InstanceStructs)
|
|
|
|
+ {
|
|
|
|
+ if (!Instance.IsValid())
|
|
|
|
+ {
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+ if (const FEzAbilityInstanceObjectWrapper* Wrapper = Instance.GetPtr<const FEzAbilityInstanceObjectWrapper>())
|
|
|
|
+ {
|
|
|
|
+ if (!Wrapper->InstanceObject)
|
|
|
|
+ {
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return true;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void FEzAbilityInstanceStorage::ResetTemporaryInstances()
|
|
|
|
+{
|
|
|
|
+ TemporaryInstances.Reset();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
+///InstanceData
|
|
|
|
+
|
|
|
|
+FEzAbilityInstanceData::FEzAbilityInstanceData(const FEzAbilityInstanceData& Other)
|
|
|
|
+{
|
|
|
|
+ InstanceStorage = MakeShared<FEzAbilityInstanceStorage>(*Other.InstanceStorage);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+FEzAbilityInstanceData::FEzAbilityInstanceData(FEzAbilityInstanceData&& Other)
|
|
|
|
+{
|
|
|
|
+ InstanceStorage = Other.InstanceStorage;
|
|
|
|
+ Other.InstanceStorage = MakeShared<FEzAbilityInstanceStorage>();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+FEzAbilityInstanceData::~FEzAbilityInstanceData()
|
|
|
|
+{
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+FEzAbilityInstanceData& FEzAbilityInstanceData::operator=(const FEzAbilityInstanceData& Other)
|
|
|
|
+{
|
|
|
|
+ InstanceStorage = MakeShared<FEzAbilityInstanceStorage>(*Other.InstanceStorage);
|
|
|
|
+ return *this;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+FEzAbilityInstanceData& FEzAbilityInstanceData::operator=(FEzAbilityInstanceData&& Other)
|
|
|
|
+{
|
|
|
|
+ InstanceStorage = Other.InstanceStorage;
|
|
|
|
+ Other.InstanceStorage = MakeShared<FEzAbilityInstanceStorage>();
|
|
|
|
+ return *this;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void FEzAbilityInstanceData::Reset()
|
|
|
|
+{
|
|
|
|
+ FEzAbilityInstanceStorage& Storage = GetMutableStorage();
|
|
|
|
+ Storage.Reset();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void FEzAbilityInstanceData::Init(UObject& InOwner, TConstArrayView<FInstancedStruct> InStructs)
|
|
|
|
+{
|
|
|
|
+ Reset();
|
|
|
|
+ Append(InOwner, InStructs);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void FEzAbilityInstanceData::Init(UObject& InOwner, TConstArrayView<FConstStructView> InStructs)
|
|
|
|
+{
|
|
|
|
+ Reset();
|
|
|
|
+ Append(InOwner, InStructs);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void FEzAbilityInstanceData::Append(UObject& InOwner, TConstArrayView<FInstancedStruct> InStructs) const
|
|
|
|
+{
|
|
|
|
+ FEzAbilityInstanceStorage& Storage = GetMutableStorage();
|
|
|
|
+
|
|
|
|
+ const int32 StartIndex = Storage.InstanceStructs.Num();
|
|
|
|
+ Storage.InstanceStructs.Append(InStructs);
|
|
|
|
+
|
|
|
|
+ for (int32 Index = StartIndex; Index < Storage.InstanceStructs.Num(); Index++)
|
|
|
|
+ {
|
|
|
|
+ if (FEzAbilityInstanceObjectWrapper* Wrapper = Storage.InstanceStructs[Index].GetPtr<FEzAbilityInstanceObjectWrapper>())
|
|
|
|
+ {
|
|
|
|
+ if (Wrapper->InstanceObject)
|
|
|
|
+ {
|
|
|
|
+ Wrapper->InstanceObject = EzAbility::DuplicateNodeInstance(*Wrapper->InstanceObject, InOwner);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void FEzAbilityInstanceData::Append(UObject& InOwner, TConstArrayView<FConstStructView> InStructs) const
|
|
|
|
+{
|
|
|
|
+ FEzAbilityInstanceStorage& Storage = GetMutableStorage();
|
|
|
|
+
|
|
|
|
+ const int32 StartIndex = Storage.InstanceStructs.Num();
|
|
|
|
+ Storage.InstanceStructs.Append(InStructs);
|
|
|
|
+
|
|
|
|
+ for (int32 Index = StartIndex; Index < Storage.InstanceStructs.Num(); Index++)
|
|
|
|
+ {
|
|
|
|
+ if (FEzAbilityInstanceObjectWrapper* Wrapper = Storage.InstanceStructs[Index].GetPtr<FEzAbilityInstanceObjectWrapper>())
|
|
|
|
+ {
|
|
|
|
+ if (Wrapper->InstanceObject)
|
|
|
|
+ {
|
|
|
|
+ Wrapper->InstanceObject = EzAbility::DuplicateNodeInstance(*Wrapper->InstanceObject, InOwner);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void FEzAbilityInstanceData::Append(UObject& InOwner, TConstArrayView<FConstStructView> InStructs, TConstArrayView<FInstancedStruct*> InInstancesToMove) const
|
|
|
|
+{
|
|
|
|
+ check(InStructs.Num() == InInstancesToMove.Num());
|
|
|
|
+
|
|
|
|
+ FEzAbilityInstanceStorage& Storage = GetMutableStorage();
|
|
|
|
+
|
|
|
|
+ const int32 StartIndex = Storage.InstanceStructs.Num();
|
|
|
|
+ Storage.InstanceStructs.Append(InStructs);
|
|
|
|
+
|
|
|
|
+ for (int32 Index = StartIndex; Index < Storage.InstanceStructs.Num(); Index++)
|
|
|
|
+ {
|
|
|
|
+ FStructView Struct = Storage.InstanceStructs[Index];
|
|
|
|
+ FInstancedStruct* Source = InInstancesToMove[Index - StartIndex];
|
|
|
|
+
|
|
|
|
+ // The source is used to move temporary instance data into instance data. Not all entries may have it.
|
|
|
|
+ // The instance struct can be empty, in which case the temporary instance is ignored.
|
|
|
|
+ // If the source is specified, move it to the instance data.
|
|
|
|
+ // We assume that if the source is object wrapper, it is already the instance we want.
|
|
|
|
+ if (Struct.IsValid() && (Source && Source->IsValid()))
|
|
|
|
+ {
|
|
|
|
+ check(Struct.GetScriptStruct() == Source->GetScriptStruct());
|
|
|
|
+
|
|
|
|
+ FMemory::Memswap(Struct.GetMemory(), Source->GetMutableMemory(), Struct.GetScriptStruct()->GetStructureSize());
|
|
|
|
+ Source->Reset();
|
|
|
|
+ }
|
|
|
|
+ else if (FEzAbilityInstanceObjectWrapper* Wrapper = Struct.GetPtr<FEzAbilityInstanceObjectWrapper>())
|
|
|
|
+ {
|
|
|
|
+ if (Wrapper->InstanceObject)
|
|
|
|
+ {
|
|
|
|
+ Wrapper->InstanceObject = EzAbility::DuplicateNodeInstance(*Wrapper->InstanceObject, InOwner);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void FEzAbilityInstanceData::ShrinkTo(const int32 Num) const
|
|
|
|
+{
|
|
|
|
+ FEzAbilityInstanceStorage& Storage = GetMutableStorage();
|
|
|
|
+ check(Num <= Storage.InstanceStructs.Num());
|
|
|
|
+ Storage.InstanceStructs.SetNum(Num);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void FEzAbilityInstanceData::CopyFrom(UObject& InOwner, const FEzAbilityInstanceData& InOther) const
|
|
|
|
+{
|
|
|
|
+ if (&InOther == this)
|
|
|
|
+ {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ FEzAbilityInstanceStorage& Storage = GetMutableStorage();
|
|
|
|
+ const FEzAbilityInstanceStorage& OtherStorage = InOther.GetStorage();
|
|
|
|
+
|
|
|
|
+ // Copy structs
|
|
|
|
+ Storage.InstanceStructs = OtherStorage.InstanceStructs;
|
|
|
|
+
|
|
|
|
+ // Copy instance objects.
|
|
|
|
+ for (FStructView Instance : Storage.InstanceStructs)
|
|
|
|
+ {
|
|
|
|
+ if (FEzAbilityInstanceObjectWrapper* Wrapper = Instance.GetPtr<FEzAbilityInstanceObjectWrapper>())
|
|
|
|
+ {
|
|
|
|
+ if (Wrapper->InstanceObject)
|
|
|
|
+ {
|
|
|
|
+ Wrapper->InstanceObject = EzAbility::DuplicateNodeInstance(*Wrapper->InstanceObject, InOwner);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+bool FEzAbilityInstanceData::AreAllInstancesValid() const
|
|
|
|
+{
|
|
|
|
+ return GetStorage().AreAllInstancesValid();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+int32 FEzAbilityInstanceData::GetEstimatedMemoryUsage() const
|
|
|
|
+{
|
|
|
|
+ const FEzAbilityInstanceStorage& Storage = GetStorage();
|
|
|
|
+ int32 Size = sizeof(FEzAbilityInstanceData);
|
|
|
|
+
|
|
|
|
+ Size += Storage.InstanceStructs.GetAllocatedMemory();
|
|
|
|
+
|
|
|
|
+ for (FConstStructView Instance : Storage.InstanceStructs)
|
|
|
|
+ {
|
|
|
|
+ if (const FEzAbilityInstanceObjectWrapper* Wrapper = Instance.GetPtr<const FEzAbilityInstanceObjectWrapper>())
|
|
|
|
+ {
|
|
|
|
+ if (Wrapper->InstanceObject)
|
|
|
|
+ {
|
|
|
|
+ Size += Wrapper->InstanceObject->GetClass()->GetStructureSize();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return Size;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+bool FEzAbilityInstanceData::Identical(const FEzAbilityInstanceData* Other, uint32 PortFlags) const
|
|
|
|
+{
|
|
|
|
+ if (Other == nullptr)
|
|
|
|
+ {
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ const FEzAbilityInstanceStorage& Storage = GetStorage();
|
|
|
|
+ const FEzAbilityInstanceStorage& OtherStorage = Other->GetStorage();
|
|
|
|
+
|
|
|
|
+ // Not identical if global parameters don't match.
|
|
|
|
+ // if (!Storage.GlobalParameters.Identical(&OtherStorage.GlobalParameters, PortFlags))
|
|
|
|
+ // {
|
|
|
|
+ // return false;
|
|
|
|
+ // }
|
|
|
|
+
|
|
|
|
+ // Not identical if structs are different.
|
|
|
|
+ if (Storage.InstanceStructs.Identical(&OtherStorage.InstanceStructs, PortFlags) == false)
|
|
|
|
+ {
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // Check that the instance object contents are identical.
|
|
|
|
+ // Copied from object property.
|
|
|
|
+ auto AreObjectsIdentical = [](UObject* A, UObject* B, uint32 PortFlags) -> bool
|
|
|
|
+ {
|
|
|
|
+ if ((PortFlags & PPF_DuplicateForPIE) != 0)
|
|
|
|
+ {
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (A == B)
|
|
|
|
+ {
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // Resolve the object handles and run the deep comparison logic
|
|
|
|
+ if ((PortFlags & (PPF_DeepCompareInstances | PPF_DeepComparison)) != 0)
|
|
|
|
+ {
|
|
|
|
+ return FObjectPropertyBase::StaticIdentical(A, B, PortFlags);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return true;
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ bool bResult = true;
|
|
|
|
+
|
|
|
|
+ for (int32 Index = 0; Index < Storage.InstanceStructs.Num(); Index++)
|
|
|
|
+ {
|
|
|
|
+ const FEzAbilityInstanceObjectWrapper* Wrapper = Storage.InstanceStructs[Index].GetPtr<const FEzAbilityInstanceObjectWrapper>();
|
|
|
|
+ const FEzAbilityInstanceObjectWrapper* OtherWrapper = OtherStorage.InstanceStructs[Index].GetPtr<const FEzAbilityInstanceObjectWrapper>();
|
|
|
|
+
|
|
|
|
+ if (Wrapper)
|
|
|
|
+ {
|
|
|
|
+ if (!OtherWrapper)
|
|
|
|
+ {
|
|
|
|
+ bResult = false;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ if (Wrapper->InstanceObject && OtherWrapper->InstanceObject)
|
|
|
|
+ {
|
|
|
|
+ if (!AreObjectsIdentical(Wrapper->InstanceObject, OtherWrapper->InstanceObject, PortFlags))
|
|
|
|
+ {
|
|
|
|
+ bResult = false;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return bResult;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void FEzAbilityInstanceData::AddStructReferencedObjects(FReferenceCollector& Collector)
|
|
|
|
+{
|
|
|
|
+ Collector.AddPropertyReferencesWithStructARO(FEzAbilityInstanceStorage::StaticStruct(), &GetMutableStorage());
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+bool FEzAbilityInstanceData::Serialize(FArchive& Ar)
|
|
|
|
+{
|
|
|
|
+ if (Ar.IsLoading())
|
|
|
|
+ {
|
|
|
|
+ InstanceStorage = MakeShared<FEzAbilityInstanceStorage>();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ FEzAbilityInstanceStorage::StaticStruct()->SerializeItem(Ar, &InstanceStorage.Get(), nullptr);
|
|
|
|
+
|
|
|
|
+ return true;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void FEzAbilityInstanceData::GetPreloadDependencies(TArray<UObject*>& OutDeps)
|
|
|
|
+{
|
|
|
|
+ UScriptStruct* ScriptStruct = FEzAbilityInstanceStorage::StaticStruct();
|
|
|
|
+ OutDeps.Add(ScriptStruct);
|
|
|
|
+
|
|
|
|
+ if (UScriptStruct::ICppStructOps* CppStructOps = ScriptStruct->GetCppStructOps())
|
|
|
|
+ {
|
|
|
|
+ CppStructOps->GetPreloadDependencies(&GetMutableStorage(), OutDeps);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ for (TPropertyValueIterator<FStructProperty> It(ScriptStruct, &GetMutableStorage()); It; ++It)
|
|
|
|
+ {
|
|
|
|
+ const UScriptStruct* StructType = It.Key()->Struct;
|
|
|
|
+ if (UScriptStruct::ICppStructOps* CppStructOps = StructType->GetCppStructOps())
|
|
|
|
+ {
|
|
|
|
+ void* StructDataPtr = const_cast<void*>(It.Value());
|
|
|
|
+ CppStructOps->GetPreloadDependencies(StructDataPtr, OutDeps);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|