Ejemplo n.º 1
0
        public ModelAnimationGraph ConvertModelAnimationGraph(Stream cacheStream, Dictionary <ResourceLocation, Stream> resourceStreams, ModelAnimationGraph definition)
        {
            if (BlamCache.ResourceGestalt == null)
            {
                BlamCache.LoadResourceTags();
            }

            definition.ResourceGroups = ConvertModelAnimationGraphResourceGroups(cacheStream, resourceStreams, definition.ResourceGroups);
            definition.Modes          = definition.Modes.OrderBy(a => a.Name.Set).ThenBy(a => a.Name.Index).ToList();

            foreach (var mode in definition.Modes)
            {
                mode.WeaponClass = mode.WeaponClass.OrderBy(a => a.Label.Set).ThenBy(a => a.Label.Index).ToList();

                foreach (var weaponClass in mode.WeaponClass)
                {
                    weaponClass.WeaponType = weaponClass.WeaponType.OrderBy(a => a.Label.Set).ThenBy(a => a.Label.Index).ToList();

                    foreach (var weaponType in weaponClass.WeaponType)
                    {
                        weaponType.Actions        = weaponType.Actions.OrderBy(a => a.Label.Set).ThenBy(a => a.Label.Index).ToList();
                        weaponType.Overlays       = weaponType.Overlays.OrderBy(a => a.Label.Set).ThenBy(a => a.Label.Index).ToList();
                        weaponType.DeathAndDamage = weaponType.DeathAndDamage.OrderBy(a => a.Label.Set).ThenBy(a => a.Label.Index).ToList();
                        weaponType.Transitions    = weaponType.Transitions.OrderBy(a => a.FullName.Set).ThenBy(a => a.FullName.Index).ToList();

                        foreach (var transition in weaponType.Transitions)
                        {
                            transition.Destinations = transition.Destinations.OrderBy(a => a.FullName.Set).ThenBy(a => a.FullName.Index).ToList();
                        }
                    }
                }
            }

            return(definition);
        }
Ejemplo n.º 2
0
        private void MergeMultilingualUnicodeStringList(Stream cacheStream, Stream blamCacheStream, Dictionary <ResourceLocation, Stream> resourceStreams, CachedTag edTag, CachedTag h3Tag)
        {
            MultilingualUnicodeStringList h3Def = BlamCache.Deserialize <MultilingualUnicodeStringList>(blamCacheStream, h3Tag);
            var edDef = CacheContext.Deserialize <MultilingualUnicodeStringList>(cacheStream, edTag);

            ConvertMultilingualUnicodeStringList(cacheStream, blamCacheStream, resourceStreams, h3Def);

            var mergedStringCount = 0;

            for (var i = 0; i < h3Def.Strings.Count; i++)
            {
                var found = false;

                for (var j = 0; j < edDef.Strings.Count; j++)
                {
                    if (h3Def.Strings[i].StringID == edDef.Strings[j].StringID)
                    {
                        found = true;
                        break;
                    }
                }

                if (!found)
                {
                    var localizedStr = new LocalizedString
                    {
                        StringID    = h3Def.Strings[i].StringID,
                        StringIDStr = h3Def.Strings[i].StringIDStr
                    };

                    edDef.Strings.Add(localizedStr);

                    for (var x = 0; x < 12; x++)
                    {
                        edDef.SetString(
                            localizedStr,
                            (GameLanguage)x,
                            h3Def.GetString(
                                h3Def.Strings[i],
                                (GameLanguage)x));
                    }

                    mergedStringCount++;
                }
            }

            if (mergedStringCount > 0)
            {
                Console.WriteLine($"Merged {mergedStringCount} localized strings.");
                CacheContext.Serialize(cacheStream, edTag, edDef);
            }
        }
