public IoPackage( FArchive uasset, IoGlobalData globalData, 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 <FPackageSummary5>(); Summary = new FPackageFileSummary { PackageFlags = summary.PackageFlags, TotalHeaderSize = summary.GraphDataOffset + (int)summary.HeaderSize, ExportCount = (summary.ExportBundleEntriesOffset - summary.ExportMapOffset) / Unsafe.SizeOf <FExportMapEntry>(), ImportCount = (summary.ExportMapOffset - summary.ImportMapOffset) / FPackageObjectIndex.Size }; // Name map NameMap = FNameEntrySerialized.LoadNameBatch(uassetAr); Summary.NameCount = NameMap.Length; 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 <FExportMapEntry>(Summary.ExportCount); 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 = 1; // TODO just a placeholder until loading of package store entries are implemented exportBundleHeaders = uassetAr.ReadArray <FExportBundleHeader>(exportBundleHeadersCount); // We don't read the graph data importedPackageIds = Array.Empty <FPackageId>(); // TODO imported packages are now only stored in the package store entry, no longer in the graph data too 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) / Unsafe.SizeOf <FExportMapEntry>(), ImportCount = (summary.ExportMapOffset - summary.ImportMapOffset) / FPackageObjectIndex.Size }; // 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 <FExportMapEntry>(Summary.ExportCount); 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 |= (EObjectFlags)export.ObjectFlags; // We give loaded objects the RF_WasLoaded flag in ConstructObject, so don't remove it again in here // Serialize uassetAr.AbsoluteOffset = (int)export.CookedSerialOffset - localExportDataOffset; uassetAr.Seek(localExportDataOffset, SeekOrigin.Begin); DeserializeObject(obj, uassetAr, (long)export.CookedSerialSize); // TODO right place ??? obj.Flags |= EObjectFlags.RF_LoadCompleted; obj.PostLoad(); return(obj); }); currentExportDataOffset += (int)export.CookedSerialSize; } } } Summary.BulkDataStartOffset = currentExportDataOffset; }
public IoPackage( FArchive uasset, IoGlobalData globalData, Lazy <FArchive?>?ubulk = null, Lazy <FArchive?>?uptnl = null, IFileProvider?provider = null, TypeMappings?mappings = null) : base(uasset.Name.SubstringBeforeLast(".uasset"), provider, mappings) { if (provider == null) { throw new ParserException("Cannot load I/O store package without a file provider. This is needed to link the package imports."); } GlobalData = globalData; var uassetAr = new FAssetArchive(uasset, this); // Summary IoSummary = uassetAr.Read <FPackageSummary>(); Summary = new FPackageFileSummary { PackageFlags = (PackageFlags)IoSummary.PackageFlags, TotalHeaderSize = IoSummary.GraphDataOffset + IoSummary.GraphDataSize, NameCount = IoSummary.NameMapHashesSize / sizeof(ulong) - 1, ExportCount = (IoSummary.ExportBundlesOffset - IoSummary.ExportMapOffset) / Unsafe.SizeOf <FExportMapEntry>(), ImportCount = (IoSummary.ExportMapOffset - IoSummary.ImportMapOffset) / FPackageObjectIndex.Size }; // Name map uassetAr.Position = IoSummary.NameMapNamesOffset; NameMap = FNameEntrySerialized.LoadNameBatch(uassetAr, Summary.NameCount); Name = CreateFNameFromMappedName(IoSummary.Name).Text; // Import map uassetAr.Position = IoSummary.ImportMapOffset; ImportMap = uasset.ReadArray <FPackageObjectIndex>(Summary.ImportCount); // Export map uassetAr.Position = IoSummary.ExportMapOffset; ExportMap = uasset.ReadArray <FExportMapEntry>(Summary.ExportCount); ExportsLazy = new Lazy <UObject> [Summary.ExportCount]; // Export bundles uassetAr.Position = IoSummary.ExportBundlesOffset; LoadExportBundles(uassetAr, out var exportBundleHeaders, out var exportBundleEntries); // Graph data uassetAr.Position = IoSummary.GraphDataOffset; var importedPackageIds = LoadGraphData(uassetAr); // Preload dependencies ImportedPackages = new Lazy <IoPackage?[]>(() => { var packages = new IoPackage?[importedPackageIds.Length]; for (int i = 0; i < importedPackageIds.Length; i++) { provider.TryLoadPackage(importedPackageIds[i], out packages[i]); } return(packages); }); // 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 allExportDataOffset = IoSummary.GraphDataOffset + IoSummary.GraphDataSize; 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 objectName = CreateFNameFromMappedName(export.ObjectName); var obj = ConstructObject(ResolveObjectIndex(export.ClassIndex)?.Object?.Value as UStruct); obj.Name = objectName.Text; obj.Outer = (ResolveObjectIndex(export.OuterIndex) as ResolvedExportObject)?.ExportObject.Value ?? this; obj.Template = ResolveObjectIndex(export.TemplateIndex) as ResolvedExportObject; obj.Flags = (int)export.ObjectFlags; var exportType = obj.ExportType; // Serialize uassetAr.AbsoluteOffset = (int)export.CookedSerialOffset - localExportDataOffset; uassetAr.Seek(localExportDataOffset, SeekOrigin.Begin); var validPos = uassetAr.Position + (long)export.CookedSerialSize; try { obj.Deserialize(uassetAr, validPos); #if DEBUG if (validPos != uassetAr.Position) { Log.Warning("Did not read {0} correctly, {1} bytes remaining", exportType, validPos - uassetAr.Position); } else { Log.Debug("Successfully read {0} at {1} with size {2}", exportType, localExportDataOffset, export.CookedSerialSize); } #endif // TODO right place ??? obj.PostLoad(); } catch (Exception e) { Log.Error(e, "Could not read {0} correctly", exportType); } return(obj); }); currentExportDataOffset += (int)export.CookedSerialSize; } } } Summary.BulkDataStartOffset = currentExportDataOffset; }
public Package(FArchive uasset, FArchive?uexp, Lazy <FArchive?>?ubulk = null, Lazy <FArchive?>?uptnl = null, IFileProvider?provider = null, TypeMappings?mappings = null, bool useLazySerialization = true) : base(uasset.Name.SubstringBeforeLast(".uasset"), provider, mappings) { // We clone the version container because it can be modified with package specific versions when reading the summary uasset.Versions = (VersionContainer)uasset.Versions.Clone(); var uassetAr = new FAssetArchive(uasset, this); Summary = new FPackageFileSummary(uassetAr); uassetAr.SeekAbsolute(Summary.NameOffset, SeekOrigin.Begin); NameMap = new FNameEntrySerialized[Summary.NameCount]; uassetAr.ReadArray(NameMap, () => new FNameEntrySerialized(uassetAr)); uassetAr.SeekAbsolute(Summary.ImportOffset, SeekOrigin.Begin); ImportMap = new FObjectImport[Summary.ImportCount]; uassetAr.ReadArray(ImportMap, () => new FObjectImport(uassetAr)); uassetAr.SeekAbsolute(Summary.ExportOffset, SeekOrigin.Begin); ExportMap = new FObjectExport[Summary.ExportCount]; // we need this to get its final size in some case uassetAr.ReadArray(ExportMap, () => new FObjectExport(uassetAr)); FAssetArchive uexpAr = uexp != null ? new FAssetArchive(uexp, this, (int)uassetAr.Length) : uassetAr; // allows embedded uexp data if (ubulk != null) { //var offset = (int) (Summary.TotalHeaderSize + ExportMap.Sum(export => export.SerialSize)); var offset = Summary.BulkDataStartOffset; uexpAr.AddPayload(PayloadType.UBULK, offset, ubulk); } if (uptnl != null) { var offset = Summary.BulkDataStartOffset; uexpAr.AddPayload(PayloadType.UPTNL, offset, uptnl); } if (useLazySerialization) { foreach (var export in ExportMap) { export.ExportObject = new Lazy <UObject>(() => { // Create var obj = ConstructObject(ResolvePackageIndex(export.ClassIndex)?.Object?.Value as UStruct); obj.Name = export.ObjectName.Text; obj.Outer = (ResolvePackageIndex(export.OuterIndex) as ResolvedExportObject)?.Object.Value ?? this; obj.Super = ResolvePackageIndex(export.SuperIndex) as ResolvedExportObject; obj.Template = ResolvePackageIndex(export.TemplateIndex) as ResolvedExportObject; obj.Flags |= (EObjectFlags)export.ObjectFlags; // We give loaded objects the RF_WasLoaded flag in ConstructObject, so don't remove it again in here // Serialize uexpAr.SeekAbsolute(export.SerialOffset, SeekOrigin.Begin); DeserializeObject(obj, uexpAr, export.SerialSize); // TODO right place ??? obj.Flags |= EObjectFlags.RF_LoadCompleted; obj.PostLoad(); return(obj); }); } } else { var newObjNames = new List <string>(); foreach (var export in ExportMap) { if (export.ExportObject == null) { var obj = ConstructObject(ResolvePackageIndex(export.ClassIndex)?.Object?.Value as UStruct); obj.Name = export.ObjectName.Text; obj.Super = ResolvePackageIndex(export.SuperIndex) as ResolvedExportObject; obj.Template = ResolvePackageIndex(export.TemplateIndex) as ResolvedExportObject; obj.Flags |= (EObjectFlags)export.ObjectFlags; // We give loaded objects the RF_WasLoaded flag in ConstructObject, so don't remove it again in here export.ExportObject = new Lazy <UObject>(obj); newObjNames.Add(export.ObjectName.Text); } } foreach (var export in ExportMap) { if (newObjNames.Contains(export.ObjectName.Text)) { var obj = export.ExportObject.Value; uexpAr.SeekAbsolute(export.SerialOffset, SeekOrigin.Begin); DeserializeObject(obj, uexpAr, export.SerialSize); } } foreach (var export in ExportMap) { if (newObjNames.Contains(export.ObjectName.Text)) { var obj = export.ExportObject.Value; obj.Outer = (ResolvePackageIndex(export.OuterIndex) as ResolvedExportObject)?.Object.Value ?? this; } } foreach (var export in ExportMap) { if (newObjNames.Contains(export.ObjectName.Text)) { var obj = export.ExportObject.Value; obj.Flags |= EObjectFlags.RF_LoadCompleted; obj.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; }
public Package(FArchive uasset, FArchive uexp, Lazy <FArchive?>?ubulk = null, Lazy <FArchive?>?uptnl = null, IFileProvider?provider = null, TypeMappings?mappings = null) : base(uasset.Name.SubstringBeforeLast(".uasset"), provider, mappings) { var uassetAr = new FAssetArchive(uasset, this); Summary = new FPackageFileSummary(uassetAr); if (Summary.Tag != PackageMagic) { throw new ParserException(uassetAr, $"Invalid uasset magic: {Summary.Tag} != {PackageMagic}"); } uassetAr.Seek(Summary.NameOffset, SeekOrigin.Begin); NameMap = new FNameEntrySerialized[Summary.NameCount]; uassetAr.ReadArray(NameMap, () => new FNameEntrySerialized(uassetAr)); uassetAr.Seek(Summary.ImportOffset, SeekOrigin.Begin); ImportMap = new FObjectImport[Summary.ImportCount]; uassetAr.ReadArray(ImportMap, () => new FObjectImport(uassetAr)); uassetAr.Seek(Summary.ExportOffset, SeekOrigin.Begin); ExportMap = new FObjectExport[Summary.ExportCount]; // we need this to get its final size in some case uassetAr.ReadArray(ExportMap, () => new FObjectExport(uassetAr)); var uexpAr = new FAssetArchive(uexp, this, Summary.TotalHeaderSize); if (ubulk != null) { //var offset = (int) (Summary.TotalHeaderSize + ExportMap.Sum(export => export.SerialSize)); var offset = Summary.BulkDataStartOffset; uexpAr.AddPayload(PayloadType.UBULK, offset, ubulk); } if (uptnl != null) { var offset = Summary.BulkDataStartOffset; uexpAr.AddPayload(PayloadType.UPTNL, offset, uptnl); } foreach (var it in ExportMap) { if (ResolvePackageIndex(it.ClassIndex)?.Object?.Value is not UStruct uStruct) { continue; } var export = ConstructObject(uStruct); export.Name = it.ObjectName.Text; export.Outer = (ResolvePackageIndex(it.OuterIndex) as ResolvedExportObject)?.Object?.Value ?? this; export.Template = ResolvePackageIndex(it.TemplateIndex) as ResolvedExportObject; export.Flags = (int)it.ObjectFlags; it.ExportType = export.GetType(); it.ExportObject = new Lazy <UObject>(() => { uexpAr.SeekAbsolute(it.RealSerialOffset, SeekOrigin.Begin); var validPos = uexpAr.Position + it.SerialSize; try { export.Deserialize(uexpAr, validPos); #if DEBUG if (validPos != uexpAr.Position) { Log.Warning("Did not read {0} correctly, {1} bytes remaining", export.ExportType, validPos - uexpAr.Position); } else { Log.Debug("Successfully read {0} at {1} with size {2}", export.ExportType, it.RealSerialOffset, it.SerialSize); } #endif // TODO right place ??? export.PostLoad(); } catch (Exception e) { Log.Error(e, "Could not read {0} correctly", export.ExportType); } return(export); }); } }