Esempio n. 1
0
        private Dialogue ConvertDialogue(Stream cacheStream, Dialogue dialogue)
        {
            if (BlamSoundGestalt == null)
            {
                BlamSoundGestalt = PortingContextFactory.LoadSoundGestalt(CacheContext, ref BlamCache);
            }

            CachedTagInstance edAdlg = null;
            AiDialogueGlobals adlg   = null;

            foreach (var tag in CacheContext.TagCache.Index.FindAllInGroup("adlg"))
            {
                edAdlg = tag;
                break;
            }

            adlg = CacheContext.Deserialize <AiDialogueGlobals>(cacheStream, edAdlg);

            //Create empty udlg vocalization block and fill it with empty blocks matching adlg

            List <Dialogue.Vocalization> newVocalization = new List <Dialogue.Vocalization>();

            foreach (var vocalization in adlg.Vocalizations)
            {
                Dialogue.Vocalization block = new Dialogue.Vocalization
                {
                    Sound   = null,
                    Flags   = 0,
                    Unknown = 0,
                    Name    = vocalization.Name,
                };
                newVocalization.Add(block);
            }

            //Match the tags with the proper stringId

            for (int i = 0; i < 304; i++)
            {
                var vocalization = newVocalization[i];
                for (int j = 0; j < dialogue.Vocalizations.Count; j++)
                {
                    var vocalizationH3 = dialogue.Vocalizations[j];
                    if (CacheContext.StringIdCache.GetString(vocalization.Name).Equals(CacheContext.StringIdCache.GetString(vocalizationH3.Name)))
                    {
                        vocalization.Flags   = vocalizationH3.Flags;
                        vocalization.Unknown = vocalizationH3.Unknown;
                        vocalization.Sound   = vocalizationH3.Sound;
                        break;
                    }
                }
            }

            dialogue.Vocalizations = newVocalization;

            return(dialogue);
        }
Esempio n. 2
0
        public void ExtractXMA(CacheFile.IndexItem blamTag, string directory)
        {
            if (BlamSoundGestalt == null)
            {
                BlamSoundGestalt = PortingContextFactory.LoadSoundGestalt(CacheContext, ref BlamCache);
            }

            var blamContext = new CacheSerializationContext(ref BlamCache, blamTag);

            var sound = BlamCache.Deserializer.Deserialize <Sound>(blamContext);


            var xmaFileSize = BlamSoundGestalt.GetFileSize(sound.SoundReference.PitchRangeIndex, sound.SoundReference.PitchRangeCount);

            if (xmaFileSize < 0)
            {
                return;
            }

            var xmaData = BlamCache.GetSoundRaw(sound.SoundReference.ZoneAssetHandle, xmaFileSize);

            if (xmaData == null)
            {
                Console.WriteLine($"ERROR: Failed to find sound data!");
                return;
            }

            var    parts    = blamTag.Name.Split('\\');
            string baseName = parts[parts.Length - 1];

            for (int pitchRangeIndex = sound.SoundReference.PitchRangeIndex; pitchRangeIndex < sound.SoundReference.PitchRangeIndex + sound.SoundReference.PitchRangeCount; pitchRangeIndex++)
            {
                var relativePitchRangeIndex = pitchRangeIndex - sound.SoundReference.PitchRangeIndex;
                var permutationCount        = BlamSoundGestalt.GetPermutationCount(pitchRangeIndex);

                for (int i = 0; i < permutationCount; i++)
                {
                    BlamSound blamSound       = SoundConverter.GetXMA(BlamCache, BlamSoundGestalt, sound, relativePitchRangeIndex, i, xmaData);
                    string    permutationName = $"{baseName}_{relativePitchRangeIndex}_{i}";
                    var       fileName        = $"{directory}\\{permutationName}.xma";

                    using (EndianWriter output = new EndianWriter(new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.None), EndianFormat.BigEndian))
                    {
                        XMAFile XMAfile = new XMAFile(blamSound);
                        XMAfile.Write(output);
                    }
                }
            }
        }
