/// <summary> /// Gets a pointer from the table /// </summary> /// <param name="index">The offset index</param> /// <returns>The pointer</returns> public Pointer GetPointer(int index, bool isRelativeOffset = false) { UsedOffsets[index] = true; var pointerTable = PointerTables.GBA_PointerTable(Offset.Context, Context.GetFile(((GBA_Manager)Offset.Context.Settings.GetGameManager).GetROMFilePath(Context))); if (Context.Settings.EngineVersion == EngineVersion.GBA_SplinterCell_NGage) { if (Block == null) { return(pointerTable[GBA_Pointer.UiOffsetTable] + Offsets[index]); } else { if (Block.DecompressedBlockOffset != null) { return(Block.DecompressedBlockOffset + Offsets[index]); } else { return(Block.Offset + Offsets[index]); } } } else { if (isRelativeOffset && Block != null) { return(Block.Offset + Offsets[index]); } else { return(pointerTable[GBA_Pointer.UiOffsetTable] + (Offsets[index] * 4)); } } }
/// <summary> /// Handles the data serialization /// </summary> /// <param name="s">The serializer object</param> public override void SerializeImpl(SerializerObject s) { // Serialize ROM header base.SerializeImpl(s); var manager = ((GBA_Manager)s.Context.Settings.GetGameManager); // Get the pointer table var pointerTable = PointerTables.GBA_PointerTable(s.Context, Offset.file); var lvlType = manager.GetLevelType(s.Context); // Serialize the offset table if (lvlType != GBA_Manager.LevelType.R3SinglePak) { s.DoAt(pointerTable[GBA_Pointer.UiOffsetTable], () => Data = s.SerializeObject <GBA_Data>(Data, name: nameof(Data))); } // Serialize level info if (pointerTable.ContainsKey(GBA_Pointer.LevelInfo)) { LevelInfo = s.DoAt(pointerTable[GBA_Pointer.LevelInfo], () => s.SerializeObjectArray <GBA_R3_SceneInfo>(LevelInfo, manager.LevelCount, name: nameof(LevelInfo))); } // Serialize localization if (pointerTable.ContainsKey(GBA_Pointer.Localization)) { if (s.GameSettings.GBA_IsMilan) { s.DoAt(pointerTable[GBA_Pointer.Localization], () => Milan_Localization = s.SerializeObject <GBA_Milan_LocTable>(Milan_Localization, name: nameof(Milan_Localization))); } else { s.DoAt(pointerTable[GBA_Pointer.Localization], () => Localization = s.SerializeObject <GBA_LocLanguageTable>(Localization, name: nameof(Localization))); } } // Serialize actor type data if (pointerTable.ContainsKey(GBA_Pointer.ActorTypeTable)) { ActorTypeTable = s.DoAt(pointerTable[GBA_Pointer.ActorTypeTable], () => s.SerializeObjectArray <GBA_ActorTypeTableEntry>(ActorTypeTable, manager.ActorTypeTableLength, name: nameof(ActorTypeTable))); } if (lvlType == GBA_Manager.LevelType.R3SinglePak) { R3SinglePak_OffsetTable = s.DoAt(pointerTable[GBA_Pointer.R3SinglePak_OffsetTable], () => s.SerializeObject <GBA_OffsetTable>(R3SinglePak_OffsetTable, name: nameof(R3SinglePak_OffsetTable))); R3SinglePak_Palette = s.DoAt(pointerTable[GBA_Pointer.R3SinglePak_Palette], () => s.SerializeObjectArray <RGBA5551Color>(R3SinglePak_Palette, 256, name: nameof(R3SinglePak_Palette))); R3SinglePak_TileMap = s.DoAt(pointerTable[GBA_Pointer.R3SinglePak_TileMap], () => s.SerializeArray <ushort>(R3SinglePak_TileMap, 0x400, name: nameof(R3SinglePak_TileMap))); R3SinglePak_TileSet = s.DoAt(pointerTable[GBA_Pointer.R3SinglePak_TileSet], () => s.SerializeArray <byte>(R3SinglePak_TileSet, (R3SinglePak_TileMap.Max() + 1) * 0x40, name: nameof(R3SinglePak_TileSet))); if (R3SinglePak_Puppets == null) { R3SinglePak_Puppets = new GBA_Puppet[R3SinglePak_OffsetTable.OffsetsCount]; } for (int i = 0; i < R3SinglePak_Puppets.Length; i++) { R3SinglePak_Puppets[i] = s.DoAt(R3SinglePak_OffsetTable.GetPointer(i), () => s.SerializeObject <GBA_Puppet>(R3SinglePak_Puppets[i], name: $"{nameof(R3SinglePak_Puppets)}[{i}]")); } } }
public override void SerializeImpl(SerializerObject s) { // Get the language count for the current game var langCount = ((GBAIsometric_Spyro_Manager)s.GameSettings.GetGameManager).GetLanguages.Count(); var pointerTable = PointerTables.GBAIsometric_Spyro_PointerTable(s.GameSettings.GameModeSelection, Offset.file); if (s.GameSettings.EngineVersion == EngineVersion.GBAIsometric_Spyro3) { // Parse loc tables LocalizationBlockIndices = s.DoAt(pointerTable.TryGetItem(GBAIsometric_Spyro_Pointer.LocalizationBlockIndices), () => s.SerializeObjectArray <GBAIsometric_Spyro_DataBlockIndex>(LocalizationBlockIndices, langCount, x => x.HasPadding = true, name: nameof(LocalizationBlockIndices))); LocalizationDecompressionBlockIndices = s.DoAt(pointerTable.TryGetItem(GBAIsometric_Spyro_Pointer.LocalizationDecompressionBlockIndices), () => s.SerializeObjectArray <GBAIsometric_Spyro_DataBlockIndex>(LocalizationDecompressionBlockIndices, langCount, x => x.HasPadding = true, name: nameof(LocalizationDecompressionBlockIndices))); LocTables = s.DoAt(pointerTable.TryGetItem(GBAIsometric_Spyro_Pointer.LocTables), () => s.SerializeObjectArray <GBAIsometric_Spyro_LocTable>(LocTables, 38, name: nameof(LocTables))); // Parse block data if (LocDecompressHelpers == null) { LocDecompressHelpers = new GBAIsometric_Spyro_LocDecompress[langCount][]; } for (int i = 0; i < LocDecompressHelpers.Length; i++) { LocDecompressHelpers[i] = LocalizationDecompressionBlockIndices[i].DoAtBlock(size => s.SerializeObjectArray <GBAIsometric_Spyro_LocDecompress>(LocDecompressHelpers[i], size / 3, name: $"{nameof(LocDecompressHelpers)}[{i}]")); } if (LocBlocks == null) { LocBlocks = new GBAIsometric_Spyro_LocBlock[langCount]; } for (int i = 0; i < LocBlocks.Length; i++) { LocBlocks[i] = LocalizationBlockIndices[i].DoAtBlock(size => s.SerializeObject <GBAIsometric_Spyro_LocBlock>(LocBlocks[i], onPreSerialize: lb => { lb.Length = LocTables.Max(lt => lt.StartIndex + lt.NumEntries); lb.DecompressHelpers = LocDecompressHelpers[i]; }, name: $"{nameof(LocBlocks)}[{i}]")); } } else { LocalizationPointers = s.DoAt(pointerTable.TryGetItem(GBAIsometric_Spyro_Pointer.LocalizationPointers), () => s.SerializePointerArray(LocalizationPointers, langCount, name: nameof(LocalizationPointers))); if (LocBlocks == null) { LocBlocks = new GBAIsometric_Spyro_LocBlock[langCount]; } for (int i = 0; i < LocBlocks.Length; i++) { LocBlocks[i] = s.DoAt(LocalizationPointers[i], () => s.SerializeObject <GBAIsometric_Spyro_LocBlock>(LocBlocks[i], name: $"{nameof(LocBlocks)}[{i}]")); } } // Store the localization tables so we can access them to get the strings s.Context.StoreObject("Loc", LocBlocks.Select(x => x.Strings).ToArray()); }
/// <summary> /// Gets a pointer from the table /// </summary> /// <param name="index">The offset index</param> /// <returns>The pointer</returns> public Pointer GetPointer(int index, bool isRelativeOffset = false) { if (index >= OffsetsCount) { throw new Exception($"Invalid offset index {index}, length is {OffsetsCount}"); } UsedOffsets[index] = true; var manager = (GBA_Manager)Offset.Context.Settings.GetGameManager; var pointerTable = PointerTables.GBA_PointerTable(Offset.Context, Context.GetFile(manager.GetROMFilePath(Context))); var root = pointerTable[GBA_Pointer.UiOffsetTable]; if (manager.GetLevelType(Context) == GBA_Manager.LevelType.R3SinglePak) { root = pointerTable[GBA_Pointer.R3SinglePak_OffsetTable]; } if (Context.Settings.EngineVersion == EngineVersion.GBA_SplinterCell_NGage) { if (Block == null) { return(root + Offsets[index]); } else { if (Block.DecompressedBlockOffset != null) { return(Block.DecompressedBlockOffset + Offsets[index]); } else { return(Block.Offset + Offsets[index]); } } } else { if (isRelativeOffset && Block != null) { return(Block.Offset + Offsets[index]); } else { return(root + (Offsets[index] * 4)); } } }
/// <summary> /// Handles the data serialization /// </summary> /// <param name="s">The serializer object</param> public override void SerializeImpl(SerializerObject s) { // Serialize ROM header base.SerializeImpl(s); // Get the pointer table var pointerTable = PointerTables.R1_GBA_PointerTable(s.GameSettings.GameModeSelection, this.Offset.file); s.DoAt(pointerTable[R1_GBA_ROMPointer.WorldLevelOffsetTable], () => WorldLevelOffsetTable = s.SerializeArray <byte>(WorldLevelOffsetTable, 12, name: nameof(WorldLevelOffsetTable))); // Get the global level index var levelIndex = WorldLevelOffsetTable[s.GameSettings.World] + (s.GameSettings.Level - 1); // Hardcode files if (s is BinaryDeserializer && s.GameSettings.R1_World == R1_World.Image && s.GameSettings.Level == 4) { s.DoAt(Offset + 0x55cc, () => { void CreateFakeFile(int index, int size) { uint memAddress = s.Serialize <uint>(default, name: nameof(memAddress));
// TODO: Find the way the game gets the vignette offsets public override async UniTask ExtractVignetteAsync(GameSettings settings, string outputDir) { // Create a context using (var context = new Context(settings)) { // Load the ROM await LoadFilesAsync(context); // Get the file var file = context.GetFile(GetROMFilePath(context)); // Get the deserialize var s = context.Deserializer; var pointerTable = PointerTables.GBA_PointerTable(context, file); int vigCount = settings.GameModeSelection == GameModeSelection.Rayman3GBAUSPrototype ? 18 : 20; var palettes = new ARGB1555Color[vigCount][]; for (int i = 0; i < vigCount; i++) { palettes[i] = s.DoAt(pointerTable[GBA_Pointer.VignettePalettes] + (512 * i), () => s.SerializeObjectArray <ARGB1555Color>(default, 256));
/// <summary> /// Handles the data serialization /// </summary> /// <param name="s">The serializer object</param> public override void SerializeImpl(SerializerObject s) { // Serialize ROM header base.SerializeImpl(s); var pointerTable = PointerTables.GBAIsometric_RHR_PointerTable(s.GameSettings.GameModeSelection, Offset.file); // Serialize localization Localization = s.DoAt(pointerTable[GBAIsometric_RHR_Pointer.Localization], () => s.SerializeObject <GBAIsometric_RHR_Localization>(Localization, name: nameof(Localization))); if (s.GameSettings.World == 0) { // Serialize level infos s.DoAt(pointerTable[GBAIsometric_RHR_Pointer.Levels], () => { if (LevelInfos == null) { LevelInfos = new GBAIsometric_RHR_LevelInfo[20]; } for (int i = 0; i < LevelInfos.Length; i++) { LevelInfos[i] = s.SerializeObject(LevelInfos[i], x => x.SerializeData = i == s.GameSettings.Level, name: $"{nameof(LevelInfos)}[{i}]"); } }); PaletteAnimations = new GBAIsometric_RHR_PaletteAnimationTable[3]; s.DoAt(pointerTable[GBAIsometric_RHR_Pointer.PaletteAnimations0], () => { PaletteAnimations[0] = s.SerializeObject <GBAIsometric_RHR_PaletteAnimationTable>(PaletteAnimations[0], name: $"{nameof(PaletteAnimations)}[0]"); }); s.DoAt(pointerTable[GBAIsometric_RHR_Pointer.PaletteAnimations1], () => { PaletteAnimations[1] = s.SerializeObject <GBAIsometric_RHR_PaletteAnimationTable>(PaletteAnimations[1], name: $"{nameof(PaletteAnimations)}[1]"); }); s.DoAt(pointerTable[GBAIsometric_RHR_Pointer.PaletteAnimations2], () => { PaletteAnimations[2] = s.SerializeObject <GBAIsometric_RHR_PaletteAnimationTable>(PaletteAnimations[2], name: $"{nameof(PaletteAnimations)}[2]"); }); // Serialize object types ObjectTypes = s.DoAt(pointerTable[GBAIsometric_RHR_Pointer.ObjTypes], () => s.SerializeObjectArray <GBAIsometric_ObjectType>(ObjectTypes, 105, name: nameof(ObjectTypes))); // Serialize the crab type and add to the array (the crab entry points to memory) ObjectTypes[13].Data = s.DoAt(pointerTable[GBAIsometric_RHR_Pointer.CrabObjType], () => s.SerializeObject <GBAIsometric_ObjectTypeData>(ObjectTypes[13].Data, name: $"CrabObjectTypeData")); // Serialize additional object types var additionalObjTypePointers = ObjTypePointers[s.GameSettings.GameModeSelection]; if (AdditionalObjectTypes == null) { AdditionalObjectTypes = new GBAIsometric_ObjectTypeData[additionalObjTypePointers.Length]; } for (int i = 0; i < AdditionalObjectTypes.Length; i++) { AdditionalObjectTypes[i] = s.DoAt(new Pointer(additionalObjTypePointers[i], Offset.file), () => s.SerializeObject <GBAIsometric_ObjectTypeData>(AdditionalObjectTypes[i], name: $"{nameof(AdditionalObjectTypes)}[{i}]")); } // Serialize additional animation sets var additionalAnimSetPointers = AnimSetPointers[s.GameSettings.GameModeSelection]; if (AdditionalAnimSets == null) { AdditionalAnimSets = new GBAIsometric_RHR_AnimSet[additionalAnimSetPointers.Length]; } for (int i = 0; i < AdditionalAnimSets.Length; i++) { AdditionalAnimSets[i] = s.DoAt(new Pointer(additionalAnimSetPointers[i], Offset.file), () => s.SerializeObject <GBAIsometric_RHR_AnimSet>(AdditionalAnimSets[i], name: $"{nameof(AdditionalAnimSets)}[{i}]")); } // Serialize sprite sets var spriteSetPointers = SpriteSetPointers[s.GameSettings.GameModeSelection]; if (SpriteSets == null) { SpriteSets = new GBAIsometric_RHR_SpriteSet[spriteSetPointers.Length]; } for (int i = 0; i < SpriteSets.Length; i++) { SpriteSets[i] = s.DoAt(new Pointer(spriteSetPointers[i], Offset.file), () => s.SerializeObject <GBAIsometric_RHR_SpriteSet>(SpriteSets[i], name: $"{nameof(SpriteSets)}[{i}]")); } // Serialize sprites var spritePointers = SpritePointers[s.GameSettings.GameModeSelection]; if (Sprites == null) { Sprites = new GBAIsometric_RHR_Sprite[spritePointers.Length]; } for (int i = 0; i < Sprites.Length; i++) { Sprites[i] = s.DoAt(new Pointer(spritePointers[i], Offset.file), () => s.SerializeObject <GBAIsometric_RHR_Sprite>(Sprites[i], name: $"{nameof(Sprites)}[{i}]")); } // Serialize sprite icons SpriteIconPointers = s.DoAt(pointerTable[GBAIsometric_RHR_Pointer.SpriteIcons], () => s.SerializePointerArray(SpriteIconPointers, 84, name: nameof(SpriteIconPointers))); if (SpriteIcons == null) { SpriteIcons = new GBAIsometric_RHR_Sprite[SpriteIconPointers.Length]; } for (int i = 0; i < SpriteIcons.Length; i++) { SpriteIcons[i] = s.DoAt(SpriteIconPointers[i], () => s.SerializeObject <GBAIsometric_RHR_Sprite>(SpriteIcons[i], name: $"{nameof(SpriteIcons)}[{i}]")); } // Serialize flag sprites FlagSpritesUS = s.DoAt(pointerTable[GBAIsometric_RHR_Pointer.SpriteFlagsUS], () => s.SerializeObjectArray <GBAIsometric_RHR_FlagSprite>(FlagSpritesUS, 3, name: nameof(FlagSpritesUS))); FlagSpritesEU = s.DoAt(pointerTable[GBAIsometric_RHR_Pointer.SpriteFlagsEU], () => s.SerializeObjectArray <GBAIsometric_RHR_FlagSprite>(FlagSpritesEU, 6, name: nameof(FlagSpritesEU))); // Serialize font Font0 = s.DoAt(pointerTable[GBAIsometric_RHR_Pointer.Font0], () => s.SerializeObject <GBAIsometric_RHR_Font>(Font0, name: nameof(Font0))); Font1 = s.DoAt(pointerTable[GBAIsometric_RHR_Pointer.Font1], () => s.SerializeObject <GBAIsometric_RHR_Font>(Font1, name: nameof(Font1))); Font2 = s.DoAt(pointerTable[GBAIsometric_RHR_Pointer.Font2], () => s.SerializeObject <GBAIsometric_RHR_Font>(Font2, name: nameof(Font2))); // Serialize portraits PortraitPointers = s.DoAt(pointerTable[GBAIsometric_RHR_Pointer.Portraits], () => s.SerializePointerArray(PortraitPointers, 10, name: nameof(PortraitPointers))); if (Portraits == null) { Portraits = new GBAIsometric_RHR_AnimSet[PortraitPointers.Length]; } for (int i = 0; i < Portraits.Length; i++) { Portraits[i] = s.DoAt(PortraitPointers[i], () => s.SerializeObject <GBAIsometric_RHR_AnimSet>(Portraits[i], name: $"{nameof(Portraits)}[{i}]")); } // Serialize alternative anim set palettes var alternativeAnimSetPalettes = AlternativeAnimSetPalettes[s.GameSettings.GameModeSelection]; foreach (GBAIsometric_RHR_AnimSet animSet in GetAllAnimSets().Where(x => alternativeAnimSetPalettes.ContainsKey(x.Name))) { animSet.SerializeAlternativePalettes(s, alternativeAnimSetPalettes[animSet.Name]); } } else { var maps = ((GBAIsometric_RHR_Manager)s.GameSettings.GetGameManager).GetMenuMaps(s.GameSettings.Level); MenuMaps = new GBAIsometric_RHR_MapLayer[maps.Length]; for (int i = 0; i < MenuMaps.Length; i++) { MenuMaps[i] = s.DoAt(pointerTable[maps[i]], () => s.SerializeObject <GBAIsometric_RHR_MapLayer>(default, name: $"{maps[i]}"));
/// <summary> /// Handles the data serialization /// </summary> /// <param name="s">The serializer object</param> public override void SerializeImpl(SerializerObject s) { // Get the pointer table var pointerTable = PointerTables.R1_DSi_PointerTable(s.GameSettings.GameModeSelection, this.Offset.file); s.DoAt(pointerTable[R1_DSi_Pointer.WorldLevelOffsetTable], () => WorldLevelOffsetTable = s.SerializeArray <byte>(WorldLevelOffsetTable, 8, name: nameof(WorldLevelOffsetTable))); // Get the global level index var levelIndex = WorldLevelOffsetTable[s.GameSettings.World] + (s.GameSettings.Level - 1); DES_Ray = s.DoAt(pointerTable[R1_DSi_Pointer.DES_Ray], () => s.SerializeObject <R1_GBA_EventGraphicsData>(DES_Ray, name: nameof(DES_Ray))); ETA_Ray = s.DoAt(pointerTable.TryGetItem(R1_DSi_Pointer.ETA_Ray), () => s.SerializeObject <R1_GBA_ETA>(ETA_Ray, x => x.Lengths = new byte[] { 66, 12, 34, 53, 14, 14, 1, 2 }, name: nameof(ETA_Ray))); DES_RayLittle = s.DoAt(pointerTable[R1_DSi_Pointer.DES_RayLittle], () => s.SerializeObject <R1_GBA_EventGraphicsData>(DES_RayLittle, name: nameof(DES_RayLittle))); DES_Clock = s.DoAt(pointerTable[R1_DSi_Pointer.DES_Clock], () => s.SerializeObject <R1_GBA_EventGraphicsData>(DES_Clock, name: nameof(DES_Clock))); ETA_Clock = s.DoAt(pointerTable.TryGetItem(R1_DSi_Pointer.ETA_Clock), () => s.SerializeObject <R1_GBA_ETA>(ETA_Clock, x => x.Lengths = new byte[] { 3 }, name: nameof(ETA_Clock))); DES_Div = s.DoAt(pointerTable[R1_DSi_Pointer.DES_Div], () => s.SerializeObject <R1_GBA_EventGraphicsData>(DES_Div, name: nameof(DES_Div))); ETA_Div = s.DoAt(pointerTable.TryGetItem(R1_DSi_Pointer.ETA_Div), () => s.SerializeObject <R1_GBA_ETA>(ETA_Div, x => x.Lengths = new byte[] { 1, 1, 1, 1, 1, 1, 2, 2, 12, 12, 4 }, name: nameof(ETA_Div))); DES_Map = s.DoAt(pointerTable[R1_DSi_Pointer.DES_Map], () => s.SerializeObject <R1_GBA_EventGraphicsData>(DES_Map, name: nameof(DES_Map))); ETA_Map = s.DoAt(pointerTable.TryGetItem(R1_DSi_Pointer.ETA_Map), () => s.SerializeObject <R1_GBA_ETA>(ETA_Map, x => x.Lengths = new byte[] { 64, 1, 19, 1, 1, 69, 3 }, name: nameof(ETA_Map))); // Serialize data from the ROM if (s.GameSettings.R1_World != R1_World.Menu) { s.DoAt((s.GameSettings.R1_World == R1_World.Jungle ? pointerTable[R1_DSi_Pointer.JungleMaps] : pointerTable[R1_DSi_Pointer.LevelMaps]) + (levelIndex * 32), () => LevelMapData = s.SerializeObject <R1_GBA_LevelMapData>(LevelMapData, name: nameof(LevelMapData))); } s.DoAt(pointerTable[R1_DSi_Pointer.BackgroundVignette], () => BackgroundVignettes = s.SerializeObjectArray <R1_GBA_BackgroundVignette>(BackgroundVignettes, 48, name: nameof(BackgroundVignettes))); WorldMapVignette = s.SerializeObject <R1_GBA_WorldMapVignette>(WorldMapVignette, name: nameof(WorldMapVignette)); // Serialize the level event data if (s.GameSettings.R1_World != R1_World.Menu) { LevelEventData = new R1_GBA_LevelEventData(); LevelEventData.SerializeData(s, pointerTable[R1_DSi_Pointer.EventGraphicsPointers], pointerTable[R1_DSi_Pointer.EventDataPointers], pointerTable[R1_DSi_Pointer.EventGraphicsGroupCountTablePointers], pointerTable[R1_DSi_Pointer.LevelEventGraphicsGroupCounts]); } s.DoAt(pointerTable[R1_DSi_Pointer.SpecialPalettes], () => Palettes = s.SerializeObjectArray <R1_DSi_PaletteReference>(Palettes, 10, name: nameof(Palettes))); // Serialize strings s.DoAt(pointerTable[R1_DSi_Pointer.StringPointers], () => { StringPointerTable = s.SerializePointerArray(StringPointerTable, 5 * 394, name: nameof(StringPointerTable)); if (Strings == null) { Strings = new string[5][]; } var enc = new Encoding[] { // Spanish Encoding.GetEncoding(1252), // English Encoding.GetEncoding(437), // French Encoding.GetEncoding(1252), // Italian Encoding.GetEncoding(1252), // German Encoding.GetEncoding(437), }; for (int i = 0; i < Strings.Length; i++) { if (Strings[i] == null) { Strings[i] = new string[394]; } for (int j = 0; j < Strings[i].Length; j++) { s.DoAt(StringPointerTable[i * 394 + j], () => Strings[i][j] = s.SerializeString(Strings[i][j], encoding: enc[i], name: $"{nameof(Strings)}[{i}][{j}]")); } } }); // Serialize tables s.DoAt(pointerTable[R1_DSi_Pointer.TypeZDC], () => TypeZDC = s.SerializeObjectArray <R1_ZDCEntry>(TypeZDC, 262, name: nameof(TypeZDC))); s.DoAt(pointerTable[R1_DSi_Pointer.ZdcData], () => ZdcData = s.SerializeObjectArray <R1_ZDCData>(ZdcData, 200, name: nameof(ZdcData))); s.DoAt(pointerTable[R1_DSi_Pointer.EventFlags], () => EventFlags = s.SerializeArray <R1_EventFlags>(EventFlags, 262, name: nameof(EventFlags))); if (s.GameSettings.R1_World != R1_World.Menu) { WorldVignetteIndicesPointers = s.DoAt(pointerTable[R1_DSi_Pointer.WorldVignetteIndices], () => s.SerializePointerArray(WorldVignetteIndicesPointers, 7, name: nameof(WorldVignetteIndicesPointers))); WorldVignetteIndices = s.DoAt(WorldVignetteIndicesPointers[s.GameSettings.World], () => s.SerializeArray <byte>(WorldVignetteIndices, 8, name: nameof(WorldVignetteIndices))); // The max size is 8 // Get the background indices s.DoAt(pointerTable[R1_DSi_Pointer.LevelMapsBGIndices] + (levelIndex * 32), () => { LevelMapData.Unk_10 = s.Serialize <byte>(LevelMapData.Unk_10, name: nameof(LevelMapData.Unk_10)); LevelMapData.Unk_11 = s.Serialize <byte>(LevelMapData.Unk_11, name: nameof(LevelMapData.Unk_11)); LevelMapData.BackgroundIndex = s.Serialize <byte>(LevelMapData.BackgroundIndex, name: nameof(LevelMapData.BackgroundIndex)); LevelMapData.ParallaxBackgroundIndex = s.Serialize <byte>(LevelMapData.ParallaxBackgroundIndex, name: nameof(LevelMapData.ParallaxBackgroundIndex)); }); } WorldInfos = s.DoAt(pointerTable[R1_DSi_Pointer.WorldInfo], () => s.SerializeObjectArray <R1_WorldMapInfo>(WorldInfos, 24, name: nameof(WorldInfos))); }
/// <summary> /// Handles the data serialization /// </summary> /// <param name="s">The serializer object</param> public override void SerializeImpl(SerializerObject s) { // Get info var pointerTable = s.GameSettings.EngineVersion != EngineVersion.R1Jaguar_Proto ? PointerTables.JaguarR1_PointerTable(s.GameSettings.EngineVersion, this.Offset.file) : null; var manager = (R1Jaguar_Manager)s.GameSettings.GetGameManager; var levels = manager.GetNumLevels; // Serialize the references for the prototype if (s.GameSettings.EngineVersion == EngineVersion.R1Jaguar_Proto) { s.DoAt(new Pointer(0x8BB6A8, Offset.file), () => { References = s.SerializeObjectArray <R1Jaguar_ReferenceEntry>(References, 1676, onPreSerialize: (x => x.StringBase = new Pointer(0x8C0538, Offset.file)), name: nameof(References)); // Unknown initial 4 bytes, part of the string table UnkReferenceValue = s.Serialize <uint>(UnkReferenceValue, name: nameof(UnkReferenceValue)); }); } // Serialize event definition data if (s.GameSettings.EngineVersion == EngineVersion.R1Jaguar) { if (!s.Context.FileExists("RAM_EventDefinitions")) { // Copied to 0x001f9000 in memory. All pointers to 0x001Fxxxx likely point to an entry in this table s.DoAt(pointerTable[JaguarR1_Pointer.EventDefinitions], () => { byte[] EventDefsDataBytes = s.SerializeArray <byte>(null, manager.EventCount * 0x28, name: nameof(EventDefsDataBytes)); var file = new MemoryMappedByteArrayFile("RAM_EventDefinitions", EventDefsDataBytes, s.Context, 0x001f9000) { Endianness = BinaryFile.Endian.Big }; s.Context.AddFile(file); s.DoAt(file.StartPointer, () => EventDefinitions = s.SerializeObjectArray <R1Jaguar_EventDefinition>(EventDefinitions, manager.EventCount, name: nameof(EventDefinitions))); }); } } else { var offset = s.GameSettings.EngineVersion == EngineVersion.R1Jaguar_Proto ? GetProtoDataPointer(R1Jaguar_Proto_References.MS_rayman) : pointerTable[JaguarR1_Pointer.EventDefinitions]; // Pointers all point to the ROM, not RAM s.DoAt(offset, () => EventDefinitions = s.SerializeObjectArray <R1Jaguar_EventDefinition>(EventDefinitions, manager.EventCount, name: nameof(EventDefinitions))); } if (AdditionalEventDefinitions == null) { if (s.GameSettings.EngineVersion != EngineVersion.R1Jaguar_Proto) { AdditionalEventDefinitions = manager.AdditionalEventDefinitionPointers.Select(p => { return(s.DoAt(new Pointer(p, pointerTable[JaguarR1_Pointer.EventDefinitions].file), () => s.SerializeObject <R1Jaguar_EventDefinition>(default, name: nameof(AdditionalEventDefinitions))));
public override void SerializeImpl(SerializerObject s) { // Serialize ROM header base.SerializeImpl(s); // Get pointer table var pointerTable = PointerTables.GBARRR_PointerTable(s.GameSettings.GameModeSelection, Offset.file); // Serialize offset table OffsetTable = s.DoAt(pointerTable[GBARRR_Pointer.OffsetTable], () => s.SerializeObject <GBARRR_OffsetTable>(OffsetTable, name: nameof(OffsetTable))); // Serialize localization OffsetTable.DoAtBlock(s.Context, 3, size => Localization = s.SerializeObject <GBARRR_LocalizationBlock>(Localization, name: nameof(Localization))); var gameMode = GBA_RRR_Manager.GetCurrentGameMode(s.GameSettings); if (gameMode == GBA_RRR_Manager.GameMode.Game || gameMode == GBA_RRR_Manager.GameMode.Village) { // Serialize level info VillageLevelInfo = s.DoAt(pointerTable[GBARRR_Pointer.VillageLevelInfo], () => s.SerializeObjectArray <GBARRR_LevelInfo>(VillageLevelInfo, 3, name: nameof(VillageLevelInfo))); LevelInfo = s.DoAt(pointerTable[GBARRR_Pointer.LevelInfo], () => s.SerializeObjectArray <GBARRR_LevelInfo>(LevelInfo, 32, name: nameof(LevelInfo))); LevelProperties = s.DoAt(pointerTable[GBARRR_Pointer.LevelProperties], () => s.SerializeObjectArray <GBARRR_LevelProperties>(LevelProperties, 32, name: nameof(LevelProperties))); // Get the current level info var lvlInfo = GetLevelInfo(s.GameSettings); // Serialize tile maps OffsetTable.DoAtBlock(s.Context, lvlInfo.LevelTilesetIndex, size => LevelTileset = s.SerializeObject <GBARRR_Tileset>(LevelTileset, name: nameof(LevelTileset), onPreSerialize: x => x.BlockSize = size)); OffsetTable.DoAtBlock(s.Context, lvlInfo.BG0TilesetIndex, size => BG0TileSet = s.SerializeObject <GBARRR_Tileset>(BG0TileSet, name: nameof(BG0TileSet), onPreSerialize: x => x.BlockSize = size)); OffsetTable.DoAtBlock(s.Context, lvlInfo.FGTilesetIndex, size => FGTileSet = s.SerializeObject <GBARRR_Tileset>(FGTileSet, name: nameof(FGTileSet), onPreSerialize: x => x.BlockSize = size)); OffsetTable.DoAtBlock(s.Context, lvlInfo.BG1TilesetIndex, size => BG1TileSet = s.SerializeObject <GBARRR_Tileset>(BG1TileSet, name: nameof(BG1TileSet), onPreSerialize: x => x.BlockSize = size)); // Serialize level scene OffsetTable.DoAtBlock(s.Context, lvlInfo.ObjectArrayIndex, size => ObjectArray = s.SerializeObject <GBARRR_ObjectArray>(ObjectArray, name: nameof(ObjectArray))); // Serialize maps OffsetTable.DoAtBlock(s.Context, lvlInfo.BG0MapIndex, size => BG0Map = s.SerializeObject <GBARRR_BGMapBlock>(BG0Map, name: nameof(BG0Map))); OffsetTable.DoAtBlock(s.Context, lvlInfo.BG1MapIndex, size => BG1Map = s.SerializeObject <GBARRR_BGMapBlock>(BG1Map, name: nameof(BG1Map))); OffsetTable.DoAtBlock(s.Context, lvlInfo.CollisionMapIndex, size => CollisionMap = s.SerializeObject <GBARRR_MapBlock>(CollisionMap, name: nameof(CollisionMap), onPreSerialize: x => x.Type = GBARRR_MapBlock.MapType.Collision)); OffsetTable.DoAtBlock(s.Context, lvlInfo.LevelMapIndex, size => LevelMap = s.SerializeObject <GBARRR_MapBlock>(LevelMap, name: nameof(LevelMap), onPreSerialize: x => x.Type = GBARRR_MapBlock.MapType.Tiles)); OffsetTable.DoAtBlock(s.Context, lvlInfo.FGMapIndex, size => FGMap = s.SerializeObject <GBARRR_MapBlock>(FGMap, name: nameof(FGMap), onPreSerialize: x => x.Type = GBARRR_MapBlock.MapType.Foreground)); // Serialize palettes var tilePalIndex = GetLevelTilePaletteOffsetIndex(s.GameSettings); if (tilePalIndex != null) { OffsetTable.DoAtBlock(s.Context, tilePalIndex.Value, size => TilePalette = s.SerializeObjectArray <RGBA5551Color>(TilePalette, 0x100, name: nameof(TilePalette))); } OffsetTable.DoAtBlock(s.Context, lvlInfo.SpritePaletteIndex, size => SpritePalette = s.SerializeObjectArray <RGBA5551Color>(SpritePalette, 0x100, name: nameof(SpritePalette))); if (AnimatedPalettes == null) { AnimatedPalettes = new RGBA5551Color[5][]; } for (int i = 0; i < AnimatedPalettes.Length; i++) { OffsetTable.DoAtBlock(s.Context, 764 + i, size => AnimatedPalettes[i] = s.SerializeObjectArray <RGBA5551Color>(AnimatedPalettes[i], 0x100, name: $"{nameof(AnimatedPalettes)}[{i}]")); } // Serialize tables s.DoAt(pointerTable[GBARRR_Pointer.GraphicsTables], () => { var counts = new uint[] { 0x47, 0x40, 0x45, 0x44, 0x50, 0x42 }; if (GraphicsTable0 == null) { GraphicsTable0 = new GBARRR_GraphicsTableEntry[counts.Length][]; } if (GraphicsTable1 == null) { GraphicsTable1 = new uint[counts.Length][]; } if (GraphicsTable2 == null) { GraphicsTable2 = new uint[counts.Length][]; } if (GraphicsTable3 == null) { GraphicsTable3 = new uint[counts.Length][]; } if (GraphicsTable4 == null) { GraphicsTable4 = new uint[counts.Length][]; } for (int i = 0; i < counts.Length; i++) { GraphicsTable0[i] = s.SerializeObjectArray <GBARRR_GraphicsTableEntry>(GraphicsTable0[i], counts[i], name: $"{nameof(GraphicsTable0)}[{i}]"); GraphicsTable1[i] = s.SerializeArray <uint>(GraphicsTable1[i], counts[i], name: $"{nameof(GraphicsTable1)}[{i}]"); GraphicsTable2[i] = s.SerializeArray <uint>(GraphicsTable2[i], counts[i], name: $"{nameof(GraphicsTable2)}[{i}]"); GraphicsTable3[i] = s.SerializeArray <uint>(GraphicsTable3[i], counts[i], name: $"{nameof(GraphicsTable3)}[{i}]"); GraphicsTable4[i] = s.SerializeArray <uint>(GraphicsTable4[i], counts[i], name: $"{nameof(GraphicsTable4)}[{i}]"); if (i == 2 || i == 3) { s.Serialize <uint>(1, name: "Padding"); } } }); } else if (gameMode == GBA_RRR_Manager.GameMode.Mode7) { // Serialize pointer tables Mode7_MapTilesPointers = s.DoAt(pointerTable[GBARRR_Pointer.Mode7_MapTiles], () => s.SerializePointerArray(Mode7_MapTilesPointers, 3, name: nameof(Mode7_MapTilesPointers))); Mode7_BG1TilesPointers = s.DoAt(pointerTable[GBARRR_Pointer.Mode7_BG1Tiles], () => s.SerializePointerArray(Mode7_BG1TilesPointers, 3, name: nameof(Mode7_BG1TilesPointers))); Mode7_BG1MapPointers = s.DoAt(pointerTable[GBARRR_Pointer.Mode7_Bg1Map], () => s.SerializePointerArray(Mode7_BG1MapPointers, 3, name: nameof(Mode7_BG1MapPointers))); Mode7_BG0TilesPointers = s.DoAt(pointerTable[GBARRR_Pointer.Mode7_BG0Tiles], () => s.SerializePointerArray(Mode7_BG0TilesPointers, 3, name: nameof(Mode7_BG0TilesPointers))); Mode7_BG0MapPointers = s.DoAt(pointerTable[GBARRR_Pointer.Mode7_BG0Map], () => s.SerializePointerArray(Mode7_BG0MapPointers, 3, name: nameof(Mode7_BG0MapPointers))); Mode7_MapPointers = s.DoAt(pointerTable[GBARRR_Pointer.Mode7_MapData], () => s.SerializePointerArray(Mode7_MapPointers, 3, name: nameof(Mode7_MapPointers))); Mode7_CollisionMapDataPointers = s.DoAt(pointerTable[GBARRR_Pointer.Mode7_CollisionMapData], () => s.SerializePointerArray(Mode7_CollisionMapDataPointers, 3, name: nameof(Mode7_CollisionMapDataPointers))); Mode7_MapPalettePointers = s.DoAt(pointerTable[GBARRR_Pointer.Mode7_TilePalette], () => s.SerializePointerArray(Mode7_MapPalettePointers, 3, name: nameof(Mode7_MapPalettePointers))); Mode7_BG1PalettePointers = s.DoAt(pointerTable[GBARRR_Pointer.Mode7_BG1Palette], () => s.SerializePointerArray(Mode7_BG1PalettePointers, 3, name: nameof(Mode7_BG1PalettePointers))); Mode7_BG0PalettePointers = s.DoAt(pointerTable[GBARRR_Pointer.Mode7_BG0Palette], () => s.SerializePointerArray(Mode7_BG0PalettePointers, 3, name: nameof(Mode7_BG0PalettePointers))); Mode7_ObjectsPointers = s.DoAt(pointerTable[GBARRR_Pointer.Mode7_Objects], () => s.SerializePointerArray(Mode7_ObjectsPointers, 3, name: nameof(Mode7_ObjectsPointers))); Mode7_CollisionTypesPointers = s.DoAt(pointerTable[GBARRR_Pointer.Mode7_CollisionTypesArray], () => s.SerializePointerArray(Mode7_CollisionTypesPointers, 3, name: nameof(Mode7_CollisionTypesPointers))); Mode7_WaypointsCount = s.DoAt(pointerTable[GBARRR_Pointer.Mode7_WaypointsCount], () => s.SerializeArray <short>(Mode7_WaypointsCount, 3, name: nameof(Mode7_WaypointsCount))); Mode7_WaypointsPointers = s.DoAt(pointerTable[GBARRR_Pointer.Mode7_Waypoints], () => s.SerializePointerArray(Mode7_WaypointsPointers, 3, name: nameof(Mode7_WaypointsPointers))); // Serialize compressed tile data s.DoAt(Mode7_MapTilesPointers[s.GameSettings.Level], () => { s.DoEncoded(new RNCEncoder(hasHeader: false), () => Mode7_MapTiles = s.SerializeArray <byte>(Mode7_MapTiles, s.CurrentLength, name: nameof(Mode7_MapTiles))); }); s.DoAt(Mode7_BG0TilesPointers[s.GameSettings.Level], () => { s.DoEncoded(new RNCEncoder(hasHeader: false), () => Mode7_BG0Tiles = s.SerializeArray <byte>(Mode7_BG0Tiles, s.CurrentLength, name: nameof(Mode7_BG0Tiles))); }); s.DoAt(Mode7_BG1TilesPointers[s.GameSettings.Level], () => { s.DoEncoded(new RNCEncoder(hasHeader: false), () => Mode7_BG1Tiles = s.SerializeArray <byte>(Mode7_BG1Tiles, s.CurrentLength, name: nameof(Mode7_BG1Tiles))); }); // Serialize map data if (s.GameSettings.GameModeSelection == GameModeSelection.RaymanRavingRabbidsGBAEU) { Mode7_MapData = s.DoAt(Mode7_MapPointers[s.GameSettings.Level], () => s.SerializeObjectArray <MapTile>(Mode7_MapData, 256 * 256, onPreSerialize: x => x.GBARRRType = GBARRR_MapBlock.MapType.Mode7Tiles, name: nameof(Mode7_MapData))); } else { s.DoAt(Mode7_MapPointers[s.GameSettings.Level], () => { s.DoEncoded(new RNCEncoder(hasHeader: false), () => Mode7_MapData = s.SerializeObjectArray <MapTile>(Mode7_MapData, 256 * 256, onPreSerialize: x => x.GBARRRType = GBARRR_MapBlock.MapType.Mode7Tiles, name: nameof(Mode7_MapData))); }); } s.DoAt(Mode7_BG0MapPointers[s.GameSettings.Level], () => { s.DoEncoded(new RNCEncoder(hasHeader: false), () => Mode7_BG0MapData = s.SerializeObjectArray <MapTile>(Mode7_BG0MapData, 32 * 32, onPreSerialize: x => x.GBARRRType = GBARRR_MapBlock.MapType.Foreground, name: nameof(Mode7_BG0MapData))); }); s.DoAt(Mode7_BG1MapPointers[s.GameSettings.Level], () => { s.DoEncoded(new RNCEncoder(hasHeader: false), () => Mode7_BG1MapData = s.SerializeObjectArray <MapTile>(Mode7_BG1MapData, 32 * 32, onPreSerialize: x => x.GBARRRType = GBARRR_MapBlock.MapType.Foreground, name: nameof(Mode7_BG1MapData))); }); s.DoAt(Mode7_ObjectsPointers[s.GameSettings.Level], () => { s.DoEncoded(new RNCEncoder(hasHeader: false), () => Mode7_Objects = s.SerializeObjectArray <GBARRR_Mode7Object>(Mode7_Objects, 141, name: nameof(Mode7_Objects))); }); if (s.GameSettings.GameModeSelection == GameModeSelection.RaymanRavingRabbidsGBAEU) { s.DoAt(Mode7_CollisionMapDataPointers[s.GameSettings.Level], () => { Mode7_CollisionMapData = s.SerializeArray <ushort>(Mode7_CollisionMapData, 256 * 256, name: nameof(Mode7_CollisionMapData)); }); } else { s.DoAt(Mode7_CollisionMapDataPointers[s.GameSettings.Level], () => { s.DoEncoded(new RNCEncoder(hasHeader: false), () => Mode7_CollisionMapData = s.SerializeArray <ushort>(Mode7_CollisionMapData, 256 * 256, name: nameof(Mode7_CollisionMapData))); }); } s.DoAt(Mode7_CollisionTypesPointers[s.GameSettings.Level], () => { s.DoEncoded(new RNCEncoder(hasHeader: false), () => Mode7_CollisionTypes = s.SerializeArray <byte>(Mode7_CollisionTypes, s.CurrentLength, name: nameof(Mode7_CollisionTypes))); }); s.DoAt(Mode7_WaypointsPointers[s.GameSettings.Level], () => { Mode7_Waypoints = s.SerializeObjectArray <GBARRR_Mode7Waypoint>(Mode7_Waypoints, Mode7_WaypointsCount[s.GameSettings.Level], name: nameof(Mode7_Waypoints)); }); // Serialize palettes Mode7_MapPalette = s.DoAt(Mode7_MapPalettePointers[s.GameSettings.Level], () => s.SerializeObjectArray <RGBA5551Color>(Mode7_MapPalette, 16 * 16, name: nameof(Mode7_MapPalette))); Mode7_BG1Palette = s.DoAt(Mode7_BG1PalettePointers[s.GameSettings.Level], () => s.SerializeObjectArray <RGBA5551Color>(Mode7_BG1Palette, 16, name: nameof(Mode7_BG1Palette))); Mode7_BG0Palette = s.DoAt(Mode7_BG0PalettePointers[s.GameSettings.Level], () => s.SerializeObjectArray <RGBA5551Color>(Mode7_BG0Palette, 16, name: nameof(Mode7_BG0Palette))); // Fill in full tilemap palette Mode7_TilemapPalette = new RGBA5551Color[16 * 16]; for (int i = 0; i < 12 * 16; i++) { Mode7_TilemapPalette[i] = Mode7_MapPalette[i]; } for (int i = 0; i < 16; i++) { Mode7_TilemapPalette[12 * 16 + i] = Mode7_BG0Palette[i]; } for (int i = 0; i < 16; i++) { Mode7_TilemapPalette[14 * 16 + i] = Mode7_BG1Palette[i]; } } else if (gameMode == GBA_RRR_Manager.GameMode.Mode7Unused) { OffsetTable.DoAtBlock(s.Context, 1180, size => { ObjectArray = s.SerializeObject <GBARRR_ObjectArray>(ObjectArray, onPreSerialize: x => x.IsUnusedMode7 = true, name: nameof(ObjectArray)); Mode7_MapData = s.SerializeObjectArray <MapTile>(Mode7_MapData, 256 * 256, onPreSerialize: x => x.GBARRRType = GBARRR_MapBlock.MapType.Foreground, name: nameof(Mode7_MapData)); }); OffsetTable.DoAtBlock(s.Context, 1181, size => CollisionMap = s.SerializeObject <GBARRR_MapBlock>(CollisionMap, name: nameof(CollisionMap), onPreSerialize: x => x.Type = GBARRR_MapBlock.MapType.Collision)); OffsetTable.DoAtBlock(s.Context, 1177, size => BG0TileSet = s.SerializeObject <GBARRR_Tileset>(BG0TileSet, onPreSerialize: x => x.BlockSize = size, name: nameof(BG0TileSet))); OffsetTable.DoAtBlock(s.Context, 1178, size => BG1TileSet = s.SerializeObject <GBARRR_Tileset>(BG1TileSet, onPreSerialize: x => x.BlockSize = size, name: nameof(BG1TileSet))); OffsetTable.DoAtBlock(s.Context, 1179, size => LevelTileset = s.SerializeObject <GBARRR_Tileset>(LevelTileset, onPreSerialize: x => x.BlockSize = size, name: nameof(LevelTileset))); } else if (gameMode == GBA_RRR_Manager.GameMode.Menu) { Menu_Pointers = s.DoAt(pointerTable[GBARRR_Pointer.MenuArray], () => s.SerializePointerArray(Menu_Pointers, 15 * 3, name: nameof(Menu_Pointers))); var manager = (GBA_RRR_Manager)s.GameSettings.GetGameManager; var menuLevels = manager.GetMenuLevels(s.GameSettings.Level); Menu_Tiles = new byte[menuLevels.Length][]; Menu_MapData = new MapTile[menuLevels.Length][]; Menu_Palette = new RGBA5551Color[menuLevels.Length][]; for (int i = 0; i < menuLevels.Length; i++) { var lvl = menuLevels[i]; var size = manager.GetMenuSize(lvl); var isCompressed = manager.IsMenuCompressed(lvl); var mapType = manager.HasMenuAlphaBlending(lvl) ? GBARRR_MapBlock.MapType.Menu : GBARRR_MapBlock.MapType.Foreground; if (isCompressed) { s.DoAt(Menu_Pointers[lvl * 3 + 0], () => { s.DoEncoded(new RNCEncoder(hasHeader: false), () => Menu_Tiles[i] = s.SerializeArray <byte>(Menu_Tiles[i], s.CurrentLength, name: $"{nameof(Menu_Tiles)}[{i}]")); }); s.DoAt(Menu_Pointers[lvl * 3 + 1], () => { s.DoEncoded(new RNCEncoder(hasHeader: false), () => Menu_MapData[i] = s.SerializeObjectArray <MapTile>(Menu_MapData[i], size.Width * size.Height, onPreSerialize: x => x.GBARRRType = mapType, name: $"{nameof(Menu_MapData)}[{i}]")); }); } else { s.DoAt(Menu_Pointers[lvl * 3 + 0], () => Menu_Tiles[i] = s.SerializeArray <byte>(Menu_Tiles[i], 0x4B00 * 2, name: $"{nameof(Menu_Tiles)}[{i}]")); s.DoAt(Menu_Pointers[lvl * 3 + 1], () => Menu_MapData[i] = s.SerializeObjectArray <MapTile>(Menu_MapData[i], size.Width * size.Height, onPreSerialize: x => x.GBARRRType = mapType, name: $"{nameof(Menu_MapData)}[{i}]")); } Menu_Palette[i] = s.DoAt(Menu_Pointers[lvl * 3 + 2], () => s.SerializeObjectArray <RGBA5551Color>(Menu_Palette[i], 16 * 16, name: $"{nameof(Menu_Palette)}[{i}]")); } } }
public override void SerializeImpl(SerializerObject s) { // Serialize ROM header base.SerializeImpl(s); // Get the pointer table var pointerTable = PointerTables.GBAVV_PointerTable(s.GameSettings.GameModeSelection, Offset.file); // Get the current lev info var manager = (GBAVV_BaseManager)s.GameSettings.GetGameManager; if (pointerTable.ContainsKey(GBAVV_Pointer.Localization)) { var multipleLanguages = s.GameSettings.GameModeSelection == GameModeSelection.Crash1GBAEU || s.GameSettings.GameModeSelection == GameModeSelection.Crash2GBAEU; if (multipleLanguages) { LocTablePointers = s.DoAt(pointerTable[GBAVV_Pointer.Localization], () => s.SerializePointerArray(LocTablePointers, 6, name: nameof(LocTablePointers))); } else { LocTablePointers = new Pointer[] { pointerTable[GBAVV_Pointer.Localization] } }; if (LocTables == null) { LocTables = new GBAVV_LocTable[LocTablePointers.Length]; } for (int i = 0; i < LocTables.Length; i++) { LocTables[i] = s.DoAt(LocTablePointers[i], () => s.SerializeObject <GBAVV_LocTable>(LocTables[i], name: $"{nameof(LocTables)}[{i}]")); } } s.Context.StoreObject(GBAVV_BaseManager.LocTableID, LocTables?.FirstOrDefault()); s.DoAt(pointerTable[GBAVV_Pointer.LevelInfo], () => { if (LevelInfos == null) { LevelInfos = new GBAVV_LevelInfo[manager.LevInfos.Max(x => x.LevelIndex) + 1]; } for (int i = 0; i < LevelInfos.Length; i++) { LevelInfos[i] = s.SerializeObject <GBAVV_LevelInfo>(LevelInfos[i], x => x.LevInfo = i == CurrentLevInfo.LevelIndex ? CurrentLevInfo : null, name: $"{nameof(LevelInfos)}[{i}]"); } }); if (CurrentMapInfo.MapType == GBAVV_MapInfo.GBAVV_MapType.Normal || CurrentMapInfo.MapType == GBAVV_MapInfo.GBAVV_MapType.Normal_Vehicle_0 || CurrentMapInfo.MapType == GBAVV_MapInfo.GBAVV_MapType.Normal_Vehicle_1 || CurrentMapInfo.MapType == GBAVV_MapInfo.GBAVV_MapType.WorldMap) { Map2D_Graphics = s.DoAt(pointerTable[GBAVV_Pointer.Map2D_Graphics], () => s.SerializeObject <GBAVV_Map2D_Graphics>(Map2D_Graphics, name: nameof(Map2D_Graphics))); } if (CurrentMapInfo.MapType == GBAVV_MapInfo.GBAVV_MapType.Mode7) { s.DoAt(pointerTable[GBAVV_Pointer.Mode7_LevelInfo], () => { if (Mode7_LevelInfos == null) { Mode7_LevelInfos = new GBAVV_Mode7_LevelInfo[7]; } var index3D = CurrentMapInfo.Index3D; for (int i = 0; i < Mode7_LevelInfos.Length; i++) { Mode7_LevelInfos[i] = s.SerializeObject <GBAVV_Mode7_LevelInfo>(Mode7_LevelInfos[i], x => x.SerializeData = i == index3D, name: $"{nameof(Mode7_LevelInfos)}[{i}]"); } }); if (s.GameSettings.EngineVersion == EngineVersion.GBAVV_Crash2) { GBAVV_Pointer palPointer = CurrentMode7LevelInfo.LevelType == 0 ? GBAVV_Pointer.Mode7_TilePalette_Type0 : GBAVV_Pointer.Mode7_TilePalette_Type1_Flames; Mode7_TilePalette = s.DoAt(pointerTable[palPointer], () => s.SerializeObjectArray <RGBA5551Color>(Mode7_TilePalette, CurrentMode7LevelInfo.LevelType == 0 ? 256 : 16, name: nameof(Mode7_TilePalette))); } else if (s.GameSettings.EngineVersion == EngineVersion.GBAVV_Crash1 && CurrentMode7LevelInfo.LevelType == 0) { Mode7_Crash1_Type0_TilePalette_0F = s.DoAt(pointerTable[GBAVV_Pointer.Mode7_Crash1_Type0_TilePalette_0F], () => s.SerializeObjectArray <RGBA5551Color>(Mode7_Crash1_Type0_TilePalette_0F, 16, name: nameof(Mode7_Crash1_Type0_TilePalette_0F))); } if (s.GameSettings.EngineVersion == EngineVersion.GBAVV_Crash2 && CurrentMode7LevelInfo.LevelType == 0) { Mode7_Crash2_Type0_BG1 = s.DoAt(pointerTable[GBAVV_Pointer.Mode7_Crash2_Type0_BG1], () => s.SerializeArray <byte>(Mode7_Crash2_Type0_BG1, 38 * 9 * 32, name: nameof(Mode7_Crash2_Type0_BG1))); } else if (s.GameSettings.EngineVersion == EngineVersion.GBAVV_Crash2 && CurrentMode7LevelInfo.LevelType == 1) { Mode7_Crash2_Type1_FlamesTileMapsPointers = s.DoAt(pointerTable[GBAVV_Pointer.Mode7_Crash2_Type1_FlamesTileMaps], () => s.SerializePointerArray(Mode7_Crash2_Type1_FlamesTileMapsPointers, 20, name: nameof(Mode7_Crash2_Type1_FlamesTileMapsPointers))); if (Mode7_Crash2_Type1_FlamesTileMaps == null) { Mode7_Crash2_Type1_FlamesTileMaps = new MapTile[20][]; } for (int i = 0; i < Mode7_Crash2_Type1_FlamesTileMaps.Length; i++) { Mode7_Crash2_Type1_FlamesTileMaps[i] = s.DoAt(Mode7_Crash2_Type1_FlamesTileMapsPointers[i], () => s.SerializeObjectArray <MapTile>(Mode7_Crash2_Type1_FlamesTileMaps[i], 0x1E * 0x14, name: $"{nameof(Mode7_Crash2_Type1_FlamesTileMaps)}[{i}]")); } Mode7_Crash2_Type1_FlamesTileSetLengths = s.DoAt(pointerTable[GBAVV_Pointer.Mode7_Crash2_Type1_FlamesTileSetLengths], () => s.SerializeArray <uint>(Mode7_Crash2_Type1_FlamesTileSetLengths, 20, name: nameof(Mode7_Crash2_Type1_FlamesTileSetLengths))); Mode7_Crash2_Type1_FlamesTileSetsPointers = s.DoAt(pointerTable[GBAVV_Pointer.Mode7_Crash2_Type1_FlamesTileSets], () => s.SerializePointerArray(Mode7_Crash2_Type1_FlamesTileSetsPointers, 20, name: nameof(Mode7_Crash2_Type1_FlamesTileSetsPointers))); if (Mode7_Crash2_Type1_FlamesTileSets == null) { Mode7_Crash2_Type1_FlamesTileSets = new byte[20][]; } for (int i = 0; i < Mode7_Crash2_Type1_FlamesTileSets.Length; i++) { Mode7_Crash2_Type1_FlamesTileSets[i] = s.DoAt(Mode7_Crash2_Type1_FlamesTileSetsPointers[i], () => s.SerializeArray <byte>(Mode7_Crash2_Type1_FlamesTileSets[i], Mode7_Crash2_Type1_FlamesTileSetLengths[i], name: $"{nameof(Mode7_Crash2_Type1_FlamesTileSets)}[{i}]")); } } } if (CurrentMapInfo.MapType == GBAVV_MapInfo.GBAVV_MapType.Isometric) { var index3D = CurrentMapInfo.Index3D; s.DoAt(pointerTable[GBAVV_Pointer.Isometric_MapDatas], () => { if (Isometric_MapDatas == null) { Isometric_MapDatas = new GBAVV_Isometric_MapData[7]; } for (int i = 0; i < Isometric_MapDatas.Length; i++) { Isometric_MapDatas[i] = s.SerializeObject <GBAVV_Isometric_MapData>(Isometric_MapDatas[i], x => x.SerializeData = i == index3D + 4, name: $"{nameof(Isometric_MapDatas)}[{i}]"); } }); s.DoAt(pointerTable[GBAVV_Pointer.Isometric_ObjectDatas], () => { if (Isometric_ObjectDatas == null) { Isometric_ObjectDatas = new GBAVV_Isometric_ObjectData[7]; } for (int i = 0; i < Isometric_ObjectDatas.Length; i++) { Isometric_ObjectDatas[i] = s.SerializeObject <GBAVV_Isometric_ObjectData>(Isometric_ObjectDatas[i], x => { x.SerializeData = i == index3D + 4; x.IsMultiplayer = i < 4; }, name: $"{nameof(Isometric_ObjectDatas)}[{i}]"); } }); Isometric_CharacterInfos = s.DoAt(pointerTable[GBAVV_Pointer.Isometric_Characters], () => s.SerializeObjectArray <GBAVV_Isometric_CharacterInfo>(Isometric_CharacterInfos, 12, name: nameof(Isometric_CharacterInfos))); Isometric_CharacterIcons = s.DoAt(pointerTable[GBAVV_Pointer.Isometric_CharacterIcons], () => s.SerializeObjectArray <GBAVV_Isometric_CharacterIcon>(Isometric_CharacterIcons, 11, name: nameof(Isometric_CharacterIcons))); Isometric_ObjAnimations = s.DoAt(pointerTable[GBAVV_Pointer.Isometric_ObjAnimations], () => s.SerializeObjectArray <GBAVV_Isometric_Animation>(Isometric_ObjAnimations, 22, name: nameof(Isometric_ObjAnimations))); Isometric_ObjPalette_0 = s.DoAt(pointerTable[GBAVV_Pointer.Isometric_ObjPalette_0], () => s.SerializeObjectArray <RGBA5551Color>(Isometric_ObjPalette_0, 16, name: nameof(Isometric_ObjPalette_0))); Isometric_ObjPalette_1 = s.DoAt(pointerTable[GBAVV_Pointer.Isometric_ObjPalette_1], () => s.SerializeObjectArray <RGBA5551Color>(Isometric_ObjPalette_1, 16, name: nameof(Isometric_ObjPalette_1))); Isometric_ObjPalette_2 = s.DoAt(pointerTable[GBAVV_Pointer.Isometric_ObjPalette_2], () => s.SerializeObjectArray <RGBA5551Color>(Isometric_ObjPalette_2, 16, name: nameof(Isometric_ObjPalette_2))); Isometric_ObjPalette_4 = s.DoAt(pointerTable[GBAVV_Pointer.Isometric_ObjPalette_4], () => s.SerializeObjectArray <RGBA5551Color>(Isometric_ObjPalette_4, 16, name: nameof(Isometric_ObjPalette_4))); Isometric_ObjPalette_11 = s.DoAt(pointerTable[GBAVV_Pointer.Isometric_ObjPalette_11], () => s.SerializeObjectArray <RGBA5551Color>(Isometric_ObjPalette_11, 16, name: nameof(Isometric_ObjPalette_11))); Isometric_ObjPalette_12 = s.DoAt(pointerTable[GBAVV_Pointer.Isometric_ObjPalette_12], () => s.SerializeObjectArray <RGBA5551Color>(Isometric_ObjPalette_12, 16, name: nameof(Isometric_ObjPalette_12))); Isometric_ObjPalette_13 = s.DoAt(pointerTable[GBAVV_Pointer.Isometric_ObjPalette_13], () => s.SerializeObjectArray <RGBA5551Color>(Isometric_ObjPalette_13, 16, name: nameof(Isometric_ObjPalette_13))); // These animations are all hard-coded from functions: Isometric_AdditionalAnimations = new GBAVV_Isometric_Animation[] { GBAVV_Isometric_Animation.CrateAndSerialize(s, pointerTable[GBAVV_Pointer.Isometric_AdditionalAnim0_Frames], 0x03, 4, 4, 2), // Green barrel GBAVV_Isometric_Animation.CrateAndSerialize(s, pointerTable[GBAVV_Pointer.Isometric_AdditionalAnim1_Frames], 0x03, 4, 4, 2), // Laser beam GBAVV_Isometric_Animation.CrateAndSerialize(s, pointerTable[GBAVV_Pointer.Isometric_AdditionalAnim2_Frames], 0x06, 4, 4, 1), // Crate breaks GBAVV_Isometric_Animation.CrateAndSerialize(s, pointerTable[GBAVV_Pointer.Isometric_AdditionalAnim3_Frames], 0x07, 4, 4, 1), // Checkpoint breaks GBAVV_Isometric_Animation.CrateAndSerialize(s, pointerTable[GBAVV_Pointer.Isometric_AdditionalAnim4_Frames], 0x18, 8, 4, 0), // Checkpoint text GBAVV_Isometric_Animation.CrateAndSerialize(s, pointerTable[GBAVV_Pointer.Isometric_AdditionalAnim5_Frames], 0x08, 4, 4, 2), // Nitro explosion GBAVV_Isometric_Animation.CrateAndSerialize(s, pointerTable[GBAVV_Pointer.Isometric_AdditionalAnim6_Frames], 0x08, 4, 4, 2), // Nitro switch GBAVV_Isometric_Animation.CrateAndSerialize(s, pointerTable[GBAVV_Pointer.Isometric_AdditionalAnim7_Frames], 0x0E, 4, 4, 0), // Wumpa HUD GBAVV_Isometric_Animation.CrateAndSerialize(s, pointerTable[GBAVV_Pointer.Isometric_AdditionalAnim8_Frames], 0x0A, 8, 8, pointerTable[GBAVV_Pointer.Isometric_AdditionalAnim8_Palette]), // Crystal collected GBAVV_Isometric_Animation.CrateAndSerialize(s, pointerTable[GBAVV_Pointer.Isometric_AdditionalAnim9_Frames], 0x03, 4, 4, pointerTable[GBAVV_Pointer.Isometric_AdditionalAnim9_Palette]), // Multiplayer base GBAVV_Isometric_Animation.CrateAndSerialize(s, pointerTable[GBAVV_Pointer.Isometric_AdditionalAnim10_Frames], 0x0A, 2, 2, pointerTable[GBAVV_Pointer.Isometric_AdditionalAnim10_Palette]), // Multiplayer item }; } if (CurrentMapInfo.MapType == GBAVV_MapInfo.GBAVV_MapType.WorldMap) { if (pointerTable.ContainsKey(GBAVV_Pointer.WorldMap)) { WorldMap = s.DoAt(pointerTable[GBAVV_Pointer.WorldMap], () => s.SerializeObject(WorldMap, name: nameof(WorldMap))); } if (s.GameSettings.EngineVersion == EngineVersion.GBAVV_Crash1) { WorldMap_Crash1_LevelIcons = s.DoAt(pointerTable[GBAVV_Pointer.WorldMap_Crash1_LevelIcons], () => s.SerializeObjectArray <GBAVV_WorldMap_Crash1_LevelIcon>(WorldMap_Crash1_LevelIcons, 10, name: nameof(WorldMap_Crash1_LevelIcons))); } } } }
public GBA_R3MadTraxSprite[] LoadMadTraxSprites(Context context) { var output = new List <GBA_R3MadTraxSprite>(); var file = (Files)context.Settings.World; var pointerTable = PointerTables.GBA_PointerTable(context, context.GetFile(GetROMFilePath(context))); var s = context.Deserializer; s.Goto(pointerTable[GBA_Pointer.MadTrax_Sprites]); int index = 0; loadSprites(width: 8, height: 8, length: 9); // Gumsi loadSprites(width: 8, height: 8, length: 9); // Rayman loadSprites(width: 2, height: 4, length: 5); // Big blocks if (file == Files.client_pad2 || file == Files.client_pad3) { loadSprites(width: 2, height: 4, length: 2); // Big blocks (are these correct?) loadSprites(width: 2, height: 4, length: 5); // Blocks loadSprites(width: 1, height: 2, length: 2); // Effect loadSprites(width: 4, height: 4, length: 1); loadSprites(width: 2, height: 2, length: 4); loadSprites(width: 2, height: 2, length: 1); loadSprites(width: 1, height: 1, length: 3); loadSprites(width: 8, height: 8, length: 1); // ? s.Goto(s.CurrentPointer + 0x20 * 1); // ? loadSprites(width: 4, height: 8, assmbleWidth: 8, assembleHeight: 2, length: 1); // Controls screen } else { loadSprites(width: 4, height: 4, length: 1); // Big blocks loadSprites(width: 2, height: 4, length: 1); // Missile loadSprites(width: 4, height: 4, length: file == Files.client_pad145 ? 6 : 21); // Blocks loadSprites(width: 2, height: 4, length: 6); // Missiles loadSprites(width: 2, height: 2, length: 1); // Missiles loadSprites(width: 2, height: 1, length: 1); // Effect loadSprites(width: 2, height: 4, length: 1); // Vertical bar if (file != Files.client_pad145) { loadSprites(width: 2, height: 1, length: 1); // Arrow } loadSprites(width: 2, height: 2, length: 4); loadSprites(width: 4, height: 4, length: 7); // Explosion loadSprites(width: 2, height: 2, length: 1); loadSprites(width: 4, height: 4, length: 1); loadSprites(width: 1, height: 1, length: 3); s.Goto(s.CurrentPointer + 0x20 * 4); // ? loadSprites(width: 4, height: 4, assmbleWidth: 8, assembleHeight: 5, length: 1); // Controls screen } if (file == Files.client_pad145 || file == Files.client_pad2 || file == Files.client_pad3) { loadSprites(width: 4, height: 8, assmbleWidth: 8, assembleHeight: 1, length: 1); // Restart } if (file == Files.client_pad2 || file == Files.client_pad3) { loadSprites(width: 4, height: 8, assmbleWidth: 8, assembleHeight: 1, length: 1); // Try again } else { loadSprites(width: 8, height: 8, length: 1); // Fail } if (file == Files.client_pad145 || file == Files.client_pad2 || file == Files.client_pad3) { loadSprites(width: 4, height: 8, assmbleWidth: 8, assembleHeight: 1, length: 1); // Thank you } else { loadSprites(width: 4, height: 4, assmbleWidth: 8, assembleHeight: 3, length: 1); // Win } loadSprites(width: 4, height: 8, assmbleWidth: 8, assembleHeight: 1, length: 1); // Connection failed if (file != Files.client_pad2 && file != Files.client_pad3) { loadSprites(width: 4, height: 8, assmbleWidth: 4, assembleHeight: 1, length: 1); // Pause loadSprites(width: 4, height: 4, length: 1); // Balloon small loadSprites(width: 8, height: 8, length: 1); // Balloon big loadSprites(width: 8, height: 4, length: 4); // 3, 2, 1, Go! loadSprites(width: 2, height: 2, length: 9); // 1-9 loadSprites(width: 4, height: 2, assmbleWidth: 2, assembleHeight: 1, length: 1); // Level } void loadSprites(int width, int height, int assmbleWidth = 1, int assembleHeight = 1, int length = 1) { for (int i = 0; i < length; i++) { output.Add(s.SerializeObject <GBA_R3MadTraxSprite>(default, onPreSerialize: x =>
public override void SerializeImpl(SerializerObject s) { LevelType = s.Serialize <uint>(LevelType, name: nameof(LevelType)); TileSetFramesPointer = s.SerializePointer(TileSetFramesPointer, name: nameof(TileSetFramesPointer)); TileSetFramesBlockLength = s.Serialize <uint>(TileSetFramesBlockLength, name: nameof(TileSetFramesBlockLength)); if (s.GameSettings.EngineVersion == EngineVersion.GBAVV_Crash1) { Crash1_BackgroundPointer = s.SerializePointer(Crash1_BackgroundPointer, name: nameof(Crash1_BackgroundPointer)); } else { Crash2_BackgroundIndex = s.Serialize <uint>(Crash2_BackgroundIndex, name: nameof(Crash2_BackgroundIndex)); } ObjPalettePointer = s.SerializePointer(ObjPalettePointer, name: nameof(ObjPalettePointer)); ObjDataPointer = s.SerializePointer(ObjDataPointer, name: nameof(ObjDataPointer)); AnimSetsPointer = s.SerializePointer(AnimSetsPointer, name: nameof(AnimSetsPointer)); ObjGraphicsPointer = s.SerializePointer(ObjGraphicsPointer, name: nameof(ObjGraphicsPointer)); Uint_20 = s.Serialize <uint>(Uint_20, name: nameof(Uint_20)); Uint_24 = s.Serialize <uint>(Uint_24, name: nameof(Uint_24)); Uint_28 = s.Serialize <uint>(Uint_28, name: nameof(Uint_28)); Uint_2C = s.Serialize <uint>(Uint_2C, name: nameof(Uint_2C)); Uint_30 = s.Serialize <uint>(Uint_30, name: nameof(Uint_30)); if (!SerializeData) { return; } TileSetFrames = s.DoAt(TileSetFramesPointer, () => s.SerializeObject <GBAVV_Mode7_TileFrames>(TileSetFrames, x => { x.TileSetFramesBlockLength = TileSetFramesBlockLength; x.HasPaletteIndices = LevelType == 0 && s.GameSettings.EngineVersion == EngineVersion.GBAVV_Crash1; }, name: nameof(TileSetFrames))); Crash1_Background = s.DoAt(Crash1_BackgroundPointer, () => s.SerializeObject <GBAVV_Mode7_Background>(Crash1_Background, name: nameof(Crash1_Background))); ObjPalette = s.DoAt(ObjPalettePointer, () => s.SerializeObjectArray <RGBA5551Color>(ObjPalette, 256, name: nameof(ObjPalette))); ObjData = s.DoAt(ObjDataPointer, () => s.SerializeObject <GBAVV_Mode7_ObjData>(ObjData, name: nameof(ObjData))); int animSetsCount = 0; if (LevelType == 0) { animSetsCount = 41; } else if ((LevelType == 1 || LevelType == 2) && s.GameSettings.EngineVersion == EngineVersion.GBAVV_Crash1) { animSetsCount = 47; } else if (LevelType == 1 && s.GameSettings.EngineVersion == EngineVersion.GBAVV_Crash2) { animSetsCount = 55; } AnimSets = s.DoAt(AnimSetsPointer, () => s.SerializeObjectArray <GBAVV_Mode7_AnimSet>(AnimSets, animSetsCount, name: nameof(AnimSets))); var pointerTable = PointerTables.GBAVV_PointerTable(s.GameSettings.GameModeSelection, Offset.file); if (LevelType == 0) { AnimSet_Chase = s.SerializeObject <GBAVV_Mode7_AnimSet>(AnimSet_Chase, x => { x.SerializeValues = false; x.AnimationsPointer = pointerTable[GBAVV_Pointer.Mode7_Type0_ChaseObjAnimations]; x.FrameOffsetsPointer = pointerTable[GBAVV_Pointer.Mode7_Type0_ChaseObjFrames]; x.PaletteIndex = (uint)(s.GameSettings.EngineVersion == EngineVersion.GBAVV_Crash1 ? 0x1F : 0x12); // Tile pal 0x0F and 0x02 }, name: nameof(AnimSet_Chase)); } ObjGraphics = s.DoAt(ObjGraphicsPointer, () => s.SerializeObject <GBAVV_Mode7_ObjGraphics>(ObjGraphics, x => x.AnimSets = GetAllAnimSets.ToArray(), name: nameof(ObjGraphics))); if (s.GameSettings.EngineVersion == EngineVersion.GBAVV_Crash1 && LevelType == 1) { // Load the blimp SpecialFrames = s.DoAt(pointerTable[GBAVV_Pointer.Mode7_Crash1_Type1_SpecialFrame], () => s.SerializeObject <GBAVV_Mode7_SpecialFrames>(SpecialFrames, x => x.FramesCount = 4, name: nameof(SpecialFrames))); } else if (s.GameSettings.EngineVersion == EngineVersion.GBAVV_Crash1 && LevelType == 2) { // Load N. Gin SpecialFrames = s.DoAt(pointerTable[GBAVV_Pointer.Mode7_Crash1_Type2_SpecialFrame], () => s.SerializeObject <GBAVV_Mode7_SpecialFrames>(SpecialFrames, x => x.FramesCount = 1, name: nameof(SpecialFrames))); } if (s.GameSettings.EngineVersion == EngineVersion.GBAVV_Crash1) { Crash1_PolarDeathPalette = s.DoAt(pointerTable[GBAVV_Pointer.Mode7_Crash1_PolarDeathPalette], () => s.SerializeObjectArray <RGBA5551Color>(Crash1_PolarDeathPalette, 16, name: nameof(Crash1_PolarDeathPalette))); } }
public async UniTask ExportMusicAsync(GameSettings settings, string outputPath) { using (var context = new Context(settings)) { var s = context.Deserializer; void ExportSampleSigned(string directory, string filename, sbyte[] data, uint sampleRate, ushort channels) { // Create the directory Directory.CreateDirectory(directory); byte[] unsignedData = data.Select(b => (byte)(b + 128)).ToArray(); // Create WAV data var formatChunk = new WAVFormatChunk() { ChunkHeader = "fmt ", FormatType = 1, ChannelCount = channels, SampleRate = sampleRate, BitsPerSample = 8, }; var wav = new WAV { Magic = "RIFF", FileTypeHeader = "WAVE", Chunks = new WAVChunk[] { formatChunk, new WAVChunk() { ChunkHeader = "data", Data = unsignedData } } }; formatChunk.ByteRate = (formatChunk.SampleRate * formatChunk.BitsPerSample * formatChunk.ChannelCount) / 8; formatChunk.BlockAlign = (ushort)((formatChunk.BitsPerSample * formatChunk.ChannelCount) / 8); // Get the output path var outputFilePath = Path.Combine(directory, filename + ".wav"); // Create and open the output file using (var outputStream = File.Create(outputFilePath)) { // Create a context using (var wavContext = new Context(settings)) { // Create a key const string wavKey = "wav"; // Add the file to the context wavContext.AddFile(new StreamFile(wavKey, outputStream, wavContext)); // Write the data FileFactory.Write <WAV>(wavKey, wav, wavContext); } } } await LoadFilesAsync(context); Pointer ptr = context.FilePointer(GetROMFilePath); var pointerTable = PointerTables.GBAIsometric_PointerTable(s.GameSettings.GameModeSelection, ptr.file); MusyX_File musyxFile = null; s.DoAt(pointerTable[GBAIsometric_Pointer.MusyxFile], () => { musyxFile = s.SerializeObject <MusyX_File>(musyxFile, name: nameof(musyxFile)); }); string outPath = outputPath + "/Sounds/"; for (int i = 0; i < musyxFile.SampleTable.Value.Samples.Length; i++) { var e = musyxFile.SampleTable.Value.Samples[i].Value; //Util.ByteArrayToFile(outPath + $"{i}_{e.Offset.AbsoluteOffset:X8}.bin", e.SampleData); ExportSampleSigned(outPath, $"{i}_{musyxFile.SampleTable.Value.Samples[i].pointer.SerializedOffset:X8}", e.SampleData, e.SampleRate, 1); } outPath = outputPath + "/SongData/"; for (int i = 0; i < musyxFile.SongTable.Value.Length; i++) { var songBytes = musyxFile.SongTable.Value.SongBytes[i]; Util.ByteArrayToFile(outPath + $"{i}_{musyxFile.SongTable.Value.Songs[i].SerializedOffset:X8}.son", songBytes); } outPath = outputPath + "/InstrumentData/"; for (int i = 0; i < musyxFile.InstrumentTable.Value.Instruments.Length; i++) { var instrumentBytes = musyxFile.InstrumentTable.Value.InstrumentBytes[i]; Util.ByteArrayToFile(outPath + $"{i}_{musyxFile.InstrumentTable.Value.Instruments[i].SerializedOffset:X8}.bin", instrumentBytes); } } }