using global::SM64Lib.Data; using global::System.IO; using SM64Lib.SegmentedBanking; using System; using System.Collections.Generic; using System.Threading.Tasks; namespace SM64Lib.Geolayout.Script; public class Geolayoutscript : GeolayoutCommandCollection { public List GeopointerOffsets = []; public Geolayoutscript() { } public Task ReadAsync(RomManager rommgr, int segAddress) { var t = new Task(() => Read(rommgr, segAddress)); t.Start(); return t; } public void Read(byte[] data, byte bankID) { var ms = new MemoryStream(data); var segBank = new SegmentedBank(bankID, ms); Read(segBank, 0); } public void Read(RomManager rommgr, int segAddress) { var segBank = rommgr.GetSegBank(Convert.ToByte(segAddress >> 24)); segBank.ReadDataIfNull(rommgr.RomFile); Read(segBank, segAddress & 0x00ffffff); } public void Read(SegmentedBank segBank, int offset) { Close(); Clear(); GeopointerOffsets.Clear(); if (segBank is null) return; var data = new BinaryStreamData(segBank.Data) { Position = offset }; var tb = new List(); GeolayoutCommandTypes cb = default; int subNodeIndex = 0; bool ende = false; while (!ende) { if (data.Position >= data.Length) break; cb = (GeolayoutCommandTypes)data.ReadByte(); byte lenth = 0; switch (cb) { case GeolayoutCommandTypes.Background: lenth = 0x8; break; case GeolayoutCommandTypes.CameraPreset: lenth = 0x14; break; case GeolayoutCommandTypes.DrawingDistance: lenth = 0x4; break; case GeolayoutCommandTypes.EndOfGeolayout: lenth = 0x4; break; case GeolayoutCommandTypes.EndOfNode: lenth = 0x4; break; case GeolayoutCommandTypes.JumpBack: lenth = 0x4; break; case GeolayoutCommandTypes.JumpToSegAddr: lenth = 0x8; break; case GeolayoutCommandTypes.LoadDisplaylist: lenth = 0x8; break; case GeolayoutCommandTypes.LoadDisplaylistWithOffset: lenth = 0xC; break; case GeolayoutCommandTypes.ObjectShadown: lenth = 0x8; break; case GeolayoutCommandTypes.Scale1: lenth = 0x4; break; case GeolayoutCommandTypes.Scale2: lenth = 0x8; break; case GeolayoutCommandTypes.StartOfNode: lenth = 0x4; break; case GeolayoutCommandTypes.SetScreenRenderArea: lenth = 0xC; break; case GeolayoutCommandTypes.BillboardModel: lenth = 0x8; break; case GeolayoutCommandTypes.BranchAndStore: lenth = 0x8; break; case GeolayoutCommandTypes.CameraFrustrum: { var switchExpr = data.ReadByte(); switch (switchExpr) { case 0x1: lenth = 0xC; break; default: lenth = 0x8; break; } segBank.Data.Position -= 1; break; } case GeolayoutCommandTypes.x0B: lenth = 0x4; break; case GeolayoutCommandTypes.x0C: lenth = 0x4; break; case GeolayoutCommandTypes.x0D: lenth = 0x8; break; case GeolayoutCommandTypes.x0E: lenth = 0x8; break; case GeolayoutCommandTypes.x10: lenth = 0x10; break; case GeolayoutCommandTypes.x11: lenth = 0x8; break; case GeolayoutCommandTypes.x12: { var switchExpr = data.ReadByte() >> 4; switch (switchExpr) { case 0x8: lenth = 0xC; break; default: lenth = 0x8; break; } segBank.Data.Position -= 1; break; } case GeolayoutCommandTypes.x17: lenth = 0x4; break; case GeolayoutCommandTypes.x18: lenth = 0x8; break; case GeolayoutCommandTypes.x1A: lenth = 0x8; break; case GeolayoutCommandTypes.x1C: lenth = 0xC; break; case var @case when @case == GeolayoutCommandTypes.x1E: lenth = 0x8; break; case var case1 when case1 == GeolayoutCommandTypes.x1f: lenth = 0x10; break; default: break; } segBank.Data.Position -= 1; if (lenth == 0 || segBank.Data.Position + lenth > segBank.Data.Length) break; for (int i = 1, loopTo = lenth; i <= loopTo; i++) tb.Add(data.ReadByte()); var tCommand = new GeolayoutCommand(tb.ToArray()); int bankOffset = (int)(segBank.Data.Position - lenth); tCommand.RomAddress = segBank.RomStart + bankOffset; tCommand.BankAddress = segBank.BankAddress + bankOffset; Add(tCommand); tb.Clear(); var switchExpr1 = tCommand.CommandType; switch (switchExpr1) { case GeolayoutCommandTypes.EndOfGeolayout: ende = true; break; case GeolayoutCommandTypes.EndOfNode: subNodeIndex -= 1; break; case GeolayoutCommandTypes.StartOfNode: subNodeIndex += 1; break; } } } public void Write(Stream s, int GeolayoutStart) { var bw = new BinaryWriter(s); // Write new Levelscript s.Position = GeolayoutStart; foreach (GeolayoutCommand c in this) { if (c.CommandType == GeolayoutCommandTypes.LoadDisplaylist) GeopointerOffsets.Add((int)(s.Position + 0x4)); foreach (byte b in c.ToArray()) bw.Write(b); } } public GeolayoutCommand GetFirst(GeolayoutCommandTypes cmdType) { foreach (GeolayoutCommand cmd in this) { if (cmd.CommandType == cmdType) { return cmd; } } return null; } }