Ejemplo n.º 1
0
        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;
        }
Ejemplo n.º 2
0
        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;
        }
Ejemplo n.º 3
0
 public IoPackage(FArchive uasset, IoGlobalData globalData, FArchive?ubulk = null, FArchive?uptnl = null, IFileProvider?provider = null, TypeMappings?mappings = null)
     : this(uasset, globalData, ubulk != null ? new Lazy <FArchive?>(() => ubulk) : null, uptnl != null ? new Lazy <FArchive?>(() => uptnl) : null, provider, mappings)
 {
 }
Ejemplo n.º 4
0
        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;
        }