Esempio n. 3
0
        public void ExtractWAV(CacheFile.IndexItem blamTag, string directory)
        {
            Console.WriteLine($"Extracting {blamTag.Name}.sound");
            if (BlamSoundGestalt == null)
            {
                BlamSoundGestalt = PortingContextFactory.LoadSoundGestalt(CacheContext, ref BlamCache);
            }

            var blamContext = new CacheSerializationContext(ref BlamCache, blamTag);

            var sound = BlamCache.Deserializer.Deserialize <Sound>(blamContext);

            var xmaFileSize = BlamSoundGestalt.GetFileSize(sound.SoundReference.PitchRangeIndex, sound.SoundReference.PitchRangeCount);

            var xmaData = BlamCache.GetSoundRaw(sound.SoundReference.ZoneAssetHandle, xmaFileSize);

            if (xmaData == null)
            {
                Console.WriteLine($"ERROR: Failed to find sound data!");
                return;
            }

            var    OutDir     = directory;
            string sound_name = blamTag.Name.Replace('\\', '_');

            sound_name = Path.Combine(directory, sound_name);

            for (int pitchRangeIndex = sound.SoundReference.PitchRangeIndex; pitchRangeIndex < sound.SoundReference.PitchRangeIndex + sound.SoundReference.PitchRangeCount; pitchRangeIndex++)
            {
                var relativePitchRangeIndex = pitchRangeIndex - sound.SoundReference.PitchRangeIndex;
                var permutationCount        = BlamSoundGestalt.GetPermutationCount(pitchRangeIndex);

                for (int i = 0; i < permutationCount; i++)
                {
                    string permutationName = $"{sound_name}_{relativePitchRangeIndex}_{i}";
                    permutationName += ".mp3";

                    BlamSound blamSound = SoundConverter.ConvertGen3Sound(BlamCache, BlamSoundGestalt, sound, relativePitchRangeIndex, i, xmaData);
                    using (EndianWriter output = new EndianWriter(new FileStream(permutationName, FileMode.Create, FileAccess.Write, FileShare.None), EndianFormat.BigEndian))
                    {
                        output.WriteBlock(blamSound.Data);
                    }
                }
            }
        }
Esempio n. 4
0
        private SoundLooping ConvertSoundLooping(SoundLooping soundLooping)
        {
            if (BlamSoundGestalt == null)
            {
                BlamSoundGestalt = PortingContextFactory.LoadSoundGestalt(CacheContext, ref BlamCache);
            }

            soundLooping.Unused = null;

            soundLooping.SoundClass = ((int)soundLooping.SoundClass < 50) ? soundLooping.SoundClass : (soundLooping.SoundClass + 1);

            if (soundLooping.SoundClass == SoundLooping.SoundClassValue.FirstPersonInside)
            {
                soundLooping.SoundClass = SoundLooping.SoundClassValue.InsideSurroundTail;
            }

            if (soundLooping.SoundClass == SoundLooping.SoundClassValue.FirstPersonOutside)
            {
                soundLooping.SoundClass = SoundLooping.SoundClassValue.OutsideSurroundTail;
            }

            /* unsuccessful hacks of death and suffering
             * foreach (var track in soundLooping.Tracks)
             * {
             *  track.FadeInDuration *= 2f;
             *  track.Unknown1 *= 2f;
             *  track.FadeOutDuration *= 2f;
             *  track.AlternateCrossfadeDuration *= 2f;
             *  track.Unknown5 *= 2;
             *  track.AlternateFadeOutDuration *= 2f;
             *  track.Unknown6 *= 2f;
             * }
             *
             * foreach (var detailSound in soundLooping.DetailSounds)
             *  detailSound.RandomPeriodBounds = new Bounds<float>(
             *      detailSound.RandomPeriodBounds.Lower * 2f,
             *      detailSound.RandomPeriodBounds.Upper * 2f);*/

            return(soundLooping);
        }
