EM_Task/CoreUObject/Public/UObject/PersistentObjectPtr.h

264 lines
8.0 KiB
C
Raw Normal View History

2026-02-13 16:18:33 +08:00
// Copyright Epic Games, Inc. All Rights Reserved.
/*=============================================================================
PersistentObjectPtr.h: Template that is a base class for Lazy and Asset pointers
=============================================================================*/
#pragma once
#include "CoreMinimal.h"
#include "UObject/WeakObjectPtr.h"
#include "UObject/FastReferenceCollectorOptions.h"
/**
* TPersistentObjectPtr is a template base class for FLazyObjectPtr and FSoftObjectPtr
*/
template <class TObjectID>
struct TPersistentObjectPtr
{
public:
template <typename ReferenceProcessorType, typename CollectorType, typename ArrayPoolType, EFastReferenceCollectorOptions Options>
friend class TFastReferenceCollector;
/** Default constructor, will be null */
FORCEINLINE TPersistentObjectPtr()
{
Reset();
}
/** Reset the lazy pointer back to the null state */
FORCEINLINE void Reset()
{
WeakPtr.Reset();
ObjectID.Reset();
TagAtLastTest = 0;
}
/** Resets the weak ptr only, call this when ObjectId may change */
FORCEINLINE void ResetWeakPtr()
{
WeakPtr.Reset();
TagAtLastTest = 0;
}
/** Construct from a unique object identifier */
explicit FORCEINLINE TPersistentObjectPtr(const TObjectID& InObjectID)
: WeakPtr(), TagAtLastTest(0), ObjectID(InObjectID)
{
}
/** Copy from a unique object identifier */
FORCEINLINE void operator=(const TObjectID& InObjectID)
{
WeakPtr.Reset();
ObjectID = InObjectID;
TagAtLastTest = 0;
}
/** Copy from an object pointer */
FORCEINLINE void operator=(const class UObject* Object)
{
if (Object)
{
ObjectID = TObjectID::GetOrCreateIDForObject(Object);
WeakPtr = Object;
TagAtLastTest = TObjectID::GetCurrentTag();
}
else
{
Reset();
}
}
/** Copy from an existing weak pointer, reserve IDs if required */
FORCEINLINE void operator=(const FWeakObjectPtr& Other)
{
// If object exists need to make sure it gets registered properly in above function, if it doesn't exist just empty it
const UObject* Object = Other.Get();
*this = Object;
}
/**
* Gets the unique object identifier associated with this lazy pointer. Valid even if pointer is not currently valid
*
* @return Unique ID for this object, or an invalid FUniqueObjectGuid if this pointer isn't set to anything
*/
FORCEINLINE const TObjectID& GetUniqueID() const
{
return ObjectID;
}
/** Non-const version of the above */
FORCEINLINE TObjectID& GetUniqueID()
{
return ObjectID;
}
/**
* Dereference the pointer, which may cause it to become valid again. Will not try to load pending outside of game thread
*
* @return nullptr if this object is gone or the pointer was null, otherwise a valid UObject pointer
*/
FORCEINLINE UObject* Get() const
{
UObject* Object = WeakPtr.Get();
// Do a full resolve if the returned object is null and either we think we've loaded new objects, or the weak ptr may be stale
if (!Object && ObjectID.IsValid() && (TObjectID::GetCurrentTag() != TagAtLastTest || !WeakPtr.IsExplicitlyNull()))
{
Object = ObjectID.ResolveObject();
WeakPtr = Object;
// Not safe to update tag during save as ResolveObject may have failed accidentally
if (Object || !GIsSavingPackage)
{
TagAtLastTest = TObjectID::GetCurrentTag();
}
// If this object is pending kill or otherwise invalid, this will return nullptr as expected
Object = WeakPtr.Get();
}
return Object;
}
/**
* Dereference the lazy pointer, which may cause it to become valid again. Will not try to load pending outside of game thread
*
* @param bEvenIfPendingKill, if this is true, pendingkill objects are considered valid
* @return nullptr if this object is gone or the lazy pointer was null, otherwise a valid UObject pointer
*/
FORCEINLINE UObject* Get(bool bEvenIfPendingKill) const
{
UObject* Object = WeakPtr.Get(bEvenIfPendingKill);
if (!Object && TObjectID::GetCurrentTag() != TagAtLastTest && ObjectID.IsValid())
{
Object = ObjectID.ResolveObject();
WeakPtr = Object;
// Not safe to update tag during save as ResolveObject may have failed accidentally
if (Object || !GIsSavingPackage)
{
TagAtLastTest = TObjectID::GetCurrentTag();
}
// If this object is pending kill or otherwise invalid, this will return nullptr as expected
Object = WeakPtr.Get(bEvenIfPendingKill);
}
return Object;
}
/** Dereference the pointer */
FORCEINLINE class UObject& operator*() const
{
return *Get();
}
/** Dereference the pointer */
FORCEINLINE class UObject* operator->() const
{
return Get();
}
/** Compare pointers for equality. Only Serial Number matters for the base implementation */
FORCEINLINE friend bool operator==(const TPersistentObjectPtr& Lhs, const TPersistentObjectPtr& Rhs)
{
return Lhs.ObjectID == Rhs.ObjectID;
}
FORCEINLINE friend bool operator==(const TPersistentObjectPtr& Lhs, TYPE_OF_NULLPTR)
{
return !Lhs.IsValid();
}
FORCEINLINE friend bool operator==(TYPE_OF_NULLPTR, const TPersistentObjectPtr& Rhs)
{
return !Rhs.IsValid();
}
/** Compare pointers for inequality. Only Serial Number matters for the base implementation */
FORCEINLINE friend bool operator!=(const TPersistentObjectPtr& Lhs, const TPersistentObjectPtr& Rhs)
{
return Lhs.ObjectID != Rhs.ObjectID;
}
FORCEINLINE friend bool operator!=(const TPersistentObjectPtr& Lhs, TYPE_OF_NULLPTR)
{
return Lhs.IsValid();
}
FORCEINLINE friend bool operator!=(TYPE_OF_NULLPTR, const TPersistentObjectPtr& Rhs)
{
return Rhs.IsValid();
}
/**
* Test if this does not point to a live UObject, but may in the future
*
* @return true if this does not point to a real object, but could possibly
*/
FORCEINLINE bool IsPending() const
{
return Get() == nullptr && ObjectID.IsValid();
}
/**
* Test if this points to a live UObject
*
* @return true if Get() would return a valid non-null pointer
*/
FORCEINLINE bool IsValid() const
{
return !!Get();
}
/**
* Slightly different than !IsValid(), returns true if this used to point to a UObject, but doesn't any more and has not been assigned or reset in the mean time.
*
* @return true if this used to point at a real object but no longer does.
*/
FORCEINLINE bool IsStale() const
{
return WeakPtr.IsStale();
}
/**
* Test if this can never point to a live UObject
*
* @return true if this is explicitly pointing to no object
*/
FORCEINLINE bool IsNull() const
{
return !ObjectID.IsValid();
}
/** Hash function */
FORCEINLINE friend uint32 GetTypeHash(const TPersistentObjectPtr& Ptr)
{
return GetTypeHash(Ptr.ObjectID);
}
private:
/** Once the object has been noticed to be loaded, this is set to the object weak pointer **/
mutable FWeakObjectPtr WeakPtr;
/** Compared to CurrentAnnotationTag and if they are not equal, a guid search will be performed **/
mutable int32 TagAtLastTest;
/** Guid for the object this pointer points to or will point to. **/
TObjectID ObjectID;
};
template <class TObjectID>
struct TIsPODType<TPersistentObjectPtr<TObjectID>>
{
enum
{
Value = TIsPODType<TObjectID>::Value
};
};
template <class TObjectID>
struct TIsWeakPointerType<TPersistentObjectPtr<TObjectID>>
{
enum
{
Value = TIsWeakPointerType<FWeakObjectPtr>::Value
};
};