Ejemplo n.º 3
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);
        }
        private PageableResource ConvertStructureBspCacheFileTagResources(ScenarioStructureBsp bsp, Dictionary <ResourceLocation, Stream> resourceStreams)
        {
            //
            // Set up ElDorado resource reference
            //

            bsp.PathfindingResource = new PageableResource
            {
                Page = new RawPage
                {
                    Index = -1
                },
                Resource = new TagResourceGen3
                {
                    ResourceType             = TagResourceTypeGen3.Pathfinding,
                    DefinitionData           = new byte[0x30],
                    DefinitionAddress        = new CacheResourceAddress(CacheResourceAddressType.Definition, 0),
                    ResourceFixups           = new List <TagResourceGen3.ResourceFixup>(),
                    ResourceDefinitionFixups = new List <TagResourceGen3.ResourceDefinitionFixup>(),
                    Unknown2 = 1
                }
            };

            //
            // Load Blam resource data
            //

            var resourceData = BlamCache.Version > CacheVersion.Halo3Retail ?
                               BlamCache.GetRawFromID(bsp.ZoneAssetIndex4) :
                               null;

            if (resourceData == null)
            {
                if (BlamCache.Version >= CacheVersion.Halo3ODST)
                {
                    return(bsp.PathfindingResource);
                }

                resourceData = new byte[0x30];
            }

            //
            // Port Blam resource definition
            //

            StructureBspCacheFileTagResources resourceDefinition = null;

            if (BlamCache.Version >= CacheVersion.Halo3ODST)
            {
                var resourceEntry = BlamCache.ResourceGestalt.TagResources[bsp.ZoneAssetIndex4.Index];

                bsp.PathfindingResource.Resource.DefinitionAddress = resourceEntry.DefinitionAddress;
                bsp.PathfindingResource.Resource.DefinitionData    = BlamCache.ResourceGestalt.FixupInformation.Skip(resourceEntry.FixupInformationOffset).Take(resourceEntry.FixupInformationLength).ToArray();

                using (var definitionStream = new MemoryStream(bsp.PathfindingResource.Resource.DefinitionData, true))
                    using (var definitionReader = new EndianReader(definitionStream, EndianFormat.BigEndian))
                        using (var definitionWriter = new EndianWriter(definitionStream, EndianFormat.BigEndian))
                        {
                            foreach (var fixup in resourceEntry.ResourceFixups)
                            {
                                var newFixup = new TagResourceGen3.ResourceFixup
                                {
                                    BlockOffset = (uint)fixup.BlockOffset,
                                    Address     = new CacheResourceAddress(
                                        fixup.Type == 4 ?
                                        CacheResourceAddressType.Resource :
                                        CacheResourceAddressType.Definition,
                                        fixup.Offset)
                                };

                                definitionStream.Position = newFixup.BlockOffset;
                                definitionWriter.Write(newFixup.Address.Value);

                                bsp.PathfindingResource.Resource.ResourceFixups.Add(newFixup);
                            }

                            var dataContext = new DataSerializationContext(definitionReader, definitionWriter, CacheResourceAddressType.Definition);

                            definitionStream.Position = bsp.PathfindingResource.Resource.DefinitionAddress.Offset;
                            resourceDefinition        = BlamCache.Deserializer.Deserialize <StructureBspCacheFileTagResources>(dataContext);
                        }
            }
            else
            {
                resourceDefinition = new StructureBspCacheFileTagResources()
                {
                    SurfacePlanes   = new TagBlock <ScenarioStructureBsp.SurfacesPlanes>(bsp.SurfacePlanes.Count, new CacheResourceAddress()),
                    Planes          = new TagBlock <ScenarioStructureBsp.Plane>(bsp.Planes.Count, new CacheResourceAddress()),
                    EdgeToSeams     = new TagBlock <ScenarioStructureBsp.EdgeToSeamMapping>(bsp.EdgeToSeams.Count, new CacheResourceAddress()),
                    PathfindingData = new List <StructureBspCacheFileTagResources.PathfindingDatum>() // TODO: copy from bsp.PathfindingData...
                };
            }

            //
            // Port Blam resource to ElDorado resource cache
            //

            using (var blamResourceStream = new MemoryStream(resourceData))
                using (var resourceReader = new EndianReader(blamResourceStream, EndianFormat.BigEndian))
                    using (var dataStream = new MemoryStream())
                        using (var resourceWriter = new EndianWriter(dataStream, EndianFormat.LittleEndian))
                        {
                            var dataContext = new DataSerializationContext(resourceReader, resourceWriter);

                            //
                            // Surfaces Planes
                            //

                            StreamUtil.Align(dataStream, 0x4);

                            if (BlamCache.Version >= CacheVersion.Halo3ODST)
                            {
                                blamResourceStream.Position = resourceDefinition.SurfacePlanes.Address.Offset;
                            }

                            resourceDefinition.SurfacePlanes = new TagBlock <ScenarioStructureBsp.SurfacesPlanes>(
                                (BlamCache.Version < CacheVersion.Halo3ODST ? bsp.SurfacePlanes.Count : resourceDefinition.SurfacePlanes.Count),
                                new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position));

                            for (var i = 0; i < resourceDefinition.SurfacePlanes.Count; i++)
                            {
                                var element = BlamCache.Version < CacheVersion.Halo3ODST ?
                                              bsp.SurfacePlanes[i] :
                                              BlamCache.Deserializer.Deserialize <ScenarioStructureBsp.SurfacesPlanes>(dataContext);

                                if (BlamCache.Version < CacheVersion.Halo3ODST)
                                {
                                    element.PlaneIndexNew = element.PlaneIndexOld;
                                    element.PlaneCountNew = element.PlaneCountOld;
                                }

                                CacheContext.Serializer.Serialize(dataContext, element);
                            }

                            //
                            // UnknownRaw1sts
                            //

                            StreamUtil.Align(dataStream, 0x4);

                            if (BlamCache.Version >= CacheVersion.Halo3ODST)
                            {
                                blamResourceStream.Position = resourceDefinition.Planes.Address.Offset;
                            }

                            resourceDefinition.Planes = new TagBlock <ScenarioStructureBsp.Plane>(
                                (BlamCache.Version < CacheVersion.Halo3ODST ? bsp.Planes.Count : resourceDefinition.Planes.Count),
                                new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position));

                            for (var i = 0; i < resourceDefinition.Planes.Count; i++)
                            {
                                var element = BlamCache.Version < CacheVersion.Halo3ODST ?
                                              bsp.Planes[i] :
                                              BlamCache.Deserializer.Deserialize <ScenarioStructureBsp.Plane>(dataContext);

                                CacheContext.Serializer.Serialize(dataContext, element);
                            }

                            //
                            // UnknownRaw7ths
                            //

                            StreamUtil.Align(dataStream, 0x4);

                            if (BlamCache.Version >= CacheVersion.Halo3ODST)
                            {
                                blamResourceStream.Position = resourceDefinition.EdgeToSeams.Address.Offset;
                            }

                            resourceDefinition.EdgeToSeams = new TagBlock <ScenarioStructureBsp.EdgeToSeamMapping>(
                                (BlamCache.Version < CacheVersion.Halo3ODST ? bsp.EdgeToSeams.Count : resourceDefinition.EdgeToSeams.Count),
                                new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position));

                            for (var i = 0; i < resourceDefinition.EdgeToSeams.Count; i++)
                            {
                                var element = BlamCache.Version < CacheVersion.Halo3ODST ?
                                              bsp.EdgeToSeams[i] :
                                              BlamCache.Deserializer.Deserialize <ScenarioStructureBsp.EdgeToSeamMapping>(dataContext);

                                CacheContext.Serializer.Serialize(dataContext, element);
                            }

                            if (BlamCache.Version < CacheVersion.Halo3ODST && bsp.PathfindingData.Count != 0)
                            {
                                var pathfinding = new StructureBspCacheFileTagResources.PathfindingDatum()
                                {
                                    StructureChecksum = bsp.PathfindingData[0].StructureChecksum,
                                    ObjectReferences  = new List <StructureBspCacheFileTagResources.PathfindingDatum.ObjectReference>(),
                                    Seams             = new List <StructureBspCacheFileTagResources.PathfindingDatum.Seam>(),
                                    JumpSeams         = new List <StructureBspCacheFileTagResources.PathfindingDatum.JumpSeam>()
                                };

                                foreach (var oldObjectReference in bsp.PathfindingData[0].ObjectReferences)
                                {
                                    var objectReference = new StructureBspCacheFileTagResources.PathfindingDatum.ObjectReference
                                    {
                                        Flags          = oldObjectReference.Flags,
                                        Bsps           = new List <StructureBspCacheFileTagResources.PathfindingDatum.ObjectReference.BspReference>(),
                                        ObjectUniqueID = oldObjectReference.ObjectUniqueID,
                                        OriginBspIndex = oldObjectReference.OriginBspIndex,
                                        ObjectType     = oldObjectReference.ObjectType.DeepClone(),
                                        Source         = oldObjectReference.Source
                                    };

                                    foreach (var bspRef in oldObjectReference.Bsps)
                                    {
                                        objectReference.Bsps.Add(new StructureBspCacheFileTagResources.PathfindingDatum.ObjectReference.BspReference
                                        {
                                            BspIndex     = bspRef.BspIndex,
                                            NodeIndex    = bspRef.NodeIndex,
                                            Bsp2dRefs    = new TagBlock <ScenarioStructureBsp.PathfindingDatum.ObjectReference.BspReference.Bsp2dRef>(bspRef.Bsp2dRefs.Count, new CacheResourceAddress()),
                                            VertexOffset = bspRef.VertexOffset
                                        });
                                    }

                                    pathfinding.ObjectReferences.Add(objectReference);
                                }

                                foreach (var oldSeam in bsp.PathfindingData[0].Seams)
                                {
                                    pathfinding.Seams.Add(new StructureBspCacheFileTagResources.PathfindingDatum.Seam
                                    {
                                        LinkIndices = new TagBlock <ScenarioStructureBsp.PathfindingDatum.Seam.LinkIndexBlock>(
                                            oldSeam.LinkIndices.Count, new CacheResourceAddress())
                                    });
                                }

                                foreach (var oldJumpSeam in bsp.PathfindingData[0].JumpSeams)
                                {
                                    pathfinding.JumpSeams.Add(new StructureBspCacheFileTagResources.PathfindingDatum.JumpSeam
                                    {
                                        UserJumpIndex = oldJumpSeam.UserJumpIndex,
                                        DestOnly      = oldJumpSeam.DestOnly,
                                        Length        = oldJumpSeam.Length,
                                        JumpIndices   = new TagBlock <ScenarioStructureBsp.PathfindingDatum.JumpSeam.JumpIndexBlock>(
                                            oldJumpSeam.JumpIndices.Count, new CacheResourceAddress())
                                    });
                                }

                                resourceDefinition.PathfindingData.Add(pathfinding);
                            }

                            foreach (var pathfindingDatum in resourceDefinition.PathfindingData)
                            {
                                StreamUtil.Align(dataStream, 0x4);
                                if (BlamCache.Version >= CacheVersion.Halo3ODST)
                                {
                                    blamResourceStream.Position = pathfindingDatum.Sectors.Address.Offset;
                                }
                                pathfindingDatum.Sectors = new TagBlock <ScenarioStructureBsp.PathfindingDatum.Sector>(
                                    (BlamCache.Version < CacheVersion.Halo3ODST ? bsp.PathfindingData[0].Sectors.Count : pathfindingDatum.Sectors.Count),
                                    new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position));
                                for (var i = 0; i < pathfindingDatum.Sectors.Count; i++)
                                {
                                    CacheContext.Serializer.Serialize(dataContext,
                                                                      BlamCache.Version < CacheVersion.Halo3ODST ?
                                                                      bsp.PathfindingData[0].Sectors[i] :
                                                                      BlamCache.Deserializer.Deserialize <ScenarioStructureBsp.PathfindingDatum.Sector>(dataContext));
                                }

                                StreamUtil.Align(dataStream, 0x4);
                                if (BlamCache.Version >= CacheVersion.Halo3ODST)
                                {
                                    blamResourceStream.Position = pathfindingDatum.Links.Address.Offset;
                                }
                                pathfindingDatum.Links = new TagBlock <ScenarioStructureBsp.PathfindingDatum.Link>(
                                    (BlamCache.Version < CacheVersion.Halo3ODST ? bsp.PathfindingData[0].Links.Count : pathfindingDatum.Links.Count),
                                    new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position));
                                for (var i = 0; i < pathfindingDatum.Links.Count; i++)
                                {
                                    CacheContext.Serializer.Serialize(dataContext,
                                                                      BlamCache.Version < CacheVersion.Halo3ODST ?
                                                                      bsp.PathfindingData[0].Links[i] :
                                                                      BlamCache.Deserializer.Deserialize <ScenarioStructureBsp.PathfindingDatum.Link>(dataContext));
                                }

                                StreamUtil.Align(dataStream, 0x4);
                                if (BlamCache.Version >= CacheVersion.Halo3ODST)
                                {
                                    blamResourceStream.Position = pathfindingDatum.References.Address.Offset;
                                }
                                pathfindingDatum.References = new TagBlock <ScenarioStructureBsp.PathfindingDatum.Reference>(
                                    (BlamCache.Version < CacheVersion.Halo3ODST ? bsp.PathfindingData[0].References.Count : pathfindingDatum.References.Count),
                                    new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position));
                                for (var i = 0; i < pathfindingDatum.References.Count; i++)
                                {
                                    CacheContext.Serializer.Serialize(dataContext,
                                                                      BlamCache.Version < CacheVersion.Halo3ODST ?
                                                                      bsp.PathfindingData[0].References[i] :
                                                                      BlamCache.Deserializer.Deserialize <ScenarioStructureBsp.PathfindingDatum.Reference>(dataContext));
                                }

                                StreamUtil.Align(dataStream, 0x4);
                                if (BlamCache.Version >= CacheVersion.Halo3ODST)
                                {
                                    blamResourceStream.Position = pathfindingDatum.Bsp2dNodes.Address.Offset;
                                }
                                pathfindingDatum.Bsp2dNodes = new TagBlock <ScenarioStructureBsp.PathfindingDatum.Bsp2dNode>(
                                    (BlamCache.Version < CacheVersion.Halo3ODST ? bsp.PathfindingData[0].Bsp2dNodes.Count : pathfindingDatum.Bsp2dNodes.Count),
                                    new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position));
                                for (var i = 0; i < pathfindingDatum.Bsp2dNodes.Count; i++)
                                {
                                    CacheContext.Serializer.Serialize(dataContext,
                                                                      BlamCache.Version < CacheVersion.Halo3ODST ?
                                                                      bsp.PathfindingData[0].Bsp2dNodes[i] :
                                                                      BlamCache.Deserializer.Deserialize <ScenarioStructureBsp.PathfindingDatum.Bsp2dNode>(dataContext));
                                }

                                StreamUtil.Align(dataStream, 0x4);
                                if (BlamCache.Version >= CacheVersion.Halo3ODST)
                                {
                                    blamResourceStream.Position = pathfindingDatum.Vertices.Address.Offset;
                                }
                                pathfindingDatum.Vertices = new TagBlock <ScenarioStructureBsp.PathfindingDatum.Vertex>(
                                    (BlamCache.Version < CacheVersion.Halo3ODST ? bsp.PathfindingData[0].Vertices.Count : pathfindingDatum.Vertices.Count),
                                    new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position));
                                for (var i = 0; i < pathfindingDatum.Vertices.Count; i++)
                                {
                                    CacheContext.Serializer.Serialize(dataContext,
                                                                      BlamCache.Version < CacheVersion.Halo3ODST ?
                                                                      bsp.PathfindingData[0].Vertices[i] :
                                                                      BlamCache.Deserializer.Deserialize <ScenarioStructureBsp.PathfindingDatum.Vertex>(dataContext));
                                }

                                for (var objRefIdx = 0; objRefIdx < pathfindingDatum.ObjectReferences.Count; objRefIdx++)
                                {
                                    for (var bspRefIdx = 0; bspRefIdx < pathfindingDatum.ObjectReferences[objRefIdx].Bsps.Count; bspRefIdx++)
                                    {
                                        var bspRef = pathfindingDatum.ObjectReferences[objRefIdx].Bsps[bspRefIdx];

                                        StreamUtil.Align(dataStream, 0x4);
                                        if (BlamCache.Version >= CacheVersion.Halo3ODST)
                                        {
                                            blamResourceStream.Position = bspRef.Bsp2dRefs.Address.Offset;
                                        }
                                        bspRef.Bsp2dRefs.Address = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);

                                        for (var bsp2dRefIdx = 0; bsp2dRefIdx < bspRef.Bsp2dRefs.Count; bsp2dRefIdx++)
                                        {
                                            var bsp2dRef = BlamCache.Version < CacheVersion.Halo3ODST ?
                                                           bsp.PathfindingData[0].ObjectReferences[objRefIdx].Bsps[bspRefIdx].Bsp2dRefs[bsp2dRefIdx] :
                                                           BlamCache.Deserializer.Deserialize <ScenarioStructureBsp.PathfindingDatum.ObjectReference.BspReference.Bsp2dRef>(dataContext);

                                            CacheContext.Serializer.Serialize(dataContext, bsp2dRef);
                                        }
                                    }
                                }

                                StreamUtil.Align(dataStream, 0x4);
                                if (BlamCache.Version >= CacheVersion.Halo3ODST)
                                {
                                    blamResourceStream.Position = pathfindingDatum.PathfindingHints.Address.Offset;
                                }
                                pathfindingDatum.PathfindingHints = new TagBlock <ScenarioStructureBsp.PathfindingDatum.PathfindingHint>(
                                    (BlamCache.Version < CacheVersion.Halo3ODST ? bsp.PathfindingData[0].PathfindingHints.Count : pathfindingDatum.PathfindingHints.Count),
                                    new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position));
                                for (var i = 0; i < pathfindingDatum.PathfindingHints.Count; i++)
                                {
                                    var hint = BlamCache.Version < CacheVersion.Halo3ODST ?
                                               bsp.PathfindingData[0].PathfindingHints[i] :
                                               BlamCache.Deserializer.Deserialize <ScenarioStructureBsp.PathfindingDatum.PathfindingHint>(dataContext);

                                    if (BlamCache.Version < CacheVersion.Halo3ODST &&
                                        (hint.HintType == JumpLink || hint.HintType == WallJumpLink))
                                    {
                                        hint.Data[3] = (hint.Data[3] & ~ushort.MaxValue) | ((hint.Data[2] >> 16) & ushort.MaxValue);
                                        hint.Data[2] = (hint.Data[2] & ~(ushort.MaxValue << 16));                     //remove old landing sector
                                        hint.Data[2] = (hint.Data[2] | ((hint.Data[2] & (byte.MaxValue << 8)) << 8)); //move jump height flags
                                        hint.Data[2] = (hint.Data[2] & ~(byte.MaxValue << 8));                        //remove old flags
                                    }

                                    CacheContext.Serializer.Serialize(dataContext, hint);
                                }

                                StreamUtil.Align(dataStream, 0x4);
                                if (BlamCache.Version >= CacheVersion.Halo3ODST)
                                {
                                    blamResourceStream.Position = pathfindingDatum.InstancedGeometryReferences.Address.Offset;
                                }
                                pathfindingDatum.InstancedGeometryReferences = new TagBlock <ScenarioStructureBsp.PathfindingDatum.InstancedGeometryReference>(
                                    (BlamCache.Version < CacheVersion.Halo3ODST ? bsp.PathfindingData[0].InstancedGeometryReferences.Count : pathfindingDatum.InstancedGeometryReferences.Count),
                                    new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position));
                                for (var i = 0; i < pathfindingDatum.InstancedGeometryReferences.Count; i++)
                                {
                                    CacheContext.Serializer.Serialize(dataContext,
                                                                      BlamCache.Version < CacheVersion.Halo3ODST ?
                                                                      bsp.PathfindingData[0].InstancedGeometryReferences[i] :
                                                                      BlamCache.Deserializer.Deserialize <ScenarioStructureBsp.PathfindingDatum.InstancedGeometryReference>(dataContext));
                                }

                                StreamUtil.Align(dataStream, 0x4);
                                if (BlamCache.Version >= CacheVersion.Halo3ODST)
                                {
                                    blamResourceStream.Position = pathfindingDatum.GiantPathfinding.Address.Offset;
                                }
                                pathfindingDatum.GiantPathfinding = new TagBlock <ScenarioStructureBsp.PathfindingDatum.GiantPathfindingBlock>(
                                    (BlamCache.Version < CacheVersion.Halo3ODST ? bsp.PathfindingData[0].GiantPathfinding.Count : pathfindingDatum.GiantPathfinding.Count),
                                    new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position));
                                for (var i = 0; i < pathfindingDatum.GiantPathfinding.Count; i++)
                                {
                                    CacheContext.Serializer.Serialize(dataContext,
                                                                      BlamCache.Version < CacheVersion.Halo3ODST ?
                                                                      bsp.PathfindingData[0].GiantPathfinding[i] :
                                                                      BlamCache.Deserializer.Deserialize <ScenarioStructureBsp.PathfindingDatum.GiantPathfindingBlock>(dataContext));
                                }

                                for (var unk2Idx = 0; unk2Idx < pathfindingDatum.Seams.Count; unk2Idx++)
                                {
                                    var unknown2 = pathfindingDatum.Seams[unk2Idx];

                                    StreamUtil.Align(dataStream, 0x4);

                                    if (BlamCache.Version >= CacheVersion.Halo3ODST)
                                    {
                                        blamResourceStream.Position = unknown2.LinkIndices.Address.Offset;
                                    }

                                    unknown2.LinkIndices = new TagBlock <ScenarioStructureBsp.PathfindingDatum.Seam.LinkIndexBlock>(
                                        (BlamCache.Version < CacheVersion.Halo3ODST ? bsp.PathfindingData[0].Seams[unk2Idx].LinkIndices.Count : unknown2.LinkIndices.Count),
                                        new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position));

                                    for (var unkIdx = 0; unkIdx < unknown2.LinkIndices.Count; unkIdx++)
                                    {
                                        CacheContext.Serializer.Serialize(dataContext,
                                                                          BlamCache.Version < CacheVersion.Halo3ODST ?
                                                                          bsp.PathfindingData[0].Seams[unk2Idx].LinkIndices[unkIdx] :
                                                                          BlamCache.Deserializer.Deserialize <ScenarioStructureBsp.PathfindingDatum.Seam.LinkIndexBlock>(dataContext));
                                    }
                                }

                                for (var unk3Idx = 0; unk3Idx < pathfindingDatum.JumpSeams.Count; unk3Idx++)
                                {
                                    var unknown3 = pathfindingDatum.JumpSeams[unk3Idx];

                                    StreamUtil.Align(dataStream, 0x4);

                                    if (BlamCache.Version >= CacheVersion.Halo3ODST)
                                    {
                                        blamResourceStream.Position = unknown3.JumpIndices.Address.Offset;
                                    }

                                    unknown3.JumpIndices = new TagBlock <ScenarioStructureBsp.PathfindingDatum.JumpSeam.JumpIndexBlock>(
                                        (BlamCache.Version < CacheVersion.Halo3ODST ? bsp.PathfindingData[0].JumpSeams[unk3Idx].JumpIndices.Count : unknown3.JumpIndices.Count),
                                        new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position));

                                    for (var unk4Idx = 0; unk4Idx < unknown3.JumpIndices.Count; unk4Idx++)
                                    {
                                        CacheContext.Serializer.Serialize(dataContext,
                                                                          BlamCache.Version < CacheVersion.Halo3ODST ?
                                                                          bsp.PathfindingData[0].JumpSeams[unk3Idx].JumpIndices[unk4Idx] :
                                                                          BlamCache.Deserializer.Deserialize <ScenarioStructureBsp.PathfindingDatum.JumpSeam.JumpIndexBlock>(dataContext));
                                    }
                                }

                                StreamUtil.Align(dataStream, 0x4);
                                if (BlamCache.Version >= CacheVersion.Halo3ODST)
                                {
                                    blamResourceStream.Position = pathfindingDatum.Doors.Address.Offset;
                                }
                                pathfindingDatum.Doors = new TagBlock <ScenarioStructureBsp.PathfindingDatum.Door>(
                                    (BlamCache.Version < CacheVersion.Halo3ODST ? bsp.PathfindingData[0].Doors.Count : pathfindingDatum.Doors.Count),
                                    new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position));
                                for (var i = 0; i < pathfindingDatum.Doors.Count; i++)
                                {
                                    CacheContext.Serializer.Serialize(dataContext,
                                                                      BlamCache.Version < CacheVersion.Halo3ODST ?
                                                                      bsp.PathfindingData[0].Doors[i] :
                                                                      BlamCache.Deserializer.Deserialize <ScenarioStructureBsp.PathfindingDatum.Door>(dataContext));
                                }
                            }

                            CacheContext.Serializer.Serialize(new ResourceSerializationContext(CacheContext, bsp.PathfindingResource), resourceDefinition);
                            resourceWriter.BaseStream.Position = 0;
                            dataStream.Position = 0;

                            bsp.PathfindingResource.ChangeLocation(ResourceLocation.ResourcesB);
                            var resource = bsp.PathfindingResource;

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

                            if (!dataStream.CanRead)
                            {
                                throw new ArgumentException("The input stream is not open for reading", "dataStream");
                            }

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

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

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

                            var dataSize = (int)(dataStream.Length - dataStream.Position);
                            var data     = new byte[dataSize];
                            dataStream.Read(data, 0, dataSize);

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

            if (BlamCache.Version < CacheVersion.Halo3ODST)
            {
                bsp.SurfacePlanes.Clear();
                bsp.Planes.Clear();
                bsp.EdgeToSeams.Clear();
                bsp.PathfindingData.Clear();
            }

            return(bsp.PathfindingResource);
        }
Ejemplo n.º 5
0
        private void MergeCharacter(Stream cacheStream, Stream blamCacheStream, Dictionary <ResourceLocation, Stream> resourceStreams, CachedTag edTag, CachedTag h3Tag)
        {
            var edDef = CacheContext.Deserialize <Character>(cacheStream, edTag);
            var h3Def = BlamCache.Deserialize <Character>(blamCacheStream, h3Tag);

            var merged = false;

            if (edDef.WeaponsProperties.Count == h3Def.WeaponsProperties.Count)
            {
                for (var i = 0; i < edDef.WeaponsProperties.Count; i++)
                {
                    if (edDef.WeaponsProperties[i].Weapon != null || h3Def.WeaponsProperties[i].Weapon == null)
                    {
                        continue;
                    }

                    edDef.WeaponsProperties[i].Weapon = ConvertTag(cacheStream, blamCacheStream, resourceStreams, h3Def.WeaponsProperties[i].Weapon);

                    merged = true;
                }
            }

            if (edDef.VehicleProperties.Count == h3Def.VehicleProperties.Count)
            {
                for (var i = 0; i < edDef.VehicleProperties.Count; i++)
                {
                    if (edDef.VehicleProperties[i].Unit != null || h3Def.VehicleProperties[i].Unit == null)
                    {
                        continue;
                    }

                    edDef.VehicleProperties[i].Unit = ConvertTag(cacheStream, blamCacheStream, resourceStreams, h3Def.VehicleProperties[i].Unit);

                    merged = true;
                }
            }

            if (edDef.EquipmentProperties.Count == h3Def.EquipmentProperties.Count)
            {
                for (var i = 0; i < edDef.EquipmentProperties.Count; i++)
                {
                    if (edDef.EquipmentProperties[i].Equipment != null || h3Def.EquipmentProperties[i].Equipment == null)
                    {
                        continue;
                    }

                    edDef.EquipmentProperties[i].Equipment = ConvertTag(cacheStream, blamCacheStream, resourceStreams, h3Def.EquipmentProperties[i].Equipment);

                    merged = true;
                }
            }

            if (edDef.FiringPatternProperties.Count == h3Def.FiringPatternProperties.Count)
            {
                for (var i = 0; i < edDef.FiringPatternProperties.Count; i++)
                {
                    if (edDef.FiringPatternProperties[i].Weapon != null || h3Def.FiringPatternProperties[i].Weapon == null)
                    {
                        continue;
                    }

                    edDef.FiringPatternProperties[i].Weapon = ConvertTag(cacheStream, blamCacheStream, resourceStreams, h3Def.FiringPatternProperties[i].Weapon);

                    merged = true;
                }
            }

            if (edDef.ActAttachments.Count == h3Def.ActAttachments.Count)
            {
                for (var i = 0; i < edDef.ActAttachments.Count; i++)
                {
                    if (edDef.ActAttachments[i].Crate != null || h3Def.ActAttachments[i].Crate == null)
                    {
                        continue;
                    }

                    edDef.ActAttachments[i].Crate = ConvertTag(cacheStream, blamCacheStream, resourceStreams, h3Def.ActAttachments[i].Crate);

                    merged = true;
                }
            }

            if (merged)
            {
                CacheContext.Serialize(cacheStream, edTag, edDef);
            }
        }
