public void Parse(Dictionary <ushort, List <ulong> > track, Dictionary <ulong, Record> map, CASCHandler handler, bool quiet, OverToolFlags flags) { string[] baseArgs = Environment.GetCommandLineArgs(); List <string> args = new List <string>(); string[] origFlags = baseArgs.Where(x => x[0] == '-').ToArray(); args.Add(flags.Positionals[0]); Dictionary <string, string> tracking = new Dictionary <string, string>(); tracking[Opt.ToString()] = string.Empty; tracking[FullOpt] = string.Empty; foreach (string modeargument in flags.Positionals.Skip(2)) { string modearg = modeargument; string subargs = null; if (modearg.Contains('[')) { modearg = modearg.Substring(0, modearg.Length - 1); subargs = modearg.Substring(modearg.IndexOf('[') + 1); modearg = modearg.Substring(0, modearg.IndexOf('[')); } string[] modes = modearg.Split('+'); foreach (string mode in modes) { tracking[mode] = subargs; } } foreach (KeyValuePair <string, string> modes in tracking) { string mode = modes.Key; if ((mode.Length == 1 && mode[0] == Opt) || mode == FullOpt) { continue; } if (!Program.toolsMap.ContainsKey(mode)) { continue; } string subargs = modes.Value; string global = tracking[Opt.ToString()] + " " + tracking[FullOpt]; List <string> tmp = new List <string>(); tmp.Add(baseArgs[0]); tmp.Add(mode.ToString()); tmp.Add(global); tmp.Add(subargs); string[] newargs = CommandLineToArgs(string.Join(" ", tmp)); tmp.Clear(); tmp.AddRange(origFlags); tmp.AddRange(args); tmp.AddRange(newargs.Skip(1)); OverToolFlags newflags = FlagParser.Parse <OverToolFlags>(null, tmp.ToArray()); IOvertool tool = Program.toolsMap[mode]; tool.Parse(track, map, handler, quiet, newflags); } }
static void Main(string[] args) { Console.OutputEncoding = Encoding.UTF8; List <IOvertool> tools = new List <IOvertool>(); { Assembly asm = typeof(IOvertool).Assembly; Type t = typeof(IOvertool); List <Type> types = asm.GetTypes().Where(tt => tt != t && t.IsAssignableFrom(tt)).ToList(); foreach (Type tt in types) { if (tt.IsInterface) { continue; } IOvertool toolinst = (IOvertool)Activator.CreateInstance(tt); if (toolinst.Display) { tools.Add(toolinst); } } } OverToolFlags flags = FlagParser.Parse <OverToolFlags>(() => PrintHelp(tools)); if (flags == null) { return; } bool quiet = flags.Quiet; string root = flags.OverwatchDirectory; char opt = flags.Mode[0]; IOvertool tool = null; Dictionary <ushort, List <ulong> > track = new Dictionary <ushort, List <ulong> >(); track[0x90] = new List <ulong>(); // internal requirements toolsMap = new Dictionary <char, IOvertool>(); foreach (IOvertool t in tools) { if (t.Opt == opt) { tool = t; } foreach (ushort tr in t.Track) { if (!track.ContainsKey(tr)) { track[tr] = new List <ulong>(); } } if (toolsMap.ContainsKey(t.Opt)) { Console.Out.WriteLine("Duplicate opt! {0} conflicts with {1}", t.Title, toolsMap[t.Opt].Title); } toolsMap[t.Opt] = t; } if (tool == null || flags.Positionals.Length - 2 < tool.MinimumArgs) { PrintHelp(tools); return; } Dictionary <ulong, Record> map = new Dictionary <ulong, Record>(); Console.Out.WriteLine("{0} v{1}", Assembly.GetExecutingAssembly().GetName().Name, OWLib.Util.GetVersion()); Console.Out.WriteLine("Initializing CASC..."); Console.Out.WriteLine("Set language to {0}", flags.Language); CDNIndexHandler.Cache.Enabled = flags.UseCache; CDNIndexHandler.Cache.CacheData = flags.CacheData; CDNIndexHandler.Cache.Validate = flags.ValidateCache; CASCConfig config = null; // ngdp:us:pro // http:us:pro:us.patch.battle.net:1119 if (root.ToLowerInvariant().Substring(0, 5) == "ngdp:") { string cdn = root.Substring(5, 4); string[] parts = root.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(root, !flags.SkipKeys, false); } config.Languages = new HashSet <string>(new string[1] { flags.Language }); if (flags.SkipKeys) { Console.Out.WriteLine("Disabling Key auto-detection..."); } Console.Out.WriteLine("Using Overwatch Version {0}", config.BuildName); CASCHandler handler = CASCHandler.OpenStorage(config); OwRootHandler ow = handler.Root as OwRootHandler; if (ow == null) { Console.Error.WriteLine("Not a valid overwatch installation"); return; } // Fail when trying to extract data from a specified language with 2 or less files found. if (ow.APMFiles.Count() == 0) { Console.Error.WriteLine("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); return; } Console.Out.WriteLine("Mapping..."); Util.MapCMF(ow, handler, map, track, flags); if (!flags.SkipKeys) { Console.Out.WriteLine("Adding Encryption Keys..."); foreach (ulong key in track[0x90]) { if (!map.ContainsKey(key)) { continue; } using (Stream stream = Util.OpenFile(map[key], handler)) { if (stream == null) { continue; } STUD stud = new STUD(stream); if (stud.Instances[0].Name != stud.Manager.GetName(typeof(EncryptionKey))) { continue; } EncryptionKey ek = (EncryptionKey)stud.Instances[0]; if (!KeyService.keys.ContainsKey(ek.KeyNameLong)) { KeyService.keys.Add(ek.KeyNameLong, ek.KeyValueText.ToByteArray()); Console.Out.WriteLine("Added Encryption Key {0}, Value: {1}", ek.KeyNameText, ek.KeyValueText); } } } } Console.Out.WriteLine("Tooling..."); tool.Parse(track, map, handler, quiet, flags); if (System.Diagnostics.Debugger.IsAttached) { System.Diagnostics.Debugger.Break(); } }
public void Parse(Dictionary <ushort, List <ulong> > track, Dictionary <ulong, Record> map, CASCHandler handler, bool quiet, OverToolFlags flags) { List <ulong> masters = track[0x75]; foreach (ulong masterKey in masters) { if (!map.ContainsKey(masterKey)) { continue; } STUD masterStud = new STUD(Util.OpenFile(map[masterKey], handler)); if (masterStud.Instances == null) { continue; } HeroMaster master = (HeroMaster)masterStud.Instances[0]; if (master == null) { continue; } string heroName = Util.GetString(master.Header.name.key, map, handler); if (heroName == null) { continue; } if (master.Header.itemMaster.key != 0) // AI { InventoryMaster inventory = Extract.OpenInventoryMaster(master, map, handler); if (inventory.ItemGroups.Length > 0 || inventory.DefaultGroups.Length > 0) { continue; } } Console.Out.WriteLine("{0} {1:X}", heroName, GUID.LongKey(masterKey)); } }
public void Parse(Dictionary <ushort, List <ulong> > track, Dictionary <ulong, Record> map, CASCHandler handler, bool quiet, OverToolFlags flags) { List <ulong> masters = track[0x75]; foreach (ulong masterKey in masters) { if (!map.ContainsKey(masterKey)) { continue; } STUD masterStud = new STUD(Util.OpenFile(map[masterKey], handler)); if (masterStud.Instances == null) { continue; } HeroMaster master = (HeroMaster)masterStud.Instances[0]; if (master == null) { continue; } string heroName = Util.GetString(master.Header.name.key, map, handler); if (heroName == null) { continue; } string goodhero = heroName; foreach (var c in Path.GetInvalidFileNameChars()) { goodhero = goodhero.Replace(c, '_'); } if (master.Header.itemMaster.key == 0) // AI { continue; } bool ex = System.Diagnostics.Debugger.IsAttached || flags.Expert; if (ex) { Console.Out.WriteLine("Cosmetics for {0} ({1:X16})", heroName, GUID.LongKey(masterKey)); } else { Console.Out.WriteLine("Cosmetics for {0}", heroName); } if (!map.ContainsKey(master.Header.itemMaster.key)) { Console.Out.WriteLine("Error loading inventory master file..."); continue; } STUD inventoryStud = new STUD(Util.OpenFile(map[master.Header.itemMaster.key], handler)); #if OUTPUT_STUDINVENTORYMASTER Stream studStream = Util.OpenFile(map[master.Header.itemMaster.key], handler); string outFilename = string.Format("./STUDs/ListInventoryMaster/{0}.stud", goodhero); string putPathname = outFilename.Substring(0, outFilename.LastIndexOf('/')); Directory.CreateDirectory(putPathname); Stream OutWriter = File.Create(outFilename); studStream.CopyTo(OutWriter); OutWriter.Close(); studStream.Close(); #endif InventoryMaster inventory = (InventoryMaster)inventoryStud.Instances[0]; if (inventory == null) { Console.Out.WriteLine("Error loading inventory master file..."); continue; } Console.Out.WriteLine("\tACHIEVEMENT ({0} items)", inventory.Achievables.Length); foreach (OWRecord record in inventory.Achievables) { GetInventoryName(record.key, ex, map, handler, goodhero); } for (int i = 0; i < inventory.DefaultGroups.Length; ++i) { if (inventory.Defaults[i].Length == 0) { continue; } OWRecord[] records = inventory.Defaults[i]; Console.Out.WriteLine("\tSTANDARD_{0} ({1} items)", ItemEvents.GetInstance().GetEvent(inventory.DefaultGroups[i].@event), records.Length); foreach (OWRecord record in records) { GetInventoryName(record.key, ex, map, handler, goodhero); } } for (int i = 0; i < inventory.ItemGroups.Length; ++i) { if (inventory.Items[i].Length == 0) { continue; } OWRecord[] records = inventory.Items[i]; Console.Out.WriteLine("\t{0} ({1} items)", ItemEvents.GetInstance().GetEvent(inventory.ItemGroups[i].@event), records.Length); foreach (OWRecord record in records) { GetInventoryName(record.key, ex, map, handler, goodhero); } } Console.Out.WriteLine(""); } }
public void Parse(Dictionary <ushort, List <ulong> > track, Dictionary <ulong, Record> map, CASCHandler handler, bool quiet, OverToolFlags flags) { string output = flags.Positionals[2]; foreach (ulong key in track[0x54]) { if (!map.ContainsKey(key)) { continue; } Dictionary <OWRecord, string> items = new Dictionary <OWRecord, string>(); using (Stream input = Util.OpenFile(map[key], handler)) { if (input == null) { continue; } STUD stud = new STUD(input); if (stud.Instances == null || stud.Instances[0] == null) { continue; } GlobalInventoryMaster master = stud.Instances[0] as GlobalInventoryMaster; if (master == null) { continue; } foreach (OWRecord record in master.StandardItems) { items[record] = "ACHIEVEMENT"; } for (int i = 0; i < master.Generic.Length; ++i) { string name = $"STANDARD_{ItemEvents.GetInstance().GetEvent(master.Generic[i].@event)}"; for (int j = 0; j < master.GenericItems[i].Length; ++j) { items[master.GenericItems[i][j]] = name; } } for (int i = 0; i < master.Categories.Length; ++i) { string name = ItemEvents.GetInstance().GetEvent(master.Categories[i].@event); for (int j = 0; j < master.CategoryItems[i].Length; ++j) { items[master.CategoryItems[i][j]] = name; } } for (int i = 0; i < master.ExclusiveOffsets.Length; ++i) { string name = $"LOOTBOX_EXCLUSIVE_{i:X}"; for (int j = 0; j < master.LootboxExclusive[i].Length; ++j) { items[master.LootboxExclusive[i][j].item] = name; } } } foreach (KeyValuePair <OWRecord, string> recordname in items) { OWRecord record = recordname.Key; string itemGroup = recordname.Value; if (!map.ContainsKey(record.key)) { continue; } STUD stud = new STUD(Util.OpenFile(map[record.key], handler)); if (stud.Instances == null) { continue; } IInventorySTUDInstance instance = (IInventorySTUDInstance)stud.Instances[0]; string name = Util.GetString(instance.Header.name.key, map, handler); if (name == null) { name = $"{GUID.LongKey(key):X12}"; } switch (instance.Name) { case "Spray": Console.Out.WriteLine("Extracting spray {0}...", name); ExtractLogic.Spray.Extract(stud, output, "Generic", name, itemGroup, track, map, handler, quiet, flags); break; case "Icon": Console.Out.WriteLine("Extracting icon {0}...", name); ExtractLogic.Icon.Extract(stud, output, "Generic", name, itemGroup, track, map, handler, quiet, flags); break; case "Portrait": PortraitItem portrait = instance as PortraitItem; ExtractLogic.Portrait.Extract(stud, output, "Generic", $"Tier {portrait.Data.tier}", itemGroup, track, map, handler, quiet, flags); break; default: continue; } } } }
public void Parse(Dictionary <ushort, List <ulong> > track, Dictionary <ulong, Record> map, CASCHandler handler, bool quiet, OverToolFlags flags) { foreach (ulong key in track[0x54]) { if (!map.ContainsKey(key)) { continue; } Dictionary <OWRecord, string> items = new Dictionary <OWRecord, string>(); using (Stream input = Util.OpenFile(map[key], handler)) { if (input == null) { continue; } STUD stud = new STUD(input); if (stud.Instances == null || stud.Instances[0] == null) { continue; } GlobalInventoryMaster master = stud.Instances[0] as GlobalInventoryMaster; if (master == null) { continue; } Console.Out.WriteLine("\tACHIEVEMENT"); foreach (OWRecord record in master.StandardItems) { ListInventory.GetInventoryName(record.key, false, map, handler, "General"); } Dictionary <string, List <OWRecord> > aggreg = new Dictionary <string, List <OWRecord> >(); for (int i = 0; i < master.Generic.Length; ++i) { if (master.GenericItems[i].Length == 0) { continue; } string s = $"\tSTANDARD_{ItemEvents.GetInstance().GetEvent(master.Generic[i].@event)}"; if (!aggreg.ContainsKey(s)) { aggreg[s] = new List <OWRecord>(); } for (int j = 0; j < master.GenericItems[i].Length; ++j) { aggreg[s].Add(master.GenericItems[i][j]); } } foreach (KeyValuePair <string, List <OWRecord> > pair in aggreg) { Console.Out.WriteLine(pair.Key); foreach (OWRecord record in pair.Value) { ListInventory.GetInventoryName(record, false, map, handler, "General"); } } aggreg.Clear(); for (int i = 0; i < master.Categories.Length; ++i) { if (master.CategoryItems[i].Length == 0) { continue; } Console.Out.WriteLine($"\t{ItemEvents.GetInstance().GetEvent(master.Categories[i].@event)}"); for (int j = 0; j < master.CategoryItems[i].Length; ++j) { ListInventory.GetInventoryName(master.CategoryItems[i][j], false, map, handler, "General"); } } for (int i = 0; i < master.ExclusiveOffsets.Length; ++i) { if (master.LootboxExclusive[i].Length == 0) { continue; } Console.Out.WriteLine($"\tLOOTBOX_EXCLUSIVE_{ItemEvents.GetInstance().GetEvent((ulong)i)}"); for (int j = 0; j < master.LootboxExclusive[i].Length; ++j) { ListInventory.GetInventoryName(master.LootboxExclusive[i][j].item, false, map, handler, "General"); } } } } }
public void Parse(Dictionary <ushort, List <ulong> > track, Dictionary <ulong, Record> map, CASCHandler handler, bool quiet, OverToolFlags flags) { List <ulong> masters = track[0x75]; List <ulong> blank = new List <ulong>(); Dictionary <ulong, ulong> blankdict = new Dictionary <ulong, ulong>(); List <string> extract = new List <string>(); for (int i = 3; i < flags.Positionals.Length; ++i) { extract.Add(flags.Positionals[i].ToLowerInvariant()); } foreach (ulong masterKey in masters) { if (!map.ContainsKey(masterKey)) { continue; } STUD masterStud = new STUD(Util.OpenFile(map[masterKey], handler)); if (masterStud.Instances == null) { continue; } HeroMaster master = (HeroMaster)masterStud.Instances[0]; if (master == null) { continue; } string heroName = Util.GetString(master.Header.name.key, map, handler); if (heroName == null) { continue; } if (extract.Count > 0 && !extract.Contains(heroName.ToLowerInvariant())) { continue; } if (master.Header.itemMaster.key != 0) // AI { InventoryMaster inventory = Extract.OpenInventoryMaster(master, map, handler); if (inventory.ItemGroups.Length > 0 || inventory.DefaultGroups.Length > 0) { continue; } } Console.Out.WriteLine("{0} {1:X}", heroName, GUID.Index(masterKey)); string path = string.Format("{0}{1}{2}{1}{3:X}{1}", flags.Positionals[2], Path.DirectorySeparatorChar, Util.Strip(Util.SanitizePath(heroName)), GUID.LongKey(masterKey)); HashSet <ulong> models = new HashSet <ulong>(); Dictionary <ulong, ulong> animList = new Dictionary <ulong, ulong>(); HashSet <ulong> parsed = new HashSet <ulong>(); Dictionary <ulong, List <ImageLayer> > layers = new Dictionary <ulong, List <ImageLayer> >(); Dictionary <ulong, List <ulong> > sound = new Dictionary <ulong, List <ulong> >(); ExtractLogic.Skin.FindModels(master.Header.binding, blank, models, animList, layers, blankdict, parsed, map, handler, sound); ExtractLogic.Skin.Save(master, path, heroName, $"{GUID.LongKey(masterKey):X}", blankdict, parsed, models, layers, animList, flags, track, map, handler, masterKey, false, quiet, sound, 0); } }
public void Parse(Dictionary <ushort, List <ulong> > track, Dictionary <ulong, Record> map, CASCHandler handler, bool quiet, OverToolFlags flags) { Console.Out.WriteLine(" BE : LE : SWP"); Dictionary <ushort, ushort> types = new Dictionary <ushort, ushort>(); foreach (ulong key in map.Keys) { ushort normal = (ushort)(key >> 48); ushort guid = GUID.Type(key); if (!types.ContainsKey(normal)) { types[normal] = guid; } } foreach (KeyValuePair <ushort, ushort> type in types) { ushort be = type.Key; ushort le = (ushort)(((be & 0xFF) << 8) + ((be & 0xFF00) >> 8)); ushort swp = type.Value; Console.Out.WriteLine("{0:X4} : {1:X4} : {2:X3}", le, be, swp); } }
public void Parse(Dictionary <ushort, List <ulong> > track, Dictionary <ulong, Record> map, CASCHandler handler, bool quiet, OverToolFlags flags) { string output = flags.Positionals[2]; HashSet <string> heroes = new HashSet <string>(); HashSet <string> heroBlank = new HashSet <string>(); Dictionary <string, HashSet <string> > heroSkin = new Dictionary <string, HashSet <string> >(); bool heroAllWildcard = false; if (flags.Positionals.Length > 3 && flags.Positionals[1] != "*") { foreach (string name in flags.Positionals[3].ToLowerInvariant().Split(new char[] { '+' }, StringSplitOptions.RemoveEmptyEntries)) { string[] data = name.Split(new char[] { '=' }, StringSplitOptions.RemoveEmptyEntries); string realname = data[0]; heroes.Add(realname); data = data.Skip(1).ToArray(); if (data.Length == 0) { heroBlank.Add(realname); continue; } heroSkin[realname] = new HashSet <string>(); foreach (string skin in data) { heroSkin[realname].Add(skin); } } } else { heroAllWildcard = true; } List <ulong> masters = track[0x75]; foreach (ulong masterKey in masters) { if (!map.ContainsKey(masterKey)) { continue; } STUD masterStud = new STUD(Util.OpenFile(map[masterKey], handler)); if (masterStud.Instances == null) { continue; } HeroMaster master = (HeroMaster)masterStud.Instances[0]; if (master == null) { continue; } if (master.Header.itemMaster.key == 0) { continue; } string heroName = Util.GetString(master.Header.name.key, map, handler); if (heroName == null) { continue; } if (heroAllWildcard) { heroes.Add(heroName.ToLowerInvariant()); heroBlank.Add(heroName.ToLowerInvariant()); } if (!heroes.Contains(heroName.ToLowerInvariant())) { continue; } InventoryMaster inventory = OpenInventoryMaster(master, map, handler); if (inventory == null) { continue; } Dictionary <OWRecord, string> items = new Dictionary <OWRecord, string>(); foreach (OWRecord record in inventory.Achievables) { items[record] = "ACHIEVEMENT"; } for (int i = 0; i < inventory.DefaultGroups.Length; ++i) { string name = $"STANDARD_{ItemEvents.GetInstance().GetEvent(inventory.DefaultGroups[i].@event)}"; for (int j = 0; j < inventory.Defaults[i].Length; ++j) { items[inventory.Defaults[i][j]] = name; } } for (int i = 0; i < inventory.ItemGroups.Length; ++i) { string name = ItemEvents.GetInstance().GetEvent(inventory.ItemGroups[i].@event); for (int j = 0; j < inventory.Items[i].Length; ++j) { items[inventory.Items[i][j]] = name; } } Dictionary <string, WeaponSkinItem> weaponskins = new Dictionary <string, WeaponSkinItem>(); Console.Out.WriteLine("Finding weapon skins for {0}", heroName); foreach (KeyValuePair <OWRecord, string> recordname in items) { OWRecord record = recordname.Key; string itemGroup = recordname.Value; if (!map.ContainsKey(record.key)) { continue; } STUD stud = new STUD(Util.OpenFile(map[record.key], handler)); if (stud.Instances == null) { continue; } IInventorySTUDInstance instance = (IInventorySTUDInstance)stud.Instances[0]; WeaponSkinItem weapon = instance as WeaponSkinItem; if (weapon == null) { continue; } if (weapon.Data.index == 0) { continue; } string name = Util.GetString(instance.Header.name.key, map, handler); if (name == null) { name = $"Untitled-{GUID.LongKey(instance.Header.name.key):X12}"; continue; } weaponskins[name] = weapon; Console.Out.WriteLine("Found data for weapon skin {0}", name); } foreach (KeyValuePair <OWRecord, string> recordname in items) { OWRecord record = recordname.Key; string itemGroup = recordname.Value; if (!map.ContainsKey(record.key)) { continue; } STUD stud = new STUD(Util.OpenFile(map[record.key], handler)); if (stud.Instances == null) { continue; } IInventorySTUDInstance instance = (IInventorySTUDInstance)stud.Instances[0]; SkinItem skin = instance as SkinItem; if (skin == null) { continue; } string name = Util.GetString(instance.Header.name.key, map, handler); if (name == null) { name = $"Untitled-{GUID.LongKey(instance.Header.name.key):X12}"; continue; } if (heroBlank.Contains(heroName.ToLowerInvariant()) || heroSkin[heroName.ToLowerInvariant()].Contains(name.ToLowerInvariant())) { Console.Out.WriteLine("Saving textures for skin {0}", name); foreach (KeyValuePair <string, WeaponSkinItem> pair in weaponskins) { string output_real = string.Format("{0}{1}{4}{1}Weapon Skin{1}{2}{1}{3}{1}", output, System.IO.Path.DirectorySeparatorChar, Util.SanitizePath(pair.Key), Util.SanitizePath(name), Util.SanitizePath(heroName)); Dictionary <ulong, ulong> replace = new Dictionary <ulong, ulong>(); ExtractLogic.Skin.FindReplacements(skin.Data.skin.key, (int)pair.Value.Data.index, replace, new HashSet <ulong>(), map, handler, master, skin, true); Dictionary <ulong, ulong> replace_blank = new Dictionary <ulong, ulong>(); ExtractLogic.Skin.FindReplacements(skin.Data.skin.key, -1, replace_blank, new HashSet <ulong>(), map, handler, master, skin, false); if (replace.Values.Count == 0) { continue; } Dictionary <ulong, List <ImageLayer> > layers = new Dictionary <ulong, List <ImageLayer> >(); Dictionary <ulong, List <ImageLayer> > layers_orig = new Dictionary <ulong, List <ImageLayer> >(); foreach (KeyValuePair <ulong, ulong> texture_pair in replace) { ushort type = GUID.Type(texture_pair.Key); switch (type) { case 0x1A: ExtractLogic.Skin.FindTextures(texture_pair.Value, layers, replace, new HashSet <ulong>(), map, handler); if (replace_blank.ContainsKey(texture_pair.Key)) { ExtractLogic.Skin.FindTextures(replace_blank[texture_pair.Key], layers_orig, replace_blank, new HashSet <ulong>(), map, handler); } else { ExtractLogic.Skin.FindTextures(texture_pair.Key, layers_orig, replace_blank, new HashSet <ulong>(), map, handler); } break; } } Dictionary <ulong, HashSet <ulong> > origTextures = new Dictionary <ulong, HashSet <ulong> >(); foreach (KeyValuePair <ulong, List <ImageLayer> > kv in layers_orig) { ulong materialId = kv.Key; List <ImageLayer> sublayers = kv.Value; HashSet <ulong> materialParsed = new HashSet <ulong>(); if (!origTextures.ContainsKey(materialId)) { origTextures[materialId] = new HashSet <ulong>(); } foreach (ImageLayer layer in sublayers) { origTextures[materialId].Add(layer.key); } } foreach (KeyValuePair <ulong, List <ImageLayer> > kv in layers) { ulong materialId = kv.Key; List <ImageLayer> sublayers = kv.Value; HashSet <ulong> materialParsed = new HashSet <ulong>(); foreach (ImageLayer layer in sublayers) { if (!materialParsed.Add(layer.key)) { continue; } if (origTextures.ContainsKey(materialId) && origTextures[materialId].Contains(layer.key)) { continue; } ExtractLogic.Skin.SaveTexture(layer.key, materialId, map, handler, output_real, quiet, ""); } } } } } } }
public void Parse(Dictionary <ushort, List <ulong> > track, Dictionary <ulong, Record> map, CASCHandler handler, bool quiet, OverToolFlags flags) { List <ulong> ids = new List <ulong>(); foreach (string arg in flags.Positionals.Skip(2)) { ids.Add(ulong.Parse(arg.Split('.')[0], System.Globalization.NumberStyles.HexNumber)); } Console.Out.WriteLine("Scanning for textures..."); foreach (ulong f003 in track[0x3]) { STUD record = new STUD(Util.OpenFile(map[f003], handler), true, STUDManager.Instance, false, true); if (record.Instances == null) { continue; } foreach (ISTUDInstance instance in record.Instances) { if (instance == null) { continue; } if (instance.Name == record.Manager.GetName(typeof(ComplexModelRecord))) { ComplexModelRecord r = (ComplexModelRecord)instance; if (ids.Contains(GUID.LongKey(r.Data.model.key))) { Dictionary <ulong, List <ImageLayer> > layers = new Dictionary <ulong, List <ImageLayer> >(); ExtractLogic.Skin.FindTextures(r.Data.material.key, layers, new Dictionary <ulong, ulong>(), new HashSet <ulong>(), map, handler); Console.Out.WriteLine("Model ID {0:X12}", GUID.LongKey(r.Data.model.key)); foreach (KeyValuePair <ulong, List <ImageLayer> > pair in layers) { Console.Out.WriteLine("Material ID {0:X16}", pair.Key); HashSet <ulong> dedup = new HashSet <ulong>(); foreach (ImageLayer layer in pair.Value) { if (dedup.Add(layer.Key)) { Console.Out.WriteLine("Texture ID {0:X12}", GUID.LongKey(layer.Key)); } } } ids.Remove(GUID.LongKey(r.Data.model.key)); } } } } }
public void Parse(Dictionary <ushort, List <ulong> > track, Dictionary <ulong, Record> map, CASCHandler handler, bool quiet, OverToolFlags flags) { switch (flags.Positionals[2].ToLowerInvariant()) { case "list": { DeltaFile old = new DeltaFile(flags.Positionals[3]); DeltaFile @new = new DeltaFile(flags.Positionals[4]); if (string.IsNullOrEmpty(old.Name) || old.Files.Count == 0) { Console.Error.WriteLine("Invalid old file"); } else if (string.IsNullOrEmpty(@new.Name) || @new.Files.Count == 0) { Console.Error.WriteLine("Invalid new file"); } else { Console.Out.WriteLine("Comparing {0} with {1}", old.Name, @new.Name); foreach (KeyValuePair <ulong, int> pair in @new.Files) { if (old.Files.ContainsKey(pair.Key)) { if (old.Files[pair.Key] == pair.Value) { continue; } Console.Out.WriteLine("{0:X12}.{1:X3} changed ({2} bytes)", GUID.LongKey(pair.Key), GUID.Type(pair.Key), old.Files[pair.Key] - pair.Value); } else { Console.Out.WriteLine("{0:X12}.{1:X3} added ({2} bytes)", GUID.LongKey(pair.Key), GUID.Type(pair.Key), pair.Value); } } foreach (KeyValuePair <ulong, int> pair in old.Files) { if ([email protected](pair.Key)) { Console.Out.WriteLine("{0:X12}.{1:X3} removed", GUID.LongKey(pair.Key), GUID.Type(pair.Key)); } } } old.Dispose(); @new.Dispose(); break; } case "delta": { DeltaFile old = new DeltaFile(flags.Positionals[3]); if (string.IsNullOrEmpty(old.Name) || old.Files.Count == 0) { Console.Error.WriteLine("Invalid old file"); } else { Console.Out.WriteLine("Comparing {0} with current ({1})", old.Name, handler.Config.BuildName); foreach (KeyValuePair <ulong, Record> pair in map) { if (old.Files.ContainsKey(pair.Key)) { if (old.Files[pair.Key] == pair.Value.record.Size) { continue; } Console.Out.WriteLine("{0:X12}.{1:X3} changed ({2} bytes)", GUID.LongKey(pair.Key), GUID.Type(pair.Key), old.Files[pair.Key] - pair.Value.record.Size); } else { Console.Out.WriteLine("{0:X12}.{1:X3} added ({2} bytes)", GUID.LongKey(pair.Key), GUID.Type(pair.Key), pair.Value.record.Size); } } foreach (KeyValuePair <ulong, int> pair in old.Files) { if (!map.ContainsKey(pair.Key)) { Console.Out.WriteLine("{0:X12}.{1:X3} removed", GUID.LongKey(pair.Key), GUID.Type(pair.Key)); } } } old.Dispose(); break; } case "create": { DeltaFile delta = new DeltaFile(flags.Positionals[3]); delta.SetName(handler.Config.BuildName); foreach (KeyValuePair <ulong, Record> pair in map) { delta.Files[pair.Key] = pair.Value.record.Size; } delta.Save(); delta.Dispose(); break; } case "dump": { DeltaFile old = new DeltaFile(flags.Positionals[4]); List <ushort> types = new List <ushort>(); if (flags.Positionals.Length > 5) { types.AddRange(flags.Positionals.Skip(5).Select((it) => ushort.Parse(it, System.Globalization.NumberStyles.HexNumber))); } if (string.IsNullOrEmpty(old.Name) || old.Files.Count == 0) { Console.Error.WriteLine("Invalid old file"); } else { foreach (KeyValuePair <ulong, Record> pair in map) { if (types.Count > 0 && !types.Contains(GUID.Type(pair.Key))) { continue; } if (old.Files.ContainsKey(pair.Key)) { if (old.Files[pair.Key] == pair.Value.record.Size) { continue; } Save(flags.Positionals[3], pair.Value, handler, "changed", quiet); } else { Save(flags.Positionals[3], pair.Value, handler, "new", quiet); } } } old.Dispose(); break; } default: { Console.Out.WriteLine("Valid modes: list, create, delta, dump"); Console.Out.WriteLine("create [destination owdelta]"); Console.Out.WriteLine("list [old owdelta] [new owdelta]"); Console.Out.WriteLine("delta [old owdelta]"); Console.Out.WriteLine("dump [detination] [old owdelta] [types]"); break; } } }
public void Parse(Dictionary <ushort, List <ulong> > track, Dictionary <ulong, Record> map, CASCHandler handler, bool quiet, OverToolFlags flags) { string output = flags.Positionals[2]; List <string> maps = flags.Positionals.Skip(3).ToList(); bool skipCmodel = !flags.ExportCollision; for (int i = 0; i < maps.Count; ++i) { maps[i] = maps[i].ToUpperInvariant().TrimStart('0'); } bool mapWildcard = maps.Count == 0; if (maps.Count > 0 && maps.Contains("*")) { mapWildcard = true; } char animEncoding = flags.AnimFormat; if (flags.Raw) { animEncoding = '+'; } bool suppressAnimations = flags.SkipAnimations; if (animEncoding == '+' && !flags.RawAnimation) { suppressAnimations = true; } char modelEncoding = flags.ModelFormat; if (flags.Raw) { modelEncoding = '+'; } bool suppressModels = flags.SkipModels; if (modelEncoding == '+' && !flags.RawModel) { suppressModels = true; } IDataWriter animWriter = null; if (animEncoding != 0 && animEncoding != '+') { Assembly asm = typeof(IDataWriter).Assembly; Type t = typeof(IDataWriter); List <Type> types = asm.GetTypes().Where(tt => tt != t && t.IsAssignableFrom(tt)).ToList(); foreach (Type tt in types) { if (animWriter != null) { break; } if (tt.IsInterface) { continue; } IDataWriter tmp = (IDataWriter)Activator.CreateInstance(tt); for (int i = 0; i < tmp.Identifier.Length; ++i) { if (tmp.Identifier[i] == animEncoding) { animWriter = tmp; break; } } } } IDataWriter modelWriter = null; if (modelEncoding != 0 && modelEncoding != '+') { Assembly asm = typeof(IDataWriter).Assembly; Type t = typeof(IDataWriter); List <Type> types = asm.GetTypes().Where(tt => tt != t && t.IsAssignableFrom(tt)).ToList(); foreach (Type tt in types) { if (modelWriter != null) { break; } if (tt.IsInterface) { continue; } IDataWriter tmp = (IDataWriter)Activator.CreateInstance(tt); for (int i = 0; i < tmp.Identifier.Length; ++i) { if (tmp.Identifier[i] == modelEncoding) { modelWriter = tmp; break; } } } } List <ulong> masters = track[0x9F]; List <byte> LODs = new List <byte>(new byte[5] { 0, 1, 128, 254, 255 }); Dictionary <ulong, ulong> replace = new Dictionary <ulong, ulong>(); foreach (ulong masterKey in masters) { if (!map.ContainsKey(masterKey)) { continue; } STUD masterStud = new STUD(Util.OpenFile(map[masterKey], handler)); if (masterStud.Instances == null) { continue; } MapMaster master = (MapMaster)masterStud.Instances[0]; if (master == null) { continue; } string name = Util.GetString(master.Header.name.key, map, handler); if (string.IsNullOrWhiteSpace(name)) { name = $"Unknown{GUID.Index(master.Header.data.key):X}"; } if (!mapWildcard && !(maps.Contains(name.ToUpperInvariant()) || maps.Contains($"{GUID.Index(masterKey):X}"))) { continue; } string outputPath = string.Format("{0}{1}{2}{1}{3:X}{1}", output, Path.DirectorySeparatorChar, Util.SanitizePath(name), GUID.Index(master.Header.data.key)); if (!map.ContainsKey(master.Header.data.key)) { continue; } HashSet <ulong> parsed = new HashSet <ulong>(); Dictionary <ulong, ulong> animList = new Dictionary <ulong, ulong>(); Dictionary <ulong, List <ulong> > soundData = new Dictionary <ulong, List <ulong> >(); if (!map.ContainsKey(master.DataKey(1))) { continue; } if (!map.ContainsKey(master.DataKey(2))) { continue; } if (!map.ContainsKey(master.DataKey(8))) { continue; } if (!map.ContainsKey(master.DataKey(0xB))) { continue; } if (!map.ContainsKey(master.DataKey(0x11))) { continue; } if (!map.ContainsKey(master.DataKey(0x10))) { continue; } using (Stream mapStream = Util.OpenFile(map[master.DataKey(1)], handler)) { Console.Out.WriteLine("Extracting map {0} with ID {1:X8}", name, GUID.Index(master.Header.data.key)); Map mapData = new Map(mapStream); IDataWriter owmap = new OWMAPWriter(); Dictionary <ulong, List <string> >[] used = null; if (!Directory.Exists(outputPath)) { Directory.CreateDirectory(outputPath); } HashSet <ulong> soundDone = new HashSet <ulong>(); Sound.FindSoundsEx(master.Header.audio.key, soundDone, soundData, map, handler, replace, master.Header.data.key); using (Stream map2Stream = Util.OpenFile(map[master.DataKey(2)], handler)) { if (map2Stream != null) { Map map2Data = new Map(map2Stream); using (Stream map8Stream = Util.OpenFile(map[master.DataKey(8)], handler)) { if (map8Stream != null) { Map map8Data = new Map(map8Stream); using (Stream mapBStream = Util.OpenFile(map[master.DataKey(0xB)], handler)) { if (mapBStream != null) { Map mapBData = new Map(mapBStream, true); using (Stream map11Stream = Util.OpenFile(map[master.DataKey(0x11)], handler)) { if (map11Stream != null) { Map11 map11 = new Map11(map11Stream); Sound.FindSoundsSTUD(map11.main, soundDone, soundData, map, handler, replace, masterKey, master.DataKey(0x11)); Sound.FindSoundsSTUD(map11.secondary, soundDone, soundData, map, handler, replace, masterKey, master.DataKey(0x11)); } } mapBStream.Position = (long)(Math.Ceiling((float)mapBStream.Position / 16.0f) * 16); // Future proofing for (int i = 0; i < mapBData.STUDs.Count; ++i) { STUD stud = mapBData.STUDs[i]; Sound.FindSoundsSTUD(stud, soundDone, soundData, map, handler, replace, master.DataKey(0xB), master.DataKey(0xB)); } for (int i = 0; i < mapBData.Records.Length; ++i) { if (mapBData.Records[i] != null && mapBData.Records[i].GetType() != typeof(MapEntity)) { continue; } MapEntity mapprop = (MapEntity)mapBData.Records[i]; if (!map.ContainsKey(mapprop.Header.Entity)) { continue; } Sound.FindSoundsEx(mapprop.Header.Entity, soundDone, soundData, map, handler, replace, master.DataKey(0xB)); HashSet <ulong> bindingModels = new HashSet <ulong>(); Dictionary <ulong, List <ImageLayer> > bindingTextures = new Dictionary <ulong, List <ImageLayer> >(); using (Stream bindingFile = Util.OpenFile(map[mapprop.Header.Entity], handler)) { STUD binding = new STUD(bindingFile, true, STUDManager.Instance, false, true); foreach (ISTUDInstance instance in binding.Instances) { if (instance == null) { continue; } if (instance.Name != binding.Manager.GetName(typeof(ComplexModelRecord))) { continue; } ComplexModelRecord cmr = (ComplexModelRecord)instance; mapprop.ModelLook = cmr.Data.material.key; mapprop.Model = cmr.Data.model.key; Skin.FindAnimations(cmr.Data.animationList.key, soundData, animList, replace, parsed, map, handler, bindingModels, bindingTextures, mapprop.Model); Skin.FindAnimations(cmr.Data.secondaryAnimationList.key, soundData, animList, replace, parsed, map, handler, bindingModels, bindingTextures, mapprop.Model); break; } } mapBData.Records[i] = mapprop; } using (Stream mapLStream = Util.OpenFile(map[master.DataKey(9)], handler)) { Map mapLData = new Map(mapLStream); using (Stream outputStream = File.Open($"{outputPath}{Util.SanitizePath(name)}{owmap.Format}", FileMode.Create, FileAccess.Write)) { used = owmap.Write(outputStream, mapData, map2Data, map8Data, mapBData, mapLData, name, modelWriter); } } } } } } } } IDataWriter owmat = new OWMATWriter(); using (Stream map10Stream = Util.OpenFile(map[master.DataKey(0x10)], handler)) { Map10 physics = new Map10(map10Stream); using (Stream outputStream = File.Open($"{outputPath}physics{modelWriter.Format}", FileMode.Create, FileAccess.Write)) { modelWriter.Write(physics, outputStream, new object[0]); } } if (used != null) { Dictionary <ulong, List <string> > models = used[0]; Dictionary <ulong, List <string> > materials = used[1]; Dictionary <ulong, Dictionary <ulong, List <ImageLayer> > > cache = new Dictionary <ulong, Dictionary <ulong, List <ImageLayer> > >(); if (!suppressModels) { foreach (KeyValuePair <ulong, List <string> > modelpair in models) { if (!map.ContainsKey(modelpair.Key)) { continue; } if (!parsed.Add(modelpair.Key)) { continue; } HashSet <string> extracted = new HashSet <string>(); using (Stream modelStream = Util.OpenFile(map[modelpair.Key], handler)) { Chunked mdl = new Chunked(modelStream, true); modelStream.Position = 0; if (modelEncoding != '+' && modelWriter != null) { foreach (string modelOutput in modelpair.Value) { if (!extracted.Add(modelOutput)) { continue; } using (Stream outputStream = File.Open($"{outputPath}{modelOutput}", FileMode.Create, FileAccess.Write)) { if (modelWriter.Write(mdl, outputStream, LODs, new Dictionary <ulong, List <ImageLayer> >(), new object[5] { null, null, null, null, skipCmodel })) { if (!quiet) { Console.Out.WriteLine("Wrote model {0}", modelOutput); } } else { if (!quiet) { Console.Out.WriteLine("Failed to write model"); } } } } } if (flags.RawModel) { using (Stream outputStream = File.Open($"{outputPath}{GUID.LongKey(modelpair.Key):X12}.{GUID.Type(modelpair.Key):X3}", FileMode.Create, FileAccess.Write)) { if (modelWriter.Write(mdl, outputStream, LODs, new Dictionary <ulong, List <ImageLayer> >(), new object[5] { null, null, null, null, skipCmodel })) { if (!quiet) { Console.Out.WriteLine("Wrote raw model {0:X12}.{1:X3}", GUID.LongKey(modelpair.Key), GUID.Type(modelpair.Key)); } } else { if (!quiet) { Console.Out.WriteLine("Failed to write model"); } } } } } } } if (!suppressAnimations) { foreach (KeyValuePair <ulong, ulong> kv in animList) { ulong parent = kv.Value; ulong key = kv.Key; Stream animStream = Util.OpenFile(map[key], handler); if (animStream == null) { continue; } Animation anim = new Animation(animStream); animStream.Position = 0; string outpath = string.Format("{0}Animations{1}{2:X12}{1}{5}{1}{3:X12}.{4:X3}", outputPath, Path.DirectorySeparatorChar, GUID.Index(parent), GUID.LongKey(key), GUID.Type(key), anim.Header.priority); if (!Directory.Exists(Path.GetDirectoryName(outpath))) { Directory.CreateDirectory(Path.GetDirectoryName(outpath)); } if (flags.RawAnimation) { using (Stream outp = File.Open(outpath, FileMode.Create, FileAccess.Write)) { animStream.CopyTo(outp); if (!quiet) { Console.Out.WriteLine("Wrote raw animation {0}", outpath); } } } if (animEncoding != '+' && animWriter != null) { outpath = string.Format("{0}Animations{1}{2:X12}{1}{5}{1}{3:X12}.{4}", outputPath, Path.DirectorySeparatorChar, GUID.Index(parent), GUID.LongKey(key), animWriter.Format, anim.Header.priority); using (Stream outp = File.Open(outpath, FileMode.Create, FileAccess.Write)) { animWriter.Write(anim, outp); if (!quiet) { Console.Out.WriteLine("Wrote animation {0}", outpath); } } } } } if (!flags.SkipSound) { Console.Out.WriteLine("Dumping sounds..."); string soundPath = $"{outputPath}Sounds{Path.DirectorySeparatorChar}"; if (!Directory.Exists(soundPath)) { Directory.CreateDirectory(soundPath); } DumpVoice.Save(soundPath, soundData, map, handler, quiet); } if (!flags.SkipTextures) { foreach (KeyValuePair <ulong, List <string> > matpair in materials) { Dictionary <ulong, List <ImageLayer> > tmp = new Dictionary <ulong, List <ImageLayer> >(); if (cache.ContainsKey(matpair.Key)) { tmp = cache[matpair.Key]; } else { Skin.FindTextures(matpair.Key, tmp, new Dictionary <ulong, ulong>(), new HashSet <ulong>(), map, handler); cache.Add(matpair.Key, tmp); } Dictionary <string, TextureType> types = new Dictionary <string, TextureType>(); foreach (KeyValuePair <ulong, List <ImageLayer> > kv in tmp) { ulong materialId = kv.Key; List <ImageLayer> sublayers = kv.Value; HashSet <ulong> materialParsed = new HashSet <ulong>(); foreach (ImageLayer layer in sublayers) { if (!materialParsed.Add(layer.Key)) { continue; } KeyValuePair <string, TextureType> pair = Skin.SaveTexture(layer.Key, materialId, map, handler, outputPath, quiet, $"Textures/{GUID.Index(matpair.Key):X8}"); if (pair.Key == null) { continue; } types.Add(pair.Key, pair.Value); } } foreach (string matOutput in matpair.Value) { if (File.Exists($"{outputPath}{matOutput}")) { continue; } using (Stream outputStream = File.Open($"{outputPath}{matOutput}", FileMode.Create, FileAccess.Write)) { if (owmat.Write(null, outputStream, null, tmp, new object[1] { types })) { if (!quiet) { Console.Out.WriteLine("Wrote material {0}", matOutput); } } else { if (!quiet) { Console.Out.WriteLine("Failed to write material"); } } } } } } } } } }
public void Parse(Dictionary <ushort, List <ulong> > track, Dictionary <ulong, Record> map, CASCHandler handler, bool quiet, OverToolFlags flags) { string output = flags.Positionals[2]; List <string> maps = new List <string>(); if (flags.Positionals.Length > 3) { maps.AddRange(flags.Positionals.Skip(2).Select((it) => it.ToLower())); } bool wildcard = maps.Count == 0 || maps.Contains("*"); List <ulong> masters = track[0x9F]; Dictionary <ulong, ulong> replace = new Dictionary <ulong, ulong>(); foreach (ulong masterKey in masters) { if (!map.ContainsKey(masterKey)) { continue; } STUD masterStud = new STUD(Util.OpenFile(map[masterKey], handler)); if (masterStud.Instances == null || masterStud.Instances[0] == null) { continue; } MapMaster master = (MapMaster)masterStud.Instances[0]; if (master == null) { continue; } string name = Util.GetString(master.Header.name.key, map, handler); if (string.IsNullOrWhiteSpace(name)) { name = $"Unknown{GUID.Index(master.Header.data.key):X}"; } if (!maps.Contains(name.ToLowerInvariant()) && !wildcard) { continue; } if (!map.ContainsKey(master.DataKey(0xB))) { continue; } if (!map.ContainsKey(master.DataKey(0x11))) { continue; } Console.Out.WriteLine("Dumping audio for map {0}", name); Dictionary <ulong, List <ulong> > soundData = new Dictionary <ulong, List <ulong> >(); string path = string.Format("{0}{1}{2}{1}{3}{1}{4}{1}", output, Path.DirectorySeparatorChar, Util.Strip(Util.SanitizePath(name)), "Audio", GUID.Index(master.Header.data.key)); HashSet <ulong> soundDone = new HashSet <ulong>(); using (Stream mapBStream = Util.OpenFile(map[master.DataKey(0xB)], handler)) { if (mapBStream != null) { Map mapB = new Map(mapBStream); foreach (STUD stud in mapB.STUDs) { Sound.FindSoundsSTUD(stud, soundDone, soundData, map, handler, replace, masterKey, master.DataKey(0xB)); } for (int i = 0; i < mapB.Records.Length; ++i) { if (mapB.Records[i] != null && mapB.Records[i].GetType() != typeof(Map0B)) { continue; } Map0B mapprop = (Map0B)mapB.Records[i]; if (!map.ContainsKey(mapprop.Header.binding)) { continue; } Sound.FindSoundsEx(mapprop.Header.binding, soundDone, soundData, map, handler, replace, master.DataKey(0xB)); } } } using (Stream map11Stream = Util.OpenFile(map[master.DataKey(0x11)], handler)) { if (map11Stream != null) { Map11 map11 = new Map11(map11Stream); Sound.FindSoundsSTUD(map11.main, soundDone, soundData, map, handler, replace, masterKey, master.DataKey(0x11)); Sound.FindSoundsSTUD(map11.secondary, soundDone, soundData, map, handler, replace, masterKey, master.DataKey(0x11)); } } if (!Directory.Exists(path)) { Directory.CreateDirectory(path); } DumpVoice.Save(path, soundData, map, handler, quiet); } }
public void Parse(Dictionary <ushort, List <ulong> > track, Dictionary <ulong, Record> map, CASCHandler handler, bool quiet, OverToolFlags flags) { string output = flags.Positionals[2]; List <string> heroes = new List <string>(); if (flags.Positionals.Length > 3) { heroes.AddRange(flags.Positionals[3].ToLowerInvariant().Split(new char[] { '+' }, StringSplitOptions.RemoveEmptyEntries)); } bool heroAllWildcard = heroes.Count == 0 || heroes.Contains("*"); List <ulong> masters = track[0x75]; foreach (ulong masterKey in masters) { if (!map.ContainsKey(masterKey)) { continue; } STUD masterStud = new STUD(Util.OpenFile(map[masterKey], handler)); if (masterStud.Instances == null || masterStud.Instances[0] == null) { continue; } HeroMaster master = (HeroMaster)masterStud.Instances[0]; if (master == null) { continue; } string heroName = Util.GetString(master.Header.name.key, map, handler); if (heroName == null) { continue; } if (!heroes.Contains(heroName.ToLowerInvariant())) { if (!heroAllWildcard) { continue; } } if (master.Header.itemMaster.key != 0) // AI { InventoryMaster inventory = Extract.OpenInventoryMaster(master, map, handler); if (inventory.ItemGroups.Length > 0 || inventory.DefaultGroups.Length > 0) { continue; } } Console.Out.WriteLine("Dumping voice bites for NPC {0}", heroName); Dictionary <ulong, List <ulong> > soundData = ExtractLogic.Sound.FindSounds(master, track, map, handler, null, masterKey); string path = string.Format("{0}{1}{2}{1}{3}{1}", output, Path.DirectorySeparatorChar, Util.Strip(Util.SanitizePath(heroName)), "Sound Dump"); if (!Directory.Exists(path)) { Directory.CreateDirectory(path); } Save(path, soundData, map, handler, quiet); } }
public void Parse(Dictionary <ushort, List <ulong> > track, Dictionary <ulong, Record> map, CASCHandler handler, bool quiet, OverToolFlags flags) { string output = flags.Positionals[2]; List <ulong> masters = track[0x9D]; Dictionary <ulong, ulong> replace = new Dictionary <ulong, ulong>(); foreach (ulong masterKey in masters) { if (!map.ContainsKey(masterKey)) { continue; } STUD masterStud = new STUD(Util.OpenFile(map[masterKey], handler)); if (masterStud.Instances == null || masterStud.Instances[0] == null) { continue; } AnnouncerVoiceList master = (AnnouncerVoiceList)masterStud.Instances[0]; if (master == null) { continue; } string path = string.Format("{0}{1}{2:X}{1}Announcer{1}", output, Path.DirectorySeparatorChar, GUID.Index(masterKey)); HashSet <ulong> done = new HashSet <ulong>(); Console.Out.WriteLine("Dumping voice lines for announcer {0:X}", GUID.Index(masterKey)); Dictionary <ulong, List <ulong> > soundData = new Dictionary <ulong, List <ulong> >(); for (int i = 0; i < master.Entries.Length; ++i) { AnnouncerVoiceList.AnnouncerFXEntry entry = master.Entries[i]; OWRecord[] primary = master.Primary[i]; OWRecord[] secondary = master.Secondary[i]; Sound.FindSoundsEx(entry.master, done, soundData, map, handler, replace, masterKey); foreach (OWRecord record in primary) { Sound.FindSoundsEx(record, done, soundData, map, handler, replace, masterKey); } foreach (OWRecord record in secondary) { Sound.FindSoundsEx(record, done, soundData, map, handler, replace, masterKey); } } DumpVoice.Save(path, soundData, map, handler, quiet); } }
public void Parse(Dictionary <ushort, List <ulong> > track, Dictionary <ulong, Record> map, CASCHandler handler, bool quiet, OverToolFlags flags) { foreach (KeyValuePair <ushort, List <ulong> > pair in track) { Console.Out.WriteLine($"{pair.Key:X3} {pair.Value.Count} entries"); } }
public void Parse(Dictionary <ushort, List <ulong> > track, Dictionary <ulong, Record> map, CASCHandler handler, bool quiet, OverToolFlags flags) { string output = flags.Positionals[2]; string[] validCommands = new string[] { "skin", "spray", "icon", "victory pose", "emote", "heroic intro" }; bool typeWildcard = true; List <string> types = new List <string>(); if (flags.Positionals.Length > 3) { types.AddRange(flags.Positionals[3].ToLowerInvariant().Split(new char[] { '+' }, StringSplitOptions.RemoveEmptyEntries)); typeWildcard = types.Contains("*"); types = types.FindAll((string it) => validCommands.Contains(it)).ToList(); } if (!typeWildcard && types.Count == 0) { string cmdlist = ""; for (int i = 0; i < validCommands.Length; i++) { if (i != 0) { cmdlist += ", "; if (i == validCommands.Length - 1) { cmdlist += "or "; } } cmdlist += validCommands[i].ToString().ToLower(); } Console.Out.WriteLine("The output type was not a valid option. ({0})", cmdlist); return; } Dictionary <string, List <string> > heroTypes = new Dictionary <string, List <string> >(); Dictionary <string, bool> heroWildcard = new Dictionary <string, bool>(); Dictionary <string, Dictionary <string, List <ulong> > > heroIgnore = new Dictionary <string, Dictionary <string, List <ulong> > >(); bool heroAllWildcard = false; if (flags.Positionals.Length > 4 && flags.Positionals[4] != "*") { foreach (string pair in flags.Positionals[4].ToLowerInvariant().Split(new char[] { '+' }, StringSplitOptions.RemoveEmptyEntries)) { List <string> data = new List <string>(pair.Split(new char[] { '=' }, StringSplitOptions.RemoveEmptyEntries)); string name = data[0]; data.RemoveAt(0); if (!heroTypes.ContainsKey(name)) { heroTypes[name] = new List <string>(); heroIgnore[name] = new Dictionary <string, List <ulong> >(); heroWildcard[name] = false; } if (data.Count > 0) { foreach (string d in data) { List <string> subdata = new List <string>(d.Split(new char[] { '|' }, StringSplitOptions.RemoveEmptyEntries)); string subn = subdata[0]; subdata.RemoveAt(0); heroTypes[name].Add(subn); heroIgnore[name][subn] = new List <ulong>(); if (subdata.Count > 0) { foreach (string sd in subdata) { try { heroIgnore[name][subn].Add(ulong.Parse(sd, System.Globalization.NumberStyles.HexNumber)); } catch { } } } } } if (data.Count == 0 || data.Contains("*")) { heroWildcard[name] = true; } } } else { heroAllWildcard = true; } int replacementIndex = flags.WeaponSkinIndex; List <ulong> masters = track[0x75]; foreach (ulong masterKey in masters) { if (!map.ContainsKey(masterKey)) { continue; } STUD masterStud = new STUD(Util.OpenFile(map[masterKey], handler)); if (masterStud.Instances == null) { continue; } HeroMaster master = (HeroMaster)masterStud.Instances[0]; if (master == null) { continue; } if (master.Header.itemMaster.key == 0) { continue; } string heroName = Util.GetString(master.Header.name.key, map, handler); if (heroName == null) { continue; } if (heroAllWildcard) { if (!heroTypes.ContainsKey(heroName.ToLowerInvariant())) { heroTypes.Add(heroName.ToLowerInvariant(), new List <string>()); } if (!heroWildcard.ContainsKey(heroName.ToLowerInvariant())) { heroWildcard.Add(heroName.ToLowerInvariant(), true); } } if (!heroTypes.ContainsKey(heroName.ToLowerInvariant())) { continue; } InventoryMaster inventory = OpenInventoryMaster(master, map, handler); if (inventory == null) { continue; } Dictionary <OWRecord, string> items = new Dictionary <OWRecord, string>(); foreach (OWRecord record in inventory.Achievables) { items[record] = "ACHIEVEMENT"; } for (int i = 0; i < inventory.DefaultGroups.Length; ++i) { string name = $"STANDARD_{ItemEvents.GetInstance().GetEvent(inventory.DefaultGroups[i].@event)}"; for (int j = 0; j < inventory.Defaults[i].Length; ++j) { items[inventory.Defaults[i][j]] = name; } } for (int i = 0; i < inventory.ItemGroups.Length; ++i) { string name = ItemEvents.GetInstance().GetEvent(inventory.ItemGroups[i].@event); for (int j = 0; j < inventory.Items[i].Length; ++j) { items[inventory.Items[i][j]] = name; } } foreach (KeyValuePair <OWRecord, string> recordname in items) { OWRecord record = recordname.Key; string itemGroup = recordname.Value; if (!map.ContainsKey(record.key)) { continue; } STUD stud = new STUD(Util.OpenFile(map[record.key], handler)); if (stud.Instances == null) { continue; } IInventorySTUDInstance instance = (IInventorySTUDInstance)stud.Instances[0]; if (!typeWildcard && !types.Contains(instance.Name.ToLowerInvariant())) { continue; } string name = Util.GetString(instance.Header.name.key, map, handler); if (name == null) { name = $"Untitled-{GUID.LongKey(instance.Header.name.key):X12}"; continue; } if (!heroWildcard[heroName.ToLowerInvariant()] && !heroTypes[heroName.ToLowerInvariant()].Contains(name.ToLowerInvariant())) { continue; } switch (instance.Name) { case "Spray": Console.Out.WriteLine("Extracting spray {0} for {1}...", name, heroName); ExtractLogic.Spray.Extract(stud, output, heroName, name, itemGroup, track, map, handler, quiet, flags); break; case "Skin": List <ulong> ignoreList = new List <ulong>(); try { ignoreList = heroIgnore[heroName.ToLowerInvariant()][name.ToLowerInvariant()]; } catch { } Console.Out.WriteLine("Extracting {0} models and textures for {1}", name, heroName); ExtractLogic.Skin.Extract(master, stud, output, heroName, name, itemGroup, ignoreList, track, map, handler, quiet, flags, masterKey, replacementIndex); break; case "Icon": Console.Out.WriteLine("Extracting icon {0} for {1}...", name, heroName); ExtractLogic.Icon.Extract(stud, output, heroName, name, itemGroup, track, map, handler, quiet, flags); break; case "Emote": case "Victory Pose": case "Heroic Intro": Console.Out.WriteLine("Extracting {2} {0} for {1}...", name, heroName, instance.Name); ExtractLogic.ItemAnimation.Extract(record.key, stud, output, heroName, name, itemGroup, track, map, handler, quiet, flags); break; case "Voice Line": //Console.Out.WriteLine("Extracting voice line {0} for {1}...", name, heroName); //ExtractLogic.VoiceLine.Extract(master, stud, output, heroName, name, track, map, handler); break; } } } }
public static void MapCMF(OwRootHandler ow, CASCHandler handler, Dictionary <ulong, Record> map, Dictionary <ushort, List <ulong> > track, OverToolFlags flags) { if (ow == null || handler == null) { return; } foreach (APMFile apm in ow.APMFiles) { if (!apm.Name.ToLowerInvariant().Contains("rdev")) { continue; } if (flags != null && !apm.Name.ToLowerInvariant().Contains("l" + flags.Language.ToLowerInvariant())) { continue; } foreach (KeyValuePair <ulong, CMFHashData> pair in apm.CMFMap) { ushort id = GUID.Type(pair.Key); if (track != null && track.ContainsKey(id)) { track[id].Add(pair.Value.id); } if (map.ContainsKey(pair.Key)) { continue; } Record rec = new Record { record = new PackageIndexRecord() }; rec.record.Flags = 0; rec.record.Key = pair.Value.id; rec.record.ContentKey = pair.Value.HashKey; rec.package = new APMPackage(new APMPackageItem()); rec.index = new PackageIndex(new PackageIndexItem()); EncodingEntry enc; if (handler.Encoding.GetEntry(pair.Value.HashKey, out enc)) { rec.record.Size = enc.Size; map.Add(pair.Key, rec); } } } }
public void Parse(Dictionary <ushort, List <ulong> > track, Dictionary <ulong, Record> map, CASCHandler handler, bool quiet, OverToolFlags flags) { string output = flags.Positionals[2]; List <string> heroes = new List <string>(); if (flags.Positionals.Length > 3) { heroes.AddRange(flags.Positionals[3].ToLowerInvariant().Split(new char[] { '+' }, StringSplitOptions.RemoveEmptyEntries)); } bool heroAllWildcard = heroes.Count == 0 || heroes.Contains("*"); List <ulong> masters = track[0x75]; foreach (ulong masterKey in masters) { if (!map.ContainsKey(masterKey)) { continue; } STUD masterStud = new STUD(Util.OpenFile(map[masterKey], handler)); if (masterStud.Instances == null || masterStud.Instances[0] == null) { continue; } HeroMaster master = (HeroMaster)masterStud.Instances[0]; if (master == null) { continue; } string heroName = Util.GetString(master.Header.name.key, map, handler); if (heroName == null) { continue; } if (!heroes.Contains(heroName.ToLowerInvariant())) { if (!heroAllWildcard) { continue; } } HashSet <ulong> items = new HashSet <ulong>(); InventoryMaster inventory = Extract.OpenInventoryMaster(master, map, handler); if (inventory == null) { continue; } foreach (OWRecord record in inventory.Achievables) { items.Add(record); } for (int i = 0; i < inventory.DefaultGroups.Length; ++i) { for (int j = 0; j < inventory.Defaults[i].Length; ++j) { items.Add(inventory.Defaults[i][j]); } } for (int i = 0; i < inventory.ItemGroups.Length; ++i) { for (int j = 0; j < inventory.Items[i].Length; ++j) { items.Add(inventory.Items[i][j]); } } HashSet <ulong> done = new HashSet <ulong>(); string path = string.Format("{0}{1}{2}{1}{3}{1}", output, Path.DirectorySeparatorChar, Util.Strip(Util.SanitizePath(heroName)), "Sound Dump Full"); if (!Directory.Exists(path)) { Directory.CreateDirectory(path); } bool haveBase = false; foreach (ulong itemKey in items) { if (!map.ContainsKey(itemKey)) { continue; } using (Stream itemStream = Util.OpenFile(map[itemKey], handler)) { STUD itemStud = new STUD(itemStream); if (itemStud.Instances == null) { continue; } SkinItem item = itemStud.Instances[0] as SkinItem; if (item == null) { continue; } Dictionary <ulong, List <ulong> > sound = new Dictionary <ulong, List <ulong> >(); if (!haveBase) { sound.Clear(); Console.Out.WriteLine("Processing base sounds for hero {0}", heroName); Skin.ExtractData(item, master, false, new HashSet <ulong>(), new Dictionary <ulong, ulong>(), new HashSet <ulong>(), new Dictionary <ulong, List <ImageLayer> >(), new Dictionary <ulong, ulong>(), sound, new List <ulong>(), -1, map, handler); Sound.FindSounds(master, track, map, handler, null, masterKey, sound); DumpVoice.Save($"{path}_Base{Path.DirectorySeparatorChar}", sound, map, handler, quiet, null, done); haveBase = true; } sound.Clear(); string itemName = Util.GetString(item.Header.name, map, handler); if (string.IsNullOrWhiteSpace(itemName)) { itemName = $"Item-{itemKey:X16}"; } Console.Out.WriteLine("Processing new sounds for skin {0}", itemName); Dictionary <ulong, ulong> replace = new Dictionary <ulong, ulong>(); Skin.ExtractData(item, master, true, new HashSet <ulong>(), new Dictionary <ulong, ulong>(), new HashSet <ulong>(), new Dictionary <ulong, List <ImageLayer> >(), replace, sound, new List <ulong>(), -1, map, handler); Sound.FindSounds(master, track, map, handler, replace, masterKey, sound); DumpVoice.Save($"{path}{Util.Strip(Util.SanitizePath(itemName))}{Path.DirectorySeparatorChar}", sound, map, handler, quiet, replace, done); } } } }
public void Parse(Dictionary <ushort, List <ulong> > track, Dictionary <ulong, Record> map, CASCHandler handler, bool quiet, OverToolFlags flags) { List <ulong> masters = track[0x9F]; foreach (ulong key in masters) { if (!map.ContainsKey(key)) { continue; } ISTU stu = ISTU.NewInstance(Util.OpenFile(map[key], handler), uint.MaxValue); if (stu.Instances == null) { continue; } STUMap mapSTU = stu.Instances.First() as STUMap; if (map == null) { continue; } // Console.Out.WriteLine($"{key}"); // // if (mapSTU.StringDescriptionA != null) { // Console.Out.WriteLine($"\tStringDescriptionA: {Util.GetString(mapSTU.StringDescriptionA, map, handler)}"); // } // if (mapSTU.StringStateA != null) { // Console.Out.WriteLine($"\tStringStateA: {Util.GetString(mapSTU.StringStateA, map, handler)}"); // } // if (mapSTU.StringName != null) { // Console.Out.WriteLine($"\tStringName: {Util.GetString(mapSTU.StringName, map, handler)}"); // } // if (mapSTU.StringStateB != null) { // Console.Out.WriteLine($"StringStateB: {Util.GetString(mapSTU.StringStateB, map, handler)}"); // } // if (mapSTU.StringDescriptionB != null) { // Console.Out.WriteLine($"\tStringDescriptionB: {Util.GetString(mapSTU.StringDescriptionB, map, handler)}"); // } // if (mapSTU.StringSubline != null) { // Console.Out.WriteLine($"\tStringSubline: {Util.GetString(mapSTU.StringSubline, map, handler)}"); // } // if (mapSTU.StringNameB != null) { // Console.Out.WriteLine($"\tStringNameB: {Util.GetString(mapSTU.StringNameB, map, handler)}"); // } //string name = Util.GetString(map.Header.name.key, map, handler); //if (string.IsNullOrWhiteSpace(name)) { // name = $"Unknown{GUID.Index(masterKey):X}"; //} //Console.Out.WriteLine(name); //Console.Out.WriteLine("\tID: {0:X8}", GUID.Index(masterKey)); //string subline = Util.GetString(map.Header.subline.key, map, handler); //if (subline == null) { // subline = ""; //} //if (map.Header.subline.key != map.Header.subline2.key && map.Header.subline2.key != 0) { // subline += " " + Util.GetString(map.Header.subline2.key, map, handler); //} //subline = subline.Trim(); //if (subline.Length > 0) { // Console.Out.WriteLine("\tSubline: {0}", subline); //} //TryString("State", Util.GetString(map.Header.stateA.key, map, handler)); //TryString("State", Util.GetString(map.Header.stateB.key, map, handler)); //string description = Util.GetString(map.Header.description1.key, map, handler); //if (description == null) { // description = ""; //} //if (map.Header.description1.key != map.Header.description2.key && map.Header.description2.key != 0) { // description += " " + Util.GetString(map.Header.description2.key, map, handler); //} //description = description.Trim(); //if (description.Length > 0) { // Console.Out.WriteLine("\tDescription: {0}", description); //} } }
static void Main(string[] args) { Console.OutputEncoding = Encoding.UTF8; List <IOvertool> tools = new List <IOvertool>(); { Assembly asm = typeof(IOvertool).Assembly; Type t = typeof(IOvertool); List <Type> types = asm.GetTypes().Where(tt => tt != t && t.IsAssignableFrom(tt)).ToList(); foreach (Type tt in types) { if (tt.IsInterface) { continue; } IOvertool toolinst = (IOvertool)Activator.CreateInstance(tt); if (toolinst.Display) { tools.Add(toolinst); } } } OverToolFlags flags = FlagParser.Parse <OverToolFlags>(() => PrintHelp(tools)); if (flags == null) { return; } Logger.EXIT = !flags.GracefulExit; bool quiet = flags.Quiet; string root = flags.OverwatchDirectory; string opt = flags.Mode; IOvertool tool = null; Dictionary <ushort, List <ulong> > track = new Dictionary <ushort, List <ulong> > { [0x90] = new List <ulong>() // internal requirements }; toolsMap = new Dictionary <string, IOvertool>(); foreach (IOvertool t in tools) { if (t.FullOpt == opt || (opt.Length == 1 && t.Opt != (char)0 && t.Opt == opt[0])) { tool = t; } if (t.Track != null) { foreach (ushort tr in t.Track) { if (!track.ContainsKey(tr)) { track[tr] = new List <ulong>(); } } } if (toolsMap.ContainsKey(t.FullOpt)) { Console.Out.WriteLine("Duplicate opt! {0} conflicts with {1}", t.Title, toolsMap[t.FullOpt].Title); } if (t.FullOpt.Length == 1) { Console.Out.WriteLine("FullOpt should not be length 1 for {0}", t.Title); } toolsMap[t.FullOpt] = t; } if (tool == null || flags.Positionals.Length - 2 < tool.MinimumArgs) { PrintHelp(tools); return; } Dictionary <ulong, Record> map = new Dictionary <ulong, Record>(); Console.Out.WriteLine("{0} v{1}", Assembly.GetExecutingAssembly().GetName().Name, OWLib.Util.GetVersion()); Console.Out.WriteLine("Initializing CASC..."); Console.Out.WriteLine("Set language to {0}", flags.Language); CDNIndexHandler.Cache.Enabled = flags.UseCache; CDNIndexHandler.Cache.CacheData = flags.CacheData; CDNIndexHandler.Cache.Validate = flags.ValidateCache; CASCConfig config = null; // ngdp:us:pro // http:us:pro:us.patch.battle.net:1119 if (root.ToLowerInvariant().Substring(0, 5) == "ngdp:") { string cdn = root.Substring(5, 4); string[] parts = root.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(root, !flags.SkipKeys, false); } config.Languages = new HashSet <string>(new string[1] { flags.Language }); if (flags.SkipKeys) { Console.Out.WriteLine("Disabling Key auto-detection..."); } Regex versionRegex = new Regex(@"\d+\.\d+"); Match versionMatch = versionRegex.Match(config.BuildName); if (versionMatch.Success) { float version = float.Parse(versionMatch.Value); if (version > 1.13) { Console.ForegroundColor = ConsoleColor.Red; Console.Out.WriteLine("==========\nWARNING: Overtool only works with Overwatch version 1.13 and below! You are using {0}!", config.BuildName); Console.Out.WriteLine("You must use DataTool for Overwatch 1.14 and above!\n=========="); Console.ResetColor(); } } Console.Out.WriteLine("Using Overwatch Version {0}", config.BuildName); CASCHandler handler = CASCHandler.OpenStorage(config); OwRootHandler ow = handler.Root as OwRootHandler; if (ow == null) { Console.Error.WriteLine("Not a valid overwatch installation"); return; } // Fail when trying to extract data from a specified language with 2 or less files found. if (ow.APMFiles.Count() == 0) { Console.Error.WriteLine("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; } } Console.Out.WriteLine("Mapping..."); Util.MapCMF(ow, handler, map, track, flags.Language); if (!flags.SkipKeys) { Console.Out.WriteLine("Adding Encryption Keys..."); foreach (ulong key in track[0x90]) { if (!map.ContainsKey(key)) { continue; } using (Stream stream = Util.OpenFile(map[key], handler)) { if (stream == null) { continue; } ISTU stu = ISTU.NewInstance(stream, UInt32.Parse(config.BuildName.Split('.').Last())); if (!(stu.Instances.FirstOrDefault() is STUEncryptionKey)) { continue; } STUEncryptionKey ek = stu.Instances.FirstOrDefault() as STUEncryptionKey; if (ek != null && !KeyService.keys.ContainsKey(ek.LongRevKey)) { KeyService.keys.Add(ek.LongRevKey, ek.KeyValue); Console.Out.WriteLine("Added Encryption Key {0}, Value: {1}", ek.KeyNameProper, ek.Key); } } } } Console.Out.WriteLine("Tooling..."); tool.Parse(track, map, handler, quiet, flags); if (System.Diagnostics.Debugger.IsAttached) { System.Diagnostics.Debugger.Break(); } }
public void Parse(Dictionary <ushort, List <ulong> > track, Dictionary <ulong, Record> map, CASCHandler handler, bool quiet, OverToolFlags flags) { Console.Out.WriteLine("key_name key"); foreach (ulong key in track[0x90]) { if (!map.ContainsKey(key)) { continue; } using (Stream stream = Util.OpenFile(map[key], handler)) { if (stream == null) { continue; } STUD stud = new STUD(stream); if (stud.Instances[0].Name != stud.Manager.GetName(typeof(EncryptionKey))) { continue; } EncryptionKey ek = (EncryptionKey)stud.Instances[0]; Console.Out.WriteLine("{0} {1}", ek.KeyNameText, ek.KeyValueText); } } if (System.Diagnostics.Debugger.IsAttached) { using (Stream output = File.Open("ow_dump.keys", FileMode.OpenOrCreate, FileAccess.Write, FileShare.Read)) { using (TextWriter writer = new StreamWriter(output)) { foreach (KeyValuePair <ulong, byte[]> key in KeyService.keys) { writer.WriteLine("{0:X16} {1}", key.Key, ByteArrayToString(key.Value)); } } } if (handler.Config.KeyRing != null) { using (Stream output = File.Open("ow_keyring.keys", FileMode.OpenOrCreate, FileAccess.Write, FileShare.Read)) { using (TextWriter writer = new StreamWriter(output)) { foreach (KeyValuePair <string, List <string> > pair in handler.Config.KeyRing.KeyValue) { if (pair.Key.StartsWith("key-")) { string reverseKey = pair.Key.Substring(pair.Key.Length - 16); string key = ""; for (int i = 0; i < 8; ++i) { key = reverseKey.Substring(i * 2, 2) + key; } ulong keyL = ulong.Parse(key, System.Globalization.NumberStyles.HexNumber); writer.WriteLine("{0:X16} {1}", keyL, pair.Value[0].ToByteArray()); } } } } } } }
public void Parse(Dictionary<ushort, List<ulong>> track, Dictionary<ulong, Record> map, CASCHandler handler, bool quiet, OverToolFlags flags) { Iterate(track[0x7C], map, handler); Iterate(track[0xA9], map, handler); }
public void Parse(Dictionary <ushort, List <ulong> > track, Dictionary <ulong, Record> map, CASCHandler handler, bool quiet, OverToolFlags flags) { string output = string.Format("{0}{1}Audio{1}", flags.Positionals[2], Path.DirectorySeparatorChar); Dictionary <ulong, List <ulong> > soundData = new Dictionary <ulong, List <ulong> >(); HashSet <ulong> done = new HashSet <ulong>(); foreach (ulong key in track[0x1B]) { ExtractLogic.Sound.FindSoundsEx(key, done, soundData, map, handler, new Dictionary <ulong, ulong>(), key); } DumpVoice.Save(output, soundData, map, handler, quiet); }
public void Parse(Dictionary <ushort, List <ulong> > track, Dictionary <ulong, Record> map, CASCHandler handler, bool quiet, OverToolFlags flags) { List <ulong> masters = track[0x9F]; foreach (ulong masterKey in masters) { Console.Out.WriteLine(""); if (!map.ContainsKey(masterKey)) { continue; } STUD masterStud = new STUD(Util.OpenFile(map[masterKey], handler), true, STUDManager.Instance, false, true); if (masterStud.Instances == null) { continue; } MapMaster master = (MapMaster)masterStud.Instances[0]; if (master == null) { continue; } string name = Util.GetString(master.Header.name.key, map, handler); if (string.IsNullOrWhiteSpace(name)) { name = $"Unknown{GUID.Index(masterKey):X}"; } Console.Out.WriteLine(name); Console.Out.WriteLine("\tID: {0:X8}", GUID.Index(masterKey)); string subline = Util.GetString(master.Header.subline.key, map, handler); if (subline == null) { subline = ""; } if (master.Header.subline.key != master.Header.subline2.key && master.Header.subline2.key != 0) { subline += " " + Util.GetString(master.Header.subline2.key, map, handler); } subline = subline.Trim(); if (subline.Length > 0) { Console.Out.WriteLine("\tSubline: {0}", subline); } TryString("State", Util.GetString(master.Header.stateA.key, map, handler)); TryString("State", Util.GetString(master.Header.stateB.key, map, handler)); string description = Util.GetString(master.Header.description1.key, map, handler); if (description == null) { description = ""; } if (master.Header.description1.key != master.Header.description2.key && master.Header.description2.key != 0) { description += " " + Util.GetString(master.Header.description2.key, map, handler); } description = description.Trim(); if (description.Length > 0) { Console.Out.WriteLine("\tDescription: {0}", description); } } }
public void Parse(Dictionary <ushort, List <ulong> > track, Dictionary <ulong, Record> map, CASCHandler handler, bool quiet, OverToolFlags flags) { List <ulong> masters = track[0x75]; foreach (ulong masterKey in masters) { if (!map.ContainsKey(masterKey)) { continue; } STUD masterStud = new STUD(Util.OpenFile(map[masterKey], handler)); if (masterStud.Instances == null) { continue; } HeroMaster master = (HeroMaster)masterStud.Instances[0]; if (master == null) { continue; } string heroName = Util.GetString(master.Header.name.key, map, handler); if (heroName == null) { continue; } string goodhero = heroName; foreach (var c in Path.GetInvalidFileNameChars()) { goodhero = goodhero.Replace(c, '_'); } if (master.Header.itemMaster.key == 0) // AI { continue; } bool ex = System.Diagnostics.Debugger.IsAttached || flags.Expert; bool hasName = false; if (!map.ContainsKey(master.Header.itemMaster.key)) { Console.Out.WriteLine("Error loading inventory master file..."); continue; } STUD inventoryStud = new STUD(Util.OpenFile(map[master.Header.itemMaster.key], handler)); #if OUTPUT_STUDINVENTORYMASTER Stream studStream = Util.OpenFile(map[master.Header.itemMaster.key], handler); string outFilename = string.Format("./STUDs/ListInventoryMaster/{0}.stud", goodhero); string putPathname = outFilename.Substring(0, outFilename.LastIndexOf('/')); Directory.CreateDirectory(putPathname); Stream OutWriter = File.Create(outFilename); studStream.CopyTo(OutWriter); OutWriter.Close(); studStream.Close(); #endif InventoryMaster inventory = (InventoryMaster)inventoryStud.Instances[0]; if (inventory == null) { Console.Out.WriteLine("Error loading inventory master file..."); continue; } Dictionary <int, string> indexMap = new Dictionary <int, string>(); List <OWRecord> items = new List <OWRecord>(); items.AddRange(inventory.Achievables.ToList()); for (int i = 0; i < inventory.DefaultGroups.Length; ++i) { string name = $"STANDARD_{ItemEvents.GetInstance().GetEvent(inventory.DefaultGroups[i].@event)}"; items.AddRange(inventory.Defaults[i].ToList()); } for (int i = 0; i < inventory.ItemGroups.Length; ++i) { string name = ItemEvents.GetInstance().GetEvent(inventory.ItemGroups[i].@event); items.AddRange(inventory.Items[i].ToList()); } foreach (OWRecord record in items) { STUD item = new STUD(Util.OpenFile(map[record], handler)); if (item.Instances == null) { continue; } WeaponSkinItem skin = item.Instances[0] as WeaponSkinItem; if (skin == null) { continue; } if (!hasName) { if (ex) { Console.Out.WriteLine("Weapons for {0} ({2:X16}) in package {1:X16}", heroName, map[masterKey].package.packageKey, masterKey); } else { Console.Out.WriteLine("Weapons for {0}", heroName); } hasName = true; } Console.Out.WriteLine("\tIndex {0} - {1}", skin.Data.index, Util.GetString(skin.Header.name, map, handler)); } if (hasName) { Console.Out.WriteLine(""); } } }
public void Parse(Dictionary <ushort, List <ulong> > track, Dictionary <ulong, Record> map, CASCHandler handler, bool quiet, OverToolFlags flags) { switch (flags.Positionals[2].ToLowerInvariant()) { case "list": { DeltaFile old = new DeltaFile(flags.Positionals[3]); DeltaFile @new = new DeltaFile(flags.Positionals[4]); if (string.IsNullOrEmpty(old.Name) || old.Files.Count == 0) { Console.Error.WriteLine("Invalid old file"); } else if (string.IsNullOrEmpty(@new.Name) || @new.Files.Count == 0) { Console.Error.WriteLine("Invalid new file"); } else { Console.Out.WriteLine("Comparing {0} with {1}", old.Name, @new.Name); foreach (KeyValuePair <ulong, DeltaRecord> pair in @new.Files) { if (old.Files.ContainsKey(pair.Key)) { if (old.Files[pair.Key].Size == pair.Value.Size) { if (old.Version != 2 || @new.Version != 2 || old.Files[pair.Key].Hash.EqualsTo(pair.Value.Hash)) { continue; } } Console.Out.WriteLine("{0:X12}.{1:X3} changed ({2} delta bytes)", OWLib.GUID.LongKey(pair.Key), OWLib.GUID.Type(pair.Key), old.Files[pair.Key].Size - pair.Value.Size); } else { Console.Out.WriteLine("{0:X12}.{1:X3} added ({2} bytes)", OWLib.GUID.LongKey(pair.Key), OWLib.GUID.Type(pair.Key), pair.Value.Size); } } foreach (KeyValuePair <ulong, DeltaRecord> pair in old.Files) { if ([email protected](pair.Key)) { Console.Out.WriteLine("{0:X12}.{1:X3} removed", OWLib.GUID.LongKey(pair.Key), OWLib.GUID.Type(pair.Key)); } } } old.Dispose(); @new.Dispose(); break; } case "delta": { DeltaFile old = new DeltaFile(flags.Positionals[3]); if (string.IsNullOrEmpty(old.Name) || old.Files.Count == 0) { Console.Error.WriteLine("Invalid old file"); } else { Console.Out.WriteLine("Comparing {0} with current ({1})", old.Name, handler.Config.BuildName); foreach (KeyValuePair <ulong, Record> pair in map) { if (handler.Encoding.GetEntry(pair.Value.record.ContentKey, out EncodingEntry enc)) { if (old.Files.ContainsKey(pair.Key)) { if (old.Files[pair.Key].Size == pair.Value.record.Size) { if (old.Version != 2 || old.Files[pair.Key].Hash.EqualsTo(enc.Key)) { continue; } } Console.Out.WriteLine("{0:X12}.{1:X3} changed ({2} delta bytes)", OWLib.GUID.LongKey(pair.Key), OWLib.GUID.Type(pair.Key), old.Files[pair.Key].Size - pair.Value.record.Size); } else { Console.Out.WriteLine("{0:X12}.{1:X3} added ({2} bytes)", OWLib.GUID.LongKey(pair.Key), OWLib.GUID.Type(pair.Key), pair.Value.record.Size); } } } foreach (KeyValuePair <ulong, DeltaRecord> pair in old.Files) { if (!map.ContainsKey(pair.Key)) { Console.Out.WriteLine("{0:X12}.{1:X3} removed", OWLib.GUID.LongKey(pair.Key), OWLib.GUID.Type(pair.Key)); } } } old.Dispose(); break; } case "create": { DeltaFile delta = new DeltaFile(flags.Positionals[3]); delta.SetName(handler.Config.BuildName); foreach (KeyValuePair <ulong, Record> pair in map) { if (handler.Encoding.GetEntry(pair.Value.record.ContentKey, out EncodingEntry enc)) { delta.Files[pair.Key] = new DeltaRecord { Size = pair.Value.record.Size, Hash = enc.Key }; } } delta.Save(); delta.Dispose(); break; } case "create_flat": { DeltaFile delta = new DeltaFile(flags.Positionals[3]); delta.SetName(handler.Config.BuildName); foreach (KeyValuePair <ulong, Record> pair in map) { delta.Files[pair.Key] = new DeltaRecord { Size = pair.Value.record.Size, Hash = pair.Value.record.ContentKey }; } delta.Save(); delta.Dispose(); break; } case "dump": { DeltaFile old = new DeltaFile(flags.Positionals[4]); List <ushort> types = new List <ushort>(); if (flags.Positionals.Length > 5) { types.AddRange(flags.Positionals.Skip(5) .Select((it) => ushort.Parse(it, System.Globalization.NumberStyles.HexNumber))); } if (string.IsNullOrEmpty(old.Name) || old.Files.Count == 0) { Console.Error.WriteLine("Invalid old file"); } else { foreach (KeyValuePair <ulong, Record> pair in map) { if (types.Count > 0 && !types.Contains(OWLib.GUID.Type(pair.Key))) { continue; } if (handler.Encoding.GetEntry(pair.Value.record.ContentKey, out EncodingEntry enc)) { if (old.Files.ContainsKey(pair.Key)) { if (old.Files[pair.Key].Size == pair.Value.record.Size) { if (old.Version != 2 || old.Files[pair.Key].Hash.EqualsTo(enc.Key)) { continue; } } Save(flags.Positionals[3], pair.Value, handler, "changed", quiet); } else { Save(flags.Positionals[3], pair.Value, handler, "new", quiet); } } } } old.Dispose(); break; } case "extract": { DeltaFile old = new DeltaFile(flags.Positionals[4]); List <ushort> types = new List <ushort>(); List <ushort> ignoreTypes = new List <ushort>(); if (flags.Positionals.Length > 5) { types.AddRange(flags.Positionals.Skip(5) .Where((it) => !it.StartsWith("!")).Select((it) => ushort.Parse(it, System.Globalization.NumberStyles.HexNumber))); ignoreTypes.AddRange(flags.Positionals.Skip(5) .Where((it) => it.StartsWith("!")).Select((it) => ushort.Parse(it.Substring(1), System.Globalization.NumberStyles.HexNumber))); } if (string.IsNullOrEmpty(old.Name) || old.Files.Count == 0) { Console.Error.WriteLine("Invalid old file"); } else { foreach (KeyValuePair <ulong, DeltaRecord> pair in old.Files) { if (types.Count > 0 && !types.Contains(OWLib.GUID.Type(pair.Key))) { continue; } if (ignoreTypes.Count > 0 && ignoreTypes.Contains(OWLib.GUID.Type(pair.Key))) { continue; } if (handler.Encoding.GetEntry(pair.Value.Hash, out EncodingEntry enc)) { Save(flags.Positionals[3], enc.Key, pair.Key, handler, quiet); } } } old.Dispose(); break; } default: { Console.Out.WriteLine("Valid modes: list, create, delta, dump, extract"); Console.Out.WriteLine("create [destination owdelta]"); Console.Out.WriteLine("list [old owdelta] [new owdelta]"); Console.Out.WriteLine("delta [old owdelta]"); Console.Out.WriteLine("extract [detination] [owdelta] [types]"); Console.Out.WriteLine("dump [detination] [old owdelta] [types]"); break; } } }