private void Serialize() { Trace.Assert(_phase == LoadPhase.Serialize); _phase = LoadPhase.Complete; var Ar = (FAssetArchive)_archive.Clone(); Ar.SeekAbsolute(_export.SerialOffset, SeekOrigin.Begin); DeserializeObject(_object, Ar, _export.SerialSize); // TODO right place ??? _object.Flags |= EObjectFlags.RF_LoadCompleted; _object.PostLoad(); }
public IoPackage( FArchive uasset, IoGlobalData globalData, FIoContainerHeader?containerHeader = null, Lazy <FArchive?>?ubulk = null, Lazy <FArchive?>?uptnl = null, IFileProvider?provider = null, TypeMappings?mappings = null) : base(uasset.Name.SubstringBeforeLast('.'), provider, mappings) { GlobalData = globalData; var uassetAr = new FAssetArchive(uasset, this); FExportBundleHeader[] exportBundleHeaders; FExportBundleEntry[] exportBundleEntries; FPackageId[] importedPackageIds; int allExportDataOffset; if (uassetAr.Game >= EGame.GAME_UE5_0) { // Summary var summary = uassetAr.Read <FZenPackageSummary>(); Summary = new FPackageFileSummary { PackageFlags = summary.PackageFlags, TotalHeaderSize = summary.GraphDataOffset + (int)summary.HeaderSize, ExportCount = (summary.ExportBundleEntriesOffset - summary.ExportMapOffset) / FExportMapEntry.Size, ImportCount = (summary.ExportMapOffset - summary.ImportMapOffset) / FPackageObjectIndex.Size }; // Versioning info if (summary.bHasVersioningInfo != 0) { var versioningInfo = new FZenPackageVersioningInfo(uassetAr); Summary.FileVersionUE = versioningInfo.PackageVersion; Summary.FileVersionLicenseeUE = (EUnrealEngineObjectLicenseeUEVersion)versioningInfo.LicenseeVersion; Summary.CustomVersionContainer = versioningInfo.CustomVersions; if (!uassetAr.Versions.bExplicitVer) { uassetAr.Versions.Ver = versioningInfo.PackageVersion; uassetAr.Versions.CustomVersions = versioningInfo.CustomVersions.ToList(); } } else { Summary.bUnversioned = true; } // Name map NameMap = FNameEntrySerialized.LoadNameBatch(uassetAr); Summary.NameCount = NameMap.Length; Name = CreateFNameFromMappedName(summary.Name).Text; // Find store entry by package name FFilePackageStoreEntry?storeEntry = null; if (containerHeader != null) { var storeEntryIdx = Array.IndexOf(containerHeader.PackageIds, FPackageId.FromName(Name)); if (storeEntryIdx != -1) { storeEntry = containerHeader.StoreEntries[storeEntryIdx]; } else { Log.Warning("Couldn't find store entry for package {0}, its data will not be fully read", Name); } } // Imported public export hashes uassetAr.Position = summary.ImportedPublicExportHashesOffset; ImportedPublicExportHashes = uassetAr.ReadArray <ulong>((summary.ImportMapOffset - summary.ImportedPublicExportHashesOffset) / sizeof(ulong)); // Import map uassetAr.Position = summary.ImportMapOffset; ImportMap = uasset.ReadArray <FPackageObjectIndex>(Summary.ImportCount); // Export map uassetAr.Position = summary.ExportMapOffset; ExportMap = uasset.ReadArray(Summary.ExportCount, () => new FExportMapEntry(uassetAr)); ExportsLazy = new Lazy <UObject> [Summary.ExportCount]; // Export bundle entries uassetAr.Position = summary.ExportBundleEntriesOffset; exportBundleEntries = uassetAr.ReadArray <FExportBundleEntry>(Summary.ExportCount * 2); // Export bundle headers uassetAr.Position = summary.GraphDataOffset; var exportBundleHeadersCount = storeEntry?.ExportBundleCount ?? 1; exportBundleHeaders = uassetAr.ReadArray <FExportBundleHeader>(exportBundleHeadersCount); // We don't read the graph data importedPackageIds = storeEntry?.ImportedPackages ?? Array.Empty <FPackageId>(); allExportDataOffset = (int)summary.HeaderSize; } else { // Summary var summary = uassetAr.Read <FPackageSummary>(); Summary = new FPackageFileSummary { PackageFlags = summary.PackageFlags, TotalHeaderSize = summary.GraphDataOffset + summary.GraphDataSize, NameCount = summary.NameMapHashesSize / sizeof(ulong) - 1, ExportCount = (summary.ExportBundlesOffset - summary.ExportMapOffset) / FExportMapEntry.Size, ImportCount = (summary.ExportMapOffset - summary.ImportMapOffset) / FPackageObjectIndex.Size, bUnversioned = true }; // Name map uassetAr.Position = summary.NameMapNamesOffset; NameMap = FNameEntrySerialized.LoadNameBatch(uassetAr, Summary.NameCount); Name = CreateFNameFromMappedName(summary.Name).Text; // Import map uassetAr.Position = summary.ImportMapOffset; ImportMap = uasset.ReadArray <FPackageObjectIndex>(Summary.ImportCount); // Export map uassetAr.Position = summary.ExportMapOffset; ExportMap = uasset.ReadArray(Summary.ExportCount, () => new FExportMapEntry(uassetAr)); ExportsLazy = new Lazy <UObject> [Summary.ExportCount]; // Export bundles uassetAr.Position = summary.ExportBundlesOffset; LoadExportBundles(uassetAr, summary.GraphDataOffset - summary.ExportBundlesOffset, out exportBundleHeaders, out exportBundleEntries); // Graph data uassetAr.Position = summary.GraphDataOffset; importedPackageIds = LoadGraphData(uassetAr); allExportDataOffset = summary.GraphDataOffset + summary.GraphDataSize; } // Preload dependencies ImportedPackages = new Lazy <IoPackage?[]>(provider != null ? () => { var packages = new IoPackage?[importedPackageIds.Length]; for (int i = 0; i < importedPackageIds.Length; i++) { provider.TryLoadPackage(importedPackageIds[i], out packages[i]); } return(packages); } : Array.Empty <IoPackage?>); // Attach ubulk and uptnl if (ubulk != null) { uassetAr.AddPayload(PayloadType.UBULK, Summary.BulkDataStartOffset, ubulk); } if (uptnl != null) { uassetAr.AddPayload(PayloadType.UPTNL, Summary.BulkDataStartOffset, uptnl); } // Populate lazy exports var currentExportDataOffset = allExportDataOffset; foreach (var exportBundle in exportBundleHeaders) { for (var i = 0u; i < exportBundle.EntryCount; i++) { var entry = exportBundleEntries[exportBundle.FirstEntryIndex + i]; if (entry.CommandType == EExportCommandType.ExportCommandType_Serialize) { var localExportIndex = entry.LocalExportIndex; var export = ExportMap[localExportIndex]; var localExportDataOffset = currentExportDataOffset; ExportsLazy[localExportIndex] = new Lazy <UObject>(() => { // Create var obj = ConstructObject(ResolveObjectIndex(export.ClassIndex)?.Object?.Value as UStruct); obj.Name = CreateFNameFromMappedName(export.ObjectName).Text; obj.Outer = (ResolveObjectIndex(export.OuterIndex) as ResolvedExportObject)?.ExportObject.Value ?? this; obj.Super = ResolveObjectIndex(export.SuperIndex) as ResolvedExportObject; obj.Template = ResolveObjectIndex(export.TemplateIndex) as ResolvedExportObject; obj.Flags |= export.ObjectFlags; // We give loaded objects the RF_WasLoaded flag in ConstructObject, so don't remove it again in here // Serialize var Ar = (FAssetArchive)uassetAr.Clone(); Ar.AbsoluteOffset = (int)export.CookedSerialOffset - localExportDataOffset; Ar.Position = localExportDataOffset; DeserializeObject(obj, Ar, (long)export.CookedSerialSize); // TODO right place ??? obj.Flags |= EObjectFlags.RF_LoadCompleted; obj.PostLoad(); return(obj); }); currentExportDataOffset += (int)export.CookedSerialSize; } } } Summary.BulkDataStartOffset = currentExportDataOffset; IsFullyLoaded = true; }