Esempio n. 5
0
        public override object Execute(List <string> args)
        {
            if (args.Count < 1)
            {
                return(false);
            }

            while (args.Count > 1)
            {
                switch (args[0].ToLower())
                {
                case "memory":
                    break;

                default:
                    throw new FormatException(args[0]);
                }

                args.RemoveAt(0);
            }

            var fileName = new FileInfo(args[0]);

            if (!fileName.Exists)
            {
                Console.WriteLine($"Cache {fileName.FullName} does not exist");
                return(true);
            }

            Console.Write("Loading cache...");

            GameCache blamCache = GameCache.Open(fileName);

            ContextStack.Push(PortingContextFactory.Create(ContextStack, Cache, blamCache));

            Console.WriteLine("done.");

            return(true);
        }
Esempio n. 6
0
        private SoundLooping ConvertSoundLooping(SoundLooping soundLooping)
        {
            if (BlamSoundGestalt == null)
            {
                BlamSoundGestalt = PortingContextFactory.LoadSoundGestalt(CacheContext, ref BlamCache);
            }

            soundLooping.Unused = null;

            soundLooping.SoundClass = ((int)soundLooping.SoundClass < 50) ? soundLooping.SoundClass : (soundLooping.SoundClass + 1);

            if (soundLooping.SoundClass == SoundLooping.SoundClassValue.FirstPersonInside)
            {
                soundLooping.SoundClass = SoundLooping.SoundClassValue.InsideSurroundTail;
            }

            if (soundLooping.SoundClass == SoundLooping.SoundClassValue.FirstPersonOutside)
            {
                soundLooping.SoundClass = SoundLooping.SoundClassValue.OutsideSurroundTail;
            }


            //
            // Fixes for looping sound (temporary and hacky)
            //

            if (soundLooping.SoundClass == SoundLooping.SoundClassValue.VehicleEngine ||
                soundLooping.SoundClass == SoundLooping.SoundClassValue.VehicleEngineLod ||
                soundLooping.SoundClass == SoundLooping.SoundClassValue.Music)
            {
                soundLooping.Unknown4 = 1;
            }


            return(soundLooping);
        }
