You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
676 lines
19 KiB
C++
676 lines
19 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "UniversalObjectLocatorFragment.h"
|
|
#include "Algo/Find.h"
|
|
#include "UniversalObjectLocatorFragmentType.h"
|
|
#include "UniversalObjectLocatorStringParams.h"
|
|
#include "UniversalObjectLocatorInitializeParams.h"
|
|
#include "UniversalObjectLocatorInitializeResult.h"
|
|
#include "UObject/SoftObjectPath.h"
|
|
#include "Containers/SparseArray.h"
|
|
#include "Misc/AsciiSet.h"
|
|
|
|
#define LOCTEXT_NAMESPACE "UOL"
|
|
|
|
DECLARE_LOG_CATEGORY_EXTERN(LogUniversalObjectLocator, Log, Warning);
|
|
DEFINE_LOG_CATEGORY(LogUniversalObjectLocator);
|
|
|
|
namespace UE::UniversalObjectLocator
|
|
{
|
|
extern TArray<FFragmentType> GFragmentTypes;
|
|
|
|
const FFragmentType* FindBestFragmentType(const UObject* Object, const UObject* Context)
|
|
{
|
|
// Loop through all our FragmentTypes to find the most supported one
|
|
uint32 BestFragmentTypePriority = 0;
|
|
const FFragmentType* BestFragmentType = nullptr;
|
|
|
|
for (const FFragmentType& FragmentType : GFragmentTypes)
|
|
{
|
|
const uint32 ThisFragmentTypePriority = FragmentType.ComputePriority(Object, Context);
|
|
if (ThisFragmentTypePriority > BestFragmentTypePriority)
|
|
{
|
|
BestFragmentTypePriority = ThisFragmentTypePriority;
|
|
BestFragmentType = &FragmentType;
|
|
}
|
|
}
|
|
|
|
if (BestFragmentType && BestFragmentType->PayloadType != nullptr)
|
|
{
|
|
return BestFragmentType;
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
FFragmentType* FFragmentTypeHandle::Resolve() const
|
|
{
|
|
return Handle == 0xff ? nullptr : &GFragmentTypes[Handle];
|
|
}
|
|
|
|
FFragmentTypeHandle MakeFragmentTypeHandle(const FFragmentType* FragmentType)
|
|
{
|
|
check(FragmentType);
|
|
|
|
const uint64 FragmentTypeOffset = static_cast<uint64>(FragmentType - GFragmentTypes.GetData());
|
|
checkf(FragmentTypeOffset < std::numeric_limits<uint8>::max(), TEXT("Maximum number of UOL FragmentTypes reached"));
|
|
|
|
return FFragmentTypeHandle(static_cast<uint8>(FragmentTypeOffset));
|
|
}
|
|
|
|
} // UE::UniversalObjectLocator
|
|
|
|
|
|
FUniversalObjectLocatorFragment::FUniversalObjectLocatorFragment(const UObject* InObject, const UObject* Context)
|
|
: bIsInitialized(0)
|
|
, bIsInline(0)
|
|
{
|
|
Reset(InObject, Context);
|
|
}
|
|
|
|
FUniversalObjectLocatorFragment::FUniversalObjectLocatorFragment(const UE::UniversalObjectLocator::FFragmentType& InFragmentType)
|
|
: FragmentType(MakeFragmentTypeHandle(&InFragmentType))
|
|
, bIsInitialized(0)
|
|
, bIsInline(0)
|
|
{
|
|
this->InitializePayload(InFragmentType.PayloadType);
|
|
}
|
|
|
|
FUniversalObjectLocatorFragment::FUniversalObjectLocatorFragment()
|
|
: bIsInitialized(0)
|
|
, bIsInline(0)
|
|
{
|
|
static_assert(sizeof(FUniversalObjectLocatorFragment) == FUniversalObjectLocatorFragment::Size, "Unexpected size for FUniversalObjectLocatorFragment");
|
|
static_assert(offsetof(FUniversalObjectLocatorFragment, Data) == 0, "FUniversalObjectLocatorFragment inline data is not aligned properly");
|
|
}
|
|
|
|
FUniversalObjectLocatorFragment::~FUniversalObjectLocatorFragment()
|
|
{
|
|
if (bIsInitialized && !IsEngineExitRequested())
|
|
{
|
|
DestroyPayload();
|
|
}
|
|
}
|
|
|
|
FUniversalObjectLocatorFragment::FUniversalObjectLocatorFragment(const FUniversalObjectLocatorFragment& RHS)
|
|
: FragmentType(RHS.FragmentType)
|
|
, bIsInitialized(0)
|
|
, bIsInline(0)
|
|
{
|
|
using namespace UE::UniversalObjectLocator;
|
|
|
|
if (RHS.bIsInitialized)
|
|
{
|
|
const UScriptStruct* FragmentStruct = GetFragmentStruct();
|
|
check(FragmentStruct);
|
|
|
|
this->InitializePayload(FragmentStruct);
|
|
|
|
FragmentStruct->CopyScriptStruct(this->GetPayload(), RHS.GetPayload());
|
|
}
|
|
else
|
|
{
|
|
this->bIsInitialized = false;
|
|
}
|
|
}
|
|
|
|
FUniversalObjectLocatorFragment& FUniversalObjectLocatorFragment::operator=(const FUniversalObjectLocatorFragment& RHS)
|
|
{
|
|
using namespace UE::UniversalObjectLocator;
|
|
|
|
this->DestroyPayload();
|
|
|
|
if (RHS.bIsInitialized)
|
|
{
|
|
const UScriptStruct* FragmentStruct = GetFragmentStruct();
|
|
|
|
// Assign the FragmentType and copy the payload
|
|
this->FragmentType = RHS.FragmentType;
|
|
this->InitializePayload(FragmentStruct);
|
|
FragmentStruct->CopyScriptStruct(this->GetPayload(), RHS.GetPayload());
|
|
}
|
|
else
|
|
{
|
|
this->bIsInitialized = false;
|
|
this->FragmentType = FFragmentTypeHandle();
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
FUniversalObjectLocatorFragment::FUniversalObjectLocatorFragment(FUniversalObjectLocatorFragment&& RHS)
|
|
: FragmentType(RHS.FragmentType)
|
|
, bIsInitialized(RHS.bIsInitialized)
|
|
, bIsInline(RHS.bIsInline)
|
|
{
|
|
using namespace UE::UniversalObjectLocator;
|
|
|
|
FMemory::Memcpy(this->Data, RHS.Data, sizeof(Data));
|
|
|
|
RHS.bIsInitialized = false;
|
|
RHS.bIsInline = false;
|
|
RHS.FragmentType = FFragmentTypeHandle();
|
|
}
|
|
|
|
FUniversalObjectLocatorFragment& FUniversalObjectLocatorFragment::operator=(FUniversalObjectLocatorFragment&& RHS)
|
|
{
|
|
using namespace UE::UniversalObjectLocator;
|
|
|
|
this->DestroyPayload();
|
|
|
|
this->bIsInitialized = RHS.bIsInitialized;
|
|
this->bIsInline = RHS.bIsInline;
|
|
this->FragmentType = RHS.FragmentType;
|
|
FMemory::Memcpy(this->Data, RHS.Data, sizeof(Data));
|
|
|
|
RHS.bIsInitialized = false;
|
|
RHS.bIsInline = false;
|
|
RHS.FragmentType = FFragmentTypeHandle();
|
|
|
|
return *this;
|
|
}
|
|
|
|
bool operator==(const FUniversalObjectLocatorFragment& A, const FUniversalObjectLocatorFragment& B)
|
|
{
|
|
using namespace UE::UniversalObjectLocator;
|
|
|
|
if (A.bIsInitialized != B.bIsInitialized)
|
|
{
|
|
return false;
|
|
}
|
|
else if (!A.bIsInitialized)
|
|
{
|
|
// 2 uninitialized references are the same
|
|
return true;
|
|
}
|
|
else if (A.FragmentType != B.FragmentType)
|
|
{
|
|
// Different fragment types
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
const UScriptStruct* FragmentStruct = A.GetFragmentStruct();
|
|
check(FragmentStruct);
|
|
|
|
// Same fragment types - compare payloads
|
|
const void* PayloadA = A.GetPayload();
|
|
const void* PayloadB = B.GetPayload();
|
|
|
|
return FragmentStruct->CompareScriptStruct(PayloadA, PayloadB, 0);
|
|
}
|
|
}
|
|
|
|
bool operator!=(const FUniversalObjectLocatorFragment& A, const FUniversalObjectLocatorFragment& B)
|
|
{
|
|
return !(A == B);
|
|
}
|
|
|
|
uint32 GetTypeHash(const FUniversalObjectLocatorFragment& Fragment)
|
|
{
|
|
using namespace UE::UniversalObjectLocator;
|
|
|
|
if (!Fragment.bIsInitialized)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
uint32 Hash = GetTypeHash(Fragment.FragmentType);
|
|
|
|
if (const FFragmentType* FragmentTypePtr = Fragment.GetFragmentType())
|
|
{
|
|
UScriptStruct* Struct = FragmentTypePtr->GetStruct();
|
|
if (Struct)
|
|
{
|
|
const uint32 PayloadHash = Struct->GetStructTypeHash(Fragment.GetPayload());
|
|
Hash = HashCombineFast(Hash, PayloadHash);
|
|
}
|
|
}
|
|
|
|
return Hash;
|
|
}
|
|
|
|
#if DO_CHECK
|
|
void FUniversalObjectLocatorFragment::CheckPayloadType(UScriptStruct* TypeToCompare) const
|
|
{
|
|
using namespace UE::UniversalObjectLocator;
|
|
|
|
const FFragmentType* FragmentTypePtr = GetFragmentType();
|
|
checkf(FragmentTypePtr == nullptr || FragmentTypePtr->PayloadType == TypeToCompare,
|
|
TEXT("Type mismatch when accessing payload data! Attempting to access a stored %s payload as %s."),
|
|
FragmentTypePtr->PayloadType ? *FragmentTypePtr->PayloadType->GetName() : TEXT("<expired>"),
|
|
TypeToCompare ? *TypeToCompare->GetName() : TEXT("<nullptr>"));
|
|
}
|
|
#endif
|
|
|
|
void FUniversalObjectLocatorFragment::ToString(FStringBuilderBase& OutString) const
|
|
{
|
|
using namespace UE::UniversalObjectLocator;
|
|
|
|
const FFragmentType* FragmentTypePtr = FragmentType.Resolve();
|
|
if (FragmentTypePtr && FragmentTypePtr->PayloadType)
|
|
{
|
|
FragmentTypePtr->FragmentTypeID.AppendString(OutString);
|
|
|
|
TStringBuilder<128> PayloadString;
|
|
FragmentTypePtr->ToString(GetPayload(), PayloadString);
|
|
if (PayloadString.Len() != 0)
|
|
{
|
|
OutString += '=';
|
|
OutString.Append(PayloadString.ToView());
|
|
}
|
|
}
|
|
}
|
|
|
|
UE::UniversalObjectLocator::FParseStringResult FUniversalObjectLocatorFragment::TryParseString(FStringView InString, const FParseStringParams& InParams)
|
|
{
|
|
using namespace UE::UniversalObjectLocator;
|
|
|
|
if (InString.Len() == 0)
|
|
{
|
|
Reset();
|
|
return FParseStringResult().Success();
|
|
}
|
|
|
|
// Check for a literal "none" text
|
|
static constexpr FStringView NoneString = TEXTVIEW("none");
|
|
if (InString.Compare(NoneString, ESearchCase::IgnoreCase) == 0)
|
|
{
|
|
Reset();
|
|
return FParseStringResult().Success(NoneString.Len());
|
|
}
|
|
|
|
FStringView FragmentTypeString = InString;
|
|
FStringView FragmentPayloadString;
|
|
|
|
const int32 Delimiter = UE::String::FindFirstChar(InString, '=');
|
|
if (Delimiter != INDEX_NONE)
|
|
{
|
|
// We have a payload
|
|
FragmentTypeString = InString.Left(Delimiter);
|
|
FragmentPayloadString = InString.RightChop(Delimiter + 1);
|
|
|
|
if (FragmentTypeString.Len() == 0)
|
|
{
|
|
return FParseStringResult().Failure(UE_UOL_PARSE_ERROR(InParams, LOCTEXT("Error_UnexpectedEquals", "Unexpected '='' when expecting a fragment type.")));
|
|
}
|
|
}
|
|
|
|
FParseStringResult TypeResult = TryParseFragmentType(FragmentTypeString, InParams);
|
|
if (!TypeResult)
|
|
{
|
|
return TypeResult;
|
|
}
|
|
|
|
FParseStringResult PayloadResult = TryParseFragmentPayload(FragmentPayloadString, InParams);
|
|
|
|
// Add the type chars and = to the total num parsed
|
|
PayloadResult.NumCharsParsed += TypeResult.NumCharsParsed + 1;
|
|
return PayloadResult;
|
|
}
|
|
|
|
UE::UniversalObjectLocator::FParseStringResult FUniversalObjectLocatorFragment::TryParseFragmentType(FStringView InString, const FParseStringParams& InParams)
|
|
{
|
|
using namespace UE::UniversalObjectLocator;
|
|
|
|
if (InString.Len() == 0)
|
|
{
|
|
return FParseStringResult().Failure(UE_UOL_PARSE_ERROR(InParams, LOCTEXT("Error_EmptyFragmentType", "Fragment type specifier is empty.")));
|
|
}
|
|
|
|
// Check for a literal "none" text
|
|
static constexpr FStringView NoneString = TEXTVIEW("none");
|
|
if (InString.Compare(NoneString, ESearchCase::IgnoreCase) == 0)
|
|
{
|
|
Reset();
|
|
return FParseStringResult().Success(NoneString.Len());
|
|
}
|
|
|
|
// Try and find the FragmentType as a name
|
|
FName FragmentTypeID(InString.Len(), InString.GetData(), FNAME_Find);
|
|
if (FragmentTypeID != NAME_None)
|
|
{
|
|
// Find the FragmentType
|
|
const FFragmentType* SerializedFragmentType = Algo::FindBy(GFragmentTypes, FragmentTypeID, &FFragmentType::FragmentTypeID);
|
|
if (SerializedFragmentType != nullptr && SerializedFragmentType->PayloadType != nullptr)
|
|
{
|
|
this->DestroyPayload();
|
|
this->FragmentType = MakeFragmentTypeHandle(SerializedFragmentType);
|
|
this->InitializePayload(SerializedFragmentType->PayloadType);
|
|
|
|
return FParseStringResult().Success(InString.Len());
|
|
}
|
|
}
|
|
|
|
// Not a valid fragment type string
|
|
return FParseStringResult().Failure(
|
|
UE_UOL_PARSE_ERROR(InParams,
|
|
FText::Format(
|
|
LOCTEXT("Error_UnknownFragmentType", "Unknown fragment type specifier {0}."),
|
|
FText::FromStringView(InString)
|
|
)
|
|
)
|
|
);
|
|
}
|
|
|
|
UE::UniversalObjectLocator::FParseStringResult FUniversalObjectLocatorFragment::TryParseFragmentPayload(FStringView InString, const FParseStringParams& InParams)
|
|
{
|
|
using namespace UE::UniversalObjectLocator;
|
|
|
|
if (!bIsInitialized)
|
|
{
|
|
return FParseStringResult().Failure(UE_UOL_PARSE_ERROR(InParams, LOCTEXT("Error_Uninitialized", "Unable to parse a payload for an uninitialized fragment.")));
|
|
}
|
|
|
|
const FFragmentType* FragmentTypePtr = GetFragmentType();
|
|
const UScriptStruct* FragmentStruct = FragmentTypePtr ? FragmentTypePtr->GetStruct() : nullptr;
|
|
|
|
if (!FragmentStruct)
|
|
{
|
|
return FParseStringResult().Failure(UE_UOL_PARSE_ERROR(InParams, LOCTEXT("Error_Expired", "Unable to parse a payload for a fragment whose type has expired.")));
|
|
}
|
|
|
|
void* Payload = GetPayload();
|
|
if (InString.Len() == 0)
|
|
{
|
|
// Empty payload string means a default payload
|
|
FragmentStruct->ClearScriptStruct(Payload);
|
|
return FParseStringResult().Success();
|
|
}
|
|
|
|
return FragmentTypePtr->TryParseString(Payload, InString, InParams);
|
|
}
|
|
|
|
const UE::UniversalObjectLocator::FFragmentType* FUniversalObjectLocatorFragment::GetFragmentType() const
|
|
{
|
|
return FragmentType.Resolve();
|
|
}
|
|
|
|
UScriptStruct* FUniversalObjectLocatorFragment::GetFragmentStruct() const
|
|
{
|
|
using namespace UE::UniversalObjectLocator;
|
|
if (const FFragmentType* Type = GetFragmentType())
|
|
{
|
|
return Type->GetStruct();
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
UE::UniversalObjectLocator::FFragmentTypeHandle FUniversalObjectLocatorFragment::GetFragmentTypeHandle() const
|
|
{
|
|
using namespace UE::UniversalObjectLocator;
|
|
|
|
const FFragmentType* FragmentTypePtr = GetFragmentType();
|
|
if (FragmentTypePtr)
|
|
{
|
|
return MakeFragmentTypeHandle(FragmentTypePtr);
|
|
}
|
|
return FFragmentTypeHandle();
|
|
}
|
|
|
|
void FUniversalObjectLocatorFragment::DestroyPayload()
|
|
{
|
|
using namespace UE::UniversalObjectLocator;
|
|
|
|
if (!bIsInitialized)
|
|
{
|
|
return;
|
|
}
|
|
|
|
void* Payload = GetPayload();
|
|
|
|
const UScriptStruct* FragmentStruct = GetFragmentStruct();
|
|
if (ensureMsgf(FragmentStruct, TEXT("FUniversalObjectLocatorFragment has outlived its FragmentType's payload type struct! This could leak memory if the type allocated it.")))
|
|
{
|
|
FragmentStruct->DestroyStruct(Payload);
|
|
}
|
|
|
|
if (!bIsInline)
|
|
{
|
|
FMemory::Free(Payload);
|
|
}
|
|
|
|
bIsInitialized = false;
|
|
}
|
|
|
|
void* FUniversalObjectLocatorFragment::GetPayload()
|
|
{
|
|
check(bIsInitialized);
|
|
return bIsInline ? Data : *((void**)Data);
|
|
}
|
|
|
|
const void* FUniversalObjectLocatorFragment::GetPayload() const
|
|
{
|
|
return bIsInline ? Data : *((const void* const *)Data);
|
|
}
|
|
|
|
void FUniversalObjectLocatorFragment::InitializePayload(const UScriptStruct* PayloadType)
|
|
{
|
|
check(!bIsInitialized);
|
|
|
|
bIsInitialized = true;
|
|
if (PayloadType->GetStructureSize() <= sizeof(FUniversalObjectLocatorFragment::Data) && PayloadType->GetMinAlignment() <= alignof(FUniversalObjectLocatorFragment))
|
|
{
|
|
// We can placement new this into the payload data
|
|
bIsInline = true;
|
|
}
|
|
else
|
|
{
|
|
// We have to allocate this struct on the heap
|
|
void* HeapAllocation = FMemory::Malloc(PayloadType->GetStructureSize(), PayloadType->GetMinAlignment());
|
|
*reinterpret_cast<void**>(Data) = HeapAllocation;
|
|
bIsInline = false;
|
|
}
|
|
|
|
PayloadType->InitializeStruct(GetPayload());
|
|
}
|
|
|
|
void FUniversalObjectLocatorFragment::Reset()
|
|
{
|
|
using namespace UE::UniversalObjectLocator;
|
|
|
|
DestroyPayload();
|
|
FragmentType = FFragmentTypeHandle();
|
|
}
|
|
|
|
void FUniversalObjectLocatorFragment::Reset(const UObject* InObject, const UObject* Context)
|
|
{
|
|
using namespace UE::UniversalObjectLocator;
|
|
|
|
Reset();
|
|
|
|
if (const FFragmentType* BestFragmentType = FindBestFragmentType(InObject, Context))
|
|
{
|
|
FragmentType = MakeFragmentTypeHandle(BestFragmentType);
|
|
InitializePayload(BestFragmentType->PayloadType);
|
|
|
|
BestFragmentType->InitializePayload(GetPayload(), FInitializeParams{ InObject, Context });
|
|
}
|
|
}
|
|
|
|
void FUniversalObjectLocatorFragment::Reset(const UObject* InObject, const UObject* Context, TFunctionRef<bool(UE::UniversalObjectLocator::FFragmentTypeHandle)> CanUseFragmentType)
|
|
{
|
|
using namespace UE::UniversalObjectLocator;
|
|
|
|
Reset();
|
|
|
|
// Loop through all our FragmentTypes to find the most supported one
|
|
uint32 BestFragmentTypePriority = 0;
|
|
const FFragmentType* BestFragmentType = nullptr;
|
|
|
|
if (!ensure(GFragmentTypes.Num() < 255))
|
|
{
|
|
return;
|
|
}
|
|
|
|
const uint8 Num = static_cast<uint8>(GFragmentTypes.Num());
|
|
for (uint8 Index = 0; Index < Num; ++Index)
|
|
{
|
|
if (!CanUseFragmentType(FFragmentTypeHandle(Index)))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
const FFragmentType& ThisFragmentType = GFragmentTypes[Index];
|
|
const uint32 ThisFragmentTypePriority = ThisFragmentType.ComputePriority(InObject, Context);
|
|
if (ThisFragmentTypePriority > BestFragmentTypePriority)
|
|
{
|
|
BestFragmentTypePriority = ThisFragmentTypePriority;
|
|
BestFragmentType = &ThisFragmentType;
|
|
}
|
|
}
|
|
|
|
if (BestFragmentType && BestFragmentType->PayloadType != nullptr)
|
|
{
|
|
FragmentType = MakeFragmentTypeHandle(BestFragmentType);
|
|
InitializePayload(BestFragmentType->PayloadType);
|
|
|
|
BestFragmentType->InitializePayload(GetPayload(), FInitializeParams{ InObject, Context });
|
|
}
|
|
}
|
|
|
|
UE::UniversalObjectLocator::FResolveResult FUniversalObjectLocatorFragment::Resolve(const UE::UniversalObjectLocator::FResolveParams& Params) const
|
|
{
|
|
using namespace UE::UniversalObjectLocator;
|
|
|
|
// Find our FragmentType
|
|
const FFragmentType* FragmentTypePtr = FragmentType.Resolve();
|
|
if (FragmentTypePtr && bIsInitialized)
|
|
{
|
|
return FragmentTypePtr->ResolvePayload(GetPayload(), Params);
|
|
}
|
|
|
|
return FResolveResult();
|
|
}
|
|
|
|
bool FUniversalObjectLocatorFragment::Serialize(FArchive& Ar)
|
|
{
|
|
using namespace UE::UniversalObjectLocator;
|
|
|
|
if (Ar.IsLoading())
|
|
{
|
|
FName FragmentTypeID;
|
|
Ar << FragmentTypeID;
|
|
|
|
if (FragmentTypeID == NAME_None)
|
|
{
|
|
Reset();
|
|
}
|
|
else
|
|
{
|
|
// Find the FragmentType
|
|
const FFragmentType* SerializedFragmentType = Algo::FindBy(GFragmentTypes, FragmentTypeID, &FFragmentType::FragmentTypeID);
|
|
if (!SerializedFragmentType || !SerializedFragmentType->PayloadType)
|
|
{
|
|
Reset();
|
|
|
|
// Big error - what do we do?
|
|
UE_LOG(LogUniversalObjectLocator, Error, TEXT("WARNING: POTENTIAL DATA LOSS! Universal Object Reference FragmentType %s is not recognized! This reference will be lost if re-saved."), *FragmentTypeID.ToString());
|
|
checkf(false, TEXT("WARNING: POTENTIAL DATA LOSS! Universal Object Reference FragmentType %s! This reference will be lost if re-saved."), *FragmentTypeID.ToString());
|
|
|
|
// Deserialize an empty payload so we don't corrupt the serialization data
|
|
FUniversalObjectLocatorEmptyPayload Empty;
|
|
FUniversalObjectLocatorEmptyPayload::StaticStruct()->SerializeItem(Ar, &Empty, nullptr);
|
|
return true;
|
|
}
|
|
|
|
FragmentType = MakeFragmentTypeHandle(SerializedFragmentType);
|
|
|
|
UScriptStruct* Struct = SerializedFragmentType->GetStruct();
|
|
Ar.Preload(Struct);
|
|
|
|
InitializePayload(Struct);
|
|
Struct->SerializeItem(Ar, GetPayload(), nullptr);
|
|
}
|
|
}
|
|
else if (Ar.IsSaving() || Ar.IsTransacting())
|
|
{
|
|
const FFragmentType* FragmentTypePtr = FragmentType.Resolve();
|
|
|
|
if (FragmentTypePtr == nullptr)
|
|
{
|
|
FName None;
|
|
|
|
// FragmentType ID
|
|
Ar << None;
|
|
}
|
|
else
|
|
{
|
|
FName FragmentTypeID = FragmentTypePtr->FragmentTypeID;
|
|
|
|
// FragmentType ID
|
|
Ar << FragmentTypeID;
|
|
|
|
// FragmentType payload
|
|
FragmentTypePtr->GetStruct()->SerializeItem(Ar, GetPayload(), nullptr);
|
|
}
|
|
}
|
|
else if (Ar.IsModifyingWeakAndStrongReferences())
|
|
{
|
|
UScriptStruct* FragmentStruct = GetFragmentStruct();
|
|
if (FragmentStruct && bIsInitialized)
|
|
{
|
|
FragmentStruct->SerializeItem(Ar, GetPayload(), nullptr);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void FUniversalObjectLocatorFragment::AddStructReferencedObjects(FReferenceCollector& Collector)
|
|
{
|
|
using namespace UE::UniversalObjectLocator;
|
|
|
|
if (FFragmentType* FragmentTypePtr = FragmentType.Resolve())
|
|
{
|
|
Collector.AddReferencedObject(FragmentTypePtr->PayloadType);
|
|
if (bIsInitialized && FragmentTypePtr->PayloadType)
|
|
{
|
|
Collector.AddReferencedObjects(FragmentTypePtr->PayloadType, GetPayload());
|
|
}
|
|
}
|
|
}
|
|
|
|
bool FUniversalObjectLocatorFragment::ExportTextItem(FString& ValueStr, const FUniversalObjectLocatorFragment& DefaultValue, UObject* Parent, int32 PortFlags, UObject* ExportRootScope) const
|
|
{
|
|
TStringBuilder<32> PayloadString;
|
|
ToString(PayloadString);
|
|
|
|
ValueStr.AppendChar('(');
|
|
ValueStr.Append(PayloadString.ToString(), PayloadString.Len());
|
|
ValueStr.AppendChar(')');
|
|
|
|
return true;
|
|
}
|
|
|
|
bool FUniversalObjectLocatorFragment::ImportTextItem(const TCHAR*& Buffer, int32 PortFlags, UObject* Parent, FOutputDevice* ErrorText, FArchive* InSerializingArchive)
|
|
{
|
|
using namespace UE::UniversalObjectLocator;
|
|
|
|
if (Buffer && *Buffer == '(')
|
|
{
|
|
const TCHAR* BufferEnd = FCString::Strchr(Buffer, ')');
|
|
if (Buffer != BufferEnd && (BufferEnd - Buffer) < std::numeric_limits<int32>::max())
|
|
{
|
|
FStringView View(Buffer+1, int32(BufferEnd-Buffer)-1);
|
|
if (TryParseString(View, FParseStringParams()))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool FUniversalObjectLocatorFragment::SerializeFromMismatchedTag(const FPropertyTag& Tag, FStructuredArchive::FSlot Slot)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
void FUniversalObjectLocatorFragment::GetPreloadDependencies(TArray<UObject*>& OutDeps)
|
|
{
|
|
|
|
}
|
|
|
|
#undef LOCTEXT_NAMESPACE |