private static void HeaderFix_cmd17(ROM rom, ROM initROM, out bool isFixed) { int segment = rom.Read8(3); int startAddress = initROM.GetSegmentDescriptor(0x0E).start; int endAddress = startAddress + initROM.GetSegmentDescriptor(0x0E).length; if (segment != 0x0E) { isFixed = false; return; } rom.Write32(startAddress, 4); rom.Write32(endAddress, 8); isFixed = true; }
public static void PerformHeaderParse(ROM rom, int offset) { rom.PushOffset(offset); RegionParseState state = new RegionParseState(); state.start = rom.offset; byte curCmdIndex; int stepCounter = 0; do { curCmdIndex = rom.Read8(); byte curCmdSize = rom.Read8(1); if (curCmdSize == 0) { throw new ArgumentException("cmd size is 0, loop detected"); } if (curCmdIndex == 0x00) { HeaderParse_cmd00(rom); } if (curCmdIndex == 0x17) { HeaderParse_cmd17(rom); } rom.AddOffset(curCmdSize); stepCounter++; if (stepCounter > 100) { throw new ArgumentException("Bank 0x19 && 0x0E loader was not detected"); } }while (rom.GetSegmentDescriptor(0x0E) == null || rom.GetSegmentDescriptor(0x19) == null); rom.PopOffset(); }
public static void FixLoadAddresses(ROM initROM, Region region) { // This is fake rom but it works anyways, just more convenient ROM rom = new ROM(region.data); RegionParseState state = new RegionParseState(); state.start = rom.offset; byte curCmdIndex; int stepCounter = 0; do { curCmdIndex = rom.Read8(); byte curCmdSize = rom.Read8(1); if (curCmdSize == 0) { throw new ArgumentException("cmd size is 0, loop detected"); } if (curCmdIndex == 0x17) { bool isFixed; HeaderFix_cmd17(rom, initROM, out isFixed); if (isFixed) { break; } } rom.AddOffset(curCmdSize); stepCounter++; if (stepCounter > 100) { throw new ArgumentException("Bank 0x19 && 0x0E loader was not detected"); } }while (rom.GetSegmentDescriptor(0x0E) == null || rom.GetSegmentDescriptor(0x19) == null); }
private void button1_Click(object sender, EventArgs e) { GC.Collect(); OpenFileDialog openFileDialog1 = new OpenFileDialog(); openFileDialog1.Filter = "ROM File|*.z64"; openFileDialog1.Title = "Select a ROM"; if (openFileDialog1.ShowDialog() != System.Windows.Forms.DialogResult.OK) { return; } string path = openFileDialog1.FileName; path = Path.GetFullPath(path); ROM rom = new ROM(File.ReadAllBytes(path)); int offset = Convert.ToInt32(addressTextBox.Text, 16); if (offset == 0) { MessageBox.Show("Failed to parse address, input correct address", "Level Split", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } LevelScript.PerformHeaderParse(rom, offset); SegmentDescriptor segmentDescriptor0E = rom.GetSegmentDescriptor(0x0E); SegmentDescriptor segmentDescriptor19 = rom.GetSegmentDescriptor(0x19); DataBuilder segment0E = new DataBuilder(segmentDescriptor0E.start, segmentDescriptor0E.length); DataBuilder segment19 = new DataBuilder(segmentDescriptor19.start, segmentDescriptor19.length); string dirname = splittedPathTextBox.Text; // Fill in area relocation table + geolayouts KeyRelocationTable areaGraphicsDescrRelocationTable = new KeyRelocationTable(); KeyRelocationTable areaGraphicsDataRelocationTable = new KeyRelocationTable(); KeyRelocationTable areaCollisionRelocationTable = new KeyRelocationTable(); for (int area = 1; area <= 8; area++) { if (!PathComposer.IsRegionFileExists(dirname, RegionState.GraphicsData, area: area)) { continue; } // Area graphics ParseGraphics(dirname, segment0E, segment19, rom, out RelocationUnit descrUnit, out RelocationUnit dataUnit, area: area); areaGraphicsDescrRelocationTable.AddUnit(area, descrUnit); areaGraphicsDataRelocationTable.AddUnit(area, dataUnit); // Area collision DynamicRegion collision = new DynamicRegion(dirname, RegionState.Collision, area: area); // No relocation needed segment0E.AddRegion(collision); segment0E.RoundOffset(); RelocationUnit collisionRelocationUnit = new RelocationUnit(collision, rom, isFromStatic: true); areaCollisionRelocationTable.AddUnit(area, collisionRelocationUnit); } // Fill in model relocation table + geolayouts KeyRelocationTable modelRelocationTable = new KeyRelocationTable(); for (int model = 0x00; model < 0xFF; model++) { if (!PathComposer.IsRegionFileExists(dirname, RegionState.GraphicsData, model: model)) { continue; } ParseGraphics(dirname, segment0E, segment19, rom, out RelocationUnit descrUnit, out RelocationUnit graphicsUnit, model: model); modelRelocationTable.AddUnit(model, descrUnit); } // As everything is prepared, we can finally start building level! LevelScriptRegion levelHeader = new LevelScriptRegion(dirname, RegionState.LevelHeader); LevelScript.FixLoadAddresses(rom, levelHeader); segment19.AddRegion(levelHeader); int levelScriptSegmentedAddressStart = rom.GetSegmentedAddress(levelHeader.romStart); LevelScriptRegion modelsLoader = new LevelScriptRegion(dirname, RegionState.ModelsLoader); modelsLoader.Relocate(modelRelocationTable); segment19.AddRegion(modelsLoader); for (sbyte area = 0; area < 8; area++) { if (!PathComposer.IsRegionFileExists(dirname, RegionState.GraphicsData, area: area)) { continue; } // Area header initializes graphics LevelScriptRegion areaHeader = new LevelScriptRegion(dirname, RegionState.AreaHeader, area: area); LevelScript.PerformRegionRelocation(areaHeader, areaGraphicsDescrRelocationTable, area); segment19.AddRegion(areaHeader); LevelScriptRegion areaData = new LevelScriptRegion(dirname, RegionState.AreaData, area: area); // No relocation needed segment19.AddRegion(areaData); if (PathComposer.IsRegionFileExists(dirname, RegionState.AreaScrolls, area: area)) { LevelScriptRegion scrollsData = new LevelScriptRegion(dirname, RegionState.AreaScrolls, area: area); LevelScript.PerformRegionRelocation(scrollsData, areaGraphicsDataRelocationTable, area); segment19.AddRegion(scrollsData); } // Area footer initializes collision LevelScriptRegion areaFooter = new LevelScriptRegion(dirname, RegionState.AreaFooter, area: area); LevelScript.PerformRegionRelocation(areaFooter, areaCollisionRelocationTable, area); segment19.AddRegion(areaFooter); } LevelScriptRegion levelFooter = new LevelScriptRegion(dirname, RegionState.LevelFooter); // no relocation needed segment19.AddRegion(levelFooter); // At this point we know that all data fit in rom // So just write all that in rom using (Stream stream = new FileStream(path, FileMode.Open)) { stream.Seek(segmentDescriptor0E.start, SeekOrigin.Begin); stream.Write(segment0E.Data, 0, segment0E.Offset); stream.Seek(segmentDescriptor19.start, SeekOrigin.Begin); stream.Write(segment19.Data, 0, segment19.Offset); // Also start of level script moved so write that thing too int endianData = IPAddress.HostToNetworkOrder(levelScriptSegmentedAddressStart); byte[] convertedData = BitConverter.GetBytes(endianData); stream.Seek(rom.levelScriptEntryOffset, SeekOrigin.Begin); stream.Write(convertedData, 0, 4); } MessageBox.Show(String.Format("ROM was build successfully from {0}", dirname), "Level Split", MessageBoxButtons.OK, MessageBoxIcon.Information); }