Ejemplo n.º 6
0
        public List <ModelAnimationGraph.ResourceGroup> ConvertModelAnimationGraphResourceGroups(Stream cacheStream, Dictionary <ResourceLocation, Stream> resourceStreams, List <ModelAnimationGraph.ResourceGroup> resourceGroups)
        {
            if (BlamCache.ResourceGestalt == null)
            {
                BlamCache.LoadResourceTags();
            }

            var resourceDefinition = new List <ModelAnimationTagResource>();

            foreach (var group in resourceGroups)
            {
                var resourceEntry = BlamCache.ResourceGestalt.TagResources[group.ZoneAssetHandle.Index];

                group.Resource = new PageableResource
                {
                    Page = new RawPage
                    {
                        Index = -1,
                    },
                    Resource = new TagResourceGen3
                    {
                        ResourceType             = TagResourceTypeGen3.Animation,
                        DefinitionData           = BlamCache.ResourceGestalt.FixupInformation.Skip(resourceEntry.FixupInformationOffset).Take(resourceEntry.FixupInformationLength).ToArray(),
                        DefinitionAddress        = resourceEntry.DefinitionAddress,
                        ResourceFixups           = new List <TagResourceGen3.ResourceFixup>(),
                        ResourceDefinitionFixups = new List <TagResourceGen3.ResourceDefinitionFixup>(),
                        Unknown2 = 1
                    }
                };

                // Convert blam fixups

                // get the list of members in this resourcegroup. this list contains address, various offsets, and other info about the member.
                if (group.Resource.Resource.DefinitionData.Length != 0)
                {
                    using (var definitionStream = new MemoryStream(group.Resource.Resource.DefinitionData, true))
                        using (var definitionReader = new EndianReader(definitionStream, EndianFormat.BigEndian))
                            using (var definitionWriter = new EndianWriter(definitionStream, EndianFormat.BigEndian))
                            {
                                foreach (var fixup in resourceEntry.ResourceFixups)
                                {
                                    var newFixup = new TagResourceGen3.ResourceFixup
                                    {
                                        BlockOffset = (uint)fixup.BlockOffset,
                                        Address     = new CacheResourceAddress(CacheResourceAddressType.Resource, fixup.Offset)
                                    };

                                    definitionStream.Position = newFixup.BlockOffset;
                                    definitionWriter.Write(newFixup.Address.Value);

                                    group.Resource.Resource.ResourceFixups.Add(newFixup);
                                }

                                var dataContext = new DataSerializationContext(definitionReader, definitionWriter, CacheResourceAddressType.Definition);

                                definitionStream.Position = group.Resource.Resource.DefinitionAddress.Offset + 0x4;
                                definitionWriter.Write(0x20000000);
                                // ODST's resource type is 4 when it's supposed to be 2 because the resource definition is in the tag and not as a raw resource

                                definitionStream.Position = group.Resource.Resource.DefinitionAddress.Offset;

                                resourceDefinition.Add(BlamCache.Deserializer.Deserialize <ModelAnimationTagResource>(dataContext));
                            }
                }
            }

            var diffLines   = new List <string>();
            var resDefIndex = -1;

            foreach (var group in resourceGroups)
            {
                resDefIndex++;

                if (resourceDefinition.Count < resDefIndex + 1)
                {
                    continue; // rare cases, might break the game
                }
                // Get the resource group real size, which is probably not in the resource definition
                var groupSize = 0;
                foreach (var groupMember in resourceDefinition[resDefIndex].GroupMembers)
                {
                    groupSize += groupMember.AnimationData.Size;
                    while (groupSize % 0x10 != 0) // align to 0x10.
                    {
                        groupSize += 4;
                    }
                }

                var resourceData = BlamCache.GetRawFromID(group.ZoneAssetHandle, groupSize);

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

                using (var blamResourceStream = new MemoryStream(resourceData))
                    using (var resourceReader = new EndianReader(blamResourceStream, EndianFormat.BigEndian))
                        using (var dataStream = new MemoryStream(new byte[groupSize]))
                            using (var resourceWriter = new EndianWriter(dataStream, EndianFormat.LittleEndian))
                            {
                                var dataContext = new DataSerializationContext(resourceReader, resourceWriter);

                                var memberOffset = 0;

                                for (var memberIndex = 0; memberIndex < resourceDefinition[resDefIndex].GroupMembers.Count; memberIndex++)
                                {
                                    var member = resourceDefinition[resDefIndex].GroupMembers[memberIndex];

                                    ModelAnimationTagResource.GroupMember.Codec     codec;
                                    ModelAnimationTagResource.GroupMember.FrameInfo frameInfo;

                                    if (member.BaseHeader != ModelAnimationTagResource.GroupMemberHeaderType.Overlay)
                                    {
                                        blamResourceStream.Position = member.AnimationData.Address.Offset;
                                        dataStream.Position         = member.AnimationData.Address.Offset;

                                        codec = BlamCache.Deserializer.Deserialize <ModelAnimationTagResource.GroupMember.Codec>(dataContext);

                                        CacheContext.Serializer.Serialize(dataContext, codec);

                                        var Format1 = BlamCache.Deserializer.Deserialize <ModelAnimationTagResource.GroupMember.Format1>(dataContext);

                                        CacheContext.Serializer.Serialize(dataContext, Format1);

                                        // blamResourceStream.Position = (long)member.AnimationData.Address.Offset + headerSize;
                                        // edResourceStream.Position = blamResourceStream.Position;
                                        for (int i = 0; i < codec.RotationNodeCount; i++)
                                        {
                                            CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <ModelAnimationTagResource.GroupMember.RotationFrame>(dataContext));
                                        }

                                        blamResourceStream.Position = member.AnimationData.Address.Offset + Format1.DataStart;
                                        dataStream.Position         = blamResourceStream.Position;
                                        for (int i = 0; i < codec.PositionNodeCount; i++)
                                        {
                                            CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <ModelAnimationTagResource.GroupMember.PositionFrame>(dataContext));
                                        }

                                        blamResourceStream.Position = member.AnimationData.Address.Offset + Format1.ScaleFramesOffset;
                                        dataStream.Position         = blamResourceStream.Position;
                                        for (int i = 0; i < codec.ScaleNodeCount; i++)
                                        {
                                            CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <ModelAnimationTagResource.GroupMember.ScaleFrame>(dataContext));
                                        }
                                    }

                                    // If the overlay header is alone, member.OverlayOffset = 0
                                    blamResourceStream.Position = (long)member.AnimationData.Address.Offset + member.OverlayOffset;
                                    dataStream.Position         = (long)member.AnimationData.Address.Offset + member.OverlayOffset;

                                    codec = BlamCache.Deserializer.Deserialize <ModelAnimationTagResource.GroupMember.Codec>(dataContext);
                                    CacheContext.Serializer.Serialize(dataContext, codec);

                                    // deserialize second header. or as first header if the type1/format1 header isn't used.
                                    switch (codec.AnimationCodec)
                                    {
                                    case ModelAnimationTagResource.AnimationCompressionFormats.Type3: // should merge with type1
                                        var header = BlamCache.Deserializer.Deserialize <ModelAnimationTagResource.GroupMember.Format1>(dataContext);

                                        CacheContext.Serializer.Serialize(dataContext, header);

                                        for (int nodeIndex = 0; nodeIndex < codec.RotationNodeCount; nodeIndex++)
                                        {
                                            for (int frameIndex = 0; frameIndex < member.FrameCount; frameIndex++)
                                            {
                                                CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <ModelAnimationTagResource.GroupMember.RotationFrame>(dataContext));
                                            }
                                        }

                                        blamResourceStream.Position = (long)member.AnimationData.Address.Offset + member.OverlayOffset + header.DataStart;
                                        dataStream.Position         = blamResourceStream.Position;
                                        for (int nodeIndex = 0; nodeIndex < codec.PositionNodeCount; nodeIndex++)
                                        {
                                            for (int frameIndex = 0; frameIndex < member.FrameCount; frameIndex++)
                                            {
                                                CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <ModelAnimationTagResource.GroupMember.PositionFrame>(dataContext));
                                            }
                                        }

                                        blamResourceStream.Position = (long)member.AnimationData.Address.Offset + member.OverlayOffset + header.ScaleFramesOffset;
                                        dataStream.Position         = blamResourceStream.Position;
                                        for (int nodeIndex = 0; nodeIndex < codec.ScaleNodeCount; nodeIndex++)
                                        {
                                            for (int frameIndex = 0; frameIndex < member.FrameCount; frameIndex++)
                                            {
                                                CacheContext.Serializer.Serialize(dataContext,
                                                                                  BlamCache.Deserializer.Deserialize <ModelAnimationTagResource.GroupMember.ScaleFrame>(dataContext));
                                            }
                                        }

                                        break;

                                    case ModelAnimationTagResource.AnimationCompressionFormats.Type4:
                                    case ModelAnimationTagResource.AnimationCompressionFormats.Type5:
                                    case ModelAnimationTagResource.AnimationCompressionFormats.Type6:
                                    case ModelAnimationTagResource.AnimationCompressionFormats.Type7:
                                        var overlay = BlamCache.Deserializer.Deserialize <ModelAnimationTagResource.GroupMember.Overlay>(dataContext);

                                        CacheContext.Serializer.Serialize(dataContext, overlay);

                                        #region Description
                                        // Description by DemonicSandwich from http://remnantmods.com/forums/viewtopic.php?f=13&t=1574 (matches my previous observations)

                                        // Format 6 uses Keyframes the way there are supposed to be used. As KEY frames, with the majority of the frames being Tweens.
                                        //
                                        // This format adds two extra blocks of data to it's structure.
                                        // One block that determines how many Keyframes each Node will have, and an offset to to where it's Markers start from.
                                        //
                                        // Advantages:
                                        // This format requires far fewer Keyframes to make a complex animation.
                                        // You do not need a keyframe for each render frame.
                                        // Disadvantages:
                                        // It's a bit more complex to work with.
                                        // Since it's Keyrame Markers are only 1 byte in size, you're animation cannot be longer than 256 frames, or ~8.5 seconds for non - machine objects. > 12 bits for gen3, max 0xFFF frames
                                        // Machines are still limited to 256 frames but the frames can be stretched out.
                                        #endregion

                                        var RotationFrameCount = new List <uint>();
                                        var PositionFrameCount = new List <uint>();
                                        var ScaleFrameCount    = new List <uint>();

                                        for (int i = 0; i < codec.RotationNodeCount; i++)
                                        {
                                            frameInfo = BlamCache.Deserializer.Deserialize <ModelAnimationTagResource.GroupMember.FrameInfo>(dataContext);

                                            CacheContext.Serializer.Serialize(dataContext, frameInfo);

                                            var keyframesOffset = frameInfo.FrameCount & 0x00FFF000; // unused in this conversion
                                            var keyframes       = frameInfo.FrameCount & 0x00000FFF;
                                            RotationFrameCount.Add(keyframes);
                                        }

                                        for (int i = 0; i < codec.PositionNodeCount; i++)
                                        {
                                            frameInfo = BlamCache.Deserializer.Deserialize <ModelAnimationTagResource.GroupMember.FrameInfo>(dataContext);

                                            CacheContext.Serializer.Serialize(dataContext, frameInfo);

                                            var keyframesOffset = frameInfo.FrameCount & 0x00FFF000;
                                            var keyframes       = frameInfo.FrameCount & 0x00000FFF;
                                            PositionFrameCount.Add(keyframes);
                                        }

                                        for (int i = 0; i < codec.ScaleNodeCount; i++)
                                        {
                                            frameInfo = BlamCache.Deserializer.Deserialize <ModelAnimationTagResource.GroupMember.FrameInfo>(dataContext);

                                            CacheContext.Serializer.Serialize(dataContext, frameInfo);

                                            var keyframesOffset = frameInfo.FrameCount & 0x00FFF000;
                                            var keyframes       = frameInfo.FrameCount & 0x00000FFF;
                                            ScaleFrameCount.Add(keyframes);
                                        }

                                        blamResourceStream.Position = (long)member.AnimationData.Address.Offset + member.OverlayOffset + overlay.RotationKeyframesOffset;
                                        dataStream.Position         = blamResourceStream.Position;
                                        foreach (var framecount in RotationFrameCount)
                                        {
                                            for (int i = 0; i < framecount; i++)
                                            {
                                                if (codec.AnimationCodec == ModelAnimationTagResource.AnimationCompressionFormats.Type4)
                                                {
                                                    CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <ModelAnimationTagResource.GroupMember.Keyframe>(dataContext));
                                                }
                                                else if (codec.AnimationCodec == ModelAnimationTagResource.AnimationCompressionFormats.Type5)
                                                {
                                                    CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <ModelAnimationTagResource.GroupMember.KeyframeType5>(dataContext));
                                                }
                                                else if (codec.AnimationCodec == ModelAnimationTagResource.AnimationCompressionFormats.Type6)
                                                {
                                                    CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <ModelAnimationTagResource.GroupMember.Keyframe>(dataContext));
                                                }
                                                else if (codec.AnimationCodec == ModelAnimationTagResource.AnimationCompressionFormats.Type7)
                                                {
                                                    CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <ModelAnimationTagResource.GroupMember.KeyframeType5>(dataContext));
                                                }
                                            }
                                        }

                                        blamResourceStream.Position = (long)member.AnimationData.Address.Offset + member.OverlayOffset + overlay.PositionKeyframesOffset;
                                        dataStream.Position         = blamResourceStream.Position;
                                        foreach (var framecount in PositionFrameCount)
                                        {
                                            for (int i = 0; i < framecount; i++)
                                            {
                                                if (codec.AnimationCodec == ModelAnimationTagResource.AnimationCompressionFormats.Type4)
                                                {
                                                    CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <ModelAnimationTagResource.GroupMember.Keyframe>(dataContext));
                                                }
                                                else if (codec.AnimationCodec == ModelAnimationTagResource.AnimationCompressionFormats.Type5)
                                                {
                                                    CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <ModelAnimationTagResource.GroupMember.KeyframeType5>(dataContext));
                                                }
                                                else if (codec.AnimationCodec == ModelAnimationTagResource.AnimationCompressionFormats.Type6)
                                                {
                                                    CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <ModelAnimationTagResource.GroupMember.Keyframe>(dataContext));
                                                }
                                                else if (codec.AnimationCodec == ModelAnimationTagResource.AnimationCompressionFormats.Type7)
                                                {
                                                    CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <ModelAnimationTagResource.GroupMember.KeyframeType5>(dataContext));
                                                }
                                            }
                                        }

                                        blamResourceStream.Position = (long)member.AnimationData.Address.Offset + member.OverlayOffset + overlay.ScaleKeyframesOffset;
                                        dataStream.Position         = blamResourceStream.Position;
                                        foreach (var framecount in ScaleFrameCount)
                                        {
                                            for (int i = 0; i < framecount; i++)
                                            {
                                                if (codec.AnimationCodec == ModelAnimationTagResource.AnimationCompressionFormats.Type4)
                                                {
                                                    CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <ModelAnimationTagResource.GroupMember.Keyframe>(dataContext));
                                                }
                                                else if (codec.AnimationCodec == ModelAnimationTagResource.AnimationCompressionFormats.Type5)
                                                {
                                                    CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <ModelAnimationTagResource.GroupMember.KeyframeType5>(dataContext));
                                                }
                                                else if (codec.AnimationCodec == ModelAnimationTagResource.AnimationCompressionFormats.Type6)
                                                {
                                                    CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <ModelAnimationTagResource.GroupMember.Keyframe>(dataContext));
                                                }
                                                else if (codec.AnimationCodec == ModelAnimationTagResource.AnimationCompressionFormats.Type7)
                                                {
                                                    CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <ModelAnimationTagResource.GroupMember.KeyframeType5>(dataContext));
                                                }
                                            }
                                        }

                                        blamResourceStream.Position = (long)member.AnimationData.Address.Offset + member.OverlayOffset + overlay.RotationFramesOffset;
                                        dataStream.Position         = blamResourceStream.Position;
                                        foreach (var framecount in RotationFrameCount)
                                        {
                                            for (int i = 0; i < framecount; i++)
                                            {
                                                CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <ModelAnimationTagResource.GroupMember.RotationFrame>(dataContext));
                                            }
                                        }

                                        blamResourceStream.Position = (long)member.AnimationData.Address.Offset + member.OverlayOffset + overlay.PositionFramesOffset;
                                        dataStream.Position         = blamResourceStream.Position;
                                        foreach (var framecount in PositionFrameCount)
                                        {
                                            for (int i = 0; i < framecount; i++)
                                            {
                                                CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <ModelAnimationTagResource.GroupMember.PositionFrame>(dataContext));
                                            }
                                        }

                                        blamResourceStream.Position = (long)member.AnimationData.Address.Offset + member.OverlayOffset + overlay.ScaleFramesOffset;
                                        dataStream.Position         = blamResourceStream.Position;
                                        foreach (var framecount in ScaleFrameCount)
                                        {
                                            for (int i = 0; i < framecount; i++)
                                            {
                                                CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <ModelAnimationTagResource.GroupMember.ScaleFrame>(dataContext));
                                            }
                                        }
                                        break;

                                    case ModelAnimationTagResource.AnimationCompressionFormats.Type8:
                                        // Type 8 is basically a type 3 but with rotation frames using 4 floats, or a realQuaternion
                                        var Format8 = BlamCache.Deserializer.Deserialize <ModelAnimationTagResource.GroupMember.Format8>(dataContext);

                                        CacheContext.Serializer.Serialize(dataContext, Format8);

                                        for (int nodeIndex = 0; nodeIndex < codec.RotationNodeCount; nodeIndex++)
                                        {
                                            for (int frameIndex = 0; frameIndex < member.FrameCount; frameIndex++)
                                            {
                                                CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <ModelAnimationTagResource.GroupMember.RotationFrameFloat>(dataContext));
                                            }
                                        }

                                        blamResourceStream.Position = (long)member.AnimationData.Address.Offset + member.OverlayOffset + Format8.PositionFramesOffset;
                                        dataStream.Position         = blamResourceStream.Position;
                                        for (int nodeIndex = 0; nodeIndex < codec.PositionNodeCount; nodeIndex++)
                                        {
                                            for (int frameIndex = 0; frameIndex < member.FrameCount; frameIndex++)
                                            {
                                                CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <ModelAnimationTagResource.GroupMember.PositionFrame>(dataContext));
                                            }
                                        }

                                        blamResourceStream.Position = (long)member.AnimationData.Address.Offset + member.OverlayOffset + Format8.ScaleFramesOffset;
                                        dataStream.Position         = blamResourceStream.Position;
                                        for (int nodeIndex = 0; nodeIndex < codec.ScaleNodeCount; nodeIndex++)
                                        {
                                            for (int frameIndex = 0; frameIndex < member.FrameCount; frameIndex++)
                                            {
                                                CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <ModelAnimationTagResource.GroupMember.ScaleFrame>(dataContext));
                                            }
                                        }

                                        break;

                                    default:
                                        throw new DataMisalignedException();
                                    }

                                    #region How Footer/Flags works
                                    // Better description by DemonicSandwich from http://remnantmods.com/forums/viewtopic.php?f=13&t=1574 : Node List Block: (matches my previous observations)
                                    // Just a block of flags. Tick a flag and the respective node will be affected by animation.
                                    // The size of this block should always be a multiple of 12. It's size is determined my the meta value Node List Size [byte, offset: 61]
                                    // When set to 12, the list can handle objects with a node count up to 32 (0-31).
                                    // When set to 24, the object can have 64 nodes and so on.
                                    // The block is split into 3 groups of flags.
                                    // The first group determines what nodes are affected by rotation, the second group for position, and the third group for scale.
                                    //
                                    // If looking at it in hex, the Node ticks for each group will be in order as follows:
                                    // [7][6][5][4][3][2][1][0] - [15][14][13][12][11][10][9][8] - etc.
                                    // Each flag corresponding to a Node index.
                                    #endregion

                                    #region Footer/Flag block
                                    // There's one bitfield32 for every 32 nodes that are animated which i'll call a node flags.
                                    // There's at least 3 flags if the animation only has an overlay header, which i'll call a flag set.
                                    // There's at least 6 flags if the animation has both a base header and an overlay header, so 2 sets.
                                    // If the animated nodes count is over 32, then a new flags set is added.
                                    // 1 set per header is added, such as 32 nodes = 1 set, 64 = 2 sets, 96 = 3 sets etc , 128-256 maybe max

                                    blamResourceStream.Position = (long)member.AnimationData.Address.Offset + member.OverlayOffset + member.FlagsOffset;
                                    dataStream.Position         = blamResourceStream.Position;

                                    var footerSizeBase = (byte)member.BaseHeader / 4;
                                    for (int flagsCount = 0; flagsCount < footerSizeBase; flagsCount++)
                                    {
                                        CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <ModelAnimationTagResource.GroupMember.ScaleFrame>(dataContext));
                                    }

                                    var footerSizeOverlay = (byte)member.OverlayHeader / 4;
                                    for (int flagsCount = 0; flagsCount < footerSizeOverlay; flagsCount++)
                                    {
                                        CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <ModelAnimationTagResource.GroupMember.ScaleFrame>(dataContext));
                                    }
                                    #endregion

                                    switch (member.MovementDataType)
                                    {
                                    case ModelAnimationTagResource.GroupMemberMovementDataType.None:
                                        if (member.Unknown1 > 0)
                                        {
                                            for (int i = 0; i < member.FrameCount; i++)
                                            {
                                                CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <ModelAnimationTagResource.GroupMember.FrameInfoDyaw>(dataContext));
                                            }
                                        }
                                        if (member.Unknown2 > 0)
                                        {
                                            for (int i = 0; i < member.FrameCount; i++)
                                            {
                                                CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <ModelAnimationTagResource.GroupMember.FrameInfoDxDyDyaw>(dataContext));
                                            }
                                        }
                                        break;

                                    case ModelAnimationTagResource.GroupMemberMovementDataType.dx_dy:
                                        if (member.Unknown1 > 0)
                                        {
                                            for (int i = 0; i < member.FrameCount; i++)
                                            {
                                                CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <ModelAnimationTagResource.GroupMember.FrameInfoDxDy>(dataContext));
                                            }
                                        }
                                        if (member.Unknown2 > 0)
                                        {
                                            for (int i = 0; i < member.FrameCount; i++)
                                            {
                                                CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <ModelAnimationTagResource.GroupMember.FrameInfoDxDyDyaw>(dataContext));
                                            }
                                        }
                                        break;

                                    case ModelAnimationTagResource.GroupMemberMovementDataType.dx_dy_dyaw:
                                        if (member.Unknown1 > 0)
                                        {
                                            for (int i = 0; i < member.FrameCount; i++)
                                            {
                                                CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <ModelAnimationTagResource.GroupMember.FrameInfoDxDyDyaw>(dataContext));
                                            }
                                        }
                                        if (member.Unknown2 > 0)
                                        {
                                            for (int i = 0; i < member.FrameCount; i++)
                                            {
                                                CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <ModelAnimationTagResource.GroupMember.FrameInfoDxDyDyaw>(dataContext));
                                            }
                                        }
                                        break;

                                    case ModelAnimationTagResource.GroupMemberMovementDataType.dx_dy_dz_dyaw:
                                        if (member.Unknown1 > 0)
                                        {
                                            for (int i = 0; i < member.FrameCount; i++)
                                            {
                                                CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <ModelAnimationTagResource.GroupMember.FrameInfoDxDyDzDyaw>(dataContext));
                                            }
                                        }
                                        if (member.Unknown2 > 0)
                                        {
                                            for (int i = 0; i < member.FrameCount; i++)
                                            {
                                                CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <ModelAnimationTagResource.GroupMember.FrameInfoDxDyDzDyaw>(dataContext));
                                            }
                                        }
                                        break;

                                    default:
                                        break;
                                    }

                                    dataStream.Position = memberOffset + member.AnimationData.Size;

                                    // Before the next animation member, there's some padding that is garbage data in H3/ODST, but zeroed in HO.
                                    // In order to compare converted to original raw easily, copy the original data.
                                    while (blamResourceStream.Position % 0x10 != 0) // align to 0x10, useless padding of garbage data, it's zeroed in 1:1 HO raw, just read as 4 lame bytes
                                    {
                                        if (blamResourceStream.Position == blamResourceStream.Length)
                                        {
                                            break;
                                        }

                                        CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <ModelAnimationTagResource.GroupMember.ScaleFrame>(dataContext));
                                    }

                                    // Align the next animation member to 0x10.
                                    memberOffset += member.AnimationData.Size;
                                    while (memberOffset % 0x10 != 0)
                                    {
                                        memberOffset += 4;
                                    }
                                }

                                dataStream.Position = 0;

                                CacheContext.Serializer.Serialize(new ResourceSerializationContext(CacheContext, group.Resource), resourceDefinition[resDefIndex]);

                                group.Resource.ChangeLocation(ResourceLocation.ResourcesB);
                                var resource = group.Resource;

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

                                if (!dataStream.CanRead)
                                {
                                    throw new ArgumentException("The input stream is not open for reading", "dataStream");
                                }

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

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

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

                                var dataSize = (int)(dataStream.Length - dataStream.Position);
                                var data     = new byte[dataSize];
                                dataStream.Read(data, 0, dataSize);

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

            return(resourceGroups);
        }