Esempio n. 7
0
        private Sound ConvertSound(Stream cacheStream, Dictionary <ResourceLocation, Stream> resourceStreams, Sound sound, string blamTag_Name)
        {
            if (BlamSoundGestalt == null)
            {
                BlamSoundGestalt = PortingContextFactory.LoadSoundGestalt(CacheContext, ref BlamCache);
            }

            if (!File.Exists(@"Tools\ffmpeg.exe") || !File.Exists(@"Tools\towav.exe"))
            {
                Console.WriteLine("Failed to locate sound conversion tools, please install ffmpeg and towav in the Tools folder");
                return(null);
            }

            //
            // Convert Sound Tag Data
            //

            var platformCodec      = BlamSoundGestalt.PlatformCodecs[sound.SoundReference.PlatformCodecIndex];
            var playbackParameters = BlamSoundGestalt.PlaybackParameters[sound.SoundReference.PlaybackParameterIndex];
            var scale          = BlamSoundGestalt.Scales[sound.SoundReference.ScaleIndex];
            var promotion      = sound.SoundReference.PromotionIndex != -1 ? BlamSoundGestalt.Promotions[sound.SoundReference.PromotionIndex] : new Promotion();
            var customPlayBack = sound.SoundReference.CustomPlaybackIndex != -1 ? new List <CustomPlayback> {
                BlamSoundGestalt.CustomPlaybacks[sound.SoundReference.CustomPlaybackIndex]
            } : new List <CustomPlayback>();
            var loop = sound.Flags.HasFlag(Sound.FlagsValue.LoopingSound);

            sound.PlaybackParameters = playbackParameters;
            sound.Scale           = scale;
            sound.PlatformCodec   = platformCodec.DeepClone();
            sound.Promotion       = promotion;
            sound.CustomPlayBacks = customPlayBack;

            //
            // Tag fixes
            //

            sound.SampleRate = platformCodec.SampleRate;
            sound.ImportType = ImportType.SingleLayer;
            // helps looping sound? there is another value, 10 for Unknown2 but I don't know when to activate it.
            if (sound.SoundReference.PitchRangeCount > 1)
            {
                sound.ImportType = ImportType.MultiLayer;
            }

            sound.PlatformCodec.LoadMode = 0;

            //
            // Process all the pitch ranges
            //

            var xmaFileSize = BlamSoundGestalt.GetFileSize(sound.SoundReference.PitchRangeIndex, sound.SoundReference.PitchRangeCount);

            if (xmaFileSize < 0)
            {
                return(null);
            }

            var xmaData = BlamCache.GetSoundRaw(sound.SoundReference.ZoneAssetHandle, xmaFileSize);

            if (xmaData == null)
            {
                return(null);
            }

            sound.PitchRanges = new List <PitchRange>(sound.SoundReference.PitchRangeCount);

            var soundDataAggregate     = new byte[0].AsEnumerable();
            var currentSoundDataOffset = 0;
            var totalSampleCount       = (uint)0;

            for (int pitchRangeIndex = sound.SoundReference.PitchRangeIndex; pitchRangeIndex < sound.SoundReference.PitchRangeIndex + sound.SoundReference.PitchRangeCount; pitchRangeIndex++)
            {
                totalSampleCount += BlamSoundGestalt.GetSamplesPerPitchRange(pitchRangeIndex);

                //
                // Convert Blam pitch range to ElDorado format
                //

                var pitchRange = BlamSoundGestalt.PitchRanges[pitchRangeIndex];
                pitchRange.ImportName           = ConvertStringId(BlamSoundGestalt.ImportNames[pitchRange.ImportNameIndex].Name);
                pitchRange.PitchRangeParameters = BlamSoundGestalt.PitchRangeParameters[pitchRange.PitchRangeParametersIndex];
                pitchRange.Unknown1             = 0;
                pitchRange.Unknown2             = 0;
                pitchRange.Unknown3             = 0;
                pitchRange.Unknown4             = 0;
                pitchRange.Unknown5             = -1;
                pitchRange.Unknown6             = -1;
                //I suspect this unknown7 to be a flag to tell if there is a Unknownblock in extrainfo. (See a sound in udlg for example)
                pitchRange.Unknown7         = 0;
                pitchRange.PermutationCount = (byte)BlamSoundGestalt.GetPermutationCount(pitchRangeIndex);
                pitchRange.Unknown8         = -1;

                // Add pitch range to ED sound
                sound.PitchRanges.Add(pitchRange);
                var newPitchRangeIndex = pitchRangeIndex - sound.SoundReference.PitchRangeIndex;
                sound.PitchRanges[newPitchRangeIndex].Permutations = new List <Permutation>();

                //
                // Determine the audio channel count
                //

                var channelCount = Encoding.GetChannelCount(sound.PlatformCodec.Encoding);

                //
                // Set compression format
                //

                sound.PlatformCodec.Compression = Compression.MP3;

                //
                // Convert Blam permutations to ElDorado format
                //

                var useCache = Sounds.UseAudioCacheCommand.AudioCacheDirectory != null;

                var basePermutationCacheName = Path.Combine(
                    useCache ? Sounds.UseAudioCacheCommand.AudioCacheDirectory.FullName : TempDirectory.FullName,
                    GetTagFileFriendlyName(blamTag_Name));

                var permutationCount        = BlamSoundGestalt.GetPermutationCount(pitchRangeIndex);
                var permutationOrder        = BlamSoundGestalt.GetPermutationOrder(pitchRangeIndex);
                var relativePitchRangeIndex = pitchRangeIndex - sound.SoundReference.PitchRangeIndex;

                for (int i = 0; i < permutationCount; i++)
                {
                    var permutationIndex  = pitchRange.FirstPermutationIndex + i;
                    var permutationSize   = BlamSoundGestalt.GetPermutationSize(permutationIndex);
                    var permutationOffset = BlamSoundGestalt.GetPermutationOffset(permutationIndex);

                    var permutation = BlamSoundGestalt.GetPermutation(permutationIndex).DeepClone();

                    permutation.ImportName            = ConvertStringId(BlamSoundGestalt.ImportNames[permutation.ImportNameIndex].Name);
                    permutation.SkipFraction          = new Bounds <float>(0.0f, permutation.Gain);
                    permutation.PermutationChunks     = new List <PermutationChunk>();
                    permutation.PermutationNumber     = (uint)permutationOrder[i];
                    permutation.IsNotFirstPermutation = (uint)(permutation.PermutationNumber == 0 ? 0 : 1);

                    string permutationName = $"{basePermutationCacheName}_{relativePitchRangeIndex}_{i}";

                    string extension = "mp3";

                    var cacheFileName = $"{permutationName}.{extension}";

                    bool exists = File.Exists(cacheFileName);

                    byte[] permutationData = null;

                    if (!exists || !useCache)
                    {
                        BlamSound blamSound = SoundConverter.ConvertGen3Sound(BlamCache, BlamSoundGestalt, sound, relativePitchRangeIndex, i, xmaData);
                        permutationData = blamSound.Data;
                        if (useCache)
                        {
                            using (EndianWriter output = new EndianWriter(new FileStream(cacheFileName, FileMode.Create, FileAccess.Write, FileShare.None), EndianFormat.BigEndian))
                            {
                                output.WriteBlock(blamSound.Data);
                            }
                        }
                    }
                    else
                    {
                        permutationData = File.ReadAllBytes(cacheFileName);
                    }

                    permutation.PermutationChunks.Add(new PermutationChunk(currentSoundDataOffset, permutationData.Length));
                    currentSoundDataOffset += permutationData.Length;
                    pitchRange.Permutations.Add(permutation);

                    soundDataAggregate = soundDataAggregate.Concat(permutationData);
                }
            }

            sound.Promotion.LongestPermutationDuration = (uint)sound.SoundReference.MaximumPlayTime;
            sound.Promotion.TotalSampleSize            = totalSampleCount;

            //
            // Convert Blam extra info to ElDorado format
            //

            var extraInfo = new ExtraInfo()
            {
                LanguagePermutations       = new List <ExtraInfo.LanguagePermutation>(),
                EncodedPermutationSections = new List <ExtraInfo.EncodedPermutationSection>()
            };

            for (int u = 0; u < sound.SoundReference.PitchRangeCount; u++)
            {
                var pitchRange = BlamSoundGestalt.PitchRanges[sound.SoundReference.PitchRangeIndex + u];

                for (int i = 0; i < pitchRange.PermutationCount; i++)
                {
                    var permutation      = BlamSoundGestalt.GetPermutation(pitchRange.FirstPermutationIndex + i);
                    var permutationChunk = BlamSoundGestalt.GetPermutationChunk(permutation.FirstPermutationChunkIndex);

                    extraInfo.LanguagePermutations.Add(new ExtraInfo.LanguagePermutation
                    {
                        RawInfo = new List <ExtraInfo.LanguagePermutation.RawInfoBlock>
                        {
                            new ExtraInfo.LanguagePermutation.RawInfoBlock
                            {
                                SkipFractionName = StringId.Invalid,
                                UnknownList      = new List <ExtraInfo.LanguagePermutation.RawInfoBlock.Unknown>
                                {
                                    new ExtraInfo.LanguagePermutation.RawInfoBlock.Unknown
                                    {
                                        Unknown1 = permutationChunk.UnknownA,
                                        Unknown2 = permutationChunk.UnknownSize,
                                        Unknown3 = 0,
                                        Unknown4 = permutation.SampleSize,
                                        Unknown5 = 0,
                                        Unknown6 = permutationChunk.EncodedSize & 0xFFFF
                                    }
                                },
                                Compression          = 8,
                                ResourceSampleSize   = pitchRange.Permutations[i].SampleSize,
                                ResourceSampleOffset = (uint)pitchRange.Permutations[i].PermutationChunks[0].Offset,
                                SampleCount          = (uint)pitchRange.Permutations[i].PermutationChunks[0].EncodedSize & 0x3FFFFFF,
                                //SampleCount = (uint)Math.Floor(pitchRange.Permutations[i].SampleSize * 128000.0 / (8 * sound.SampleRate.GetSampleRateHz())),
                                Unknown24 = 480
                            }
                        }
                    });
                }
            }

            if (sound.SoundReference.ExtraInfoIndex != -1)
            {
                foreach (var section in BlamSoundGestalt.ExtraInfo[sound.SoundReference.ExtraInfoIndex].EncodedPermutationSections)
                {
                    var newSection = section.DeepClone();

                    foreach (var info in newSection.SoundDialogueInfo)
                    {
                        for (var i = ((info.MouthDataLength % 2) == 0 ? 0 : 1); (i + 1) < info.MouthDataLength; i += 2)
                        {
                            Array.Reverse(newSection.EncodedData, (int)(info.MouthDataOffset + i), 2);
                        }

                        for (var i = ((info.LipsyncDataLength % 2) == 0 ? 0 : 1); (i + 1) < info.LipsyncDataLength; i += 2)
                        {
                            Array.Reverse(newSection.EncodedData, (int)(info.LipsyncDataOffset + i), 2);
                        }
                    }

                    extraInfo.EncodedPermutationSections.Add(newSection);
                }
            }

            sound.ExtraInfo = new List <ExtraInfo> {
                extraInfo
            };

            //
            // Convert Blam languages to ElDorado format
            //

            if (sound.SoundReference.LanguageIndex != -1)
            {
                sound.Languages = new List <LanguageBlock>();

                foreach (var language in BlamSoundGestalt.Languages)
                {
                    sound.Languages.Add(new LanguageBlock
                    {
                        Language             = language.Language,
                        PermutationDurations = new List <LanguageBlock.PermutationDurationBlock>(),
                        PitchRangeDurations  = new List <LanguageBlock.PitchRangeDurationBlock>(),
                    });

                    //Add all the  Pitch Range Duration block (pitch range count dependent)

                    var curLanguage = sound.Languages.Last();

                    for (int i = 0; i < sound.SoundReference.PitchRangeCount; i++)
                    {
                        curLanguage.PitchRangeDurations.Add(language.PitchRangeDurations[sound.SoundReference.LanguageIndex + i]);
                    }

                    //Add all the Permutation Duration Block and adjust offsets

                    for (int i = 0; i < curLanguage.PitchRangeDurations.Count; i++)
                    {
                        var curPRD = curLanguage.PitchRangeDurations[i];

                        //Get current block count for new index
                        short newPermutationIndex = (short)curLanguage.PermutationDurations.Count();

                        for (int j = curPRD.PermutationStartIndex; j < curPRD.PermutationStartIndex + curPRD.PermutationCount; j++)
                        {
                            curLanguage.PermutationDurations.Add(language.PermutationDurations[j]);
                        }

                        //apply new index
                        curPRD.PermutationStartIndex = newPermutationIndex;
                    }
                }
            }

            //
            // Prepare resource
            //

            sound.Unused    = new byte[] { 0, 0, 0, 0 };
            sound.Unknown12 = 0;

            sound.Resource = new PageableResource
            {
                Page = new RawPage
                {
                    Index = -1,
                },
                Resource = new TagResourceGen3
                {
                    ResourceType             = TagResourceTypeGen3.Sound,
                    DefinitionData           = new byte[20],
                    DefinitionAddress        = new CacheResourceAddress(CacheResourceAddressType.Definition, 536870912),
                    ResourceFixups           = new List <TagResourceGen3.ResourceFixup>(),
                    ResourceDefinitionFixups = new List <TagResourceGen3.ResourceDefinitionFixup>(),
                    Unknown2 = 1
                }
            };

            var data = soundDataAggregate.ToArray();

            var resourceContext = new ResourceSerializationContext(CacheContext, sound.Resource);

            CacheContext.Serializer.Serialize(resourceContext,
                                              new SoundResourceDefinition
            {
                Data = new TagData(data.Length, new CacheResourceAddress(CacheResourceAddressType.Resource, 0))
            });

            var definitionFixup = new TagResourceGen3.ResourceFixup()
            {
                BlockOffset = 12,
                Address     = new CacheResourceAddress(CacheResourceAddressType.Resource, 1073741824)
            };

            sound.Resource.Resource.ResourceFixups.Add(definitionFixup);

            sound.Resource.ChangeLocation(ResourceLocation.Audio);
            var resource = sound.Resource;

            if (resource == null)
            {
                throw new ArgumentNullException("resource");
            }

            var cache = CacheContext.GetResourceCache(ResourceLocation.Audio);

            if (!resourceStreams.ContainsKey(ResourceLocation.Audio))
            {
                resourceStreams[ResourceLocation.Audio] = FlagIsSet(PortingFlags.Memory) ?
                                                          new MemoryStream() :
                                                          (Stream)CacheContext.OpenResourceCacheReadWrite(ResourceLocation.Audio);

                if (FlagIsSet(PortingFlags.Memory))
                {
                    using (var resourceStream = CacheContext.OpenResourceCacheRead(ResourceLocation.Audio))
                        resourceStream.CopyTo(resourceStreams[ResourceLocation.Audio]);
                }
            }

            resource.Page.Index = cache.Add(resourceStreams[ResourceLocation.Audio], data, out uint compressedSize);
            resource.Page.CompressedBlockSize   = compressedSize;
            resource.Page.UncompressedBlockSize = (uint)data.Length;
            resource.DisableChecksum();

            for (int i = 0; i < 4; i++)
            {
                sound.Resource.Resource.DefinitionData[i] = (byte)(sound.Resource.Page.UncompressedBlockSize >> (i * 8));
            }

            return(sound);
        }
        public override object Execute(List <string> args)
        {
            if (args.Count < 1)
            {
                return(false);
            }

            var memory = false;

            while (args.Count > 1)
            {
                switch (args[0].ToLower())
                {
                case "memory":
                    memory = true;
                    break;

                default:
                    throw new FormatException(args[0]);
                }

                args.RemoveAt(0);
            }

            var blamCacheFile = new FileInfo(args[0]);

            if (!blamCacheFile.Exists)
            {
                Console.WriteLine($"CacheFile {blamCacheFile.FullName} does not exist");
                return(true);
            }

            Console.Write("Loading blam cache file...");

            CacheFile blamCache = null;

            using (var cacheStream = new FileStream(blamCacheFile.FullName, FileMode.Open, FileAccess.Read))
            {
                var reader = new EndianReader(cacheStream, EndianFormat.BigEndian);

                var head = reader.ReadInt32();

                if (head == 1684104552)
                {
                    reader.Format = EndianFormat.LittleEndian;
                }

                var v = reader.ReadInt32();

                switch (v)
                {
                case 8:     // Gen2
                    reader.SeekTo(36);
                    switch (reader.ReadInt32())
                    {
                    case 0:         // Halo 2 Xbox
                        reader.SeekTo(288);
                        break;

                    case -1:         // Halo 2 Vista
                        reader.SeekTo(300);
                        break;
                    }
                    break;

                default:     // Gen3+
                    reader.SeekTo(284);
                    break;
                }

                var version = CacheVersionDetection.GetFromBuildName(reader.ReadString(32));

                switch (version)
                {
                case CacheVersion.Halo2Xbox:
                case CacheVersion.Halo2Vista:
                    if (blamCacheFile.Name != "mainmenu.map")
                    {
                        new CacheFileGen2(CacheContext, new FileInfo(Path.Combine(blamCacheFile.Directory.FullName, "mainmenu.map")), version, memory);
                    }
                    if (blamCacheFile.Name != "shared.map")
                    {
                        new CacheFileGen2(CacheContext, new FileInfo(Path.Combine(blamCacheFile.Directory.FullName, "shared.map")), version, memory);
                    }
                    if (blamCacheFile.Name != "single_player_shared.map")
                    {
                        new CacheFileGen2(CacheContext, new FileInfo(Path.Combine(blamCacheFile.Directory.FullName, "single_player_shared.map")), version, memory);
                    }
                    blamCache = new CacheFileGen2(CacheContext, blamCacheFile, version, memory);
                    break;

                case CacheVersion.Halo3Retail:
                case CacheVersion.Halo3ODST:
                case CacheVersion.HaloReach:
                    blamCache = new CacheFileGen3(CacheContext, blamCacheFile, version, memory);
                    break;

                default:     // Same question here as above.
                    throw new NotSupportedException(CacheVersionDetection.GetBuildName(version));
                }
            }

            ContextStack.Push(PortingContextFactory.Create(ContextStack, CacheContext, blamCache));

            Console.WriteLine("done.");

            return(true);
        }