예제 #1
0
        public override void SerializeBlock(SerializerObject s)
        {
            // Serialize data
            Height            = s.Serialize <byte>(Height, name: nameof(Height));
            Width             = s.Serialize <byte>(Width, name: nameof(Width));
            UnkData0          = s.SerializeArray <byte>(UnkData0, 4, name: nameof(UnkData0));
            PaletteCount      = s.Serialize <byte>(PaletteCount, name: nameof(PaletteCount));
            PaletteBlockCount = s.Serialize <byte>(PaletteBlockCount, name: nameof(PaletteBlockCount));
            PaletteOffset     = s.Serialize <uint>(PaletteOffset, name: nameof(PaletteOffset));
            TileDataOffset    = s.Serialize <uint>(TileDataOffset, name: nameof(TileDataOffset));

            var basePtr = s.CurrentPointer;

            s.Goto(basePtr + TileDataOffset);
            TileSet    = s.SerializeArray <byte>(TileSet, Width * Height * 0x10, name: nameof(TileSet));
            PalIndices = s.SerializeArray <byte>(PalIndices, Width * Height, name: nameof(PalIndices));

            s.Goto(basePtr + PaletteOffset);
            if (Palette == null)
            {
                Palette = new RGBA5551Color[PaletteBlockCount][];
            }
            for (int i = 0; i < PaletteBlockCount; i++)
            {
                Palette[i] = s.SerializeObjectArray <RGBA5551Color>(Palette[i], PaletteCount * 4, name: $"{nameof(Palette)}[{i}]");
            }
        }
예제 #2
0
        protected override void InitMemoryLoading(SerializerObject s, Pointer offset)
        {
            s.Goto(offset);
            GameMemoryData.Update(s);

            s.Goto(offset);
            GlobalData.SetPointers(s);
        }
예제 #3
0
 public override void SerializeImpl(SerializerObject s)
 {
     s.Goto(Offset + 0x1C);
     Name = s.SerializeString(Name, name: nameof(Name));
     s.Goto(Offset + 0x2C);
     HuffTableOffset = s.Serialize <ushort>(HuffTableOffset, name: nameof(HuffTableOffset));
     HuffTableLength = s.Serialize <ushort>(HuffTableLength, name: nameof(HuffTableLength));
     s.DoAt(Offset + HuffTableOffset, () => {
         HuffTable = s.SerializeObjectArray <HuffTableEntry>(HuffTable, HuffTableLength / 6, name: nameof(HuffTable));
     });
     NumTables = s.Serialize <ushort>(NumTables, name: nameof(NumTables));
     Tables    = s.SerializeObjectArray <Table>(Tables, NumTables, onPreSerialize: t => t.HuffTable = HuffTable, name: nameof(Tables));
 }
예제 #4
0
        public override void SerializeBlock(SerializerObject s)
        {
            if (s.GameSettings.EngineVersion >= EngineVersion.GBA_SplinterCell)
            {
                MatrixOffsets = s.SerializeArray <ushort>(MatrixOffsets, FrameCount, name: nameof(MatrixOffsets));
                s.Align(4);
                if (Matrices == null)
                {
                    Matrices = new GBA_AffineMatrix[FrameCount][];
                }

                for (int i = 0; i < Matrices.Length; i++)
                {
                    ushort offset = MatrixOffsets[i];
                    uint   count  = (uint)Math.Min((BlockSize - offset) / 8, 32);
                    s.DoAt(Offset + offset, () => {
                        Matrices[i] = s.SerializeObjectArray <GBA_AffineMatrix>(Matrices[i], count, name: $"{nameof(Matrices)}[{i}]");
                    });
                }
                s.Goto(Offset + BlockSize);
            }
            else
            {
                if (Matrices == null)
                {
                    Matrices = new GBA_AffineMatrix[1][];
                }
                Matrices[0] = s.SerializeObjectArray <GBA_AffineMatrix>(Matrices[0], BlockSize / 8, name: $"{nameof(Matrices)}[{0}]");
            }
        }
예제 #5
0
        public override void SerializeBlock(SerializerObject s)
        {
            UShort_00            = s.Serialize <ushort>(UShort_00, name: nameof(UShort_00));
            PatternOffsetsOffset = s.Serialize <ushort>(PatternOffsetsOffset, name: nameof(PatternOffsetsOffset));
            Byte_04      = s.Serialize <byte>(Byte_04, name: nameof(Byte_04));
            PatternCount = s.Serialize <byte>(PatternCount, name: nameof(PatternCount));
            UInt_06      = s.Serialize <uint>(UInt_06, name: nameof(UInt_06));

            s.DoAt(BlockStartPointer + PatternOffsetsOffset, () => {
                PatternOffsets = s.SerializeArray <ushort>(PatternOffsets, PatternCount, name: nameof(PatternOffsets));
            });
            if (Patterns == null)
            {
                Patterns = new Pattern[PatternCount];
            }
            for (int i = 0; i < PatternCount; i++)
            {
                Patterns[i] = s.DoAt(BlockStartPointer + PatternOffsets[i], () => {
                    return(s.SerializeObject <Pattern>(Patterns[i], name: $"{nameof(Patterns)}[{i}]"));
                });
            }
            if (Patterns.Length > 0)
            {
                s.Goto(Patterns[Patterns.Length - 1].Offset + Patterns[Patterns.Length - 1].Size);
            }
        }
        public override void SerializeImpl(SerializerObject s)
        {
            Offsets   = s.SerializePointerArray <Array <ushort> >(Offsets, 6, resolve: true, onPreSerialize: x => x.Length = 690, name: nameof(Offsets));
            LocTables = s.SerializePointerArray(LocTables, 6, name: nameof(LocTables));
            if (Localization == null)
            {
                Localization = new string[Offsets.Length][];
                for (int i = 0; i < Localization.Length; i++)
                {
                    Localization[i] = new string[Offsets[i].Value.Length];
                    s.DoAt(LocTables[i], () => {
                        s.DoEncoded(new RHREncoder(), () => {
                            Pointer basePtr = s.CurrentPointer;
                            for (int j = 0; j < Offsets[i].Value.Length; j++)
                            {
                                s.DoAt(basePtr + Offsets[i].Value.Value[j], () => {
                                    Localization[i][j] = s.SerializeString(Localization[i][j], encoding: Encoding.GetEncoding(1252), name: $"{nameof(Localization)}[{i}][{j}]");
                                });
                            }

                            // Go to end
                            s.Goto(s.CurrentPointer + s.CurrentLength);
                        });
                    });
                }
            }
        }