Ejemplo n.º 7
0
        private PageableResource ConvertStructureBspTagResources(ScenarioStructureBsp bsp, Dictionary <ResourceLocation, Stream> resourceStreams)
        {
            //
            // Set up ElDorado resource reference
            //

            bsp.CollisionBspResource = new PageableResource
            {
                Page = new RawPage
                {
                    Index = -1
                },
                Resource = new TagResourceGen3
                {
                    ResourceType             = TagResourceTypeGen3.Collision,
                    DefinitionData           = new byte[0x30],
                    DefinitionAddress        = new CacheResourceAddress(CacheResourceAddressType.Definition, 0),
                    ResourceFixups           = new List <TagResourceGen3.ResourceFixup>(),
                    ResourceDefinitionFixups = new List <TagResourceGen3.ResourceDefinitionFixup>(),
                    Unknown2 = 1
                }
            };

            //
            // Port Blam resource definition
            //

            var resourceEntry = BlamCache.ResourceGestalt.TagResources[bsp.ZoneAssetIndex3.Index];

            bsp.CollisionBspResource.Resource.DefinitionAddress = resourceEntry.DefinitionAddress;
            bsp.CollisionBspResource.Resource.DefinitionData    = BlamCache.ResourceGestalt.FixupInformation.Skip(resourceEntry.FixupInformationOffset).Take(resourceEntry.FixupInformationLength).ToArray();

            StructureBspTagResources resourceDefinition = null;

            using (var definitionStream = new MemoryStream(bsp.CollisionBspResource.Resource.DefinitionData, true))
                using (var definitionReader = new EndianReader(definitionStream, EndianFormat.BigEndian))
                    using (var definitionWriter = new EndianWriter(definitionStream, EndianFormat.BigEndian))
                    {
                        foreach (var fixup in resourceEntry.ResourceFixups)
                        {
                            var newFixup = new TagResourceGen3.ResourceFixup
                            {
                                BlockOffset = (uint)fixup.BlockOffset,
                                Address     = new CacheResourceAddress(
                                    fixup.Type == 4 ?
                                    CacheResourceAddressType.Resource :
                                    CacheResourceAddressType.Definition,
                                    fixup.Offset)
                            };

                            definitionStream.Position = newFixup.BlockOffset;
                            definitionWriter.Write(newFixup.Address.Value);

                            bsp.CollisionBspResource.Resource.ResourceFixups.Add(newFixup);
                        }

                        var dataContext = new DataSerializationContext(definitionReader, definitionWriter, CacheResourceAddressType.Definition);

                        definitionStream.Position = bsp.CollisionBspResource.Resource.DefinitionAddress.Offset;
                        resourceDefinition        = BlamCache.Deserializer.Deserialize <StructureBspTagResources>(dataContext);

                        //
                        // Apply game-specific fixes to the resource definition
                        //

                        if (BlamCache.Version < CacheVersion.Halo3ODST)
                        {
                            resourceDefinition.LargeCollisionBsps = new List <StructureBspTagResources.LargeCollisionBspBlock>();
                            resourceDefinition.HavokData          = new List <StructureBspTagResources.HavokDatum>();
                        }

                        foreach (var instance in resourceDefinition.InstancedGeometry)
                        {
                            instance.Unknown5 = new TagBlock <StructureBspTagResources.InstancedGeometryBlock.Unknown4Block>();
                            instance.Unknown2 = new TagBlock <StructureBspTagResources.InstancedGeometryBlock.Unknown2Block>();
                        }
                    }

            //
            // Load Blam resource data
            //

            var resourceData = BlamCache.GetRawFromID(bsp.ZoneAssetIndex3);

            if (resourceData == null)
            {
                CacheContext.Serializer.Serialize(new ResourceSerializationContext(CacheContext, bsp.CollisionBspResource), resourceDefinition);
                return(bsp.CollisionBspResource);
            }

            //
            // Port Blam resource to ElDorado resource cache
            //

            using (var blamResourceStream = resourceData != null ? new MemoryStream(resourceData) : new MemoryStream())
                using (var resourceReader = new EndianReader(blamResourceStream, EndianFormat.BigEndian))
                    using (var dataStream = new MemoryStream())
                        using (var resourceWriter = new EndianWriter(dataStream, EndianFormat.LittleEndian))
                        {
                            var dataContext = new DataSerializationContext(resourceReader, resourceWriter);

                            foreach (var collisionBsp in resourceDefinition.CollisionBsps)
                            {
                                StreamUtil.Align(dataStream, 0x10);
                                blamResourceStream.Position     = collisionBsp.Bsp3dNodes.Address.Offset;
                                collisionBsp.Bsp3dNodes.Address = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                for (var i = 0; i < collisionBsp.Bsp3dNodes.Count; i++)
                                {
                                    CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <CollisionGeometry.Bsp3dNode>(dataContext));
                                }

                                StreamUtil.Align(dataStream, 0x10);
                                blamResourceStream.Position = collisionBsp.Planes.Address.Offset;
                                collisionBsp.Planes.Address = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                for (var i = 0; i < collisionBsp.Planes.Count; i++)
                                {
                                    CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <CollisionGeometry.Plane>(dataContext));
                                }

                                StreamUtil.Align(dataStream, 0x10);
                                blamResourceStream.Position = collisionBsp.Leaves.Address.Offset;
                                collisionBsp.Leaves.Address = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                for (var i = 0; i < collisionBsp.Leaves.Count; i++)
                                {
                                    CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <CollisionGeometry.Leaf>(dataContext));
                                }

                                StreamUtil.Align(dataStream, 0x10); // 0x4 > 0x10
                                blamResourceStream.Position          = collisionBsp.Bsp2dReferences.Address.Offset;
                                collisionBsp.Bsp2dReferences.Address = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                for (var i = 0; i < collisionBsp.Bsp2dReferences.Count; i++)
                                {
                                    CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <CollisionGeometry.Bsp2dReference>(dataContext));
                                }

                                StreamUtil.Align(dataStream, 0x10);
                                blamResourceStream.Position     = collisionBsp.Bsp2dNodes.Address.Offset;
                                collisionBsp.Bsp2dNodes.Address = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                for (var i = 0; i < collisionBsp.Bsp2dNodes.Count; i++)
                                {
                                    CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <CollisionGeometry.Bsp2dNode>(dataContext));
                                }

                                StreamUtil.Align(dataStream, 0x10);
                                blamResourceStream.Position   = collisionBsp.Surfaces.Address.Offset;
                                collisionBsp.Surfaces.Address = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                for (var i = 0; i < collisionBsp.Surfaces.Count; i++)
                                {
                                    var surface = BlamCache.Deserializer.Deserialize <CollisionGeometry.Surface>(dataContext);
                                    CacheContext.Serializer.Serialize(dataContext, surface);
                                }

                                StreamUtil.Align(dataStream, 0x10); // 0x4 > 0x10
                                blamResourceStream.Position = collisionBsp.Edges.Address.Offset;
                                collisionBsp.Edges.Address  = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                for (var i = 0; i < collisionBsp.Edges.Count; i++)
                                {
                                    CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <CollisionGeometry.Edge>(dataContext));
                                }

                                StreamUtil.Align(dataStream, 0x10);
                                blamResourceStream.Position   = collisionBsp.Vertices.Address.Offset;
                                collisionBsp.Vertices.Address = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                for (var i = 0; i < collisionBsp.Vertices.Count; i++)
                                {
                                    CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <CollisionGeometry.Vertex>(dataContext));
                                }
                            }

                            foreach (var largeCollisionBsp in resourceDefinition.LargeCollisionBsps)
                            {
                                StreamUtil.Align(dataStream, 0x10);
                                blamResourceStream.Position          = largeCollisionBsp.Bsp3dNodes.Address.Offset;
                                largeCollisionBsp.Bsp3dNodes.Address = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                for (var i = 0; i < largeCollisionBsp.Bsp3dNodes.Count; i++)
                                {
                                    CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <StructureBspTagResources.LargeCollisionBspBlock.Bsp3dNode>(dataContext));
                                }

                                StreamUtil.Align(dataStream, 0x10);
                                blamResourceStream.Position      = largeCollisionBsp.Planes.Address.Offset;
                                largeCollisionBsp.Planes.Address = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                for (var i = 0; i < largeCollisionBsp.Planes.Count; i++)
                                {
                                    CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <CollisionGeometry.Plane>(dataContext));
                                }

                                StreamUtil.Align(dataStream, 0x10);
                                blamResourceStream.Position      = largeCollisionBsp.Leaves.Address.Offset;
                                largeCollisionBsp.Leaves.Address = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                for (var i = 0; i < largeCollisionBsp.Leaves.Count; i++)
                                {
                                    CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <CollisionGeometry.Leaf>(dataContext));
                                }

                                StreamUtil.Align(dataStream, 0x10);
                                blamResourceStream.Position = largeCollisionBsp.Bsp2dReferences.Address.Offset;
                                largeCollisionBsp.Bsp2dReferences.Address = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                for (var i = 0; i < largeCollisionBsp.Bsp2dReferences.Count; i++)
                                {
                                    CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <StructureBspTagResources.LargeCollisionBspBlock.Bsp2dReference>(dataContext));
                                }

                                StreamUtil.Align(dataStream, 0x10);
                                blamResourceStream.Position          = largeCollisionBsp.Bsp2dNodes.Address.Offset;
                                largeCollisionBsp.Bsp2dNodes.Address = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                for (var i = 0; i < largeCollisionBsp.Bsp2dNodes.Count; i++)
                                {
                                    CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <StructureBspTagResources.LargeCollisionBspBlock.Bsp2dNode>(dataContext));
                                }

                                StreamUtil.Align(dataStream, 0x10);
                                blamResourceStream.Position        = largeCollisionBsp.Surfaces.Address.Offset;
                                largeCollisionBsp.Surfaces.Address = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                for (var i = 0; i < largeCollisionBsp.Surfaces.Count; i++)
                                {
                                    var surface = BlamCache.Deserializer.Deserialize <StructureBspTagResources.LargeCollisionBspBlock.Surface>(dataContext);
                                    // surface.Material = PortGlobalMaterialIndex(CacheContext, BlamCache, surface.Material);
                                    CacheContext.Serializer.Serialize(dataContext, surface);
                                }

                                StreamUtil.Align(dataStream, 0x10); // 0x4 > 0x10
                                blamResourceStream.Position     = largeCollisionBsp.Edges.Address.Offset;
                                largeCollisionBsp.Edges.Address = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                for (var i = 0; i < largeCollisionBsp.Edges.Count; i++)
                                {
                                    CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <StructureBspTagResources.LargeCollisionBspBlock.Edge>(dataContext));
                                }

                                StreamUtil.Align(dataStream, 0x10);
                                blamResourceStream.Position        = largeCollisionBsp.Vertices.Address.Offset;
                                largeCollisionBsp.Vertices.Address = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                for (var i = 0; i < largeCollisionBsp.Vertices.Count; i++)
                                {
                                    CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <StructureBspTagResources.LargeCollisionBspBlock.Vertex>(dataContext));
                                }
                            }

                            foreach (var instance in resourceDefinition.InstancedGeometry)
                            {
                                StreamUtil.Align(dataStream, 0x10); // 0x8 > 0x10
                                blamResourceStream.Position = instance.CollisionInfo.Bsp3dNodes.Address.Offset;
                                instance.CollisionInfo.Bsp3dNodes.Address = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                for (var i = 0; i < instance.CollisionInfo.Bsp3dNodes.Count; i++)
                                {
                                    CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <CollisionGeometry.Bsp3dNode>(dataContext));
                                }

                                StreamUtil.Align(dataStream, 0x10);
                                blamResourceStream.Position           = instance.CollisionInfo.Planes.Address.Offset;
                                instance.CollisionInfo.Planes.Address = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                for (var i = 0; i < instance.CollisionInfo.Planes.Count; i++)
                                {
                                    CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <CollisionGeometry.Plane>(dataContext));
                                }

                                StreamUtil.Align(dataStream, 0x10);
                                blamResourceStream.Position           = instance.CollisionInfo.Leaves.Address.Offset;
                                instance.CollisionInfo.Leaves.Address = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                for (var i = 0; i < instance.CollisionInfo.Leaves.Count; i++)
                                {
                                    CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <CollisionGeometry.Leaf>(dataContext));
                                }

                                StreamUtil.Align(dataStream, 0x10); // 0x4 > 0x10
                                blamResourceStream.Position = instance.CollisionInfo.Bsp2dReferences.Address.Offset;
                                instance.CollisionInfo.Bsp2dReferences.Address = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                for (var i = 0; i < instance.CollisionInfo.Bsp2dReferences.Count; i++)
                                {
                                    CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <CollisionGeometry.Bsp2dReference>(dataContext));
                                }

                                StreamUtil.Align(dataStream, 0x10);
                                blamResourceStream.Position = instance.CollisionInfo.Bsp2dNodes.Address.Offset;
                                instance.CollisionInfo.Bsp2dNodes.Address = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                for (var i = 0; i < instance.CollisionInfo.Bsp2dNodes.Count; i++)
                                {
                                    CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <CollisionGeometry.Bsp2dNode>(dataContext));
                                }

                                StreamUtil.Align(dataStream, 0x10);
                                blamResourceStream.Position             = instance.CollisionInfo.Surfaces.Address.Offset;
                                instance.CollisionInfo.Surfaces.Address = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                for (var i = 0; i < instance.CollisionInfo.Surfaces.Count; i++)
                                {
                                    var surface = BlamCache.Deserializer.Deserialize <CollisionGeometry.Surface>(dataContext);
                                    // surface.Material = PortGlobalMaterialIndex(CacheContext, BlamCache, surface.Material);
                                    CacheContext.Serializer.Serialize(dataContext, surface);
                                }

                                StreamUtil.Align(dataStream, 0x10); // 0x4 > 0x10
                                blamResourceStream.Position          = instance.CollisionInfo.Edges.Address.Offset;
                                instance.CollisionInfo.Edges.Address = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                for (var i = 0; i < instance.CollisionInfo.Edges.Count; i++)
                                {
                                    CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <CollisionGeometry.Edge>(dataContext));
                                }

                                StreamUtil.Align(dataStream, 0x10);
                                blamResourceStream.Position             = instance.CollisionInfo.Vertices.Address.Offset;
                                instance.CollisionInfo.Vertices.Address = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                for (var i = 0; i < instance.CollisionInfo.Vertices.Count; i++)
                                {
                                    CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <CollisionGeometry.Vertex>(dataContext));
                                }

                                foreach (var collisionGeometry in instance.CollisionGeometries)
                                {
                                    StreamUtil.Align(dataStream, 0x10); // 0x8 > 0x10
                                    blamResourceStream.Position          = collisionGeometry.Bsp3dNodes.Address.Offset;
                                    collisionGeometry.Bsp3dNodes.Address = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                    for (var i = 0; i < collisionGeometry.Bsp3dNodes.Count; i++)
                                    {
                                        CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <CollisionGeometry.Bsp3dNode>(dataContext));
                                    }

                                    StreamUtil.Align(dataStream, 0x10);
                                    blamResourceStream.Position      = collisionGeometry.Planes.Address.Offset;
                                    collisionGeometry.Planes.Address = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                    for (var i = 0; i < collisionGeometry.Planes.Count; i++)
                                    {
                                        CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <CollisionGeometry.Plane>(dataContext));
                                    }

                                    StreamUtil.Align(dataStream, 0x10);
                                    blamResourceStream.Position      = collisionGeometry.Leaves.Address.Offset;
                                    collisionGeometry.Leaves.Address = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                    for (var i = 0; i < collisionGeometry.Leaves.Count; i++)
                                    {
                                        CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <CollisionGeometry.Leaf>(dataContext));
                                    }

                                    StreamUtil.Align(dataStream, 0x10);
                                    blamResourceStream.Position = collisionGeometry.Bsp2dReferences.Address.Offset;
                                    collisionGeometry.Bsp2dReferences.Address = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                    for (var i = 0; i < collisionGeometry.Bsp2dReferences.Count; i++)
                                    {
                                        CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <CollisionGeometry.Bsp2dReference>(dataContext));
                                    }

                                    StreamUtil.Align(dataStream, 0x10);
                                    blamResourceStream.Position          = collisionGeometry.Bsp2dNodes.Address.Offset;
                                    collisionGeometry.Bsp2dNodes.Address = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                    for (var i = 0; i < collisionGeometry.Bsp2dNodes.Count; i++)
                                    {
                                        CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <CollisionGeometry.Bsp2dNode>(dataContext));
                                    }

                                    StreamUtil.Align(dataStream, 0x10);
                                    blamResourceStream.Position        = collisionGeometry.Surfaces.Address.Offset;
                                    collisionGeometry.Surfaces.Address = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                    for (var i = 0; i < collisionGeometry.Surfaces.Count; i++)
                                    {
                                        var surface = BlamCache.Deserializer.Deserialize <CollisionGeometry.Surface>(dataContext);
                                        // surface.Material = PortGlobalMaterialIndex(CacheContext, BlamCache, surface.Material);
                                        CacheContext.Serializer.Serialize(dataContext, surface);
                                    }

                                    StreamUtil.Align(dataStream, 0x10); // 0x4 > 0x10
                                    blamResourceStream.Position     = collisionGeometry.Edges.Address.Offset;
                                    collisionGeometry.Edges.Address = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                    for (var i = 0; i < collisionGeometry.Edges.Count; i++)
                                    {
                                        CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <CollisionGeometry.Edge>(dataContext));
                                    }

                                    StreamUtil.Align(dataStream, 0x10);
                                    blamResourceStream.Position        = collisionGeometry.Vertices.Address.Offset;
                                    collisionGeometry.Vertices.Address = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                    for (var i = 0; i < collisionGeometry.Vertices.Count; i++)
                                    {
                                        CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <CollisionGeometry.Vertex>(dataContext));
                                    }
                                }

                                foreach (var moppCode in instance.BspPhysics)
                                {
                                    StreamUtil.Align(dataStream, 0x10);
                                    blamResourceStream.Position = moppCode.Data.Address.Offset;
                                    moppCode.Data.Address       = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                    var moppData = resourceReader.ReadBytes(moppCode.Data.Count).Select(i => new CollisionMoppCode.Datum {
                                        Value = i
                                    }).ToList();
                                    if (BlamCache.Version < CacheVersion.Halo3ODST)
                                    {
                                        moppData = ConvertCollisionMoppData(moppData);
                                    }
                                    resourceWriter.Write(moppData.Select(i => i.Value).ToArray());
                                }

                                StreamUtil.Align(dataStream, 0x10); // 0x4 > 0x10
                                blamResourceStream.Position = instance.Unknown1.Address.Offset;
                                instance.Unknown1.Address   = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                for (var i = 0; i < instance.Unknown1.Count; i++)
                                {
                                    CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <StructureBspTagResources.InstancedGeometryBlock.Unknown1Block>(dataContext));
                                }

                                /*
                                 * StreamUtil.Align(dataStream, 0x4); // 0x4 > 0x10
                                 * blamResourceStream.Position = instance.Unknown2.Address.Offset;
                                 * instance.Unknown2.Address = new CacheAddress(CacheAddressType.Resource, (int)dataStream.Position);
                                 * for (var i = 0; i < instance.Unknown2.Count; i++)
                                 * {
                                 *  var element = BlamCache.Deserializer.Deserialize<StructureBspTagResources.InstancedGeometryBlock.Unknown2Block>(dataContext);
                                 *  if (BlamCache.Version <= CacheVersion.Halo3ODST)
                                 *  {
                                 *      element.Unknown1 = element.Unknown1_H3;
                                 *      element.Unknown2 = element.Unknown2_H3;
                                 *  }
                                 *  CacheContext.Serializer.Serialize(dataContext, element);
                                 */

                                StreamUtil.Align(dataStream, 0x10); // 0x4 > 0x10
                                blamResourceStream.Position = instance.Unknown3.Address.Offset;
                                instance.Unknown3.Address   = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                for (var i = 0; i < instance.Unknown3.Count; i++)
                                {
                                    CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <StructureBspTagResources.InstancedGeometryBlock.Unknown3Block>(dataContext));
                                }
                            }

                            dataStream.Position = 0;

                            CacheContext.Serializer.Serialize(new ResourceSerializationContext(CacheContext, bsp.CollisionBspResource), resourceDefinition);

                            bsp.CollisionBspResource.ChangeLocation(ResourceLocation.ResourcesB);
                            var resource = bsp.CollisionBspResource;

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

                            if (!dataStream.CanRead)
                            {
                                throw new ArgumentException("The input stream is not open for reading", "dataStream");
                            }

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

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

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

                            var dataSize = (int)(dataStream.Length - dataStream.Position);
                            var data     = new byte[dataSize];
                            dataStream.Read(data, 0, dataSize);

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

            return(bsp.CollisionBspResource);
        }
