You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
GetTypeHash will create a packaged object ref for hashing if the class is defined as lazy load otherwise raw pointer is hashed a map was added for moved objects and ObjectPathId can be a WeakObjectPtr the map allows UObjects to be mapped back to packed object refs #rb zousar.shaker https://p4-swarm.epicgames.net/reviews/23356491 #preflight 63b5de641c35d1cbdbccecf7 #preflight 63b70406e26e31879b8aa6d3 code cleanup of ObjectHandle made ObjectPathId to private trimmed down the public API as much as possible https://p4-swarm.epicgames.net/reviews/23658342 #rb zousar.shaker #preflight 63c5c8922a6acaf1625fcf25 #[robomerge] FNMain changed ObjectHandleTracking to use Functions instead of delegates as the performance of delegate is poor https://p4-swarm.epicgames.net/reviews/23751084 #rb zousar.shaker #preflight 63c9ae14d45afa2a8fc37d9d changed FObjectPropertyBase::CheckValidObject to not resolve FObjectPtr fields to do validation this is needed for feature work with validation of accessing asset pointers during serialization https://p4-swarm.epicgames.net/reviews/23782822 #rb zousar.shaker #[fyi] francis.hurteau #preflight 63cf06efd83c1837b14e2aeb fix for ObjectHandleTracking initialization. order of global variable initialization was problematic move globals into a struct added a singleton for the struct to do lazy initialization https://p4-swarm.epicgames.net/reviews/23877016 #rb zousar.shaker #preflight 63d308a7f626715201408881 changed `FClassProperty::Identical` to use TObjectPtr to avoid causing unnecessary reads #rb zousar.shaker #preflight 63d804493656ea96dc13d296 changed FObjectProperty::SerializeItem to not cause object handle reads #preflight 63d837e91f0aa8a2897477ee #ushell-cherrypick of 23589497 by joe.pribele #ushell-cherrypick of 23734208 by joe.pribele #ushell-cherrypick of 23781117 by joe.pribele #ushell-cherrypick of 23823212 by joe.pribele #ushell-cherrypick of 23878025 by joe.pribele #ushell-cherrypick of 23912609 by joe.pribele #ushell-cherrypick of 23916733 by joe.pribele [CL 24493715 by joe pribele in ue5-main branch]
285 lines
9.9 KiB
C++
285 lines
9.9 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#if WITH_LOW_LEVEL_TESTS
|
|
|
|
#include "ObjectRefTrackingTestBase.h"
|
|
#include "UObject/Package.h"
|
|
#include "ObjectPtrTestClass.h"
|
|
#include "Misc/ScopeExit.h"
|
|
#include "UObject/ObjectPtr.h"
|
|
|
|
thread_local uint32 FObjectRefTrackingTestBase::NumResolves = 0;
|
|
thread_local uint32 FObjectRefTrackingTestBase::NumFailedResolves = 0;
|
|
thread_local uint32 FObjectRefTrackingTestBase::NumReads = 0;
|
|
|
|
#if UE_WITH_OBJECT_HANDLE_TRACKING
|
|
UE::CoreUObject::FObjectHandleTrackingCallbackId FObjectRefTrackingTestBase::ResolvedCallbackHandle;
|
|
UE::CoreUObject::FObjectHandleTrackingCallbackId FObjectRefTrackingTestBase::HandleReadCallbackHandle;
|
|
|
|
TEST_CASE("UE::CoreUObject::ObjectHandleTracking::Callbacks")
|
|
{
|
|
using namespace UE::CoreUObject;
|
|
using namespace UE::CoreUObject::Private;
|
|
|
|
int32 CallbackCount1 = 0;
|
|
int32 CallbackCount2 = 0;
|
|
int32 CallbackCount3 = 0;
|
|
int32 CallbackCount4 = 0;
|
|
int32 CallbackCount5 = 0;
|
|
int32 CallbackCount6 = 0;
|
|
int32 CallbackCount7 = 0;
|
|
int32 CallbackCount8 = 0;
|
|
|
|
FObjectHandleReadFunc ReadCallback1 = [&](TArrayView<const UObject* const> Objects)
|
|
{
|
|
++CallbackCount1;
|
|
};
|
|
FObjectHandleReadFunc ReadCallback2 = [&](TArrayView<const UObject* const> Objects)
|
|
{
|
|
++CallbackCount2;
|
|
};
|
|
|
|
FObjectHandleClassResolvedFunc ClassResolvedCallback1 = [&](const FObjectRef& SourceRef, UPackage* ObjectPackage, UClass* Class)
|
|
{
|
|
++CallbackCount3;
|
|
};
|
|
FObjectHandleClassResolvedFunc ClassResolvedCallback2 = [&](const FObjectRef& SourceRef, UPackage* ObjectPackage, UClass* Class)
|
|
{
|
|
++CallbackCount4;
|
|
};
|
|
|
|
FObjectHandleReferenceResolvedFunc ReferenceResolvedCallback1 = [&](const FObjectRef& SourceRef, UPackage* ObjectPackage, UObject* Object)
|
|
{
|
|
++CallbackCount5;
|
|
};
|
|
FObjectHandleReferenceResolvedFunc ReferenceResolvedCallback2 = [&](const FObjectRef& SourceRef, UPackage* ObjectPackage, UObject* Object)
|
|
{
|
|
++CallbackCount6;
|
|
};
|
|
|
|
FObjectHandleReferenceLoadedFunc ReferenceLoadedCallback1 = [&](const FObjectRef& SourceRef, UPackage* ObjectPackage, UObject* Object)
|
|
{
|
|
++CallbackCount7;
|
|
};
|
|
FObjectHandleReferenceLoadedFunc ReferenceLoadedCallback2 = [&](const FObjectRef& SourceRef, UPackage* ObjectPackage, UObject* Object)
|
|
{
|
|
++CallbackCount8;
|
|
};
|
|
auto ReadCallbackHandle1 = AddObjectHandleReadCallback(ReadCallback1);
|
|
auto ReadCallbackHandle2 = AddObjectHandleReadCallback(ReadCallback2);
|
|
|
|
auto ClassResolvedHandle1 = AddObjectHandleClassResolvedCallback(ClassResolvedCallback1);
|
|
auto ClassResolvedHandle2 = AddObjectHandleClassResolvedCallback(ClassResolvedCallback2);
|
|
|
|
auto ReferenceResolvedHandle1 = AddObjectHandleReferenceResolvedCallback(ReferenceResolvedCallback1);
|
|
auto ReferenceResolvedHandle2 = AddObjectHandleReferenceResolvedCallback(ReferenceResolvedCallback2);
|
|
|
|
auto ReferenceLoadedHandle1 = AddObjectHandleReferenceLoadedCallback(ReferenceLoadedCallback1);
|
|
auto ReferenceLoadedHandle2 = AddObjectHandleReferenceLoadedCallback(ReferenceLoadedCallback2);
|
|
|
|
auto TestCounts = [&](int32 a, int32 b, int32 c, int32 d, int32 e, int32 f, int32 g, int32 h)
|
|
{
|
|
CHECK(CallbackCount1 == a);
|
|
CHECK(CallbackCount2 == b);
|
|
CHECK(CallbackCount3 == c);
|
|
CHECK(CallbackCount4 == d);
|
|
CHECK(CallbackCount5 == e);
|
|
CHECK(CallbackCount6 == f);
|
|
CHECK(CallbackCount7 == g);
|
|
CHECK(CallbackCount8 == h);
|
|
};
|
|
|
|
UE::CoreUObject::Private::OnHandleRead(nullptr);
|
|
TestCounts(1, 1, 0, 0, 0, 0, 0, 0);
|
|
|
|
//remove the first added read callback to verify they can be remove in any order
|
|
RemoveObjectHandleReadCallback(ReadCallbackHandle1);
|
|
|
|
UE::CoreUObject::Private::OnHandleRead(nullptr);
|
|
TestCounts(1, 2, 0, 0, 0, 0, 0, 0);
|
|
|
|
//add it back
|
|
ReadCallbackHandle1 = AddObjectHandleReadCallback(ReadCallback1);
|
|
UE::CoreUObject::Private::OnHandleRead(nullptr);
|
|
TestCounts(2, 3, 0, 0, 0, 0, 0, 0);
|
|
|
|
//remove it again
|
|
RemoveObjectHandleReadCallback(ReadCallbackHandle1);
|
|
UE::CoreUObject::Private::OnHandleRead(nullptr);
|
|
TestCounts(2, 4, 0, 0, 0, 0, 0, 0);
|
|
|
|
//remove last callback
|
|
RemoveObjectHandleReadCallback(ReadCallbackHandle2);
|
|
UE::CoreUObject::Private::OnHandleRead(nullptr);
|
|
TestCounts(2, 4, 0, 0, 0, 0, 0, 0);
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////
|
|
UE::CoreUObject::Private::OnClassReferenceResolved(FObjectRef(), nullptr, nullptr);
|
|
TestCounts(2, 4, 1, 1, 0, 0, 0, 0);
|
|
|
|
//remove the first added read callback to verify they can be remove in any order
|
|
RemoveObjectHandleClassResolvedCallback(ClassResolvedHandle1);
|
|
|
|
UE::CoreUObject::Private::OnClassReferenceResolved(FObjectRef(), nullptr, nullptr);
|
|
TestCounts(2, 4, 1, 2, 0, 0, 0, 0);
|
|
|
|
//add it back
|
|
ClassResolvedHandle1 = AddObjectHandleClassResolvedCallback(ClassResolvedCallback1);
|
|
UE::CoreUObject::Private::OnClassReferenceResolved(FObjectRef(), nullptr, nullptr);
|
|
TestCounts(2, 4, 2, 3, 0, 0, 0, 0);
|
|
|
|
//remove it again
|
|
RemoveObjectHandleClassResolvedCallback(ClassResolvedHandle1);
|
|
UE::CoreUObject::Private::OnClassReferenceResolved(FObjectRef(), nullptr, nullptr);
|
|
TestCounts(2, 4, 2, 4, 0, 0, 0, 0);
|
|
|
|
//remove last callback
|
|
RemoveObjectHandleClassResolvedCallback(ClassResolvedHandle2);
|
|
UE::CoreUObject::Private::OnClassReferenceResolved(FObjectRef(), nullptr, nullptr);
|
|
TestCounts(2, 4, 2, 4, 0, 0, 0, 0);
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////
|
|
UE::CoreUObject::Private::OnReferenceResolved(FObjectRef(), nullptr, nullptr);
|
|
TestCounts(2, 4, 2, 4, 1, 1, 0, 0);
|
|
|
|
//remove the first added read callback to verify they can be remove in any order
|
|
RemoveObjectHandleReferenceResolvedCallback(ReferenceResolvedHandle1);
|
|
|
|
UE::CoreUObject::Private::OnReferenceResolved(FObjectRef(), nullptr, nullptr);
|
|
TestCounts(2, 4, 2, 4, 1, 2, 0, 0);
|
|
|
|
//add it back
|
|
ReferenceResolvedHandle1 = AddObjectHandleReferenceResolvedCallback(ReferenceResolvedCallback1);
|
|
UE::CoreUObject::Private::OnReferenceResolved(FObjectRef(), nullptr, nullptr);
|
|
TestCounts(2, 4, 2, 4, 2, 3, 0, 0);
|
|
|
|
//remove it again
|
|
RemoveObjectHandleReferenceResolvedCallback(ReferenceResolvedHandle1);
|
|
UE::CoreUObject::Private::OnReferenceResolved(FObjectRef(), nullptr, nullptr);
|
|
TestCounts(2, 4, 2, 4, 2, 4, 0, 0);
|
|
|
|
//remove last callback
|
|
RemoveObjectHandleReferenceResolvedCallback(ReferenceResolvedHandle2);
|
|
UE::CoreUObject::Private::OnReferenceResolved(FObjectRef(), nullptr, nullptr);
|
|
TestCounts(2, 4, 2, 4, 2, 4, 0, 0);
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////
|
|
UE::CoreUObject::Private::OnReferenceLoaded(FObjectRef(), nullptr, nullptr);
|
|
TestCounts(2, 4, 2, 4, 2, 4, 1, 1);
|
|
|
|
//remove the first added read callback to verify they can be remove in any order
|
|
RemoveObjectHandleReferenceLoadedCallback(ReferenceLoadedHandle1);
|
|
|
|
UE::CoreUObject::Private::OnReferenceLoaded(FObjectRef(), nullptr, nullptr);
|
|
TestCounts(2, 4, 2, 4, 2, 4, 1, 2);
|
|
|
|
//add it back
|
|
ReferenceLoadedHandle1 = AddObjectHandleReferenceLoadedCallback(ReferenceLoadedCallback1);
|
|
UE::CoreUObject::Private::OnReferenceLoaded(FObjectRef(), nullptr, nullptr);
|
|
TestCounts(2, 4, 2, 4, 2, 4, 2, 3);
|
|
|
|
//remove it again
|
|
RemoveObjectHandleReferenceLoadedCallback(ReferenceLoadedHandle1);
|
|
UE::CoreUObject::Private::OnReferenceLoaded(FObjectRef(), nullptr, nullptr);
|
|
TestCounts(2, 4, 2, 4, 2, 4, 2, 4);
|
|
|
|
//remove last callback
|
|
RemoveObjectHandleReferenceLoadedCallback(ReferenceLoadedHandle2);
|
|
UE::CoreUObject::Private::OnReferenceLoaded(FObjectRef(), nullptr, nullptr);
|
|
TestCounts(2, 4, 2, 4, 2, 4, 2, 4);
|
|
}
|
|
|
|
TEST_CASE("UE::CoreUObject::ObjectHandleTracking::Callbacks::Verify")
|
|
{
|
|
using namespace UE::CoreUObject;
|
|
using namespace UE::CoreUObject::Private;
|
|
|
|
const FName TestPackageName(TEXT("/Engine/Test/ObjectRef/Transient"));
|
|
UPackage* TestPackage = NewObject<UPackage>(nullptr, TestPackageName, RF_Transient);
|
|
TestPackage->AddToRoot();
|
|
UObject* Obj1 = NewObject<UObjectPtrTestClass>(TestPackage, TEXT("DefaultSerializeObject"));
|
|
ON_SCOPE_EXIT{
|
|
TestPackage->RemoveFromRoot();
|
|
};
|
|
|
|
TObjectPtr<UObject> ObjPtr = Obj1;
|
|
int32 ReadCount = 0;
|
|
auto ReadCallbackHandle1 = AddObjectHandleReadCallback([&](TArrayView<const UObject* const> ReadObject)
|
|
{
|
|
++ReadCount;
|
|
CHECK(Obj1 == ReadObject[0]);
|
|
});
|
|
|
|
CHECK(ObjPtr == Obj1);
|
|
CHECK(ReadCount == 0);
|
|
|
|
CHECK_FALSE(ObjPtr != Obj1);
|
|
CHECK(ReadCount == 0);
|
|
|
|
CHECK_FALSE(ObjPtr == nullptr);
|
|
CHECK(ReadCount == 0);
|
|
|
|
CHECK(ObjPtr != nullptr);
|
|
CHECK(ReadCount == 0);
|
|
|
|
bool bIsNull = !ObjPtr;
|
|
CHECK_FALSE(bIsNull);
|
|
CHECK(ReadCount == 0);
|
|
|
|
if (ObjPtr)
|
|
{
|
|
CHECK(ReadCount == 0);
|
|
}
|
|
|
|
//get fires read event
|
|
CHECK(ObjPtr.Get() != nullptr);
|
|
CHECK(ReadCount == 1);
|
|
FObjectRef ObjectRef(Obj1);
|
|
int32 ClassCount = 0;
|
|
auto ClassResolvedHandle1 = AddObjectHandleClassResolvedCallback([&](const FObjectRef& SourceRef, UPackage* ClassPackage, UClass* Class)
|
|
{
|
|
++ClassCount;
|
|
CHECK(Class == UObjectPtrTestClass::StaticClass());
|
|
CHECK(&ObjectRef == &SourceRef);
|
|
CHECK(UObjectPtrTestClass::StaticClass()->GetPackage() == ClassPackage);
|
|
});
|
|
UClass* Class = ObjectRef.ResolveObjectRefClass();
|
|
CHECK(ClassCount == 1);
|
|
|
|
int32 ResolvedCount = 0;
|
|
auto ReferenceResolvedHandle1 = AddObjectHandleReferenceResolvedCallback([&](const FObjectRef& SourceRef, UPackage* ObjectPackage, UObject* Object)
|
|
{
|
|
++ResolvedCount;
|
|
CHECK(Obj1 == Object);
|
|
CHECK(&ObjectRef == &SourceRef);
|
|
CHECK(TestPackage == ObjectPackage);
|
|
|
|
});
|
|
ObjectRef.Resolve();
|
|
CHECK(ResolvedCount == 1);
|
|
|
|
int32 LoadCount = 0;
|
|
auto ReferenceLoadedHandle1 = AddObjectHandleReferenceLoadedCallback([&](const FObjectRef& SourceRef, UPackage* ObjectPackage, UObject* Object)
|
|
{
|
|
++LoadCount;
|
|
CHECK(Obj1 == Object);
|
|
CHECK(&ObjectRef == &SourceRef);
|
|
CHECK(TestPackage == ObjectPackage);
|
|
});
|
|
|
|
//don't have a good to test this as the object are never loaded from disk in the tests
|
|
OnReferenceLoaded(ObjectRef, TestPackage, Obj1);
|
|
CHECK(LoadCount == 1);
|
|
|
|
ON_SCOPE_EXIT
|
|
{
|
|
RemoveObjectHandleReadCallback(ReadCallbackHandle1);
|
|
RemoveObjectHandleClassResolvedCallback(ClassResolvedHandle1);
|
|
RemoveObjectHandleReferenceResolvedCallback(ReferenceResolvedHandle1);
|
|
RemoveObjectHandleReferenceLoadedCallback(ReferenceLoadedHandle1);
|
|
};
|
|
|
|
}
|
|
#endif
|
|
#endif |