EM_Task/CoreUObject/Public/UObject/LazyObjectPtr.h
Boshuang Zhao 5144a49c9b add
2026-02-13 16:18:33 +08:00

410 lines
12 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
/*=============================================================================
LazyObjectPtr.h: Lazy, guid-based weak pointer to a UObject, mostly useful for actors
=============================================================================*/
#pragma once
#include "CoreMinimal.h"
#include "HAL/ThreadSafeCounter.h"
#include "UObject/Object.h"
#include "Misc/Guid.h"
#include "Templates/Casts.h"
#include "UObject/PersistentObjectPtr.h"
/**
* Wrapper structure for a GUID that uniquely identifies a UObject
*/
struct COREUOBJECT_API FUniqueObjectGuid
{
FUniqueObjectGuid()
{}
FUniqueObjectGuid(const FGuid& InGuid)
: Guid(InGuid)
{}
/** Reset the guid pointer back to the invalid state */
FORCEINLINE void Reset()
{
Guid.Invalidate();
}
/** Construct from an existing object */
explicit FUniqueObjectGuid(const class UObject* InObject);
/** Converts into a string */
FString ToString() const;
/** Converts from a string */
void FromString(const FString& From);
/** Fixes up this UniqueObjectID to add or remove the PIE prefix depending on what is currently active */
FUniqueObjectGuid FixupForPIE(int32 PlayInEditorID = GPlayInEditorID) const;
/**
* Attempts to find a currently loaded object that matches this object ID
*
* @return Found UObject, or nullptr if not currently loaded
*/
class UObject* ResolveObject() const;
/** Test if this can ever point to a live UObject */
FORCEINLINE bool IsValid() const
{
return Guid.IsValid();
}
FORCEINLINE bool operator==(const FUniqueObjectGuid& Other) const
{
return Guid == Other.Guid;
}
FORCEINLINE bool operator!=(const FUniqueObjectGuid& Other) const
{
return Guid != Other.Guid;
}
/** Returns true is this is the default value */
FORCEINLINE bool IsDefault() const
{
// A default GUID is 0,0,0,0 and this is "invalid"
return !IsValid();
}
FORCEINLINE friend uint32 GetTypeHash(const FUniqueObjectGuid& ObjectGuid)
{
return GetTypeHash(ObjectGuid.Guid);
}
/** Returns wrapped Guid */
FORCEINLINE const FGuid& GetGuid() const
{
return Guid;
}
friend FArchive& operator<<(FArchive& Ar, FUniqueObjectGuid& ObjectGuid)
{
Ar << ObjectGuid.Guid;
return Ar;
}
friend void operator<<(FStructuredArchive::FSlot Slot, FUniqueObjectGuid& ObjectGuid)
{
Slot << ObjectGuid.Guid;
}
/** Code needed by FLazyPtr internals */
static int32 GetCurrentTag()
{
return CurrentAnnotationTag.GetValue();
}
static int32 InvalidateTag()
{
return CurrentAnnotationTag.Increment();
}
static FUniqueObjectGuid GetOrCreateIDForObject(const class UObject* Object);
private:
/** Guid representing the object, should be unique */
FGuid Guid;
/** Global counter that determines when we need to re-search for GUIDs because more objects have been loaded **/
static FThreadSafeCounter CurrentAnnotationTag;
};
template <>
struct TIsPODType<FUniqueObjectGuid>
{
enum
{
Value = true
};
};
/**
* FLazyObjectPtr is a type of weak pointer to a UObject that uses a GUID created at save time.
* It will change back and forth between being valid or pending as the referenced object loads or unloads.
* It has no impact on if the object is garbage collected or not.
* It can't be directly used across a network.
*
* This is useful for cross level references or places where you need to point to an object whose name changes often.
*/
struct FLazyObjectPtr: public TPersistentObjectPtr<FUniqueObjectGuid>
{
public:
/** Default constructor, sets to null */
FORCEINLINE FLazyObjectPtr()
{
}
/** Construct from object already in memory */
explicit FORCEINLINE FLazyObjectPtr(const UObject* Object)
{
(*this) = Object;
}
/** Copy from an object already in memory */
FORCEINLINE void operator=(const UObject* Object)
{
TPersistentObjectPtr<FUniqueObjectGuid>::operator=(Object);
}
/** Copy from a unique object identifier */
FORCEINLINE void operator=(const FUniqueObjectGuid& InObjectID)
{
TPersistentObjectPtr<FUniqueObjectGuid>::operator=(InObjectID);
}
/** Called by UObject::Serialize so that we can save / load the Guid possibly associated with an object */
COREUOBJECT_API static void PossiblySerializeObjectGuid(UObject* Object, FStructuredArchive::FRecord Record);
/** Called when entering PIE to prepare it for PIE-specific fixups */
COREUOBJECT_API static void ResetPIEFixups();
};
template <>
struct TIsPODType<FLazyObjectPtr>
{
enum
{
Value = TIsPODType<TPersistentObjectPtr<FUniqueObjectGuid>>::Value
};
};
template <>
struct TIsWeakPointerType<FLazyObjectPtr>
{
enum
{
Value = TIsWeakPointerType<TPersistentObjectPtr<FUniqueObjectGuid>>::Value
};
};
/**
* TLazyObjectPtr is templatized version of the generic FLazyObjectPtr
*/
template <class T = UObject>
struct TLazyObjectPtr: private FLazyObjectPtr
{
public:
TLazyObjectPtr() = default;
TLazyObjectPtr(TLazyObjectPtr<T>&&) = default;
TLazyObjectPtr(const TLazyObjectPtr<T>&) = default;
TLazyObjectPtr<T>& operator=(TLazyObjectPtr<T>&&) = default;
TLazyObjectPtr<T>& operator=(const TLazyObjectPtr<T>&) = default;
/** Construct from another lazy pointer with implicit upcasting allowed */
template <typename U, typename = decltype(ImplicitConv<T*>((U*)nullptr))>
FORCEINLINE TLazyObjectPtr(const TLazyObjectPtr<U>& Other): FLazyObjectPtr((const FLazyObjectPtr&)Other)
{
}
/** Assign from another lazy pointer with implicit upcasting allowed */
template <typename U, typename = decltype(ImplicitConv<T*>((U*)nullptr))>
FORCEINLINE TLazyObjectPtr<T>& operator=(const TLazyObjectPtr<U>& Other)
{
FLazyObjectPtr::operator=((const FLazyObjectPtr&)Other);
return *this;
}
/** Construct from an object pointer */
FORCEINLINE TLazyObjectPtr(T* Object)
{
FLazyObjectPtr::operator=(Object);
}
/** Reset the lazy pointer back to the null state */
FORCEINLINE void Reset()
{
FLazyObjectPtr::Reset();
}
/** Copy from an object pointer */
FORCEINLINE void operator=(T* Object)
{
FLazyObjectPtr::operator=(Object);
}
/**
* Copy from a unique object identifier
* WARNING: this doesn't check the type of the object is correct,
* because the object corresponding to this ID may not even be loaded!
*
* @param ObjectID Object identifier to create a lazy pointer to
*/
FORCEINLINE void operator=(const FUniqueObjectGuid& InObjectID)
{
FLazyObjectPtr::operator=(InObjectID);
}
/**
* 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 FUniqueObjectID if this pointer isn't set to anything
*/
FORCEINLINE const FUniqueObjectGuid& GetUniqueID() const
{
return FLazyObjectPtr::GetUniqueID();
}
/**
* Dereference the lazy pointer.
*
* @return nullptr if this object is gone or the lazy pointer was null, otherwise a valid UObject pointer
*/
FORCEINLINE T* Get() const
{
// there are cases where a TLazyObjectPtr can get an object of the wrong type assigned to it which are difficult to avoid
// e.g. operator=(const FUniqueObjectGuid& ObjectID)
// "WARNING: this doesn't check the type of the object is correct..."
return dynamic_cast<T*>(FLazyObjectPtr::Get());
}
/** Dereference the lazy pointer */
FORCEINLINE T& operator*() const
{
return *Get();
}
/** Dereference the lazy pointer */
FORCEINLINE T* operator->() const
{
return Get();
}
/** Test if this points to a live UObject */
FORCEINLINE bool IsValid() const
{
return FLazyObjectPtr::IsValid();
}
/**
* 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 FLazyObjectPtr::IsStale();
}
/**
* 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 FLazyObjectPtr::IsPending();
}
/**
* 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 FLazyObjectPtr::IsNull();
}
/** Dereference lazy pointer to see if it points somewhere valid */
FORCEINLINE explicit operator bool() const
{
return IsValid();
}
/** Hash function. */
FORCEINLINE friend uint32 GetTypeHash(const TLazyObjectPtr<T>& LazyObjectPtr)
{
return GetTypeHash(static_cast<const FLazyObjectPtr&>(LazyObjectPtr));
}
friend FArchive& operator<<(FArchive& Ar, TLazyObjectPtr<T>& LazyObjectPtr)
{
Ar << static_cast<FLazyObjectPtr&>(LazyObjectPtr);
return Ar;
}
};
// The reason these aren't inside the class (above) is because Visual Studio 2012-2013 crashes when compiling them :D
/** Compare with another TLazyObjectPtr of related type */
template <typename T, typename U, typename = decltype((T*)nullptr == (U*)nullptr)>
FORCEINLINE bool operator==(const TLazyObjectPtr<T>& Lhs, const TLazyObjectPtr<U>& Rhs)
{
return (const FLazyObjectPtr&)Lhs == (const FLazyObjectPtr&)Rhs;
}
template <typename T, typename U, typename = decltype((T*)nullptr != (U*)nullptr)>
FORCEINLINE bool operator!=(const TLazyObjectPtr<T>& Lhs, const TLazyObjectPtr<U>& Rhs)
{
return (const FLazyObjectPtr&)Lhs != (const FLazyObjectPtr&)Rhs;
}
/** Compare for equality with a raw pointer **/
template <typename T, typename U, typename = decltype((T*)nullptr == (U*)nullptr)>
FORCEINLINE bool operator==(const TLazyObjectPtr<T>& Lhs, const U* Rhs)
{
return Lhs.Get() == Rhs;
}
template <typename T, typename U, typename = decltype((T*)nullptr == (U*)nullptr)>
FORCEINLINE bool operator==(const U* Lhs, const TLazyObjectPtr<T>& Rhs)
{
return Lhs == Rhs.Get();
}
/** Compare to null */
template <typename T>
FORCEINLINE bool operator==(const TLazyObjectPtr<T>& Lhs, TYPE_OF_NULLPTR)
{
return !Lhs.IsValid();
}
template <typename T>
FORCEINLINE bool operator==(TYPE_OF_NULLPTR, const TLazyObjectPtr<T>& Rhs)
{
return !Rhs.IsValid();
}
/** Compare for inequality with a raw pointer **/
template <typename T, typename U, typename = decltype((T*)nullptr != (U*)nullptr)>
FORCEINLINE bool operator!=(const TLazyObjectPtr<T>& Lhs, const U* Rhs)
{
return Lhs.Get() != Rhs;
}
template <typename T, typename U, typename = decltype((T*)nullptr != (U*)nullptr)>
FORCEINLINE bool operator!=(const U* Lhs, const TLazyObjectPtr<T>& Rhs)
{
return Lhs != Rhs.Get();
}
/** Compare for inequality with null **/
template <typename T>
FORCEINLINE bool operator!=(const TLazyObjectPtr<T>& Lhs, TYPE_OF_NULLPTR)
{
return Lhs.IsValid();
}
template <typename T>
FORCEINLINE bool operator!=(TYPE_OF_NULLPTR, const TLazyObjectPtr<T>& Rhs)
{
return Rhs.IsValid();
}
template <class T>
struct TIsPODType<TLazyObjectPtr<T>>
{
enum
{
Value = TIsPODType<FLazyObjectPtr>::Value
};
};
template <class T>
struct TIsWeakPointerType<TLazyObjectPtr<T>>
{
enum
{
Value = TIsWeakPointerType<FLazyObjectPtr>::Value
};
};