public ProductHandler_Tank(ClientHandler client, Stream stream) { m_client = client; var clientArgs = client.CreateArgs.HandlerArgs as ClientCreateArgs_Tank ?? new ClientCreateArgs_Tank(); using (BinaryReader reader = new BinaryReader(stream)) { string str = Encoding.ASCII.GetString(reader.ReadBytes((int)stream.Length)); string[] array = str.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); if (ROOT_FILE_FIELD_ORDER_CHECK != array[0]) { throw new InvalidDataException($"ProductHandler_Tank: Root file field list mismatch ({array[0]})"); } m_rootFiles = new RootFile[array.Length - 1]; for (int i = 1; i < array.Length; i++) { m_rootFiles[i - 1] = new RootFile(array[i].Split('|')); } } if (!clientArgs.LoadManifest) { return; } int totalAssetCount = 0; foreach (RootFile rootFile in m_rootFiles.Reverse()) // cmf first, then apm { string extension = Path.GetExtension(rootFile.FileName); if (extension != ".cmf" && extension != ".apm" && extension != ".trg") { continue; } var manifestName = Path.GetFileNameWithoutExtension(rootFile.FileName); var manifestFileName = Path.GetFileName(rootFile.FileName); if (!manifestName.Contains(clientArgs.ManifestRegion ?? REGION_DEV)) { continue; // is a CN (china) CMF. todo: support this } var locale = GetManifestLocale(manifestName); // ReSharper disable once ConvertIfStatementToSwitchStatement if (extension == ".cmf") { bool speech = manifestName.Contains(SPEECH_MANIFEST_NAME); bool text = manifestName.Contains(TEXT_MANIFEST_NAME); if (speech) { if (locale != client.CreateArgs.SpeechLanguage) { continue; } } else if (locale != null) { // text or old root/text combo if (locale != client.CreateArgs.TextLanguage) { continue; } } ContentManifestFile cmf; //using (Stream file = File.OpenWrite($"{manifestName}.cmf")) { // cmfStream.CopyTo(file); //} try { using (Stream cmfStream = client.OpenCKey(rootFile.MD5)) cmf = new ContentManifestFile(client, cmfStream, manifestFileName); } catch (CryptographicException) { Logger.Error("CASC", OutdatedTACTLibErrorMessage); if (Debugger.IsAttached) { Debugger.Break(); } throw; } if (speech) { m_speechContentManifest = cmf; } else if (text) { m_textContentManifest = cmf; } else { m_rootContentManifest = cmf; } totalAssetCount += cmf.m_header.m_dataCount; } else if (extension == ".apm") { if (locale != client.CreateArgs.TextLanguage) { continue; } using (Stream apmStream = client.OpenCKey(rootFile.MD5)) m_packageManifest = new ApplicationPackageManifest(client, this, apmStream, manifestName); } else if (extension == ".trg") { try { using (Stream trgStream = client.OpenCKey(rootFile.MD5)) { //using (Stream file = File.OpenWrite($"{manifestName}.trg")) { // trgStream.CopyTo(file); //} m_resourceGraph = new ResourceGraph(client, trgStream, manifestFileName); } } catch (CryptographicException) { Logger.Error("CASC", OutdatedTACTLibErrorMessage); if (Debugger.IsAttached) { Debugger.Break(); } throw; } } } m_usingResourceGraph = m_rootContentManifest.m_header.m_buildVersion >= VERSION_148_PTR; m_assets = new ConcurrentDictionary <ulong, Asset>(Environment.ProcessorCount + 2, totalAssetCount); if (!m_usingResourceGraph) { for (int i = 0; i < m_packageManifest.m_header.m_packageCount; i++) { var records = m_packageManifest.m_packageRecords[i]; for (int j = 0; j < records.Length; j++) { var record = records[j]; //Console.Out.WriteLine($"{record.GUID:X8} {record.Unknown1} {record.Unknown2} {Manifests[0].ContentManifest.Exists(record.GUID)} {Manifests[1].ContentManifest.Exists(record.GUID)}"); if (m_assets.ContainsKey(record.m_GUID)) { continue; } m_assets[record.m_GUID] = new Asset(i, j); } } } RegisterCMFAssets(m_rootContentManifest, PACKAGE_IDX_FAKE_ROOT_CMF); RegisterCMFAssets(m_textContentManifest, PACKAGE_IDX_FAKE_TEXT_CMF); RegisterCMFAssets(m_speechContentManifest, PACKAGE_IDX_FAKE_SPEECH_CMF); if (m_usingResourceGraph) { m_hackedLookedUpBundles = new HashSet <ulong>(); m_hackedBundleLookup = new Dictionary <ulong, ulong>(); DoBundleLookupHack(); } }
public ProductHandler_Tank(ClientHandler client, Stream stream) { _client = client; var clientArgs = client.CreateArgs.HandlerArgs as ClientCreateArgs_Tank ?? new ClientCreateArgs_Tank(); using (BinaryReader reader = new BinaryReader(stream)) { string str = Encoding.ASCII.GetString(reader.ReadBytes((int)stream.Length)); string[] array = str.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); if (FieldOrderCheck != array[0]) { throw new InvalidDataException($"ProductHandler_Tank: Root file field list mismatch ({array[0]})"); } RootFiles = new RootFile[array.Length - 1]; for (int i = 1; i < array.Length; i++) { RootFiles[i - 1] = new RootFile(array[i].Split('|')); } } if (!clientArgs.LoadManifest) { return; } int totalAssetCount = 0; foreach (RootFile rootFile in RootFiles.Reverse()) // cmf first, then apm { string extension = Path.GetExtension(rootFile.FileName); if (extension != ".cmf" && extension != ".apm") { continue; } string manifestName = Path.GetFileNameWithoutExtension(rootFile.FileName); if (manifestName == null) { throw new InvalidDataException(); } if (!manifestName.Contains(RegionDev)) { continue; // is a CN (china?) CMF. todo: support this } var locale = GetManifestLocale(manifestName); // ReSharper disable once ConvertIfStatementToSwitchStatement if (extension == ".cmf") { bool speech = manifestName.Contains(SpeechManifestName); if (speech) { if (locale != client.CreateArgs.SpeechLanguage) { continue; } } else { if (locale != client.CreateArgs.TextLanguage) { continue; } } ContentManifestFile cmf; using (Stream cmfStream = client.OpenCKey(rootFile.MD5)) { try { cmf = new ContentManifestFile(client, cmfStream, $"{manifestName}.cmf"); } catch (CryptographicException) { Logger.Error("CASC", "Fatal - CMF decryption failed. Please update TACTLib."); if (Debugger.IsAttached) { Debugger.Break(); } throw; } } if (speech) { SpeechContentManifest = cmf; } else { MainContentManifest = cmf; } totalAssetCount += cmf.Header.DataCount; } else if (extension == ".apm") { if (locale != client.CreateArgs.TextLanguage) { continue; } using (Stream apmStream = client.OpenCKey(rootFile.MD5)) { PackageManifest = new ApplicationPackageManifest(client, this, apmStream, manifestName); } } } Assets = new ConcurrentDictionary <ulong, Asset>(Environment.ProcessorCount + 2, totalAssetCount); for (int i = 0; i < PackageManifest.Header.PackageCount; i++) { var records = PackageManifest.Records[i]; for (int j = 0; j < records.Length; j++) { var record = records[j]; //Console.Out.WriteLine($"{record.GUID:X8} {record.Unknown1} {record.Unknown2} {Manifests[0].ContentManifest.Exists(record.GUID)} {Manifests[1].ContentManifest.Exists(record.GUID)}"); if (Assets.ContainsKey(record.GUID)) { continue; } Assets[record.GUID] = new Asset(i, j); } } for (int i = 0; i < 2; i++) { ContentManifestFile contentManifestFile; int cmfId = -(i + 1); if (cmfId == -1) { contentManifestFile = MainContentManifest; } else if (cmfId == -2) { contentManifestFile = SpeechContentManifest; } else { throw new Exception("wat"); } // main = -1 // speech = -2 Parallel.For(0, contentManifestFile.HashList.Length, new ParallelOptions { MaxDegreeOfParallelism = 4 }, j => { var cmfAsset = contentManifestFile.HashList[j]; if (Assets.ContainsKey(cmfAsset.GUID)) { return; } Assets[cmfAsset.GUID] = new Asset(cmfId, j); }); } }