/** * Mounts a pak file at the specified path. * * @param InPakFilename Pak filename. * @param InPath Path to mount the pak at. */ boolMount(const TCHAR* InPakFilename, uint32 PakOrder, const TCHAR* InPath = NULL, bool bLoadIndex = true);
那么它是干什么的呢? 首先从 Mount 函数开始:
1 2 3 4
if (InPath != NULL) { Pak->SetMountPoint(InPath); }
如果在调用 Mount 时传递了 InPath,则通过加载 Pak 的 FPakFile 实例调用SetMountPoint,把 InPath 设置给它。 其实在 FPakFile 中,MountPath 是有默认值的(从 Pak 文件中读取),在 FPakFile 的构造函数中调用了 Initialize(Reader, bLoadIndex);,Initialize 中又调用了LoadIndex,在LoadIndex 中从 Pak 中读取 Pak 的 Mount Point 的逻辑:
// Runtime/PakFile/Private/IPlatformFilePak.cpp voidFPakFile::LoadIndex(FArchive* Reader) { if (CachedTotalSize < (Info.IndexOffset + Info.IndexSize)) { UE_LOG(LogPakFile, Fatal, TEXT("Corrupted index offset in pak file.")); } else { if (Info.Version >= FPakInfo::PakFile_Version_FrozenIndex && Info.bIndexIsFrozen) { SCOPED_BOOT_TIMING("PakFile_LoadFrozen");
// read frozen data Reader->Seek(Info.IndexOffset); int32 FrozenSize = Info.IndexSize;
// read in the index, etc data in one lump void* DataMemory = FMemory::Malloc(FrozenSize); Reader->Serialize(DataMemory, FrozenSize); Data = TUniquePtr<FPakFileData>((FPakFileData*)DataMemory);
// cache the number of entries NumEntries = Data->Files.Num(); // @todo loadtime: it is nice to serialize the mountpoint right into the Data so that IndexSize is right here // but it takes this to copy it out, because it's too painful for the string manipulation when dealing with // MemoryImageString everywhere MountPoint is used MountPoint = Data->MountPoint; } // ... } // ... }
简单的可以理解为:如果 Mount 时不传递 Mount Point 就会从 Pak 文件中读取,如果有传入就设置为传入的值(Pak 文件中的 MountPoint 是 Pak 中所有文件的公共路径)。
那么,给 Pak 设置 MountPoint 的作用是什么呢? 真实目的是,检测要加载的文件是否存在于当前 Pak 中!因为 Pak 的 Mount Point 的默认含义是当前 Pak 中所有文件的公共路径,所以只需要检测要读取的文件是否以这个路径开头,就可以首先排除掉基础路径不对的文件(基础路径都不对,意味着这个文件在 Pak 中也不存在)。
// Runtime/PakFile/Public/IPlatformFilePak.h /** * Finds a file in the specified pak files. * * @param Paks Pak files to find the file in. * @param Filename File to find in pak files. * @param OutPakFile Optional pointer to a pak file where the filename was found. * @return Pointer to pak entry if the file was found, NULL otherwise. */ staticboolFindFileInPakFiles(TArray<FPakListEntry>& Paks,const TCHAR* Filename,FPakFile** OutPakFile,FPakEntry* OutEntry = nullptr) { FString StandardFilename(Filename); FPaths::MakeStandardFilename(StandardFilename);
int32 DeletedReadOrder = -1;
for (int32 PakIndex = 0; PakIndex < Paks.Num(); PakIndex++) { int32 PakReadOrder = Paks[PakIndex].ReadOrder; if (DeletedReadOrder != -1 && DeletedReadOrder > PakReadOrder) { //found a delete record in a higher priority patch level, but now we're at a lower priority set - don't search further back or we'll find the original, old file. UE_LOG(LogPakFile, Verbose, TEXT("Delete Record: Accepted a delete record for %s"), Filename ); returnfalse; }
FPakFile::EFindResult FindResult = Paks[PakIndex].PakFile->Find(*StandardFilename, OutEntry); if (FindResult == FPakFile::EFindResult::Found) { if (OutPakFile != NULL) { *OutPakFile = Paks[PakIndex].PakFile; } UE_CLOG(DeletedReadOrder != -1, LogPakFile, Verbose, TEXT("Delete Record: Ignored delete record for %s - found it in %s instead (asset was moved between chunks)"), Filename, *Paks[PakIndex].PakFile->GetFilename()); returntrue; } elseif (FindResult == FPakFile::EFindResult::FoundDeleted) { DeletedReadOrder = PakReadOrder; UE_LOG(LogPakFile, Verbose, TEXT("Delete Record: Found a delete record for %s in %s"), Filename, *Paks[PakIndex].PakFile->GetFilename()); } }
UE_CLOG(DeletedReadOrder != -1, LogPakFile, Warning, TEXT("Delete Record: No lower priority pak files looking for %s. (maybe not downloaded?)"), Filename ); returnfalse; }
当我们从 Pak 中读取文件时,通过对游戏中所有 Mount 的 Pak 调用 Find 函数,而 FPakFile::Find 的函数就实现了上述我说的逻辑: