Example #1
0
        public static void ConvertIndexBuffer(CacheVersion inVersion, CacheVersion outVersion, IndexBufferDefinition indexBuffer)
        {
            using (var outputStream = new MemoryStream())
                using (var inputStream = new MemoryStream(indexBuffer.Data.Data))
                {
                    var inIndexStream  = new IndexBufferStream(inputStream, CacheVersionDetection.IsLittleEndian(inVersion) ? EndianFormat.LittleEndian : EndianFormat.BigEndian);
                    var outIndexStream = new IndexBufferStream(outputStream, CacheVersionDetection.IsLittleEndian(outVersion) ? EndianFormat.LittleEndian : EndianFormat.BigEndian);
                    var indexCount     = indexBuffer.Data.Data.Length / 2;
                    for (var j = 0; j < indexCount; j++)
                    {
                        outIndexStream.WriteIndex(inIndexStream.ReadIndex());
                    }

                    indexBuffer.Data.Data = outputStream.ToArray();
                }
        }
Example #2
0
        public static byte[] ConvertHkpMoppData(CacheVersion sourceVersion, CacheVersion destVersion, byte[] data)
        {
            if (data == null || data.Length == 0)
            {
                return(data);
            }

            byte[] result;
            using (var inputReader = new EndianReader(new MemoryStream(data), CacheVersionDetection.IsLittleEndian(sourceVersion) ? EndianFormat.LittleEndian : EndianFormat.BigEndian))
                using (var outputStream = new MemoryStream())
                    using (var outputWriter = new EndianWriter(outputStream, CacheVersionDetection.IsLittleEndian(destVersion) ? EndianFormat.LittleEndian : EndianFormat.BigEndian))
                    {
                        var dataContext  = new DataSerializationContext(inputReader, outputWriter);
                        var deserializer = new TagDeserializer(sourceVersion);
                        var serializer   = new TagSerializer(destVersion);
                        while (!inputReader.EOF)
                        {
                            var         header      = deserializer.Deserialize <HkpMoppCode>(dataContext);
                            var         dataSize    = header.ArrayBase.GetCapacity();
                            var         alignedSize = dataSize + 0xf & ~0xf;
                            var         nextOffset  = inputReader.Position + alignedSize;
                            List <byte> moppCodes   = new List <byte>();
                            for (int j = 0; j < header.ArrayBase.GetCapacity(); j++)
                            {
                                moppCodes.Add(inputReader.ReadByte());
                            }
                            inputReader.SeekTo(nextOffset);

                            moppCodes = ConvertMoppCodes(sourceVersion, destVersion, moppCodes);

                            serializer.Serialize(dataContext, header);
                            for (int j = 0; j < moppCodes.Count; j++)
                            {
                                outputWriter.Write(moppCodes[j]);
                            }

                            StreamUtil.Align(outputStream, 0x10);
                        }
                        result = outputStream.ToArray();
                    }
            return(result);
        }
        public List <ModelAnimationGraph.ResourceGroup> ConvertModelAnimationGraphResourceGroups(Stream cacheStream, Stream blamCacheStream, Dictionary <ResourceLocation, Stream> resourceStreams, List <ModelAnimationGraph.ResourceGroup> resourceGroups)
        {
            var resourceDefinitions = new List <ModelAnimationTagResource>();

            foreach (var group in resourceGroups)
            {
                var resourceDefinition = BlamCache.ResourceCache.GetModelAnimationTagResource(group.ResourceReference);

                if (resourceDefinition == null)
                {
                    group.ResourceReference = null;
                    continue;
                }

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

                    using (var sourceStream = new MemoryStream(animationData))
                        using (var sourceReader = new EndianReader(sourceStream, CacheVersionDetection.IsLittleEndian(BlamCache.Version) ? EndianFormat.LittleEndian : EndianFormat.BigEndian))
                            using (var destStream = new MemoryStream())
                                using (var destWriter = new EndianWriter(destStream, CacheVersionDetection.IsLittleEndian(CacheContext.Version) ? EndianFormat.LittleEndian : EndianFormat.BigEndian))
                                {
                                    var dataContext = new DataSerializationContext(sourceReader, destWriter);

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

                                    if (member.BaseHeader != ModelAnimationTagResource.GroupMemberHeaderType.Overlay)
                                    {
                                        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);

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

                                        sourceStream.Position = Format1.DataStart;
                                        destStream.Position   = sourceStream.Position;
                                        for (int i = 0; i < codec.PositionNodeCount; i++)
                                        {
                                            CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <ModelAnimationTagResource.GroupMember.PositionFrame>(dataContext));
                                        }

                                        sourceStream.Position = Format1.ScaleFramesOffset;
                                        destStream.Position   = sourceStream.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
                                    sourceStream.Position = member.OverlayOffset;
                                    destStream.Position   = 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));
                                            }
                                        }

                                        sourceStream.Position = member.OverlayOffset + header.DataStart;
                                        destStream.Position   = sourceStream.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));
                                            }
                                        }

                                        sourceStream.Position = member.OverlayOffset + header.ScaleFramesOffset;
                                        destStream.Position   = sourceStream.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);
                                        }

                                        sourceStream.Position = member.OverlayOffset + overlay.RotationKeyframesOffset;
                                        destStream.Position   = sourceStream.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));
                                                }
                                            }
                                        }

                                        sourceStream.Position = member.OverlayOffset + overlay.PositionKeyframesOffset;
                                        destStream.Position   = sourceStream.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));
                                                }
                                            }
                                        }

                                        sourceStream.Position = member.OverlayOffset + overlay.ScaleKeyframesOffset;
                                        destStream.Position   = sourceStream.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));
                                                }
                                            }
                                        }

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

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

                                        sourceStream.Position = member.OverlayOffset + overlay.ScaleFramesOffset;
                                        destStream.Position   = sourceStream.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));
                                            }
                                        }

                                        sourceStream.Position = member.OverlayOffset + Format8.PositionFramesOffset;
                                        destStream.Position   = sourceStream.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));
                                            }
                                        }

                                        sourceStream.Position = member.OverlayOffset + Format8.ScaleFramesOffset;
                                        destStream.Position   = sourceStream.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.None_:
                                        // empty data, copy buffer and skip
                                        member.AnimationData.Data = sourceStream.ToArray();
                                        continue;

                                    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

                                    sourceStream.Position = member.OverlayOffset + member.FlagsOffset;
                                    destStream.Position   = sourceStream.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;
                                    }

                                    // set new data
                                    member.AnimationData.Data = destStream.ToArray();
                                }
                }

                group.ResourceReference = CacheContext.ResourceCache.CreateModelAnimationGraphResource(resourceDefinition);
            }

            return(resourceGroups);
        }