[UE C++] 资源加载(三) 同步加载——LoadObject

[UE C++] 资源加载(三) 同步加载——LoadObject

常用的同步加载方法有,LoadObjectLoadClassLoadPackageFSoftObjectPath::TryLoadFStreamableManager::RequestSyncLoadFStreamableManager::LoadSynchronous等。其中LoadObject是最具代表性的加载过程,以下顺序是以LoadObjectLoadClass的执行流程来介绍。其它API执行流程读者可看下图进行参考,或者进入源码查看。
LoadObject

FStreamableManager::RequestSyncLoadFStreamableManager::LoadSynchronous等同步加载方法,放到下一篇文章中和异步加载一起分析。使用示例在文章末尾。

1. LoadObject

作用: 首先会在内存中查找目标资源是否存在,若存在就会直接返回,若不存在会把路径转化为Package再进行LoadPackage

LoadObject就是对StaticLoadObject进行模板化

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 );
}

输入参数:

  • Outer: 资源的Outer,一个可选对象,用于缩小查找/加载对象的位置
  • Name: 对象的字符串名称。如果它不是完整的引用路径,需要指定Outer和/或Filename
  • Filename: 文件名称,可以从其中加载(或在文件的Package对象中找到)
  • LoadFlags: 控制如何处理从磁盘加载的Flags,ELoadFlags enum
  • Sandbox: 用于限制搜索对象的Package的列表,参数用于网络通信

2. StaticLoadObject

内部调用StaticLoadObjectInternal,若没找到则会进行报错信息输出

3. StaticLoadObjectInternal

首先会调用ResolveName,这个函数上篇文章提到过,作用就是对传入的Path进行解析,这个Path必须是完整路径或者是相对于传入的Outer的路径,随后会将Outer设置为Path所指的Package对象,StrName设置为Path所指对象的NamePrivate。

这里与StaticFindObject调用ResolveName不同的是,传入的后两个bool值为true,代表会尝试Load或Create不存在于内存中的Package以及当找不到Package时会抛出警告

// break up the name into packages, returning the innermost name and its outer
ResolveName(InOuter, StrName, true, true, LoadFlags & (LOAD_EditorOnly | LOAD_NoVerify | LOAD_Quiet | LOAD_NoWarn | LOAD_DeferDependencyLoads), InstancingContext);

而后调用StaticFindObjectFast在内存中寻找资源对象,并判断对象是否加载完成,若完成则return

Result = StaticFindObjectFast(ObjectClass, InOuter, *StrName);
if (Result && Result->HasAnyFlags(RF_NeedLoad | RF_NeedPostLoad | RF_NeedPostLoadSubobjects | RF_WillBeLoaded))
{
    // Object needs loading so load it before returning
    Result = nullptr;
}

若没有在内存中找到目标资源对象,则考虑将资源对象所属的Package加载进内存中

一个包里如果有多个资源,他们在硬盘上对应的是同一个文件,那么只需要加载这个文件就好了

// now that we have one asset per package, we load the entire package whenever a single object is requested
LoadPackage(NULL, *InOuter->GetOutermost()->GetName(), LoadFlags & ~LOAD_Verify, nullptr, InstancingContext);

随后,会再次调用StaticFindObjectFast在内存中寻找资源对象,若还没找到则会判断资源对象是否被重定向了,并通过FindObjectFast查找

// If the object was not found, check for a redirector and follow it if the class matches
if (!Result && !(LoadFlags & LOAD_NoRedirects))
{
    UObjectRedirector* Redirector = FindObjectFast<UObjectRedirector>(InOuter, *StrName);
    if (Redirector && Redirector->DestinationObject && Redirector->DestinationObject->IsA(ObjectClass))
    {
        return Redirector->DestinationObject;
    }
}

4. LoadPackage

作用: 加载与上下文标志匹配的Package和所有包含的对象。

内部调用LoadPackageInternal,输入参数如下(只列举了前三个)

  • InOuter: 如果指定了,则会以InOuter->GetPathName()为加载路径,若为nullptr则会以InLongPackageName为加载路径
  • InLongPackageName: InOuter为nullptr则会以InLongPackageName为加载路径
  • LoadFlags: 控制如何处理从磁盘加载的Flags,ELoadFlags enum

