public LevelSettings(NitroOverlay ovl) { QuestionMarks = (byte)(ovl.Read8(0x78) & 0xf); Background = (byte)(ovl.Read8(0x78) >> 4); ObjectBanks = new uint[8]; ObjectBanks[0] = ovl.Read8(0x54); ObjectBanks[1] = ovl.Read8(0x55); ObjectBanks[2] = ovl.Read8(0x56); ObjectBanks[3] = ovl.Read8(0x57); ObjectBanks[4] = ovl.Read8(0x58); ObjectBanks[5] = ovl.Read8(0x59); ObjectBanks[6] = ovl.Read8(0x5A); ObjectBanks[7] = ovl.Read32(0x5C); BMDFileID = ovl.Read16(0x68); KCLFileID = ovl.Read16(0x6A); MinimapTsetFileID = ovl.Read16(0x6C); MinimapPalFileID = ovl.Read16(0x6E); MusicBytes = new byte[3]; MusicBytes[0] = ovl.Read8(0x7C); MusicBytes[1] = ovl.Read8(0x7D); MusicBytes[2] = ovl.Read8(0x7E); MinimapCoordinateScale = ovl.Read16(0x76); CameraStartZoomedOut = ovl.Read8(0x75); LevelFormatVersion = (byte)(ovl.Read8(0x7F) & 0x0F); OverlayInitialiserVersion = (byte)(ovl.Read8(0x7F) >> 4); }
private void copyCLPS(int sourceLevel) { NitroOverlay otherOVL = new NitroOverlay(Program.m_ROM, Program.m_ROM.GetLevelOverlayID(sourceLevel)); uint other_clps_addr = otherOVL.ReadPointer(0x60); ushort other_clps_num = otherOVL.Read16(other_clps_addr + 0x06); uint other_clps_size = (uint)(8 + (other_clps_num * 8)); uint clps_addr = _owner.m_Overlay.ReadPointer(0x60); ushort clps_num = _owner.m_Overlay.Read16(clps_addr + 0x06); uint clps_size = (uint)(8 + (clps_num * 8)); byte[] CLPS_data = otherOVL.ReadBlock(other_clps_addr, other_clps_size); // Make or remove room for other CLPS table if (clps_size < other_clps_size) { AddSpace(clps_addr + clps_size, other_clps_size - clps_size); } else if (clps_size > other_clps_size) { RemoveSpace(clps_addr + clps_size - (clps_size - other_clps_size), clps_size - other_clps_size); } // Write CLPS table from overlay _owner.m_Overlay.WriteBlock(clps_addr, CLPS_data); loadCLPSData(); }
private void btnDecompressOverlay_Click(object sender, EventArgs e) { uint ovlID = uint.Parse(m_SelectedOverlay.Substring(8)); NitroOverlay ovl = new NitroOverlay(Program.m_ROM, ovlID); ovl.SaveChanges(); }
public DoorObject(NitroOverlay ovl, uint offset, int num, int layer) : base(ovl, offset, layer) { m_UniqueID = (uint)(0x20000000 | num); m_Type = 9; ID = 0; Position.X = (float)((short)m_Overlay.Read16(m_Offset + 0x0)) / 1000f; Position.Y = (float)((short)m_Overlay.Read16(m_Offset + 0x2)) / 1000f; Position.Z = (float)((short)m_Overlay.Read16(m_Offset + 0x4)) / 1000f; YRotation = ((float)((short)m_Overlay.Read16(m_Offset + 0x6)) / 4096f) * 22.5f; DoorType = m_Overlay.Read8(m_Offset + 0xA); if (DoorType > 0x17) DoorType = 0x17; InAreaID = m_Overlay.Read8(m_Offset + 0x9); OutAreaID = InAreaID >> 4; InAreaID &= 0xF; PlaneSizeX = m_Overlay.Read8(m_Offset + 0x8); PlaneSizeY = PlaneSizeX >> 4; PlaneSizeX &= 0xF; m_Renderer = InitialiseRenderer(); m_Properties = new PropertyTable(); GenerateProperties(); }
public void LoadTables() { m_FileTable = new ushort[m_FileTableLength]; NitroOverlay ovl0 = new NitroOverlay(this, 0); for (uint i = 0; i < m_FileTableLength; i++) { if (ovl0.Read32(m_FileTableOffset + (i * 4)) != 0 || m_Version != Version.EUR) { uint str_offset = ovl0.ReadPointer(m_FileTableOffset + (i * 4)); string fname = ovl0.ReadString(str_offset, 0); m_FileTable[i] = GetFileIDFromName(fname); m_FileEntries[GetFileIDFromName(fname)].InternalID = (ushort)i; } else { m_FileTable[i] = 0xffff; } } m_FileStream.Position = m_LevelOvlIDTableOffset; m_LevelOvlIDTable = new uint[52]; for (uint i = 0; i < 52; i++) { m_LevelOvlIDTable[i] = m_BinReader.ReadUInt32(); } }
public Level(int levelID, NitroOverlay overlay) { m_LevelID = levelID; m_Overlay = overlay; m_LevelSettings = new LevelSettings(m_Overlay); if (m_LevelSettings.LevelFormatVersion > k_LevelFormatVersion) { throw new InvalidDataException("This level was added by a later version of SM64DSe and cannot be read"); } LoadCLPS(m_Overlay); // read object lists m_NumAreas = m_Overlay.Read8(0x74); uint objlistptr = m_Overlay.ReadPointer(0x70); m_LevelObjects = new Dictionary <uint, LevelObject>(); m_TexAnims = new List <LevelTexAnim>(8); for (int i = 0; i < 8; ++i) { m_TexAnims.Add(new LevelTexAnim(m_Overlay, i, m_NumAreas, m_LevelSettings.LevelFormatVersion)); } m_DynLibIDs = new List <ushort>(); if (DoesLevelUseDynamicLibs()) { uint dlDataOffset = m_Overlay.Read32(0x30); uint numDLs = m_Overlay.Read16(dlDataOffset); m_DynLibIDs = new List <ushort>((int)numDLs); for (uint i = 0; i < numDLs; ++i) { m_DynLibIDs.Add(m_Overlay.Read16(dlDataOffset + 2 * i + 2)); } } ReadObjectTable(m_Overlay, m_Overlay.ReadPointer(0x64), 0); m_MinimapIndices = new byte[k_MaxNumAreas]; for (byte a = 0; a < m_NumAreas; a++) { // read object tables uint addr = (uint)(objlistptr + (a * 12)); if (m_Overlay.Read32(addr) != 0) { ReadObjectTable(m_Overlay, m_Overlay.ReadPointer(addr), a); } // texture animations, have already been read addr += 4; addr += 4; m_MinimapIndices[a] = m_Overlay.Read8(addr); } m_ObjAvailable = new Dictionary <ushort, bool>(); DetermineAvailableObjects(); }
private void btnKCLEditor_Click(object sender, EventArgs e) { uint ovlID = Program.m_ROM.GetLevelOverlayID(lbxLevels.SelectedIndex); NitroOverlay curOvl = new NitroOverlay(Program.m_ROM, ovlID); NitroFile curKCL = Program.m_ROM.GetFileFromInternalID(curOvl.Read16((uint)(0x6A))); KCLEditorForm kclForm = new KCLEditorForm(curKCL); kclForm.Show(); }
public void RemovePatch(NitroROM rom) { List <AddressDataPair> addressDataPairs = null; switch (rom.m_Version) { case NitroROM.Version.EUR: addressDataPairs = m_EURRestoreData; break; case NitroROM.Version.USA_v1: addressDataPairs = m_USv1RestoreData; break; case NitroROM.Version.USA_v2: addressDataPairs = m_USv2RestoreData; break; case NitroROM.Version.JAP: addressDataPairs = m_JAPRestoreData; break; } INitroROMBlock fileToPatch = null; if (m_FileToPatch != null) { fileToPatch = Program.m_ROM.GetFileFromName(m_FileToPatch); } else if (m_OverlayID != null) { fileToPatch = new NitroOverlay(Program.m_ROM, uint.Parse(m_OverlayID)); } foreach (AddressDataPair addressDataPair in addressDataPairs) { for (int i = 0; i < addressDataPair.m_Data.Length; i++) { if (fileToPatch == null) { rom.Write8(addressDataPair.m_Address + (uint)i, addressDataPair.m_Data[i]); } else { fileToPatch.Write8(addressDataPair.m_Address + (uint)i, addressDataPair.m_Data[i]); } } } if (fileToPatch != null) { fileToPatch.SaveChanges(); } }
public static void DecompressOverlaysWithinGame() { if (CheckAllOverlaysDecompressed()) { return; } for (int i = 0; i < 155; i++) { NitroOverlay overlay = new NitroOverlay(Program.m_ROM, (uint)i); // Overlay is decompressed when initialised above automatically if needed, just need to save changes overlay.SaveChanges(); } }
public static List <AddressDataPair> GenerateRestoreData(List <AddressDataPair> patchData, string fileName = null, string overlayID = null) { List <AddressDataPair> restoreDataList = new List <AddressDataPair>(); INitroROMBlock fileToPatch = null; if (fileName != null) { fileToPatch = Program.m_ROM.GetFileFromName(fileName); } else if (overlayID != null) { fileToPatch = new NitroOverlay(Program.m_ROM, uint.Parse(overlayID)); } foreach (AddressDataPair addressDataPair in patchData) { AddressDataPair restoreData = new AddressDataPair(); restoreData.m_Address = addressDataPair.m_Address; List <byte> data = new List <byte>(); for (int i = 0; i < addressDataPair.m_Data.Length; i++) { if (fileToPatch == null) { if (Program.m_IsROMFolder) { Program.m_ROM.arm9R.BaseStream.Position = addressDataPair.m_Address + (uint)i - Program.m_ROM.headerSize; data.Add(Program.m_ROM.arm9R.ReadByte()); } else { data.Add(Program.m_ROM.Read8(addressDataPair.m_Address + (uint)i)); } } else { data.Add(fileToPatch.Read8(addressDataPair.m_Address + (uint)i)); } } restoreData.m_Data = data.ToArray(); restoreDataList.Add(restoreData); } return(restoreDataList); }
private void LoadCLPS(NitroOverlay ovl) { uint clpsAddr = ovl.ReadPointer(0x60); int numCLPSes = ovl.Read16(clpsAddr + 0x06); m_CLPS = new CLPS(); clpsAddr += 8; for (int i = 0; i < numCLPSes; ++i) { CLPS.Entry clps = new CLPS.Entry(); clps.flags = ovl.Read32(clpsAddr); clps.flags |= (ulong)ovl.Read32(clpsAddr + 4) << 32; m_CLPS.Add(clps); clpsAddr += 8; } }
private void btnEditCollisionMap_Click(object sender, EventArgs e) { uint overlayID = Program.m_ROM.GetLevelOverlayID(lbxLevels.SelectedIndex); NitroOverlay currentOverlay = new NitroOverlay(Program.m_ROM, overlayID); NitroFile currentKCL = Program.m_ROM.GetFileFromInternalID(currentOverlay.Read16((uint)(0x6A))); if (!Properties.Settings.Default.UseSimpleModelAndCollisionMapImporters) { ModelAndCollisionMapEditor kclForm = new ModelAndCollisionMapEditor(null, currentKCL.m_Name, 1f, ModelAndCollisionMapEditor.StartMode.CollisionMap); kclForm.Show(); } else { KCLEditorForm kclForm = new KCLEditorForm(currentKCL); kclForm.Show(); } }
private void mnitDumpAllOvls_Click(object sender, EventArgs e) { if (Program.m_ROM == null) { return; } for (int i = 0; i < 155; i++) { NitroOverlay overlay = new NitroOverlay(Program.m_ROM, (uint)i); string filename = "DecompressedOverlays/overlay_" + i.ToString("0000") + ".bin"; string dir = "DecompressedOverlays"; if (!Directory.Exists(dir)) { Directory.CreateDirectory(dir); } System.IO.File.WriteAllBytes(filename, overlay.m_Data); } slStatusLabel.Text = "All overlays have been successfully dumped."; }
private void CopyCLPS(int sourceLevel) { NitroOverlay otherOVL = new NitroOverlay(Program.m_ROM, Program.m_ROM.GetLevelOverlayID(sourceLevel)); uint other_clps_addr = otherOVL.ReadPointer(0x60); ushort other_clps_num = otherOVL.Read16(other_clps_addr + 0x06); uint other_clps_size = (uint)(8 + (other_clps_num * 8)); m_CLPS = new CLPS(); for (int i = 0; i < other_clps_num; ++i) { ulong flags = otherOVL.Read32((uint)(other_clps_addr + 8 + 8 * i + 0)); flags |= (ulong)otherOVL.Read32((uint)(other_clps_addr + 8 + 8 * i + 4)) << 32; CLPS.Entry clps = new CLPS.Entry(); clps.flags = flags; m_CLPS.Add(clps); } LoadCLPSData(); }
public void LoadTables() { m_FileTable = new ushort[m_FileTableLength]; NitroOverlay ovl0 = new NitroOverlay(this, 0); for (uint i = 0; i < m_FileTableLength; i++) { uint str_offset = ovl0.ReadPointer(m_FileTableOffset + (i * 4)); string fname = ovl0.ReadString(str_offset, 0); m_FileTable[i] = GetFileIDFromName(fname); } m_FileStream.Position = m_LevelOvlIDTableOffset; m_LevelOvlIDTable = new uint[52]; for (uint i = 0; i < 52; i++) { m_LevelOvlIDTable[i] = m_BinReader.ReadUInt32(); } }
private void btnReplaceOverlay_Click(object sender, EventArgs e) { if (m_SelectedOverlay == null) { return; } OpenFileDialog ofd = new OpenFileDialog(); if (ofd.ShowDialog() == DialogResult.Cancel) { return; } uint ovlID = uint.Parse(m_SelectedOverlay.Substring(8)); NitroOverlay ovl = new NitroOverlay(Program.m_ROM, ovlID); ovl.Clear(); ovl.WriteBlock(0, System.IO.File.ReadAllBytes(ofd.FileName)); ovl.SaveChanges(); }
public TpSrcObject(NitroOverlay ovl, uint offset, int num, int layer) : base(ovl, offset, layer) { m_UniqueID = (uint)(0x20000000 | num); m_Type = 6; Position.X = (float)((short)m_Overlay.Read16(m_Offset)) / 1000.0f; Position.Y = (float)((short)m_Overlay.Read16(m_Offset + 0x2)) / 1000.0f; Position.Z = (float)((short)m_Overlay.Read16(m_Offset + 0x4)) / 1000.0f; YRotation = 0.0f; Parameters = new ushort[2]; Parameters[0] = m_Overlay.Read8(m_Offset + 0x6); Parameters[1] = m_Overlay.Read8(m_Offset + 0x07); m_Renderer = InitialiseRenderer(); m_Properties = new PropertyTable(); GenerateProperties(); }
private void ReadObjectTable(NitroOverlay ovl, uint offset, int area) { uint subtbl_num = ovl.Read32(offset); uint subtbl_offset = ovl.ReadPointer(offset + 0x4); for (uint st = 0; st < subtbl_num; st++) { uint curoffset = subtbl_offset + (st * 8); byte flags = ovl.Read8(curoffset); byte entries_num = ovl.Read8(curoffset + 0x1); uint entries_offset = ovl.ReadPointer(curoffset + 0x4); byte type = (byte)(flags & 0x1F); byte layer = (byte)(flags >> 5); if (type == 11) { m_MinimapFileIDs = new ushort[entries_num]; } for (byte e = 0; e < entries_num; ++e) { LevelObject obj; INitroROMBlock objData = new INitroROMBlock(); objData.m_Data = ovl.ReadBlock((uint)(entries_offset + e * k_LevelObjTypeSizes[type]), (uint)k_LevelObjTypeSizes[type]); switch (type) { case 0: obj = new StandardObject(objData, m_LevelObjects.Count, layer, area); break; case 1: obj = new EntranceObject(objData, m_LevelObjects.Count, layer, m_EntranceID++); break; case 2: // Path Node obj = new PathPointObject(objData, m_LevelObjects.Count, m_PathNodeID++); break; case 3: // Path obj = new PathObject(objData, m_LevelObjects.Count, (ushort)m_PathID++); break; case 4: obj = new ViewObject(objData, m_LevelObjects.Count, m_ViewID++); break; case 5: obj = new SimpleObject(objData, m_LevelObjects.Count, layer, area); break; case 6: obj = new TpSrcObject(objData, m_LevelObjects.Count, layer); break; case 7: obj = new TpDstObject(objData, m_LevelObjects.Count, layer); break; case 8: // Fog obj = new FogObject(objData, m_LevelObjects.Count, layer, area); break; case 9: obj = new DoorObject(objData, m_LevelObjects.Count, layer); break; case 10: obj = new ExitObject(objData, m_LevelObjects.Count, layer); break; case 11: obj = new MinimapTileIDObject(objData, m_LevelObjects.Count, layer, m_MinimapTileIDNum++); // This is still used by Minimap Editor m_MinimapFileIDs[e] = ovl.Read16((uint)(entries_offset + (e * 2))); break; case 12: // per-area minimap scale factors obj = new MinimapScaleObject(objData, m_LevelObjects.Count, layer, area); break; case 14: // ??? Unknown obj = new Type14Object(objData, m_LevelObjects.Count, layer, area); break; default: throw new InvalidDataException("Bad object type: " + type); } m_LevelObjects.Add(obj.m_UniqueID, obj); } } }
public void DumpObjectInfo() { uint actorptrtable = 0x8000 + 0x88864; Program.m_ROM.BeginRW(); Stream fs = File.Create("objinfo.php"); StreamWriter wr = new StreamWriter(fs); wr.Write("<?php\n$objinfo = array\n(\n"); for (int i = 0; i < 0x146; i++) { wr.Write("\tarray\n\t(\n"); wr.Write(String.Format("\t\t'id' => 0x{0:X4},\n", i)); wr.Write("\t\t'internalname' => '" + ObjectDatabase.m_ObjectInfo[i].m_InternalName + "',\n"); uint actorid = ObjectDatabase.m_ObjectInfo[i].m_ActorID; uint actoraddr = Program.m_ROM.Read32(actorptrtable + (uint)(actorid * 4)); wr.Write(String.Format("\t\t'actorid' => 0x{0:X4},\n", actorid)); if (actoraddr < 0x021111A0) wr.Write("\t\t'requirement' => 'none',\n"); else { uint minovl = 0, maxovl = 0, bank = 0, bankbase = 0; if ((actoraddr >= 0x021111A0) && (actoraddr < 0x02115EE0)) { minovl = 8; maxovl = 59; bank = 7; bankbase = 1; } else if ((actoraddr >= 0x02115EE0) && (actoraddr < 0x0211F000)) { minovl = 0x3E; maxovl = 0x42; bank = 0; bankbase = 1; } else if ((actoraddr >= 0x0211F000) && (actoraddr < 0x02123740)) { minovl = 0x46; maxovl = 0x4A; bank = 1; bankbase = 2; } else if ((actoraddr >= 0x02123740) && (actoraddr < 0x02129020)) { minovl = 0x4D; maxovl = 0x51; bank = 2; bankbase = 1; } else if ((actoraddr >= 0x02129020) && (actoraddr < 0x02130F00)) { minovl = 0x54; maxovl = 0x55; bank = 3; bankbase = 1; } else if ((actoraddr >= 0x02130F00) && (actoraddr < 0x02135700)) { minovl = 0x59; maxovl = 0x5C; bank = 4; bankbase = 1; } else if ((actoraddr >= 0x02135700) && (actoraddr < 0x02140D80)) { minovl = 0x5E; maxovl = 0x61; bank = 5; bankbase = 1; } else if ((actoraddr >= 0x02140D80) && (actoraddr < 0x0214EAA0)) { minovl = 0x64; maxovl = 0x64; bank = 6; bankbase = 1; } uint curovl = minovl; do { NitroOverlay theovl = new NitroOverlay(Program.m_ROM, curovl); uint testval = 0xFFFFFFFF; try { testval = (uint)theovl.Read16(actoraddr - theovl.GetRAMAddr() + 4); } catch {} if (testval == actorid) { wr.Write(String.Format("\t\t'requirement' => 'bank{0}={1}',\n", bank, curovl - minovl + bankbase)); break; } curovl++; } while (curovl <= maxovl); } wr.Write("\t\t0\n\t), \n"); if ((i % 64) == 0) wr.Flush(); } wr.Write("\t0\n);\n?>\n"); wr.Flush(); fs.Close(); Program.m_ROM.EndRW(); }
public EntranceObject(NitroOverlay ovl, uint offset, int num, int layer, int id) : base(ovl, offset, layer) { m_UniqueID = (uint)(0x20000000 | num); m_EntranceID = id; m_Type = 1; ID = 0; Position.X = (float)((short)m_Overlay.Read16(m_Offset + 0x2)) / 1000.0f; Position.Y = (float)((short)m_Overlay.Read16(m_Offset + 0x4)) / 1000.0f; Position.Z = (float)((short)m_Overlay.Read16(m_Offset + 0x6)) / 1000.0f; YRotation = ((float)((short)m_Overlay.Read16(m_Offset + 0xA)) / 4096f) * 22.5f; Parameters = new ushort[5]; Parameters[0] = m_Overlay.Read16(m_Offset + 0x0); Parameters[1] = m_Overlay.Read16(m_Offset + 0x8); Parameters[2] = m_Overlay.Read16(m_Offset + 0xC); Parameters[3] = m_Overlay.Read16(m_Offset + 0xE); m_Renderer = InitialiseRenderer(); m_Properties = new PropertyTable(); GenerateProperties(); }
private void btnCompile_Click(object sender, EventArgs e) { if (!Patcher.PatchMaker.PatchToSupportBigASMHacks()) { return; } //code and patcher borrowed from NSMBe and edited. System.IO.DirectoryInfo dir = new System.IO.DirectoryInfo(txtFolder.Text); uint addr = 0x02400000; if (btnOverlay.Checked) { addr = new NitroOverlay(Program.m_ROM, uint.Parse(txtOverlayId.Text)).GetRAMAddr(); } else if (btnInjection.Checked) { } else if (!btnDynamicLibrary.Checked) { addr = uint.Parse(txtOffset.Text, System.Globalization.NumberStyles.HexNumber); } Patcher.PatchMaker pm = new Patcher.PatchMaker(dir, addr); byte[] ret = null; if (btnDynamicLibrary.Checked) { ret = pm.makeDynamicLibrary(); } else if (btnOverlay.Checked) { pm.compilePatch(); pm.makeOverlay(uint.Parse(txtOverlayId.Text)); return; } else if (btnInjection.Checked) { //TODO. } else { pm.compilePatch(); ret = pm.generatePatch(); } if (ret == null) { return; } bool isOut = btnExternal.Checked; if (isOut) { string file = txtOutput.Text; if (txtOutput.Text == "") { return; } System.IO.File.WriteAllBytes(file, ret); } else { if (txtInput.Text != "") { var file = Program.m_ROM.GetFileFromName(txtInput.Text); file.m_Data = ret; file.SaveChanges(); } } }
/* * This method takes the first Address and Data from the patch and tests if the current values in the * ROM match the values of the patch - if they match the patch is already applied. This doesn't test * all values to speed things up. */ public bool CheckIsApplied(NitroROM rom) { if (m_DecompressAllOverlays && Helper.CheckAllOverlaysDecompressed() == false) { m_IsApplied = false; return false; } INitroROMBlock fileToPatch = null; if (m_FileToPatch != null) fileToPatch = Program.m_ROM.GetFileFromName(m_FileToPatch); else if (m_OverlayID != null) fileToPatch = new NitroOverlay(Program.m_ROM, uint.Parse(m_OverlayID)); AddressDataPair testAddressDataPair = null; switch (rom.m_Version) { case NitroROM.Version.EUR: testAddressDataPair = (m_EURPatch.Count == 0) ? null : m_EURPatch.ElementAt(0); break; case NitroROM.Version.USA_v1: testAddressDataPair = (m_USv1Patch.Count == 0) ? null : m_USv1Patch.ElementAt(0); break; case NitroROM.Version.USA_v2: testAddressDataPair = (m_USv2Patch.Count == 0) ? null : m_USv2Patch.ElementAt(0); break; case NitroROM.Version.JAP: testAddressDataPair = (m_JAPPatch.Count == 0) ? null : m_JAPPatch.ElementAt(0); break; } if (testAddressDataPair == null || testAddressDataPair.m_Data == null || testAddressDataPair.m_Data.Length == 0) { m_IsApplied = false; return false; } for (int i = 0; i < testAddressDataPair.m_Data.Length; i++) { if (fileToPatch == null && rom.Read8(testAddressDataPair.m_Address + (uint)i) != testAddressDataPair.m_Data[i]) { m_IsApplied = false; return false; } else if (fileToPatch != null && fileToPatch.Read8(testAddressDataPair.m_Address + (uint)i) != testAddressDataPair.m_Data[i]) { m_IsApplied = false; return false; } } //If it reaches here, the patch has already been applied m_IsApplied = true; return true; }
private void btnReplaceOverlay_Click(object sender, EventArgs e) { if (m_SelectedOverlay == null || m_SelectedOverlay.Equals("")) return; OpenFileDialog ofd = new OpenFileDialog(); if (ofd.ShowDialog() == DialogResult.Cancel) return; uint ovlID = uint.Parse(m_SelectedOverlay.Substring(8)); NitroOverlay ovl = new NitroOverlay(Program.m_ROM, ovlID); ovl.Clear(); ovl.WriteBlock(0, System.IO.File.ReadAllBytes(ofd.FileName)); ovl.SaveChanges(); }
public void DumpObjectInfo() { uint actorptrtable = 0x8000 + 0x88864; Program.m_ROM.BeginRW(); Stream fs = File.Create("objinfo.php"); StreamWriter wr = new StreamWriter(fs); wr.Write("<?php\n$objinfo = array\n(\n"); for (int i = 0; i < 0x146; i++) { wr.Write("\tarray\n\t(\n"); wr.Write(String.Format("\t\t'id' => 0x{0:X4},\n", i)); wr.Write("\t\t'internalname' => '" + ObjectDatabase.m_ObjectInfo[i].m_InternalName + "',\n"); uint actorid = ObjectDatabase.m_ObjectInfo[i].m_ActorID; uint actoraddr = Program.m_ROM.Read32(actorptrtable + (uint)(actorid * 4)); wr.Write(String.Format("\t\t'actorid' => 0x{0:X4},\n", actorid)); if (actoraddr < 0x021111A0) { wr.Write("\t\t'requirement' => 'none',\n"); } else { uint minovl = 0, maxovl = 0, bank = 0, bankbase = 0; if ((actoraddr >= 0x021111A0) && (actoraddr < 0x02115EE0)) { minovl = 8; maxovl = 59; bank = 7; bankbase = 1; } else if ((actoraddr >= 0x02115EE0) && (actoraddr < 0x0211F000)) { minovl = 0x3E; maxovl = 0x42; bank = 0; bankbase = 1; } else if ((actoraddr >= 0x0211F000) && (actoraddr < 0x02123740)) { minovl = 0x46; maxovl = 0x4A; bank = 1; bankbase = 2; } else if ((actoraddr >= 0x02123740) && (actoraddr < 0x02129020)) { minovl = 0x4D; maxovl = 0x51; bank = 2; bankbase = 1; } else if ((actoraddr >= 0x02129020) && (actoraddr < 0x02130F00)) { minovl = 0x54; maxovl = 0x55; bank = 3; bankbase = 1; } else if ((actoraddr >= 0x02130F00) && (actoraddr < 0x02135700)) { minovl = 0x59; maxovl = 0x5C; bank = 4; bankbase = 1; } else if ((actoraddr >= 0x02135700) && (actoraddr < 0x02140D80)) { minovl = 0x5E; maxovl = 0x61; bank = 5; bankbase = 1; } else if ((actoraddr >= 0x02140D80) && (actoraddr < 0x0214EAA0)) { minovl = 0x64; maxovl = 0x64; bank = 6; bankbase = 1; } uint curovl = minovl; do { NitroOverlay theovl = new NitroOverlay(Program.m_ROM, curovl); uint testval = 0xFFFFFFFF; try { testval = (uint)theovl.Read16(actoraddr - theovl.GetRAMAddr() + 4); } catch {} if (testval == actorid) { wr.Write(String.Format("\t\t'requirement' => 'bank{0}={1}',\n", bank, curovl - minovl + bankbase)); break; } curovl++; }while (curovl <= maxovl); } wr.Write("\t\t0\n\t), \n"); if ((i % 64) == 0) { wr.Flush(); } } wr.Write("\t0\n);\n?>\n"); wr.Flush(); fs.Close(); Program.m_ROM.EndRW(); }
public MinimapTileIDObject(NitroOverlay ovl, uint offset, int num, int layer, int id) : base(ovl, offset, layer) { m_Type = 11; m_MinimapTileIDNum = id; m_UniqueID = (uint)(0x50000000 | num); Parameters = new ushort[2]; Parameters[0] = m_Overlay.Read16(m_Offset); m_Properties = new PropertyTable(); GenerateProperties(); }
public void ApplyPatch(NitroROM rom) { Program.m_ROM.BeginRW(); List <AddressDataPair> addressDataPairs = null; switch (rom.m_Version) { case NitroROM.Version.EUR: addressDataPairs = m_EURPatch; m_EURRestoreData = GenerateRestoreData(m_EURPatch); break; case NitroROM.Version.USA_v1: addressDataPairs = m_USv1Patch; m_USv1RestoreData = GenerateRestoreData(m_USv1Patch); break; case NitroROM.Version.USA_v2: addressDataPairs = m_USv2Patch; m_USv2RestoreData = GenerateRestoreData(m_USv2Patch); break; case NitroROM.Version.JAP: addressDataPairs = m_JAPPatch; m_JAPRestoreData = GenerateRestoreData(m_JAPPatch); break; } if (m_DecompressAllOverlays) { Helper.DecompressOverlaysWithinGame(); } if (m_FileToPatch != null) { NitroFile myFile = Program.m_ROM.GetFileFromName(m_FileToPatch); foreach (AddressDataPair addressDataPair in addressDataPairs) { for (int i = 0; i < addressDataPair.m_Data.Length; i++) { myFile.Write8(addressDataPair.m_Address + (uint)i, addressDataPair.m_Data[i]); } } Program.m_ROM.EndRW(); myFile.SaveChanges(); return; } INitroROMBlock fileToPatch = null; if (m_FileToPatch != null) { fileToPatch = Program.m_ROM.GetFileFromName(m_FileToPatch); } else if (m_OverlayID != null) { fileToPatch = new NitroOverlay(Program.m_ROM, uint.Parse(m_OverlayID)); } foreach (AddressDataPair addressDataPair in addressDataPairs) { for (int i = 0; i < addressDataPair.m_Data.Length; i++) { if (fileToPatch == null) { if (Program.m_IsROMFolder) { Program.m_ROM.arm9W.BaseStream.Position = addressDataPair.m_Address + (uint)i - Program.m_ROM.headerSize; Program.m_ROM.arm9W.Write(addressDataPair.m_Data[i]); } else { rom.Write8(addressDataPair.m_Address + (uint)i, addressDataPair.m_Data[i]); } } else { fileToPatch.Write8(addressDataPair.m_Address + (uint)i, addressDataPair.m_Data[i]); } } } Program.m_ROM.EndRW(); if (fileToPatch != null) { fileToPatch.SaveChanges(); } }
/* * This method takes the first Address and Data from the patch and tests if the current values in the * ROM match the values of the patch - if they match the patch is already applied. This doesn't test * all values to speed things up. */ public bool CheckIsApplied(NitroROM rom) { if (m_DecompressAllOverlays && Helper.CheckAllOverlaysDecompressed() == false) { m_IsApplied = false; return(false); } INitroROMBlock fileToPatch = null; if (m_FileToPatch != null) { fileToPatch = Program.m_ROM.GetFileFromName(m_FileToPatch); } else if (m_OverlayID != null) { fileToPatch = new NitroOverlay(Program.m_ROM, uint.Parse(m_OverlayID)); } AddressDataPair testAddressDataPair = null; switch (rom.m_Version) { case NitroROM.Version.EUR: testAddressDataPair = (m_EURPatch.Count == 0) ? null : m_EURPatch.ElementAt(0); break; case NitroROM.Version.USA_v1: testAddressDataPair = (m_USv1Patch.Count == 0) ? null : m_USv1Patch.ElementAt(0); break; case NitroROM.Version.USA_v2: testAddressDataPair = (m_USv2Patch.Count == 0) ? null : m_USv2Patch.ElementAt(0); break; case NitroROM.Version.JAP: testAddressDataPair = (m_JAPPatch.Count == 0) ? null : m_JAPPatch.ElementAt(0); break; } if (testAddressDataPair == null || testAddressDataPair.m_Data == null || testAddressDataPair.m_Data.Length == 0) { m_IsApplied = false; return(false); } for (int i = 0; i < testAddressDataPair.m_Data.Length; i++) { if (fileToPatch == null) { if (Program.m_IsROMFolder) { Program.m_ROM.arm9R.BaseStream.Position = testAddressDataPair.m_Address + (uint)i - Program.m_ROM.headerSize; if (Program.m_ROM.arm9R.ReadByte() != testAddressDataPair.m_Data[i]) { m_IsApplied = false; return(false); } } else { if (rom.Read8(testAddressDataPair.m_Address + (uint)i) != testAddressDataPair.m_Data[i]) { m_IsApplied = false; return(false); } } } else if (fileToPatch != null && fileToPatch.Read8(testAddressDataPair.m_Address + (uint)i) != testAddressDataPair.m_Data[i]) { m_IsApplied = false; return(false); } } //If it reaches here, the patch has already been applied m_IsApplied = true; return(true); }
public FogObject(NitroOverlay ovl, uint offset, int num, int layer, int area) : base(ovl, offset, layer) { m_Area = area; m_Type = 8; m_UniqueID = (uint)(0x50000000 | num); Parameters = new ushort[6]; Parameters[0] = m_Overlay.Read8(m_Offset); Parameters[1] = m_Overlay.Read8(m_Offset + 1); Parameters[2] = m_Overlay.Read8(m_Offset + 2); Parameters[3] = m_Overlay.Read8(m_Offset + 3); Parameters[4] = m_Overlay.Read16(m_Offset + 4); Parameters[5] = m_Overlay.Read16(m_Offset + 6); //m_Renderer = new ColorCubeRenderer(Color.FromArgb(255, 255, 0), Color.FromArgb(Parameters[1], Parameters[2], Parameters[3]), true); m_Properties = new PropertyTable(); GenerateProperties(); }
public LevelSettings(NitroOverlay ovl) { m_Overlay = ovl; Background = (byte)(m_Overlay.Read8(0x78) >> 4); ObjectBanks = new uint[8]; ObjectBanks[0] = m_Overlay.Read8(0x54); ObjectBanks[1] = m_Overlay.Read8(0x55); ObjectBanks[2] = m_Overlay.Read8(0x56); ObjectBanks[3] = m_Overlay.Read8(0x57); ObjectBanks[4] = m_Overlay.Read8(0x58); ObjectBanks[5] = m_Overlay.Read8(0x59); ObjectBanks[6] = m_Overlay.Read8(0x5A); ObjectBanks[7] = m_Overlay.Read32(0x5C); BMDFileID = m_Overlay.Read16(0x68); KCLFileID = m_Overlay.Read16(0x6A); MinimapTsetFileID = m_Overlay.Read16(0x6C); MinimapPalFileID = m_Overlay.Read16(0x6E); MusicBytes = new byte[3]; MusicBytes[0] = m_Overlay.Read8(0x7C); MusicBytes[1] = m_Overlay.Read8(0x7D); MusicBytes[2] = m_Overlay.Read8(0x7E); MinimapCoordinateScale = m_Overlay.Read16(0x76); CameraStartZoomedOut = m_Overlay.Read8(0x75); }
private void mnitDumpAllOvls_Click(object sender, EventArgs e) { if (Program.m_ROM == null) return; for (int i = 0; i < 155; i++) { NitroOverlay overlay = new NitroOverlay(Program.m_ROM, (uint)i); string filename = "DecompressedOverlays/overlay_" + i.ToString("0000") + ".bin"; string dir = "DecompressedOverlays"; if (!Directory.Exists(dir)) Directory.CreateDirectory(dir); System.IO.File.WriteAllBytes(filename, overlay.m_Data); } slStatusLabel.Text = "All overlays have been successfully dumped."; }
public void RemovePatch(NitroROM rom) { List<AddressDataPair> addressDataPairs = null; switch (rom.m_Version) { case NitroROM.Version.EUR: addressDataPairs = m_EURRestoreData; break; case NitroROM.Version.USA_v1: addressDataPairs = m_USv1RestoreData; break; case NitroROM.Version.USA_v2: addressDataPairs = m_USv2RestoreData; break; case NitroROM.Version.JAP: addressDataPairs = m_JAPRestoreData; break; } INitroROMBlock fileToPatch = null; if (m_FileToPatch != null) fileToPatch = Program.m_ROM.GetFileFromName(m_FileToPatch); else if (m_OverlayID != null) fileToPatch = new NitroOverlay(Program.m_ROM, uint.Parse(m_OverlayID)); foreach (AddressDataPair addressDataPair in addressDataPairs) { for (int i = 0; i < addressDataPair.m_Data.Length; i++) { if (fileToPatch == null) { rom.Write8(addressDataPair.m_Address + (uint)i, addressDataPair.m_Data[i]); } else { fileToPatch.Write8(addressDataPair.m_Address + (uint)i, addressDataPair.m_Data[i]); } } } if (fileToPatch != null) fileToPatch.SaveChanges(); }
private void importPatchToolStripMenuItem_Click(object sender, EventArgs e) { OpenFileDialog o = new OpenFileDialog(); o.Filter = "SM64DSe Patch|*.sp"; o.RestoreDirectory = true; if (o.ShowDialog() == DialogResult.OK) { //Each line. var s = File.ReadAllLines(o.FileName); string basePath = Path.GetDirectoryName(o.FileName) + "/"; foreach (var l in s) { //Get parameters. string t = l; if (t.Contains("#")) { t = t.Substring(0, t.IndexOf('#')); } var p = t.Split(' '); if (p.Length == 0) { continue; } //Switch command. switch (p[0].ToLower()) { //Replace file. case "replace": if (ushort.TryParse(p[1], NumberStyles.HexNumber, CultureInfo.CurrentCulture, out _)) { Program.m_ROM.ReinsertFile(Program.m_ROM.GetFileIDFromInternalID(ushort.Parse(p[1], NumberStyles.HexNumber, CultureInfo.CurrentCulture)), File.ReadAllBytes(basePath + p[2])); } else { Program.m_ROM.ReinsertFile(Program.m_ROM.GetFileIDFromName(p[1]), File.ReadAllBytes(basePath + p[2])); } break; //Replace ARM9. case "replace_arm9": var r = Program.m_ROM; r.BeginRW(true); uint arm9addr = r.Read32(0x20); uint arm9size = r.Read32(0x2C); byte[] newArm9 = File.ReadAllBytes(basePath + p[1]); if (newArm9.Length > arm9size) { r.MakeRoom(arm9addr + arm9size, (uint)(newArm9.Length - arm9size)); r.AutoFix(0xFFFF, arm9addr + arm9size, (int)(newArm9.Length - arm9size)); } r.Write32(0x2C, (uint)newArm9.Length); r.WriteBlock(arm9addr, newArm9); r.EndRW(true); r.LoadROM(r.m_Path); break; //Replace overlay. case "replace_overlay": NitroOverlay n2 = new NitroOverlay(Program.m_ROM, uint.Parse(p[1])); n2.m_Data = File.ReadAllBytes(basePath + p[2]); n2.SaveChanges(); break; //Rename file. case "rename": if (Program.m_ROM.m_Version != NitroROM.Version.EUR) { MessageBox.Show("This is for EUR ROMs only!"); continue; } Program.m_ROM.StartFilesystemEdit(); ushort fileIdFromName; if (ushort.TryParse(p[1], NumberStyles.HexNumber, CultureInfo.CurrentCulture, out _)) { fileIdFromName = Program.m_ROM.GetFileIDFromInternalID(ushort.Parse(p[1], NumberStyles.HexNumber, CultureInfo.CurrentCulture)); } else { fileIdFromName = Program.m_ROM.GetFileIDFromName(p[1]); } string filename = Program.m_ROM.m_FileEntries[fileIdFromName].FullName; string newName = p[2]; int length = filename.LastIndexOf('/') + 1; string str1 = filename.Substring(0, length) + newName; Program.m_ROM.m_FileEntries[fileIdFromName].Name = newName; Program.m_ROM.m_FileEntries[fileIdFromName].FullName = str1; Program.m_ROM.SaveFilesystem(); this.tvFileList.Nodes.Clear(); ROMFileSelect.LoadFileList(this.tvFileList); this.tvARM9Overlays.Nodes.Clear(); ROMFileSelect.LoadOverlayList(this.tvARM9Overlays); break; //Import level XML. case "import_xml": Level lv = new Level(int.Parse(p[1])); try { LevelDataXML_Importer.ImportLevel(lv, basePath + p[2], true); } catch (InvalidDataException ex) { MessageBox.Show(ex.Message); } catch (Exception ex) { new ExceptionMessageBox("Error parsing level, changes have not been saved", ex).ShowDialog(); } Program.m_ROM.LoadROM(Program.m_ROM.m_Path); break; //Add overlay. case "add_overlay": if (Program.m_ROM.m_Version != NitroROM.Version.EUR) { MessageBox.Show("This is for EUR ROMs only!"); continue; } OverlayEditor oe = new OverlayEditor(); oe.AddOverlay(oe.Overlays.Count); var ov = oe.Overlays[oe.Overlays.Count - 1]; var overlayFile = File.ReadAllBytes(basePath + p[6]); ov.ID = (uint)(oe.Overlays.Count - 1); ov.RAMAddress = uint.Parse(p[1], NumberStyles.HexNumber, CultureInfo.CurrentCulture); ov.RAMSize = (uint)overlayFile.Length; ov.BSSSize = uint.Parse(p[4], NumberStyles.HexNumber, CultureInfo.CurrentCulture); ov.StaticInitStart = uint.Parse(p[2], NumberStyles.HexNumber, CultureInfo.CurrentCulture); ov.StaticInitEnd = uint.Parse(p[3], NumberStyles.HexNumber, CultureInfo.CurrentCulture); ov.Flags = uint.Parse(p[5], NumberStyles.HexNumber, CultureInfo.CurrentCulture); oe.Overlays[oe.Overlays.Count - 1] = ov; oe.saveChangesButton_Click(null, new EventArgs()); oe.closeButton_Click(null, new EventArgs()); NitroOverlay n = new NitroOverlay(Program.m_ROM, (uint)(oe.Overlays.Count - 1)); n.m_Data = overlayFile; n.SaveChanges(); this.tvFileList.Nodes.Clear(); ROMFileSelect.LoadFileList(this.tvFileList); this.tvARM9Overlays.Nodes.Clear(); ROMFileSelect.LoadOverlayList(this.tvARM9Overlays); break; //Edit overlay. case "edit_overlay": if (Program.m_ROM.m_Version != NitroROM.Version.EUR) { MessageBox.Show("This is for EUR ROMs only!"); continue; } Program.m_ROM.StartFilesystemEdit(); var ov2 = Program.m_ROM.m_OverlayEntries[int.Parse(p[1])]; ov2.RAMAddress = uint.Parse(p[2], NumberStyles.HexNumber, CultureInfo.CurrentCulture); ov2.BSSSize = uint.Parse(p[5], NumberStyles.HexNumber, CultureInfo.CurrentCulture); ov2.StaticInitStart = uint.Parse(p[3], NumberStyles.HexNumber, CultureInfo.CurrentCulture); ov2.StaticInitEnd = uint.Parse(p[4], NumberStyles.HexNumber, CultureInfo.CurrentCulture); ov2.Flags = uint.Parse(p[6], NumberStyles.HexNumber, CultureInfo.CurrentCulture); Program.m_ROM.m_OverlayEntries[int.Parse(p[1])] = ov2; Program.m_ROM.SaveFilesystem(); break; //Delete overlay. case "delete_overlay": if (Program.m_ROM.m_Version != NitroROM.Version.EUR) { MessageBox.Show("This is for EUR ROMs only!"); continue; } OverlayEditor oe2 = new OverlayEditor(); oe2.DeleteOverlay(int.Parse(p[1])); oe2.saveChangesButton_Click(null, new EventArgs()); oe2.closeButton_Click(null, new EventArgs()); break; } } } }
public ExitObject(NitroOverlay ovl, uint offset, int num, int layer) : base(ovl, offset, layer) { m_UniqueID = (uint)(0x20000000 | num); m_Type = 10; Position.X = (float)((short)m_Overlay.Read16(m_Offset)) / 1000.0f; Position.Y = (float)((short)m_Overlay.Read16(m_Offset + 0x2)) / 1000.0f; Position.Z = (float)((short)m_Overlay.Read16(m_Offset + 0x4)) / 1000.0f; YRotation = ((float)((short)m_Overlay.Read16(m_Offset + 0x8)) / 4096f) * 22.5f; LevelID = m_Overlay.Read8(m_Offset + 0xA); EntranceID = m_Overlay.Read8(m_Offset + 0xB); Param1 = m_Overlay.Read16(m_Offset + 0x6); Param2 = m_Overlay.Read16(m_Offset + 0xC); m_Renderer = InitialiseRenderer(); m_Properties = new PropertyTable(); GenerateProperties(); }
private void dLPatchToolStripMenuItem_Click(object sender, EventArgs e) { if (Program.m_ROM.m_Version != NitroROM.Version.EUR) { MessageBox.Show("This is for EUR roms only!"); } else { bool autorw = Program.m_ROM.CanRW(); if (!autorw) { Program.m_ROM.BeginRW(); } if (Program.m_ROM.Read32(0x6590) != 0) //the patch makes this not 0 { if (!autorw) { Program.m_ROM.EndRW(); } MessageBox.Show("Rom has already been patched!"); return; } if (!autorw) { Program.m_ROM.EndRW(); } if (MessageBox.Show("This will patch the ROM. " + "Continue with the patch?", "Table Shifting Patch", MessageBoxButtons.YesNo) == DialogResult.No) { return; } if (!autorw) { Program.m_ROM.BeginRW(); } NitroOverlay ov2 = new NitroOverlay(Program.m_ROM, 2); //Move the ACTOR_SPAWN_TABLE so it can expand Program.m_ROM.WriteBlock(0x6590, Program.m_ROM.ReadBlock(0x90864, 0x61c)); Program.m_ROM.WriteBlock(0x90864, new byte[0x61c]); //Adjust pointers Program.m_ROM.Write32(0x1a198, 0x02006590); //Move the OBJ_TO_ACTOR_TABLE so it can expand Program.m_ROM.WriteBlock(0x4b00, ov2.ReadBlock(0x0210cbf4 - ov2.GetRAMAddr(), 0x28c)); ov2.WriteBlock(0x0210cbf4 - ov2.GetRAMAddr(), new byte[0x28c]); //Adjust pointers ov2.Write32(0x020fe890 - ov2.GetRAMAddr(), 0x02004b00); ov2.Write32(0x020fe958 - ov2.GetRAMAddr(), 0x02004b00); ov2.Write32(0x020fea44 - ov2.GetRAMAddr(), 0x02004b00); //Add the dynamic library loading and cleanup code Program.m_ROM.WriteBlock(0x90864, Properties.Resources.dynamic_library_loader); //Add the hooks (by replacing LoadObjBankOverlays()) Program.m_ROM.WriteBlock(0x2df70, Properties.Resources.static_overlay_loader); if (!autorw) { Program.m_ROM.EndRW(); } ov2.SaveChanges(); } }
public NitroROM(string path) { m_Path = path; m_CanRW = false; BeginRW(); m_FileStream.Position = 0x00; char[] gametitle = m_BinReader.ReadChars(12); if (new string(gametitle) != "S.MARIO64DS\0") { EndRW(); throw new Exception("This file isn't a Super Mario 64 DS ROM."); } m_FileStream.Position = 0x0C; uint gamecode = m_BinReader.ReadUInt32(); m_FileStream.Position = 0x1E; byte romversion = m_BinReader.ReadByte(); switch (gamecode) { case 0x454D5341: // ASME / USA if (romversion == 0x01) { m_Version = Version.USA_v2; m_LevelOvlIDTableOffset = 0x742B4; m_FileTableOffset = 0x11244; m_FileTableLength = 1824; } else { m_Version = Version.USA_v1; m_LevelOvlIDTableOffset = 0x73594; m_FileTableOffset = 0x1123C; m_FileTableLength = 1824; } break; case 0x4A4D5341: // ASMJ / JAP m_Version = Version.JAP; m_LevelOvlIDTableOffset = 0x73B38; m_FileTableOffset = 0x1123C; m_FileTableLength = 1824; break; case 0x504D5341: // ASMP / EUR m_Version = Version.EUR; m_LevelOvlIDTableOffset = 0x758C8; m_FileTableOffset = 0x13098; m_FileTableLength = 2058; break; default: m_Version = Version.UNK; EndRW(); throw new Exception("Unknown ROM version. Tell Mega-Mario about it."); } m_FileStream.Position = 0x28; ARM9RAMAddress = m_BinReader.ReadUInt32(); m_FileStream.Position = 0x30; ARM7Offset = m_BinReader.ReadUInt32(); m_FileStream.Position += 0x04; ARM7RAMAddress = m_BinReader.ReadUInt32(); ARM7Size = m_BinReader.ReadUInt32(); m_FileStream.Position = 0x40; FNTOffset = m_BinReader.ReadUInt32(); FNTSize = m_BinReader.ReadUInt32(); FATOffset = m_BinReader.ReadUInt32(); FATSize = m_BinReader.ReadUInt32(); OVTOffset = m_BinReader.ReadUInt32(); OVTSize = m_BinReader.ReadUInt32(); // no need to bother about ARM7 overlays... there's none in SM64DS m_FileStream.Position = 0x80; m_UsedSize = m_BinReader.ReadUInt32(); //m_UsedSize += ROM_END_MARGIN; m_FileStream.Position = FNTOffset + 6; ushort numdirs = m_BinReader.ReadUInt16(); ushort numfiles = (ushort)(FATSize / 8); m_DirEntries = new DirEntry[numdirs]; m_FileEntries = new FileEntry[numfiles]; m_FileStream.Position = FATOffset; for (ushort f = 0; f < numfiles; f++) { uint start = m_BinReader.ReadUInt32(); uint end = m_BinReader.ReadUInt32(); FileEntry fe; fe.ID = f; fe.InternalID = 0xFFFF; fe.ParentID = 0; fe.Offset = start; fe.Size = end - start; fe.Name = fe.FullName = ""; fe.Data = null; m_FileEntries[f] = fe; } DirEntry root; root.ID = 0xF000; root.ParentID = 0; root.Name = root.FullName = ""; m_DirEntries[0] = root; uint tableoffset = FNTOffset; for (ushort d = 0; d < numdirs; d++) { m_FileStream.Position = tableoffset; uint subtableoffset = FNTOffset + m_BinReader.ReadUInt32(); ushort first_fileid = m_BinReader.ReadUInt16(); ushort cur_fileid = first_fileid; m_FileStream.Position = subtableoffset; for (;;) { byte type_len = m_BinReader.ReadByte(); if (type_len == 0x00) { break; } else if (type_len > 0x80) { DirEntry dir; dir.Name = new string(m_BinReader.ReadChars(type_len & 0x7F)); dir.ID = m_BinReader.ReadUInt16(); dir.ParentID = (ushort)(d + 0xF000); dir.FullName = ""; m_DirEntries[dir.ID - 0xF000] = dir; } else if (type_len < 0x80) { char[] _name = m_BinReader.ReadChars(type_len & 0x7F); m_FileEntries[cur_fileid].ParentID = (ushort)(d + 0xF000); m_FileEntries[cur_fileid].Name = new string(_name); cur_fileid++; } } tableoffset += 8; } for (int i = 0; i < m_DirEntries.Length; i++) { if (m_DirEntries[i].ParentID > 0xF000) { m_DirEntries[i].FullName = m_DirEntries[m_DirEntries[i].ParentID - 0xF000].FullName + "/" + m_DirEntries[i].Name; } else { m_DirEntries[i].FullName = m_DirEntries[i].Name; } } for (int i = 0; i < m_FileEntries.Length; i++) { if (m_FileEntries[i].ParentID > 0xF000) { m_FileEntries[i].FullName = m_DirEntries[m_FileEntries[i].ParentID - 0xF000].FullName + "/" + m_FileEntries[i].Name; } else { m_FileEntries[i].FullName = m_FileEntries[i].Name; } } uint numoverlays = OVTSize / 0x20; m_OverlayEntries = new OverlayEntry[numoverlays]; for (uint i = 0; i < numoverlays; i++) { m_FileStream.Position = OVTOffset + (i * 0x20); OverlayEntry oe; oe.EntryOffset = (uint)m_FileStream.Position; oe.ID = m_BinReader.ReadUInt32(); oe.RAMAddress = m_BinReader.ReadUInt32(); oe.RAMSize = m_BinReader.ReadUInt32(); oe.BSSSize = m_BinReader.ReadUInt32(); oe.StaticInitStart = this.m_BinReader.ReadUInt32(); oe.StaticInitEnd = this.m_BinReader.ReadUInt32(); oe.FileID = (ushort)this.m_BinReader.ReadUInt32(); oe.Flags = this.m_BinReader.ReadUInt32(); m_OverlayEntries[(int)oe.ID] = oe; } if (m_Version == Version.EUR) { //screw the l that looks like a 1 // \/ NitroOverlay ov0 = new NitroOverlay(this, 0); //And of course, fix those hardcoded values //Who expected a new object to be inserted, anyway? m_FileTableOffset = ov0.ReadPointer(0xA4); m_FileTableLength = ov0.Read32(0x9C); } EndRW(); UpdateStrings(); }
public void LoadTables() { m_FileTable = new ushort[m_FileTableLength]; NitroOverlay ovl0 = new NitroOverlay(this, 0); for (uint i = 0; i < m_FileTableLength; i++) { uint str_offset = ovl0.ReadPointer(m_FileTableOffset + (i*4)); string fname = ovl0.ReadString(str_offset, 0); m_FileTable[i] = GetFileIDFromName(fname); } m_FileStream.Position = m_LevelOvlIDTableOffset; m_LevelOvlIDTable = new uint[52]; for (uint i = 0; i < 52; i++) m_LevelOvlIDTable[i] = m_BinReader.ReadUInt32(); }
public SimpleObject(NitroOverlay ovl, uint offset, int num, int layer, int area) : base(ovl, offset, layer) { m_Area = area; m_UniqueID = (uint)(0x10000000 | num); m_Type = 5; ushort idparam = m_Overlay.Read16(m_Offset); ID = (ushort)(idparam & 0x1FF); Position.X = (float)((short)m_Overlay.Read16(m_Offset + 0x2)) / 1000f; Position.Y = (float)((short)m_Overlay.Read16(m_Offset + 0x4)) / 1000f; Position.Z = (float)((short)m_Overlay.Read16(m_Offset + 0x6)) / 1000f; YRotation = 0.0f; Parameters = new ushort[1]; Parameters[0] = (ushort)(idparam >> 9); m_Renderer = InitialiseRenderer(); m_Properties = new PropertyTable(); GenerateProperties(); }
public LevelTexAnim(NitroOverlay ovl, uint tbloffset, uint offset, int num, int area) { m_Overlay = ovl; // Address of the animation data m_Offset = offset; m_UniqueID = (uint)num; m_Area = area; // Address of the texture animation data header for this texture animation m_TexAnimHeaderOffset = tbloffset; // Addresses at which the scale, rotation and translation data for this texture animation starts m_ScaleTblOffset = m_Overlay.ReadPointer(tbloffset + 0x4) + (uint)(m_Overlay.Read16(m_Offset + 0xE) * 4); m_RotTblOffset = m_Overlay.ReadPointer(tbloffset + 0x8) + (uint)(m_Overlay.Read16(m_Offset + 0x12) * 2); m_TransTblOffset = m_Overlay.ReadPointer(tbloffset + 0xC) + (uint)(m_Overlay.Read16(m_Offset + 0x16) * 4); // Addresses of the shared scale, rotation and translation tables m_BaseScaleTblAddr = m_Overlay.ReadPointer(tbloffset + 0x4); m_BaseRotTblAddr = m_Overlay.ReadPointer(tbloffset + 0x8); m_BaseTransTblAddr = m_Overlay.ReadPointer(tbloffset + 0xC); m_MatNameOffset = m_Overlay.ReadPointer(m_Offset + 0x4); }
public MinimapScaleObject(NitroOverlay ovl, uint offset, int num, int layer, int area) : base(ovl, offset, layer) { m_Type = 12; m_Area = area; m_UniqueID = (uint)(0x50000000 | num); Parameters = new ushort[1]; Parameters[0] = m_Overlay.Read16(m_Offset); m_Properties = new PropertyTable(); GenerateProperties(); }
public Type14Object(NitroOverlay ovl, uint offset, int num, int layer, int area) : base(ovl, offset, layer) { m_Area = area; m_Type = 14; m_UniqueID = (uint)(0x50000000 | num); Parameters = new ushort[4]; Parameters[0] = m_Overlay.Read8(m_Offset); Parameters[1] = m_Overlay.Read8(m_Offset + 1); Parameters[2] = m_Overlay.Read8(m_Offset + 2); Parameters[3] = m_Overlay.Read8(m_Offset + 3); m_Properties = new PropertyTable(); GenerateProperties(); }
private void Patch_v4(BackgroundWorker lazyman) { uint lvl_start = 0; // Music table address uint music_tbl_addr = 0; // Store locations of the music bytes (music table address, +1, +2) - update to point to within overlay uint music_tbl_byte_1_addr = 0, music_tbl_byte_2_addr = 0, music_tbl_byte_3_addr = 0; // Locations at which offsets into the music table are calculated uint music_byte_1_offset = 0, music_byte_2_offset = 0, music_byte_3_offset = 0; switch (m_Version) { case Version.EUR: music_tbl_addr = 0x75768; music_byte_1_offset = 0x2de28; music_byte_2_offset = 0x2d184; music_byte_3_offset = 0x2d360; music_tbl_byte_1_addr = 0x2de60; music_tbl_byte_2_addr = 0x2d608; music_tbl_byte_3_addr = 0x2d644; lvl_start = 34925216; break; case Version.JAP: music_tbl_addr = 0x739d8; music_byte_1_offset = 0x2cd80; music_byte_2_offset = 0x2c32c; music_byte_3_offset = 0x2c508; music_tbl_byte_1_addr = 0x2cdb8; music_tbl_byte_2_addr = 0x2c7b0; music_tbl_byte_3_addr = 0x2c7ec; lvl_start = 34878592; break; case Version.USA_v1: music_tbl_addr = 0x73434; music_byte_1_offset = 0x2caa8; music_byte_2_offset = 0x2c058; music_byte_3_offset = 0x2c234; music_tbl_byte_1_addr = 0x2cae0; music_tbl_byte_2_addr = 0x2c4d8; music_tbl_byte_3_addr = 0x2c514; lvl_start = 34880416; break; case Version.USA_v2: music_tbl_addr = 0x74154; music_byte_1_offset = 0x2cdbc; music_byte_2_offset = 0x2c368; music_byte_3_offset = 0x2c544; music_tbl_byte_1_addr = 0x2cdf4; music_tbl_byte_2_addr = 0x2c7ec; music_tbl_byte_3_addr = 0x2c828; lvl_start = 34887456; break; } // Copy level music data for (int i = 0; i < 52; i++) { NitroOverlay ovl = new NitroOverlay(this, (uint)(103 + i)); m_FileStream.Position = music_tbl_addr + (i * 3); ovl.Write8(0x7C + 0, m_BinReader.ReadByte()); ovl.Write8(0x7C + 1, m_BinReader.ReadByte()); ovl.Write8(0x7C + 2, m_BinReader.ReadByte()); ovl.SaveChanges(); } // Patch music code to load from overlays m_FileStream.Position = music_byte_1_offset; // Offset into table generated m_BinWriter.Write((uint)0xe3a03000); //MOV R3, #0 ;Set offset to 0 m_FileStream.Position = music_tbl_byte_1_addr; // Stores location of music table byte 1 m_BinWriter.Write((uint)(lvl_start + 0x7C)); // Write location in overlay of music data m_FileStream.Position = music_byte_2_offset; m_BinWriter.Write((uint)0xe3a02001); //MOV R2, #1 ;Set offset to 1 m_FileStream.Position = music_tbl_byte_2_addr; m_BinWriter.Write((uint)(lvl_start + 0x7C)); m_FileStream.Position = music_byte_3_offset; m_BinWriter.Write((uint)0xe3a01002);//MOV R1, #2 ;Set offset to 0 m_FileStream.Position = music_tbl_byte_3_addr; m_BinWriter.Write((uint)(lvl_start + 0x7C)); lazyman.ReportProgress(499); }
private void Patch_v2(BackgroundWorker lazyman) { lazyman.ReportProgress(200); uint levelptr_table = 0, objbank_table = 0; uint mempatch1 = 0, mempatch2 = 0; byte[] loadercode = null; uint lvl_ovlid_table = 0; uint unload_patch = 0, unload_branchop = 0; uint[] ovltable_addr_patch = new uint[4]; uint[] ovltable_size_patch = new uint[4]; uint lvlload_addr_patch = 0, lvlload_code_patch = 0; uint objbank_addr_patch = 0, objbank_code_patch = 0; switch (m_Version) { case Version.EUR: levelptr_table = 0x92208; objbank_table = 0x75998; mempatch1 = 0x18B60; mempatch2 = 0x58DE0; loadercode = Properties.Resources.level_ovl_init_EUR; lvl_ovlid_table = 0x758C8; unload_patch = 0x2DE80; unload_branchop = ARM_BL(0x0202DE80, 0x0214EAD8); ovltable_addr_patch[0] = 0x17E90; ovltable_addr_patch[1] = 0x17F30; ovltable_addr_patch[2] = 0x17FCC; ovltable_addr_patch[3] = 0x180FC; ovltable_size_patch[0] = 0x17E80; ovltable_size_patch[1] = 0x17ED0; ovltable_size_patch[2] = 0x17F70; ovltable_size_patch[3] = 0x180C4; lvlload_addr_patch = 0x2D62C; lvlload_code_patch = 0x2D288; objbank_addr_patch = 0x2E074; objbank_code_patch = 0x2DFAC; break; case Version.JAP: levelptr_table = 0x902B8; objbank_table = 0x73C08; mempatch1 = 0x57368; mempatch2 = 0xFFFFFFFF; loadercode = Properties.Resources.level_ovl_init_JAP; lvl_ovlid_table = 0x73B38; unload_patch = 0x2CDD8; unload_branchop = ARM_BL(0x0202CDD8, 0x021434B8); ovltable_addr_patch[0] = 0x17DE4; ovltable_addr_patch[1] = 0x17E84; ovltable_addr_patch[2] = 0x17F20; ovltable_addr_patch[3] = 0x18050; ovltable_size_patch[0] = 0x17DD4; ovltable_size_patch[1] = 0x17E24; ovltable_size_patch[2] = 0x17EC4; ovltable_size_patch[3] = 0x18018; lvlload_addr_patch = 0x2C7D4; lvlload_code_patch = 0x2C430; objbank_addr_patch = 0x2CFCC; objbank_code_patch = 0x2CF04; break; case Version.USA_v1: levelptr_table = 0x8FDB0; objbank_table = 0x73664; mempatch1 = 0x56EB8; mempatch2 = 0xFFFFFFFF; loadercode = Properties.Resources.level_ovl_init_USAv1; lvl_ovlid_table = 0x73594; unload_patch = 0x2CB00; unload_branchop = ARM_BL(0x0202CB00, 0x02143BD8); ovltable_addr_patch[0] = 0x17D70; ovltable_addr_patch[1] = 0x17E10; ovltable_addr_patch[2] = 0x17EAC; ovltable_addr_patch[3] = 0x17FDC; ovltable_size_patch[0] = 0x17D60; ovltable_size_patch[1] = 0x17DB0; ovltable_size_patch[2] = 0x17E50; ovltable_size_patch[3] = 0x17FA4; lvlload_addr_patch = 0x2C4FC; lvlload_code_patch = 0x2C15C; objbank_addr_patch = 0x2CCF4; objbank_code_patch = 0x2CC2C; break; case Version.USA_v2: levelptr_table = 0x90ACC; objbank_table = 0x74384; mempatch1 = 0x18A44; mempatch2 = 0x57B30; loadercode = Properties.Resources.level_ovl_init_USAv2; lvl_ovlid_table = 0x742B4; unload_patch = 0x2CE14; unload_branchop = ARM_BL(0x0202CE14, 0x02145758); ovltable_addr_patch[0] = 0x17DE4; ovltable_addr_patch[1] = 0x17E84; ovltable_addr_patch[2] = 0x17F20; ovltable_addr_patch[3] = 0x18050; ovltable_size_patch[0] = 0x17DD4; ovltable_size_patch[1] = 0x17E24; ovltable_size_patch[2] = 0x17EC4; ovltable_size_patch[3] = 0x18018; lvlload_addr_patch = 0x2C810; lvlload_code_patch = 0x2C46C; objbank_addr_patch = 0x2D008; objbank_code_patch = 0x2CF40; break; } // tweak the root heap start address to gain more overlay space :) m_FileStream.Position = mempatch1; uint lvl_start = m_BinReader.ReadUInt32(); uint lvl_end = lvl_start + LEVEL_OVERLAY_SIZE; m_FileStream.Position = mempatch1; m_BinWriter.Write(lvl_end); if (mempatch2 != 0xFFFFFFFF) { m_FileStream.Position = mempatch2; m_BinWriter.Write(lvl_end); } // patch level overlay unloading m_FileStream.Position = unload_patch; m_BinWriter.Write(unload_branchop); // patch more stuff foreach (uint addr in ovltable_addr_patch) { m_FileStream.Position = addr; m_BinWriter.Write((uint)(0x02000000 + levelptr_table)); } foreach (uint addr in ovltable_size_patch) { m_FileStream.Position = addr; uint op = m_BinReader.ReadUInt32(); op = (op & 0xFFFFFF00) | 0x0D; m_FileStream.Position = addr; m_BinWriter.Write(op); } lazyman.ReportProgress(201); // for each level, create a new overlay with the loader code and level data uint dataoffset = (uint)((loadercode.Length + 3) & ~3); for (int i = 0; i < 52; i++) { uint overlayid = AddOverlay(lvl_start); m_FileStream.Position = lvl_ovlid_table + (i*4); uint old_overlayid = m_BinReader.ReadUInt32(); m_FileStream.Position = lvl_ovlid_table + (i*4); m_BinWriter.Write(overlayid); NitroOverlay ovl = new NitroOverlay(this, overlayid); ovl.SetInitializer(lvl_start, 4); ovl.WriteBlock(0, loadercode); // write the object bank settings m_FileStream.Position = objbank_table + (i * 7); byte[] objbanks = m_BinReader.ReadBytes(7); ovl.WriteBlock(dataoffset, objbanks); ovl.Write8(dataoffset + 0x7, 0x00); ovl.Write32(dataoffset + 0x8, (uint)(i + 1)); // copy level data { NitroOverlay oldovl = new NitroOverlay(this, old_overlayid); uint oldbase = oldovl.GetRAMAddr(); m_FileStream.Position = levelptr_table + (i*4); uint header_offset = m_BinReader.ReadUInt32() - oldbase; uint curoffset = dataoffset + 0x40; // CLPS (collision behaviors) chunk { uint clps_addr = oldovl.ReadPointer(header_offset); ushort clps_num = oldovl.Read16(clps_addr + 0x06); uint clps_size = (uint)(8 + (clps_num * 8)); byte[] clps = oldovl.ReadBlock(clps_addr, clps_size); ovl.WriteBlock(curoffset, clps); ovl.WritePointer(dataoffset + 0x0C, curoffset); curoffset += clps_size; } // misc objects table list { uint tables_addr = oldovl.ReadPointer(header_offset + 0x4); ushort tables_num = oldovl.Read16(tables_addr); tables_addr = oldovl.ReadPointer(tables_addr + 0x4); ovl.WritePointer(dataoffset + 0x10, curoffset); ovl.Write16(curoffset, tables_num); ovl.WritePointer(curoffset + 0x04, curoffset + 0x8); curoffset += 0x8; uint objdata_offset = (uint)(curoffset + (tables_num * 8)); for (ushort t = 0; t < tables_num; t++) { uint tbl_part1 = oldovl.Read32(tables_addr); uint tbl_addr = oldovl.ReadPointer(tables_addr + 0x4); ovl.Write32(curoffset, tbl_part1); ovl.WritePointer(curoffset + 0x4, objdata_offset); tables_addr += 8; curoffset += 8; byte tbltype = (byte)(tbl_part1 & 0x1F); byte numentries = (byte)((tbl_part1 >> 8) & 0xFF); if ((tbltype == 13) || (tbltype > 14)) throw new Exception(String.Format("Wrong object table type {0} (0x{0:X2}) in level data", tbltype)); int[] datasizes = {16, 16, 6, 6, 14, 8, 8, 8, 8, 12, 14, 2, 2, 0, 4}; int datasize = numentries * datasizes[tbltype]; byte[] data = oldovl.ReadBlock(tbl_addr, (uint)datasize); ovl.WriteBlock(objdata_offset, data); objdata_offset += (uint)((datasize + 3) & ~3); } curoffset = objdata_offset; } // main object table lists // and that stuff about texture scrolling { uint tlists_addr = oldovl.ReadPointer(header_offset + 0x10); byte tlists_num = oldovl.Read8(header_offset + 0x14); uint tlists_new_addr = curoffset; curoffset += (uint)(tlists_num * 12); ovl.WritePointer(dataoffset + 0x1C, tlists_new_addr); ovl.Write8(dataoffset + 0x20, tlists_num); for (byte tl = 0; tl < tlists_num; tl++) { uint tables_addr = oldovl.ReadPointer(tlists_addr); uint texanm_addr = oldovl.ReadPointer(tlists_addr + 0x4); if (tables_addr != 0xFFFFFFFF) { ovl.WritePointer(tlists_new_addr, curoffset); ushort tables_num = oldovl.Read16(tables_addr); tables_addr = oldovl.ReadPointer(tables_addr + 0x4); ovl.Write16(curoffset, tables_num); ovl.WritePointer(curoffset + 0x04, curoffset + 0x8); curoffset += 0x8; uint objdata_offset = (uint)(curoffset + (tables_num * 8)); for (ushort t = 0; t < tables_num; t++) { uint tbl_part1 = oldovl.Read32(tables_addr); uint tbl_addr = oldovl.ReadPointer(tables_addr + 0x4); ovl.Write32(curoffset, tbl_part1); ovl.WritePointer(curoffset + 0x4, objdata_offset); tables_addr += 8; curoffset += 8; byte tbltype = (byte)(tbl_part1 & 0x1F); byte numentries = (byte)((tbl_part1 >> 8) & 0xFF); if ((tbltype == 13) || (tbltype > 14)) throw new Exception(String.Format("Wrong object table type {0} (0x{0:X2}) in level data", tbltype)); int[] datasizes = { 16, 16, 6, 6, 14, 8, 8, 8, 8, 12, 14, 2, 2, 0, 4 }; int datasize = numentries * datasizes[tbltype]; byte[] data = oldovl.ReadBlock(tbl_addr, (uint)datasize); ovl.WriteBlock(objdata_offset, data); objdata_offset += (uint)((datasize + 3) & ~3); } curoffset = objdata_offset; } else ovl.Write32(tlists_new_addr, 0); if (texanm_addr != 0xFFFFFFFF)//If not null { ovl.WritePointer(tlists_new_addr + 0x4, curoffset); uint texanm_new_addr = curoffset; curoffset += 0x18; uint textures_addr = oldovl.ReadPointer(texanm_addr + 0x14); uint numscale = 0, numrot = 0, numtrans = 0; uint numtextures = oldovl.Read32(texanm_addr + 0x10); ovl.Write32(texanm_new_addr, oldovl.Read32(texanm_addr)); ovl.Write32(texanm_new_addr + 0x10, numtextures); uint textures_new_addr = curoffset; curoffset += (numtextures * 0x1C); ovl.WritePointer(texanm_new_addr + 0x14, textures_new_addr); for (uint t = 0; t < numtextures; t++) { uint tex_old_addr = textures_addr + (t * 0x1C); uint tex_new_addr = textures_new_addr + (t * 0x1C); ushort tex_scalenum = oldovl.Read16(tex_old_addr + 0x0C); ushort tex_scalestart = oldovl.Read16(tex_old_addr + 0x0E); ushort tex_rotnum = oldovl.Read16(tex_old_addr + 0x10); ushort tex_rotstart = oldovl.Read16(tex_old_addr + 0x12); ushort tex_transnum = oldovl.Read16(tex_old_addr + 0x14); ushort tex_transstart = oldovl.Read16(tex_old_addr + 0x16); if ((tex_scalestart + tex_scalenum) > numscale) numscale = (uint)(tex_scalestart + tex_scalenum); if ((tex_rotstart + tex_rotnum) > numrot) numrot = (uint)(tex_rotstart + tex_rotnum); if ((tex_transstart + tex_transnum) > numtrans) numtrans = (uint)(tex_transstart + tex_transnum); ovl.Write32(tex_new_addr, oldovl.Read32(tex_old_addr)); ovl.WritePointer(tex_new_addr + 0x4, curoffset); ovl.Write32(tex_new_addr + 0x8, oldovl.Read32(tex_old_addr + 0x8)); ovl.Write16(tex_new_addr + 0xC, tex_scalenum); ovl.Write16(tex_new_addr + 0xE, tex_scalestart); ovl.Write16(tex_new_addr + 0x10, tex_rotnum); ovl.Write16(tex_new_addr + 0x12, tex_rotstart); ovl.Write16(tex_new_addr + 0x14, tex_transnum); ovl.Write16(tex_new_addr + 0x16, tex_transstart); ovl.Write32(tex_new_addr + 0x18, oldovl.Read32(tex_old_addr + 0x18)); string tex_matname = oldovl.ReadString(oldovl.ReadPointer(tex_old_addr + 0x4), 0); ovl.WriteString(curoffset, tex_matname, 0); curoffset += (uint)((tex_matname.Length + 3) & ~3); } uint scale_addr = oldovl.ReadPointer(texanm_addr + 0x4); ovl.WritePointer(texanm_new_addr + 0x4, curoffset); for (uint v = 0; v < numscale; v++) { ovl.Write32(curoffset, oldovl.Read32(scale_addr + (v * 4))); curoffset += 4; } uint rot_addr = oldovl.ReadPointer(texanm_addr + 0x8); ovl.WritePointer(texanm_new_addr + 0x8, curoffset); for (uint v = 0; v < numrot; v++) { ovl.Write16(curoffset, oldovl.Read16(rot_addr + (v * 2))); curoffset += 2; } curoffset = (uint)((curoffset + 3) & ~3); uint trans_addr = oldovl.ReadPointer(texanm_addr + 0xC); ovl.WritePointer(texanm_new_addr + 0xC, curoffset); for (uint v = 0; v < numtrans; v++) { ovl.Write32(curoffset, oldovl.Read32(trans_addr + (v * 4))); curoffset += 4; } } else ovl.Write32(tlists_new_addr + 0x4, 0); ovl.Write32(tlists_new_addr + 0x8, oldovl.Read32(tlists_addr + 0x8)); tlists_new_addr += 12; tlists_addr += 12; } } // misc header pieces ovl.Write32(dataoffset + 0x14, oldovl.Read32(header_offset + 0x8)); ovl.Write32(dataoffset + 0x18, oldovl.Read32(header_offset + 0xC)); ovl.Write16(dataoffset + 0x22, oldovl.Read16(header_offset + 0x16)); ovl.Write8(dataoffset + 0x24, oldovl.Read8(header_offset + 0x18)); } ovl.SaveChanges(); lazyman.ReportProgress(201 + (int)((98f / 54f) * i)); } // fix the level loader as to load from the new overlays m_FileStream.Position = lvlload_addr_patch; m_BinWriter.Write((uint)(lvl_start + dataoffset + 0xC)); m_FileStream.Position = lvlload_code_patch; m_BinWriter.Write((uint)0xE1A00000); // refill the old level header address table // to adapt it to its new usages m_FileStream.Position = levelptr_table; for (uint i = 0; i < 13; i++) { m_BinWriter.Write((uint)0xFFFFFFFF); m_BinWriter.Write((uint)0x00000000); m_BinWriter.Write((uint)0x00000000); } m_BinWriter.Write((uint)0x00000000); m_BinWriter.Write((uint)0x00000000); // fix the object banks thingy m_FileStream.Position = objbank_addr_patch; m_BinWriter.Write((uint)(levelptr_table + 0x0200009C)); m_FileStream.Position = objbank_code_patch; m_BinWriter.Write((uint)0xE1A07001); // phew! what a goddamn long thing lazyman.ReportProgress(299); }
public PathObject(NitroOverlay ovl, uint offset, int num) : base(ovl, offset, 0) { m_UniqueID = (uint)(0x30000000 | num); m_Type = 3; Parameters = new ushort[5]; Parameters[0] = m_Overlay.Read16(m_Offset); Parameters[1] = (ushort)m_Overlay.Read8(m_Offset + 0x2); Parameters[2] = (ushort)m_Overlay.Read8(m_Offset + 0x3); Parameters[3] = (ushort)m_Overlay.Read8(m_Offset + 0x4); Parameters[4] = (ushort)m_Overlay.Read8(m_Offset + 0x5); m_Properties = new PropertyTable(); GenerateProperties(); }
//private Hashtable m_PParams; public StandardObject(NitroOverlay ovl, uint offset, int num, int layer, int area) : base(ovl, offset, layer) { m_Area = area; m_UniqueID = (uint)(0x10000000 | num); m_Type = 0; ID = m_Overlay.Read16(m_Offset); Position.X = (float)((short)m_Overlay.Read16(m_Offset + 0x2)) / 1000f; Position.Y = (float)((short)m_Overlay.Read16(m_Offset + 0x4)) / 1000f; Position.Z = (float)((short)m_Overlay.Read16(m_Offset + 0x6)) / 1000f; YRotation = ((float)((short)m_Overlay.Read16(m_Offset + 0xA)) / 4096f) * 22.5f; Parameters = new ushort[3]; Parameters[0] = m_Overlay.Read16(m_Offset + 0xE); Parameters[1] = m_Overlay.Read16(m_Offset + 0x8); Parameters[2] = m_Overlay.Read16(m_Offset + 0xC); m_Renderer = InitialiseRenderer(); // m_PParams = new Hashtable(); m_Properties = new PropertyTable(); GenerateProperties(); }
private void Patch_v4(BackgroundWorker lazyman) { uint lvl_start = 0; // Music table address uint music_tbl_addr = 0; // Store locations of the music bytes (music table address, +1, +2) - update to point to within overlay uint music_tbl_byte_1_addr = 0, music_tbl_byte_2_addr = 0, music_tbl_byte_3_addr = 0; // Locations at which offsets into the music table are calculated uint music_byte_1_offset = 0, music_byte_2_offset = 0, music_byte_3_offset = 0; switch (m_Version) { case Version.EUR: music_tbl_addr = 0x75768; music_byte_1_offset = 0x2de28; music_byte_2_offset = 0x2d184; music_byte_3_offset = 0x2d360; music_tbl_byte_1_addr = 0x2de60; music_tbl_byte_2_addr = 0x2d608; music_tbl_byte_3_addr = 0x2d644; lvl_start = 34925216; break; case Version.JAP: music_tbl_addr = 0x739d8; music_byte_1_offset = 0x2cd80; music_byte_2_offset = 0x2c32c; music_byte_3_offset = 0x2c508; music_tbl_byte_1_addr = 0x2cdb8; music_tbl_byte_2_addr = 0x2c7b0; music_tbl_byte_3_addr = 0x2c7ec; lvl_start = 34878592; break; case Version.USA_v1: music_tbl_addr = 0x73434; music_byte_1_offset = 0x2caa8; music_byte_2_offset = 0x2c058; music_byte_3_offset = 0x2c234; music_tbl_byte_1_addr = 0x2cae0; music_tbl_byte_2_addr = 0x2c4d8; music_tbl_byte_3_addr = 0x2c514; lvl_start = 34880416; break; case Version.USA_v2: music_tbl_addr = 0x74154; music_byte_1_offset = 0x2cdbc; music_byte_2_offset = 0x2c368; music_byte_3_offset = 0x2c544; music_tbl_byte_1_addr = 0x2cdf4; music_tbl_byte_2_addr = 0x2c7ec; music_tbl_byte_3_addr = 0x2c828; lvl_start = 34887456; break; } // Copy level music data for (int i = 0; i < 52; i++) { NitroOverlay ovl = new NitroOverlay(this, (uint)(103 + i)); m_FileStream.Position = music_tbl_addr + (i * 3); ovl.Write8(0x7C + 0, m_BinReader.ReadByte()); ovl.Write8(0x7C + 1, m_BinReader.ReadByte()); ovl.Write8(0x7C + 2, m_BinReader.ReadByte()); ovl.SaveChanges(); } // Patch music code to load from overlays m_FileStream.Position = music_byte_1_offset;// Offset into table generated m_BinWriter.Write((uint)0xe3a03000);//MOV R3, #0 ;Set offset to 0 m_FileStream.Position = music_tbl_byte_1_addr;// Stores location of music table byte 1 m_BinWriter.Write((uint)(lvl_start + 0x7C));// Write location in overlay of music data m_FileStream.Position = music_byte_2_offset; m_BinWriter.Write((uint)0xe3a02001);//MOV R2, #1 ;Set offset to 1 m_FileStream.Position = music_tbl_byte_2_addr; m_BinWriter.Write((uint)(lvl_start + 0x7C)); m_FileStream.Position = music_byte_3_offset; m_BinWriter.Write((uint)0xe3a01002);//MOV R1, #2 ;Set offset to 0 m_FileStream.Position = music_tbl_byte_3_addr; m_BinWriter.Write((uint)(lvl_start + 0x7C)); lazyman.ReportProgress(499); }
private void Patch_v2(BackgroundWorker lazyman) { lazyman.ReportProgress(200); uint levelptr_table = 0, objbank_table = 0; uint mempatch1 = 0, mempatch2 = 0; byte[] loadercode = null; uint lvl_ovlid_table = 0; uint unload_patch = 0, unload_branchop = 0; uint[] ovltable_addr_patch = new uint[4]; uint[] ovltable_size_patch = new uint[4]; uint lvlload_addr_patch = 0, lvlload_code_patch = 0; uint objbank_addr_patch = 0, objbank_code_patch = 0; switch (m_Version) { case Version.EUR: levelptr_table = 0x92208; objbank_table = 0x75998; mempatch1 = 0x18B60; mempatch2 = 0x58DE0; loadercode = Properties.Resources.level_ovl_init_EUR; lvl_ovlid_table = 0x758C8; unload_patch = 0x2DE80; unload_branchop = ARM_BL(0x0202DE80, 0x0214EAD8); ovltable_addr_patch[0] = 0x17E90; ovltable_addr_patch[1] = 0x17F30; ovltable_addr_patch[2] = 0x17FCC; ovltable_addr_patch[3] = 0x180FC; ovltable_size_patch[0] = 0x17E80; ovltable_size_patch[1] = 0x17ED0; ovltable_size_patch[2] = 0x17F70; ovltable_size_patch[3] = 0x180C4; lvlload_addr_patch = 0x2D62C; lvlload_code_patch = 0x2D288; objbank_addr_patch = 0x2E074; objbank_code_patch = 0x2DFAC; break; case Version.JAP: levelptr_table = 0x902B8; objbank_table = 0x73C08; mempatch1 = 0x57368; mempatch2 = 0xFFFFFFFF; loadercode = Properties.Resources.level_ovl_init_JAP; lvl_ovlid_table = 0x73B38; unload_patch = 0x2CDD8; unload_branchop = ARM_BL(0x0202CDD8, 0x021434B8); ovltable_addr_patch[0] = 0x17DE4; ovltable_addr_patch[1] = 0x17E84; ovltable_addr_patch[2] = 0x17F20; ovltable_addr_patch[3] = 0x18050; ovltable_size_patch[0] = 0x17DD4; ovltable_size_patch[1] = 0x17E24; ovltable_size_patch[2] = 0x17EC4; ovltable_size_patch[3] = 0x18018; lvlload_addr_patch = 0x2C7D4; lvlload_code_patch = 0x2C430; objbank_addr_patch = 0x2CFCC; objbank_code_patch = 0x2CF04; break; case Version.USA_v1: levelptr_table = 0x8FDB0; objbank_table = 0x73664; mempatch1 = 0x56EB8; mempatch2 = 0xFFFFFFFF; loadercode = Properties.Resources.level_ovl_init_USAv1; lvl_ovlid_table = 0x73594; unload_patch = 0x2CB00; unload_branchop = ARM_BL(0x0202CB00, 0x02143BD8); ovltable_addr_patch[0] = 0x17D70; ovltable_addr_patch[1] = 0x17E10; ovltable_addr_patch[2] = 0x17EAC; ovltable_addr_patch[3] = 0x17FDC; ovltable_size_patch[0] = 0x17D60; ovltable_size_patch[1] = 0x17DB0; ovltable_size_patch[2] = 0x17E50; ovltable_size_patch[3] = 0x17FA4; lvlload_addr_patch = 0x2C4FC; lvlload_code_patch = 0x2C15C; objbank_addr_patch = 0x2CCF4; objbank_code_patch = 0x2CC2C; break; case Version.USA_v2: levelptr_table = 0x90ACC; objbank_table = 0x74384; mempatch1 = 0x18A44; mempatch2 = 0x57B30; loadercode = Properties.Resources.level_ovl_init_USAv2; lvl_ovlid_table = 0x742B4; unload_patch = 0x2CE14; unload_branchop = ARM_BL(0x0202CE14, 0x02145758); ovltable_addr_patch[0] = 0x17DE4; ovltable_addr_patch[1] = 0x17E84; ovltable_addr_patch[2] = 0x17F20; ovltable_addr_patch[3] = 0x18050; ovltable_size_patch[0] = 0x17DD4; ovltable_size_patch[1] = 0x17E24; ovltable_size_patch[2] = 0x17EC4; ovltable_size_patch[3] = 0x18018; lvlload_addr_patch = 0x2C810; lvlload_code_patch = 0x2C46C; objbank_addr_patch = 0x2D008; objbank_code_patch = 0x2CF40; break; } // tweak the root heap start address to gain more overlay space :) m_FileStream.Position = mempatch1; uint lvl_start = m_BinReader.ReadUInt32(); uint lvl_end = lvl_start + LEVEL_OVERLAY_SIZE; m_FileStream.Position = mempatch1; m_BinWriter.Write(lvl_end); if (mempatch2 != 0xFFFFFFFF) { m_FileStream.Position = mempatch2; m_BinWriter.Write(lvl_end); } // patch level overlay unloading m_FileStream.Position = unload_patch; m_BinWriter.Write(unload_branchop); // patch more stuff foreach (uint addr in ovltable_addr_patch) { m_FileStream.Position = addr; m_BinWriter.Write((uint)(0x02000000 + levelptr_table)); } foreach (uint addr in ovltable_size_patch) { m_FileStream.Position = addr; uint op = m_BinReader.ReadUInt32(); op = (op & 0xFFFFFF00) | 0x0D; m_FileStream.Position = addr; m_BinWriter.Write(op); } lazyman.ReportProgress(201); // for each level, create a new overlay with the loader code and level data uint dataoffset = (uint)((loadercode.Length + 3) & ~3); for (int i = 0; i < 52; i++) { uint overlayid = AddOverlay(lvl_start); m_FileStream.Position = lvl_ovlid_table + (i * 4); uint old_overlayid = m_BinReader.ReadUInt32(); m_FileStream.Position = lvl_ovlid_table + (i * 4); m_BinWriter.Write(overlayid); NitroOverlay ovl = new NitroOverlay(this, overlayid); ovl.SetInitializer(lvl_start, 4); ovl.WriteBlock(0, loadercode); // write the object bank settings m_FileStream.Position = objbank_table + (i * 7); byte[] objbanks = m_BinReader.ReadBytes(7); ovl.WriteBlock(dataoffset, objbanks); ovl.Write8(dataoffset + 0x7, 0x00); ovl.Write32(dataoffset + 0x8, (uint)(i + 1)); // copy level data { NitroOverlay oldovl = new NitroOverlay(this, old_overlayid); uint oldbase = oldovl.GetRAMAddr(); m_FileStream.Position = levelptr_table + (i * 4); uint header_offset = m_BinReader.ReadUInt32() - oldbase; uint curoffset = dataoffset + 0x40; // CLPS (collision behaviors) chunk { uint clps_addr = oldovl.ReadPointer(header_offset); ushort clps_num = oldovl.Read16(clps_addr + 0x06); uint clps_size = (uint)(8 + (clps_num * 8)); byte[] clps = oldovl.ReadBlock(clps_addr, clps_size); ovl.WriteBlock(curoffset, clps); ovl.WritePointer(dataoffset + 0x0C, curoffset); curoffset += clps_size; } // misc objects table list { uint tables_addr = oldovl.ReadPointer(header_offset + 0x4); ushort tables_num = oldovl.Read16(tables_addr); tables_addr = oldovl.ReadPointer(tables_addr + 0x4); ovl.WritePointer(dataoffset + 0x10, curoffset); ovl.Write16(curoffset, tables_num); ovl.WritePointer(curoffset + 0x04, curoffset + 0x8); curoffset += 0x8; uint objdata_offset = (uint)(curoffset + (tables_num * 8)); for (ushort t = 0; t < tables_num; t++) { uint tbl_part1 = oldovl.Read32(tables_addr); uint tbl_addr = oldovl.ReadPointer(tables_addr + 0x4); ovl.Write32(curoffset, tbl_part1); ovl.WritePointer(curoffset + 0x4, objdata_offset); tables_addr += 8; curoffset += 8; byte tbltype = (byte)(tbl_part1 & 0x1F); byte numentries = (byte)((tbl_part1 >> 8) & 0xFF); if ((tbltype == 13) || (tbltype > 14)) { throw new Exception(String.Format("Wrong object table type {0} (0x{0:X2}) in level data", tbltype)); } int[] datasizes = { 16, 16, 6, 6, 14, 8, 8, 8, 8, 12, 14, 2, 2, 0, 4 }; int datasize = numentries * datasizes[tbltype]; byte[] data = oldovl.ReadBlock(tbl_addr, (uint)datasize); ovl.WriteBlock(objdata_offset, data); objdata_offset += (uint)((datasize + 3) & ~3); } curoffset = objdata_offset; } // main object table lists // and that stuff about texture scrolling { uint tlists_addr = oldovl.ReadPointer(header_offset + 0x10); byte tlists_num = oldovl.Read8(header_offset + 0x14); uint tlists_new_addr = curoffset; curoffset += (uint)(tlists_num * 12); ovl.WritePointer(dataoffset + 0x1C, tlists_new_addr); ovl.Write8(dataoffset + 0x20, tlists_num); for (byte tl = 0; tl < tlists_num; tl++) { uint tables_addr = oldovl.ReadPointer(tlists_addr); uint texanm_addr = oldovl.ReadPointer(tlists_addr + 0x4); if (tables_addr != 0xFFFFFFFF) { ovl.WritePointer(tlists_new_addr, curoffset); ushort tables_num = oldovl.Read16(tables_addr); tables_addr = oldovl.ReadPointer(tables_addr + 0x4); ovl.Write16(curoffset, tables_num); ovl.WritePointer(curoffset + 0x04, curoffset + 0x8); curoffset += 0x8; uint objdata_offset = (uint)(curoffset + (tables_num * 8)); for (ushort t = 0; t < tables_num; t++) { uint tbl_part1 = oldovl.Read32(tables_addr); uint tbl_addr = oldovl.ReadPointer(tables_addr + 0x4); ovl.Write32(curoffset, tbl_part1); ovl.WritePointer(curoffset + 0x4, objdata_offset); tables_addr += 8; curoffset += 8; byte tbltype = (byte)(tbl_part1 & 0x1F); byte numentries = (byte)((tbl_part1 >> 8) & 0xFF); if ((tbltype == 13) || (tbltype > 14)) { throw new Exception(String.Format("Wrong object table type {0} (0x{0:X2}) in level data", tbltype)); } int[] datasizes = { 16, 16, 6, 6, 14, 8, 8, 8, 8, 12, 14, 2, 2, 0, 4 }; int datasize = numentries * datasizes[tbltype]; byte[] data = oldovl.ReadBlock(tbl_addr, (uint)datasize); ovl.WriteBlock(objdata_offset, data); objdata_offset += (uint)((datasize + 3) & ~3); } curoffset = objdata_offset; } else { ovl.Write32(tlists_new_addr, 0); } if (texanm_addr != 0xFFFFFFFF)//If not null { ovl.WritePointer(tlists_new_addr + 0x4, curoffset); uint texanm_new_addr = curoffset; curoffset += 0x18; uint textures_addr = oldovl.ReadPointer(texanm_addr + 0x14); uint numscale = 0, numrot = 0, numtrans = 0; uint numtextures = oldovl.Read32(texanm_addr + 0x10); ovl.Write32(texanm_new_addr, oldovl.Read32(texanm_addr)); ovl.Write32(texanm_new_addr + 0x10, numtextures); uint textures_new_addr = curoffset; curoffset += (numtextures * 0x1C); ovl.WritePointer(texanm_new_addr + 0x14, textures_new_addr); for (uint t = 0; t < numtextures; t++) { uint tex_old_addr = textures_addr + (t * 0x1C); uint tex_new_addr = textures_new_addr + (t * 0x1C); ushort tex_scalenum = oldovl.Read16(tex_old_addr + 0x0C); ushort tex_scalestart = oldovl.Read16(tex_old_addr + 0x0E); ushort tex_rotnum = oldovl.Read16(tex_old_addr + 0x10); ushort tex_rotstart = oldovl.Read16(tex_old_addr + 0x12); ushort tex_transnum = oldovl.Read16(tex_old_addr + 0x14); ushort tex_transstart = oldovl.Read16(tex_old_addr + 0x16); if ((tex_scalestart + tex_scalenum) > numscale) { numscale = (uint)(tex_scalestart + tex_scalenum); } if ((tex_rotstart + tex_rotnum) > numrot) { numrot = (uint)(tex_rotstart + tex_rotnum); } if ((tex_transstart + tex_transnum) > numtrans) { numtrans = (uint)(tex_transstart + tex_transnum); } ovl.Write32(tex_new_addr, oldovl.Read32(tex_old_addr)); ovl.WritePointer(tex_new_addr + 0x4, curoffset); ovl.Write32(tex_new_addr + 0x8, oldovl.Read32(tex_old_addr + 0x8)); ovl.Write16(tex_new_addr + 0xC, tex_scalenum); ovl.Write16(tex_new_addr + 0xE, tex_scalestart); ovl.Write16(tex_new_addr + 0x10, tex_rotnum); ovl.Write16(tex_new_addr + 0x12, tex_rotstart); ovl.Write16(tex_new_addr + 0x14, tex_transnum); ovl.Write16(tex_new_addr + 0x16, tex_transstart); ovl.Write32(tex_new_addr + 0x18, oldovl.Read32(tex_old_addr + 0x18)); string tex_matname = oldovl.ReadString(oldovl.ReadPointer(tex_old_addr + 0x4), 0); ovl.WriteString(curoffset, tex_matname, 0); curoffset += (uint)((tex_matname.Length + 3) & ~3); } uint scale_addr = oldovl.ReadPointer(texanm_addr + 0x4); ovl.WritePointer(texanm_new_addr + 0x4, curoffset); for (uint v = 0; v < numscale; v++) { ovl.Write32(curoffset, oldovl.Read32(scale_addr + (v * 4))); curoffset += 4; } uint rot_addr = oldovl.ReadPointer(texanm_addr + 0x8); ovl.WritePointer(texanm_new_addr + 0x8, curoffset); for (uint v = 0; v < numrot; v++) { ovl.Write16(curoffset, oldovl.Read16(rot_addr + (v * 2))); curoffset += 2; } curoffset = (uint)((curoffset + 3) & ~3); uint trans_addr = oldovl.ReadPointer(texanm_addr + 0xC); ovl.WritePointer(texanm_new_addr + 0xC, curoffset); for (uint v = 0; v < numtrans; v++) { ovl.Write32(curoffset, oldovl.Read32(trans_addr + (v * 4))); curoffset += 4; } } else { ovl.Write32(tlists_new_addr + 0x4, 0); } ovl.Write32(tlists_new_addr + 0x8, oldovl.Read32(tlists_addr + 0x8)); tlists_new_addr += 12; tlists_addr += 12; } } // misc header pieces ovl.Write32(dataoffset + 0x14, oldovl.Read32(header_offset + 0x8)); ovl.Write32(dataoffset + 0x18, oldovl.Read32(header_offset + 0xC)); ovl.Write16(dataoffset + 0x22, oldovl.Read16(header_offset + 0x16)); ovl.Write8(dataoffset + 0x24, oldovl.Read8(header_offset + 0x18)); } ovl.SaveChanges(); lazyman.ReportProgress(201 + (int)((98f / 54f) * i)); } // fix the level loader as to load from the new overlays m_FileStream.Position = lvlload_addr_patch; m_BinWriter.Write((uint)(lvl_start + dataoffset + 0xC)); m_FileStream.Position = lvlload_code_patch; m_BinWriter.Write((uint)0xE1A00000); // refill the old level header address table // to adapt it to its new usages m_FileStream.Position = levelptr_table; for (uint i = 0; i < 13; i++) { m_BinWriter.Write((uint)0xFFFFFFFF); m_BinWriter.Write((uint)0x00000000); m_BinWriter.Write((uint)0x00000000); } m_BinWriter.Write((uint)0x00000000); m_BinWriter.Write((uint)0x00000000); // fix the object banks thingy m_FileStream.Position = objbank_addr_patch; m_BinWriter.Write((uint)(levelptr_table + 0x0200009C)); m_FileStream.Position = objbank_code_patch; m_BinWriter.Write((uint)0xE1A07001); // phew! what a goddamn long thing lazyman.ReportProgress(299); }
public static List<AddressDataPair> GenerateRestoreData(List<AddressDataPair> patchData, string fileName = null, string overlayID = null) { List<AddressDataPair> restoreDataList = new List<AddressDataPair>(); INitroROMBlock fileToPatch = null; if (fileName != null) fileToPatch = Program.m_ROM.GetFileFromName(fileName); else if (overlayID != null) fileToPatch = new NitroOverlay(Program.m_ROM, uint.Parse(overlayID)); foreach (AddressDataPair addressDataPair in patchData) { AddressDataPair restoreData = new AddressDataPair(); restoreData.m_Address = addressDataPair.m_Address; List<byte> data = new List<byte>(); for (int i = 0; i < addressDataPair.m_Data.Length; i++) { if (fileToPatch == null) data.Add(Program.m_ROM.Read8(addressDataPair.m_Address + (uint)i)); else data.Add(fileToPatch.Read8(addressDataPair.m_Address + (uint)i)); } restoreData.m_Data = data.ToArray(); restoreDataList.Add(restoreData); } return restoreDataList; }
public void SaveFilesystem() { MemoryStream memoryStream = new MemoryStream(); BinaryWriter binWriter = new BinaryWriter((Stream)memoryStream, Encoding.ASCII); List <NitroROM.FileEntry> list1 = ((IEnumerable <NitroROM.FileEntry>) this.m_FileEntries).ToList <NitroROM.FileEntry>(); list1.RemoveAll((Predicate <NitroROM.FileEntry>)(x => x.Name == "")); list1.Sort((Comparison <NitroROM.FileEntry>)((x, y) => { if ((int)x.ParentID > (int)y.ParentID) { return(1); } return((int)x.ParentID >= (int)y.ParentID ? string.Compare(x.Name, y.Name) : -1); })); this.m_BinReader.BaseStream.Position = 0L; binWriter.Write(this.m_BinReader.ReadBytes(16384)); this.m_BinReader.BaseStream.Position = 44L; int count = this.m_BinReader.ReadInt32(); this.m_BinReader.BaseStream.Position = 16384L; binWriter.Write(this.m_BinReader.ReadBytes(count)); int position1 = (int)binWriter.BaseStream.Position; binWriter.BaseStream.Position = 48L; binWriter.Write(position1); this.m_BinReader.BaseStream.Position = 48L; int num1 = this.m_BinReader.ReadInt32(); binWriter.BaseStream.Position = (long)position1; this.m_BinReader.BaseStream.Position = (long)num1; binWriter.Write(this.m_BinReader.ReadBytes(150308)); int[] numArray1 = new int[this.m_OverlayEntries.Length + list1.Count]; int[] numArray2 = new int[this.m_OverlayEntries.Length + list1.Count]; numArray1[0] = (int)binWriter.BaseStream.Position; int length = list1.Max <NitroROM.FileEntry>((Func <NitroROM.FileEntry, int>)(x => x.InternalID != ushort.MaxValue ? (int)x.InternalID : 0)) + 1; NitroOverlay nitroOverlay = new NitroOverlay(this, 0U); int position2 = (int)binWriter.BaseStream.Position; binWriter.Write(nitroOverlay.ReadBlock(0U, 156U)); binWriter.Write(length); binWriter.Write(nitroOverlay.Read32(160U)); binWriter.Write(uint.MaxValue); binWriter.Write(nitroOverlay.ReadBlock(168U, 24U)); int[] numArray3 = new int[length]; for (int index = 0; index < list1.Count; ++index) { if (list1[index].InternalID != ushort.MaxValue) { numArray3[(int)list1[index].InternalID] = (int)binWriter.BaseStream.Position - position2 + 34251808; binWriter.Write((list1[index].FullName + "\0").ToCharArray()); Helper.AlignWriter(binWriter, 4U); } } Helper.WritePosAndRestore(binWriter, (uint)(position2 + 164), (uint)(34251808 - position2)); foreach (int num2 in numArray3) { binWriter.Write(num2); } numArray2[0] = (int)binWriter.BaseStream.Position; for (int index = 1; index < this.m_OverlayEntries.Length; ++index) { numArray1[index] = (int)binWriter.BaseStream.Position; NitroROM.FileEntry fileEntry = this.m_FileEntries[(int)this.m_OverlayEntries[index].FileID]; if (fileEntry.Data != null) { binWriter.Write(fileEntry.Data); } else { this.m_BinReader.BaseStream.Position = (long)fileEntry.Offset; binWriter.Write(this.m_BinReader.ReadBytes((int)fileEntry.Size)); } numArray2[index] = (int)binWriter.BaseStream.Position; Helper.AlignWriter(binWriter, 4U); } Helper.WritePosAndRestore(binWriter, 80U, 0U); for (int index = 0; index < this.m_OverlayEntries.Length; ++index) { binWriter.Write(index); binWriter.Write(this.m_OverlayEntries[index].RAMAddress); binWriter.Write(this.m_OverlayEntries[index].RAMSize); binWriter.Write(this.m_OverlayEntries[index].BSSSize); binWriter.Write(this.m_OverlayEntries[index].StaticInitStart); binWriter.Write(this.m_OverlayEntries[index].StaticInitEnd); binWriter.Write(index); binWriter.Write((uint)((long)this.m_OverlayEntries[index].Flags & (long)~(index == 0 ? 16777216 : 0))); } for (int index = 0; index < list1.Count; ++index) { numArray1[index + this.m_OverlayEntries.Length] = (int)binWriter.BaseStream.Position; if (list1[index].Data != null) { binWriter.Write(list1[index].Data); NitroROM.FileEntry fileEntry = list1[index]; fileEntry.Data = (byte[])null; list1[index] = fileEntry; } else { this.m_BinReader.BaseStream.Position = (long)list1[index].Offset; binWriter.Write(this.m_BinReader.ReadBytes((int)list1[index].Size)); } numArray2[index + this.m_OverlayEntries.Length] = (int)binWriter.BaseStream.Position; Helper.AlignWriter(binWriter, 4U); } int position3 = (int)binWriter.BaseStream.Position; binWriter.Write(new byte[8 * this.m_DirEntries.Length]); int[] numArray4 = new int[this.m_DirEntries.Length]; List <NitroROM.DirEntry> list2 = ((IEnumerable <NitroROM.DirEntry>) this.m_DirEntries).ToList <NitroROM.DirEntry>(); list2.RemoveAt(0); list2.Sort((Comparison <NitroROM.DirEntry>)((x, y) => { if ((int)x.ParentID > (int)y.ParentID) { return(1); } return((int)x.ParentID >= (int)y.ParentID ? string.Compare(x.Name, y.Name) : -1); })); int index1 = 0; int index2 = 0; for (int index3 = 0; index3 < this.m_DirEntries.Length; ++index3) { numArray4[index3] = (int)binWriter.BaseStream.Position - position3; for (; index1 < list1.Count && (int)list1[index1].ParentID == index3 + 61440; ++index1) { binWriter.Write((byte)list1[index1].Name.Length); binWriter.Write(list1[index1].Name.ToCharArray()); } for (; index2 < list2.Count && (int)list2[index2].ParentID == index3 + 61440; ++index2) { binWriter.Write((byte)(list2[index2].Name.Length + 128)); binWriter.Write(list2[index2].Name.ToCharArray()); binWriter.Write(list2[index2].ID); } binWriter.Write((byte)0); } Helper.AlignWriter(binWriter, 4U); int position4 = (int)binWriter.BaseStream.Position; binWriter.BaseStream.Position = (long)position3; int index4 = 0; for (int index3 = 0; index3 < this.m_DirEntries.Length; ++index3) { binWriter.Write(numArray4[index3]); binWriter.Write((ushort)(index4 + this.m_OverlayEntries.Length)); if (index3 == 0) { binWriter.Write((ushort)this.m_DirEntries.Length); } else { binWriter.Write(this.m_DirEntries[index3].ParentID); } while (index4 < list1.Count && (int)list1[index4].ParentID == index3 + 61440) { ++index4; } } binWriter.BaseStream.Position = (long)position4; for (int index3 = 0; index3 < numArray1.Length; ++index3) { binWriter.Write(numArray1[index3]); binWriter.Write(numArray2[index3]); } int position5 = (int)binWriter.BaseStream.Position; binWriter.BaseStream.Position = 64L; binWriter.Write(position3); binWriter.Write(position4 - position3); binWriter.Write(position4); binWriter.Write(position5 - position4); binWriter.BaseStream.Position = 20L; byte num3 = 0; int num4 = position5; while (num4 > 131072) { num4 >>= 1; ++num3; } binWriter.Write(num3); binWriter.BaseStream.Position = 128L; binWriter.Write(position5); this.m_FileStream.Close(); this.m_FileStream = (Stream)memoryStream; this.m_BinReader = new BinaryReader(this.m_FileStream, Encoding.ASCII); this.m_BinWriter = binWriter; this.FixCRC16(); this.AllowEmptySpaceInOv0(); this.m_BinWriter.BaseStream.SetLength((long)position5); this.EndRW(true); this.LoadROM(this.m_Path); }
public LevelObject(NitroOverlay ovl, uint offset, int layer) { m_Overlay = ovl; m_Offset = offset; m_Layer = layer; m_Area = 0; //m_TestMatrix = new Matrix4(1f, 0f, 0f, 0f, 0f, 1f, 0f, 0f, 0f, 0f, 1f, 0f, 0f, 0f, 0f, 1f); }
public PathPointObject(NitroOverlay ovl, uint offset, int num, int nodeID) : base(ovl, offset, 0) { m_UniqueID = (uint)(0x30000000 | num); m_Type = 2; m_NodeID = nodeID; Position.X = (float)((short)m_Overlay.Read16(m_Offset)) / 1000f; Position.Y = (float)((short)m_Overlay.Read16(m_Offset + 0x2)) / 1000f; Position.Z = (float)((short)m_Overlay.Read16(m_Offset + 0x4)) / 1000f; m_Renderer = InitialiseRenderer(); m_Properties = new PropertyTable(); GenerateProperties(); }