Ejemplo n.º 8
0
        private void MergeCharacter(Stream cacheStream, Dictionary <ResourceLocation, Stream> resourceStreams, CachedTagInstance edTag, CacheFile.IndexItem h3Tag)
        {
            var edDef = CacheContext.Deserialize <Character>(cacheStream, edTag);

            var h3Def = BlamCache.Deserializer.Deserialize <Character>(
                new CacheSerializationContext(ref BlamCache, h3Tag));

            var merged = false;

            if (edDef.WeaponsProperties.Count == h3Def.WeaponsProperties.Count)
            {
                for (var i = 0; i < edDef.WeaponsProperties.Count; i++)
                {
                    if (edDef.WeaponsProperties[i].Weapon != null || h3Def.WeaponsProperties[i].Weapon == null)
                    {
                        continue;
                    }

                    edDef.WeaponsProperties[i].Weapon = ConvertTag(cacheStream, resourceStreams,
                                                                   BlamCache.GetIndexItemFromID(h3Def.WeaponsProperties[i].Weapon.Index));

                    merged = true;
                }
            }

            if (edDef.VehicleProperties.Count == h3Def.VehicleProperties.Count)
            {
                for (var i = 0; i < edDef.VehicleProperties.Count; i++)
                {
                    if (edDef.VehicleProperties[i].Unit != null || h3Def.VehicleProperties[i].Unit == null)
                    {
                        continue;
                    }

                    edDef.VehicleProperties[i].Unit = ConvertTag(cacheStream, resourceStreams,
                                                                 BlamCache.GetIndexItemFromID(h3Def.VehicleProperties[i].Unit.Index));

                    merged = true;
                }
            }

            if (edDef.EquipmentProperties.Count == h3Def.EquipmentProperties.Count)
            {
                for (var i = 0; i < edDef.EquipmentProperties.Count; i++)
                {
                    if (edDef.EquipmentProperties[i].Equipment != null || h3Def.EquipmentProperties[i].Equipment == null)
                    {
                        continue;
                    }

                    edDef.EquipmentProperties[i].Equipment = ConvertTag(cacheStream, resourceStreams,
                                                                        BlamCache.GetIndexItemFromID(h3Def.EquipmentProperties[i].Equipment.Index));

                    merged = true;
                }
            }

            if (merged)
            {
                CacheContext.Serialize(cacheStream, edTag, edDef);
            }
        }
