当前位置 :首页 >> 网红

浅谈UE4的JSON

2024-01-27   来源 : 网红

知识在毫无疑问地朋相符缺陷以后,必须不须对UE4的基本概念有一个差不多的了解。

类本本体不须来个木造UML平面图。

FArchiveFArchive意译为文档类,存取和指为存取全靠它。

作为函数调用,新版本成了各个旧版本的<<加载符。

前提专有名词是Ar << IntMember,依赖性是把IntMember存取到Ar中的。

如果你核对在此之当年文档FArchive | Unreal Engine Documentation,FArchive有各式各样数目不限的派生类。其中的主要职责把UObject存取到存储设备和从存储设备指为存取转化UObject最有趣的分别是:

FLinkerSeFLinkerLoad

在后文章的我们上会稍稍揭开一点讲到。

UObject::Serialize()工具在开始讲到Linker以后,当然必须不须有趣平原地带过一下UObject::Serialize()工具。这个工具的依赖性恰恰其名,主要职责存取。

它有两个旧版本,其中的第一个旧版本稍长这样:

// Object.hvirtual void Serialize(FArchiveCo Ar);// Object.cpp#define IMPLEMENT_FARCHIVE_SERIALIZER( TClass ) void TClass::Serialize(FArchiveCo Ar) { TClass::Serialize(FStructuredArchiveFromArchive(Ar).GetSlot().EnterRecord()); }IMPLEMENT_FARCHIVE_SERIALIZER(UObject)

把祥揭开就是:

void UObject::Serialize(FArchiveCo Ar) { UObject::Serialize(FStructuredArchiveFromArchive(Ar).GetSlot().EnterRecord());}

只不过就都是FArchive中的装入Record,然后把它当认真给定传给另一个旧版本的UObject::Serialize()。另一个旧版本又稍长这样:

virtual void Serialize(FStructuredArchive::FRecord Record);

所以这个第二个旧版本才是毫无疑问的主角。

不须揭开讲到,就上会更为大篇幅,所以不须止步于此,左边上会不须平面图斯到它。

Linker家族

说道回去UML平面图中的平面图斯到的Linker。

首起不须Linker最中庭的函数调用,称作FLinkerTable,这个本本体本体可以参考文章《Ue4_存取浅析》Ue4_存取浅析_ue 存取-CSDNTwitter。

可以打听FLinkerTable的本本体与uasset副本的主旨是一一完全一致的。反之亦然道我们可以暗示,当uasset被擦除到闪存底下的时候,核对FLinkerTable的主旨就能其实uasset底下面是不是是什么主旨。

年中是FLinker,这个类是FLinkerLoad和FLinkerSe的函数调用,暂时情况下必须我们注意到的;也。

不须年中就是擦除uasset的主力部队FLinkerLoad!

LinkerLoad的大致工作工序有趣地描述一下我们擦除uasset副本的一个差不多工序。

首不须我们必须其实我们要擦除的工具箱的轨迹,然后线程LoadObject来载入。

就像上上会说道到的:

UMyClass* LoadedInstance = LoadObject(nullptr, TEXT("/Game/xxx.xxx"));

稍稍在留言板阅过稍稍「UE4 擦除副本」或者「UE4 存取」的编者们一定其实,LoadObject有一层层的工具箱装,差不多线程工序是这样的:

这就是我们常常其实的两姐妹的当年半截,擦除Object上会一路线程下去,不须度的借以是线程LoadPackage擦除一个工具箱。

而两姐妹的后半截,两姐妹FLinkerLoad再次显现经常出现。

LoadPackageIntenal()中的上会根据轨迹创始人一个完全一致的FLinkerLoad,它被创始人完后上会竟然监督自身的Tick()。

我们来忘了Tick底下面都是在干什么(只刷不可或缺预定义):

Status = CreateLoader(TFunction([]() {}));// ...Status = SerializePackageFileSummary();// ...Status = SerializeNameMap();

可以看着,Tick只不过就是在稍稍擦除uasset的主旨停下来。就其主旨其他同学可以自己摸索,主要就是把上上会刷的那个平面图底下面的每个之外都擦除到Linker中的。

1.4 关于存取的根基知识这一变奏讲到的是存取。

