(UE4 4.20) UE4 synchronous loading and asynchronous loading UObject ----------LoadObject, LoadClass, FStreamableManager

(UE4 4.20) UE4 synchronous loading and asynchronous loading UObject ----------LoadObject, LoadClass, FStreamableManager

Resource classification

Here I divide UE4 resources into two types:

Blueprint class resources, namely BlueprintClass, inherit from UObject and blueprinted resources, as shown below:

View Image

 

Non-blueprint resources: UTexture, UStaticMesh, UParticleSystem, UmaterialInterface These resources: such as textures, particles, static meshes, materials, etc., as shown below:

View Image

LoadClass (synchronously load blueprint class resources as UClass*)

The LoadClass function is in UObjectGlobal.h, the source code is

//Load a class object. template< class T > inline UClass* LoadClass( UObject* Outer, const TCHAR* Name, const TCHAR* Filename=nullptr, uint32 LoadFlags=LOAD_None, UPackageMap* Sandbox=nullptr ) { return StaticLoadClass( T::StaticClass(), Outer, Name, Filename, LoadFlags, Sandbox ); }

The second parameter "Name" is the path of the corresponding resource, here is an experiment to load an AActor blueprint class

FString strBPFileName = "/Game/ThirdPersonCPP/Blueprints/TestActor.TestActor_C"; UClass* pClass = LoadClass<AActor>(this, *strBPFileName); if (pClass) { UE_LOG(LogTemp, Error, TEXT("UClass name is %s"), *pClass->GetName()); }

It’s important to note that the blueprint resource name has "_C" added at the end

Print result:

View Image

 

 

LoadObject (synchronously load non-blueprint resources)

The LoadObject function is in UObjectGlobal.h, the source code is

//Load an object. template< class T > inline T* LoadObject( UObject* Outer, const TCHAR* Name, const TCHAR* Filename=nullptr, uint32 LoadFlags=LOAD_None, UPackageMap* Sandbox=nullptr ) { return (T*)StaticLoadObject( T::StaticClass(), Outer, Name, Filename, LoadFlags, Sandbox ); }

The second parameter "Name" is the path of the corresponding resource, here is an experiment to load a StaticMesh resource

FString strMeshFileName = "/Game/Geometry/Meshes/1M_Cube.1M_Cube"; UStaticMesh* pStaticMesh = LoadObject<UStaticMesh>(this, *strBPFileName); if (pStaticMesh) { UE_LOG(LogTemp, Error, TEXT("Static Object name is %s"), *pStaticMesh->GetName()); }

Print result:

View Image

 

FStreamableManager (asynchronous loading and synchronous loading)

FStreamableManager provides two interfaces of RequestSyncLoad (synchronous) and RequestAsyncLoad (asynchronous).

RequestSyncLoad and RequestAsyncLoad are a bit long, so they won't be posted.