Ejemplo n.º 9
0
        private void MergeMultiplayerEvent(Stream cacheStream, Dictionary <ResourceLocation, Stream> resourceStreams, MultiplayerGlobals.RuntimeBlock.EventBlock edEvent, MultiplayerGlobals.RuntimeBlock.EventBlock h3Event)
        {
            if (h3Event.EnglishSound != null)
            {
                edEvent.EnglishSound = ConvertTag(cacheStream, resourceStreams, BlamCache.GetIndexItemFromID(h3Event.EnglishSound.Index));
            }

            if (h3Event.JapaneseSound != null)
            {
                edEvent.JapaneseSound = ConvertTag(cacheStream, resourceStreams, BlamCache.GetIndexItemFromID(h3Event.JapaneseSound.Index));
            }

            if (h3Event.GermanSound != null)
            {
                edEvent.GermanSound = ConvertTag(cacheStream, resourceStreams, BlamCache.GetIndexItemFromID(h3Event.GermanSound.Index));
            }

            if (h3Event.FrenchSound != null)
            {
                edEvent.FrenchSound = ConvertTag(cacheStream, resourceStreams, BlamCache.GetIndexItemFromID(h3Event.FrenchSound.Index));
            }

            if (h3Event.SpanishSound != null)
            {
                edEvent.SpanishSound = ConvertTag(cacheStream, resourceStreams, BlamCache.GetIndexItemFromID(h3Event.SpanishSound.Index));
            }

            if (h3Event.LatinAmericanSpanishSound != null)
            {
                edEvent.LatinAmericanSpanishSound = ConvertTag(cacheStream, resourceStreams, BlamCache.GetIndexItemFromID(h3Event.LatinAmericanSpanishSound.Index));
            }

            if (h3Event.ItalianSound != null)
            {
                edEvent.ItalianSound = ConvertTag(cacheStream, resourceStreams, BlamCache.GetIndexItemFromID(h3Event.ItalianSound.Index));
            }

            if (h3Event.KoreanSound != null)
            {
                edEvent.KoreanSound = ConvertTag(cacheStream, resourceStreams, BlamCache.GetIndexItemFromID(h3Event.KoreanSound.Index));
            }

            if (h3Event.ChineseTraditionalSound != null)
            {
                edEvent.ChineseTraditionalSound = ConvertTag(cacheStream, resourceStreams, BlamCache.GetIndexItemFromID(h3Event.ChineseTraditionalSound.Index));
            }

            if (h3Event.ChineseSimplifiedSound != null)
            {
                edEvent.ChineseSimplifiedSound = ConvertTag(cacheStream, resourceStreams, BlamCache.GetIndexItemFromID(h3Event.ChineseSimplifiedSound.Index));
            }

            if (h3Event.PortugueseSound != null)
            {
                edEvent.PortugueseSound = ConvertTag(cacheStream, resourceStreams, BlamCache.GetIndexItemFromID(h3Event.PortugueseSound.Index));
            }

            if (h3Event.PolishSound != null)
            {
                edEvent.PolishSound = ConvertTag(cacheStream, resourceStreams, BlamCache.GetIndexItemFromID(h3Event.PolishSound.Index));
            }
        }
Ejemplo n.º 10
0
        private RenderMethod FixAnimationProperties(Stream cacheStream, Stream blamCacheStream, Dictionary <ResourceLocation, Stream> resourceStreams, GameCache blamCache, GameCacheHaloOnlineBase CacheContext, RenderMethod finalRm, RenderMethodTemplate edRmt2, RenderMethodTemplate bmRmt2, string blamTagName)
        {
            // finalRm is a H3 rendermethod with ported bitmaps,
            if (finalRm.ShaderProperties[0].Functions.Count == 0)
            {
                return(finalRm);
            }

            foreach (var properties in finalRm.ShaderProperties[0].Functions)
            {
                properties.InputName = ConvertStringId(properties.InputName);
                properties.RangeName = ConvertStringId(properties.RangeName);

                ConvertTagFunction(properties.Function);
            }

            var pixlTag = CacheContext.Deserialize(cacheStream, edRmt2.PixelShader);
            var edPixl  = (PixelShader)pixlTag;
            var bmPixl  = BlamCache.Deserialize <PixelShader>(blamCacheStream, bmRmt2.PixelShader);

            // Make a collection of drawmodes and their DrawModeItem's
            // DrawModeItem are has info about all registers modified by functions for each drawmode.

            var bmPixlParameters = new Dictionary <int, List <ArgumentMapping> >(); // key is shader index

            // pixl side
            // For each drawmode, find its shader, and get all that shader's parameter.
            // Each parameter has a registerIndex, a registerType, and a registerName.
            // We'll use this to know which function acts on what shader and which registers

            var RegistersList = new Dictionary <int, string>();

            foreach (var a in finalRm.ShaderProperties[0].Parameters)
            {
                if (!RegistersList.ContainsKey(a.RegisterIndex))
                {
                    RegistersList.Add(a.RegisterIndex, "");
                }
            }

            var DrawModeIndex = -1;

            foreach (var a in bmPixl.DrawModes)
            {
                DrawModeIndex++;

                bmPixlParameters.Add(DrawModeIndex, new List <ArgumentMapping>());

                if (a.Count == 0)
                {
                    continue;
                }

                foreach (var b in bmPixl.Shaders[a.Offset].XboxParameters)
                {
                    var ParameterName = BlamCache.StringTable.GetString(b.ParameterName);

                    bmPixlParameters[DrawModeIndex].Add(new ArgumentMapping
                    {
                        ShaderIndex   = a.Offset,
                        ParameterName = ParameterName,
                        RegisterIndex = b.RegisterIndex,
                        RegisterType  = b.RegisterType
                    });
                }
            }

            // rm side
            var bmDrawmodesFunctions = new Dictionary <int, Unknown3Tagblock>(); // key is shader index

            DrawModeIndex = -1;
            foreach (var a in finalRm.ShaderProperties[0].EntryPoints)
            {
                DrawModeIndex++;

                // These are not modes. This is an indireciton table of packed 10_6 shorts
                // from RMT2 ShaderDrawmodes to RegisterOffsets
                // register_offset = ShaderDrawmodes[current_drawmode].Offset
                var drawmodeRegisterOffset = (int)a.Offset;
                var drawmodeRegisterCount  = (int)a.Count;


                var ArgumentMappingsIndexSampler = (byte)finalRm.ShaderProperties[0].ParameterTables[drawmodeRegisterOffset].Texture.Offset;
                var ArgumentMappingsCountSampler = finalRm.ShaderProperties[0].ParameterTables[drawmodeRegisterOffset].Texture.Count;
                var ArgumentMappingsIndexUnknown = (byte)finalRm.ShaderProperties[0].ParameterTables[drawmodeRegisterOffset].RealVertex.Offset;
                var ArgumentMappingsCountUnknown = finalRm.ShaderProperties[0].ParameterTables[drawmodeRegisterOffset].RealVertex.Count;
                var ArgumentMappingsIndexVector  = (byte)finalRm.ShaderProperties[0].ParameterTables[drawmodeRegisterOffset].RealPixel.Offset;
                var ArgumentMappingsCountVector  = finalRm.ShaderProperties[0].ParameterTables[drawmodeRegisterOffset].RealPixel.Count;
                var ArgumentMappings             = new List <ArgumentMapping>();

                for (int j = 0; j < ArgumentMappingsCountSampler; j++)
                {
                    ArgumentMappings.Add(new ArgumentMapping
                    {
                        RegisterIndex = finalRm.ShaderProperties[0].Parameters[ArgumentMappingsIndexSampler + j].RegisterIndex,
                        ArgumentIndex = finalRm.ShaderProperties[0].Parameters[ArgumentMappingsIndexSampler + j].SourceIndex, // i don't think i can use it to match stuf
                        ArgumentMappingsTagblockIndex = ArgumentMappingsIndexSampler + j,
                        RegisterType = TagTool.Shaders.ShaderParameter.RType.Sampler,
                        ShaderIndex  = drawmodeRegisterOffset,
                        // WARNING i think drawmodes in rm aren't the same as in pixl, because rm drawmodes can point to a global shader .
                        // say rm.drawmodes[17]'s value is 13, pixl.drawmodes[17] would typically be 12
                    });
                }

                for (int j = 0; j < ArgumentMappingsCountUnknown; j++)
                {
                    ArgumentMappings.Add(new ArgumentMapping
                    {
                        RegisterIndex = finalRm.ShaderProperties[0].Parameters[ArgumentMappingsIndexUnknown + j].RegisterIndex,
                        ArgumentIndex = finalRm.ShaderProperties[0].Parameters[ArgumentMappingsIndexUnknown + j].SourceIndex,
                        ArgumentMappingsTagblockIndex = ArgumentMappingsIndexUnknown + j,
                        RegisterType = TagTool.Shaders.ShaderParameter.RType.Vector,
                        ShaderIndex  = drawmodeRegisterOffset,
                        // it's something else, uses a global shader or some shit, one water shader pointed to a vtsh in rasg, but not in H3, maybe coincidence
                        // yeah guaranteed rmdf's glvs or rasg shaders
                    });
                }

                for (int j = 0; j < ArgumentMappingsCountVector; j++)
                {
                    ArgumentMappings.Add(new ArgumentMapping
                    {
                        RegisterIndex = finalRm.ShaderProperties[0].Parameters[ArgumentMappingsIndexVector + j].RegisterIndex,
                        ArgumentIndex = finalRm.ShaderProperties[0].Parameters[ArgumentMappingsIndexVector + j].SourceIndex,
                        ArgumentMappingsTagblockIndex = ArgumentMappingsIndexVector + j,
                        RegisterType = TagTool.Shaders.ShaderParameter.RType.Vector,
                        ShaderIndex  = drawmodeRegisterOffset,
                    });
                }

                bmDrawmodesFunctions.Add(DrawModeIndex, new Unknown3Tagblock
                {
                    Unknown3Index = drawmodeRegisterOffset, // not shader index for rm and rmt2
                    Unknown3Count = drawmodeRegisterCount,  // should always be 4 for enabled drawmodes
                    ArgumentMappingsIndexSampler = ArgumentMappingsIndexSampler,
                    ArgumentMappingsCountSampler = ArgumentMappingsCountSampler,
                    ArgumentMappingsIndexUnknown = ArgumentMappingsIndexUnknown, // no clue what it's used for, global shaders? i know one of the drawmodes will use one or more shaders from glvs, no idea if always or based on something
                    ArgumentMappingsCountUnknown = ArgumentMappingsCountUnknown,
                    ArgumentMappingsIndexVector  = ArgumentMappingsIndexVector,
                    ArgumentMappingsCountVector  = ArgumentMappingsCountVector,
                    ArgumentMappings             = ArgumentMappings
                });
            }

            DrawModeIndex = -1;
            foreach (var a in bmDrawmodesFunctions)
            {
                DrawModeIndex++;
                if (a.Value.Unknown3Count == 0)
                {
                    continue;
                }

                foreach (var b in a.Value.ArgumentMappings)
                {
                    foreach (var c in bmPixlParameters[a.Key])
                    {
                        if (b.RegisterIndex == c.RegisterIndex && b.RegisterType == c.RegisterType)
                        {
                            b.ParameterName = c.ParameterName;
                            break;
                        }
                    }
                }
            }

            // // Now that we know which register is what for each drawmode, find its halo online equivalent register indexes based on register name.
            // // This is where it gets tricky because drawmodes count changed in HO.
            foreach (var a in bmDrawmodesFunctions)
            {
                if (a.Value.Unknown3Count == 0)
                {
                    continue;
                }

                foreach (var b in a.Value.ArgumentMappings)
                {
                    foreach (var c in edPixl.Shaders[edPixl.DrawModes[a.Key].Offset].PCParameters)
                    {
                        var ParameterName = CacheContext.StringTable.GetString(c.ParameterName);

                        if (ParameterName == b.ParameterName && b.RegisterType == c.RegisterType)
                        {
                            if (RegistersList[b.RegisterIndex] == "")
                            {
                                RegistersList[b.RegisterIndex] = $"{c.RegisterIndex}";
                            }
                            else
                            {
                                RegistersList[b.RegisterIndex] = $"{RegistersList[b.RegisterIndex]},{c.RegisterIndex}";
                            }

                            b.EDRegisterIndex = c.RegisterIndex;
                        }
                    }
                }
            }

            // DEBUG draw registers
            // DEBUG check for invalid registers
            foreach (var a in bmDrawmodesFunctions)
            {
                if (a.Value.Unknown3Count == 0)
                {
                    continue;
                }

                foreach (var b in a.Value.ArgumentMappings)
                {
                    finalRm.ShaderProperties[0].Parameters[b.ArgumentMappingsTagblockIndex].RegisterIndex = (short)b.EDRegisterIndex;
                }
            }

            // one final check
            // Gather all register indexes from pixl tag. Then check against all the converted register indexes.
            // It should detect registers that are invalid and would crash, but it does not verify if the register is valid.
            var validEDRegisters = new List <int>();

            foreach (var a in edPixl.Shaders)
            {
                foreach (var b in a.PCParameters)
                {
                    if (!validEDRegisters.Contains(b.RegisterIndex))
                    {
                        validEDRegisters.Add(b.RegisterIndex);
                    }
                }
            }

            foreach (var a in finalRm.ShaderProperties[0].Parameters)
            {
                if (!validEDRegisters.Contains((a.RegisterIndex)))
                {
                    // Display a warning
                    // Console.WriteLine($"INVALID REGISTERS IN TAG {blamTagName}!");

                    finalRm.ShaderProperties[0].EntryPoints     = new List <RenderMethodTemplate.PackedInteger_10_6>();
                    finalRm.ShaderProperties[0].ParameterTables = new List <ParameterTable>();
                    finalRm.ShaderProperties[0].Parameters      = new List <ParameterMapping>();
                    finalRm.ShaderProperties[0].Functions       = new List <ShaderFunction>();
                    foreach (var map in finalRm.ShaderProperties[0].TextureConstants)
                    {
                        map.Functions.Integer = 0;
                    }
                    return(finalRm);
                }
            }

            return(finalRm);
        }