根据留言板的资料以及各种断点统计数据处理,可以清楚地其实一般主要职责存取的FArchive的并不一定为FArchiveSeTagExports。看它的起名就其实它是主要职责将UObject中的被UPROPERTY祥打上标记的统计数据存取的。

就其的一些前提概念可以参考文章《UE4中的的Serialization》UE4中的的Serialization | StoneのBLOG。

文章差不多参阅了两种存取的工具:TPS和UPS。

这底下我们用的是TPS。

顺着UPackage::Se()工具往下看,在SePackage.cpp的2419行临近能发觉显现出这句不可或缺预定义:

PackageExportTagger.TagPackageExports(ExportTaggerArchive, bRoutePrese);

线程了FPackageExportTagger::TagPackageExports()。

往常看SePackage.cpp的1793行临近:

ExportTagger.ProcessBaseObject(Base);

线程的是FArchiveSeTagExports::ProcessBaseObject()。

void FArchiveSeTagExports::ProcessBaseObject(UObject* BaseObject){ (*this) << BaseObject; ProcessTaggedObjects();}

这个预定义就非常有趣了,只不过就是线程BaseObject的Serialize()工具来进行存取,把自己作为UObject::Serialize(FArchiveCo Ar)的给定。

1.5 实验者存取应该最终(以及修复结果)根据当年文的平面图斯到的,可以打听错误性:

只要是存取,一定上会走回UObject::Serialize()工具。

但是我在这边断点的时候,或许情况下走回到这底下。

上一变奏讲到存取的过程的时候并未讲到相符了存取的工序,那么直到现在所必须认真的就是在每一个之外接踵而至点,看有情况下停下来。

再次可以聚焦到程序在可以这样的土话放到FArchiveSeTagExports::operator<<():

FArchiveCo FArchiveSeTagExports::operator<<(UObject*Co Obj){ if (!Obj || Obj->HasAnyMarks(OBJECTMARK_TagExp) || Obj->HasAnyFlags(RF_Transient) || !Obj->IsInPackage(Outer)) { return *this; }}

但是在第一个if这底下就被作罢了。

用A、B、C、D四个临时数组来忘了if是有哪些先决条件合乎了:

bool A = !Obj;bool B = Obj->HasAnyMarks(OBJECTMARK_TagExp);bool C = Obj->HasAnyFlags(RF_Transient);bool D = !Obj->IsInPackage(Outer);

可以看着在目当年的才会,D是true。字面意义上就是Obj之外Outer这个工具箱底下面。

那么Outer是什么呢?Outer就是我们线程UPackage::Se()时传入的第一个给定,也就是要被存放的工具箱。反之亦然道,只要我们要存放的UObject所在的工具箱不是我们要存放的那个工具箱,那并不需要就可能会来进行存取了。

那么UObject怎么指定自己同属的工具箱呢?作答是在NewObject的时候就无论如何把Package作为Outer传入。

在上上会这个例子中的,预定义就无论如何复成这样:

UPackage* MyPkg = CreatePackage(*PackagePath);UMyClass* MyInstance = NewObject(MyPkg);

不须运转一次程序在,可以看着导显现出来的uasset副本最终地从1KB演变成了2KB!

1.6 实验者指为存取应该最终经历过上上会的摸索和修正,可以不须断言存取这一步是没缺陷了。年中要认真的是探寻一下指为存取上会不须度的主因。

首不须知悉轨迹是不是难为了。于是停下来留言板的文章《UE4:四种擦除自然资源的手段》复了很多个旧版本的轨迹,还是不对。

这个时候也就情况下一路断点统计数据处理了。

求证指为存取应该最终当年文讲到根基知识的时候,讲到到第一次擦除副本时,不须度都是上会线程LoadPackageInternal,它又上会创始人一个FLinkerLoad来主要职责擦除自然资源。

于是并不需要断点到LoadPackageInternal()的这一行:

Linker = GetPackageLinker(InOuter, *FileToLoad, LoadFlags, nullptr, nullptr, InReaderOverride, CoInOutLoadContext, ImportLinker, InstancingContext);

这样丢出下一行就可以看着Linker的主旨。Linker继承于FLinkerTables,日志着uasset的全部电子邮件。而从的有中的可以打听,uasset中的的ExportMap工具箱含着它的所有Object统计数据。