예제 #7
0
        public override void SerializeBlock(SerializerObject s)
        {
            if (s.GameSettings.GBA_IsMilan && s.GameSettings.EngineVersion != EngineVersion.GBA_TomClancysRainbowSixRogueSpear)
            {
                // Copied from function at 0x080087e4 in The Mummy (US)

                // Serialize header
                s.DoAt(ShanghaiOffsetTable.GetPointer(0), () =>
                {
                    Milan_Ushort_00 = s.Serialize <ushort>(Milan_Ushort_00, name: nameof(Milan_Ushort_00));
                    Milan_Ushort_02 = s.Serialize <ushort>(Milan_Ushort_02, name: nameof(Milan_Ushort_02));
                });

                // Go to palette data
                s.Goto(ShanghaiOffsetTable.GetPointer(1));

                if (Milan_Palettes == null)
                {
                    Milan_Palettes = new Dictionary <int, RGBA5551Color[]>();

                    if (Milan_Ushort_00 == 0)
                    {
                        var palIndex = 0;

                        do
                        {
                            if (BitHelpers.ExtractBits(Milan_Ushort_02, 1, palIndex) == 1)
                            {
                                var pal = s.SerializeObjectArray <RGBA5551Color>(default, 0x10, name: $"Palette[{palIndex}]");
예제 #8
0
        public override void SerializeImpl(SerializerObject s)
        {
            bool determineTileSize = false;

            if (Count == 0)
            {
                Headers = s.SerializeObjectArray <Header>(Headers, 2, name: nameof(Headers));

                if (Headers[0].TileOffset % 4 != 0 || Headers[0].ExtraBytes >= 4 || (Headers[0].TileOffset / 4) < 2)
                {
                    return;                                                                                                 // Invalid
                }
                Count             = (uint)(Headers[0].TileOffset / 4) - 1;
                determineTileSize = true;
                s.Goto(Offset);
            }
            Headers = s.SerializeObjectArray <Header>(Headers, Count + 1, name: nameof(Headers));
            if (TileData == null)
            {
                TileData = new byte[Count][];
                for (int i = 0; i < Count; i++)
                {
                    s.DoAt(Offset + Headers[i].TileOffset, () => {
                        int length = (Headers[i + 1].TileOffset - Headers[i].TileOffset - Headers[i].ExtraBytes);

                        if (determineTileSize && i == 0)
                        {
                            if (Math.Sqrt(length * 2) % 1 == 0)
                            {
                                int val = Mathf.RoundToInt(Mathf.Sqrt(length * 2));
                                if ((val != 0) && ((val & (val - 1)) == 0))
                                {
                                    TileSize = (uint)val;
                                }
                            }
                        }

                        if (length != TileSize * TileSize / 2)
                        {
                            s.DoEncoded(new LZSSEncoder((uint)length, hasHeader: false), () => {
                                TileData[i] = s.SerializeArray <byte>(TileData[i], s.CurrentLength, name: $"{nameof(TileData)}[{i}]");
                            });
                        }
                        else
                        {
                            TileData[i] = s.SerializeArray <byte>(TileData[i], length, name: $"{nameof(TileData)}[{i}]");
                        }
                        if (determineTileSize && i == 0)
                        {
                            int len = TileData[i].Length;
                            if (Math.Sqrt(len * 2) % 1 == 0)
                            {
                                TileSize = (uint)Mathf.RoundToInt(Mathf.Sqrt(len * 2));
                            }
                        }
                    });
                }
            }
        }
예제 #9
0
 protected void SwitchSerializer(SerializerObject s)
 {
     if (s != CurrentSerializer)
     {
         s.Goto(CurrentSerializer.CurrentPointer);
         CurrentSerializer = s;
     }
 }
예제 #10
0
        /// <summary>
        /// Gets the file bytes based on name
        /// </summary>
        /// <param name="s">The serializer object</param>
        /// <param name="fileName">The file name</param>
        /// <returns>The file bytes</returns>
        public async UniTask <byte[]> GetFileBytesAsync(SerializerObject s, string fileName)
        {
            // Attempt to find the file
            var file = GetFile(fileName);

            s.Goto(BaseOffset + file.FileOffset);

            await s.FillCacheForRead((int)file.FileSize);

            // Read the bytes
            byte[] buffer = s.SerializeArray <byte>(default, file.FileSize, name: nameof(buffer));
예제 #11
0
        public override void SerializeImpl(SerializerObject s)
        {
            // Header
            SceneBlockLength = s.Serialize <uint>(SceneBlockLength, name: nameof(SceneBlockLength));
            Scene            = s.SerializeObject <GBA_Scene>(Scene, onPreSerialize: sc => sc.IsGCNBlock = true, name: nameof(Scene));

            // Data
            s.Goto(Offset + SceneBlockLength);
            PlayFieldBlockLength = s.Serialize <uint>(PlayFieldBlockLength, name: nameof(PlayFieldBlockLength));
            PlayField            = s.SerializeObject <GBA_PlayField>(PlayField, onPreSerialize: pf => pf.IsGCNBlock = true, name: nameof(PlayField));
        }
예제 #12
0
        public override void SerializeBlock(SerializerObject s)
        {
            Flags = s.Serialize <byte>(Flags, name: nameof(Flags));

            if (!s.GameSettings.GBA_IsMilan)
            {
                Byte_01             = s.Serialize <byte>(Byte_01, name: nameof(Byte_01));
                AffineMatricesIndex = s.Serialize <byte>((byte)AffineMatricesIndex, name: nameof(AffineMatricesIndex));
                Byte_03             = s.Serialize <byte>(Byte_03, name: nameof(Byte_03));
                FrameCount          = (byte)BitHelpers.ExtractBits(Byte_03, 6, 0);

                LayersPerFrame = s.SerializeArray <byte>(LayersPerFrame, FrameCount, name: nameof(LayersPerFrame));

                s.Align();

                if (Layers == null)
                {
                    Layers = new GBA_AnimationChannel[FrameCount][];
                }

                for (int i = 0; i < FrameCount; i++)
                {
                    Layers[i] = s.SerializeObjectArray <GBA_AnimationChannel>(Layers[i], LayersPerFrame[i], name: $"{nameof(Layers)}[{i}]");
                }
            }
            else
            {
                FrameCount          = s.Serialize <byte>(FrameCount, name: nameof(FrameCount));
                Milan_Ushort_02     = s.Serialize <ushort>(Milan_Ushort_02, name: nameof(Milan_Ushort_02));
                AffineMatricesIndex = s.Serialize <ushort>(AffineMatricesIndex, name: nameof(AffineMatricesIndex));
                Milan_Int_06        = s.Serialize <int>(Milan_Int_06, name: nameof(Milan_Int_06));

                var offsetBase = s.CurrentPointer;

                Milan_LayerOffsets = s.SerializeArray <ushort>(Milan_LayerOffsets, FrameCount + 1, name: nameof(Milan_LayerOffsets)); // +1 since last offset is the end

                if (Layers == null)
                {
                    Layers = new GBA_AnimationChannel[FrameCount][];
                }

                for (int i = 0; i < FrameCount; i++)
                {
                    Layers[i] = s.DoAt(offsetBase + Milan_LayerOffsets[i], () => s.SerializeObjectArray <GBA_AnimationChannel>(Layers[i], (Milan_LayerOffsets[i + 1] - Milan_LayerOffsets[i]) / 6, name: $"{nameof(Layers)}[{i}]"));
                }

                s.Goto(offsetBase + Milan_LayerOffsets.LastOrDefault());
            }
        }
예제 #13
0
        public override void SerializeBlock(SerializerObject s)
        {
            var blockOffset = s.CurrentPointer;

            // Serialize data (always little endian)
            s.DoEndian(R1Engine.Serialize.BinaryFile.Endian.Little, () =>
            {
                // Parse data
                GameObjectsCount     = s.Serialize <ushort>(GameObjectsCount, name: nameof(GameObjectsCount));
                GameObjectsOffset    = s.Serialize <ushort>(GameObjectsOffset, name: nameof(GameObjectsOffset));
                KnotsHeight          = s.Serialize <byte>(KnotsHeight, name: nameof(KnotsHeight));
                KnotsWidth           = s.Serialize <byte>(KnotsWidth, name: nameof(KnotsWidth));
                KnotsOffset          = s.Serialize <ushort>(KnotsOffset, name: nameof(KnotsOffset));
                Height               = s.Serialize <ushort>(Height, name: nameof(Height));
                Width                = s.Serialize <ushort>(Width, name: nameof(Width));
                Timeout              = s.Serialize <byte>(Timeout, name: nameof(Timeout));
                Index_PlayField      = s.Serialize <byte>(Index_PlayField, name: nameof(Index_PlayField));
                IndexMin_ActorModels = s.Serialize <byte>(IndexMin_ActorModels, name: nameof(IndexMin_ActorModels));
                IndexMax_ActorModels = s.Serialize <byte>(IndexMax_ActorModels, name: nameof(IndexMax_ActorModels));
                ObjPalette           = s.SerializeObjectArray <RGBA5551Color>(ObjPalette, 8 * 4, name: nameof(ObjPalette));
                TilePalette          = s.SerializeObjectArray <RGBA5551Color>(TilePalette, 8 * 4, name: nameof(TilePalette));
                MainActor_0          = s.Serialize <ushort>(MainActor_0, name: nameof(MainActor_0));
                MainActor_1          = s.Serialize <ushort>(MainActor_1, name: nameof(MainActor_1));
                MainActor_2          = s.Serialize <ushort>(MainActor_2, name: nameof(MainActor_2));
                Index_SoundBank      = s.Serialize <byte>(Index_SoundBank, name: nameof(Index_SoundBank));

                // TODO: Parse data (UnkActorStructs?)
                UnknownData = s.SerializeArray <byte>(UnknownData, (blockOffset + GameObjectsOffset).AbsoluteOffset - s.CurrentPointer.AbsoluteOffset, name: nameof(UnknownData));

                // Parse from pointers
                GameObjects = s.DoAt(blockOffset + GameObjectsOffset, () => s.SerializeObjectArray <GBC_GameObject>(GameObjects, GameObjectsCount, name: nameof(GameObjects)));
                Knots       = s.DoAt(blockOffset + KnotsOffset, () => s.SerializeObjectArray <GBC_Knot>(Knots, KnotsHeight * KnotsWidth, name: nameof(Knots)));
                s.Goto(Knots.Last().Offset + Knots.Last().ActorsCount * 2 + 1); // Go to end of the block
            });

            // Parse data from pointers
            PlayField = s.DoAt(DependencyTable.GetPointer(Index_PlayField - 1), () => s.SerializeObject <GBC_PlayField>(PlayField, name: nameof(PlayField)));
            SoundBank = s.DoAt(DependencyTable.GetPointer(Index_SoundBank - 1), () => s.SerializeObject <GBC_SoundBank>(SoundBank, name: nameof(SoundBank)));

            // Parse actor models
            foreach (var actor in GameObjects.Where(x => x.Index_ActorModel > 1))
            {
                actor.ActorModel = s.DoAt(DependencyTable.GetPointer(actor.Index_ActorModel - 1), () => s.SerializeObject <GBC_ActorModelBlock>(actor.ActorModel, name: $"{nameof(actor.ActorModel)}[{actor.Index_ActorModel}]"));
            }
        }
        public IEnumerable <Texture2D> GetAnimationFrames(Context context, GBAIsometric_RHR_AnimSet animSet, GBAIsometric_RHR_Animation anim, Dictionary <ushort, byte[]> decompressedDictionary, RGBA5551Color[] palette)
        {
            SerializerObject s = context.Deserializer;

            var startFrame = anim.StartFrameIndex;
            var frameCount = anim.FrameCount;

            Color[] pal = Util.ConvertGBAPalette(palette);

            for (int f = 0; f < frameCount; f++)
            {
                var frame = animSet.Frames[startFrame + f];

                Texture2D tex = TextureHelpers.CreateTexture2D(animSet.Width * CellSize, animSet.Height * CellSize, clear: true);

                if (frame.PatternIndex == 0xFFFF || frame.TileIndicesIndex == 0xFFFF)
                {
                    // Empty frame
                }
                else
                {
                    var patIndex = frame.PatternIndex;

                    int curTile = frame.TileIndicesIndex;

                    for (int p = 0; p < animSet.Patterns[patIndex].Length; p++)
                    {
                        var pattern = animSet.Patterns[patIndex][p];
                        for (int y = 0; y < pattern.Height; y++)
                        {
                            for (int x = 0; x < pattern.Width; x++)
                            {
                                int    actualX   = x + pattern.XPosition;
                                int    actualY   = y + pattern.YPosition;
                                ushort tileIndex = animSet.TileIndices[curTile];

                                if (!decompressedDictionary.ContainsKey(tileIndex))
                                {
                                    s.Goto(animSet.GraphicsDataPointer.Value.CompressedDataPointer);

                                    s.DoEncoded(new RHR_SpriteEncoder(animSet.Is8Bit,
                                                                      animSet.GraphicsDataPointer.Value.CompressionLookupBuffer,
                                                                      animSet.GraphicsDataPointer.Value.CompressedDataPointer,
                                                                      tileIndex), () => {
                                        decompressedDictionary[tileIndex] = s.SerializeArray <byte>(default, s.CurrentLength, name: $"{animSet.Name}:Tiles[{curTile}]:{tileIndex}");
예제 #15
0
        public override void SerializeImpl(SerializerObject s)
        {
            if (s.GameSettings.EngineVersion == EngineVersion.GBC_R1)
            {
                GBC_Header      = s.SerializeObject <GBC_BlockHeader>(GBC_Header, name: nameof(GBC_Header));
                GBC_DataLength  = s.Serialize <ushort>(GBC_DataLength, name: nameof(GBC_DataLength));
                GBC_DataPointer = s.SerializeObject <GBC_Pointer>(GBC_DataPointer, onPreSerialize: x => x.HasMemoryBankValue = false, name: nameof(GBC_DataPointer));
            }
            else
            {
                LUDI_Header = s.SerializeObject <LUDI_BlockIdentifier>(LUDI_Header, name: nameof(LUDI_Header));
            }

            DependencyTable = s.SerializeObject <GBC_DependencyTable>(DependencyTable, name: nameof(DependencyTable));
            s.Goto(BlockStartPointer);
            SerializeBlock(s);

            if (s.GameSettings.EngineVersion == EngineVersion.GBC_R1_Palm || s.GameSettings.EngineVersion == EngineVersion.GBC_R1_PocketPC)
            {
                s.Align(baseOffset: BlockStartPointer);
            }
            CheckBlockSize(s);
        }
예제 #16
0
        public override void SerializeImpl(SerializerObject s)
        {
            Length = s.Serialize <byte>(Length, name: nameof(Length));
            if (Length == 0)
            {
                return;
            }
            ExtendedAttributeRecord = s.Serialize <byte>(ExtendedAttributeRecord, name: nameof(ExtendedAttributeRecord));

            ExtentLBA      = s.Serialize <uint>(ExtentLBA, name: nameof(ExtentLBA));
            BigEndianValue = s.SerializeArray <byte>(BigEndianValue, 4, name: nameof(BigEndianValue));

            ExtentSize     = s.Serialize <uint>(ExtentSize, name: nameof(ExtentSize));
            BigEndianValue = s.SerializeArray <byte>(BigEndianValue, 4, name: nameof(BigEndianValue));

            RecordingDateTime      = s.SerializeArray <byte>(RecordingDateTime, 7, name: nameof(RecordingDateTime));
            FileFlags              = s.Serialize <RecordFileFlags>(FileFlags, name: nameof(FileFlags));
            InterleaveFileUnitSize = s.Serialize <byte>(InterleaveFileUnitSize, name: nameof(InterleaveFileUnitSize));
            InterleaveFileGapSize  = s.Serialize <byte>(InterleaveFileGapSize, name: nameof(InterleaveFileGapSize));

            VolumeSequenceNumber = s.Serialize <ushort>(VolumeSequenceNumber, name: nameof(VolumeSequenceNumber));
            BigEndianValue       = s.SerializeArray <byte>(BigEndianValue, 2, name: nameof(BigEndianValue));

            FileIdentifierLength = s.Serialize <byte>(FileIdentifierLength, name: nameof(FileIdentifierLength));
            FileIdentifier       = s.SerializeString(FileIdentifier, length: FileIdentifierLength, name: nameof(FileIdentifier));

            if (s.CurrentPointer - Offset < Length && FileIdentifierLength % 2 != 0)
            {
                Padding = s.Serialize <byte>(Padding, name: nameof(Padding));
            }
            if (s.CurrentPointer - Offset < Length)
            {
                SystemUse = s.SerializeArray <byte>(SystemUse, Length - (s.CurrentPointer - Offset), name: nameof(SystemUse));
            }

            s.Goto(Offset + Length);
        }
예제 #17
0
 public override void SerializeBlock(SerializerObject s)
 {
     // Serialize data
     if (s.GameSettings.EngineVersion == EngineVersion.GBC_R1_PocketPC)
     {
         if (PresetTilesCount.HasValue)
         {
             TilesCount = PresetTilesCount.Value;
         }
         else
         {
             TilesCount = s.Serialize <uint>(TilesCount, name: nameof(TilesCount));
         }
         TileDataPocketPC = s.SerializeObjectArray <BGR565Color>(TileDataPocketPC, TilesCount * 8 * 8, name: nameof(TileDataPocketPC));
     }
     else if (s.GameSettings.EngineVersion == EngineVersion.GBC_R1_Palm)
     {
         bool greyScale = s.GameSettings.GameModeSelection == GameModeSelection.RaymanGBCPalmOSGreyscale || s.GameSettings.GameModeSelection == GameModeSelection.RaymanGBCPalmOSGreyscaleDemo;
         TilesCount = s.Serialize <uint>(TilesCount, name: nameof(TilesCount));
         TileData   = s.SerializeArray <byte>(TileData, TilesCount * (greyScale ? 0x20 : 0x40), name: nameof(TileData));
     }
     else
     {
         PaletteCount   = s.Serialize <byte>(PaletteCount, name: nameof(PaletteCount));
         PaletteOffset  = s.Serialize <ushort>(PaletteOffset, name: nameof(PaletteOffset));
         TileDataOffset = s.Serialize <ushort>(TileDataOffset, name: nameof(TileDataOffset));
         TilesCount     = s.Serialize <UInt24>((UInt24)TilesCount, name: nameof(TilesCount));
         s.DoAt(BlockStartPointer + PaletteOffset, () => {
             Palette = s.SerializeObjectArray <RGBA5551Color>(Palette, PaletteCount * 4, name: nameof(Palette));
         });
         s.DoAt(BlockStartPointer + TileDataOffset, () => {
             TileData = s.SerializeArray <byte>(TileData, TilesCount * 0x10, name: nameof(TileData));
         });
         // Go to end of block
         s.Goto(BlockStartPointer + TileDataOffset + TilesCount * 0x10);
     }
 }
예제 #18
0
        public override void SerializeBlock(SerializerObject s)
        {
            var basePointer = s.CurrentPointer;

            if (TileLayerDatas == null)
            {
                TileLayerDatas = new GBAVV_TileLayerData[MapData.MapLayers.Length];
            }

            for (int i = 0; i < TileLayerDatas.Length; i++)
            {
                if (MapData.MapLayers[i] != null)
                {
                    TileLayerDatas[i] = s.DoAt(basePointer + MapData.MapLayers[i].DataBlockOffset, () => s.SerializeObject <GBAVV_TileLayerData>(TileLayerDatas[i], x => x.MapLayer = MapData.MapLayers[i], name: $"{nameof(TileLayerDatas)}[{i}]"));
                }
            }

            if (MapData.CollisionDataPointer != null)
            {
                CollisionLayerData = s.DoAt(basePointer + MapData.CollisionLayer.DataBlockOffset, () => s.SerializeObject <GBAVV_TileLayerData>(CollisionLayerData, x => x.MapLayer = MapData.CollisionLayer, name: nameof(CollisionLayerData)));
            }

            s.Goto(basePointer + BlockLength);
        }
예제 #19
0
        /// <summary>
        /// Serializes the data
        /// </summary>
        /// <param name="s">The serializer object</param>
        public override void SerializeImpl(SerializerObject s)
        {
            // HEADER BLOCK
            LevelDefines = s.SerializeObject <R1_PC_KitLevelDefinesBlock>(LevelDefines, name: nameof(LevelDefines));

            // Serialize map size
            Width  = s.Serialize <ushort>(Width, name: nameof(Width));
            Height = s.Serialize <ushort>(Height, name: nameof(Height));

            // Create the palettes if necessary
            if (ColorPalettes == null)
            {
                ColorPalettes = new RGB666Color[][]
                {
                    new RGB666Color[256],
                    new RGB666Color[256],
                    new RGB666Color[256],
                };
            }

            // Serialize each palette
            for (var paletteIndex = 0; paletteIndex < ColorPalettes.Length; paletteIndex++)
            {
                var palette = ColorPalettes[paletteIndex];
                ColorPalettes[paletteIndex] = s.SerializeObjectArray <RGB666Color>(palette, palette.Length, name: nameof(ColorPalettes) + "[" + paletteIndex + "]");
            }

            // Serialize unknown byte
            LastPlan1Palette = s.Serialize <byte>(LastPlan1Palette, name: nameof(LastPlan1Palette));

            // Serialize unknown bytes
            Unk1_1 = s.Serialize <uint>(Unk1_1, name: nameof(Unk1_1));
            LeftoverTextureOffsetTable = s.SerializeArray <uint>(LeftoverTextureOffsetTable, 1200, name: nameof(LeftoverTextureOffsetTable));

            // Serialize event block header
            Unk3              = s.Serialize <uint>(Unk3, name: nameof(Unk3));
            Unk4              = s.Serialize <uint>(Unk4, name: nameof(Unk4));
            EventCount        = s.Serialize <ushort>(EventCount, name: nameof(EventCount));
            EventBlockSize    = s.Serialize <uint>(EventBlockSize, name: nameof(EventBlockSize));
            EventBlockPointer = s.CurrentPointer;
            s.Goto(EventBlockPointer + EventBlockSize);

            // Serialize event command counts
            EventNumCommands     = s.SerializeArray <ushort>(EventNumCommands, EventCount, name: nameof(EventNumCommands));
            EventNumLabelOffsets = s.SerializeArray <ushort>(EventNumLabelOffsets, EventCount, name: nameof(EventNumLabelOffsets));

            // Serialize tile-set texture data
            TileTextures = s.SerializeArray <byte>(TileTextures, 512 * 256, name: nameof(TileTextures));

            // Serialize the map tiles
            MapBlockSize = s.Serialize <uint>(MapBlockSize, name: nameof(MapBlockSize));
            MapTiles     = s.SerializeObjectArray <MapTile>(MapTiles, MapBlockSize / 6, name: nameof(MapTiles));


            // Finally, read the events
            s.DoAt(EventBlockPointer, () => {
                // Helper method to get the current position inside of the event block
                int GetPosInEventBlock()
                {
                    int currentPos = (int)(s.CurrentPointer - EventBlockPointer);
                    return(currentPos);
                }

                // Serialize the events
                Events = s.SerializeObjectArray <R1_EventData>(Events, EventCount, name: nameof(Events));

                // Padding...
                s.SerializeArray <byte>(Enumerable.Repeat((byte)0xCD, EventCount * 4).ToArray(), EventCount * 4, name: "Padding");
                if (EventCount % 2 != 0)
                {
                    const int padding = 4;
                    s.SerializeArray <byte>(Enumerable.Repeat((byte)0xCD, padding).ToArray(), padding, name: "Padding");
                }

                // Serialize the event link table
                EventLinkTable = s.SerializeArray <ushort>(EventLinkTable, EventCount, name: nameof(EventLinkTable));

                // Padding...
                if (EventCount % 2 == 0)
                {
                    const int padding = 2;
                    s.SerializeArray <byte>(Enumerable.Repeat((byte)0xCD, padding).ToArray(), padding, name: "Padding");
                }

                // Serialize the commands
                if (EventCommands == null)
                {
                    EventCommands = new R1_PC_EventCommand[EventCount];
                }
                for (int i = 0; i < EventCount; i++)
                {
                    EventCommands[i] = new R1_PC_EventCommand();
                    if (EventNumCommands[i] != 0)
                    {
                        if (GetPosInEventBlock() % 4 != 0)
                        {
                            int padding = 4 - GetPosInEventBlock() % 4;
                            s.SerializeArray <byte>(Enumerable.Repeat((byte)0xCD, padding).ToArray(), padding, name: "Padding");
                        }
                        EventCommands[i].CommandLength = EventNumCommands[i];
                        EventCommands[i].Commands      = s.SerializeObject <R1_EventCommandCollection>(EventCommands[i].Commands, name: nameof(R1_PC_EventCommand.Commands));
                    }
                    else
                    {
                        EventCommands[i].Commands = new R1_EventCommandCollection()
                        {
                            Commands = new R1_EventCommand[0]
                        };
                    }
                    if (EventNumLabelOffsets[i] != 0)
                    {
                        if (GetPosInEventBlock() % 4 != 0)
                        {
                            int padding = 4 - GetPosInEventBlock() % 4;
                            s.SerializeArray <byte>(Enumerable.Repeat((byte)0xCD, padding).ToArray(), padding, name: "Padding");
                        }
                        EventCommands[i].LabelOffsetCount = EventNumLabelOffsets[i];
                        EventCommands[i].LabelOffsetTable = s.SerializeArray <ushort>(EventCommands[i].LabelOffsetTable, EventCommands[i].LabelOffsetCount, name: nameof(R1_PC_EventCommand.LabelOffsetTable));
                    }
                    else
                    {
                        EventCommands[i].LabelOffsetTable = new ushort[0];
                    }
                }
            });
        }
예제 #20
0
        public override void SerializeImpl(SerializerObject s)
        {
            bool isShanghai = s.GameSettings.GBA_IsShanghai || s.GameSettings.GBA_IsMilan;

            Command = s.Serialize <InstructionCommand>(Command, name: nameof(Command));

            if (isShanghai)
            {
                CommandSize = s.Serialize <byte>(CommandSize, name: nameof(CommandSize)); // In bytes
            }
            switch (Command)
            {
            case InstructionCommand.SpriteNew:
                LayerCount = s.Serialize <byte>(LayerCount, name: nameof(LayerCount));
                Padding    = s.SerializeArray <byte>(Padding, isShanghai ? 1 : 2, name: nameof(Padding));
                Layers     = s.SerializeObjectArray <GBA_BatmanVengeance_AnimationChannel>(Layers, LayerCount, name: nameof(Layers));
                break;

            case InstructionCommand.SpriteTilemap:
                Padding = s.SerializeArray <byte>(Padding, isShanghai ? 2 : 3, name: nameof(Padding));
                TileMap = s.SerializeObjectArray <TileGraphicsInfo>(TileMap, Puppet.TilemapWidth * Puppet.TilemapHeight, name: nameof(TileMap));
                break;

            case InstructionCommand.Hitbox:
                HitboxXPos       = s.Serialize <sbyte>(HitboxXPos, name: nameof(HitboxXPos));
                HitboxYPos       = s.Serialize <sbyte>(HitboxYPos, name: nameof(HitboxYPos));
                HitboxHalfWidth  = s.Serialize <ushort>(HitboxHalfWidth, name: nameof(HitboxHalfWidth));
                HitboxHalfHeight = s.Serialize <ushort>(HitboxHalfHeight, name: nameof(HitboxHalfHeight));
                break;

            case InstructionCommand.Unknown81:
                Byte_81_02 = s.Serialize <byte>(Byte_81_02, name: nameof(Byte_81_02));
                Byte_81_03 = s.Serialize <byte>(Byte_81_03, name: nameof(Byte_81_03));
                Byte_81_04 = s.Serialize <byte>(Byte_81_04, name: nameof(Byte_81_04));
                break;

            case InstructionCommand.Unknown82:
                Byte_82_02 = s.Serialize <byte>(Byte_82_02, name: nameof(Byte_82_02));
                Byte_82_03 = s.Serialize <byte>(Byte_82_03, name: nameof(Byte_82_03));
                break;

            case InstructionCommand.Unknown83:
                Byte_83_02 = s.Serialize <byte>(Byte_83_02, name: nameof(Byte_83_02));
                Byte_83_03 = s.Serialize <byte>(Byte_83_03, name: nameof(Byte_83_03));
                break;

            case InstructionCommand.Hitbox_Batman:
                Padding   = s.SerializeArray <byte>(Padding, isShanghai ? 2 : 3, name: nameof(Padding));
                Hitbox_Y1 = s.Serialize <sbyte>(Hitbox_Y1, name: nameof(Hitbox_Y1));
                Hitbox_X1 = s.Serialize <sbyte>(Hitbox_X1, name: nameof(Hitbox_X1));
                Hitbox_Y2 = s.Serialize <sbyte>(Hitbox_Y2, name: nameof(Hitbox_Y2));
                Hitbox_X2 = s.Serialize <sbyte>(Hitbox_X2, name: nameof(Hitbox_X2));
                break;

            case InstructionCommand.Unknown85:
                Byte_85_02 = s.Serialize <byte>(Byte_85_02, name: nameof(Byte_85_02));
                Byte_85_03 = s.Serialize <byte>(Byte_85_03, name: nameof(Byte_85_03));
                break;

            case InstructionCommand.Unknown86:
                Byte_86_02 = s.Serialize <byte>(Byte_86_02, name: nameof(Byte_86_02));
                Byte_86_03 = s.Serialize <byte>(Byte_86_03, name: nameof(Byte_86_03));
                Byte_86_04 = s.Serialize <byte>(Byte_86_04, name: nameof(Byte_86_04));
                Byte_86_05 = s.Serialize <byte>(Byte_86_05, name: nameof(Byte_86_05));
                Byte_86_06 = s.Serialize <byte>(Byte_86_06, name: nameof(Byte_86_06));
                Byte_86_07 = s.Serialize <byte>(Byte_86_07, name: nameof(Byte_86_07));
                break;

            case InstructionCommand.Terminator0:
            case InstructionCommand.Terminator20:
                Time    = s.Serialize <byte>(Time, name: nameof(Time));
                Padding = s.SerializeArray <byte>(Padding, isShanghai ? 1 : 2, name: nameof(Padding));
                break;

            default:
                throw new Exception($"Unknown command {Command}");
            }
            if (isShanghai)
            {
                if (CommandSize < 2)
                {
                    throw new Exception($"Command size {CommandSize} at {Offset}");
                }

                s.Goto(Offset + CommandSize);
            }
        }
예제 #21
0
        /// <summary>
        /// Serializes the data
        /// </summary>
        /// <param name="s">The serializer object</param>
        public override void SerializeImpl(SerializerObject s)
        {
            if (FileType == Type.World)
            {
                // Serialize header
                BG1 = s.Serialize <ushort>(BG1, name: nameof(BG1));
                BG2 = s.Serialize <ushort>(BG2, name: nameof(BG2));
                Plan0NumPcxCount = s.Serialize <byte>(Plan0NumPcxCount, name: nameof(Plan0NumPcxCount));
                s.DoXOR(0x19, () => Plan0NumPcxFiles = s.SerializeStringArray(Plan0NumPcxFiles, Plan0NumPcxCount, 8, name: nameof(Plan0NumPcxFiles)));

                // Serialize counts
                DESCount       = s.Serialize <ushort>(DESCount, name: nameof(DESCount));
                ETACount       = s.Serialize <byte>(ETACount, name: nameof(ETACount));
                DESBlockLength = s.Serialize <uint>(DESBlockLength, name: nameof(DESBlockLength));
            }
            else
            {
                // Serialize header
                ETACount = s.Serialize <byte>(ETACount, name: nameof(ETACount));
                DESCount = s.Serialize <ushort>(DESCount, name: nameof(DESCount));
            }

            // Serialize DES data
            DESData = s.SerializeObjectArray <R1_PS1Edu_DESData>(DESData, DESCount, name: nameof(DESData));

            if (FileType == Type.World)
            {
                WorldDefine = WorldDefine = s.SerializeObject <R1_PC_WorldDefine>(WorldDefine, name: nameof(WorldDefine));
            }

            // Serialize main data block length
            MainDataBlockLength = s.Serialize <uint>(MainDataBlockLength, name: nameof(MainDataBlockLength));

            // We parse the main data block later...
            MainDataBlockPointer = s.CurrentPointer;
            s.Goto(MainDataBlockPointer + MainDataBlockLength);

            if (FileType == Type.Allfix)
            {
                DESDataIndices = s.SerializeArray <uint>(DESDataIndices, 8, name: nameof(DESDataIndices));
            }

            // Serialize ETA tables
            if (FileType == Type.World)
            {
                ETAStateCountTableCount = s.Serialize <byte>(ETAStateCountTableCount, name: nameof(ETAStateCountTableCount));
                ETAStateCountTable      = s.SerializeArray <byte>(ETAStateCountTable, ETAStateCountTableCount, name: nameof(ETAStateCountTable));
            }
            else
            {
                ETAStateCountTable = s.SerializeArray <byte>(ETAStateCountTable, ETACount, name: nameof(ETAStateCountTable));
            }
            ETASubStateCountTableCount = s.Serialize <byte>(ETASubStateCountTableCount, name: nameof(ETASubStateCountTableCount));
            ETASubStateCountTable      = s.SerializeArray <byte>(ETASubStateCountTable, ETASubStateCountTableCount, name: nameof(ETASubStateCountTable));

            // Serialize animation descriptor layer table
            AnimationDescriptorLayersBlockSizeTableCount = s.Serialize <uint>(AnimationDescriptorLayersBlockSizeTableCount, name: nameof(AnimationDescriptorLayersBlockSizeTableCount));
            AnimationDescriptorLayersBlockSizeTable      = s.SerializeArray <ushort>(AnimationDescriptorLayersBlockSizeTable, AnimationDescriptorLayersBlockSizeTableCount, name: nameof(AnimationDescriptorLayersBlockSizeTable));

            // Serialize animation layers
            AnimationLayers = s.SerializeObjectArray <R1_AnimationLayer>(AnimationLayers, 0xFE, name: nameof(AnimationLayers));

            // Serialize the main data block
            s.DoAt(MainDataBlockPointer, () =>
            {
                if (FileType == Type.World)
                {
                    SerializeDES();
                    SerializeETA();
                }
                else
                {
                    SerializeETA();
                    SerializeDES();
                }

                // Helper method for serializing the DES
                void SerializeDES()
                {
                    if (ImageDescriptors == null)
                    {
                        ImageDescriptors = new R1_ImageDescriptor[DESCount][];
                    }

                    if (AnimationDescriptors == null)
                    {
                        AnimationDescriptors = new R1_PS1Edu_AnimationDescriptor[DESCount][];
                    }

                    int curAnimDesc = 0;

                    // Serialize data for every DES
                    for (int i = 0; i < DESCount; i++)
                    {
                        // Serialize image descriptors
                        ImageDescriptors[i] = s.SerializeObjectArray <R1_ImageDescriptor>(ImageDescriptors[i], DESData[i].ImageDescriptorsCount, name: $"{nameof(ImageDescriptors)}[{i}]");

                        // Serialize animation descriptors
                        AnimationDescriptors[i] = s.SerializeObjectArray <R1_PS1Edu_AnimationDescriptor>(AnimationDescriptors[i], DESData[i].AnimationDescriptorsCount, name: $"{nameof(AnimationDescriptors)}[{i}]");

                        // Serialize animation descriptor data
                        for (int j = 0; j < AnimationDescriptors[i].Length; j++)
                        {
                            var descriptor = AnimationDescriptors[i][j];

                            if (descriptor.FrameCount <= 0)
                            {
                                curAnimDesc++;
                                continue;
                            }

                            // Serialize layer data
                            descriptor.LayersData = s.SerializeArray <byte>(descriptor.LayersData, AnimationDescriptorLayersBlockSizeTable[curAnimDesc], name: nameof(descriptor.LayersData));

                            // Padding...
                            if (AnimationDescriptorLayersBlockSizeTable[curAnimDesc] % 4 != 0)
                            {
                                // Padding seems to contain garbage data in this case instead of 0xCD?
                                int paddingLength = 4 - AnimationDescriptorLayersBlockSizeTable[curAnimDesc] % 4;
                                s.SerializeArray <byte>(Enumerable.Repeat((byte)0xCD, paddingLength).ToArray(), paddingLength, name: "Padding");
                            }

                            // Serialize frames
                            if (descriptor.AnimFramesPointer != 0xFFFFFFFF)
                            {
                                descriptor.Frames = s.SerializeObjectArray <R1_AnimationFrame>(descriptor.Frames, descriptor.FrameCount, name: nameof(descriptor.Frames));
                            }

                            // Parse layers
                            if (descriptor.Layers == null)
                            {
                                var layers = new List <R1_AnimationLayer>();
                                var offset = 0;

                                while (offset < descriptor.LayersData.Length)
                                {
                                    if (descriptor.LayersData[offset] < 2)
                                    {
                                        layers.Add(new R1_AnimationLayer()
                                        {
                                            IsFlippedHorizontally = descriptor.LayersData[offset + 0] == 1,
                                            XPosition             = descriptor.LayersData[offset + 1],
                                            YPosition             = descriptor.LayersData[offset + 2],
                                            ImageIndex            = descriptor.LayersData[offset + 3],
                                        });

                                        offset += 4;
                                    }
                                    else
                                    {
                                        layers.Add(AnimationLayers[descriptor.LayersData[offset] - 2]);
                                        offset++;
                                    }
                                }

                                descriptor.Layers = layers.ToArray();
                            }

                            curAnimDesc++;
                        }
                    }
                }

                // Helper method for serializing the ETA
                void SerializeETA()
                {
                    if (ETA == null)
                    {
                        ETA = new R1_EventState[ETACount][][];
                    }

                    var stateIndex = 0;

                    // Serialize every ETA
                    for (int i = 0; i < ETA.Length; i++)
                    {
                        if (ETA[i] == null)
                        {
                            ETA[i] = new R1_EventState[ETAStateCountTable[i]][];
                        }

                        // EDU serializes the pointer structs, but the pointers are invalid. They can be anything as they're overwritten with valid memory pointers upon load
                        uint[] pointerStructs = Enumerable.Repeat((uint)1, ETA[i].Length).ToArray();
                        _ = s.SerializeArray <uint>(pointerStructs, pointerStructs.Length, name: $"ETAPointers[{i}]");

                        // Serialize every state
                        for (int j = 0; j < ETA[i].Length; j++)
                        {
                            // Serialize sub-states
                            ETA[i][j] = s.SerializeObjectArray <R1_EventState>(ETA[i][j], ETASubStateCountTable[stateIndex], name: $"{nameof(ETA)}[{i}][{j}]");

                            stateIndex++;
                        }
                    }
                }
            });
        }
예제 #22
0
        public override void SerializeBlock(SerializerObject s)
        {
            if (s.GameSettings.EngineVersion == EngineVersion.GBA_BatmanVengeance)
            {
                if (StructType != Type.Collision)
                {
                    Unk_02 = s.Serialize <byte>(Unk_02, name: nameof(Unk_02));
                    Unk_03 = s.Serialize <byte>(Unk_03, name: nameof(Unk_03));

                    LayerID      = s.Serialize <byte>(LayerID, name: nameof(LayerID));
                    ClusterIndex = s.Serialize <byte>(ClusterIndex, name: nameof(ClusterIndex));
                    // TODO: figure out what this is. One of these
                    UnkBytes = s.SerializeArray <byte>(UnkBytes, 5, name: nameof(UnkBytes));
                    ShouldSetBGAlphaBlending = s.Serialize <bool>(ShouldSetBGAlphaBlending, name: nameof(ShouldSetBGAlphaBlending));
                    Unk_0E    = s.Serialize <byte>(Unk_0E, name: nameof(Unk_0E));
                    ColorMode = s.Serialize <GBA_ColorMode>(ColorMode, name: nameof(ColorMode));
                }
            }
            else if (s.GameSettings.GBA_IsMilan)
            {
                ColorMode = GBA_ColorMode.Color4bpp;

                // Serialize cluster
                Cluster = s.DoAt(ShanghaiOffsetTable.GetPointer(0), () => s.SerializeObject <GBA_Cluster>(Cluster, name: nameof(Cluster)));

                IStreamEncoder encoder = null;

                switch (Cluster.Milan_MapCompressionType)
                {
                case GBA_Cluster.Milan_CompressionType.Collision_RL:
                case GBA_Cluster.Milan_CompressionType.Map_RL:
                    encoder = new GBA_RLEEncoder();
                    break;

                case GBA_Cluster.Milan_CompressionType.Collsiion_LZSS:
                case GBA_Cluster.Milan_CompressionType.Map_LZSS:
                    encoder = new GBA_LZSSEncoder();
                    break;
                }

                // Go to the map data
                s.Goto(ShanghaiOffsetTable.GetPointer(2));

                if (StructType == Type.Layer2D)
                {
                    s.DoEncodedIf(encoder, encoder != null, () => Shanghai_MapIndices_16 = s.SerializeArray <ushort>(Shanghai_MapIndices_16, ((Width + Width % 2) * (Height + Height % 2)) / 4, name: nameof(Shanghai_MapIndices_16)));

                    var end = s.CurrentPointer;

                    // Go to the map tiles
                    s.Goto(ShanghaiOffsetTable.GetPointer(1));

                    s.DoEncodedIf(encoder, encoder != null, () => Shanghai_MapTiles = s.SerializeObjectArray <MapTile>(Shanghai_MapTiles, (Shanghai_MapIndices_16.Max(x => BitHelpers.ExtractBits(x, 12, 0)) + 1) * 4, name: nameof(Shanghai_MapTiles)));

                    s.Goto(end);
                }
                else // Collision
                {
                    s.DoEncodedIf(encoder, encoder != null, () => SerializeTileMap(s));
                }

                s.Align();

                // Return to avoid serializing the map tile array normally
                return;
            }
            else if (s.GameSettings.GBA_IsShanghai)
            {
                ColorMode    = GBA_ColorMode.Color4bpp;
                IsCompressed = false;

                if (StructType == Type.Layer2D)
                {
                    // Serialize cluster
                    Cluster = s.DoAt(ShanghaiOffsetTable.GetPointer(0), () => s.SerializeObject <GBA_Cluster>(Cluster, name: nameof(Cluster)));

                    // Go to the map data
                    s.Goto(ShanghaiOffsetTable.GetPointer(2));

                    // If the map tile size is not 0 the map is split into a 32x8 index array and 8x8 map tiles
                    if (Cluster.Shanghai_MapTileSize != 0)
                    {
                        var indexArrayLength = Mathf.CeilToInt(Width / 4f) * Height;

                        // The tile size is either 1 or 2 bytes
                        if (Cluster.Shanghai_MapTileSize == 1)
                        {
                            Shanghai_MapIndices_8 = s.SerializeArray <byte>(Shanghai_MapIndices_8, indexArrayLength, name: nameof(Shanghai_MapIndices_8));
                        }
                        else
                        {
                            Shanghai_MapIndices_16 = s.SerializeArray <ushort>(Shanghai_MapIndices_16, indexArrayLength, name: nameof(Shanghai_MapIndices_16));
                        }

                        var indexArray = Cluster.Shanghai_MapTileSize == 1 ? Shanghai_MapIndices_8.Select(x => (ushort)x).ToArray() : Shanghai_MapIndices_16;

                        Shanghai_MapTiles = s.SerializeObjectArray <MapTile>(Shanghai_MapTiles, (indexArray.Max() + 1) * 4, name: nameof(Shanghai_MapTiles));

                        // Return to avoid serializing the map tile array normally
                        return;
                    }
                }
                else
                {
                    // Go to the collision data
                    s.Goto(ShanghaiOffsetTable.GetPointer(0));

                    // Serialize header properties
                    Shanghai_CollisionValue1 = s.Serialize <ushort>(Shanghai_CollisionValue1, name: nameof(Shanghai_CollisionValue1));
                    Width  = s.Serialize <ushort>(Width, name: nameof(Width));
                    Height = s.Serialize <ushort>(Height, name: nameof(Height));
                    Shanghai_CollisionValue2 = s.Serialize <ushort>(Shanghai_CollisionValue2, name: nameof(Shanghai_CollisionValue2));
                }
            }
            else
            {
                StructType = s.Serialize <Type>(StructType, name: nameof(StructType));

                if (StructType != Type.TextLayerMode7)
                {
                    IsCompressed = s.Serialize <bool>(IsCompressed, name: nameof(IsCompressed));
                }
                else
                {
                    Unk_01 = s.Serialize <bool>(Unk_01, name: nameof(Unk_01));
                }

                Unk_02 = s.Serialize <byte>(Unk_02, name: nameof(Unk_02));
                Unk_03 = s.Serialize <byte>(Unk_03, name: nameof(Unk_03));

                Width  = s.Serialize <ushort>(Width, name: nameof(Width));
                Height = s.Serialize <ushort>(Height, name: nameof(Height));

                switch (StructType)
                {
                case Type.TextLayerMode7:
                    LayerID = s.Serialize <byte>(LayerID, name: nameof(LayerID));
                    ShouldSetBGAlphaBlending = s.Serialize <bool>(ShouldSetBGAlphaBlending, name: nameof(ShouldSetBGAlphaBlending));
                    AlphaBlending_Coeff      = s.Serialize <sbyte>(AlphaBlending_Coeff, name: nameof(AlphaBlending_Coeff));
                    UnkBytes  = s.SerializeArray <byte>(UnkBytes, 0x14, name: nameof(UnkBytes));
                    ColorMode = s.Serialize <GBA_ColorMode>(ColorMode, name: nameof(ColorMode));
                    // 21 bytes
                    // Prio is 0x1D
                    // ColorMode is 0x1F
                    // Width & height seems duplicates again (is it actually width and height?)

                    break;

                case Type.RotscaleLayerMode7:
                    LayerID = s.Serialize <byte>(LayerID, name: nameof(LayerID));
                    ShouldSetBGAlphaBlending = s.Serialize <bool>(ShouldSetBGAlphaBlending, name: nameof(ShouldSetBGAlphaBlending));
                    AlphaBlending_Coeff      = s.Serialize <sbyte>(AlphaBlending_Coeff, name: nameof(AlphaBlending_Coeff));
                    // The game hard-codes the color mode
                    ColorMode = GBA_ColorMode.Color8bpp;

                    Unk_0C   = s.Serialize <byte>(Unk_0C, name: nameof(Unk_0C));
                    Unk_0D   = s.Serialize <byte>(Unk_0D, name: nameof(Unk_0D));
                    Unk_0E   = s.Serialize <byte>(Unk_0E, name: nameof(Unk_0E));
                    Unk_0F   = s.Serialize <byte>(Unk_0F, name: nameof(Unk_0F));
                    Mode7_10 = s.Serialize <byte>(Mode7_10, name: nameof(Mode7_10));
                    Mode7_11 = s.Serialize <byte>(Mode7_11, name: nameof(Mode7_11));
                    Mode7_12 = s.Serialize <byte>(Mode7_12, name: nameof(Mode7_12));
                    Mode7_13 = s.Serialize <byte>(Mode7_13, name: nameof(Mode7_13));
                    Mode7_14 = s.Serialize <byte>(Mode7_14, name: nameof(Mode7_14));
                    break;

                case Type.SplinterCellZoom:
                    if (LayerID < 2)
                    {
                        Unk_0C = s.Serialize <byte>(Unk_0C, name: nameof(Unk_0C));
                        Unk_0D = s.Serialize <byte>(Unk_0D, name: nameof(Unk_0D));
                        Unk_0E = s.Serialize <byte>(Unk_0E, name: nameof(Unk_0E));
                        Unk_0F = s.Serialize <byte>(Unk_0F, name: nameof(Unk_0F));
                        if (s.GameSettings.EngineVersion == EngineVersion.GBA_SplinterCell_NGage)
                        {
                            ColorMode = GBA_ColorMode.Color8bpp;
                        }
                        else
                        {
                            ColorMode = GBA_ColorMode.Color4bpp;
                        }
                    }
                    else
                    {
                        ColorMode = GBA_ColorMode.Color8bpp;
                    }
                    UsesTileKitDirectly = true;
                    break;

                case Type.PoP:
                    Unk_0C    = s.Serialize <byte>(Unk_0C, name: nameof(Unk_0C));
                    Unk_0D    = s.Serialize <byte>(Unk_0D, name: nameof(Unk_0D));
                    Unk_0E    = s.Serialize <byte>(Unk_0E, name: nameof(Unk_0E));
                    Unk_0F    = s.Serialize <byte>(Unk_0F, name: nameof(Unk_0F));
                    ColorMode = GBA_ColorMode.Color8bpp;
                    break;

                case Type.Layer2D:
                    LayerID                  = s.Serialize <byte>(LayerID, name: nameof(LayerID));
                    ClusterIndex             = s.Serialize <byte>(ClusterIndex, name: nameof(ClusterIndex));
                    ShouldSetBGAlphaBlending = s.Serialize <bool>(ShouldSetBGAlphaBlending, name: nameof(ShouldSetBGAlphaBlending));
                    AlphaBlending_Coeff      = s.Serialize <sbyte>(AlphaBlending_Coeff, name: nameof(AlphaBlending_Coeff));

                    UsesTileKitDirectly = s.Serialize <bool>(UsesTileKitDirectly, name: nameof(UsesTileKitDirectly));
                    ColorMode           = s.Serialize <GBA_ColorMode>(ColorMode, name: nameof(ColorMode));
                    TileKitIndex        = s.Serialize <byte>(TileKitIndex, name: nameof(TileKitIndex));
                    Unk_0F = s.Serialize <byte>(Unk_0F, name: nameof(Unk_0F));
                    break;
                }
            }

            if (StructType != Type.TextLayerMode7)
            {
                if (!IsCompressed)
                {
                    SerializeTileMap(s);
                }
                else if (s.GameSettings.EngineVersion >= EngineVersion.GBA_PrinceOfPersia && StructType != Type.PoP)
                {
                    s.DoEncoded(new GBA_Huffman4Encoder(), () => s.DoEncoded(new GBA_LZSSEncoder(), () => SerializeTileMap(s)));
                }
                else
                {
                    s.DoEncoded(new GBA_LZSSEncoder(), () => SerializeTileMap(s));
                }
                s.Align();
            }
        }