You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
#lockdown Nick.Penwarden ========================== MAJOR FEATURES + CHANGES ========================== Change 2716841 on 2015/10/05 by Mike.Beach (WIP) Cleaning up how we setup script assets for replacement on cook (aligning more with the Blueprint conversion tool). #codereview Maciej.Mroz Change 2719089 on 2015/10/07 by Maciej.Mroz ToValidCPPIdentifierChars handles propertly '?' char. #codereview Dan.Oconnor Change 2719361 on 2015/10/07 by Maciej.Mroz Generated native code for AnimBPGC - some preliminary changes. Refactor: UAnimBlueprintGeneratedClass is not accessed directly in runtime. It is accessed via UAnimClassInterface interface. Properties USkeletalMeshComponent::AnimBlueprintGeneratedClass and UInterpTrackFloatAnimBPParam::AnimBlueprintClass were changed into "TSubclassOf<UAnimInstance> AnimClass" The UDynamicClass also can deliver the IAnimClassInterface interface. See UAnimClassData, IAnimClassInterface::GetFromClass and UDynamicClass::AnimClassImplementation. #codereview Lina.Halper, Thomas.Sarkanen Change 2719383 on 2015/10/07 by Maciej.Mroz Debug-only code removed Change 2720528 on 2015/10/07 by Dan.Oconnor Fix for determinsitc cooking of async tasks and load asset nodes #codereview Mike.Beach, Maciej.Mroz Change 2721273 on 2015/10/08 by Maciej.Mroz Blueprint Compiler Cpp Backend - Anim Blueprints can be converted - Various fixes/improvements Change 2721310 on 2015/10/08 by Maciej.Mroz refactor (cl#2719361) - no "auto" keyword Change 2721727 on 2015/10/08 by Mike.Beach (WIP) Setup the cook commandlet so it handles converted assets, replacing them with generated classes. - Refactored the conversion manifest (using a map over an array) - Centralized destination paths into a helper struct (for the manifest) - Generating an Editor module that automatically hooks into the cook process when enabled - Loading and applying native replacments for the cook Change 2723276 on 2015/10/09 by Michael.Schoell Blueprints duplicated for PIE will no longer register as dependencies to other Blueprint. #jira UE-16695 - Editor freezes then crashes while attempting to save during PIE #jira UE-21614 - [CrashReport] Crash while saving during PIE - FKismetEditorUtilities::CompileBlueprint() kismet2.cpp:736 Change 2724345 on 2015/10/11 by Ben.Cosh Blueprint profiler at first pass, this includes the ability to instrument specific blueprints with realtime editor stat display. #UEBP-21 - Profiling data capture and storage #UEBP-13 - Performance capture landing page #Branch UE4 #Proj BlueprintProfiler, BlueprintGraph, EditorStyle, Kismet, UnrealEd, CoreUObject, Engine Change 2724613 on 2015/10/12 by Ben.Cosh Incremental update for blueprint profiler to fix the way some of the reported stats cascade through events and branches and additionally some missed bits of code are refactored/removed. #Branch UE4 #Proj BlueprintProfiler #info Whilst looking into this I spotted the reason why the stats seem so erratic, There appears to be an issue with FText's use of EXPERIMENTAL_TEXT_FAST_DECIMAL_FORMAT which I have reported, but ideally disable this locally until a fix is integrated. Change 2724723 on 2015/10/12 by Maciej.Mroz Constructor of a dynamic class creates CDO. #codereview Robert.Manuszewski Change 2725108 on 2015/10/12 by Mike.Beach [UE-21891] Minor fix to the array shuffle() function; now processes the last entry like all the others. Change 2726358 on 2015/10/13 by Maciej.Mroz UDataTable is properly saved even if its RowStruct is null. https://udn.unrealengine.com/questions/264064/crash-using-hotreload-in-custom-datatable-cdo-clas.html Change 2727395 on 2015/10/13 by Mike.Beach (WIP) Second pass on the Blueprint conversion pipeline; setting it up for more optimal (speedier) performance. * Using stubs for replacements (rather than loading dynamic replacement). * Giving the cook commandlet more control (so a conversion could be ran directly). * Now logging replacements by old object path (to account for UPackage replacement queries). * Fix for [UE-21947], unshelved from CL 2724944 (by Maciej.Mroz). #codereview Maciej.Mroz Change 2727484 on 2015/10/13 by Mike.Beach [UE-22008] Fixing up comment/tooltip typo for UActorComponent::bAutoActivate. Change 2727527 on 2015/10/13 by Mike.Beach Downgrading an inactionable EdGraph warning, while adding more info so we could possibly determine what's happening. Change 2727702 on 2015/10/13 by Dan.Oconnor Fix for crash in UDelegateProperty::GetCPPType when called on a function with no OwnerClass (events) Change 2727968 on 2015/10/14 by Maciej.Mroz Since ConstructorHelpers::FClassFinder is usually static, the loaded class should be in root set, to prevent the pointer stored in ConstructorHelpers::FClassFinder from being obsolete. FindOrLoadClass behaves now like FindOrLoadObject. #codereview Robert.Manuszewski, Nick.Whiting Change 2728139 on 2015/10/14 by Phillip.Kavan
455 lines
13 KiB
C++
455 lines
13 KiB
C++
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "BlueprintCompilerCppBackendModulePrivatePCH.h"
|
|
|
|
class FArchiveSkipTransientObjectCRC32 : public FArchiveObjectCrc32
|
|
{
|
|
// Begin FArchive Interface
|
|
virtual bool ShouldSkipProperty(const UProperty* InProperty) const override
|
|
{
|
|
return FArchiveObjectCrc32::ShouldSkipProperty(InProperty)
|
|
|| InProperty->HasAllPropertyFlags(CPF_Transient)
|
|
|| InProperty->HasAllPropertyFlags(CPF_EditorOnly)
|
|
|| InProperty->GetName() == TEXT("BlueprintCreatedComponents")
|
|
|| InProperty->GetName() == TEXT("CreationMethod")
|
|
|| InProperty->GetName() == TEXT("InstanceComponents")
|
|
|| InProperty->GetName() == TEXT("bNetAddressable")
|
|
|| InProperty->GetName() == TEXT("OwnedComponents");
|
|
}
|
|
// End FArchive Interface
|
|
};
|
|
|
|
void ClearNativeRecursive(UObject* OnObject)
|
|
{
|
|
OnObject->ClearInternalFlags(EInternalObjectFlags::Native);
|
|
TArray<UObject*> Children;
|
|
GetObjectsWithOuter(OnObject, Children, false);
|
|
for (auto Entry : Children)
|
|
{
|
|
ClearNativeRecursive(Entry);
|
|
}
|
|
}
|
|
|
|
// We mess with the rootset flag instead of using FGCObject because it's an error for any test data to remain in the rootset after the test runs
|
|
struct FOwnedObjectsHelper
|
|
{
|
|
~FOwnedObjectsHelper()
|
|
{
|
|
for (auto Entry : OwnedObjects)
|
|
{
|
|
Entry->RemoveFromRoot();
|
|
Entry->ClearFlags(RF_Standalone);
|
|
if (Entry->IsNative())
|
|
{
|
|
ClearNativeRecursive(Entry);
|
|
}
|
|
|
|
// Actors need to be explicitly destroyed, probably just to remove them from their owning
|
|
// level:
|
|
if (AActor* AsActor = Cast<AActor>(Entry))
|
|
{
|
|
AsActor->Destroy();
|
|
}
|
|
}
|
|
CollectGarbage(RF_NoFlags);
|
|
}
|
|
|
|
void Push(UObject* Obj)
|
|
{
|
|
Obj->AddToRoot();
|
|
OwnedObjects.Push(Obj);
|
|
}
|
|
private:
|
|
TArray<UObject*> OwnedObjects;
|
|
};
|
|
|
|
// Helper functions introduced to load classes (generated or native:
|
|
static UClass* GetGeneratedClass(const TCHAR* TestFolder, const TCHAR* ClassName, FAutomationTestBase* Context, FOwnedObjectsHelper &OwnedObjects)
|
|
{
|
|
FString FullName = FString::Printf(TEXT("/Engine/NotForLicensees/Automation/CompilerTests/%s/%s.%s"), TestFolder, ClassName, ClassName);
|
|
UBlueprint* Blueprint = LoadObject<UBlueprint>(NULL, *FullName);
|
|
|
|
if (!Blueprint)
|
|
{
|
|
Context->AddWarning(FString::Printf(TEXT("Missing blueprint for test: '%s'"), *FullName));
|
|
return nullptr;
|
|
}
|
|
|
|
TArray<UObject*> Objects;
|
|
GetObjectsWithOuter(Blueprint->GetOuter(), Objects, false);
|
|
for (auto Entry : Objects)
|
|
{
|
|
OwnedObjects.Push(Entry);
|
|
}
|
|
|
|
CollectGarbage(RF_NoFlags);
|
|
|
|
return Blueprint->GeneratedClass;
|
|
}
|
|
|
|
static UClass* GetNativeClass(const TCHAR* TestFolder, const TCHAR* ClassName, FAutomationTestBase* Context, FOwnedObjectsHelper &OwnedObjects)
|
|
{
|
|
FString FullName = FString::Printf(TEXT("/Game/Blueprints/CompilerTests/%s/%s"), TestFolder, ClassName);
|
|
UPackage* NativePackage = CreatePackage(NULL, *FullName);
|
|
check(NativePackage);
|
|
|
|
CollectGarbage(RF_NoFlags);
|
|
const FString FStringFullPathName = FString::Printf(TEXT("%s.%s_C"), *FullName, ClassName);
|
|
UClass* Ret = (UClass*)ConstructDynamicType(*FStringFullPathName); //FindObjectFast<UClass>(NativePackage, *(FString(ClassName) + TEXT("_C")));
|
|
|
|
if (!Ret)
|
|
{
|
|
Context->AddWarning(FString::Printf(TEXT("Missing native type for test: '%s'"), ClassName));
|
|
return nullptr;
|
|
}
|
|
|
|
TArray<UObject*> Objects;
|
|
GetObjectsWithOuter(NativePackage, Objects, false);
|
|
for (auto Entry : Objects)
|
|
{
|
|
OwnedObjects.Push(Entry);
|
|
}
|
|
|
|
CollectGarbage(RF_NoFlags);
|
|
|
|
return Ret;
|
|
}
|
|
|
|
typedef UClass* (*ClassAccessor)(const TCHAR*, const TCHAR*, FAutomationTestBase*, FOwnedObjectsHelper&);
|
|
|
|
typedef uint32(*TestImpl)(ClassAccessor F, FAutomationTestBase* Context);
|
|
|
|
// This pattern is repeated in each test, so I'm just writing a helper function rather than copy/pasting it:
|
|
static bool RunTestHelper(TestImpl T, FAutomationTestBase* Context)
|
|
{
|
|
uint32 ResultsGenerated = T(&GetGeneratedClass, Context);
|
|
uint32 ResultsNative = T(&GetNativeClass, Context);
|
|
|
|
if (ResultsGenerated == 0)
|
|
{
|
|
Context->AddError(TEXT("Test failed to run!"));
|
|
}
|
|
else if (ResultsGenerated != ResultsNative)
|
|
{
|
|
Context->AddError(TEXT("Native differs from generated!"));
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// Helper functions introduced to avoid crashing if classes are missing:
|
|
static UObject* NewTestObject(UClass* Class, FOwnedObjectsHelper &OwnedObjects)
|
|
{
|
|
if (Class)
|
|
{
|
|
UObject* Result = NewObject<UObject>(GetTransientPackage(), Class, NAME_None);
|
|
if (Result)
|
|
{
|
|
OwnedObjects.Push(Result);
|
|
}
|
|
return Result;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
static UObject* NewTestActor(UClass* ActorClass, FOwnedObjectsHelper &OwnedObjects)
|
|
{
|
|
if (ActorClass)
|
|
{
|
|
AActor* Actor = GWorld->SpawnActor(ActorClass);
|
|
#if WITH_EDITORONLY_DATA
|
|
if (Actor)
|
|
{
|
|
OwnedObjects.Push(Actor);
|
|
Actor->GetRootComponent()->bVisualizeComponent = true;
|
|
}
|
|
#endif
|
|
return Actor;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
static void Call(UObject* Target, const TCHAR* FunctionName, void* Args = nullptr)
|
|
{
|
|
if (!Target)
|
|
{
|
|
return;
|
|
}
|
|
UFunction* Fn = Target->FindFunction(FunctionName);
|
|
if (Fn)
|
|
{
|
|
Target->ProcessEvent(Fn, Args);
|
|
}
|
|
}
|
|
|
|
// Remove EAutomationTestFlags::Disabled to enable these tests, note that these will need to be moved into the ClientContext because we can only test cooked content:
|
|
static const uint32 CompilerTestFlags = EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter;
|
|
|
|
// Tests:
|
|
IMPLEMENT_SIMPLE_AUTOMATION_TEST(FBPCompilerArrayTest, "Project.Blueprints.NativeBackend.ArrayTest", CompilerTestFlags)
|
|
bool FBPCompilerArrayTest::RunTest(const FString& Parameters)
|
|
{
|
|
auto TestBody = [](ClassAccessor F, FAutomationTestBase* Context)
|
|
{
|
|
FOwnedObjectsHelper OwnedObjects;
|
|
|
|
TArray<FString> Input;
|
|
Input.Push(TEXT("addedString"));
|
|
|
|
UObject* TestInstance = NewTestObject(F(TEXT("Array"), TEXT("BP_Array_Basic"), Context, OwnedObjects), OwnedObjects);
|
|
if (!TestInstance)
|
|
{
|
|
return 0u;
|
|
}
|
|
|
|
Call(TestInstance, TEXT("RunArrayTest"), &Input);
|
|
|
|
FArchiveSkipTransientObjectCRC32 Results;
|
|
return Results.Crc32(TestInstance);
|
|
};
|
|
|
|
return RunTestHelper(TestBody, this);
|
|
}
|
|
|
|
IMPLEMENT_SIMPLE_AUTOMATION_TEST(FBPCompilerCDOTest, "Project.Blueprints.NativeBackend.CDOTest", CompilerTestFlags)
|
|
bool FBPCompilerCDOTest::RunTest(const FString& Parameters)
|
|
{
|
|
auto TestBody = [](ClassAccessor F, FAutomationTestBase* Context)
|
|
{
|
|
FOwnedObjectsHelper OwnedObjects;
|
|
|
|
UObject* TestInstance = NewTestObject(F(TEXT("CDO"), TEXT("BP_CDO_Basic"), Context, OwnedObjects), OwnedObjects);
|
|
if (!TestInstance)
|
|
{
|
|
return 0u;
|
|
}
|
|
|
|
FArchiveSkipTransientObjectCRC32 Results;
|
|
return Results.Crc32(TestInstance->GetClass()->ClassDefaultObject);
|
|
};
|
|
|
|
return RunTestHelper(TestBody, this);
|
|
}
|
|
|
|
IMPLEMENT_SIMPLE_AUTOMATION_TEST(FBPCompilerCommunicationTest, "Project.Blueprints.NativeBackend.CommunicationTest", CompilerTestFlags)
|
|
bool FBPCompilerCommunicationTest::RunTest(const FString& Parameters)
|
|
{
|
|
auto TestBody = [](ClassAccessor F, FAutomationTestBase* Context)
|
|
{
|
|
FOwnedObjectsHelper OwnedObjects;
|
|
|
|
UObject* A = NewTestObject(F(TEXT("Communication"), TEXT("BP_Comm_Test_A"), Context, OwnedObjects), OwnedObjects);
|
|
UObject* B = NewTestObject(F(TEXT("Communication"), TEXT("BP_Comm_Test_B"), Context, OwnedObjects), OwnedObjects);
|
|
if (!A || !B)
|
|
{
|
|
return 0u;
|
|
}
|
|
|
|
Call(A, TEXT("Flop"));
|
|
Call(B, TEXT("Flip"));
|
|
|
|
FArchiveSkipTransientObjectCRC32 Results;
|
|
return Results.Crc32(B, Results.Crc32(A));
|
|
};
|
|
|
|
return RunTestHelper(TestBody, this);
|
|
}
|
|
|
|
IMPLEMENT_SIMPLE_AUTOMATION_TEST(FBPCompilerConstructionScriptTest, "Project.Blueprints.NativeBackend.ConstructionScriptTest", CompilerTestFlags)
|
|
bool FBPCompilerConstructionScriptTest::RunTest(const FString& Parameters)
|
|
{
|
|
auto TestBody = [](ClassAccessor F, FAutomationTestBase* Context)
|
|
{
|
|
FOwnedObjectsHelper OwnedObjects;
|
|
|
|
UObject* TestInstance = NewTestActor(F(TEXT("ConstructionScript"), TEXT("BP_ConstructionScript_Test"), Context, OwnedObjects), OwnedObjects);
|
|
if (!TestInstance)
|
|
{
|
|
return 0u;
|
|
}
|
|
|
|
FArchiveSkipTransientObjectCRC32 Results;
|
|
return Results.Crc32(TestInstance);
|
|
};
|
|
|
|
return RunTestHelper(TestBody, this);
|
|
}
|
|
|
|
IMPLEMENT_SIMPLE_AUTOMATION_TEST(FBPCompilerControlFlowTest, "Project.Blueprints.NativeBackend.ControlFlow", CompilerTestFlags)
|
|
bool FBPCompilerControlFlowTest::RunTest(const FString& Parameters)
|
|
{
|
|
auto TestBody = [](ClassAccessor F, FAutomationTestBase* Context)
|
|
{
|
|
FOwnedObjectsHelper OwnedObjects;
|
|
|
|
UObject* TestInstance = NewTestObject(F(TEXT("ControlFlow"), TEXT("BP_ControlFlow_Basic"), Context, OwnedObjects), OwnedObjects);
|
|
if (!TestInstance)
|
|
{
|
|
return 0u;
|
|
}
|
|
|
|
Call(TestInstance, TEXT("RunControlFlowTest"));
|
|
|
|
FArchiveSkipTransientObjectCRC32 Results;
|
|
return Results.Crc32(TestInstance);
|
|
};
|
|
|
|
return RunTestHelper(TestBody, this);
|
|
}
|
|
|
|
IMPLEMENT_SIMPLE_AUTOMATION_TEST(FBPCompilerEnumTest, "Project.Blueprints.NativeBackend.EnumTest", CompilerTestFlags)
|
|
bool FBPCompilerEnumTest::RunTest(const FString& Parameters)
|
|
{
|
|
auto TestBody = [](ClassAccessor F, FAutomationTestBase* Context)
|
|
{
|
|
FOwnedObjectsHelper OwnedObjects;
|
|
|
|
UObject* TestInstance = NewTestObject(F(TEXT("Enum"), TEXT("BP_Enum_Reader_Writer"), Context, OwnedObjects), OwnedObjects);
|
|
if (!TestInstance)
|
|
{
|
|
return 0u;
|
|
}
|
|
|
|
Call(TestInstance, TEXT("UpdateEnum"));
|
|
|
|
FArchiveSkipTransientObjectCRC32 Results;
|
|
return Results.Crc32(TestInstance);
|
|
};
|
|
|
|
return RunTestHelper(TestBody, this);
|
|
}
|
|
|
|
IMPLEMENT_SIMPLE_AUTOMATION_TEST(FBPCompilerEventTest, "Project.Blueprints.NativeBackend.Event", CompilerTestFlags)
|
|
bool FBPCompilerEventTest::RunTest(const FString& Parameters)
|
|
{
|
|
auto TestBody = [](ClassAccessor F, FAutomationTestBase* Context)
|
|
{
|
|
FOwnedObjectsHelper OwnedObjects;
|
|
|
|
UObject* TestInstance = NewTestObject(F(TEXT("Event"), TEXT("BP_Event_Basic"), Context, OwnedObjects), OwnedObjects);
|
|
if (!TestInstance)
|
|
{
|
|
return 0u;
|
|
}
|
|
|
|
Call(TestInstance, TEXT("BeginEventChain"));
|
|
|
|
FArchiveSkipTransientObjectCRC32 Results;
|
|
return Results.Crc32(TestInstance);
|
|
};
|
|
|
|
return RunTestHelper(TestBody, this);
|
|
}
|
|
|
|
struct FInheritenceTestParams
|
|
{
|
|
bool bFlag;
|
|
TArray<FString> Strings;
|
|
TArray<int32> Result;
|
|
};
|
|
|
|
inline bool operator==(const FInheritenceTestParams& LHS, const FInheritenceTestParams& RHS)
|
|
{
|
|
return
|
|
LHS.bFlag == RHS.bFlag &&
|
|
LHS.Strings == RHS.Strings &&
|
|
LHS.Result == RHS.Result;
|
|
}
|
|
|
|
inline bool operator!=(const FInheritenceTestParams& LHS, const FInheritenceTestParams& RHS)
|
|
{
|
|
return !(LHS == RHS);
|
|
}
|
|
|
|
IMPLEMENT_SIMPLE_AUTOMATION_TEST(FBPCompilerInheritenceTest, "Project.Blueprints.NativeBackend.Inheritence", CompilerTestFlags)
|
|
bool FBPCompilerInheritenceTest::RunTest(const FString& Parameters)
|
|
{
|
|
auto TestBody = [](ClassAccessor F, FAutomationTestBase* Context)
|
|
{
|
|
FOwnedObjectsHelper OwnedObjects;
|
|
|
|
UObject* TestInstance = NewTestObject(F(TEXT("Inheritence"), TEXT("BP_Child_Basic"), Context, OwnedObjects), OwnedObjects);
|
|
if (!TestInstance)
|
|
{
|
|
return 0u;
|
|
}
|
|
|
|
FInheritenceTestParams Params;
|
|
Params.bFlag = true;
|
|
Call(TestInstance, TEXT("VirtualFunction"), &Params);
|
|
|
|
FArchiveSkipTransientObjectCRC32 Results;
|
|
return Results.Crc32(TestInstance);
|
|
};
|
|
|
|
return RunTestHelper(TestBody, this);
|
|
}
|
|
|
|
IMPLEMENT_SIMPLE_AUTOMATION_TEST(FBPCompilerStructureTest, "Project.Blueprints.NativeBackend.Structure", CompilerTestFlags)
|
|
bool FBPCompilerStructureTest::RunTest(const FString& Parameters)
|
|
{
|
|
auto TestBody = [](ClassAccessor F, FAutomationTestBase* Context)
|
|
{
|
|
FOwnedObjectsHelper OwnedObjects;
|
|
|
|
UObject* TestInstance = NewTestObject(F(TEXT("Structure"), TEXT("BP_Structure_Driver"), Context, OwnedObjects), OwnedObjects);
|
|
if (!TestInstance)
|
|
{
|
|
return 0u;
|
|
}
|
|
|
|
Call(TestInstance, TEXT("RunStructTest"));
|
|
|
|
FArchiveSkipTransientObjectCRC32 Results;
|
|
return Results.Crc32(TestInstance);
|
|
};
|
|
|
|
return RunTestHelper(TestBody, this);
|
|
}
|
|
|
|
IMPLEMENT_SIMPLE_AUTOMATION_TEST(FBPCompilerNodeTest, "Project.Blueprints.NativeBackend.Node", CompilerTestFlags)
|
|
bool FBPCompilerNodeTest::RunTest(const FString& Parameters)
|
|
{
|
|
auto TestBody = [](ClassAccessor F, FAutomationTestBase* Context)
|
|
{
|
|
FOwnedObjectsHelper OwnedObjects;
|
|
|
|
UObject* TestInstance = NewTestObject(F(TEXT("Node"), TEXT("BP_Node_Basic"), Context, OwnedObjects), OwnedObjects);
|
|
if (!TestInstance)
|
|
{
|
|
return 0u;
|
|
}
|
|
|
|
Call(TestInstance, TEXT("RunNodes"));
|
|
|
|
FArchiveSkipTransientObjectCRC32 Results;
|
|
return Results.Crc32(TestInstance);
|
|
};
|
|
|
|
return RunTestHelper(TestBody, this);
|
|
}
|
|
|
|
IMPLEMENT_SIMPLE_AUTOMATION_TEST(FBPCompilerLatentTest, "Project.Blueprints.NativeBackend.Latent", CompilerTestFlags)
|
|
bool FBPCompilerLatentTest::RunTest(const FString& Parameters)
|
|
{
|
|
auto TestBody = [](ClassAccessor F, FAutomationTestBase* Context)
|
|
{
|
|
FOwnedObjectsHelper OwnedObjects;
|
|
TGuardValue<bool> AutoRestore(GAllowActorScriptExecutionInEditor, true);
|
|
|
|
UObject* TestInstance = NewTestActor(F(TEXT("Node"), TEXT("BP_Latent_Basic"), Context, OwnedObjects), OwnedObjects);
|
|
if (!TestInstance)
|
|
{
|
|
return 0u;
|
|
}
|
|
|
|
Call(TestInstance, TEXT("RunDelayTest"));
|
|
Call(TestInstance, TEXT("RunDownloadTest"));
|
|
|
|
FArchiveSkipTransientObjectCRC32 Results;
|
|
return Results.Crc32(TestInstance);
|
|
};
|
|
|
|
return RunTestHelper(TestBody, this);
|
|
}
|