于是点开Linker的主旨,这个时候可以看着函数调用的ExportMap的主旨。我这底下可以相符地看着,以后存取的UMyClass是可以错误从那时起转化的!

装入UObject既然Package并未被最终擦除,完全一致的UObject也被这样的土话存取,那为什么再次回回去的是nullptr呢?

既然擦除进了Package,那么下一步就都是Package中的装入统计数据了。

UE4是怎么从Package中的装入统计数据的呢?

忘了StaticLoadObjectInternal()工具中的,在线程了ResolveName来设法擦除Package后来,有这么一句不可或缺的语句:

Result = StaticFindObjectFast(ObjectClass, InOuter, *StrName);

很突显现出这一步的借以就都是闪存中的装入我们并未擦除好的UObject。

一路往下点,起不须线程到正因如此的Internal做到:

UObject* StaticFindObjectFastInternal()

年中不须度线程到:

UObject* StaticFindObjectFastInternalThreadSafe(FUObjectHashTablesCo ThreadHash, const UClass* ObjectClass, const UObject* ObjectPackage, FName ObjectName, bool bExactClass, bool bAnyPackage, EObjectFlags ExcludeFlags, EInternalObjectFlags ExclusiveInternalFlags){ ExclusiveInternalFlags |= EInternalObjectFlags::Unreachable; // If they specified an outer use that during the hashing UObject* Result = nullptr; if (ObjectPackage != nullptr) { int32 Hash = GetObjectOuterHash(ObjectName, (PTRINT)ObjectPackage); FHashTableLock HashLock(ThreadHash); for (TMultiMap::TConstKeyIterator HashIt(ThreadHash.HashOuter, Hash); HashIt; ++HashIt) { } } // ...}

为了从可观的所有UObject中的发觉显现出我们要的那个,必须采用UObject的数据结构取值来发觉。看上上会这段预定义的依赖性,就是不算显现出UObject的数据结构取值,然后根据这个数据结构格外到一个给定容器,再次不须从给定容器中的挑选显现出前提Object。

既然前提Object是存在的,而采用不算显现出来的数据结构取值又发觉足足它,那么可以推不算显现出数据结构取值本身是有缺陷的。

忘了数据结构取值是怎么不算的:

static FORCEINLINE int32 GetObjectOuterHash(FName ObjName,PTRINT Outer){ return GetTypeHash(ObjName) + (Outer>> 6);}

正因如此数据结构取值的给定有两个:

ObjName也就是传停下来的ObjName的起名。ObjName的并不一定是一个FName,FName有自己的一套量度数据结构取值的公式。Outer的重定向在这个一幕中的,Outer就是上面擦除先行的Package本身。

上面并未实验者过擦除完的Package前提是没缺陷的,那么要知悉的就是ObjName这个给定了。

1.7 如何才能在Package底下面发觉显现出完全一致的Object(以及工具箱的轨迹的就其意即)那么ObjName这个给定从哪来的呢?

回去忆一不须一次诉说道上面LoadObject的时候填埋的轨迹:

UMyClass* LoadedInstance = LoadObject(nullptr, TEXT("/Game/xxx.xxx"));

各位有情况下打算过,为什么轨迹底下面,再次那个工具箱名要写成两次,一定要写成xxx.xxx呢?

只不过逗点上面的那之外是工具箱名,而左边那之外是「你要擦除的Object的起名」。

回去忆二诉说道以后断点统计数据处理的时候点开的FLinkerTable::ExportMap中的,擦除停下来的主旨。

记得不,底下面那个最有趣的起名称作什么?

显然是MyClass_0,显然是MyClass_1,还或许是MyClass_12345。总之!它的起名不上会是MyClass。

那么你怎么或许够用MyClass作为ObjName把前提其实错误的阅寻到呢。

错误性与妥善解决方案错误性:LoadObject的轨迹工具箱括两个之外,逗点当年的是工具箱名,逗点后的是其实名。

由于创始人最有趣的时候,当前的起名是{你的类名}_{序列号},所以不须度被存取到uasset副本中的的其实也是这个起名。当你用工具箱名.工具箱名来给与其实的时候,就上会给与不须度。

怎么妥善解决呢?

有两种工具:

在存取存放其实以后,用UObject::Rename()来把其实名称复成你打算要的那个起名,LoadObject的时候,逗点后的其实名就用你指定的起名。在每次创始人完要被写成土话的其实后来,日志下它的起名到服务容器或者存储设备,到时LoadObject的时候,采用这个日志的起名来擦除完全一致的uasset。

这样一波加载后来,就最终地将副本擦除到了闪存中的。

1.8 新科技论述上头来进行新科技论述。

第一,你要有一个缺陷,偷偷缺陷去看预定义,比如在这底下我的缺陷就是如何在Runtime中的来进行UObject的存取。

第二,发觉显现出留言板所有能发觉显现出的文章,这一步的借以是让我们最起码对各个类和计算机系统有一个根基的前提概念。

第三,他站看预定义,他站自己画点UML平面图把你所其实的类关系组合成大大的,让自己心底下有个前提概念。

第四,为了让断点统计数据处理验证自己的猜打算。

第五,毫无疑问地采用上上会的知识来妥善解决你的缺陷。

所以这就是一个大滑,在你短时间不上会除此以外紧的才会,以求不须认真好实地调朋,不须无论如何,上会比你并不需要撞到缺陷上平面图斯高很多生产成本。

二、UE4中的存取副本的表明缺陷

上上会是讲到到将一系列UObject存取为一个uasset副本。

虽然UObjects尽可能较稍长时间被存取,也尽可能最终从那时起指为存取成最有趣,但是目当年为止还有一个缺陷,就是它情况下被自然资源浏览容器辨认和表明显现出来。

采用《UE4追加Asset并不一定》文章中的平面图斯到的工具,可以自己创始人一个与自订自然资源同并不一定的自然资源,但是对于我们自己创始人的null却情况下表明。

为了尽可能在自然资源浏览容器表明这个null,必须我们自己去翻完全一致的程式码,发觉显现出它不被表明显现出来的主因。

2.1 从自然软件系统容器的程式码开始因为是自然软件系统容器不表明自然资源,所以无论如何不须看自然软件系统容器的程式码。

怎么发觉显现出完全一致的程式码呢,这个时候就要请显现出不可忽视的工具。

滑鼠可到在自然软件系统容器的主窗口,可以看足足它的做到自然语言。

点进去就能看足足预定义:

TSharedRef SAssetView::CreateTileView(){ return SNew(SAssetTileView) .SelectionMode( SelectionMode ) .ListItemsSource(CoFilteredAssetItems) .OnGenerateTile(this, CoSAssetView::MakeTileViewWidget) .OnItemScrolledIntoView(this, CoSAssetView::ItemScrolledIntoView) .OnContextMenuOpening(this, CoSAssetView::OnGetContextMenuContent) .OnMouseButtonDoubleClick(this, CoSAssetView::OnListMouseButtonDoubleClick) .OnSelectionChanged(this, CoSAssetView::AssetSelectionChanged) .ItemHeight(this, CoSAssetView::GetTileViewItemHeight) .ItemWidth(this, CoSAssetView::GetTileViewItemWidth);}

写成过UI的同学无论如何对于这段预定义忽略上会马上,以下的统计数据可能突显现出就是上上会写成的FilteredAssetItems。

有了正门,年中的往回去推就有趣了,不断地采用IDE的「朋发觉提到」的功能,不须度发觉显现出统计数据的可能。

对于每一个统计数据可能,在其二叉树中的都打印显现出自然资源的起名来,用来判断我们的自订自然资源是在哪一步被处理过程丢了。

这之外UI的预定义有点太简单,我就并不需要给作答了。自订null自然资源的处理过程不是在自然软件系统容器这个计算机系统中的发生的,而是在上流被处理过程的。

自然资源浏览容器的上流便是副本系统,这其中的的关系又有点太繁杂,我也情况下险恶去了解。

2.2 指为向悬疑利用uasset后缀名在实践中阅寻我们理一下简而言之。在UE4中的,每一个自然资源无论如何完全一致一个uasset副本。在上次试验性中的,我们验证了这个uasset副本是能被擦除的。那么有几个疑惑:

副本系统在二叉树所有副本的过程中的,能否发觉显现出我们的uasset副本?我们的uasset副本是在哪底下被处理过程丢的,处理过程的先决条件是什么?

这时候就要祭显现出在实践中阅寻大法,在实践中阅素「.uasset"」不可或缺字,可以发觉显现出提到的;也在FPackageName类。这个类有几个工具和uasset后缀名有关系,其中的工具箱括:

IsAssetPackageExtension()IsPackageFileName()

分别朋发觉其提到,不须度可以发觉显现出类FAssetDataDiscovery。这个类的依赖性便是阅集所有的Asset电子邮件。

于是又是一路探寻统计数据的根源。

调用自然资源电子邮件副本在FAssetDataGatherer::Run()工具中的,有这个预定义:

FDiskCachedAssetData* DiskCachedAssetData = DiskCachedAssetDataMap.Find(PackageName);

可以朋到这个DiskCachedAssetDataMap只不过叫作调用副本你的工程工程项目名/Intermidiate/CachedAssetRegistry.bin。

其中的有几句预定义,它从DiskCachedAssetDataMap中的装入电子邮件,而后擦除配置文件AssetDataList,如果这个配置文件非自力,那么将其转为到LocalAssetResults以下(这个以下就是统计数据库)。

for (const FAssetDataCo AssetData : DiskCachedAssetData->AssetDataList){ LocalAssetResults.Add(new FAssetData(AssetData));}

从断点统计数据处理打听我们的自订自然资源就是因为DiskCachedAssetData->AssetDataList是自力而被挑选丢。

那么下一步就是朋相符:为什么这个以下上会是自力,这个以下的统计数据从哪来的?

调用自然资源电子邮件副本的转化将你的工程工程项目名/Intermidiate/CachedAssetRegistry.bin这个副本删丢后来不须断点统计数据处理,就可以朋到这个副本是如何转化的。

如果在调用副本中的发觉足足完全一致的asset电子邮件,那么上会监督这几句预定义:

if (!bLoadedFromCache){ ReadContexts.Emplace(PackageName, Extension, AssetFileData);}

然后设法擦除Asset副本:

ParallelFor(ReadContexts.Num(),[this, CoReadContexts](int32 Index){ FReadContextCo ReadContext = ReadContexts[Index]; ReadContext.bResult = ReadAssetFile(ReadContext.AssetFileData.PackageFilename, ReadContext.AssetDataFromFile, ReadContext.DependencyData, ReadContext.CookedPackageNamesWithoutAssetData, ReadContext.bCanAttemptAssetRetry);},EParallelForFlags::Unbalanced | EParallelForFlags::BackgroundPriority);

一直怼着ReadAssetFile()工具读,发觉显现出预定义:

if ( !PackageReader.ReadAssetRegistryData(AssetDataList) ){ if ( !PackageReader.ReadAssetDataFromThumbnailCache(AssetDataList) ) { // It's ok to keep reading even if the asset registry data doesn't exist yet //return false; }}

在ReadPackageDataMain()formula_中的:

// ReadPackageDataMain()int32 ObjectCount = 0;BinaryArchive << ObjectCount;// ...for (int32 ObjectIdx = 0; ObjectIdx < ObjectCount; ++ObjectIdx){ // ... OutAssetDataList.Add(new FAssetData(PackageName, ObjectPath, FName(*ObjectClassName), MoveTemp(TagsAndValues), PackageFileSummary.ChunkIDs, PackageFileSummary.PackageFlags));}

这底下有一个for气化,根据上上会指为存装入来的ObjectCount的数目来擦除Asset并写成入到OutAssetDataList,这个以下完全一致的就是上头平面图斯到的DiskCachedAssetData->AssetDataList。

ObjectCount从何而来这个ObjectCount都是FArchive中的指为存取得到的,仅指Package本身的根基电子邮件之一。

讲到道理,一个配置文件既然能被读显现出来,就赞同有被写成入的;也,由于ObjectCount这个起名实在是有点泛了,用它来在实践中阅寻实在是不靠谱。这个时候我注意到到它上一个回存取的配置文件的预定义:

BinaryArchive << OutDependencyDataOffset;

于是在实践中阅寻了DependencyDataOffset,发觉显现出SePackageUtilities.cpp副本中的的完全一致存取预定义:

AssetRegistryRecord << SA_VALUE(TEXT("AssetRegistryDependencyDataOffset"), AssetRegistryDependencyDataOffset);

往下再次看,果然接着就是ObjectCount的存取预定义:

TArray AssetObjects;if (!(Linker->Summary.PackageFlags Co PKG_FilterEditorOnly)){ // Find any exports which are not in the tag map for (int32 i = 0; i ExportMap.Num(); i++) { FObjectExportCo Export = Linker->ExportMap[i]; if (Export.Object CoCo Export.Object->IsAsset()) { AssetObjects.Add(Export.Object); } }}int32 ObjectCount = AssetObjects.Num();FStructuredArchive::FArray AssetArray = AssetRegistryRecord.EnterArray(SA_FIELD_NAME(TEXT("TagMap")), ObjectCount);

这底下的自然语言很有趣,就都是Linker的ExportMap中的读显现出UObject,填埋充到AssetObjects以下中的,不须度又将以下稍大小赋取值给ObjectCount,并存取。

在第一节中的我们实验者显现出FLinker::ExportMap不是自力的,那么赞同就是在上上会这个if中的被挑选丢了。

从离开UObject::IsAsset()工具中的,看足足UE4对于应该是自然资源的判断很有趣,要合乎几个先决条件:

可能会有RF_Transient和RF_ClassDefaultObject的flag一定要有RF_Public的flag可能会是IsPendingKill的

断点统计数据处理推测第二个先决条件不合乎,读显现出来的flag是RF_NoFlag。

我们忘了RF_Public的说明了:

UOBject的flag那么是不是是哪个;也设为了UObject的flag呢?

可以通过两种必需:

NewObject的时候有个给定可以设为flagUObject::SetFlags()也可以设为

回去打算一下上一节中的的预定义:

UMyClass* MyClass = NewObject(MyPkg);

只必须这么复才可:

UMyClass* MyClass = NewObject(MyPkg, UMyClass::StaticClass, TEXT("MyAssetName"), RF_Public);

2.3 新科技论述上头来进行新科技论述。

看程式码的工具论首起不须看程式码。自然资源之外的预定义其实是非常大块,如果打算一点一点地啃,不是没用,但是很费短时间,而且烧脑。从缺陷显现启航确有可以给自己平面图斯供一个非常好的正门。

朋这之外的程式码的技巧如上平面图斯及的,有两个工具:

用UE4的工具核对完全一致Slate的转化预定义,然后顺着统计数据的可能往上读。并不需要阅寻你有点有用的一些不可或缺字,如上上会平面图斯到的.uasset",并不需要从uasset的擦除开始看。

第二种工具只不过稍稍必须一些根基,在阅寻以后你要对这之外的设计简而言之有一个差不多的暗示,比如说道你要其实:自然资源擦除,必然都是副本的阅寻开始,副本阅寻后来便是要擦除其副本电子邮件,然后来进行某些挑选,再次将通过挑选的自然资源填埋充到不须度的以下。

指为复读根基顺着自己暗示的简而言之去看,一一完全一致进去,在阅寻预定义和忽略预定义上就上会有趣许多。

第二个是写成了UE4一定短时间了,要指为过来去险恶了解一些根基formula_、根基计算机系统。

比如NewObject()formula_,以后我们用的时候都是并不需要无给定线程。直到现在抬起坑了才其实NewObject()底下面只不过每一个给定都非常不可或缺,一般来说甚至上会导致一些莫名其妙的缺陷。所以对于常用的formula_,最好完全弄相符它所有的给定,比如NewObject的Outer和Flags给定。

土话说道在此之当年文档对这之外的说明了其实是少,没自行,情况下靠自己看了。

越加有趣的,越加要完全忽略。

三、指为存取第二次上会不须度的缺陷

3.1 第二次指为存取不须度在当年两章中的我们并未最终地来进行了「一次」存取和指为存取,这一切都看大大的很好很妙。直到我必须来进行第二次存取的时候,缺陷就显现出来了。

第一次存取尽可能非常其实地存装入其实来,尽可能较稍长时间采用。然而当我在Editor中的再一浏览者「Play」按住,不须一次敦促指为存取的时候,回回去的是自力。

3.2 放过该游戏后来情况下不须总编存取副本除此之外还有一个很令人吃惊的物理现象。

从IDE触发Editor后来,可以较稍长时间地挡住和总编n次(0 <= 0 <= +无限)存取自然资源(指的就是我们上上会存取的那个副本)。然而只要有一次在情况下挡住这个自然资源的才会,浏览者Play挡住了一次该游戏,那么停止该游戏后来任你不须怎么工具栏这个副本,都上会推测没自行不须挡住。

并且EditorLog上会打印报难为:

LogAssetEditorSubsystem: Error: Opening Asset editor failed because of null asset

3.3 缺陷初探不管是在该游戏底下面线程LoadObject,还是在自然资源浏览容器中的工具栏一个自然资源(编者好友可以自行接踵而至点统计数据处理),不须度都上会线程到LoadObject()formula_。

根据我断点统计数据处理的结果,在第一次线程LoadObject()的时候,确有上会走回一遍LoadPackage()然后StaticFindObject()的工序。但是到了第二次LoadObject()的时候,由于Package并未被擦除了,所以不必须再一LoadPackage,而是并不需要探寻完全一致的Object才可。

不可或缺就在于为什么发觉足足这个Object。

在ResolveName()formula_中的,有这句预定义:

InPackage = StaticFindObjectFast(UPackage::StaticClass(), InPackage, *PartialName);

断点统计数据处理的时候,可以从UPackage::LinkerLoad发觉显现出完全一致的LinkerLoad,由此发觉显现出它的ExportMap。很那时候ExportMap虽然不为自力,但是底下面每一项的Object赋取值都是NULL。

3.4 知悉于是知悉是不是GC的锅,无疑从Editor离开Runtime一次,完全一致的Object赋取值就演变成了nullptr。但是我们看ExportTable的做到,上上会并无UPROPERTY()的标记,所以这些UObject的提到数目并不上会因为UPROPERTY()标记而降低。

说道到GC,那么就必须知悉一下EObjectFlags了。

上面章节中的说道过我们通过给UObject设为RF_Public的Flags来达到让总编容器尽可能辨认和总编自然资源的效果。这个Flags无论如何是一个很不可或缺的功用。

3.5 证实回去过头来打算,为啥Editor创始人的自然资源就可以较稍长时间地多次被指为存取呢,它的存取给定是不是和我们的有什么各有不同?

不用挡住一个已存在的其他自然资源,然后在UPackage::Se()formula_上接踵而至点,然后在Editor下浏览者Se。

这个时候可以断点到第二个给定Base,点开它的ObjectFlags:

RF_Public | RF_Standalone | RF_Transaction | RF_WasLoaded | RF_LoadComplete

然后把这一串flag全部设为到我们自己要存取的副本上去。

可以推测缺陷被妥善解决了!

然后不须通过排除法,一个一个把flag去丢,不须度推测不可或缺在于:

RF_Standanlone

打算要自然资源尽可能被多次存取,尽可能在Runtime运转后来还能在Editor下总编副本,就必须设为这个flag。

3.5 基本概念那么为什么设为了RF_Standalone就可以消除Object被置自力呢?这就必须我们不须在实践中阅一下这个flag的提到,发觉显现出可疑的;也险恶去看。

这是侑虎科技第1465文章,表示感谢原作者佐味供稿。注目转发个人,未经原作者授权照样转载。如果您有任何精辟的立论或者推测也注目联系我们,一起探究。(QQ群:465082844)

原作者页面:「链接」

不须次表示感谢佐味的个人,如果您有任何精辟的立论或者推测也注目联系我们,一起探究。(QQ群:465082844)

来氟米特片副作用
关节炎疼痛如何缓解
痛风性关节炎怎么治
关节僵硬的治疗方法
英太青缓释胶囊和扶他林缓释片哪个好
“X杀手”踏入大好消息!Threads宣布已在欧盟正式上线

财联社12翌年15日讯(撰稿人 马兰)周四,Meta首席可执行扎克伯格宣布,交友该平台Threads并未在欧盟委员会南部上架。 ...

友情链接