[{"data":1,"prerenderedAt":131},["ShallowReactive",2],{"\u002F2014-10-05-ue4%E5%BC%82%E6%AD%A5%E8%BD%BD%E5%85%A5%E8%B5%84%E6%BA%90":3},{"id":4,"title":5,"body":6,"date":108,"description":12,"extension":109,"meta":110,"navigation":113,"path":125,"seo":126,"stem":127,"tags":128,"__hash__":130},"blogs\u002F_legacy\u002F2014\u002F2014-10-05-ue4%e5%bc%82%e6%ad%a5%e8%bd%bd%e5%85%a5%e8%b5%84%e6%ba%90.md","UE4异步载入资源",{"type":7,"value":8,"toc":104},"minimark",[9,13,16,26,29,32,35,46,49,56,59,64,67,73,76,82,85,88,94,101],[10,11,12],"p",{},"所有的“硬”指针指向的资源都会被UE4在启动时进行载入，为了防止某些情况下引发的巨大延迟，必要的时候我们需要使用异步资源载入系统。",[10,14,15],{},"当前UE4版本为4.7。",[10,17,18,19,25],{},"本文参考：",[20,21,22],"a",{"href":22,"rel":23,"title":22},"https:\u002F\u002Fdocs.unrealengine.com\u002Flatest\u002FINT\u002FProgramming\u002FAssets\u002FAsyncLoading\u002Findex.html",[24],"nofollow","进行整理。同时也是研究引擎的记录。",[10,27,28],{},"对于异步载入有两个类很重要:FStringAssetReferences和TAssetPtr。",[10,30,31],{},"FStringAssetReferences是对资源(Asset)的“软”引用，这个结构在BP中使用起来就像是UObject指针一样。而TAssetPtr是对FStringAssetReferences的一个弱引用封装，同时规范所指向的类型，可以在需要的时候调用Get()来解析到具体的资源。",[10,33,34],{},"为了避免理解上的偏差，来实际测试一次是最快的。在代码中添加如下属性：",[36,37,42],"pre",{"className":38,"code":40,"language":41},[39],"language-text","UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = Test) \n    FStringAssetReference tf;\n\nUPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = Test) \n    TAssetPtr\u003CUTexture2D> ttp;\n","text",[43,44,40],"code",{"__ignoreMap":45},"",[10,47,48],{},"FstringAssetReference在可视化编辑器中显示如下，确实是可以当作UObject指针来使用：",[10,50,51],{},[52,53],"img",{"alt":54,"src":55},"image","\u002Fwp-content\u002Fuploads\u002F2014\u002F10\u002Fimage_thumb.png",[10,57,58],{},"TAssetPtr则显示如下：",[10,60,61],{},[52,62],{"alt":54,"src":63},"\u002Fwp-content\u002Fuploads\u002F2014\u002F10\u002Fimage_thumb1.png",[10,65,66],{},"大多数时候，异步载入一个单独的资源基本没什么意义，除非他真的很大。如果要批量异步载入资源的话，就需要用到Object Libraries。这个是Content brower用来进行资源筛选和显示的类，在游戏逻辑中使用也是可以的。",[36,68,71],{"className":69,"code":70,"language":41},[39],"if (!ObjectLibrary)\n{\n       ObjectLibrary = UObjectLibrary::CreateLibrary(BaseClass, false, GIsEditor);\n       ObjectLibrary->AddToRoot();\n}\nObjectLibrary->LoadAssetDataFromPath(TEXT(\"\u002FGame\u002FPathWithAllObjectsOfSameType\");\nif (bFullyLoad)\n{\n       ObjectLibrary->LoadAssetsFromAssetData();\n}\n",[43,72,70],{"__ignoreMap":45},[10,74,75],{},"上面的代码对指定的目录创建了一个Library，并且资源进行了载入操作。第二个步骤并不是必须的：",[36,77,80],{"className":78,"code":79,"language":41},[39],"TArray\u003CFAssetData> AssetDatas;\nObjectLibrary->GetAssetDataList(AssetDatas);\n\nfor (int32 i = 0; i \u003C AssetDatas.Num(); ++i)\n{\n       FAssetData& AssetData = AssetDatas[i];\n\n       const FString* FoundTypeNameString = AssetData.TagsAndValues.Find(GET_MEMBER_NAME_CHECKED(UAssetObject,TypeName));\n\n       if (FoundTypeNameString && FoundTypeNameString->Contains(TEXT(\"FooType\")))\n       {\n              return AssetData;\n       }\n}\n",[43,81,79],{"__ignoreMap":45},[10,83,84],{},"上面的代码在ObjectLibrary中进行筛选并将找到的第一个资源返回。",[10,86,87],{},"得到AssetData之后可以将其转换为FStringAssetReference，然后使用StreamableManager进行异步载入。",[36,89,92],{"className":90,"code":91,"language":41},[39],"void UGameCheatManager::GrantItems()\n{\n       TArray\u003CFStringAssetReference> ItemsToStream;\n       FStreamableManager& Streamable = UGameGlobals::Get().StreamableManager;\n       for(int32 i = 0; i \u003C ItemList.Num(); ++i)\n       {\n              ItemsToStream.AddUnique(ItemList[i].ToStringReference());\n       }\n       Streamable.RequestAsyncLoad(ItemsToStream, FStreamableDelegate::CreateUObject(this, &UGameCheatManager::GrantItemsDeferred));\n}\n\nvoid UGameCheatManager::GrantItemsDeferred()\n{\n       for(int32 i = 0; i \u003C ItemList.Num(); ++i)\n       {\n              UGameItemData* ItemData = ItemList[i].Get();\n              if(ItemData)\n              {\n                     MyPC->GrantItem(ItemData);\n              }\n       }\n}\n",[43,93,91],{"__ignoreMap":45},[10,95,96,97,100],{},"StreamableManager可以对传递给他的StringReference所引用的资源全部进行载入操作。上面的例子中ItemList的定义为",[43,98,99],{},"TArray\u003C TAssetPtr\u003CUGameItem> >","。也就说针对一个弱引用的列表，获得所有的StringReference之后传递给StreamableManager进行一次性的异步载入。载入之后会调用回调函数以便及时进行处理。在回调函数之前，所有的引用都会被StreamableManager保留，防止其被垃圾回收。",[10,102,103],{},"如上，将StreamableManager和Object Libaries进行组合使用，即可实现异步的资源载入了。",{"title":45,"searchDepth":105,"depth":106,"links":107},2,3,[],"2014-10-05","md",{"layout":111,"status":112,"published":113,"author":114,"author_login":115,"author_email":116,"author_url":117,"wordpress_id":118,"wordpress_url":119,"date_gmt":120,"excerpt":121},"post","publish",true,{"display_name":115,"login":115,"email":116,"url":117},"chaoshikari","chaoshikari@gmail.com","\u002F",1052,"\u002F\u002F?p=1052","2014-10-05 09:27:08 +0000",{"type":7,"value":122},[123],[10,124,12],{},"\u002F2014-10-05-ue4异步载入资源",{"title":5,"description":12},"_legacy\u002F2014\u002F2014-10-05-ue4%e5%bc%82%e6%ad%a5%e8%bd%bd%e5%85%a5%e8%b5%84%e6%ba%90",[129],"UE4","bqp6nM7vv0ExVK_MBRUW0P-TNF0F9dbp-0DmCdQN_QE",1788763181080]