private static void Main() { InitTankSettings(); HookConsole(); var tools = GetTools(); #if DEBUG FlagParser.CheckCollisions(typeof(ToolFlags), (flag, duplicate) => { Logger.Error("Flag", $"The flag \"{flag}\" from {duplicate} is a duplicate!"); }); #endif FlagParser.LoadArgs(); Logger.Info("Core", $"{Assembly.GetExecutingAssembly().GetName().Name} v{Util.GetVersion(typeof(Program).Assembly)}"); Logger.Info("Core", $"CommandLine: [{string.Join(", ", FlagParser.AppArgs.Select(x => $"\"{x}\""))}]"); Flags = FlagParser.Parse <ToolFlags>(full => PrintHelp(full, tools)); if (Flags == null) { return; } Logger.Info("Core", $"CommandLineFile: {FlagParser.ArgFilePath}"); if (Flags.SaveArgs) { FlagParser.AppArgs = FlagParser.AppArgs.Where(x => !x.StartsWith("--arg")) .ToArray(); FlagParser.SaveArgs(Flags.OverwatchDirectory); } else if (Flags.ResetArgs || Flags.DeleteArgs) { FlagParser.ResetArgs(); if (Flags.DeleteArgs) { FlagParser.DeleteArgs(); } Logger.Info("Core", $"CommandLineNew: [{string.Join(", ", FlagParser.AppArgs.Select(x => $"\"{x}\""))}]"); Flags = FlagParser.Parse <ToolFlags>(full => PrintHelp(full, tools)); if (Flags == null) { return; } } if (string.IsNullOrWhiteSpace(Flags.OverwatchDirectory) || string.IsNullOrWhiteSpace(Flags.Mode) || Flags.Help) { PrintHelp(false, tools); return; } ITool targetTool = null; ICLIFlags targetToolFlags = null; ToolAttribute targetToolAttributes = null; #region Tool Activation foreach (var type in tools) { var attribute = type.GetCustomAttribute <ToolAttribute>(); if (!string.Equals(attribute.Keyword, Flags.Mode, StringComparison.InvariantCultureIgnoreCase)) { continue; } targetTool = Activator.CreateInstance(type) as ITool; targetToolAttributes = attribute; if (attribute.CustomFlags != null) { var flags = attribute.CustomFlags; if (typeof(ICLIFlags).IsAssignableFrom(flags)) { targetToolFlags = typeof(FlagParser).GetMethod(nameof(FlagParser.Parse), new Type[] { }) ?.MakeGenericMethod(flags) .Invoke(null, null) as ICLIFlags; } } break; } if (targetToolFlags == null) { return; } #endregion if (targetTool == null) { FlagParser.Help <ToolFlags>(false, new Dictionary <string, string>()); PrintHelp(false, tools); return; } if (!targetToolAttributes.UtilNoArchiveNeeded) { InitStorage(); //foreach (KeyValuePair<ushort, HashSet<ulong>> type in TrackedFiles.OrderBy(x => x.Key)) { // //Console.Out.WriteLine($"Found type: {type.Key:X4} ({type.Value.Count} files)"); // Console.Out.WriteLine($"Found type: {type.Key:X4}"); //} InitKeys(); InitMisc(); } var stopwatch = new Stopwatch(); Logger.Info("Core", "Tooling..."); stopwatch.Start(); targetTool.Parse(targetToolFlags); stopwatch.Stop(); Logger.Success("Core", $"Execution finished in {stopwatch.Elapsed} seconds"); ShutdownMisc(); }
private static void Main() { Console.OutputEncoding = Encoding.UTF8; Files = new Dictionary <ulong, PackageRecord>(); TrackedFiles = new Dictionary <ushort, HashSet <ulong> >(); #region Tool Detection HashSet <Type> tools = new HashSet <Type>(); { Assembly asm = typeof(ITool).Assembly; Type t = typeof(ITool); List <Type> types = asm.GetTypes().Where(tt => tt != t && t.IsAssignableFrom(tt)).ToList(); foreach (Type tt in types) { ToolAttribute attrib = tt.GetCustomAttribute <ToolAttribute>(); if (tt.IsInterface || attrib == null) { continue; } tools.Add(tt); if (attrib.TrackTypes == null) { continue; } foreach (ushort type in attrib.TrackTypes) { if (!TrackedFiles.ContainsKey(type)) { TrackedFiles[type] = new HashSet <ulong>(); } } } } #endregion Flags = FlagParser.Parse <ToolFlags>(() => PrintHelp(tools)); if (Flags == null) { return; } Logger.EXIT = !Flags.GracefulExit; ITool targetTool = null; ICLIFlags targetToolFlags = null; #region Tool Activation foreach (Type type in tools) { ToolAttribute attrib = type.GetCustomAttribute <ToolAttribute>(); if (!string.Equals(attrib.Keyword, Flags.Mode, StringComparison.InvariantCultureIgnoreCase)) { continue; } targetTool = Activator.CreateInstance(type) as ITool; if (attrib.CustomFlags != null) { Type flags = attrib.CustomFlags; if (typeof(ICLIFlags).IsAssignableFrom(flags)) { targetToolFlags = typeof(FlagParser).GetMethod("Parse", new Type[] { }).MakeGenericMethod(flags).Invoke(null, null) as ICLIFlags; } } break; } #endregion if (targetTool == null) { FlagParser.Help <ToolFlags>(false); PrintHelp(tools); if (Debugger.IsAttached) { Debugger.Break(); } return; } #region Initialize CASC Log("{0} v{1}", Assembly.GetExecutingAssembly().GetName().Name, Util.GetVersion()); Log("Initializing CASC..."); Log("Set language to {0}", Flags.Language); CDNIndexHandler.Cache.Enabled = Flags.UseCache; CDNIndexHandler.Cache.CacheData = Flags.CacheData; CDNIndexHandler.Cache.Validate = Flags.ValidateCache; // ngdp:us:pro // http:us:pro:us.patch.battle.net:1119 if (Flags.OverwatchDirectory.ToLowerInvariant().Substring(0, 5) == "ngdp:") { string cdn = Flags.OverwatchDirectory.Substring(5, 4); string[] parts = Flags.OverwatchDirectory.Substring(5).Split(':'); string region = "us"; string product = "pro"; if (parts.Length > 1) { region = parts[1]; } if (parts.Length > 2) { product = parts[2]; } if (cdn == "bnet") { Config = CASCConfig.LoadOnlineStorageConfig(product, region); } else { if (cdn == "http") { string host = string.Join(":", parts.Skip(3)); Config = CASCConfig.LoadOnlineStorageConfig(host, product, region, true, true, true); } } } else { Config = CASCConfig.LoadLocalStorageConfig(Flags.OverwatchDirectory, !Flags.SkipKeys, false); } Config.Languages = new HashSet <string>(new[] { Flags.Language }); #endregion foreach (Dictionary <string, string> build in Config.BuildInfo) { if (!build.ContainsKey("Tags")) { continue; } if (build["Tags"].Contains("XX?")) { IsPTR = true; } // us ptr region is known as XX, so just look for it in the tags. // this should work... untested for Asia } BuildVersion = uint.Parse(Config.BuildName.Split('.').Last()); if (Flags.SkipKeys) { Log("Disabling Key auto-detection..."); } Log("Using Overwatch Version {0}", Config.BuildName); CASC = CASCHandler.OpenStorage(Config); Root = CASC.Root as OwRootHandler; if (Root == null) { ErrorLog("Not a valid overwatch installation"); return; } // Fail when trying to extract data from a specified language with 2 or less files found. if (!Root.APMFiles.Any()) { ErrorLog("Could not find the files for language {0}. Please confirm that you have that language installed, and are using the names from the target language.", Flags.Language); if (!Flags.GracefulExit) { return; } } Log("Mapping..."); TrackedFiles[0x90] = new HashSet <ulong>(); IO.MapCMF(); IO.LoadGUIDTable(); Sound.WwiseBank.GetReady(); #region Key Detection if (!Flags.SkipKeys) { Log("Adding Encryption Keys..."); foreach (ulong key in TrackedFiles[0x90]) { if (!ValidKey(key)) { continue; } using (Stream stream = IO.OpenFile(Files[key])) { if (stream == null) { continue; } STUEncryptionKey encryptionKey = GetInstance <STUEncryptionKey>(key); if (encryptionKey != null && encryptionKey.LongKey != 0 && !KeyService.keys.ContainsKey(encryptionKey.LongRevKey)) { KeyService.keys.Add(encryptionKey.LongRevKey, encryptionKey.KeyValue); Log("Added Encryption Key {0}, Value: {1}", encryptionKey.KeyNameProper, encryptionKey.Key); } } } } #endregion Log("Tooling..."); targetTool.Parse(targetToolFlags); if (Debugger.IsAttached) { Debugger.Break(); } }
private static void Main() { AppDomain.CurrentDomain.UnhandledException += ExceptionHandler; Process.GetCurrentProcess().EnableRaisingEvents = true; AppDomain.CurrentDomain.ProcessExit += (sender, @event) => Console.ForegroundColor = ConsoleColor.Gray; Console.CancelKeyPress += (sender, @event) => Console.ForegroundColor = ConsoleColor.Gray; Console.OutputEncoding = Encoding.UTF8; Files = new Dictionary <ulong, ApplicationPackageManifest.Types.PackageRecord>(); TrackedFiles = new Dictionary <ushort, HashSet <ulong> >(); #region Tool Detection HashSet <Type> tools = new HashSet <Type>(); { Assembly asm = typeof(ITool).Assembly; Type t = typeof(ITool); List <Type> types = asm.GetTypes().Where(tt => tt != t && t.IsAssignableFrom(tt)).ToList(); foreach (Type tt in types) { ToolAttribute attrib = tt.GetCustomAttribute <ToolAttribute>(); if (tt.IsInterface || attrib == null) { continue; } tools.Add(tt); if (attrib.TrackTypes == null) { continue; } foreach (ushort type in attrib.TrackTypes) { if (!TrackedFiles.ContainsKey(type)) { TrackedFiles[type] = new HashSet <ulong>(); } } } } #endregion Flags = FlagParser.Parse <ToolFlags>(() => PrintHelp(tools)); if (Flags == null) { return; } //Logger.EXIT = !Flags.GracefulExit; ITool targetTool = null; ICLIFlags targetToolFlags = null; #region Tool Activation foreach (Type type in tools) { ToolAttribute attrib = type.GetCustomAttribute <ToolAttribute>(); if (!string.Equals(attrib.Keyword, Flags.Mode, StringComparison.InvariantCultureIgnoreCase)) { continue; } targetTool = Activator.CreateInstance(type) as ITool; if (attrib.CustomFlags != null) { Type flags = attrib.CustomFlags; if (typeof(ICLIFlags).IsAssignableFrom(flags)) { targetToolFlags = typeof(FlagParser).GetMethod(nameof(FlagParser.Parse), new Type[] { }).MakeGenericMethod(flags).Invoke(null, null) as ICLIFlags; } } break; } #endregion if (targetTool == null) { FlagParser.Help <ToolFlags>(false); PrintHelp(tools); if (Debugger.IsAttached) { Debugger.Break(); } return; } TankLib.Helpers.Logger.Info("Core", $"{Assembly.GetExecutingAssembly().GetName().Name} v{TankLib.Util.GetVersion(typeof(Program).Assembly)}"); TankLib.Helpers.Logger.Info("Core", $"CommandLine: [{string.Join(", ", Environment.GetCommandLineArgs().Skip(1).Select(x => $"\"{x}\""))}]"); #region Initialize CASC if (Flags.Language != null) { TankLib.Helpers.Logger.Info("CASC", $"Set language to {Flags.Language}"); } if (Flags.SpeechLanguage != null) { TankLib.Helpers.Logger.Info("CASC", $"Set speech language to {Flags.SpeechLanguage}"); } CASCHandler.Cache.CacheAPM = Flags.UseCache; CASCHandler.Cache.CacheCDN = Flags.UseCache; CASCHandler.Cache.CacheCDNData = Flags.CacheData; Config = CASCConfig.LoadFromString(Flags.OverwatchDirectory, Flags.SkipKeys); Config.SpeechLanguage = Flags.SpeechLanguage ?? Flags.Language ?? Config.SpeechLanguage; Config.TextLanguage = Flags.Language ?? Config.TextLanguage; if (Config != null) { if (Flags.Language != null && !Config.InstallData.Settings.Languages.Select(x => x.Language).Contains(Flags.Language)) { TankLib.Helpers.Logger.Warn("Core", "Battle.Net Agent reports that language {0} is not installed.", Flags.Language); } if (Config.InstallData.Uid != "prometheus") { TankLib.Helpers.Logger.Warn("Core", $"The branch \"{Config.InstallData.Uid}\" is not supported!. This might result in failure to load. Proceed with caution."); } } #endregion BuildVersion = uint.Parse(Config.BuildVersion.Split('.').Last()); if (BuildVersion < 39028) { TankLib.Helpers.Logger.Error("Core", "DataTool doesn't support Overwatch versions below 1.14. Please use OverTool"); } else if (BuildVersion < 39241) { TankLib.Helpers.Logger.Error("Core", "DataTool doesn't support this 1.14 release as it uses unmangeled hashes"); } else if (BuildVersion < 49154) { TankLib.Helpers.Logger.Error("Core", "This version of DataTool doesn't properly support versions below 1.26. Please downgrade DataTool."); } TankLib.Helpers.Logger.Info("Core", $"Using Overwatch Version {Config.BuildVersion}"); TankLib.Helpers.Logger.Info("CASC", "Initializing..."); CASC = CASCHandler.Open(Config); Root = CASC.RootHandler; //if (Root== null) { // ErrorLog("Not a valid overwatch installation"); // return; //} if (Config.InstallData != null) { } // Fail when trying to extract data from a specified language with 2 or less files found. if (!Root.APMFiles.Any()) { TankLib.Helpers.Logger.Error("Core", "Unable to load APM files for language {0}. Please confirm that you have that language installed.", Flags.Language); return; } TankLib.Helpers.Logger.Info("Core", "Mapping storage"); TrackedFiles[0x90] = new HashSet <ulong>(); IO.MapCMF(); IO.LoadGUIDTable(); Sound.WwiseBank.GetReady(); //foreach (KeyValuePair<ushort, HashSet<ulong>> type in TrackedFiles.OrderBy(x => x.Key)) { // //Console.Out.WriteLine($"Found type: {type.Key:X4} ({type.Value.Count} files)"); // Console.Out.WriteLine($"Found type: {type.Key:X4}"); //} #region Key Detection if (!Flags.SkipKeys) { TankLib.Helpers.Logger.Info("Core", "Checking ResourceKeys"); foreach (ulong key in TrackedFiles[0x90]) { if (!ValidKey(key)) { continue; } using (Stream stream = IO.OpenFile(Files[key])) { if (stream == null) { continue; } STUResourceKey resourceKey = GetInstance <STUResourceKey>(key); if (resourceKey == null || resourceKey.GetKeyID() == 0 || TACTKeyService.Keys.ContainsKey(resourceKey.GetReverseKeyID())) { continue; } TACTKeyService.Keys.Add(resourceKey.GetReverseKeyID(), resourceKey.m_key); TankLib.Helpers.Logger.Info("Core", $"Added ResourceKey {resourceKey.GetKeyIDString()}, Value: {resourceKey.GetKeyValueString()}"); } } } #endregion Stopwatch stopwatch = new Stopwatch(); TankLib.Helpers.Logger.Info("Core", "Tooling..."); var dbPath = Flags.ScratchDBPath; if (Flags.Deduplicate) { TankLib.Helpers.Logger.Warn("ScratchDB", "Will attempt to deduplicate files if extracting..."); if (!string.IsNullOrWhiteSpace(Flags.ScratchDBPath)) { TankLib.Helpers.Logger.Warn("ScratchDB", "Loading deduplication database..."); if (!File.Exists(dbPath)) { dbPath = Path.Combine(Path.GetFullPath(Flags.ScratchDBPath), "Scratch.db"); } SaveLogic.Combo.ScratchDBInstance.Load(dbPath); } } stopwatch.Start(); targetTool.Parse(targetToolFlags); stopwatch.Stop(); TankLib.Helpers.Logger.Success("Core", $"Execution finished in {stopwatch.Elapsed} seconds"); if (Flags.Deduplicate && !string.IsNullOrWhiteSpace(dbPath)) { TankLib.Helpers.Logger.Warn("ScratchDB", "Saving deduplication database..."); SaveLogic.Combo.ScratchDBInstance.Save(dbPath); } if (Debugger.IsAttached) { Debugger.Break(); } }