Ejemplo n.º 11
0
        private RenderMethod ConvertRenderMethod(Stream cacheStream, Stream blamCacheStream, Dictionary <ResourceLocation, Stream> resourceStreams, RenderMethod finalRm, string blamTagName)
        {
            // Verify that the ShaderMatcher is ready to use
            if (!Matcher.IsInitialized())
            {
                Matcher.Init(cacheStream, CacheContext, BlamCache);
            }

            // Set flags
            Matcher.SetMS30Flag(cacheStream, FlagIsSet(PortingFlags.Ms30));

            // finalRm.ShaderProperties[0].ShaderMaps are all ported bitmaps
            // finalRm.BaseRenderMethod is a H3 tag
            // finalRm.ShaderProperties[0].Template is a H3 tag

            // TODO hardcode shader values such as argument changes for specific shaders
            var bmMaps          = new List <string>();
            var bmRealConstants = new List <string>();
            var bmIntConstants  = new List <string>();
            var bmBoolConstants = new List <string>();
            var edMaps          = new List <string>();
            var edRealConstants = new List <string>();
            var edIntConstants  = new List <string>();
            var edBoolConstants = new List <string>();

            // Reset rmt2 preset
            var pRmt2 = 0;

            // Make a template of ShaderProperty, with the correct bitmaps and arguments counts.
            var newShaderProperty = new RenderMethod.ShaderProperty
            {
                TextureConstants = new List <RenderMethod.ShaderProperty.TextureConstant>(),
                RealConstants    = new List <RenderMethod.ShaderProperty.RealConstant>(),
                IntegerConstants = new List <uint>()
            };

            // Get a simple list of bitmaps and arguments names
            var bmRmt2Instance = finalRm.ShaderProperties[0].Template;
            var bmRmt2         = BlamCache.Deserialize <RenderMethodTemplate>(blamCacheStream, bmRmt2Instance);

            // Get a simple list of H3 bitmaps and arguments names
            foreach (var a in bmRmt2.TextureParameterNames)
            {
                bmMaps.Add(BlamCache.StringTable.GetString(a.Name));
            }
            foreach (var a in bmRmt2.RealParameterNames)
            {
                bmRealConstants.Add(BlamCache.StringTable.GetString(a.Name));
            }
            foreach (var a in bmRmt2.IntegerParameterNames)
            {
                bmIntConstants.Add(BlamCache.StringTable.GetString(a.Name));
            }
            foreach (var a in bmRmt2.BooleanParameterNames)
            {
                bmBoolConstants.Add(BlamCache.StringTable.GetString(a.Name));
            }

            // Find a HO equivalent rmt2
            var edRmt2Instance = Matcher.FixRmt2Reference(cacheStream, blamTagName, bmRmt2Instance, bmRmt2, bmMaps, bmRealConstants);

            if (edRmt2Instance == null)
            {
                throw new Exception($"Failed to find HO rmt2 for this RenderMethod instance");
            }


            var edRmt2Tagname = edRmt2Instance.Name ?? $"0x{edRmt2Instance.Index:X4}";

            // pRmsh pRmt2 now potentially have a new value
            if (pRmt2 != 0)
            {
                if (pRmt2 < CacheContext.TagCache.Count && pRmt2 >= 0)
                {
                    var a = CacheContext.TagCache.GetTag(pRmt2);
                    if (a != null)
                    {
                        edRmt2Instance = a;
                    }
                }
            }

            var edRmt2 = CacheContext.Deserialize <RenderMethodTemplate>(cacheStream, edRmt2Instance);

            // fixup for no use_material_texture vector arg in ms23
            //for (int index = 0; index < edRmt2.BooleanArguments.Count; index++)
            //{
            //    if (CacheContext.StringTable.GetString(edRmt2.BooleanArguments[index].Name) == "use_material_texture")
            //    {
            //        finalRm.ShaderProperties[0].BooleanArguments = (ushort)(index + 1);
            //        break;
            //    }
            //}

            foreach (var a in edRmt2.TextureParameterNames)
            {
                edMaps.Add(CacheContext.StringTable.GetString(a.Name));
            }
            foreach (var a in edRmt2.RealParameterNames)
            {
                edRealConstants.Add(CacheContext.StringTable.GetString(a.Name));
            }
            foreach (var a in edRmt2.IntegerParameterNames)
            {
                edIntConstants.Add(CacheContext.StringTable.GetString(a.Name));
            }
            foreach (var a in edRmt2.BooleanParameterNames)
            {
                edBoolConstants.Add(CacheContext.StringTable.GetString(a.Name));
            }


            // The bitmaps are default textures.
            // Arguments are probably default values. I took the values that appeared the most frequently, assuming they are the default value.
            foreach (var a in edMaps)
            {
                var newBitmap = Matcher.GetDefaultBitmapTag(a);

                if (pRmt2 >= CacheContext.TagCache.Count || pRmt2 < 0)
                {
                    newBitmap = @"shaders\default_bitmaps\bitmaps\default_detail"; // would only happen for removed shaders
                }
                CachedTag bitmap = null;

                try
                {
                    bitmap = CacheContext.GetTag <Bitmap>(newBitmap);
                }
                catch
                {
                    bitmap = ConvertTag(cacheStream, blamCacheStream, resourceStreams, ParseLegacyTag($"{newBitmap}.bitm")[0]);
                }

                newShaderProperty.TextureConstants.Add(
                    new RenderMethod.ShaderProperty.TextureConstant
                {
                    Bitmap = bitmap
                });
            }

            foreach (var a in edRealConstants)
            {
                newShaderProperty.RealConstants.Add(Matcher.DefaultArgumentsValues(a));
            }

            foreach (var a in edIntConstants)
            {
                newShaderProperty.IntegerConstants.Add(Matcher.DefaultIntegerArgumentsValues(a));
            }

            // Reorder blam bitmaps to match the HO rmt2 order
            // Reorder blam real constants to match the HO rmt2 order
            // Reorder blam int constants to match the HO rmt2 order
            // Reorder blam bool constants to match the HO rmt2 order
            foreach (var eM in edMaps)
            {
                foreach (var bM in bmMaps)
                {
                    if (eM == bM)
                    {
                        newShaderProperty.TextureConstants[edMaps.IndexOf(eM)] = finalRm.ShaderProperties[0].TextureConstants[bmMaps.IndexOf(bM)];
                    }
                }
            }

            foreach (var eA in edRealConstants)
            {
                foreach (var bA in bmRealConstants)
                {
                    if (eA == bA)
                    {
                        newShaderProperty.RealConstants[edRealConstants.IndexOf(eA)] = finalRm.ShaderProperties[0].RealConstants[bmRealConstants.IndexOf(bA)];
                    }
                }
            }

            foreach (var eA in edIntConstants)
            {
                foreach (var bA in bmIntConstants)
                {
                    if (eA == bA)
                    {
                        newShaderProperty.IntegerConstants[edIntConstants.IndexOf(eA)] = finalRm.ShaderProperties[0].IntegerConstants[bmIntConstants.IndexOf(bA)];
                    }
                }
            }

            foreach (var eA in edBoolConstants)
            {
                foreach (var bA in bmBoolConstants)
                {
                    if (eA == bA)
                    {
                        if ((newShaderProperty.BooleanConstants & (1u << bmBoolConstants.IndexOf(bA))) != 0)
                        {
                            newShaderProperty.BooleanConstants &= ~(1u << bmBoolConstants.IndexOf(bA));
                            newShaderProperty.BooleanConstants |= (1u << edBoolConstants.IndexOf(eA));
                        }
                    }
                }
            }

            // Remove some tagblocks
            // finalRm.Unknown = new List<RenderMethod.UnknownBlock>(); // hopefully not used; this gives rmt2's name. They correspond to the first tagblocks in rmdf, they tell what the shader does
            finalRm.ImportData = new List <RenderMethod.ImportDatum>(); // most likely not used
            finalRm.ShaderProperties[0].Template         = edRmt2Instance;
            finalRm.ShaderProperties[0].TextureConstants = newShaderProperty.TextureConstants;
            finalRm.ShaderProperties[0].RealConstants    = newShaderProperty.RealConstants;
            finalRm.ShaderProperties[0].IntegerConstants = newShaderProperty.IntegerConstants;
            finalRm.ShaderProperties[0].BooleanConstants = newShaderProperty.BooleanConstants;

            // fixup runtime queryable properties
            for (int i = 0; i < finalRm.ShaderProperties[0].QueryableProperties.Length; i++)
            {
                if (finalRm.ShaderProperties[0].QueryableProperties[i] == -1)
                {
                    continue;
                }

                switch (i)
                {
                case 0:
                case 1:
                case 2:
                case 3:
                case 5:
                    finalRm.ShaderProperties[0].QueryableProperties[i] = (short)edMaps.IndexOf(bmMaps[finalRm.ShaderProperties[0].QueryableProperties[i]]);
                    break;

                case 4:
                    finalRm.ShaderProperties[0].QueryableProperties[i] = (short)edRealConstants.IndexOf(bmRealConstants[finalRm.ShaderProperties[0].QueryableProperties[i]]);
                    break;

                default:
                    finalRm.ShaderProperties[0].QueryableProperties[i] = -1;
                    break;
                }
            }

            // fixup xform arguments;
            foreach (var tex in finalRm.ShaderProperties[0].TextureConstants)
            {
                if (tex.XFormArgumentIndex != -1)
                {
                    tex.XFormArgumentIndex = (sbyte)edRealConstants.IndexOf(bmRealConstants[tex.XFormArgumentIndex]);
                }
            }

            Matcher.FixRmdfTagRef(finalRm);

            FixAnimationProperties(cacheStream, blamCacheStream, resourceStreams, BlamCache, CacheContext, finalRm, edRmt2, bmRmt2, blamTagName);

            // Fix any null bitmaps, caused by bitm port failure
            foreach (var a in finalRm.ShaderProperties[0].TextureConstants)
            {
                if (a.Bitmap != null)
                {
                    continue;
                }

                var defaultBitmap = Matcher.GetDefaultBitmapTag(edMaps[finalRm.ShaderProperties[0].TextureConstants.IndexOf(a)]);

                try
                {
                    a.Bitmap = CacheContext.GetTag <Bitmap>(defaultBitmap);
                }
                catch
                {
                    a.Bitmap = ConvertTag(cacheStream, blamCacheStream, resourceStreams, ParseLegacyTag($"{defaultBitmap}.bitm")[0]);
                }
            }

            switch (blamTagName)
            {
            case @"levels\dlc\chillout\shaders\chillout_flood_godrays" when finalRm is ShaderHalogram:
            {
                // Fixup bitmaps
                for (var i = 0; i < edRmt2.TextureParameterNames.Count; i++)
                {
                    if (CacheContext.StringTable.GetString(edRmt2.TextureParameterNames[i].Name) == "overlay_map")
                    {
                        finalRm.ShaderProperties[0].TextureConstants[i].Bitmap = ConvertTag(cacheStream, blamCacheStream, resourceStreams, ParseLegacyTag(@"levels\dlc\chillout\bitmaps\chillout_flood_godrays.bitmap")[0]);
                        break;
                    }
                }

                // Fixup arguments
                for (var i = 0; i < edRmt2.RealParameterNames.Count; i++)
                {
                    var templateArg = edRmt2.RealParameterNames[i];

                    switch (CacheContext.StringTable.GetString(templateArg.Name))
                    {
                    case "overlay_map":
                        finalRm.ShaderProperties[0].RealConstants[i].Values = new float[] { 1f, 1f, 0f, 0f };
                        break;

                    case "overlay_tint":
                        finalRm.ShaderProperties[0].RealConstants[i].Values = new float[] { 0.3764706f, 0.7254902f, 0.9215687f, 1f };
                        break;

                    case "overlay_intensity":
                        finalRm.ShaderProperties[0].RealConstants[i].Values = new float[] { 1.25f, 1.25f, 1.25f, 1.25f };
                        break;
                    }
                }
                break;
            }

            case @"levels\dlc\chillout\shaders\chillout_invis_godrays" when finalRm is ShaderHalogram:
            {
                // Fixup bitmaps
                for (var i = 0; i < edRmt2.TextureParameterNames.Count; i++)
                {
                    if (CacheContext.StringTable.GetString(edRmt2.TextureParameterNames[i].Name) == "overlay_map")
                    {
                        finalRm.ShaderProperties[0].TextureConstants[i].Bitmap = ConvertTag(cacheStream, blamCacheStream, resourceStreams, ParseLegacyTag(@"levels\dlc\chillout\bitmaps\chillout_invis_godrays.bitmap")[0]);
                        break;
                    }
                }

                // Fixup arguments
                for (var i = 0; i < edRmt2.RealParameterNames.Count; i++)
                {
                    var templateArg = edRmt2.RealParameterNames[i];

                    switch (CacheContext.StringTable.GetString(templateArg.Name))
                    {
                    case "overlay_map":
                        finalRm.ShaderProperties[0].RealConstants[i].Values = new float[] { 1f, 1f, 0f, 0f };
                        break;

                    case "overlay_tint":
                        finalRm.ShaderProperties[0].RealConstants[i].Values = new float[] { 0.3058824f, 0.7098039f, 0.937255f, 1f };
                        break;

                    case "overlay_intensity":
                        finalRm.ShaderProperties[0].RealConstants[i].Values = new float[] { 1f, 1f, 1f, 1f };
                        break;
                    }
                }
                break;
            }

            case @"levels\solo\020_base\lights\light_volume_hatlight" when finalRm is ShaderHalogram:
            {
                // Fixup bitmaps
                for (var i = 0; i < edRmt2.TextureParameterNames.Count; i++)
                {
                    if (CacheContext.StringTable.GetString(edRmt2.TextureParameterNames[i].Name) == "overlay_map")
                    {
                        finalRm.ShaderProperties[0].TextureConstants[i].Bitmap = ConvertTag(cacheStream, blamCacheStream, resourceStreams, ParseLegacyTag(@"levels\solo\020_base\bitmaps\light_volume_hatlight.bitmap")[0]);
                        break;
                    }
                }

                // Fixup arguments
                for (var i = 0; i < edRmt2.RealParameterNames.Count; i++)
                {
                    var templateArg = edRmt2.RealParameterNames[i];

                    switch (CacheContext.StringTable.GetString(templateArg.Name))
                    {
                    case "overlay_map":
                        finalRm.ShaderProperties[0].RealConstants[i].Values = new float[] { 2f, 1f, 0f, 0f };
                        break;

                    case "overlay_tint":
                        finalRm.ShaderProperties[0].RealConstants[i].Values = new float[] { 0.9960785f, 1f, 0.8039216f, 1f };
                        break;

                    case "overlay_intensity":
                        finalRm.ShaderProperties[0].RealConstants[i].Values = new float[] { 1f, 1f, 1f, 1f };
                        break;
                    }
                }
                break;
            }

            case @"objects\vehicles\ghost\shaders\ghost_dash_zcam" when finalRm is ShaderHalogram:
            case @"objects\weapons\rifle\sniper_rifle\shaders\scope_alpha" when finalRm is ShaderHalogram:
                finalRm.InputVariable = TagTool.Tags.TagMapping.VariableTypeValue.ParticleRandom1;
                finalRm.RangeVariable = TagTool.Tags.TagMapping.VariableTypeValue.ParticleAge;
                break;

            case @"levels\dlc\armory\shaders\concrete_floor_smooth" when finalRm is Shader:
            {
                // Fixup bitmaps
                for (var i = 0; i < edRmt2.TextureParameterNames.Count; i++)
                {
                    if (CacheContext.StringTable.GetString(edRmt2.TextureParameterNames[i].Name) == "bump_map")
                    {
                        finalRm.ShaderProperties[0].TextureConstants[i].Bitmap = ConvertTag(cacheStream, blamCacheStream, resourceStreams, ParseLegacyTag(@"levels\dlc\armory\bitmaps\concrete_floor_bump.bitmap")[0]);
                        break;
                    }
                }
                break;
            }

            case @"levels\dlc\sidewinder\shaders\side_tree_branch_snow" when finalRm is Shader:
                for (var i = 0; i < edRmt2.RealParameterNames.Count; i++)
                {
                    var templateArg = edRmt2.RealParameterNames[i];

                    if (CacheContext.StringTable.GetString(templateArg.Name) == "env_tint_color")
                    {
                        finalRm.ShaderProperties[0].RealConstants[i].Values = new float[] { 0f, 0f, 0f, 0f };
                        break;
                    }
                }
                break;

            case @"levels\multi\isolation\sky\shaders\skydome" when finalRm is Shader:
                for (var i = 0; i < edRmt2.RealParameterNames.Count; i++)
                {
                    var templateArg = edRmt2.RealParameterNames[i];

                    if (CacheContext.StringTable.GetString(templateArg.Name) == "albedo_color")
                    {
                        finalRm.ShaderProperties[0].RealConstants[i].Values = new float[] { 0.447059f, 0.376471f, 0.898039f, 1.0f };
                        break;
                    }
                }
                break;

            case @"levels\multi\snowbound\shaders\cov_grey_icy" when finalRm is Shader:
            {
                // Fixup bitmaps
                for (var i = 0; i < edRmt2.TextureParameterNames.Count; i++)
                {
                    switch (CacheContext.StringTable.GetString(edRmt2.TextureParameterNames[i].Name))
                    {
                    case "base_map":
                        try
                        {
                            finalRm.ShaderProperties[0].TextureConstants[i].Bitmap = ConvertTag(cacheStream, blamCacheStream, resourceStreams, ParseLegacyTag(@"levels\multi\snowbound\bitmaps\for_metal_greytech_dif.bitmap")[0]);
                        }
                        catch { }
                        break;

                    case "detail_map":
                        try
                        {
                            finalRm.ShaderProperties[0].TextureConstants[i].Bitmap = ConvertTag(cacheStream, blamCacheStream, resourceStreams, ParseLegacyTag(@"levels\multi\snowbound\bitmaps\for_metal_greytech_icy.bitmap")[0]);
                        }
                        catch { }
                        break;

                    case "bump_map":
                        try
                        {
                            finalRm.ShaderProperties[0].TextureConstants[i].Bitmap = ConvertTag(cacheStream, blamCacheStream, resourceStreams, ParseLegacyTag(@"levels\multi\snowbound\bitmaps\for_metal_greytech_platebump.bitmap")[0]);
                        }
                        catch { }
                        break;

                    case "bump_detail_map":
                        try
                        {
                            finalRm.ShaderProperties[0].TextureConstants[i].Bitmap = ConvertTag(cacheStream, blamCacheStream, resourceStreams, ParseLegacyTag(@"levels\multi\snowbound\bitmaps\for_metal_greytech_bump.bitmap")[0]);
                        }
                        catch { }
                        break;
                    }
                }

                // Fixup arguments
                for (var i = 0; i < edRmt2.RealParameterNames.Count; i++)
                {
                    var templateArg = edRmt2.RealParameterNames[i];

                    switch (CacheContext.StringTable.GetString(templateArg.Name))
                    {
                    case "base_map":
                        finalRm.ShaderProperties[0].RealConstants[i].Values = new float[] { 1f, 1f, 0f, 0f };
                        break;

                    case "detail_map":
                        finalRm.ShaderProperties[0].RealConstants[i].Values = new float[] { 1.5f, 1.5f, 0f, 0f };
                        break;

                    case "albedo_color":
                        finalRm.ShaderProperties[0].RealConstants[i].Values = new float[] { 0.554902f, 0.5588236f, 0.5921569f, 1f };
                        break;

                    case "bump_map":
                        finalRm.ShaderProperties[0].RealConstants[i].Values = new float[] { 1f, 1f, 0f, 0f };
                        break;

                    case "bump_detail_map":
                        finalRm.ShaderProperties[0].RealConstants[i].Values = new float[] { 2f, 2f, 0f, 0f };
                        break;

                    case "diffuse_coefficient":
                        finalRm.ShaderProperties[0].RealConstants[i].Values = new float[] { 0.4f, 0.4f, 0.4f, 0.4f };
                        break;

                    case "specular_coefficient":
                        finalRm.ShaderProperties[0].RealConstants[i].Values = new float[] { 1f, 1f, 1f, 1f };
                        break;

                    case "roughness":
                        finalRm.ShaderProperties[0].RealConstants[i].Values = new float[] { 0.2f, 0.2f, 0.2f, 0.2f };
                        break;

                    case "analytical_specular_contribution":
                        finalRm.ShaderProperties[0].RealConstants[i].Values = new float[] { 0.2f, 0.2f, 0.2f, 0.2f };
                        break;

                    case "area_specular_contribution":
                        finalRm.ShaderProperties[0].RealConstants[i].Values = new float[] { 0.1f, 0.1f, 0.1f, 0.1f };
                        break;

                    case "environment_map_specular_contribution":
                        finalRm.ShaderProperties[0].RealConstants[i].Values = new float[] { 0.15f, 0.15f, 0.15f, 0.15f };
                        break;

                    case "specular_tint":
                        finalRm.ShaderProperties[0].RealConstants[i].Values = new float[] { 0.8431373f, 0.8470589f, 0.8117648f, 1f };
                        break;
                    }
                }
                break;
            }

            case @"levels\multi\snowbound\shaders\rock_cliffs" when finalRm is Shader:
            case @"levels\multi\snowbound\shaders\rock_rocky" when finalRm is Shader:
            case @"levels\multi\snowbound\shaders\rock_rocky_icy" when finalRm is Shader:
            {
                // Fixup bitmaps
                for (var i = 0; i < edRmt2.TextureParameterNames.Count; i++)
                {
                    switch (CacheContext.StringTable.GetString(edRmt2.TextureParameterNames[i].Name))
                    {
                    case "base_map":
                        try
                        {
                            finalRm.ShaderProperties[0].TextureConstants[i].Bitmap = ConvertTag(cacheStream, blamCacheStream, resourceStreams, ParseLegacyTag(@"levels\multi\snowbound\bitmaps\rock_horiz.bitmap")[0]);
                        }
                        catch { }
                        break;

                    case "detail_map":
                        try
                        {
                            finalRm.ShaderProperties[0].TextureConstants[i].Bitmap = ConvertTag(cacheStream, blamCacheStream, resourceStreams, ParseLegacyTag(@"levels\multi\snowbound\bitmaps\rock_granite_detail.bitmap")[0]);
                        }
                        catch { }
                        break;

                    case "detail_map2":
                        try
                        {
                            switch (blamTagName)
                            {
                            case @"levels\multi\snowbound\shaders\rock_rocky_icy":
                                finalRm.ShaderProperties[0].TextureConstants[i].Bitmap = ConvertTag(cacheStream, blamCacheStream, resourceStreams, ParseLegacyTag(@"levels\multi\snowbound\bitmaps\rock_icy_blend.bitmap")[0]);
                                break;

                            default:
                                finalRm.ShaderProperties[0].TextureConstants[i].Bitmap = ConvertTag(cacheStream, blamCacheStream, resourceStreams, ParseLegacyTag(@"levels\multi\snowbound\bitmaps\rock_cliff_dif.bitmap")[0]);
                                break;
                            }
                        }
                        catch { }
                        break;

                    case "bump_map":
                        try
                        {
                            finalRm.ShaderProperties[0].TextureConstants[i].Bitmap = ConvertTag(cacheStream, blamCacheStream, resourceStreams, ParseLegacyTag(@"levels\multi\snowbound\bitmaps\rock_horiz_bump.bitmap")[0]);
                        }
                        catch { }
                        break;

                    case "bump_detail_map":
                        try
                        {
                            finalRm.ShaderProperties[0].TextureConstants[i].Bitmap = ConvertTag(cacheStream, blamCacheStream, resourceStreams, ParseLegacyTag(@"levels\multi\snowbound\bitmaps\rock_granite_bump.bitmap")[0]);
                        }
                        catch { }
                        break;

                    case "height_map":
                        try
                        {
                            finalRm.ShaderProperties[0].TextureConstants[i].Bitmap = ConvertTag(cacheStream, blamCacheStream, resourceStreams, ParseLegacyTag(@"levels\multi\snowbound\bitmaps\rock_horiz_parallax.bitmap")[0]);
                        }
                        catch { }
                        break;

                    case "environment_map":
                        try
                        {
                            finalRm.ShaderProperties[0].TextureConstants[i].Bitmap = ConvertTag(cacheStream, blamCacheStream, resourceStreams, ParseLegacyTag(@"shaders\default_bitmaps\bitmaps\color_white.bitmap")[0]);
                        }
                        catch { }
                        break;
                    }
                }

                // Fixup arguments
                for (var i = 0; i < edRmt2.RealParameterNames.Count; i++)
                {
                    var templateArg = edRmt2.RealParameterNames[i];

                    switch (CacheContext.StringTable.GetString(templateArg.Name))
                    {
                    case "base_map":
                        switch (blamTagName)
                        {
                        case @"levels\multi\snowbound\shaders\rock_cliffs":
                            finalRm.ShaderProperties[0].RealConstants[i].Values = new float[] { 16f, 2f, 0f, 0.5f };
                            break;
                        }
                        break;

                    case "detail_map":
                        switch (blamTagName)
                        {
                        case @"levels\multi\snowbound\shaders\rock_cliffs":
                        case @"levels\multi\snowbound\shaders\rock_rocky":
                            finalRm.ShaderProperties[0].RealConstants[i].Values = new float[] { 320f, 20f, 0f, 0f };
                            break;
                        }
                        break;

                    case "detail_map2":
                        switch (blamTagName)
                        {
                        case @"levels\multi\snowbound\shaders\rock_cliffs":
                            finalRm.ShaderProperties[0].RealConstants[i].Values = new float[] { 1f, 1f, 0f, 0f };
                            break;
                        }
                        break;

                    case "bump_detail_map":
                        switch (blamTagName)
                        {
                        case @"levels\multi\snowbound\shaders\rock_cliffs":
                        case @"levels\multi\snowbound\shaders\rock_rocky":
                            finalRm.ShaderProperties[0].RealConstants[i].Values = new float[] { 320f, 20f, 0f, 0f };
                            break;
                        }
                        break;

                    case "diffuse_coefficient":
                        switch (blamTagName)
                        {
                        case @"levels\multi\snowbound\shaders\rock_rocky_icy":
                            finalRm.ShaderProperties[0].RealConstants[i].Values = new float[] { 1.2f, 1.2f, 1.2f, 1.2f };
                            break;
                        }
                        break;
                    }
                }
                break;
            }

            case @"levels\multi\snowbound\shaders\cov_metalplates_icy" when finalRm is Shader:
                // Fixup bitmaps
                for (var i = 0; i < edRmt2.TextureParameterNames.Count; i++)
                {
                    switch (CacheContext.StringTable.GetString(edRmt2.TextureParameterNames[i].Name))
                    {
                    case "detail_map":
                        try
                        {
                            finalRm.ShaderProperties[0].TextureConstants[i].Bitmap = CacheContext.GetTag <Bitmap>(@"levels\multi\snowbound\bitmaps\for_metal_greytech_icy4");
                        }
                        catch { }
                        break;

                    case "detail_map2":
                        try
                        {
                            finalRm.ShaderProperties[0].TextureConstants[i].Bitmap = CacheContext.GetTag <Bitmap>(@"levels\multi\snowbound\bitmaps\for_metal_greytech_icy3");
                        }
                        catch { }
                        break;
                    }
                }
                break;

            case @"levels\multi\snowbound\shaders\invis_col_glass" when finalRm is Shader:
                // Fixup arguments
                for (var i = 0; i < edRmt2.RealParameterNames.Count; i++)
                {
                    var templateArg = edRmt2.RealParameterNames[i];

                    switch (CacheContext.StringTable.GetString(templateArg.Name))
                    {
                    case "albedo_color":
                        finalRm.ShaderProperties[0].RealConstants[i].Values = new float[] { 0f, 0f, 0f, 0f };
                        break;
                    }
                }
                break;
            }

            return(finalRm);
        }
