public static void PerformRegionRelocation(Region region, RelocationTable table, sbyte area = -1) { // This is fake rom but it works anyways, just more convenient ROM rom = new ROM(region.data); RegionParseState state = new RegionParseState(); state.area = area; byte curCmdIndex; while (rom.offset < region.length) { curCmdIndex = rom.Read8(); byte curCmdSize = rom.Read8(1); if (curCmdSize == 0) { throw new ArgumentException("cmd size is 0, loop detected"); } RelocationParseCmd func = relocationParser[curCmdIndex]; func(rom, table, state); if (curCmdIndex != 0x7) { rom.AddOffset(curCmdSize); } } }
private static void RegionParse_cmd06(ROM rom, List <Region> regions, RegionParseState state) { int segment = rom.Read8(4); if (segment != 0x0e) { return; } int type = rom.Read8(1); if (type != 0) { throw new NotSupportedException("Terminating Branch not supported!"); } int segmentedAddress = rom.Read32(4); int address = rom.GetROMAddress(segmentedAddress); List <Region> regionsBranch = new List <Region>(); RegionParseState stateBranch = PerformRegionParseInternal(rom, regionsBranch, address, 0); // TODO: Copy/update more if needed if (stateBranch.FDAddress != -1) { state.FDAddress = stateBranch.FDAddress; } foreach (Region region in regionsBranch) { state.textureData.AddRegion(region.romStart, region.length); } }
public static void PerformRegionParse(ROM rom, List <Region> regions, int offset) { rom.PushOffset(offset); try { int cmd = 0; do { if (rom.Read8() != 0x00) { throw new ArgumentException("invalid instruction"); } cmd = rom.Read8(1); if (cmd >= 0x40 && cmd <= 0x44) { parser[cmd - 0x40](rom, regions); } else { RegionParse_common(rom, regions); } }while (cmd != 0x42); Region region = new DynamicRegion(offset, rom.offset - offset, RegionState.Collision); regions.Add(region); } finally { rom.PopOffset(); } }
private static void RegionParse_cmd15(ROM rom, List <Region> regions) { int segment = rom.Read8(4); if (segment != 0x0e) { return; } int segmentedAddress = rom.Read32(4); int address = (int)rom.GetROMAddress(segmentedAddress); DisplayList.PerformRegionParse(rom, regions, address, rom.Read8(1)); }
private static void RegionParse_cmd2E(ROM rom, List <Region> regions, RegionParseState state) { int segmentedAddress = rom.Read32(4); int segment = rom.Read8(4); // Only 0x19 or 0x0E commands are supported if (segment != 0x19 && segment != 0x0E) { return; } try { List <Region> collisionRegions = new List <Region>(); Collision.PerformRegionParse(rom, collisionRegions, (int)rom.GetROMAddress(segmentedAddress)); foreach (Region region in collisionRegions) { region.area = state.area; } regions.AddRange(collisionRegions); } catch (NotSupportedException e) { MessageBox.Show(String.Format("Model {0} collision parsing is not supported! Reason : '{1}'", state.area, e.Message), "Level Parser", MessageBoxButtons.OK, MessageBoxIcon.Error); } catch (Exception e) { MessageBox.Show(String.Format("Failed to parse model {0} collision! Reason : '{1}'", state.area, e.Message), "Level Parser", MessageBoxButtons.OK, MessageBoxIcon.Error); } }
private static void OptimizeParse_cmd04(ROM rom, DisplayListRegion region, RegionOptimizeState state) { // initial state if (state.last04Cmd == 0) { state.last04Cmd = rom.Read64(); return; } Int64 cmd = rom.Read64(); // if current 04 loads the same vertices, remove current cmd if (cmd == state.last04Cmd) { rom.Write64(0); return; } // new vertices are being loaded, update the thing state.last04Cmd = cmd; // if previous cmd is 0x04, it will be overriden by current 04 anyways if (rom.Read8(-8) == 0x04) { rom.Write64(0, -8); } }
public static void PerformRegionRelocation(Region region, RelocationTable table) { // This is fake rom but it works anyways, just more convenient ROM rom = new ROM(region.data); byte cmd; do { cmd = rom.Read8(); int cmdSize = cmdSizeTable[cmd]; if (cmdSize == 0) { throw new ArgumentException("Loop detected"); } RelocationParseCmd func = relocationParser[cmd]; func(rom, table); if (cmdSize != 0xFF) { rom.AddOffset(cmdSize); } }while (rom.offset < region.length); }
private static void RegionParse_common(ROM rom, List <Region> regions) { // Triangles of any collision int size = rom.Read16(2); if (size == 0) { throw new ArgumentException("common collision loop detected"); } int collType = rom.Read8(1); int triangleSize = 6; switch (collType) { case 0x0E: case 0x24: case 0x25: case 0x27: case 0x2C: case 0x2D: triangleSize = 8; break; } rom.AddOffset(4 + size * triangleSize); }
private static void TriangleMapParse_cmd04(ROM rom, TriangleMap map, TriangleMapParseState state) { state.vertexLoadCmd = (UInt64)rom.Read64(); byte vertexDesc = rom.Read8(1); byte vertexCount = (byte)(((vertexDesc & 0xF0) >> 4) + 1); byte vertexOffset = (byte)((vertexDesc & 0x0F)); Int32 vertexSegmentedAddress = rom.Read32(4); state.segmentedVertexBufferAddress = vertexSegmentedAddress; Int32 romPtr = rom.GetROMAddress(vertexSegmentedAddress); if (romPtr == -1) { throw new ArgumentException("Invalid segmented address!"); } rom.PushOffset(romPtr); for (int vertex = vertexOffset; vertex < vertexCount; vertex++) { Int64 lo = rom.Read64(); Int64 hi = rom.Read64(8); state.vbuf[vertex] = new Vertex((UInt64)lo, (UInt64)hi); state.vbufRomStart[vertex] = rom.offset; state.scrollBuf[vertex] = FindMatchingScroll(state.scrolls, vertexSegmentedAddress, state.td); rom.AddOffset(0x10); vertexSegmentedAddress += 0x10; } rom.PopOffset(); }
private static void TriangleMapParse_cmdBF(ROM rom, TriangleMap map, TriangleMapParseState state) { state.isHeader = false; state.state = VisualMapParseStateCmd.Footer; byte v0index = (byte)(rom.Read8(5) / 0xA); byte v1index = (byte)(rom.Read8(6) / 0xA); byte v2index = (byte)(rom.Read8(7) / 0xA); state.vertexBytes.AddRegion(state.vbufRomStart[v0index], 0x10); state.vertexBytes.AddRegion(state.vbufRomStart[v1index], 0x10); state.vertexBytes.AddRegion(state.vbufRomStart[v2index], 0x10); // This assumes all scrolls are scrolling at the same speed which is usually true :3 if (state.scrollBuf[v0index] != state.scrollBuf[v1index] || state.scrollBuf[v0index] != state.scrollBuf[v2index] || state.scrollBuf[v1index] != state.scrollBuf[v2index]) { throw new Exception("Vertices are scrolling at different scrolls"); } Scroll scroll = state.scrollBuf[v0index]; if ((scroll == null && state.td.scroll != null) || (scroll != null && !scroll.Equals(state.td.scroll))) { ScrollingTextureDescription oldTd = state.td; state.td = new ScrollingTextureDescription(); state.td.AddRange(oldTd); state.td.scroll = scroll; if (scroll is EditorScroll editorScroll) { state.td.RegisterScroll(editorScroll); } if (scroll is TextureScroll) { state.td.omitScrollCheck = true; } } state.td.RegisterVertex(state.segmentedVertexBufferAddress + v0index * 0x10); state.td.RegisterVertex(state.segmentedVertexBufferAddress + v1index * 0x10); state.td.RegisterVertex(state.segmentedVertexBufferAddress + v2index * 0x10); map.AddTriangle(state.td, state.vbuf[v0index], state.vbuf[v1index], state.vbuf[v2index]); }
public static void PerformVisualMapRebuild(ROM realRom, Region region, int maxDLLength) { // This is fake rom but it works anyways, just more convenient // Want to be safe with overwriting the whole display list ROM fakeRom = new ROM(region.data); VisualMapParseState state = new VisualMapParseState(); DisplayListRegion dlRegion = (DisplayListRegion)region; VisualMap map = new VisualMap(); byte curCmdIndex; do { curCmdIndex = fakeRom.Read8(); VisualMapParserCmd func = visualMapParser[curCmdIndex]; func(fakeRom, map, state); fakeRom.AddOffset(8); }while (fakeRom.offset < region.length); ROM visualMapROM = new ROM(new byte[maxDLLength]); int visualMapLength = map.MakeF3D(visualMapROM); // Now write data to real rom + trimming // bzero fakeRom.offset = 0; realRom.PushOffset(region.romStart); { do { realRom.Write64(0x0101010101010101); realRom.AddOffset(8); fakeRom.AddOffset(8); } while (fakeRom.offset < region.length); } realRom.PopOffset(); visualMapROM.offset = 0; realRom.PushOffset(region.romStart); { int start = region.romStart; do { Int64 cmd = visualMapROM.Read64(); visualMapROM.AddOffset(8); realRom.Write64((ulong)cmd); realRom.AddOffset(8); } while (visualMapROM.offset < visualMapLength); region.length = realRom.offset - start; region.data = new byte[region.length]; realRom.ReadData(region.romStart, region.length, region.data); } realRom.PopOffset(); }
public static void PerformRegionOptimize(ROM realRom, Region region, FixConfig config) { // This is fake rom but it works anyways, just more convenient // Want to be safe with overwriting the whole display list ROM fakeRom = new ROM(region.data); RegionOptimizeState state = new RegionOptimizeState(config); DisplayListRegion dlRegion = (DisplayListRegion)region; byte curCmdIndex; do { curCmdIndex = fakeRom.Read8(); OptimizeParserCmd func = optimizeParser[curCmdIndex]; func(fakeRom, dlRegion, state); fakeRom.AddOffset(8); }while (fakeRom.offset < region.length); // Now write data to real rom + trimming // bzero fakeRom.offset = 0; realRom.PushOffset(region.romStart); { do { realRom.Write64(0x0101010101010101); realRom.AddOffset(8); fakeRom.AddOffset(8); } while (fakeRom.offset < region.length); } realRom.PopOffset(); fakeRom.offset = 0; realRom.PushOffset(region.romStart); { int start = region.romStart; do { Int64 cmd = fakeRom.Read64(); fakeRom.AddOffset(8); if (config.trimNOPs && cmd == 0 && dlRegion.isUnusedTrimmingAllowed) { continue; } realRom.Write64((ulong)cmd); realRom.AddOffset(8); } while (fakeRom.offset < region.length); region.length = realRom.offset - start; region.data = new byte[region.length]; realRom.ReadData(region.romStart, region.length, region.data); } realRom.PopOffset(); }
private static void RegionParse_common(ROM rom, List <Region> regions, RegionParseState state) { int curCmd = rom.Read8(); if ((state.regionState == RegionState.AreaData || state.regionState == RegionState.AreaScrolls) && curCmd != 0x24 && curCmd != 0x26) { CutRegion(rom, regions, state, rom.offset, RegionState.AreaFooter); } }
private static void HeaderParse_cmd17(ROM rom) { int segment = rom.Read8(3); int startAddress = rom.Read32(4); int endAddress = rom.Read32(8); SegmentDescriptor descriptor = new SegmentDescriptor(startAddress, endAddress - startAddress); rom.SetSegment(segment, descriptor); }
public EditorScroll(ROM rom) : base(rom) { segmentedAddress = 0x0e000000; acts = rom.Read8(0x02); X = rom.Read16(0x04); Y = rom.Read16(0x06); Z = rom.Read16(0x08); BParam = rom.Read16(0x10); BParam2 = rom.Read16(0x12); }
public static void Trim(Region region, bool addObjects) { ROM rom = new ROM(region.data); MemoryStream trimmedObject = new MemoryStream(); while (rom.offset < region.length) { byte curCmdIndex = rom.Read8(); byte curCmdSize = rom.Read8(1); if (curCmdIndex == 0x24) { byte acts = rom.Read8(2); if (acts == 0) { goto fini; } } byte[] data = new byte[curCmdSize]; rom.ReadData(rom.offset, curCmdSize, data); trimmedObject.Write(data, 0, curCmdSize); fini: rom.AddOffset(curCmdSize); } if (addObjects) { trimmedObject.Write(emptyObject, 0, emptyObject.Count()); trimmedObject.Write(emptyObject, 0, emptyObject.Count()); trimmedObject.Write(emptyObject, 0, emptyObject.Count()); trimmedObject.Write(emptyObject, 0, emptyObject.Count()); trimmedObject.Write(emptyObject, 0, emptyObject.Count()); } region.data = trimmedObject.ToArray(); region.length = (int)trimmedObject.Length; trimmedObject.Dispose(); }
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 static void RegionParse_cmd22(ROM rom, List <Region> regions, RegionParseState state) { if (state.regionState != RegionState.ModelsLoader) { CutRegion(rom, regions, state, rom.offset, RegionState.ModelsLoader); } int segmentedAddress = rom.Read32(4); int segment = rom.Read8(4); int model = rom.Read8(3); // Only 0x19 or 0x0E commands are supported if (segment != 0x19 && segment != 0x0E) { return; } try { List <Region> modelRegions = new List <Region>(); int geoLayoutROMAddress = rom.GetROMAddress(segmentedAddress); GeoLayout.PerformRegionParse(rom, modelRegions, geoLayoutROMAddress); foreach (Region region in modelRegions) { region.model = model; } regions.AddRange(modelRegions); } catch (NotSupportedException e) { MessageBox.Show(String.Format("Model {0} graphics parsing is not supported! Reason : '{1}'", state.area, e.Message), "Level Parser", MessageBoxButtons.OK, MessageBoxIcon.Error); } catch (Exception e) { MessageBox.Show(String.Format("Failed to parse model {0} graphics! Reason : '{1}'", state.area, e.Message), "Level Parser", MessageBoxButtons.OK, MessageBoxIcon.Error); } }
private static void RegionParse_cmd1F(ROM rom, List <Region> regions, RegionParseState state) { CutRegion(rom, regions, state, rom.offset, RegionState.AreaHeader); int segmentedAddress = rom.Read32(4); int segment = rom.Read8(4); sbyte area = (sbyte)rom.Read8(2); state.area = area; state.regionState = RegionState.AreaHeader; // Only 0x19 or 0x0E commands are supported // Usually it is in segment 19 anyways if (segment != 0x19 && segment != 0x0E) { return; } int geoLayoutROMAddress = rom.GetROMAddress(segmentedAddress); List <Region> areaGeolayoutRegions = new List <Region>(); try { GeoLayout.PerformRegionParse(rom, areaGeolayoutRegions, geoLayoutROMAddress); foreach (Region region in areaGeolayoutRegions) { region.area = area; } regions.AddRange(areaGeolayoutRegions); } catch (NotSupportedException e) { MessageBox.Show(String.Format("Area {0} graphics parsing is not supported! Reason : '{1}'", state.area, e.Message), "Level Parser", MessageBoxButtons.OK, MessageBoxIcon.Error); } catch (Exception e) { MessageBox.Show(String.Format("Failed to parse area {0} graphics! Reason : '{1}'", state.area, e.Message), "Level Parser", MessageBoxButtons.OK, MessageBoxIcon.Error); } }
public static void PerformRegionParse(ROM rom, List <Region> regions, int offset, bool isOldScrollBehaviour) { rom.PushOffset(offset); RegionParseState state = new RegionParseState { start = rom.offset, isOldBehaviourChecked = isOldScrollBehaviour }; byte curCmdIndex; do { curCmdIndex = rom.Read8(); byte curCmdSize = rom.Read8(1); if (curCmdSize == 0) { throw new ArgumentException("cmd size is 0, loop detected"); } RegionParseCmd func = regionParser[curCmdIndex]; if (func != RegionParse_common) { RegionParse_common(rom, regions, state); } func(rom, regions, state); if (curCmdIndex != 0x7) { rom.AddOffset(curCmdSize); } }while (curCmdIndex != terminateCmd); rom.PopOffset(); }
private static void RegionParse_cmd10(ROM rom, List <Region> regions, RegionParseState state) { if (rom.Read64() == 0x1008000000000000) { if (rom.offset == state.start) { state.start = rom.offset + rom.Read8(1); } // Skip empty commands in the beginning of any region else if (rom.offset == state.start + rom.Read8(1)) { state.start = rom.offset + rom.Read8(1); } else { // Commands is not in the beginning, cut area, start new one that is same as it was before if (state.regionState == RegionState.ModelsLoader) { CutRegion(rom, regions, state, rom.offset, state.regionState); } } } }
private static void RegionParse_cmd03(ROM rom, List <Region> regions, RegionParseState state) { int segment = rom.Read8(4); if (segment != 0x0e) { return; } int segmentedAddress = rom.Read32(4); int address = rom.GetROMAddress(segmentedAddress); state.lightData.AddRegion(address, 0x8); }
public static void PerformRegionParse(ROM rom, List <Region> regions, int offset, out Dictionary <int, List <ScrollObject> > scrolls) { rom.PushOffset(offset); RegionParseState state = new RegionParseState(); state.start = rom.offset; byte curCmdIndex; do { curCmdIndex = rom.Read8(); byte curCmdSize = rom.Read8(1); if (curCmdSize == 0) { throw new ArgumentException("cmd size is 0, loop detected"); } RegionParseCmd func = regionParser[curCmdIndex]; if (func != RegionParse_common) { RegionParse_common(rom, regions, state); } func(rom, regions, state); if (curCmdIndex != 0x7) { rom.AddOffset(curCmdSize); } }while (curCmdIndex != terminateCmd); rom.PopOffset(); scrolls = state.scrolls; }
private static void RegionParse_cmd04(ROM rom, List <Region> regions, RegionParseState state) { int segment = rom.Read8(4); if (segment != 0x0e) { return; } int segmentedAddress = rom.Read32(4); int address = rom.GetROMAddress(segmentedAddress); state.vertexData.AddRegion(address, rom.Read16(2)); //regions.Add(new Region(address, rom.Read16(2), RegionState.VertexInfo)); }
private static void VisualMapParse_cmdFB(ROM rom, VisualMap map, VisualMapParseState state) { // Some importers have the only EnvColor func for everything lmfao if (rom.Read8(8) != 0xFD) { goto fini; } state.envColorCmd = (ulong)rom.Read64(); state.state = VisualMapParseStateCmd.Texture; state.td = new TextureDescription(); fini: VisualMapParse_common(rom, map, state); }
public static void PerformRegionRelocation(Region region, RelocationTable table) { // This is fake rom but it works anyways, just more convenient ROM rom = new ROM(region.data); byte curCmdIndex; do { curCmdIndex = rom.Read8(); RelocationParseCmd func = relocationParser[curCmdIndex]; func(rom, table, (DisplayListRegion)region); rom.AddOffset(8); }while (rom.offset < region.length); }
private static void RegionParse_cmd17(ROM rom, List <Region> regions, RegionParseState state) { int segment = rom.Read8(3); int startAddress = rom.Read32(4); int endAddress = rom.Read32(8); if ((uint)startAddress > 0x4000000) { return; } SegmentDescriptor descriptor = new SegmentDescriptor(startAddress, endAddress - startAddress); rom.SetSegment(segment, descriptor); }
private static void RegionParse_cmdFD(ROM rom, List <Region> regions, RegionParseState state) { state.FDAddress = -1; int segment = rom.Read8(4); if (segment != 0x0e) { return; } int segmentedAddress = rom.Read32(4); int address = (int)rom.GetROMAddress(segmentedAddress); state.FDAddress = address; }
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; }