예제 #1
0
            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();
            }
예제 #2
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;
        }