Ejemplo n.º 12
0
        private void MergeMultiplayerGlobals(Stream cacheStream, Stream blamCacheStream, Dictionary <ResourceLocation, Stream> resourceStreams, CachedTag edTag, CachedTag h3Tag)
        {
            var edDef = CacheContext.Deserialize <MultiplayerGlobals>(cacheStream, edTag);
            var h3Def = BlamCache.Deserialize <MultiplayerGlobals>(blamCacheStream, h3Tag);

            if (h3Def.Runtime == null || h3Def.Runtime.Count == 0)
            {
                return;
            }

            for (var i = 0; i < h3Def.Runtime[0].GeneralEvents.Count; i++)
            {
                var h3Event = h3Def.Runtime[0].GeneralEvents[i];

                if (h3Event.DisplayString == StringId.Invalid)
                {
                    continue;
                }

                var h3String = BlamCache.StringTable.GetString(h3Event.DisplayString);

                for (var j = 0; j < edDef.Runtime[0].GeneralEvents.Count; j++)
                {
                    var edEvent  = edDef.Runtime[0].GeneralEvents[j];
                    var edString = CacheContext.StringTable.GetString(edEvent.DisplayString);

                    if (edString == h3String)
                    {
                        MergeMultiplayerEvent(cacheStream, blamCacheStream, resourceStreams, edEvent, h3Event);
                    }
                }
            }

            for (var i = 0; i < h3Def.Runtime[0].FlavorEvents.Count; i++)
            {
                var h3Event = h3Def.Runtime[0].FlavorEvents[i];

                if (h3Event.DisplayString == StringId.Invalid)
                {
                    continue;
                }

                var h3String = BlamCache.StringTable.GetString(h3Event.DisplayString);

                for (var j = 0; j < edDef.Runtime[0].FlavorEvents.Count; j++)
                {
                    var edEvent  = edDef.Runtime[0].FlavorEvents[j];
                    var edString = CacheContext.StringTable.GetString(edEvent.DisplayString);

                    if (edString == h3String)
                    {
                        MergeMultiplayerEvent(cacheStream, blamCacheStream, resourceStreams, edEvent, h3Event);
                    }
                }
            }

            for (var i = 0; i < h3Def.Runtime[0].SlayerEvents.Count; i++)
            {
                var h3Event = h3Def.Runtime[0].SlayerEvents[i];

                if (h3Event.DisplayString == StringId.Invalid)
                {
                    continue;
                }

                var h3String = BlamCache.StringTable.GetString(h3Event.DisplayString);

                for (var j = 0; j < edDef.Runtime[0].SlayerEvents.Count; j++)
                {
                    var edEvent  = edDef.Runtime[0].SlayerEvents[j];
                    var edString = CacheContext.StringTable.GetString(edEvent.DisplayString);

                    if (edString == h3String)
                    {
                        MergeMultiplayerEvent(cacheStream, blamCacheStream, resourceStreams, edEvent, h3Event);
                    }
                }
            }

            for (var i = 0; i < h3Def.Runtime[0].CtfEvents.Count; i++)
            {
                var h3Event = h3Def.Runtime[0].CtfEvents[i];

                if (h3Event.DisplayString == StringId.Invalid)
                {
                    continue;
                }

                var h3String = BlamCache.StringTable.GetString(h3Event.DisplayString);

                for (var j = 0; j < edDef.Runtime[0].CtfEvents.Count; j++)
                {
                    var edEvent  = edDef.Runtime[0].CtfEvents[j];
                    var edString = CacheContext.StringTable.GetString(edEvent.DisplayString);

                    if (edString == h3String)
                    {
                        MergeMultiplayerEvent(cacheStream, blamCacheStream, resourceStreams, edEvent, h3Event);
                    }
                }
            }

            for (var i = 0; i < h3Def.Runtime[0].OddballEvents.Count; i++)
            {
                var h3Event = h3Def.Runtime[0].OddballEvents[i];

                if (h3Event.DisplayString == StringId.Invalid)
                {
                    continue;
                }

                var h3String = BlamCache.StringTable.GetString(h3Event.DisplayString);

                for (var j = 0; j < edDef.Runtime[0].OddballEvents.Count; j++)
                {
                    var edEvent  = edDef.Runtime[0].OddballEvents[j];
                    var edString = CacheContext.StringTable.GetString(edEvent.DisplayString);

                    if (edString == h3String)
                    {
                        MergeMultiplayerEvent(cacheStream, blamCacheStream, resourceStreams, edEvent, h3Event);
                    }
                }
            }

            for (var i = 0; i < h3Def.Runtime[0].KingOfTheHillEvents.Count; i++)
            {
                var h3Event = h3Def.Runtime[0].KingOfTheHillEvents[i];

                if (h3Event.DisplayString == StringId.Invalid)
                {
                    continue;
                }

                var h3String = BlamCache.StringTable.GetString(h3Event.DisplayString);

                for (var j = 0; j < edDef.Runtime[0].KingOfTheHillEvents.Count; j++)
                {
                    var edEvent  = edDef.Runtime[0].KingOfTheHillEvents[j];
                    var edString = CacheContext.StringTable.GetString(edEvent.DisplayString);

                    if (edString == h3String)
                    {
                        MergeMultiplayerEvent(cacheStream, blamCacheStream, resourceStreams, edEvent, h3Event);
                    }
                }
            }

            for (var i = 0; i < h3Def.Runtime[0].VipEvents.Count; i++)
            {
                var h3Event = h3Def.Runtime[0].VipEvents[i];

                if (h3Event.DisplayString == StringId.Invalid)
                {
                    continue;
                }

                var h3String = BlamCache.StringTable.GetString(h3Event.DisplayString);

                for (var j = 0; j < edDef.Runtime[0].VipEvents.Count; j++)
                {
                    var edEvent  = edDef.Runtime[0].VipEvents[j];
                    var edString = CacheContext.StringTable.GetString(edEvent.DisplayString);

                    if (edString == h3String)
                    {
                        MergeMultiplayerEvent(cacheStream, blamCacheStream, resourceStreams, edEvent, h3Event);
                    }
                }
            }

            for (var i = 0; i < h3Def.Runtime[0].JuggernautEvents.Count; i++)
            {
                var h3Event = h3Def.Runtime[0].JuggernautEvents[i];

                if (h3Event.DisplayString == StringId.Invalid)
                {
                    continue;
                }

                var h3String = BlamCache.StringTable.GetString(h3Event.DisplayString);

                for (var j = 0; j < edDef.Runtime[0].JuggernautEvents.Count; j++)
                {
                    var edEvent  = edDef.Runtime[0].JuggernautEvents[j];
                    var edString = CacheContext.StringTable.GetString(edEvent.DisplayString);

                    if (edString == h3String)
                    {
                        MergeMultiplayerEvent(cacheStream, blamCacheStream, resourceStreams, edEvent, h3Event);
                    }
                }
            }

            for (var i = 0; i < h3Def.Runtime[0].TerritoriesEvents.Count; i++)
            {
                var h3Event = h3Def.Runtime[0].TerritoriesEvents[i];

                if (h3Event.DisplayString == StringId.Invalid)
                {
                    continue;
                }

                var h3String = BlamCache.StringTable.GetString(h3Event.DisplayString);

                for (var j = 0; j < edDef.Runtime[0].TerritoriesEvents.Count; j++)
                {
                    var edEvent  = edDef.Runtime[0].TerritoriesEvents[j];
                    var edString = CacheContext.StringTable.GetString(edEvent.DisplayString);

                    if (edString == h3String)
                    {
                        MergeMultiplayerEvent(cacheStream, blamCacheStream, resourceStreams, edEvent, h3Event);
                    }
                }
            }

            for (var i = 0; i < h3Def.Runtime[0].AssaultEvents.Count; i++)
            {
                var h3Event = h3Def.Runtime[0].AssaultEvents[i];

                if (h3Event.DisplayString == StringId.Invalid)
                {
                    continue;
                }

                var h3String = BlamCache.StringTable.GetString(h3Event.DisplayString);

                for (var j = 0; j < edDef.Runtime[0].AssaultEvents.Count; j++)
                {
                    var edEvent  = edDef.Runtime[0].AssaultEvents[j];
                    var edString = CacheContext.StringTable.GetString(edEvent.DisplayString);

                    if (edString == h3String)
                    {
                        MergeMultiplayerEvent(cacheStream, blamCacheStream, resourceStreams, edEvent, h3Event);
                    }
                }
            }

            for (var i = 0; i < h3Def.Runtime[0].InfectionEvents.Count; i++)
            {
                var h3Event = h3Def.Runtime[0].InfectionEvents[i];

                if (h3Event.DisplayString == StringId.Invalid)
                {
                    continue;
                }

                var h3String = BlamCache.StringTable.GetString(h3Event.DisplayString);

                for (var j = 0; j < edDef.Runtime[0].InfectionEvents.Count; j++)
                {
                    var edEvent  = edDef.Runtime[0].InfectionEvents[j];
                    var edString = CacheContext.StringTable.GetString(edEvent.DisplayString);

                    if (edString == h3String)
                    {
                        MergeMultiplayerEvent(cacheStream, blamCacheStream, resourceStreams, edEvent, h3Event);
                    }
                }
            }

            CacheContext.Serialize(cacheStream, edTag, edDef);
        }