private bool LoadCache(ulong build) { if (!CacheFileExists(build)) { return(false); } using (Stream file = File.OpenRead(CacheFile(build))) using (LZ4Stream lz4Stream = new LZ4Stream(file, LZ4StreamMode.Decompress)) using (BinaryReader reader = new BinaryReader(lz4Stream)) { if (reader.ReadUInt64() != APM_VERSION) { return(false); } int packageEntryCount = PackageEntries.Length; Packages = reader.ReadArray <Types.Package>(packageEntryCount); Records = new Types.PackageRecord[packageEntryCount][]; PackageSiblings = new ulong[packageEntryCount][]; Types.CachePackageRecord[][] cacheRecords = new Types.CachePackageRecord[packageEntryCount][]; for (int i = 0; i < packageEntryCount; i++) { int recordCount = reader.ReadInt32(); cacheRecords[i] = reader.ReadArray <Types.CachePackageRecord>(recordCount); int siblingCount = reader.ReadInt32(); PackageSiblings[i] = reader.ReadArray <ulong>(siblingCount); } Parallel.For(0, packageEntryCount, new ParallelOptions { MaxDegreeOfParallelism = CASCConfig.MaxThreads }, i => { Types.CachePackageRecord[] cache = cacheRecords[i]; Records[i] = new Types.PackageRecord[cache.Length]; Types.Package package = Packages[i]; MD5Hash bundleLoadHash; if (package.BundleGUID != 0) { bundleLoadHash = CMF.Map[package.BundleGUID].HashKey; } for (int j = 0; j < cache.Length; j++) { Types.CachePackageRecord cacheRecord = cache[j]; ContentManifestFile.HashData cmfRecord = CMF.HashList[cacheRecord.Index]; Types.PackageRecord record = new Types.PackageRecord { GUID = cmfRecord.GUID, Size = cacheRecord.Size, Flags = cacheRecord.Flags, Offset = cacheRecord.Offset }; if ((record.Flags & ContentFlags.Bundle) != 0) { record.LoadHash = bundleLoadHash; } else { record.LoadHash = cmfRecord.HashKey; } if (!FirstOccurence.ContainsKey(record.GUID)) { FirstOccurence.TryAdd(record.GUID, record); } Records[i][j] = record; } }); } return(true); }
private void LoadPackages(CASCHandler casc, ProgressReportSlave worker) { int c = 0; Parallel.For(0, Header.PackageCount, new ParallelOptions { MaxDegreeOfParallelism = CASCConfig.MaxThreads }, i => { c++; if (c % 1000 == 0) { if (!Console.IsOutputRedirected) { Console.Out.Write($"Loading packages: {System.Math.Floor(c / (float)Header.PackageCount * 10000) / 100:F0}% ({c}/{Header.PackageCount})\r"); } worker?.ReportProgress((int)((float)c / Header.PackageCount * 100)); } Types.PackageEntry entry = PackageEntries[i]; if (!CMF.Map.ContainsKey(entry.PackageGUID)) { return; // lol? } EncodingEntry packageEncoding; if (!casc.EncodingHandler.GetEntry(CMF.Map[entry.PackageGUID].HashKey, out packageEncoding)) { return; } using (Stream packageStream = casc.OpenFile(packageEncoding.Key)) using (BinaryReader packageReader = new BinaryReader(packageStream)) { Packages[i] = packageReader.Read <Types.Package>(); if (CMFHeaderCommon.IsV22((uint)Header.Build)) // todo: hack //Packages[i].SiblingCount *= 2; { Packages[i].SiblingCount = 0; } if (Packages[i].SiblingCount > 0) { packageStream.Position = Packages[i].OffsetSiblings; PackageSiblings[i] = packageReader.ReadArray <ulong>((int)Packages[i].SiblingCount); } else { PackageSiblings[i] = new ulong[0]; } packageStream.Position = Packages[i].OffsetRecords; Types.PackageRecordRaw[] recordsRaw; using (GZipStream recordGunzipped = new GZipStream(packageStream, CompressionMode.Decompress)) using (BinaryReader recordReader = new BinaryReader(recordGunzipped)) { recordsRaw = recordReader.ReadArray <Types.PackageRecordRaw>((int)Packages[i].RecordCount); Records[i] = new Types.PackageRecord[Packages[i].RecordCount]; } for (uint j = 0; j < Packages[i].RecordCount; ++j) { Types.PackageRecordRaw rawRecord = recordsRaw[j]; ContentManifestFile.HashData recordCMF = CMF.Map[rawRecord.GUID]; Types.PackageRecord record = new Types.PackageRecord { GUID = rawRecord.GUID, Flags = rawRecord.Flags, Offset = rawRecord.Offset }; if (record.Flags.HasFlag(ContentFlags.Bundle)) { record.LoadHash = CMF.Map[Packages[i].BundleGUID].HashKey; } else { if (CMF.Map.ContainsKey(record.GUID)) { record.LoadHash = recordCMF.HashKey; } } record.Size = recordCMF.Size; if (!FirstOccurence.ContainsKey(record.GUID)) { FirstOccurence[record.GUID] = record; } Records[i][j] = record; } } }); }