Пример #1
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);
        }
Пример #2
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);
            }
        }
Пример #3
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);
                    }
                }
            }
        }
Пример #4
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");
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
Пример #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];

            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);
            }
        }