5. LoadPackageInternal

内部实现比较复杂,恕笔者能力不够,没有做分析

最终调用的是LoadPackageAsync函数,这就是异步加载的入口,并且最后FlushAsyncLoading,内部阻塞等待,将异步加载转为同步。
LoadPackageAsync函数,这个函数就是UE4资源加载的大入口,后面整套资源加载都隐藏在了这个函数之后

int32 RequestID = LoadPackageAsync(InName, nullptr, *InPackageName);

if (RequestID != INDEX_NONE)
{
    FlushAsyncLoading(RequestID);
}

Result = (InOuter ? InOuter : FindObjectFast<UPackage>(nullptr, PackageFName));
return Result;

6. LoadClass

作用: 加载类资源

模板化的StaticLoadClass,参数输入和LoadObject完全一致。

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 );
}

7. StaticLoadClass

内部调用了LoadObject,随后对根据Path加载得到的UClass类型进行判断,若类型不匹配会报错并返回NULL

UClass* Class = LoadObject<UClass>( InOuter, InName, Filename, LoadFlags, Sandbox );
if( Class && !Class->IsChildOf(BaseClass) )
{
    //报错信息
    ······

    // return NULL class due to error
    Class = NULL;
}
return Class;

使用示列

LoadObject —— no Outer

UTexture2D* TestTexture2D = LoadObject<UTexture2D>(nullptr, TEXT("/Game/StarterContent/Textures/T_Burst_M.T_Burst_M"));

LoadPackage

UPackage* TestPackage = LoadPackage(nullptr, TEXT("/Game/StarterContent/Textures/T_Burst_M"), LOAD_None);

LoadObject —— Outer

UPackage* TestPackage = LoadPackage(nullptr, TEXT("/Game/StarterContent/Textures/T_Burst_M"), LOAD_None);
UTexture2D* TestTexture2D = LoadObject<UTexture2D>(TestPackage,TEXT("T_Burst_M"));

LoadClass —— no Outer

TSubclassOf<AActor> TestClass = LoadClass<AActor>(nullptr, TEXT("Blueprint'/Game/Blueprint/BP_Test.BP_Test_C'"));

LoadClass —— Outer

UPackage* TestPackageTwo = LoadPackage(nullptr, TEXT("/Game/Blueprint/BP_Test"), LOAD_None);
TSubclassOf<AActor> TestClass = LoadClass<AActor>(TestPackageTwo, TEXT("BP_Test_C'"));

图中所涉及的其它同步加载使用方式,可参考[UE C++] 资源加载(一) 硬&软引用加载资源

参考

UE(虚幻引擎)是一种流行的游戏开发引擎,它通过路径加载资源。 路径加载资源是指使用文件路径来加载游戏中所需的资源。使用UE开发游戏时,开发者可以通过引擎提供的函数和接口来指定文件的路径,并将其加载到游戏中使用。 UE支持多种资源的路径加载,包括但不限于图片、音频、模型、动画等。在游戏开发过程中,开发者可以使用UE提供的资源浏览器或项目管理器来管理和组织资源文件。通过在路径中指定文件的名称和位置,UE可以准确地加载所需的资源。 路径加载资源的好处是提高了游戏开发的灵活性和可定制性。开发者可以根据需要随时更改资源文件的路径,方便地替换或更新资源。此外,路径加载还可以帮助开发者在游戏中使用外部文件、共享资源等,增加了资源的复用性和拓展性。 虽然UE通过路径加载资源很方便,但也需要开发者注意一些问题。首先,文件路径必须正确设置,否则无法加载资源。其次,过多的文件路径可能导致开发文件的混乱,因此需要良好的组织和管理资源文件。最后,路径加载资源可能会增加游戏运行时的加载时间和内存消耗,开发者需要优化加载流程,以提高游戏的性能。 总之,UE通过路径加载资源是一种非常常见和有用的游戏开发技术,它提供了便捷的资源管理和使用方式,使开发者能够更好地实现他们的游戏创意。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MustardJim

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值