TSharedPtr<FStreamableHandle> FStreamableManager::RequestSyncLoad(const TArray<FSoftObjectPath>& TargetsToStream, bool bManageActiveHandle, const FString& DebugName) { //If in async loading thread or from callback always do sync as recursive tick is unsafe //If in EDL always do sync as EDL internally avoids flushing //Otherwise, only do a sync load if there are no background sync loads, this is faster but will cause a sync flush bForceSynchronousLoads = IsInAsyncLoadingThread() || IsEventDrivenLoaderEnabled() || !IsAsyncLoading(); //Do an async load and wait to complete. In some cases this will do a sync load due to safety issues TSharedPtr<FStreamableHandle> Request = RequestAsyncLoad(TargetsToStream, FStreamableDelegate(), AsyncLoadHighPriority, bManageActiveHandle, false, DebugName);

 

TSharedPtr<FStreamableHandle> FStreamableManager::RequestAsyncLoad(const TArray<FSoftObjectPath>& TargetsToStream, FStreamableDelegate DelegateToCall, TAsyncLoadPriority Priority, bool bManageActiveHandle, bool bStartStalled, const FString& DebugName) { //Schedule a new callback, this will get called when all related async loads are completed TSharedRef<FStreamableHandle> NewRequest = MakeShareable(new FStreamableHandle()); NewRequest->CompleteDelegate = DelegateToCall; NewRequest->OwningManager = this; NewRequest->RequestedAssets = TargetsToStream; NewRequest->DebugName = DebugName; NewRequest->Priority = Priority;

LoadSynchronous (synchronous loading)

For the convenience of loading objects, UE4 uses RequestSyncLoad to implement the LoadSynchronous interface:

/** Typed wrappers */ template< typename T > T* LoadSynchronous(const FSoftObjectPath& Target, bool bManageActiveHandle = false, TSharedPtr<FStreamableHandle>* RequestHandlePointer = nullptr) { return Cast<T>(LoadSynchronous(Target, bManageActiveHandle, RequestHandlePointer) ); }
UObject* FStreamableManager::LoadSynchronous(const FSoftObjectPath& Target, bool bManageActiveHandle, TSharedPtr<FStreamableHandle>* RequestHandlePointer) { TSharedPtr<FStreamableHandle> Request = RequestSyncLoad(Target, bManageActiveHandle, FString::Printf(TEXT("LoadSynchronous of %s"), *Target.ToString())); if (RequestHandlePointer) { (*RequestHandlePointer) = Request; } if (Request.IsValid()) { UObject* Result = Request->GetLoadedAsset(); if (!Result) { UE_LOG(LogStreamableManager, Verbose, TEXT("LoadSynchronous failed for load of %s! File is missing or there is a loading system problem"), *Target.ToString()); } return Result; } return nullptr; }

Synchronously load UStaticMesh (non-blueprint resource class)

FStreamableManager streamableManager; FString strMeshFileName = "/Game/Geometry/Meshes/1M_Cube.1M_Cube"; UStaticMesh* pStaticMesh = streamableManager.LoadSynchronous<UStaticMesh>(FSoftObjectPath(strMeshFileName)); if (pStaticMesh) { UE_LOG(LogTemp, Error, TEXT("Static Object name is %s"), *pStaticMesh->GetName()); }

View Image

 

Synchronously load the blueprint class as Class

FStreamableManager streamableManager; FString strBPFileName = "/Game/ThirdPersonCPP/Blueprints/TestActor.TestActor_C"; UClass* pClass = streamableManager.LoadSynchronous<UClass>(FSoftObjectPath(strBPFileName)); if (pClass) { UE_LOG(LogTemp, Error, TEXT("UClass name is %s"), *pClass->GetName()); }

View Image

Of course, synchronous loading can also directly use the interface written in UE4. The only difference from the above is the use of TSubclassOf and TSoftClassPtr. I will analyze the usage of TSubclassOf and TSoftClassPtr later.

template< typename T > TSubclassOf<T> LoadSynchronous(const TSoftClassPtr<T>& Target, bool bManageActiveHandle = false, TSharedPtr<FStreamableHandle>* RequestHandlePointer = nullptr) { TSubclassOf<T> ReturnClass; ReturnClass = Cast<UClass>(LoadSynchronous(Target.ToSoftObjectPath(), bManageActiveHandle, RequestHandlePointer)); return ReturnClass; }

 

RequestAsyncLoad (asynchronous loading)

First look at the simple version of the source code

TSharedPtr<FStreamableHandle> FStreamableManager::RequestAsyncLoad(const FSoftObjectPath& TargetToStream, FStreamableDelegate DelegateToCall, TAsyncLoadPriority Priority, bool bManageActiveHandle, bool bStartStalled, const FString& DebugName) { return RequestAsyncLoad(TArray<FSoftObjectPath>{TargetToStream}, DelegateToCall, Priority, bManageActiveHandle, bStartStalled, DebugName); }

Load UObject asynchronously

Here is an example of loading a UStaticMesh

void ATestLoadObjectCharacter::BeginPlay() { Super::BeginPlay(); FStreamableManager streamableManager; FString strMeshFileName = "/Game/Geometry/Meshes/1M_Cube.1M_Cube"; FStreamableDelegate streamableDelegate; FSoftObjectPath strMeshObjectFileName = FSoftObjectPath(strMeshFileName); streamableDelegate.BindUObject(this, &ThisClass::LoadFinish, strMeshObjectFileName); streamableManager.RequestAsyncLoad(strMeshObjectFileName, streamableDelegate); }

 

void ATestLoadObjectCharacter::LoadFinish(FSoftObjectPath meshFilePath) { FSoftObjectPtr meshObjectPtr = FSoftObjectPtr(meshFilePath); UObject* pObject = meshObjectPtr.Get(); if (nullptr == pObject) return; UStaticMesh* pStaticMesh = Cast<UStaticMesh>(pObject); if (pStaticMesh) { UE_LOG(LogTemp, Error, TEXT("UStaicMesh name is %s"), *pStaticMesh->GetName()); } }

More concise writing:

void ATestLoadObjectCharacter::LoadFinish(FSoftObjectPath meshFilePath) { TSoftObjectPtr<UStaticMesh> MeshObjectPtr = TSoftObjectPtr<UStaticMesh>(meshFilePath); UStaticMesh* pStaticMesh = MeshObjectPtr.Get(); if (pStaticMesh) { UE_LOG(LogTemp, Error, TEXT("UStaicMesh name is %s"), *pStaticMesh->GetName()); } }

It is worth mentioning that prior to this asynchronous loading is not as  LoadSynchronous  return UObject , but was loaded when binding a delegate FSteamableDelegate , were commissioned to obtain the object at the time the callback, the object here is to get through T SoftObjectPtr of FSoftObjectPath of structure.

TSoftObjectPtr<UStaticMesh> MeshObjectPtr = TSoftObjectPtr<UStaticMesh>(meshFilePath); UStaticMesh* pStaticMesh = MeshObjectPtr.Get();

 

operation result:

View Image

Load the blueprint asynchronously as UClass

void AMyProject7Character::BeginPlay() { Super::BeginPlay(); FStreamableManager streamableManager; FString strBPClassPath = "/Game/testActor.testActor_C"; FStreamableDelegate streamableDelegate; FSoftClassPath SoftBPClassPathName = FSoftClassPath(strBPClassPath); streamableDelegate.BindUObject(this, &ThisClass::LoadFinish, SoftBPClassPathName); streamableManager.RequestAsyncLoad(SoftBPClassPathName, streamableDelegate); } void AMyProject7Character::LoadFinish(FSoftClassPath SoftBPClassPathName) { TSoftClassPtr<AActor> ActorClassPtr = TSoftClassPtr<AActor>(SoftBPClassPathName); UClass* pClass = ActorClassPtr.Get(); if (pClass) { UE_LOG(LogTemp, Error, TEXT("UStaicMesh name is %s"), *pClass->GetName()); } }

In fact, UClass is a subclass of UObject, so the same set can be used for both synchronous and asynchronous.

Reference materials: [1] http://api.unrealengine.com/INT/Programming/Assets/AsyncLoading/index.html

                    [2] https://docs.unrealengine.com/en-us/Programming/Assets/ReferencingAssets

 


Reference : https://blog.csdn.net/qq_29523119/article/details/84455486