Пример #1
0
        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);
            }
        }
Пример #2
0
        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();
            }
        }
Пример #3
0
        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));
            }
        }
Пример #4
0
        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("");
            }
        }
Пример #5
0
        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;
                    }
                }
            }
        }
Пример #6
0
        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");
                        }
                    }
                }
            }
        }
Пример #7
0
        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);
            }
        }
Пример #8
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);
            }
        }
Пример #9
0
        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, "");
                                }
                            }
                        }
                    }
                }
            }
        }
Пример #10
0
        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));
                        }
                    }
                }
            }
        }
Пример #11
0
        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;
            }
            }
        }
Пример #12
0
        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");
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
Пример #13
0
        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);
            }
        }
Пример #14
0
        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);
            }
        }
Пример #15
0
        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);
            }
        }
Пример #16
0
 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");
     }
 }
Пример #17
0
        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;
                    }
                }
            }
        }
Пример #18
0
        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);
                    }
                }
            }
        }
Пример #19
0
        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);
                    }
                }
            }
        }
Пример #20
0
        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);
                //}
            }
        }
Пример #21
0
        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();
            }
        }
Пример #22
0
        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());
                                }
                            }
                        }
                    }
                }
            }
        }
Пример #23
0
 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);
 }
Пример #24
0
        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);
        }
Пример #25
0
        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);
                }
            }
        }
Пример #26
0
        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("");
                }
            }
        }
Пример #27
0
        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;
            }
            }
        }