diff --git a/SM64Lib.LIBMIO0/MIO0.cs b/SM64Lib.LIBMIO0/MIO0.cs index 085db25..f94338d 100644 --- a/SM64Lib.LIBMIO0/MIO0.cs +++ b/SM64Lib.LIBMIO0/MIO0.cs @@ -1,151 +1,148 @@ -using System; +namespace SM64Lib.LIBMIO0; -namespace SM64Lib.LIBMIO0 +public struct MIO0_Header { - public struct MIO0_Header + public uint dest_size; + public uint comp_offset; + public uint uncomp_offset; + public bool big_endian; +}; + +public class MIO0 +{ + + private const int MIO0_HEADER_LENGTH = 16; + + private static int GET_BIT(byte[] buf, int offset, int bit) { - public uint dest_size; - public uint comp_offset; - public uint uncomp_offset; - public bool big_endian; - }; + return buf[(bit / 8) + offset] & (1 << (7 - (bit % 8))); + } - public class MIO0 + private static bool compareByteArrays(byte[] buf1, byte[] buf2, int length) { + for (int i = 0; i < length; ++i) + if (buf1[i] != buf2[i]) return false; + return true; + } - private const int MIO0_HEADER_LENGTH = 16; + private static uint read_u32_be(byte[] buf, int off) + { + return (uint)(((buf)[off + 0] << 24) + ((buf)[off + 1] << 16) + + ((buf)[off + 2] << 8) + ((buf)[off + 3])); + } - private static int GET_BIT(byte[] buf, int offset, int bit) + private static uint read_u32_le(byte[] buf, int off) + { + return (uint)(((buf)[off + 1] << 24) + ((buf)[off + 0] << 16) + + ((buf)[off + 3] << 8) + ((buf)[off + 2])); + } + + private static void write_u32_be(byte[] buf, uint val, int off) + { + buf[off + 0] = (byte)((val >> 24) & 0xFF); + buf[off + 1] = (byte)((val >> 16) & 0xFF); + buf[off + 2] = (byte)((val >> 8) & 0xFF); + buf[off + 3] = (byte)(val & 0xFF); + } + + /// + /// decode MIO0 header + /// returns true if valid header, false otherwise + /// + public static bool decode_header(byte[] buf, ref MIO0_Header head) + { + byte[] mio0_ascii_be = new byte[] { 0x4D, 0x49, 0x4F, 0x30 }; + byte[] mio0_ascii_le = new byte[] { 0x49, 0x4D, 0x30, 0x4F }; + + if (compareByteArrays(buf, mio0_ascii_be, 4)) { - return buf[(bit / 8) + offset] & (1 << (7 - (bit % 8))); + head.dest_size = read_u32_be(buf, 4); + head.comp_offset = read_u32_be(buf, 8); + head.uncomp_offset = read_u32_be(buf, 12); + head.big_endian = true; + return true; } - - private static bool compareByteArrays(byte[] buf1, byte[] buf2, int length) + else if (compareByteArrays(buf, mio0_ascii_le, 4)) { - for (int i = 0; i < length; ++i) - if (buf1[i] != buf2[i]) return false; + head.dest_size = read_u32_le(buf, 4); + head.comp_offset = read_u32_le(buf, 8); + head.uncomp_offset = read_u32_le(buf, 12); + head.big_endian = false; return true; } - private static uint read_u32_be(byte[] buf, int off) - { - return (uint)(((buf)[off + 0] << 24) + ((buf)[off + 1] << 16) + - ((buf)[off + 2] << 8) + ((buf)[off + 3])); - } - - private static uint read_u32_le(byte[] buf, int off) - { - return (uint)(((buf)[off + 1] << 24) + ((buf)[off + 0] << 16) + - ((buf)[off + 3] << 8) + ((buf)[off + 2])); - } - - private static void write_u32_be(byte[] buf, uint val, int off) - { - buf[off + 0] = (byte)((val >> 24) & 0xFF); - buf[off + 1] = (byte)((val >> 16) & 0xFF); - buf[off + 2] = (byte)((val >> 8) & 0xFF); - buf[off + 3] = (byte)(val & 0xFF); - } - - /// - /// decode MIO0 header - /// returns true if valid header, false otherwise - /// - public static bool decode_header(byte[] buf, ref MIO0_Header head) - { - byte[] mio0_ascii_be = new byte[] { 0x4D, 0x49, 0x4F, 0x30 }; - byte[] mio0_ascii_le = new byte[] { 0x49, 0x4D, 0x30, 0x4F }; - - if (compareByteArrays(buf, mio0_ascii_be, 4)) - { - head.dest_size = read_u32_be(buf, 4); - head.comp_offset = read_u32_be(buf, 8); - head.uncomp_offset = read_u32_be(buf, 12); - head.big_endian = true; - return true; - } - else if (compareByteArrays(buf, mio0_ascii_le, 4)) - { - head.dest_size = read_u32_le(buf, 4); - head.comp_offset = read_u32_le(buf, 8); - head.uncomp_offset = read_u32_le(buf, 12); - head.big_endian = false; - return true; - } - - return false; - } - - /// - /// encode MIO0 header from struct - /// - public static void encode_header(byte[] buf, ref MIO0_Header head) - { - write_u32_be(buf, 0x4D494F30, 0); // write "MIO0" at start of buffer - write_u32_be(buf, head.dest_size, 4); - write_u32_be(buf, head.comp_offset, 8); - write_u32_be(buf, head.uncomp_offset, 12); - } - - /// - /// decode MIO0 data - /// mio0_buf: buffer containing MIO0 data - /// returns the raw data as a byte array - /// - public static byte[] mio0_decode(byte[] mio0_buf) - { - - MIO0_Header head = new MIO0_Header(); - uint bytes_written = 0; - int bit_idx = 0; - int comp_idx = 0; - int uncomp_idx = 0; - bool valid; - - // extract header - valid = decode_header(mio0_buf, ref head); - // verify MIO0 header - if (!valid) - { - return null; - } - - if (!head.big_endian) - { - return null; - } - - byte[] decoded = new byte[head.dest_size]; - - // decode data - while (bytes_written < head.dest_size) - { - if (GET_BIT(mio0_buf, MIO0_HEADER_LENGTH, bit_idx) > 0) - { - // 1 - pull uncompressed data - decoded[bytes_written] = mio0_buf[head.uncomp_offset + uncomp_idx]; - bytes_written++; - uncomp_idx++; - } - else - { - // 0 - read compressed data - byte a = mio0_buf[head.comp_offset + comp_idx + 0]; - byte b = mio0_buf[head.comp_offset + comp_idx + 1]; - comp_idx += 2; - int length = ((a & 0xF0) >> 4) + 3; - int idx = ((a & 0x0F) << 8) + b + 1; - for (int i = 0; i < length; i++) - { - decoded[bytes_written] = decoded[bytes_written - idx]; - bytes_written++; - } - - } - bit_idx++; - } - return decoded; - } - + return false; } + + /// + /// encode MIO0 header from struct + /// + public static void encode_header(byte[] buf, ref MIO0_Header head) + { + write_u32_be(buf, 0x4D494F30, 0); // write "MIO0" at start of buffer + write_u32_be(buf, head.dest_size, 4); + write_u32_be(buf, head.comp_offset, 8); + write_u32_be(buf, head.uncomp_offset, 12); + } + + /// + /// decode MIO0 data + /// mio0_buf: buffer containing MIO0 data + /// returns the raw data as a byte array + /// + public static byte[] mio0_decode(byte[] mio0_buf) + { + + MIO0_Header head = new MIO0_Header(); + uint bytes_written = 0; + int bit_idx = 0; + int comp_idx = 0; + int uncomp_idx = 0; + bool valid; + + // extract header + valid = decode_header(mio0_buf, ref head); + // verify MIO0 header + if (!valid) + { + return null; + } + + if (!head.big_endian) + { + return null; + } + + byte[] decoded = new byte[head.dest_size]; + + // decode data + while (bytes_written < head.dest_size) + { + if (GET_BIT(mio0_buf, MIO0_HEADER_LENGTH, bit_idx) > 0) + { + // 1 - pull uncompressed data + decoded[bytes_written] = mio0_buf[head.uncomp_offset + uncomp_idx]; + bytes_written++; + uncomp_idx++; + } + else + { + // 0 - read compressed data + byte a = mio0_buf[head.comp_offset + comp_idx + 0]; + byte b = mio0_buf[head.comp_offset + comp_idx + 1]; + comp_idx += 2; + int length = ((a & 0xF0) >> 4) + 3; + int idx = ((a & 0x0F) << 8) + b + 1; + for (int i = 0; i < length; i++) + { + decoded[bytes_written] = decoded[bytes_written - idx]; + bytes_written++; + } + + } + bit_idx++; + } + return decoded; + } + } diff --git a/SM64Lib.LIBMIO0/Properties/AssemblyInfo.cs b/SM64Lib.LIBMIO0/Properties/AssemblyInfo.cs index 0b48e7b..ab4224b 100644 --- a/SM64Lib.LIBMIO0/Properties/AssemblyInfo.cs +++ b/SM64Lib.LIBMIO0/Properties/AssemblyInfo.cs @@ -1,6 +1,4 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; +using System.Runtime.InteropServices; // Durch Festlegen von ComVisible auf FALSE werden die Typen in dieser Assembly // für COM-Komponenten unsichtbar. Wenn Sie auf einen Typ in dieser Assembly von diff --git a/SM64Lib.N64Graphics/N64Graphics.cs b/SM64Lib.N64Graphics/N64Graphics.cs index 342eb6b..3575997 100644 --- a/SM64Lib.N64Graphics/N64Graphics.cs +++ b/SM64Lib.N64Graphics/N64Graphics.cs @@ -1,524 +1,523 @@ using System.Drawing; -namespace SM64Lib.N64Graphics +namespace SM64Lib.N64Graphics; + +public enum N64Codec { RGBA16, RGBA32, IA16, IA8, IA4, I8, I4, CI8, CI4, ONEBPP }; +public enum N64IMode { AlphaCopyIntensity, AlphaBinary, AlphaOne }; + +public class N64Graphics { - public enum N64Codec { RGBA16, RGBA32, IA16, IA8, IA4, I8, I4, CI8, CI4, ONEBPP }; - public enum N64IMode { AlphaCopyIntensity, AlphaBinary, AlphaOne }; - - public class N64Graphics + private static int SCALE_5_8(int val) { - private static int SCALE_5_8(int val) + return (val * 0xFF) / 0x1F; + } + + private static byte SCALE_8_5(byte val) + { + return (byte)((((val) + 4) * 0x1F) / 0xFF); + } + + private static byte SCALE_8_4(byte val) + { + return (byte)(val / 0x11); + } + + private static int SCALE_3_8(byte val) + { + return (val * 0xFF) / 0x7; + } + + private static byte SCALE_8_3(byte val) + { + return (byte)(val / 0x24); + } + + public static Color RGBA16Color(byte c0, byte c1) + { + int r = SCALE_5_8((c0 & 0xF8) >> 3); + int g = SCALE_5_8(((c0 & 0x07) << 2) | ((c1 & 0xC0) >> 6)); + int b = SCALE_5_8((c1 & 0x3E) >> 1); + int a = ((c1 & 0x1) > 0) ? 255 : 0; + return Color.FromArgb(a, r, g, b); + } + + public static void ColorRGBA16(Color col, out byte c0, out byte c1) + { + byte r, g, b; + r = SCALE_8_5(col.R); + g = SCALE_8_5(col.G); + b = SCALE_8_5(col.B); + c0 = (byte)((r << 3) | (g >> 2)); + c1 = (byte)(((g & 0x3) << 6) | (b << 1) | ((col.A > 0) ? 1 : 0)); + } + + public static Color RGBA16Color(byte[] data, int pixOffset) + { + byte c0 = data[pixOffset]; + byte c1 = data[pixOffset + 1]; + + return RGBA16Color(c0, c1); + } + + public static Color RGBA32Color(byte[] data, int pixOffset) + { + int r, g, b, a; + r = data[pixOffset]; + g = data[pixOffset + 1]; + b = data[pixOffset + 2]; + a = data[pixOffset + 3]; + return Color.FromArgb(a, r, g, b); + } + + public static Color IA16Color(byte[] data, int pixOffset) + { + int i = data[pixOffset]; + int a = data[pixOffset + 1]; + return Color.FromArgb(a, i, i, i); + } + + public static Color IA8Color(byte[] data, int pixOffset) + { + int i, a; + byte c = data[pixOffset]; + i = (c >> 4) * 0x11; + a = (c & 0xF) * 0x11; + return Color.FromArgb(a, i, i, i); + } + + public static Color IA4Color(byte[] data, int pixOffset, int nibble) + { + int shift = (1 - nibble) * 4; + int i, a; + int val = (data[pixOffset] >> shift) & 0xF; + i = SCALE_3_8((byte)(val >> 1)); + a = (val & 0x1) > 0 ? 0xFF : 0x00; + return Color.FromArgb(a, i, i, i); + } + + public static Color I8Color(byte[] data, int pixOffset, N64IMode mode = N64IMode.AlphaCopyIntensity) + { + int i = data[pixOffset]; + int a = i; + switch (mode) { - return (val * 0xFF) / 0x1F; + case N64IMode.AlphaBinary: a = (i == 0) ? 0 : 0xFF; break; + case N64IMode.AlphaCopyIntensity: a = i; break; + case N64IMode.AlphaOne: a = 0xFF; break; } + return Color.FromArgb(a, i, i, i); + } - private static byte SCALE_8_5(byte val) + public static Color I4Color(byte[] data, int pixOffset, int nibble, N64IMode mode = N64IMode.AlphaCopyIntensity) + { + int shift = (1 - nibble) * 4; + int i = (data[pixOffset] >> shift) & 0xF; + i *= 0x11; + int a = i; + switch (mode) { - return (byte)((((val) + 4) * 0x1F) / 0xFF); + case N64IMode.AlphaBinary: a = (i == 0) ? 0 : 0xFF; break; + case N64IMode.AlphaCopyIntensity: a = i; break; + case N64IMode.AlphaOne: a = 0xFF; break; } + return Color.FromArgb(a, i, i, i); + } - private static byte SCALE_8_4(byte val) + public static Color CI8Color(byte[] data, byte[] palette, int pixOffset) + { + byte c0, c1; + int palOffset = 2 * data[pixOffset]; + c0 = palette[palOffset]; + c1 = palette[palOffset + 1]; + + return RGBA16Color(c0, c1); + } + + public static Color CI4Color(byte[] data, byte[] palette, int pixOffset, int nibble) + { + byte c0, c1; + int shift = (1 - nibble) * 4; + int palOffset = 2 * ((data[pixOffset] >> shift) & 0xF); + c0 = palette[palOffset]; + c1 = palette[palOffset + 1]; + + return RGBA16Color(c0, c1); + } + + public static Color BPPColor(byte[] data, int pixOffset, int bit) + { + int i, a; + int val = (data[pixOffset] >> (7 - bit)) & 0x1; + i = a = val == 0 ? 0x00 : 0xFF; + return Color.FromArgb(a, i, i, i); + } + + // return number of bytes needed to encode numPixels using codec + public static int PixelsToBytes(N64Codec codec, int numPixels) + { + int numBytes = 0; + switch (codec) { - return (byte)(val / 0x11); + case N64Codec.RGBA16: numBytes = numPixels * 2; break; + case N64Codec.RGBA32: numBytes = numPixels * 4; break; + case N64Codec.IA16: numBytes = numPixels * 2; break; + case N64Codec.IA8: numBytes = numPixels; break; + case N64Codec.IA4: numBytes = numPixels / 2; break; + case N64Codec.I8: numBytes = numPixels; break; + case N64Codec.I4: numBytes = numPixels / 2; break; + case N64Codec.CI8: numBytes = numPixels; break; + case N64Codec.CI4: numBytes = numPixels / 2; break; + case N64Codec.ONEBPP: numBytes = numPixels / 8; break; } + return numBytes; + } - private static int SCALE_3_8(byte val) + public static string CodecString(N64Codec codec) + { + switch (codec) { - return (val * 0xFF) / 0x7; + case N64Codec.RGBA16: return "rgba16"; + case N64Codec.RGBA32: return "rgba32"; + case N64Codec.IA16: return "ia16"; + case N64Codec.IA8: return "ia8"; + case N64Codec.IA4: return "ia4"; + case N64Codec.I8: return "i8"; + case N64Codec.I4: return "i4"; + case N64Codec.CI8: return "ci8"; + case N64Codec.CI4: return "ci4"; + case N64Codec.ONEBPP: return "1bpp"; } + return "unk"; + } - private static byte SCALE_8_3(byte val) + public static N64Codec StringCodec(string str) + { + switch (str.ToLower()) { - return (byte)(val / 0x24); + default: + case "rgba16": return N64Codec.RGBA16; + case "rgba32": return N64Codec.RGBA32; + case "ia16": return N64Codec.IA16; + case "ia8": return N64Codec.IA8; + case "ia4": return N64Codec.IA4; + case "i8": return N64Codec.I8; + case "i4": return N64Codec.I4; + case "ci8": return N64Codec.CI8; + case "ci4": return N64Codec.CI4; + case "1bpp": return N64Codec.ONEBPP; } + } - public static Color RGBA16Color(byte c0, byte c1) + public static Color MakeColor(byte[] data, byte[] palette, int offset, int select, N64Codec codec, N64IMode mode) + { + Color color; + switch (codec) { - int r = SCALE_5_8((c0 & 0xF8) >> 3); - int g = SCALE_5_8(((c0 & 0x07) << 2) | ((c1 & 0xC0) >> 6)); - int b = SCALE_5_8((c1 & 0x3E) >> 1); - int a = ((c1 & 0x1) > 0) ? 255 : 0; - return Color.FromArgb(a, r, g, b); + case N64Codec.RGBA16: + color = RGBA16Color(data, offset); + break; + case N64Codec.RGBA32: + color = RGBA32Color(data, offset); + break; + case N64Codec.IA16: + color = IA16Color(data, offset); + break; + case N64Codec.IA8: + color = IA8Color(data, offset); + break; + case N64Codec.IA4: + color = IA4Color(data, offset, select); + break; + case N64Codec.I8: + color = I8Color(data, offset, mode); + break; + case N64Codec.I4: + color = I4Color(data, offset, select, mode); + break; + case N64Codec.CI8: + color = CI8Color(data, palette, offset); + break; + case N64Codec.CI4: + color = CI4Color(data, palette, offset, select); + break; + case N64Codec.ONEBPP: + color = BPPColor(data, offset, select); + break; + default: + color = RGBA16Color(data, offset); + break; } + return color; + } - public static void ColorRGBA16(Color col, out byte c0, out byte c1) + public static void RenderTexture(Graphics g, byte[] data, byte[] palette, int offset, int width, int height, int scale, N64Codec codec, N64IMode mode) + { + Brush brush; + for (int h = 0; h < height; h++) { - byte r, g, b; - r = SCALE_8_5(col.R); - g = SCALE_8_5(col.G); - b = SCALE_8_5(col.B); - c0 = (byte)((r << 3) | (g >> 2)); - c1 = (byte)(((g & 0x3) << 6) | (b << 1) | ((col.A > 0) ? 1 : 0)); - } - - public static Color RGBA16Color(byte[] data, int pixOffset) - { - byte c0 = data[pixOffset]; - byte c1 = data[pixOffset + 1]; - - return RGBA16Color(c0, c1); - } - - public static Color RGBA32Color(byte[] data, int pixOffset) - { - int r, g, b, a; - r = data[pixOffset]; - g = data[pixOffset + 1]; - b = data[pixOffset + 2]; - a = data[pixOffset + 3]; - return Color.FromArgb(a, r, g, b); - } - - public static Color IA16Color(byte[] data, int pixOffset) - { - int i = data[pixOffset]; - int a = data[pixOffset + 1]; - return Color.FromArgb(a, i, i, i); - } - - public static Color IA8Color(byte[] data, int pixOffset) - { - int i, a; - byte c = data[pixOffset]; - i = (c >> 4) * 0x11; - a = (c & 0xF) * 0x11; - return Color.FromArgb(a, i, i, i); - } - - public static Color IA4Color(byte[] data, int pixOffset, int nibble) - { - int shift = (1 - nibble) * 4; - int i, a; - int val = (data[pixOffset] >> shift) & 0xF; - i = SCALE_3_8((byte)(val >> 1)); - a = (val & 0x1) > 0 ? 0xFF : 0x00; - return Color.FromArgb(a, i, i, i); - } - - public static Color I8Color(byte[] data, int pixOffset, N64IMode mode = N64IMode.AlphaCopyIntensity) - { - int i = data[pixOffset]; - int a = i; - switch (mode) + for (int w = 0; w < width; w++) { - case N64IMode.AlphaBinary: a = (i == 0) ? 0 : 0xFF; break; - case N64IMode.AlphaCopyIntensity: a = i; break; - case N64IMode.AlphaOne: a = 0xFF; break; - } - return Color.FromArgb(a, i, i, i); - } - - public static Color I4Color(byte[] data, int pixOffset, int nibble, N64IMode mode = N64IMode.AlphaCopyIntensity) - { - int shift = (1 - nibble) * 4; - int i = (data[pixOffset] >> shift) & 0xF; - i *= 0x11; - int a = i; - switch (mode) - { - case N64IMode.AlphaBinary: a = (i == 0) ? 0 : 0xFF; break; - case N64IMode.AlphaCopyIntensity: a = i; break; - case N64IMode.AlphaOne: a = 0xFF; break; - } - return Color.FromArgb(a, i, i, i); - } - - public static Color CI8Color(byte[] data, byte[] palette, int pixOffset) - { - byte c0, c1; - int palOffset = 2 * data[pixOffset]; - c0 = palette[palOffset]; - c1 = palette[palOffset + 1]; - - return RGBA16Color(c0, c1); - } - - public static Color CI4Color(byte[] data, byte[] palette, int pixOffset, int nibble) - { - byte c0, c1; - int shift = (1 - nibble) * 4; - int palOffset = 2 * ((data[pixOffset] >> shift) & 0xF); - c0 = palette[palOffset]; - c1 = palette[palOffset + 1]; - - return RGBA16Color(c0, c1); - } - - public static Color BPPColor(byte[] data, int pixOffset, int bit) - { - int i, a; - int val = (data[pixOffset] >> (7 - bit)) & 0x1; - i = a = val == 0 ? 0x00 : 0xFF; - return Color.FromArgb(a, i, i, i); - } - - // return number of bytes needed to encode numPixels using codec - public static int PixelsToBytes(N64Codec codec, int numPixels) - { - int numBytes = 0; - switch (codec) - { - case N64Codec.RGBA16: numBytes = numPixels * 2; break; - case N64Codec.RGBA32: numBytes = numPixels * 4; break; - case N64Codec.IA16: numBytes = numPixels * 2; break; - case N64Codec.IA8: numBytes = numPixels; break; - case N64Codec.IA4: numBytes = numPixels / 2; break; - case N64Codec.I8: numBytes = numPixels; break; - case N64Codec.I4: numBytes = numPixels / 2; break; - case N64Codec.CI8: numBytes = numPixels; break; - case N64Codec.CI4: numBytes = numPixels / 2; break; - case N64Codec.ONEBPP: numBytes = numPixels / 8; break; - } - return numBytes; - } - - public static string CodecString(N64Codec codec) - { - switch (codec) - { - case N64Codec.RGBA16: return "rgba16"; - case N64Codec.RGBA32: return "rgba32"; - case N64Codec.IA16: return "ia16"; - case N64Codec.IA8: return "ia8"; - case N64Codec.IA4: return "ia4"; - case N64Codec.I8: return "i8"; - case N64Codec.I4: return "i4"; - case N64Codec.CI8: return "ci8"; - case N64Codec.CI4: return "ci4"; - case N64Codec.ONEBPP: return "1bpp"; - } - return "unk"; - } - - public static N64Codec StringCodec(string str) - { - switch (str.ToLower()) - { - default: - case "rgba16": return N64Codec.RGBA16; - case "rgba32": return N64Codec.RGBA32; - case "ia16": return N64Codec.IA16; - case "ia8": return N64Codec.IA8; - case "ia4": return N64Codec.IA4; - case "i8": return N64Codec.I8; - case "i4": return N64Codec.I4; - case "ci8": return N64Codec.CI8; - case "ci4": return N64Codec.CI4; - case "1bpp": return N64Codec.ONEBPP; - } - } - - public static Color MakeColor(byte[] data, byte[] palette, int offset, int select, N64Codec codec, N64IMode mode) - { - Color color; - switch (codec) - { - case N64Codec.RGBA16: - color = RGBA16Color(data, offset); - break; - case N64Codec.RGBA32: - color = RGBA32Color(data, offset); - break; - case N64Codec.IA16: - color = IA16Color(data, offset); - break; - case N64Codec.IA8: - color = IA8Color(data, offset); - break; - case N64Codec.IA4: - color = IA4Color(data, offset, select); - break; - case N64Codec.I8: - color = I8Color(data, offset, mode); - break; - case N64Codec.I4: - color = I4Color(data, offset, select, mode); - break; - case N64Codec.CI8: - color = CI8Color(data, palette, offset); - break; - case N64Codec.CI4: - color = CI4Color(data, palette, offset, select); - break; - case N64Codec.ONEBPP: - color = BPPColor(data, offset, select); - break; - default: - color = RGBA16Color(data, offset); - break; - } - return color; - } - - public static void RenderTexture(Graphics g, byte[] data, byte[] palette, int offset, int width, int height, int scale, N64Codec codec, N64IMode mode) - { - Brush brush; - for (int h = 0; h < height; h++) - { - for (int w = 0; w < width; w++) + int pixOffset = (h * width + w); + int bytesPerPix = 1; + int select = 0; + switch (codec) { - int pixOffset = (h * width + w); - int bytesPerPix = 1; - int select = 0; - switch (codec) - { - case N64Codec.RGBA16: bytesPerPix = 2; pixOffset *= bytesPerPix; break; - case N64Codec.RGBA32: bytesPerPix = 4; pixOffset *= bytesPerPix; break; - case N64Codec.IA16: bytesPerPix = 2; pixOffset *= bytesPerPix; break; - case N64Codec.IA8: break; - case N64Codec.IA4: - select = pixOffset & 0x1; - pixOffset /= 2; - break; - case N64Codec.I8: break; - case N64Codec.I4: - case N64Codec.CI4: - select = pixOffset & 0x1; - pixOffset /= 2; - break; - case N64Codec.CI8: break; - case N64Codec.ONEBPP: - select = pixOffset & 0x7; - pixOffset /= 8; - break; - } - pixOffset += offset; - if (data.Length > pixOffset + bytesPerPix - 1) - { - brush = new SolidBrush(MakeColor(data, palette, pixOffset, select, codec, mode)); - g.FillRectangle(brush, w * scale, h * scale, scale, scale); - } + case N64Codec.RGBA16: bytesPerPix = 2; pixOffset *= bytesPerPix; break; + case N64Codec.RGBA32: bytesPerPix = 4; pixOffset *= bytesPerPix; break; + case N64Codec.IA16: bytesPerPix = 2; pixOffset *= bytesPerPix; break; + case N64Codec.IA8: break; + case N64Codec.IA4: + select = pixOffset & 0x1; + pixOffset /= 2; + break; + case N64Codec.I8: break; + case N64Codec.I4: + case N64Codec.CI4: + select = pixOffset & 0x1; + pixOffset /= 2; + break; + case N64Codec.CI8: break; + case N64Codec.ONEBPP: + select = pixOffset & 0x7; + pixOffset /= 8; + break; } - } - } - - // return palette index of matching c0/c1 16-bit dataset, or -1 if not found - private static int paletteIndex(byte[] pal, int palCount, byte c0, byte c1) - { - for (int i = 0; i < palCount; i++) - { - if (pal[2 * i] == c0 && pal[2 * i + 1] == c1) + pixOffset += offset; + if (data.Length > pixOffset + bytesPerPix - 1) { - return i; + brush = new SolidBrush(MakeColor(data, palette, pixOffset, select, codec, mode)); + g.FillRectangle(brush, w * scale, h * scale, scale, scale); } } - return -1; - } - - public static void Convert(ref byte[] imageData, ref byte[] paletteData, N64Codec codec, Bitmap bm) - { - int numPixels = bm.Width * bm.Height; - imageData = new byte[PixelsToBytes(codec, numPixels)]; - int palCount = 0; - switch (codec) - { - case N64Codec.RGBA16: - for (int y = 0; y < bm.Height; y++) - { - for (int x = 0; x < bm.Width; x++) - { - Color col = bm.GetPixel(x, y); - byte c0; - byte c1; - ColorRGBA16(col, out c0, out c1); - int idx = 2 * (y * bm.Width + x); - imageData[idx + 0] = c0; - imageData[idx + 1] = c1; - } - } - break; - case N64Codec.RGBA32: - for (int y = 0; y < bm.Height; y++) - { - for (int x = 0; x < bm.Width; x++) - { - Color col = bm.GetPixel(x, y); - int idx = 4 * (y * bm.Width + x); - imageData[idx + 0] = col.R; - imageData[idx + 1] = col.G; - imageData[idx + 2] = col.B; - imageData[idx + 3] = col.A; - } - } - break; - case N64Codec.IA16: - for (int y = 0; y < bm.Height; y++) - { - for (int x = 0; x < bm.Width; x++) - { - Color col = bm.GetPixel(x, y); - int sum = col.R + col.G + col.B; - byte intensity = (byte)(sum / 3); - byte alpha = col.A; - int idx = 2 * (y * bm.Width + x); - imageData[idx + 0] = intensity; - imageData[idx + 1] = alpha; - } - } - break; - case N64Codec.IA8: - for (int y = 0; y < bm.Height; y++) - { - for (int x = 0; x < bm.Width; x++) - { - Color col = bm.GetPixel(x, y); - int sum = col.R + col.G + col.B; - byte intensity = SCALE_8_4((byte)(sum / 3)); - byte alpha = SCALE_8_4(col.A); - int idx = y * bm.Width + x; - imageData[idx] = (byte)((intensity << 4) | alpha); - } - } - break; - case N64Codec.IA4: - for (int y = 0; y < bm.Height; y++) - { - for (int x = 0; x < bm.Width; x++) - { - Color col = bm.GetPixel(x, y); - int sum = col.R + col.G + col.B; - byte intensity = SCALE_8_3((byte)(sum / 3)); - byte alpha = (byte)(col.A > 0 ? 1 : 0); - int idx = y * bm.Width + x; - byte old = imageData[idx / 2]; - if ((idx % 2) > 0) - { - imageData[idx / 2] = (byte)((old & 0xF0) | (intensity << 1) | alpha); - } - else - { - imageData[idx / 2] = (byte)((old & 0x0F) | (((intensity << 1) | alpha) << 4)); - } - } - } - break; - case N64Codec.I8: - for (int y = 0; y < bm.Height; y++) - { - for (int x = 0; x < bm.Width; x++) - { - Color col = bm.GetPixel(x, y); - int sum = col.R + col.G + col.B; - byte intensity = (byte)(sum / 3); - int idx = y * bm.Width + x; - imageData[idx] = intensity; - } - } - break; - case N64Codec.I4: - for (int y = 0; y < bm.Height; y++) - { - for (int x = 0; x < bm.Width; x++) - { - Color col = bm.GetPixel(x, y); - int sum = col.R + col.G + col.B; - byte intensity = SCALE_8_4((byte)(sum / 3)); - int idx = y * bm.Width + x; - byte old = imageData[idx / 2]; - if ((idx % 2) > 0) - { - imageData[idx / 2] = (byte)((old & 0xF0) | intensity); - } - else - { - imageData[idx / 2] = (byte)((old & 0x0F) | (intensity << 4)); - } - } - } - break; - case N64Codec.CI4: - paletteData = new byte[16 * 2]; - for (int y = 0; y < bm.Height; y++) - { - for (int x = 0; x < bm.Width; x++) - { - Color col = bm.GetPixel(x, y); - byte r, g, b; - r = SCALE_8_5(col.R); - g = SCALE_8_5(col.G); - b = SCALE_8_5(col.B); - byte c0 = (byte)((r << 3) | (g >> 2)); - byte c1 = (byte)(((g & 0x3) << 6) | (b << 1) | ((col.A > 0) ? 1 : 0)); - int idx = y * bm.Width + x; - int palIdx = paletteIndex(paletteData, palCount, c0, c1); - if (palIdx < 0) - { - if (palCount < paletteData.Length / 2) - { - palIdx = palCount; - paletteData[2 * palCount] = c0; - paletteData[2 * palCount + 1] = c1; - palCount++; - } - else - { - palIdx = 0; - // TODO: out of palette entries. error or pick closest? - } - } - byte old = imageData[idx / 2]; - if ((idx % 2) > 0) - { - imageData[idx / 2] = (byte)((old & 0xF0) | (byte)palIdx); - } - else - { - imageData[idx / 2] = (byte)((old & 0x0F) | ((byte)palIdx << 4)); - } - } - } - break; - case N64Codec.CI8: - paletteData = new byte[256 * 2]; - for (int y = 0; y < bm.Height; y++) - { - for (int x = 0; x < bm.Width; x++) - { - Color col = bm.GetPixel(x, y); - byte r, g, b; - r = SCALE_8_5(col.R); - g = SCALE_8_5(col.G); - b = SCALE_8_5(col.B); - byte c0 = (byte)((r << 3) | (g >> 2)); - byte c1 = (byte)(((g & 0x3) << 6) | (b << 1) | ((col.A > 0) ? 1 : 0)); - int idx = y * bm.Width + x; - int palIdx = paletteIndex(paletteData, palCount, c0, c1); - if (palIdx < 0) - { - if (palCount < paletteData.Length / 2) - { - palIdx = palCount; - paletteData[2 * palCount] = c0; - paletteData[2 * palCount + 1] = c1; - palCount++; - } - else - { - palIdx = 0; - // TODO: out of palette entries. error or pick closest? - } - } - imageData[idx] = (byte)palIdx; - } - } - break; - case N64Codec.ONEBPP: - for (int y = 0; y < bm.Height; y++) - { - for (int x = 0; x < bm.Width; x++) - { - Color col = bm.GetPixel(x, y); - int sum = col.R + col.G + col.B; - byte intensity = (sum > 0) ? (byte)1 : (byte)0; - int idx = y * bm.Width + x; - byte old = imageData[idx / 8]; - int bit = idx % 8; - int mask = ~(1 << bit); - imageData[idx / 8] = (byte)((old & mask) | (intensity << bit)); - } - } - break; - } + } + } + + // return palette index of matching c0/c1 16-bit dataset, or -1 if not found + private static int paletteIndex(byte[] pal, int palCount, byte c0, byte c1) + { + for (int i = 0; i < palCount; i++) + { + if (pal[2 * i] == c0 && pal[2 * i + 1] == c1) + { + return i; + } + } + return -1; + } + + public static void Convert(ref byte[] imageData, ref byte[] paletteData, N64Codec codec, Bitmap bm) + { + int numPixels = bm.Width * bm.Height; + imageData = new byte[PixelsToBytes(codec, numPixels)]; + int palCount = 0; + switch (codec) + { + case N64Codec.RGBA16: + for (int y = 0; y < bm.Height; y++) + { + for (int x = 0; x < bm.Width; x++) + { + Color col = bm.GetPixel(x, y); + byte c0; + byte c1; + ColorRGBA16(col, out c0, out c1); + int idx = 2 * (y * bm.Width + x); + imageData[idx + 0] = c0; + imageData[idx + 1] = c1; + } + } + break; + case N64Codec.RGBA32: + for (int y = 0; y < bm.Height; y++) + { + for (int x = 0; x < bm.Width; x++) + { + Color col = bm.GetPixel(x, y); + int idx = 4 * (y * bm.Width + x); + imageData[idx + 0] = col.R; + imageData[idx + 1] = col.G; + imageData[idx + 2] = col.B; + imageData[idx + 3] = col.A; + } + } + break; + case N64Codec.IA16: + for (int y = 0; y < bm.Height; y++) + { + for (int x = 0; x < bm.Width; x++) + { + Color col = bm.GetPixel(x, y); + int sum = col.R + col.G + col.B; + byte intensity = (byte)(sum / 3); + byte alpha = col.A; + int idx = 2 * (y * bm.Width + x); + imageData[idx + 0] = intensity; + imageData[idx + 1] = alpha; + } + } + break; + case N64Codec.IA8: + for (int y = 0; y < bm.Height; y++) + { + for (int x = 0; x < bm.Width; x++) + { + Color col = bm.GetPixel(x, y); + int sum = col.R + col.G + col.B; + byte intensity = SCALE_8_4((byte)(sum / 3)); + byte alpha = SCALE_8_4(col.A); + int idx = y * bm.Width + x; + imageData[idx] = (byte)((intensity << 4) | alpha); + } + } + break; + case N64Codec.IA4: + for (int y = 0; y < bm.Height; y++) + { + for (int x = 0; x < bm.Width; x++) + { + Color col = bm.GetPixel(x, y); + int sum = col.R + col.G + col.B; + byte intensity = SCALE_8_3((byte)(sum / 3)); + byte alpha = (byte)(col.A > 0 ? 1 : 0); + int idx = y * bm.Width + x; + byte old = imageData[idx / 2]; + if ((idx % 2) > 0) + { + imageData[idx / 2] = (byte)((old & 0xF0) | (intensity << 1) | alpha); + } + else + { + imageData[idx / 2] = (byte)((old & 0x0F) | (((intensity << 1) | alpha) << 4)); + } + } + } + break; + case N64Codec.I8: + for (int y = 0; y < bm.Height; y++) + { + for (int x = 0; x < bm.Width; x++) + { + Color col = bm.GetPixel(x, y); + int sum = col.R + col.G + col.B; + byte intensity = (byte)(sum / 3); + int idx = y * bm.Width + x; + imageData[idx] = intensity; + } + } + break; + case N64Codec.I4: + for (int y = 0; y < bm.Height; y++) + { + for (int x = 0; x < bm.Width; x++) + { + Color col = bm.GetPixel(x, y); + int sum = col.R + col.G + col.B; + byte intensity = SCALE_8_4((byte)(sum / 3)); + int idx = y * bm.Width + x; + byte old = imageData[idx / 2]; + if ((idx % 2) > 0) + { + imageData[idx / 2] = (byte)((old & 0xF0) | intensity); + } + else + { + imageData[idx / 2] = (byte)((old & 0x0F) | (intensity << 4)); + } + } + } + break; + case N64Codec.CI4: + paletteData = new byte[16 * 2]; + for (int y = 0; y < bm.Height; y++) + { + for (int x = 0; x < bm.Width; x++) + { + Color col = bm.GetPixel(x, y); + byte r, g, b; + r = SCALE_8_5(col.R); + g = SCALE_8_5(col.G); + b = SCALE_8_5(col.B); + byte c0 = (byte)((r << 3) | (g >> 2)); + byte c1 = (byte)(((g & 0x3) << 6) | (b << 1) | ((col.A > 0) ? 1 : 0)); + int idx = y * bm.Width + x; + int palIdx = paletteIndex(paletteData, palCount, c0, c1); + if (palIdx < 0) + { + if (palCount < paletteData.Length / 2) + { + palIdx = palCount; + paletteData[2 * palCount] = c0; + paletteData[2 * palCount + 1] = c1; + palCount++; + } + else + { + palIdx = 0; + // TODO: out of palette entries. error or pick closest? + } + } + byte old = imageData[idx / 2]; + if ((idx % 2) > 0) + { + imageData[idx / 2] = (byte)((old & 0xF0) | (byte)palIdx); + } + else + { + imageData[idx / 2] = (byte)((old & 0x0F) | ((byte)palIdx << 4)); + } + } + } + break; + case N64Codec.CI8: + paletteData = new byte[256 * 2]; + for (int y = 0; y < bm.Height; y++) + { + for (int x = 0; x < bm.Width; x++) + { + Color col = bm.GetPixel(x, y); + byte r, g, b; + r = SCALE_8_5(col.R); + g = SCALE_8_5(col.G); + b = SCALE_8_5(col.B); + byte c0 = (byte)((r << 3) | (g >> 2)); + byte c1 = (byte)(((g & 0x3) << 6) | (b << 1) | ((col.A > 0) ? 1 : 0)); + int idx = y * bm.Width + x; + int palIdx = paletteIndex(paletteData, palCount, c0, c1); + if (palIdx < 0) + { + if (palCount < paletteData.Length / 2) + { + palIdx = palCount; + paletteData[2 * palCount] = c0; + paletteData[2 * palCount + 1] = c1; + palCount++; + } + else + { + palIdx = 0; + // TODO: out of palette entries. error or pick closest? + } + } + imageData[idx] = (byte)palIdx; + } + } + break; + case N64Codec.ONEBPP: + for (int y = 0; y < bm.Height; y++) + { + for (int x = 0; x < bm.Width; x++) + { + Color col = bm.GetPixel(x, y); + int sum = col.R + col.G + col.B; + byte intensity = (sum > 0) ? (byte)1 : (byte)0; + int idx = y * bm.Width + x; + byte old = imageData[idx / 8]; + int bit = idx % 8; + int mask = ~(1 << bit); + imageData[idx / 8] = (byte)((old & mask) | (intensity << bit)); + } + } + break; } } } diff --git a/SM64Lib.N64Graphics/Properties/AssemblyInfo.cs b/SM64Lib.N64Graphics/Properties/AssemblyInfo.cs index 8903d48..4796be6 100644 --- a/SM64Lib.N64Graphics/Properties/AssemblyInfo.cs +++ b/SM64Lib.N64Graphics/Properties/AssemblyInfo.cs @@ -1,6 +1,4 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; +using System.Runtime.InteropServices; // Durch Festlegen von ComVisible auf "false" werden die Typen in dieser Assembly unsichtbar // für COM-Komponenten. Wenn Sie auf einen Typ in dieser Assembly von diff --git a/SM64Lib.N64Graphics/TextureFormat.cs b/SM64Lib.N64Graphics/TextureFormat.cs index d067855..7e447fb 100644 --- a/SM64Lib.N64Graphics/TextureFormat.cs +++ b/SM64Lib.N64Graphics/TextureFormat.cs @@ -1,598 +1,593 @@ using System; -using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; -using System.Linq; using System.Runtime.InteropServices; -using System.Text; -using System.Threading.Tasks; -namespace SM64Lib.N64Graphics +namespace SM64Lib.N64Graphics; + +public class TextureFormats { - public class TextureFormats + public static Bitmap createColorTexture(Color color) { - public static Bitmap createColorTexture(Color color) + Bitmap tex = new Bitmap(1, 1); + Graphics.FromImage(tex).Clear(color); + return tex; + } + + public static string ConvertFormatToString(byte formatColorType, byte formatByteSize) + { + string formatStr = ""; + switch (formatColorType & 7) { - Bitmap tex = new Bitmap(1, 1); - Graphics.FromImage(tex).Clear(color); - return tex; + case 0: formatStr = "RGBA"; break; + case 1: formatStr = "YUV"; break; + case 2: formatStr = "CI"; break; + case 3: formatStr = "IA"; break; + case 4: formatStr = "I"; break; + default: formatStr = "UNKNOWN"; break; } - - public static string ConvertFormatToString(byte formatColorType, byte formatByteSize) + switch (formatByteSize & 3) { - string formatStr = ""; - switch (formatColorType & 7) - { - case 0: formatStr = "RGBA"; break; - case 1: formatStr = "YUV"; break; - case 2: formatStr = "CI"; break; - case 3: formatStr = "IA"; break; - case 4: formatStr = "I"; break; - default: formatStr = "UNKNOWN"; break; - } - switch (formatByteSize & 3) - { - case 0: formatStr += "4"; break; - case 1: formatStr += "8"; break; - case 2: formatStr += "16"; break; - case 3: formatStr += "32"; break; - } - return formatStr; + case 0: formatStr += "4"; break; + case 1: formatStr += "8"; break; + case 2: formatStr += "16"; break; + case 3: formatStr += "32"; break; } + return formatStr; + } - public static byte ConvertStringToFormat(string str) - { - str = str.ToLower(); - if (str.Equals("rgba16")) - return 0x10; - else if (str.Equals("rgba32")) - return 0x18; - else if (str.Equals("ci4")) - return 0x40; - else if (str.Equals("ci8")) - return 0x48; - else if (str.Equals("ia4")) - return 0x60; - else if (str.Equals("ia8")) - return 0x68; - else if (str.Equals("ia16")) - return 0x70; - else if (str.Equals("i4")) - return 0x80; - else if (str.Equals("i8")) - return 0x88; - else if (str.Equals("1bpp")) // Not a real F3D format. - return 0x00; - + public static byte ConvertStringToFormat(string str) + { + str = str.ToLower(); + if (str.Equals("rgba16")) return 0x10; - } + else if (str.Equals("rgba32")) + return 0x18; + else if (str.Equals("ci4")) + return 0x40; + else if (str.Equals("ci8")) + return 0x48; + else if (str.Equals("ia4")) + return 0x60; + else if (str.Equals("ia8")) + return 0x68; + else if (str.Equals("ia16")) + return 0x70; + else if (str.Equals("i4")) + return 0x80; + else if (str.Equals("i8")) + return 0x88; + else if (str.Equals("1bpp")) // Not a real F3D format. + return 0x00; - public static int getNumberOfBitsForFormat(byte format) + return 0x10; + } + + public static int getNumberOfBitsForFormat(byte format) + { + switch (format) { - switch (format) - { - case 0x00: // Note: "1 bit per pixel" is not a Fast3D format. - return 1; - case 0x40: - case 0x60: - case 0x80: - return 4; - case 0x48: - case 0x68: - case 0x88: - return 8; - case 0x10: - case 0x70: - case 0x90: - default: - return 16; - case 0x18: - return 32; - } - } - - public static byte[] encodeTexture(N64Codec format, Bitmap texture) - { - switch (format) - { - default: - case N64Codec.ONEBPP: // Note: "1 bit per pixel" is not a Fast3D format. - return encode1BPP(texture); - case N64Codec.RGBA16: - return encodeRGBA16(texture); - case N64Codec.RGBA32: - return encodeRGBA32(texture); - case N64Codec.IA4: - return encodeIA4(texture); - case N64Codec.IA8: - return encodeIA8(texture); - case N64Codec.IA16: - return encodeIA16(texture); - case N64Codec.I4: - return encodeI4(texture); - case N64Codec.I8: - return encodeI4(texture); - case N64Codec.CI4: - case N64Codec.CI8: - throw new ArgumentException("CI texture encoding is not currently supported in this version."); - } - } - - public static byte getBit(int color, int bit) - { - return (byte)(((color >> 24) & 0xFF) > 0 ? (1 << bit) : 0); - } - - public static byte[] encode1BPP(Bitmap texture) - { - int data_size = (texture.Width * texture.Height) / 8; - byte[] data = new byte[data_size]; - for (int i = 0; i < data_size; i++) - { - int x = (i * 8) % texture.Width; - int y = (i * 8) / texture.Width; - - data[i] = (byte)( - getBit(texture.GetPixel(x + 0, y).ToArgb(), 7) | - getBit(texture.GetPixel(x + 1, y).ToArgb(), 6) | - getBit(texture.GetPixel(x + 2, y).ToArgb(), 5) | - getBit(texture.GetPixel(x + 3, y).ToArgb(), 4) | - getBit(texture.GetPixel(x + 4, y).ToArgb(), 3) | - getBit(texture.GetPixel(x + 5, y).ToArgb(), 2) | - getBit(texture.GetPixel(x + 6, y).ToArgb(), 1) | - getBit(texture.GetPixel(x + 7, y).ToArgb(), 0) - ); - } - return data; - } - - public static byte[] encodeRGBA16(Bitmap texture) - { - int data_size = (texture.Width * texture.Height) * 2; - byte[] data = new byte[data_size]; - for (int i = 0; i < data_size / 2; i++) - { - int x = i % texture.Width; - int y = i / texture.Width; - Color pix = texture.GetPixel(x, y); - byte red = (byte)((pix.R / 256.0f) * 32.0f); - byte green = (byte)((pix.G / 256.0f) * 32.0f); - byte blue = (byte)((pix.B / 256.0f) * 32.0f); - byte alpha = (byte)(pix.A >= 128.0f ? 1 : 0); - - data[i * 2] = (byte)((red << 3) | (green >> 2)); - data[(i * 2) + 1] = (byte)(((green & 3) << 6) | (blue << 1) | alpha); - } - return data; - } - - public static byte[] encodeRGBA32(Bitmap texture) - { - int data_size = (texture.Width * texture.Height) * 4; - byte[] data = new byte[data_size]; - for (int i = 0; i < data_size / 4; i++) - { - int x = i % texture.Width; - int y = i / texture.Width; - Color pix = texture.GetPixel(x, y); - - data[(i * 4) + 0] = pix.R; - data[(i * 4) + 1] = pix.G; - data[(i * 4) + 2] = pix.B; - data[(i * 4) + 3] = pix.A; - } - return data; - } - - public static byte[] encodeIA4(Bitmap texture) - { - int data_size = (texture.Width * texture.Height) / 2; - byte[] data = new byte[data_size]; - for (int i = 0; i < data_size; i++) - { - int x = (i * 2) % texture.Width; - int y = (i * 2) / texture.Width; - - Color pix1 = texture.GetPixel(x, y); - byte pix1_avg = (byte)((((pix1.R + pix1.G + pix1.B) / 3) / 255.0f) * 8.0f); - byte upper = (byte)((pix1_avg << 1) | (pix1.A < 255 ? 0 : 1)); - - Color pix2 = texture.GetPixel(x + 1, y); - byte pix2_avg = (byte)((((pix2.R + pix2.G + pix2.B) / 3) / 255.0f) * 8.0f); - byte lower = (byte)((pix2_avg << 1) | (pix2.A < 255 ? 0 : 1)); - - data[i] = (byte)(((upper & 0xF) << 4) | (lower & 0xF)); - } - return data; - } - - public static byte[] encodeIA8(Bitmap texture) - { - int data_size = texture.Width * texture.Height; - byte[] data = new byte[data_size]; - for (int i = 0; i < data_size; i++) - { - int x = i % texture.Width; - int y = i / texture.Width; - - Color pix = texture.GetPixel(x, y); - byte pix_avg = (byte)((((pix.R + pix.G + pix.B) / 3) / 255.0f) * 16.0f); - byte pix_alpha = (byte)((pix.A / 255.0f) * 16.0f); - - data[i] = (byte)(((pix_avg & 0xF) << 4) | (pix_alpha & 0xF)); - } - return data; - } - - public static byte[] encodeIA16(Bitmap texture) - { - int data_size = texture.Width * texture.Height * 2; - byte[] data = new byte[data_size]; - for (int i = 0; i < data_size / 2; i++) - { - int x = i % texture.Width; - int y = i / texture.Width; - - Color pix = texture.GetPixel(x, y); - byte pix_avg = (byte)((pix.R + pix.G + pix.B) / 3); - - data[i * 2] = pix_avg; - data[(i * 2) + 1] = pix.A; - } - return data; - } - - public static byte[] encodeI4(Bitmap texture) - { - int data_size = (texture.Width * texture.Height) / 2; - byte[] data = new byte[data_size]; - for (int i = 0; i < data_size; i++) - { - int x = (i * 2) % texture.Width; - int y = (i * 2) / texture.Width; - - Color pix1 = texture.GetPixel(x, y); - byte upper = (byte)((((pix1.R + pix1.G + pix1.B) / 3) / 255.0f) * 16.0f); - - Color pix2 = texture.GetPixel(x + 1, y); - byte lower = (byte)((((pix2.R + pix2.G + pix2.B) / 3) / 255.0f) * 16.0f); - - data[i] = (byte)(((upper & 0xF) << 4) | (lower & 0xF)); - } - return data; - } - - - public static byte[] encodeI8(Bitmap texture) - { - int data_size = texture.Width * texture.Height; - byte[] data = new byte[data_size]; - for (int i = 0; i < data_size; i++) - { - int x = i % texture.Width; - int y = i / texture.Width; - - Color pix = texture.GetPixel(x, y); - - data[i] = (byte)((pix.R + pix.G + pix.B) / 3); - } - return data; - } - - public static Bitmap decodeTexture(N64Codec format, byte[] data, int width, int height, ushort[] palette) - { - switch (format) - { - default: - case N64Codec.ONEBPP: // Note: "1 bit per pixel" is not a Fast3D format. - return decode1BPP(data, width, height); - case N64Codec.RGBA16: - return decodeRGBA16(data, width, height); - case N64Codec.RGBA32: - return decodeRGBA32(data, width, height); - case N64Codec.CI4: - return decodeCI4(data, width, height, palette); - case N64Codec.CI8: - return decodeCI8(data, width, height, palette); - case N64Codec.IA4: - return decodeIA4(data, width, height); - case N64Codec.IA8: - return decodeIA8(data, width, height); - case N64Codec.IA16: - return decodeIA16(data, width, height); - case N64Codec.I4: - return decodeI4(data, width, height); - case N64Codec.I8: - return decodeI8(data, width, height); - } - } - - - public static Bitmap decode1BPP(byte[] data, int width, int height) - { - Bitmap tex = new Bitmap(width, height); - if (data.Length >= (width * height) / 8) // Sanity Check - { - int len = (width * height) / 8; - for (int i = 0; i < len; ++i) - { - for (int x = 0; x < 8; x++) - { - byte intensity = (byte)((data[i] >> (7 - x)) & 1); - if (intensity > 0) - intensity = 0xFF; - int alpha = intensity; - int pos = (i * 8) + x; - tex.SetPixel(pos % width, pos / width, Color.FromArgb(alpha, intensity, intensity, intensity)); - } - } - } - tex.Tag = new string[] { "Format: 1BPP", "Width: " + width, - "Height: " + height }; - return tex; - } - - public static Bitmap decodeRGBA32(byte[] data, int width, int height) - { - Console.WriteLine("Texture size = (" + width + "x" + height + ")"); - Console.WriteLine("data.Length = (" + data.Length + ")"); - Bitmap tex = new Bitmap(width, height); - - if (data.Length >= width * height * 4) // Sanity Check - { - BitmapData bitmapData = tex.LockBits(new Rectangle(0, 0, width, height), - ImageLockMode.ReadWrite, tex.PixelFormat); - - int len = width * height; - for (int i = 0; i < len; i++) - { - // Swap red and blue values - byte temp_red = data[(i * 4) + 0]; - data[(i * 4) + 0] = data[(i * 4) + 2]; - data[(i * 4) + 2] = temp_red; - } - Marshal.Copy(data, 0, bitmapData.Scan0, data.Length); - tex.UnlockBits(bitmapData); - - } - tex.Tag = new string[] { "Format: RGBA32", "Width: " + width, - "Height: " + height }; - return tex; - } - - public static Bitmap decodeRGBA16(byte[] data, int width, int height) - { - Bitmap tex = new Bitmap(width, height); - if (data.Length >= width * height * 2) // Sanity Check - { - BitmapData bitmapData = tex.LockBits(new Rectangle(0, 0, width, height), - ImageLockMode.ReadWrite, tex.PixelFormat); - byte[] pixels = new byte[width * height * 4]; - - int len = width * height; - for (int i = 0; i < len; i++) - { - ushort pixel = (ushort)((data[i * 2] << 8) | data[i * 2 + 1]); - pixels[(i * 4) + 2] = (byte)(((pixel >> 11) & 0x1F) * 8); // Red - pixels[(i * 4) + 1] = (byte)(((pixel >> 6) & 0x1F) * 8); // Green - pixels[(i * 4) + 0] = (byte)(((pixel >> 1) & 0x1F) * 8); // Blue - pixels[(i * 4) + 3] = (pixel & 1) > 0 ? (byte)0xFF : (byte)0x00; // (Transparency) - } - Marshal.Copy(pixels, 0, bitmapData.Scan0, pixels.Length); - tex.UnlockBits(bitmapData); - } - - tex.Tag = new string[] { "Format: RGBA16", "Width: " + width, - "Height: " + height }; - return tex; - } - - public static Bitmap decodeIA16(byte[] data, int width, int height) - { - Bitmap tex = new Bitmap(width, height); - if (data.Length >= width * height * 2) // Sanity Check - { - BitmapData bitmapData = tex.LockBits(new Rectangle(0, 0, width, height), - ImageLockMode.ReadWrite, tex.PixelFormat); - byte[] pixels = new byte[width * height * 4]; - - int len = width * height; - for (int i = 0; i < len; i++) - { - pixels[(i * 4) + 2] = data[i * 2]; // Red - pixels[(i * 4) + 1] = data[i * 2]; // Green - pixels[(i * 4) + 0] = data[i * 2]; // Blue - pixels[(i * 4) + 3] = data[(i * 2) + 1]; // Alpha - } - Marshal.Copy(pixels, 0, bitmapData.Scan0, pixels.Length); - tex.UnlockBits(bitmapData); - } - tex.Tag = new string[] { "Format: IA16", "Width: " + width, - "Height: " + height}; - return tex; - } - - public static Bitmap decodeIA8(byte[] data, int width, int height) - { - Bitmap tex = new Bitmap(width, height); - if (data.Length >= width * height) // Sanity Check - { - BitmapData bitmapData = tex.LockBits(new Rectangle(0, 0, width, height), - ImageLockMode.ReadWrite, tex.PixelFormat); - byte[] pixels = new byte[width * height * 4]; - - int len = width * height; - for (int i = 0; i < len; i++) - { - byte intensity = (byte)(((data[i] >> 4) & 0xF) * 16); - pixels[(i * 4) + 2] = intensity; // Red - pixels[(i * 4) + 1] = intensity; // Green - pixels[(i * 4) + 0] = intensity; // Blue - pixels[(i * 4) + 3] = (byte)((data[i] & 0xF) * 16); // Alpha - } - Marshal.Copy(pixels, 0, bitmapData.Scan0, pixels.Length); - tex.UnlockBits(bitmapData); - } - tex.Tag = new string[] { "Format: IA8", "Width: " + width, - "Height: " + height }; - return tex; - } - public static Bitmap decodeIA4(byte[] data, int width, int height) - { - Bitmap tex = new Bitmap(width, height); - - if (data.Length >= (width * height) / 2) // Sanity Check - { - BitmapData bitmapData = tex.LockBits(new Rectangle(0, 0, width, height), - ImageLockMode.ReadWrite, tex.PixelFormat); - byte[] pixels = new byte[width * height * 4]; - - int len = (width * height) / 2; - for (int i = 0; i < len; i++) - { - byte twoPixels = data[i]; - - byte intensity = (byte)((twoPixels >> 5) * 32); - pixels[(i * 8) + 2] = intensity; // Red - pixels[(i * 8) + 1] = intensity; // Green - pixels[(i * 8) + 0] = intensity; // Blue - pixels[(i * 8) + 3] = (byte)(((twoPixels >> 4) & 0x1) * 255); // Alpha - - intensity = (byte)(((twoPixels >> 1) & 0x7) * 32); - pixels[(i * 8) + 6] = intensity; // Red - pixels[(i * 8) + 5] = intensity; // Green - pixels[(i * 8) + 4] = intensity; // Blue - pixels[(i * 8) + 7] = (byte)((twoPixels & 0x1) * 255); // Alpha - } - Marshal.Copy(pixels, 0, bitmapData.Scan0, pixels.Length); - tex.UnlockBits(bitmapData); - tex.Tag = new string[] { "Format: IA4", "Width: " + width, - "Height: " + height }; - } - return tex; - } - public static Bitmap decodeI8(byte[] data, int width, int height) - { - Bitmap tex = new Bitmap(width, height); - - if (data.Length >= width * height) // Sanity Check - { - BitmapData bitmapData = tex.LockBits(new Rectangle(0, 0, width, height), - ImageLockMode.ReadWrite, tex.PixelFormat); - byte[] pixels = new byte[width * height * 4]; - - int len = width * height; - for (int i = 0; i < len; i++) - { - byte intensity = data[i]; - pixels[(i * 4) + 2] = intensity; // Red - pixels[(i * 4) + 1] = intensity; // Green - pixels[(i * 4) + 0] = intensity; // Blue - pixels[(i * 4) + 3] = 0xFF; // Alpha - } - Marshal.Copy(pixels, 0, bitmapData.Scan0, pixels.Length); - tex.UnlockBits(bitmapData); - - tex.Tag = new string[] { "Format: I8", "Width: " + width, - "Height: " + height }; - } - return tex; - } - public static Bitmap decodeI4(byte[] data, int width, int height) - { - Bitmap tex = new Bitmap(width, height); - - if (data.Length >= (width * height) / 2) // Sanity Check - { - BitmapData bitmapData = tex.LockBits(new Rectangle(0, 0, width, height), - ImageLockMode.ReadWrite, tex.PixelFormat); - byte[] pixels = new byte[width * height * 4]; - - int len = (width * height) / 2; - for (int i = 0; i < len; i++) - { - byte twoPixels = data[i]; - - byte intensity = (byte)((twoPixels >> 4) * 16); - pixels[(i * 8) + 2] = intensity; // Red - pixels[(i * 8) + 1] = intensity; // Green - pixels[(i * 8) + 0] = intensity; // Blue - pixels[(i * 8) + 3] = 0xFF; // Alpha - - intensity = (byte)((twoPixels & 0xF) * 16); - pixels[(i * 8) + 6] = intensity; // Red - pixels[(i * 8) + 5] = intensity; // Green - pixels[(i * 8) + 4] = intensity; // Blue - pixels[(i * 8) + 7] = 0xFF; // Alpha - } - Marshal.Copy(pixels, 0, bitmapData.Scan0, pixels.Length); - tex.UnlockBits(bitmapData); - } - tex.Tag = new string[] { "Format: I4", "Width: " + width, - "Height: " + height }; - return tex; - } - - public static Bitmap decodeCI4(byte[] data, int width, int height, ushort[] palette) - { - Bitmap tex = new Bitmap(width, height); - - if (data.Length >= (width * height) / 2) // Sanity Check - { - BitmapData bitmapData = tex.LockBits(new Rectangle(0, 0, width, height), - ImageLockMode.ReadWrite, tex.PixelFormat); - byte[] pixels = new byte[width * height * 4]; - - int len = (width * height) / 2; - for (int i = 0; i < len; i++) - { - ushort pixel = palette[(data[i] >> 4) & 0xF]; - pixels[(i * 8) + 2] = (byte)(((pixel >> 11) & 0x1F) * 8); // Red - pixels[(i * 8) + 1] = (byte)(((pixel >> 6) & 0x1F) * 8); // Green - pixels[(i * 8) + 0] = (byte)(((pixel >> 1) & 0x1F) * 8); // Blue - pixels[(i * 8) + 3] = (pixel & 1) > 0 ? (byte)0xFF : (byte)0x00; // Alpha - - pixel = palette[(data[i]) & 0xF]; - pixels[(i * 8) + 6] = (byte)(((pixel >> 11) & 0x1F) * 8); // Red - pixels[(i * 8) + 5] = (byte)(((pixel >> 6) & 0x1F) * 8); // Green - pixels[(i * 8) + 4] = (byte)(((pixel >> 1) & 0x1F) * 8); // Blue - pixels[(i * 8) + 7] = (pixel & 1) > 0 ? (byte)0xFF : (byte)0x00; // Alpha - - } - Marshal.Copy(pixels, 0, bitmapData.Scan0, pixels.Length); - tex.UnlockBits(bitmapData); - } - tex.Tag = new string[] { "Format: CI4", "Width: " + width, - "Height: " + height }; - return tex; - } - - public static Bitmap decodeCI8(byte[] data, int width, int height, ushort[] palette) - { - Bitmap tex = new Bitmap(width, height); - - if (data.Length >= width * height) // Sanity Check - { - BitmapData bitmapData = tex.LockBits(new Rectangle(0, 0, width, height), - ImageLockMode.ReadWrite, tex.PixelFormat); - byte[] pixels = new byte[width * height * 4]; - - int len = width * height; - for (int i = 0; i < len; i++) - { - ushort pixel = palette[data[i]]; - pixels[(i * 4) + 2] = (byte)(((pixel >> 11) & 0x1F) * 8); // Red - pixels[(i * 4) + 1] = (byte)(((pixel >> 6) & 0x1F) * 8); // Green - pixels[(i * 4) + 0] = (byte)(((pixel >> 1) & 0x1F) * 8); // Blue - pixels[(i * 4) + 3] = (pixel & 1) > 0 ? (byte)0xFF : (byte)0x00; // (Transparency) - //tex.SetPixel(i % width, i / width, Color.FromArgb(alpha, red, green, blue)); - } - Marshal.Copy(pixels, 0, bitmapData.Scan0, pixels.Length); - tex.UnlockBits(bitmapData); - } - tex.Tag = new string[] { "Format: CI8", "Width: " + width, - "Height: " + height }; - return tex; + case 0x00: // Note: "1 bit per pixel" is not a Fast3D format. + return 1; + case 0x40: + case 0x60: + case 0x80: + return 4; + case 0x48: + case 0x68: + case 0x88: + return 8; + case 0x10: + case 0x70: + case 0x90: + default: + return 16; + case 0x18: + return 32; } } + + public static byte[] encodeTexture(N64Codec format, Bitmap texture) + { + switch (format) + { + default: + case N64Codec.ONEBPP: // Note: "1 bit per pixel" is not a Fast3D format. + return encode1BPP(texture); + case N64Codec.RGBA16: + return encodeRGBA16(texture); + case N64Codec.RGBA32: + return encodeRGBA32(texture); + case N64Codec.IA4: + return encodeIA4(texture); + case N64Codec.IA8: + return encodeIA8(texture); + case N64Codec.IA16: + return encodeIA16(texture); + case N64Codec.I4: + return encodeI4(texture); + case N64Codec.I8: + return encodeI4(texture); + case N64Codec.CI4: + case N64Codec.CI8: + throw new ArgumentException("CI texture encoding is not currently supported in this version."); + } + } + + public static byte getBit(int color, int bit) + { + return (byte)(((color >> 24) & 0xFF) > 0 ? (1 << bit) : 0); + } + + public static byte[] encode1BPP(Bitmap texture) + { + int data_size = (texture.Width * texture.Height) / 8; + byte[] data = new byte[data_size]; + for (int i = 0; i < data_size; i++) + { + int x = (i * 8) % texture.Width; + int y = (i * 8) / texture.Width; + + data[i] = (byte)( + getBit(texture.GetPixel(x + 0, y).ToArgb(), 7) | + getBit(texture.GetPixel(x + 1, y).ToArgb(), 6) | + getBit(texture.GetPixel(x + 2, y).ToArgb(), 5) | + getBit(texture.GetPixel(x + 3, y).ToArgb(), 4) | + getBit(texture.GetPixel(x + 4, y).ToArgb(), 3) | + getBit(texture.GetPixel(x + 5, y).ToArgb(), 2) | + getBit(texture.GetPixel(x + 6, y).ToArgb(), 1) | + getBit(texture.GetPixel(x + 7, y).ToArgb(), 0) + ); + } + return data; + } + + public static byte[] encodeRGBA16(Bitmap texture) + { + int data_size = (texture.Width * texture.Height) * 2; + byte[] data = new byte[data_size]; + for (int i = 0; i < data_size / 2; i++) + { + int x = i % texture.Width; + int y = i / texture.Width; + Color pix = texture.GetPixel(x, y); + byte red = (byte)((pix.R / 256.0f) * 32.0f); + byte green = (byte)((pix.G / 256.0f) * 32.0f); + byte blue = (byte)((pix.B / 256.0f) * 32.0f); + byte alpha = (byte)(pix.A >= 128.0f ? 1 : 0); + + data[i * 2] = (byte)((red << 3) | (green >> 2)); + data[(i * 2) + 1] = (byte)(((green & 3) << 6) | (blue << 1) | alpha); + } + return data; + } + + public static byte[] encodeRGBA32(Bitmap texture) + { + int data_size = (texture.Width * texture.Height) * 4; + byte[] data = new byte[data_size]; + for (int i = 0; i < data_size / 4; i++) + { + int x = i % texture.Width; + int y = i / texture.Width; + Color pix = texture.GetPixel(x, y); + + data[(i * 4) + 0] = pix.R; + data[(i * 4) + 1] = pix.G; + data[(i * 4) + 2] = pix.B; + data[(i * 4) + 3] = pix.A; + } + return data; + } + + public static byte[] encodeIA4(Bitmap texture) + { + int data_size = (texture.Width * texture.Height) / 2; + byte[] data = new byte[data_size]; + for (int i = 0; i < data_size; i++) + { + int x = (i * 2) % texture.Width; + int y = (i * 2) / texture.Width; + + Color pix1 = texture.GetPixel(x, y); + byte pix1_avg = (byte)((((pix1.R + pix1.G + pix1.B) / 3) / 255.0f) * 8.0f); + byte upper = (byte)((pix1_avg << 1) | (pix1.A < 255 ? 0 : 1)); + + Color pix2 = texture.GetPixel(x + 1, y); + byte pix2_avg = (byte)((((pix2.R + pix2.G + pix2.B) / 3) / 255.0f) * 8.0f); + byte lower = (byte)((pix2_avg << 1) | (pix2.A < 255 ? 0 : 1)); + + data[i] = (byte)(((upper & 0xF) << 4) | (lower & 0xF)); + } + return data; + } + + public static byte[] encodeIA8(Bitmap texture) + { + int data_size = texture.Width * texture.Height; + byte[] data = new byte[data_size]; + for (int i = 0; i < data_size; i++) + { + int x = i % texture.Width; + int y = i / texture.Width; + + Color pix = texture.GetPixel(x, y); + byte pix_avg = (byte)((((pix.R + pix.G + pix.B) / 3) / 255.0f) * 16.0f); + byte pix_alpha = (byte)((pix.A / 255.0f) * 16.0f); + + data[i] = (byte)(((pix_avg & 0xF) << 4) | (pix_alpha & 0xF)); + } + return data; + } + + public static byte[] encodeIA16(Bitmap texture) + { + int data_size = texture.Width * texture.Height * 2; + byte[] data = new byte[data_size]; + for (int i = 0; i < data_size / 2; i++) + { + int x = i % texture.Width; + int y = i / texture.Width; + + Color pix = texture.GetPixel(x, y); + byte pix_avg = (byte)((pix.R + pix.G + pix.B) / 3); + + data[i * 2] = pix_avg; + data[(i * 2) + 1] = pix.A; + } + return data; + } + + public static byte[] encodeI4(Bitmap texture) + { + int data_size = (texture.Width * texture.Height) / 2; + byte[] data = new byte[data_size]; + for (int i = 0; i < data_size; i++) + { + int x = (i * 2) % texture.Width; + int y = (i * 2) / texture.Width; + + Color pix1 = texture.GetPixel(x, y); + byte upper = (byte)((((pix1.R + pix1.G + pix1.B) / 3) / 255.0f) * 16.0f); + + Color pix2 = texture.GetPixel(x + 1, y); + byte lower = (byte)((((pix2.R + pix2.G + pix2.B) / 3) / 255.0f) * 16.0f); + + data[i] = (byte)(((upper & 0xF) << 4) | (lower & 0xF)); + } + return data; + } + + + public static byte[] encodeI8(Bitmap texture) + { + int data_size = texture.Width * texture.Height; + byte[] data = new byte[data_size]; + for (int i = 0; i < data_size; i++) + { + int x = i % texture.Width; + int y = i / texture.Width; + + Color pix = texture.GetPixel(x, y); + + data[i] = (byte)((pix.R + pix.G + pix.B) / 3); + } + return data; + } + + public static Bitmap decodeTexture(N64Codec format, byte[] data, int width, int height, ushort[] palette) + { + switch (format) + { + default: + case N64Codec.ONEBPP: // Note: "1 bit per pixel" is not a Fast3D format. + return decode1BPP(data, width, height); + case N64Codec.RGBA16: + return decodeRGBA16(data, width, height); + case N64Codec.RGBA32: + return decodeRGBA32(data, width, height); + case N64Codec.CI4: + return decodeCI4(data, width, height, palette); + case N64Codec.CI8: + return decodeCI8(data, width, height, palette); + case N64Codec.IA4: + return decodeIA4(data, width, height); + case N64Codec.IA8: + return decodeIA8(data, width, height); + case N64Codec.IA16: + return decodeIA16(data, width, height); + case N64Codec.I4: + return decodeI4(data, width, height); + case N64Codec.I8: + return decodeI8(data, width, height); + } + } + + + public static Bitmap decode1BPP(byte[] data, int width, int height) + { + Bitmap tex = new Bitmap(width, height); + if (data.Length >= (width * height) / 8) // Sanity Check + { + int len = (width * height) / 8; + for (int i = 0; i < len; ++i) + { + for (int x = 0; x < 8; x++) + { + byte intensity = (byte)((data[i] >> (7 - x)) & 1); + if (intensity > 0) + intensity = 0xFF; + int alpha = intensity; + int pos = (i * 8) + x; + tex.SetPixel(pos % width, pos / width, Color.FromArgb(alpha, intensity, intensity, intensity)); + } + } + } + tex.Tag = new string[] { "Format: 1BPP", "Width: " + width, + "Height: " + height }; + return tex; + } + + public static Bitmap decodeRGBA32(byte[] data, int width, int height) + { + Console.WriteLine("Texture size = (" + width + "x" + height + ")"); + Console.WriteLine("data.Length = (" + data.Length + ")"); + Bitmap tex = new Bitmap(width, height); + + if (data.Length >= width * height * 4) // Sanity Check + { + BitmapData bitmapData = tex.LockBits(new Rectangle(0, 0, width, height), + ImageLockMode.ReadWrite, tex.PixelFormat); + + int len = width * height; + for (int i = 0; i < len; i++) + { + // Swap red and blue values + byte temp_red = data[(i * 4) + 0]; + data[(i * 4) + 0] = data[(i * 4) + 2]; + data[(i * 4) + 2] = temp_red; + } + Marshal.Copy(data, 0, bitmapData.Scan0, data.Length); + tex.UnlockBits(bitmapData); + + } + tex.Tag = new string[] { "Format: RGBA32", "Width: " + width, + "Height: " + height }; + return tex; + } + + public static Bitmap decodeRGBA16(byte[] data, int width, int height) + { + Bitmap tex = new Bitmap(width, height); + if (data.Length >= width * height * 2) // Sanity Check + { + BitmapData bitmapData = tex.LockBits(new Rectangle(0, 0, width, height), + ImageLockMode.ReadWrite, tex.PixelFormat); + byte[] pixels = new byte[width * height * 4]; + + int len = width * height; + for (int i = 0; i < len; i++) + { + ushort pixel = (ushort)((data[i * 2] << 8) | data[i * 2 + 1]); + pixels[(i * 4) + 2] = (byte)(((pixel >> 11) & 0x1F) * 8); // Red + pixels[(i * 4) + 1] = (byte)(((pixel >> 6) & 0x1F) * 8); // Green + pixels[(i * 4) + 0] = (byte)(((pixel >> 1) & 0x1F) * 8); // Blue + pixels[(i * 4) + 3] = (pixel & 1) > 0 ? (byte)0xFF : (byte)0x00; // (Transparency) + } + Marshal.Copy(pixels, 0, bitmapData.Scan0, pixels.Length); + tex.UnlockBits(bitmapData); + } + + tex.Tag = new string[] { "Format: RGBA16", "Width: " + width, + "Height: " + height }; + return tex; + } + + public static Bitmap decodeIA16(byte[] data, int width, int height) + { + Bitmap tex = new Bitmap(width, height); + if (data.Length >= width * height * 2) // Sanity Check + { + BitmapData bitmapData = tex.LockBits(new Rectangle(0, 0, width, height), + ImageLockMode.ReadWrite, tex.PixelFormat); + byte[] pixels = new byte[width * height * 4]; + + int len = width * height; + for (int i = 0; i < len; i++) + { + pixels[(i * 4) + 2] = data[i * 2]; // Red + pixels[(i * 4) + 1] = data[i * 2]; // Green + pixels[(i * 4) + 0] = data[i * 2]; // Blue + pixels[(i * 4) + 3] = data[(i * 2) + 1]; // Alpha + } + Marshal.Copy(pixels, 0, bitmapData.Scan0, pixels.Length); + tex.UnlockBits(bitmapData); + } + tex.Tag = new string[] { "Format: IA16", "Width: " + width, + "Height: " + height}; + return tex; + } + + public static Bitmap decodeIA8(byte[] data, int width, int height) + { + Bitmap tex = new Bitmap(width, height); + if (data.Length >= width * height) // Sanity Check + { + BitmapData bitmapData = tex.LockBits(new Rectangle(0, 0, width, height), + ImageLockMode.ReadWrite, tex.PixelFormat); + byte[] pixels = new byte[width * height * 4]; + + int len = width * height; + for (int i = 0; i < len; i++) + { + byte intensity = (byte)(((data[i] >> 4) & 0xF) * 16); + pixels[(i * 4) + 2] = intensity; // Red + pixels[(i * 4) + 1] = intensity; // Green + pixels[(i * 4) + 0] = intensity; // Blue + pixels[(i * 4) + 3] = (byte)((data[i] & 0xF) * 16); // Alpha + } + Marshal.Copy(pixels, 0, bitmapData.Scan0, pixels.Length); + tex.UnlockBits(bitmapData); + } + tex.Tag = new string[] { "Format: IA8", "Width: " + width, + "Height: " + height }; + return tex; + } + public static Bitmap decodeIA4(byte[] data, int width, int height) + { + Bitmap tex = new Bitmap(width, height); + + if (data.Length >= (width * height) / 2) // Sanity Check + { + BitmapData bitmapData = tex.LockBits(new Rectangle(0, 0, width, height), + ImageLockMode.ReadWrite, tex.PixelFormat); + byte[] pixels = new byte[width * height * 4]; + + int len = (width * height) / 2; + for (int i = 0; i < len; i++) + { + byte twoPixels = data[i]; + + byte intensity = (byte)((twoPixels >> 5) * 32); + pixels[(i * 8) + 2] = intensity; // Red + pixels[(i * 8) + 1] = intensity; // Green + pixels[(i * 8) + 0] = intensity; // Blue + pixels[(i * 8) + 3] = (byte)(((twoPixels >> 4) & 0x1) * 255); // Alpha + + intensity = (byte)(((twoPixels >> 1) & 0x7) * 32); + pixels[(i * 8) + 6] = intensity; // Red + pixels[(i * 8) + 5] = intensity; // Green + pixels[(i * 8) + 4] = intensity; // Blue + pixels[(i * 8) + 7] = (byte)((twoPixels & 0x1) * 255); // Alpha + } + Marshal.Copy(pixels, 0, bitmapData.Scan0, pixels.Length); + tex.UnlockBits(bitmapData); + tex.Tag = new string[] { "Format: IA4", "Width: " + width, + "Height: " + height }; + } + return tex; + } + public static Bitmap decodeI8(byte[] data, int width, int height) + { + Bitmap tex = new Bitmap(width, height); + + if (data.Length >= width * height) // Sanity Check + { + BitmapData bitmapData = tex.LockBits(new Rectangle(0, 0, width, height), + ImageLockMode.ReadWrite, tex.PixelFormat); + byte[] pixels = new byte[width * height * 4]; + + int len = width * height; + for (int i = 0; i < len; i++) + { + byte intensity = data[i]; + pixels[(i * 4) + 2] = intensity; // Red + pixels[(i * 4) + 1] = intensity; // Green + pixels[(i * 4) + 0] = intensity; // Blue + pixels[(i * 4) + 3] = 0xFF; // Alpha + } + Marshal.Copy(pixels, 0, bitmapData.Scan0, pixels.Length); + tex.UnlockBits(bitmapData); + + tex.Tag = new string[] { "Format: I8", "Width: " + width, + "Height: " + height }; + } + return tex; + } + public static Bitmap decodeI4(byte[] data, int width, int height) + { + Bitmap tex = new Bitmap(width, height); + + if (data.Length >= (width * height) / 2) // Sanity Check + { + BitmapData bitmapData = tex.LockBits(new Rectangle(0, 0, width, height), + ImageLockMode.ReadWrite, tex.PixelFormat); + byte[] pixels = new byte[width * height * 4]; + + int len = (width * height) / 2; + for (int i = 0; i < len; i++) + { + byte twoPixels = data[i]; + + byte intensity = (byte)((twoPixels >> 4) * 16); + pixels[(i * 8) + 2] = intensity; // Red + pixels[(i * 8) + 1] = intensity; // Green + pixels[(i * 8) + 0] = intensity; // Blue + pixels[(i * 8) + 3] = 0xFF; // Alpha + + intensity = (byte)((twoPixels & 0xF) * 16); + pixels[(i * 8) + 6] = intensity; // Red + pixels[(i * 8) + 5] = intensity; // Green + pixels[(i * 8) + 4] = intensity; // Blue + pixels[(i * 8) + 7] = 0xFF; // Alpha + } + Marshal.Copy(pixels, 0, bitmapData.Scan0, pixels.Length); + tex.UnlockBits(bitmapData); + } + tex.Tag = new string[] { "Format: I4", "Width: " + width, + "Height: " + height }; + return tex; + } + + public static Bitmap decodeCI4(byte[] data, int width, int height, ushort[] palette) + { + Bitmap tex = new Bitmap(width, height); + + if (data.Length >= (width * height) / 2) // Sanity Check + { + BitmapData bitmapData = tex.LockBits(new Rectangle(0, 0, width, height), + ImageLockMode.ReadWrite, tex.PixelFormat); + byte[] pixels = new byte[width * height * 4]; + + int len = (width * height) / 2; + for (int i = 0; i < len; i++) + { + ushort pixel = palette[(data[i] >> 4) & 0xF]; + pixels[(i * 8) + 2] = (byte)(((pixel >> 11) & 0x1F) * 8); // Red + pixels[(i * 8) + 1] = (byte)(((pixel >> 6) & 0x1F) * 8); // Green + pixels[(i * 8) + 0] = (byte)(((pixel >> 1) & 0x1F) * 8); // Blue + pixels[(i * 8) + 3] = (pixel & 1) > 0 ? (byte)0xFF : (byte)0x00; // Alpha + + pixel = palette[(data[i]) & 0xF]; + pixels[(i * 8) + 6] = (byte)(((pixel >> 11) & 0x1F) * 8); // Red + pixels[(i * 8) + 5] = (byte)(((pixel >> 6) & 0x1F) * 8); // Green + pixels[(i * 8) + 4] = (byte)(((pixel >> 1) & 0x1F) * 8); // Blue + pixels[(i * 8) + 7] = (pixel & 1) > 0 ? (byte)0xFF : (byte)0x00; // Alpha + + } + Marshal.Copy(pixels, 0, bitmapData.Scan0, pixels.Length); + tex.UnlockBits(bitmapData); + } + tex.Tag = new string[] { "Format: CI4", "Width: " + width, + "Height: " + height }; + return tex; + } + + public static Bitmap decodeCI8(byte[] data, int width, int height, ushort[] palette) + { + Bitmap tex = new Bitmap(width, height); + + if (data.Length >= width * height) // Sanity Check + { + BitmapData bitmapData = tex.LockBits(new Rectangle(0, 0, width, height), + ImageLockMode.ReadWrite, tex.PixelFormat); + byte[] pixels = new byte[width * height * 4]; + + int len = width * height; + for (int i = 0; i < len; i++) + { + ushort pixel = palette[data[i]]; + pixels[(i * 4) + 2] = (byte)(((pixel >> 11) & 0x1F) * 8); // Red + pixels[(i * 4) + 1] = (byte)(((pixel >> 6) & 0x1F) * 8); // Green + pixels[(i * 4) + 0] = (byte)(((pixel >> 1) & 0x1F) * 8); // Blue + pixels[(i * 4) + 3] = (pixel & 1) > 0 ? (byte)0xFF : (byte)0x00; // (Transparency) + //tex.SetPixel(i % width, i / width, Color.FromArgb(alpha, red, green, blue)); + } + Marshal.Copy(pixels, 0, bitmapData.Scan0, pixels.Length); + tex.UnlockBits(bitmapData); + } + tex.Tag = new string[] { "Format: CI8", "Width: " + width, + "Height: " + height }; + return tex; + } } diff --git a/SM64Lib.Text.Exporters/ExcelExporter.cs b/SM64Lib.Text.Exporters/ExcelExporter.cs index bd71057..935b53f 100644 --- a/SM64Lib.Text.Exporters/ExcelExporter.cs +++ b/SM64Lib.Text.Exporters/ExcelExporter.cs @@ -1,102 +1,98 @@ using OfficeOpenXml; using System; -using System.Collections.Generic; using System.IO; -using System.Linq; -using System.Text; using System.Threading.Tasks; -namespace SM64Lib.Text.Exporters +namespace SM64Lib.Text.Exporters; + +public class ExcelExporter { - public class ExcelExporter + public ExcelExporter() { - public ExcelExporter() + ExcelPackage.LicenseContext = LicenseContext.NonCommercial; + } + + public async Task Export(string destFilePath, TextGroup[] groups) + { + var pkg = new ExcelPackage(); + + foreach (var tg in groups) { - ExcelPackage.LicenseContext = LicenseContext.NonCommercial; + var ws = pkg.Workbook.Worksheets.Add(tg.TextGroupInfo.Name); + var hasDialogCells = false; + + ws.Cells.Style.VerticalAlignment = OfficeOpenXml.Style.ExcelVerticalAlignment.Top; + ws.Cells.Style.HorizontalAlignment = OfficeOpenXml.Style.ExcelHorizontalAlignment.Left; + ws.Row(1).Style.Font.Bold = true; + ws.Cells[1, 1].Value = "#"; + ws.Cells[1, 2].Value = "Text"; + + for (int i = 0; i < tg.Count; i++) + { + var ti = tg[i]; + var ri = i + 2; + + ws.Cells[ri, 1].Value = i; + ws.Cells[ri, 2].Value = ti.Text; + + if (ti is TextTableDialogItem) + hasDialogCells = true; + } + + + for (int ri = 1; ri <= ws.Cells.Rows; ri++) + { + var r = ws.Row(ri); + r.CustomHeight = false; + } + + if (hasDialogCells) + { + var c = ws.Column(2); + c.Style.WrapText = true; + c.Width = 30; + } + + for (int ci = 1; ci <= 2; ci++) + { + var c = ws.Column(ci); + if (!c.Style.WrapText) + c.AutoFit(); + } } - public async Task Export(string destFilePath, TextGroup[] groups) + await pkg.SaveAsAsync(new FileInfo(destFilePath)); + pkg.Dispose(); + } + + public async Task Import(string filePath, TextGroup[] groups) + { + try { var pkg = new ExcelPackage(); + await pkg.LoadAsync(new FileInfo(filePath)); foreach (var tg in groups) { - var ws = pkg.Workbook.Worksheets.Add(tg.TextGroupInfo.Name); - var hasDialogCells = false; - - ws.Cells.Style.VerticalAlignment = OfficeOpenXml.Style.ExcelVerticalAlignment.Top; - ws.Cells.Style.HorizontalAlignment = OfficeOpenXml.Style.ExcelHorizontalAlignment.Left; - ws.Row(1).Style.Font.Bold = true; - ws.Cells[1, 1].Value = "#"; - ws.Cells[1, 2].Value = "Text"; - - for (int i = 0; i < tg.Count; i++) + var ws = pkg.Workbook.Worksheets[tg.TextGroupInfo.Name]; + if (ws is not null) { - var ti = tg[i]; - var ri = i + 2; - - ws.Cells[ri, 1].Value = i; - ws.Cells[ri, 2].Value = ti.Text; - - if (ti is TextTableDialogItem) - hasDialogCells = true; - } - - - for (int ri = 1; ri <= ws.Cells.Rows; ri++) - { - var r = ws.Row(ri); - r.CustomHeight = false; - } - - if (hasDialogCells) - { - var c = ws.Column(2); - c.Style.WrapText = true; - c.Width = 30; - } - - for (int ci = 1; ci <= 2; ci++) - { - var c = ws.Column(ci); - if (!c.Style.WrapText) - c.AutoFit(); - } - } - - await pkg.SaveAsAsync(new FileInfo(destFilePath)); - pkg.Dispose(); - } - - public async Task Import(string filePath, TextGroup[] groups) - { - try - { - var pkg = new ExcelPackage(); - await pkg.LoadAsync(new FileInfo(filePath)); - - foreach (var tg in groups) - { - var ws = pkg.Workbook.Worksheets[tg.TextGroupInfo.Name]; - if (ws is not null) + for (int iti = 0; iti < tg.Count; iti++) { - for (int iti = 0; iti < tg.Count; iti++) - { - var ti = tg[iti]; - var ri = iti + 2; - var c = ws.Cells[ri, 2]; + var ti = tg[iti]; + var ri = iti + 2; + var c = ws.Cells[ri, 2]; - ti.Text = ((string)c.Value).Replace("\r\n", "\n").Replace("\n", "\r\n"); - tg.NeedToSave = true; - } + ti.Text = ((string)c.Value).Replace("\r\n", "\n").Replace("\n", "\r\n"); + tg.NeedToSave = true; } } + } - pkg.Dispose(); - } - catch (Exception) - { - } + pkg.Dispose(); + } + catch (Exception) + { } } } diff --git a/SM64Lib.Text.Exporters/Properties/AssemblyInfo.cs b/SM64Lib.Text.Exporters/Properties/AssemblyInfo.cs index 0a38d8c..09226f9 100644 --- a/SM64Lib.Text.Exporters/Properties/AssemblyInfo.cs +++ b/SM64Lib.Text.Exporters/Properties/AssemblyInfo.cs @@ -1,6 +1,4 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; +using System.Runtime.InteropServices; // Durch Festlegen von ComVisible auf FALSE werden die Typen in dieser Assembly // für COM-Komponenten unsichtbar. Wenn Sie auf einen Typ in dieser Assembly von diff --git a/SM64Lib.Text.Exporters/TxtExporter.cs b/SM64Lib.Text.Exporters/TxtExporter.cs index da66691..8e9cfe0 100644 --- a/SM64Lib.Text.Exporters/TxtExporter.cs +++ b/SM64Lib.Text.Exporters/TxtExporter.cs @@ -1,48 +1,43 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; +using System.IO; using System.Threading.Tasks; -namespace SM64Lib.Text.Exporters +namespace SM64Lib.Text.Exporters; + +public class TxtExporter { - public class TxtExporter + public async Task Export(string destFilePath, TextGroup[] groups) { - public async Task Export(string destFilePath, TextGroup[] groups) + var sw = new StreamWriter(destFilePath); + + for (int itg = 0; itg < groups.Length; itg++) { - var sw = new StreamWriter(destFilePath); + var tg = groups[itg]; - for (int itg = 0; itg < groups.Length; itg++) - { - var tg = groups[itg]; - - if (itg != 0) - await sw.WriteLineAsync("------------------------------\n"); - await sw.WriteLineAsync($"Text Group - {tg.TextGroupInfo.Name}\n"); + if (itg != 0) await sw.WriteLineAsync("------------------------------\n"); + await sw.WriteLineAsync($"Text Group - {tg.TextGroupInfo.Name}\n"); + await sw.WriteLineAsync("------------------------------\n"); - for (int iti = 0; iti < tg.Count; iti++) + for (int iti = 0; iti < tg.Count; iti++) + { + var ti = tg[iti]; + + if (ti is TextTableDialogItem) { - var ti = tg[iti]; - - if (ti is TextTableDialogItem) - { - await sw.WriteLineAsync($"Dialog #{iti}\n"); - await sw.WriteLineAsync(ti.Text); - await sw.WriteLineAsync("\n\n"); - } - else - { - await sw.WriteLineAsync($"Text Item #{iti}"); - await sw.WriteLineAsync(ti.Text); - await sw.WriteLineAsync(); - } + await sw.WriteLineAsync($"Dialog #{iti}\n"); + await sw.WriteLineAsync(ti.Text); + await sw.WriteLineAsync("\n\n"); + } + else + { + await sw.WriteLineAsync($"Text Item #{iti}"); + await sw.WriteLineAsync(ti.Text); + await sw.WriteLineAsync(); } } - - await sw.FlushAsync(); - sw.Close(); } + + await sw.FlushAsync(); + sw.Close(); } } diff --git a/SM64Lib.TextValueConverter/Properties/AssemblyInfo.cs b/SM64Lib.TextValueConverter/Properties/AssemblyInfo.cs index 021c7af..3c546af 100644 --- a/SM64Lib.TextValueConverter/Properties/AssemblyInfo.cs +++ b/SM64Lib.TextValueConverter/Properties/AssemblyInfo.cs @@ -1,5 +1,4 @@ using global::System; -using global::System.Reflection; using global::System.Runtime.InteropServices; [assembly: ComVisible(false)] diff --git a/SM64Lib.TextValueConverter/TextValueConverter.cs b/SM64Lib.TextValueConverter/TextValueConverter.cs index 170a6f1..f54df49 100644 --- a/SM64Lib.TextValueConverter/TextValueConverter.cs +++ b/SM64Lib.TextValueConverter/TextValueConverter.cs @@ -1,89 +1,87 @@ using System; -using Microsoft.VisualBasic.CompilerServices; -namespace SM64Lib.TextValueConverter +namespace SM64Lib.TextValueConverter; + +public static class TextValueConverter { - public static class TextValueConverter + public static event WantIntegerValueModeEventHandler WantIntegerValueMode; + public delegate void WantIntegerValueModeEventHandler(WantIntegerValueModeEventArgs e); + + public static int ValueFromText(string Text, int DefaultValue = 0, int useIVM = -1) { - public static event WantIntegerValueModeEventHandler WantIntegerValueMode; - public delegate void WantIntegerValueModeEventHandler(WantIntegerValueModeEventArgs e); + return Convert.ToInt32(LongFromText(Text, DefaultValue, useIVM)); + } - public static int ValueFromText(string Text, int DefaultValue = 0, int useIVM = -1) + public static long LongFromText(string Text, long DefaultValue = 0, int useIVM = -1) + { + try { - return Convert.ToInt32(LongFromText(Text, DefaultValue, useIVM)); - } + int IVM = useIVM > -1 ? useIVM : GetIntegerValueMode(); + Text = Text?.ToLower()?.Trim(); - public static long LongFromText(string Text, long DefaultValue = 0, int useIVM = -1) - { - try + if (string.IsNullOrWhiteSpace(Text)) + return 0; + + switch (true) { - int IVM = useIVM > -1 ? useIVM : GetIntegerValueMode(); - Text = Text?.ToLower()?.Trim(); - - if (string.IsNullOrWhiteSpace(Text)) - return 0; - - switch (true) - { - case object _ when Text.StartsWith("0x"): - case object _ when Text.StartsWith("&h"): - return Convert.ToInt32(Text.Substring(2), 16); - case object _ when Text.StartsWith("$"): - return Convert.ToInt32(Text.Substring(1), 16); - case object _ when Text.StartsWith("0b"): - case object _ when Text.StartsWith("&b"): - return Convert.ToInt32(Text.Substring(2), 2); - default: - return Convert.ToInt32(Text); - } - } - catch (Exception) - { - return DefaultValue; - } - } - - public static string TextFromValue(long Value, int IVM = -1, int charCount = 0) - { - if (IVM == -1) - { - IVM = GetIntegerValueMode(); - } - - switch (IVM) - { - case 0: - return Value.ToString(GetCharCountAsZeroString(charCount)); - case 1: - return "0x" + Value.ToString("X" + (charCount > 0 ? charCount.ToString() : "")); - case 2: - return "&H" + Value.ToString("X" + (charCount > 0 ? charCount.ToString() : "")); - case 3: - return "$" + Value.ToString("X" + (charCount > 0 ? charCount.ToString() : "")); + case object _ when Text.StartsWith("0x"): + case object _ when Text.StartsWith("&h"): + return Convert.ToInt32(Text.Substring(2), 16); + case object _ when Text.StartsWith("$"): + return Convert.ToInt32(Text.Substring(1), 16); + case object _ when Text.StartsWith("0b"): + case object _ when Text.StartsWith("&b"): + return Convert.ToInt32(Text.Substring(2), 2); default: - return string.Empty; + return Convert.ToInt32(Text); } } - - private static string GetCharCountAsZeroString(int charCount) + catch (Exception) { - string GetCharCountAsZeroStringRet = default; - GetCharCountAsZeroStringRet = ""; - while (GetCharCountAsZeroStringRet.Length < charCount) - GetCharCountAsZeroStringRet += "0"; - return GetCharCountAsZeroStringRet; - } - - private static int GetIntegerValueMode() - { - var e = new WantIntegerValueModeEventArgs(); - WantIntegerValueMode?.Invoke(e); - return e.IntegerValueMode; + return DefaultValue; } } - public class WantIntegerValueModeEventArgs : EventArgs + public static string TextFromValue(long Value, int IVM = -1, int charCount = 0) { - public int IntegerValueMode { get; set; } + if (IVM == -1) + { + IVM = GetIntegerValueMode(); + } + + switch (IVM) + { + case 0: + return Value.ToString(GetCharCountAsZeroString(charCount)); + case 1: + return "0x" + Value.ToString("X" + (charCount > 0 ? charCount.ToString() : "")); + case 2: + return "&H" + Value.ToString("X" + (charCount > 0 ? charCount.ToString() : "")); + case 3: + return "$" + Value.ToString("X" + (charCount > 0 ? charCount.ToString() : "")); + default: + return string.Empty; + } } + + private static string GetCharCountAsZeroString(int charCount) + { + string GetCharCountAsZeroStringRet = default; + GetCharCountAsZeroStringRet = ""; + while (GetCharCountAsZeroStringRet.Length < charCount) + GetCharCountAsZeroStringRet += "0"; + return GetCharCountAsZeroStringRet; + } + + private static int GetIntegerValueMode() + { + var e = new WantIntegerValueModeEventArgs(); + WantIntegerValueMode?.Invoke(e); + return e.IntegerValueMode; + } +} + +public class WantIntegerValueModeEventArgs : EventArgs +{ + public int IntegerValueMode { get; set; } } \ No newline at end of file diff --git a/SM64Lib/ASM/CustomAsmArea.cs b/SM64Lib/ASM/CustomAsmArea.cs index e34272b..dbff10b 100644 --- a/SM64Lib/ASM/CustomAsmArea.cs +++ b/SM64Lib/ASM/CustomAsmArea.cs @@ -1,83 +1,77 @@ using Newtonsoft.Json; using SM64Lib.Data; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace SM64Lib.ASM +namespace SM64Lib.ASM; + +public class CustomAsmArea { - public class CustomAsmArea + public byte[] AreaBytes { get; set; } + + [JsonProperty(nameof(Config))] + private CustomAsmAreaConfig config; + + [JsonIgnore] + public CustomAsmAreaConfig Config { - public byte[] AreaBytes { get; set; } - - [JsonProperty(nameof(Config))] - private CustomAsmAreaConfig config; - - [JsonIgnore] - public CustomAsmAreaConfig Config + get { - get - { - if (config == null) - config = new CustomAsmAreaConfig(); - return config; - } - } - - [JsonConstructor] - private CustomAsmArea(JsonConstructorAttribute emptyObject) - { - } - - public CustomAsmArea() - : this(true) - { - } - - private CustomAsmArea(bool createEmptyAreaBytesArray) - : this(null, createEmptyAreaBytesArray) - { - } - - public CustomAsmArea(CustomAsmAreaConfig config) - : this(config, false) - { - } - - private CustomAsmArea(CustomAsmAreaConfig config, bool createEmptyAreaBytesArray) - { - this.config = config; - - if (createEmptyAreaBytesArray) - AreaBytes = new byte[] { }; - } - - public void Load(BinaryData data, CustomAsmBankConfig bankConfig) - { - if (Config.RomAddress != -1 && Config.Length > 0) - { - data.Position = Config.RomAddress; - AreaBytes = data.Read(Config.Length); - } - else - AreaBytes = new byte[] { }; - } - - public int Save(BinaryData data, int address, CustomAsmBankConfig bankConfig) - { - data.Position = address; - data.Write(AreaBytes); - return UpdateAddresses(address, bankConfig); - } - - internal int UpdateAddresses(int address, CustomAsmBankConfig bankConfig) - { - Config.RomAddress = address; - Config.Length = AreaBytes.Length; - Config.RamAddress = address - bankConfig.GetRomStartAddress() + bankConfig.GetRamStartAddress(); - return Config.Length; + if (config == null) + config = new CustomAsmAreaConfig(); + return config; } } + + [JsonConstructor] + private CustomAsmArea(JsonConstructorAttribute emptyObject) + { + } + + public CustomAsmArea() + : this(true) + { + } + + private CustomAsmArea(bool createEmptyAreaBytesArray) + : this(null, createEmptyAreaBytesArray) + { + } + + public CustomAsmArea(CustomAsmAreaConfig config) + : this(config, false) + { + } + + private CustomAsmArea(CustomAsmAreaConfig config, bool createEmptyAreaBytesArray) + { + this.config = config; + + if (createEmptyAreaBytesArray) + AreaBytes = new byte[] { }; + } + + public void Load(BinaryData data, CustomAsmBankConfig bankConfig) + { + if (Config.RomAddress != -1 && Config.Length > 0) + { + data.Position = Config.RomAddress; + AreaBytes = data.Read(Config.Length); + } + else + AreaBytes = new byte[] { }; + } + + public int Save(BinaryData data, int address, CustomAsmBankConfig bankConfig) + { + data.Position = address; + data.Write(AreaBytes); + return UpdateAddresses(address, bankConfig); + } + + internal int UpdateAddresses(int address, CustomAsmBankConfig bankConfig) + { + Config.RomAddress = address; + Config.Length = AreaBytes.Length; + Config.RamAddress = address - bankConfig.GetRomStartAddress() + bankConfig.GetRamStartAddress(); + return Config.Length; + } } diff --git a/SM64Lib/ASM/CustomAsmAreaConfig.cs b/SM64Lib/ASM/CustomAsmAreaConfig.cs index dff55ca..c7f61bc 100644 --- a/SM64Lib/ASM/CustomAsmAreaConfig.cs +++ b/SM64Lib/ASM/CustomAsmAreaConfig.cs @@ -1,39 +1,33 @@ using Newtonsoft.Json; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Pilz.Cryptography; using Pilz.Json.Converters; -namespace SM64Lib.ASM +namespace SM64Lib.ASM; + +public class CustomAsmAreaConfig { - public class CustomAsmAreaConfig + internal delegate void RequestCustomAsmAreaEventHandler(CustomAsmAreaConfig config, RequestCustomAsmAreaEventArgs request); + internal static event RequestCustomAsmAreaEventHandler RequestCustomAsmArea; + + [JsonConverter(typeof(UniquieIDStringJsonConverter))] + public UniquieID ID { get; set; } = new(); + public string Name { get; set; } + [JsonProperty] + public int RamAddress { get; internal set; } = -1; + [JsonProperty] + public int RomAddress { get; internal set; } = -1; + [JsonProperty] + public int Length { get; internal set; } = 0; + + public CustomAsmArea FindCustomAsmArea() { - internal delegate void RequestCustomAsmAreaEventHandler(CustomAsmAreaConfig config, RequestCustomAsmAreaEventArgs request); - internal static event RequestCustomAsmAreaEventHandler RequestCustomAsmArea; + var args = new RequestCustomAsmAreaEventArgs(); + RequestCustomAsmArea?.Invoke(this, args); + return args.CustomAsmArea; + } - [JsonConverter(typeof(UniquieIDStringJsonConverter))] - public UniquieID ID { get; set; } = new(); - public string Name { get; set; } - [JsonProperty] - public int RamAddress { get; internal set; } = -1; - [JsonProperty] - public int RomAddress { get; internal set; } = -1; - [JsonProperty] - public int Length { get; internal set; } = 0; - - public CustomAsmArea FindCustomAsmArea() - { - var args = new RequestCustomAsmAreaEventArgs(); - RequestCustomAsmArea?.Invoke(this, args); - return args.CustomAsmArea; - } - - internal class RequestCustomAsmAreaEventArgs - { - public CustomAsmArea CustomAsmArea { get; set; } - } + internal class RequestCustomAsmAreaEventArgs + { + public CustomAsmArea CustomAsmArea { get; set; } } } diff --git a/SM64Lib/ASM/CustomAsmBank.cs b/SM64Lib/ASM/CustomAsmBank.cs index 0013409..33450a5 100644 --- a/SM64Lib/ASM/CustomAsmBank.cs +++ b/SM64Lib/ASM/CustomAsmBank.cs @@ -1,85 +1,81 @@ using Newtonsoft.Json; -using System; using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace SM64Lib.ASM +namespace SM64Lib.ASM; + +public class CustomAsmBank { - public class CustomAsmBank + public CustomAsmBankConfig Config { get; } + [JsonIgnore] + public List Areas { get; } = new List(); + + public CustomAsmBank() : this(new CustomAsmBankConfig()) { - public CustomAsmBankConfig Config { get; } - [JsonIgnore] - public List Areas { get; } = new List(); + } - public CustomAsmBank() : this(new CustomAsmBankConfig()) + public CustomAsmBank(CustomAsmBankConfig config) + { + Config = config; + } + + public void Load(RomManager romManager) + { + Areas.Clear(); + + bool canLoadArea(CustomAsmAreaConfig areaConfig) => + areaConfig.RomAddress != -1; + + if (Config.Areas.Where(n => canLoadArea(n)).Any()) { - } + var data = romManager.GetBinaryRom(System.IO.FileAccess.Read); - public CustomAsmBank(CustomAsmBankConfig config) - { - Config = config; - } - - public void Load(RomManager romManager) - { - Areas.Clear(); - - bool canLoadArea(CustomAsmAreaConfig areaConfig) => - areaConfig.RomAddress != -1; - - if (Config.Areas.Where(n => canLoadArea(n)).Any()) + foreach (var areaConfig in Config.Areas) { - var data = romManager.GetBinaryRom(System.IO.FileAccess.Read); - - foreach (var areaConfig in Config.Areas) - { - var area = new CustomAsmArea(areaConfig); - area.Config.ID.GenerateIfNull(); - area.Load(data, Config); - Areas.Add(area); - } - - data.Close(); + var area = new CustomAsmArea(areaConfig); + area.Config.ID.GenerateIfNull(); + area.Load(data, Config); + Areas.Add(area); } + + data.Close(); + } + } + + public void Save(RomManager romManager) + { + var startAddr = Config.GetRomStartAddress(); + var curRomAddr = startAddr; + + if (Areas.Any()) + { + var data = romManager.GetBinaryRom(System.IO.FileAccess.ReadWrite); + + foreach (var area in Areas) + curRomAddr += area.Save(data, curRomAddr, Config); + + data.Close(); } - public void Save(RomManager romManager) + UpdateAreaConfigCollection(); + Config.Length = curRomAddr - startAddr; + } + + public void UpdateAddresses() + { + if (Areas.Any()) { var startAddr = Config.GetRomStartAddress(); var curRomAddr = startAddr; - - if (Areas.Any()) - { - var data = romManager.GetBinaryRom(System.IO.FileAccess.ReadWrite); - - foreach (var area in Areas) - curRomAddr += area.Save(data, curRomAddr, Config); - - data.Close(); - } - - UpdateAreaConfigCollection(); + foreach (var area in Areas) + curRomAddr += area.UpdateAddresses(curRomAddr, Config); Config.Length = curRomAddr - startAddr; } + } - public void UpdateAddresses() - { - if (Areas.Any()) - { - var startAddr = Config.GetRomStartAddress(); - var curRomAddr = startAddr; - foreach (var area in Areas) - curRomAddr += area.UpdateAddresses(curRomAddr, Config); - Config.Length = curRomAddr - startAddr; - } - } - - public void UpdateAreaConfigCollection() - { - Config.Areas.Clear(); - Config.Areas.AddRange(Areas.Select(n => n.Config)); - } + public void UpdateAreaConfigCollection() + { + Config.Areas.Clear(); + Config.Areas.AddRange(Areas.Select(n => n.Config)); } } diff --git a/SM64Lib/ASM/CustomAsmBankConfig.cs b/SM64Lib/ASM/CustomAsmBankConfig.cs index 14646bb..63df9ef 100644 --- a/SM64Lib/ASM/CustomAsmBankConfig.cs +++ b/SM64Lib/ASM/CustomAsmBankConfig.cs @@ -1,50 +1,45 @@ using Newtonsoft.Json; -using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace SM64Lib.ASM +namespace SM64Lib.ASM; + +public class CustomAsmBankConfig { - public class CustomAsmBankConfig + public static int DefaultMaxLength { get; set; } = 0xA000; + public static int DefaultRomStartAddress { get; internal set; } = 0x1206000; + public static int DefaultRamStartAddress { get; internal set; } = 0x406000; + + public List Areas { get; } = new List(); + public int MaxLength { get; set; } = -1; + [JsonProperty] + public int Length { get; internal set; } = -1; + public int RomStartAddress { get; set; } = -1; + public int RamStartAddress { get; set; } = -1; + + public int GetRomStartAddress() + => GetRomStartAddressAdv().address; + + public (int address, bool isDefault) GetRomStartAddressAdv() { - public static int DefaultMaxLength { get; set; } = 0xA000; - public static int DefaultRomStartAddress { get; internal set; } = 0x1206000; - public static int DefaultRamStartAddress { get; internal set; } = 0x406000; + bool isDefault = RomStartAddress == -1; + return (isDefault ? DefaultRomStartAddress : RomStartAddress, isDefault); + } - public List Areas { get; } = new List(); - public int MaxLength { get; set; } = -1; - [JsonProperty] - public int Length { get; internal set; } = -1; - public int RomStartAddress { get; set; } = -1; - public int RamStartAddress { get; set; } = -1; + public int GetRamStartAddress() + => GetRamStartAddressAdv().address; - public int GetRomStartAddress() - => GetRomStartAddressAdv().address; + public (int address, bool isDefault) GetRamStartAddressAdv() + { + bool isDefault = RamStartAddress == -1; + return (isDefault ? DefaultRamStartAddress : RamStartAddress, isDefault); + } - public (int address, bool isDefault) GetRomStartAddressAdv() - { - bool isDefault = RomStartAddress == -1; - return (isDefault ? DefaultRomStartAddress : RomStartAddress, isDefault); - } + public int GetMaxLength() + => GetMaxLengthAdv().length; - public int GetRamStartAddress() - => GetRamStartAddressAdv().address; - - public (int address, bool isDefault) GetRamStartAddressAdv() - { - bool isDefault = RamStartAddress == -1; - return (isDefault ? DefaultRamStartAddress : RamStartAddress, isDefault); - } - - public int GetMaxLength() - => GetMaxLengthAdv().length; - - public (int length, bool isDefault) GetMaxLengthAdv() - { - bool isDefault = RamStartAddress == -1; - return (isDefault ? DefaultMaxLength : MaxLength, isDefault); - } + public (int length, bool isDefault) GetMaxLengthAdv() + { + bool isDefault = RamStartAddress == -1; + return (isDefault ? DefaultMaxLength : MaxLength, isDefault); } } diff --git a/SM64Lib/BaseTweakScriptInfo.cs b/SM64Lib/BaseTweakScriptInfo.cs index 55a1b66..92a507e 100644 --- a/SM64Lib/BaseTweakScriptInfo.cs +++ b/SM64Lib/BaseTweakScriptInfo.cs @@ -1,30 +1,25 @@ using SM64Lib.Patching; using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace SM64Lib +namespace SM64Lib; + +public class BaseTweakScriptInfo { - public class BaseTweakScriptInfo - { - public PatchScript Script { get; private set; } - public int Priority { get; private set; } - public bool IsReadOnly { get; private set; } - public string Name { get; private set; } - public bool EnabledByDefault { get; private set; } - public bool Enabled { get; set; } + public PatchScript Script { get; private set; } + public int Priority { get; private set; } + public bool IsReadOnly { get; private set; } + public string Name { get; private set; } + public bool EnabledByDefault { get; private set; } + public bool Enabled { get; set; } - public BaseTweakScriptInfo(PatchScript script) - { - var infos = script.Name.Split('#'); - Priority = Convert.ToInt32(infos[0]); - IsReadOnly = infos[1] == "w" ? true : false; - EnabledByDefault = infos[2] == "y" ? true : false; - Enabled = EnabledByDefault; - Name = infos[3]; - Script = script; - } + public BaseTweakScriptInfo(PatchScript script) + { + var infos = script.Name.Split('#'); + Priority = Convert.ToInt32(infos[0]); + IsReadOnly = infos[1] == "w" ? true : false; + EnabledByDefault = infos[2] == "y" ? true : false; + Enabled = EnabledByDefault; + Name = infos[3]; + Script = script; } } diff --git a/SM64Lib/Behaviors/Behavior.cs b/SM64Lib/Behaviors/Behavior.cs index a2dd0f1..5af431b 100644 --- a/SM64Lib/Behaviors/Behavior.cs +++ b/SM64Lib/Behaviors/Behavior.cs @@ -5,237 +5,234 @@ using SM64Lib.Data; using System; using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; using Z.Collections.Extensions; using static SM64Lib.Extensions.ObjectExtensions; -namespace SM64Lib.Behaviors +namespace SM64Lib.Behaviors; + +public class Behavior { - public class Behavior + private readonly Dictionary knownCustomAsmCommands = new Dictionary(); + + [JsonProperty] + public BehaviorConfig Config { get; private set; } + [JsonProperty] + public Behaviorscript Script { get; private set; } + public int CollisionPointer { get; set; } + public bool EnableCollisionPointer { get; set; } + public List BehaviorAddressDestinations { get; set; } = new List(); + + [JsonIgnore] + public long Length { - private readonly Dictionary knownCustomAsmCommands = new Dictionary(); - - [JsonProperty] - public BehaviorConfig Config { get; private set; } - [JsonProperty] - public Behaviorscript Script { get; private set; } - public int CollisionPointer { get; set; } - public bool EnableCollisionPointer { get; set; } - public List BehaviorAddressDestinations { get; set; } = new List(); - - [JsonIgnore] - public long Length + get { - get + if (Config.FixedLength == -1) + return Script.Length; + else + return Config.FixedLength; + } + } + + public Behavior() : this(new BehaviorConfig()) + { + } + + public Behavior(BehaviorConfig config) + { + CreateNewBehaviorscript(); + Config = config; + } + + public Behavior(BehaviorCreationTypes behaviorCreationType) : this() + { + Create(behaviorCreationType); + } + + public void Create(BehaviorCreationTypes type) + { + CreateNewBehaviorscript(); + + switch (type) + { + case BehaviorCreationTypes.SolidObject: + Script.Add(new BehaviorscriptCommand("00 09 00 00")); + Script.Add(new BehaviorscriptCommand("11 01 00 01")); + Script.Add(new BehaviorscriptCommand("2a 00 00 00 00 00 00 00")); + Script.Add(new BehaviorscriptCommand("08 00 00 00")); + Script.Add(new BehaviorscriptCommand("0c 00 00 00 80 38 39 cc")); + Script.Add(new BehaviorscriptCommand("09 00 00 00")); + break; + } + + ParseScript(); + } + + private void CreateNewBehaviorscript() + { + if (Script != null) + Script.Close(); + Script = new Behaviorscript(); + } + + public bool Read(BinaryData data, int address) + { + CreateNewBehaviorscript(); + var success = Script.Read(data, address, Config.IsVanilla, Config.ExpectedLength != -1, Config.ExpectedLength); + if (Config.IsVanilla) + Config.FixedLength = (int)Script.Length; + Config.ExpectedLength = (int)Script.Length; + ParseScript(); + return success; + } + + public void Write(BinaryData data, int address) + { + //if (!Config.IsVanilla) + TakeoverSettingsToScript(); + + var length = Script.Write(data, address); + + if (Config.FixedLength != -1 && length != Config.FixedLength) + data.Position -= length - Config.FixedLength; + Config.ExpectedLength = length; + } + + public void ParseScript() + { + var dicCustomAsmFuncs = new Dictionary(); + EnableCollisionPointer = false; + knownCustomAsmCommands.Clear(); + + foreach (var link in Config.CustomAsmLinks) + dicCustomAsmFuncs.AddOrUpdate(link.CustomAsmAreaConfig.RamAddress | unchecked((int)0x80000000), link); + + foreach (BehaviorscriptCommand cmd in Script) + { + switch (cmd.CommandType) { - if (Config.FixedLength == -1) - return Script.Length; - else - return Config.FixedLength; - } - } - - public Behavior() : this(new BehaviorConfig()) - { - } - - public Behavior(BehaviorConfig config) - { - CreateNewBehaviorscript(); - Config = config; - } - - public Behavior(BehaviorCreationTypes behaviorCreationType) : this() - { - Create(behaviorCreationType); - } - - public void Create(BehaviorCreationTypes type) - { - CreateNewBehaviorscript(); - - switch (type) - { - case BehaviorCreationTypes.SolidObject: - Script.Add(new BehaviorscriptCommand("00 09 00 00")); - Script.Add(new BehaviorscriptCommand("11 01 00 01")); - Script.Add(new BehaviorscriptCommand("2a 00 00 00 00 00 00 00")); - Script.Add(new BehaviorscriptCommand("08 00 00 00")); - Script.Add(new BehaviorscriptCommand("0c 00 00 00 80 38 39 cc")); - Script.Add(new BehaviorscriptCommand("09 00 00 00")); + case BehaviorscriptCommandTypes.x2A_SetCollision: + CollisionPointer = BehaviorscriptCommandFunctions.X2A.GetCollisionPointer(cmd); + EnableCollisionPointer = true; + break; + case BehaviorscriptCommandTypes.x0C_CallFunction: + var ptr = BehaviorscriptCommandFunctions.X0C.GetAsmPointer(cmd); + if (dicCustomAsmFuncs.ContainsKey(ptr)) + knownCustomAsmCommands.AddOrUpdate(dicCustomAsmFuncs[ptr].CustomAsmAreaConfig, cmd); break; } - - ParseScript(); } + } - private void CreateNewBehaviorscript() + public void TakeoverSettingsToScript() + { + // Update collision pointer + AddUpdateRemoveCmd( + BehaviorscriptCommandTypes.x2A_SetCollision, + EnableCollisionPointer, + () => BehaviorscriptCommandFactory.Build_x2A(CollisionPointer), + (cmd) => BehaviorscriptCommandFunctions.X2A.SetCollisionPointer(cmd, CollisionPointer)); + + // Insert Custom Asm Links { - if (Script != null) - Script.Close(); - Script = new Behaviorscript(); - } - - public bool Read(BinaryData data, int address) - { - CreateNewBehaviorscript(); - var success = Script.Read(data, address, Config.IsVanilla, Config.ExpectedLength != -1, Config.ExpectedLength); - if (Config.IsVanilla) - Config.FixedLength = (int)Script.Length; - Config.ExpectedLength = (int)Script.Length; - ParseScript(); - return success; - } - - public void Write(BinaryData data, int address) - { - //if (!Config.IsVanilla) - TakeoverSettingsToScript(); - - var length = Script.Write(data, address); - - if (Config.FixedLength != -1 && length != Config.FixedLength) - data.Position -= length - Config.FixedLength; - Config.ExpectedLength = length; - } - - public void ParseScript() - { - var dicCustomAsmFuncs = new Dictionary(); - EnableCollisionPointer = false; - knownCustomAsmCommands.Clear(); - foreach (var link in Config.CustomAsmLinks) - dicCustomAsmFuncs.AddOrUpdate(link.CustomAsmAreaConfig.RamAddress | unchecked((int)0x80000000), link); - - foreach (BehaviorscriptCommand cmd in Script) { - switch (cmd.CommandType) + var asmPointer = link.CustomAsmAreaConfig.RamAddress | unchecked((int)0x80000000); + var cmdStartLoop = Script.FirstOfType(BehaviorscriptCommandTypes.x08_LoopStart); + var cmdStartLoopIndex = Script.IndexOf(cmdStartLoop); + int iInsert; + + if (link.Loop) { - case BehaviorscriptCommandTypes.x2A_SetCollision: - CollisionPointer = BehaviorscriptCommandFunctions.X2A.GetCollisionPointer(cmd); - EnableCollisionPointer = true; - break; - case BehaviorscriptCommandTypes.x0C_CallFunction: - var ptr = BehaviorscriptCommandFunctions.X0C.GetAsmPointer(cmd); - if (dicCustomAsmFuncs.ContainsKey(ptr)) - knownCustomAsmCommands.AddOrUpdate(dicCustomAsmFuncs[ptr].CustomAsmAreaConfig, cmd); - break; - } - } - } - - public void TakeoverSettingsToScript() - { - // Update collision pointer - AddUpdateRemoveCmd( - BehaviorscriptCommandTypes.x2A_SetCollision, - EnableCollisionPointer, - () => BehaviorscriptCommandFactory.Build_x2A(CollisionPointer), - (cmd) => BehaviorscriptCommandFunctions.X2A.SetCollisionPointer(cmd, CollisionPointer)); - - // Insert Custom Asm Links - { - foreach (var link in Config.CustomAsmLinks) - { - var asmPointer = link.CustomAsmAreaConfig.RamAddress | unchecked((int)0x80000000); - var cmdStartLoop = Script.FirstOfType(BehaviorscriptCommandTypes.x08_LoopStart); - var cmdStartLoopIndex = Script.IndexOf(cmdStartLoop); - int iInsert; - - if (link.Loop) - { - if (cmdStartLoop is not null) - iInsert = cmdStartLoopIndex + 1; - else - iInsert = -1; - } + if (cmdStartLoop is not null) + iInsert = cmdStartLoopIndex + 1; else - { - if (cmdStartLoop is not null) - iInsert = cmdStartLoopIndex; - else - iInsert = (int)Script.Count - 2; - } - - if (knownCustomAsmCommands.ContainsKey(link.CustomAsmAreaConfig)) - { - var cmd = knownCustomAsmCommands[link.CustomAsmAreaConfig]; - var cmdIndex = Script.IndexOf(cmd); - BehaviorscriptCommandFunctions.X0C.SetAsmPointer(cmd, asmPointer); - - if (cmdIndex != -1) - { - var reinsert = false; - - if (link.Loop && cmdIndex < cmdStartLoopIndex) - { - reinsert = true; - iInsert -= 1; - } - else if (!link.Loop && cmdIndex > cmdStartLoopIndex) - reinsert = true; - - if (reinsert) - { - Script.Remove(cmd); - Script.Insert(iInsert, cmd); - } - } - } - else if (iInsert != -1) - { - var cmd = BehaviorscriptCommandFactory.Build_x0C(asmPointer); - Script.Insert(iInsert, cmd); - knownCustomAsmCommands.Add(link.CustomAsmAreaConfig, cmd); - } + iInsert = -1; } - - foreach (var kvp in knownCustomAsmCommands.ToArray()) - { - if (!Config.CustomAsmLinks.Where(n => n.CustomAsmAreaConfig == kvp.Key).Any()) - { - knownCustomAsmCommands.Remove(kvp.Key); - Script.RemoveIfContains(kvp.Value); - kvp.Value.Close(); - } - } - } - } - - private void AddUpdateRemoveCmd(BehaviorscriptCommandTypes cmdType, bool conditionAddUpdate, Func createCmd, Action updateCmd) - { - var cmd = Script.FirstOfType(cmdType); - if (cmd is not null) - { - if (conditionAddUpdate) - updateCmd(cmd); else { - Script.Remove(cmd); - cmd.Close(); + if (cmdStartLoop is not null) + iInsert = cmdStartLoopIndex; + else + iInsert = (int)Script.Count - 2; + } + + if (knownCustomAsmCommands.ContainsKey(link.CustomAsmAreaConfig)) + { + var cmd = knownCustomAsmCommands[link.CustomAsmAreaConfig]; + var cmdIndex = Script.IndexOf(cmd); + BehaviorscriptCommandFunctions.X0C.SetAsmPointer(cmd, asmPointer); + + if (cmdIndex != -1) + { + var reinsert = false; + + if (link.Loop && cmdIndex < cmdStartLoopIndex) + { + reinsert = true; + iInsert -= 1; + } + else if (!link.Loop && cmdIndex > cmdStartLoopIndex) + reinsert = true; + + if (reinsert) + { + Script.Remove(cmd); + Script.Insert(iInsert, cmd); + } + } + } + else if (iInsert != -1) + { + var cmd = BehaviorscriptCommandFactory.Build_x0C(asmPointer); + Script.Insert(iInsert, cmd); + knownCustomAsmCommands.Add(link.CustomAsmAreaConfig, cmd); } } - else if (conditionAddUpdate) + + foreach (var kvp in knownCustomAsmCommands.ToArray()) { - cmd = createCmd(); - Script.Insert(1, cmd); + if (!Config.CustomAsmLinks.Where(n => n.CustomAsmAreaConfig == kvp.Key).Any()) + { + knownCustomAsmCommands.Remove(kvp.Key); + Script.RemoveIfContains(kvp.Value); + kvp.Value.Close(); + } } } - - public void CopyPropertiesTo(Behavior dest) - { - // Copy Script - TakeoverSettingsToScript(); - dest.Script.Close(); - dest.Script.AddRange(Script); - dest.ParseScript(); - - // Copy Configs - dest.Config.Name = Config.Name; - Config.ParamsInfo.CloneTo(dest.Config.ParamsInfo); - } - } + + private void AddUpdateRemoveCmd(BehaviorscriptCommandTypes cmdType, bool conditionAddUpdate, Func createCmd, Action updateCmd) + { + var cmd = Script.FirstOfType(cmdType); + if (cmd is not null) + { + if (conditionAddUpdate) + updateCmd(cmd); + else + { + Script.Remove(cmd); + cmd.Close(); + } + } + else if (conditionAddUpdate) + { + cmd = createCmd(); + Script.Insert(1, cmd); + } + } + + public void CopyPropertiesTo(Behavior dest) + { + // Copy Script + TakeoverSettingsToScript(); + dest.Script.Close(); + dest.Script.AddRange(Script); + dest.ParseScript(); + + // Copy Configs + dest.Config.Name = Config.Name; + Config.ParamsInfo.CloneTo(dest.Config.ParamsInfo); + } + } diff --git a/SM64Lib/Behaviors/BehaviorBank.cs b/SM64Lib/Behaviors/BehaviorBank.cs index c0ab209..1abfb8d 100644 --- a/SM64Lib/Behaviors/BehaviorBank.cs +++ b/SM64Lib/Behaviors/BehaviorBank.cs @@ -1,220 +1,216 @@ using Newtonsoft.Json; using SM64Lib.Data; using SM64Lib.SegmentedBanking; -using System; using System.Collections.Generic; using System.IO; using System.Linq; -using System.Text; -using System.Threading.Tasks; using Z.Collections.Extensions; -namespace SM64Lib.Behaviors +namespace SM64Lib.Behaviors; + +public class BehaviorBank { - public class BehaviorBank + public BehaviorBankConfig Config { get; private set; } + public List Behaviors { get; } = new List(); + + [JsonIgnore] + public long Length { - public BehaviorBankConfig Config { get; private set; } - public List Behaviors { get; } = new List(); + get => Behaviors.Sum(n => n.Length); + } - [JsonIgnore] - public long Length + public BehaviorBank(BehaviorBankConfig config) + { + Config = config; + } + + public void ReadBank(SegmentedBank seg, int offset) + { + ReadBank(seg, offset, false); + } + + public void ReadVanillaBank(SegmentedBank seg) + { + ReadBank(seg, 0, true); + } + + private void ReadBank(SegmentedBank seg, int offset, bool isVanilla) + { + var data = new BinaryStreamData(seg.Data); + data.Position = offset; + ReadBank(data, isVanilla, seg.Length, (sbyte)seg.BankID); + } + + public void ReadBank(BinaryData data) + { + ReadBank(data, false, -1, -1); + } + + private void ReadBank(BinaryData data, bool isVanilla, int endAddress, sbyte bankID) + { + // Clear current list + Behaviors.Clear(); + + if (isVanilla) { - get => Behaviors.Sum(n => n.Length); + while (data.Position <= endAddress - 0x10) + { + var conf = new BehaviorConfig(); + Config.BehaviorConfigs.Add(conf); + readBehavior(conf); + } + } + else + { + foreach (var config in Config.BehaviorConfigs.OrderBy(n => n.BankAddress)) + readBehavior(config); } - public BehaviorBank(BehaviorBankConfig config) + void readBehavior(BehaviorConfig config) { - Config = config; - } - - public void ReadBank(SegmentedBank seg, int offset) - { - ReadBank(seg, offset, false); - } - - public void ReadVanillaBank(SegmentedBank seg) - { - ReadBank(seg, 0, true); - } - - private void ReadBank(SegmentedBank seg, int offset, bool isVanilla) - { - var data = new BinaryStreamData(seg.Data); - data.Position = offset; - ReadBank(data, isVanilla, seg.Length, (sbyte)seg.BankID); - } - - public void ReadBank(BinaryData data) - { - ReadBank(data, false, -1, -1); - } - - private void ReadBank(BinaryData data, bool isVanilla, int endAddress, sbyte bankID) - { - // Clear current list - Behaviors.Clear(); + int bankOffset; + Behavior behav = new Behavior(config); if (isVanilla) { - while (data.Position <= endAddress - 0x10) - { - var conf = new BehaviorConfig(); - Config.BehaviorConfigs.Add(conf); - readBehavior(conf); - } + bankOffset = (int)data.Position; + config.BankAddress = (bankID << 24) | bankOffset; + behav.Config.IsVanilla = true; } else { - foreach (var config in Config.BehaviorConfigs.OrderBy(n => n.BankAddress)) - readBehavior(config); + bankOffset = config.BankAddress & 0xffffff; + if (!behav.Config.IsVanilla && !config.ID.HasID) config.ID.Generate(); } - void readBehavior(BehaviorConfig config) + var lastBehav = Behaviors.LastOrDefault(); + + if (behav.Read(data, bankOffset)) { - int bankOffset; - Behavior behav = new Behavior(config); + if (isVanilla && lastBehav is not null && lastBehav.Config.IsVanilla && lastBehav.Config.FixedLength != -1) + lastBehav.Config.FixedLength = bankOffset - (lastBehav.Config.BankAddress & 0xffffff); - if (isVanilla) + Behaviors.Add(behav); + } + } + } + + public SegmentedBank WriteToSeg(byte bankID, int offset, RomManager rommgr) + { + var segStream = new MemoryStream(); + var seg = new SegmentedBank(bankID, segStream); + int lastPos = WriteToSeg(seg, offset, rommgr); + seg.Length = General.HexRoundUp1(lastPos); + return seg; + } + + public int WriteToSeg(SegmentedBank seg, int offset, RomManager rommgr) + { + var addressUpdates = new Dictionary(); + var segStartAddress = seg.BankAddress | offset; + var data = new BinaryStreamData(seg.Data); + data.Position = offset; + + if (Behaviors.Any()) + { + // Save Behaviors to ROM + foreach (var behav in Behaviors) + { + var address = (int)data.Position; + var newBankAddress = (int)data.Position - offset + segStartAddress; + if (newBankAddress != behav.Config.BankAddress) { - bankOffset = (int)data.Position; - config.BankAddress = (bankID << 24) | bankOffset; - behav.Config.IsVanilla = true; - } - else - { - bankOffset = config.BankAddress & 0xffffff; - if (!behav.Config.IsVanilla && !config.ID.HasID) config.ID.Generate(); - } - - var lastBehav = Behaviors.LastOrDefault(); - - if (behav.Read(data, bankOffset)) - { - if (isVanilla && lastBehav is not null && lastBehav.Config.IsVanilla && lastBehav.Config.FixedLength != -1) - lastBehav.Config.FixedLength = bankOffset - (lastBehav.Config.BankAddress & 0xffffff); - - Behaviors.Add(behav); + if (behav.Config.BankAddress != -1) + addressUpdates.AddOrUpdate(behav.Config.BankAddress, newBankAddress); + behav.Config.BankAddress = newBankAddress; } + behav.Write(data, (int)data.Position); } } - public SegmentedBank WriteToSeg(byte bankID, int offset, RomManager rommgr) - { - var segStream = new MemoryStream(); - var seg = new SegmentedBank(bankID, segStream); - int lastPos = WriteToSeg(seg, offset, rommgr); - seg.Length = General.HexRoundUp1(lastPos); - return seg; - } + // Delete unused configs / Add new configs + Config.BehaviorConfigs.Clear(); + Config.BehaviorConfigs.AddRange(Behaviors.Select(n => n.Config)); - public int WriteToSeg(SegmentedBank seg, int offset, RomManager rommgr) - { - var addressUpdates = new Dictionary(); - var segStartAddress = seg.BankAddress | offset; - var data = new BinaryStreamData(seg.Data); - data.Position = offset; + // Update addresses + UpdateBehaviorAddresses(rommgr, addressUpdates); - if (Behaviors.Any()) + return (int)data.Position; + } + + private void UpdateBehaviorAddresses(RomManager rommgr, Dictionary addressUpdates) + { + if (Behaviors.Any() && rommgr is not null) + { + foreach (var lvl in rommgr.Levels) { - // Save Behaviors to ROM - foreach (var behav in Behaviors) + foreach (var area in lvl.Areas) { - var address = (int)data.Position; - var newBankAddress = (int)data.Position - offset + segStartAddress; - if (newBankAddress != behav.Config.BankAddress) + foreach (var obj in area.Objects) { - if (behav.Config.BankAddress != -1) - addressUpdates.AddOrUpdate(behav.Config.BankAddress, newBankAddress); - behav.Config.BankAddress = newBankAddress; - } - behav.Write(data, (int)data.Position); - } - } - - // Delete unused configs / Add new configs - Config.BehaviorConfigs.Clear(); - Config.BehaviorConfigs.AddRange(Behaviors.Select(n => n.Config)); - - // Update addresses - UpdateBehaviorAddresses(rommgr, addressUpdates); - - return (int)data.Position; - } - - private void UpdateBehaviorAddresses(RomManager rommgr, Dictionary addressUpdates) - { - if (Behaviors.Any() && rommgr is not null) - { - foreach (var lvl in rommgr.Levels) - { - foreach (var area in lvl.Areas) - { - foreach (var obj in area.Objects) + var behavAddr = Levels.Script.Commands.clNormal3DObject.GetSegBehaviorAddr(obj); + foreach (var kvp in addressUpdates) { - var behavAddr = Levels.Script.Commands.clNormal3DObject.GetSegBehaviorAddr(obj); - foreach (var kvp in addressUpdates) - { - if (behavAddr == kvp.Key) - Levels.Script.Commands.clNormal3DObject.SetSegBehaviorAddr(obj, (uint)kvp.Value); - } + if (behavAddr == kvp.Key) + Levels.Script.Commands.clNormal3DObject.SetSegBehaviorAddr(obj, (uint)kvp.Value); } } } } } + } - public void WriteBehaviorAddresss(RomManager rommgr) + public void WriteBehaviorAddresss(RomManager rommgr) + { + var data = rommgr.GetBinaryRom(FileAccess.ReadWrite); + WriteBehaviorAddresss(data); + data.Close(); + } + + public void WriteBehaviorAddresss(BinaryData data) + { + if (Behaviors.Any()) { - var data = rommgr.GetBinaryRom(FileAccess.ReadWrite); - WriteBehaviorAddresss(data); - data.Close(); - } - - public void WriteBehaviorAddresss(BinaryData data) - { - if (Behaviors.Any()) - { - foreach (var behav in Behaviors) - { - foreach (var dest in behav.BehaviorAddressDestinations) - { - data.Position = dest; - data.Write(behav.Config.BankAddress); - } - } - } - } - - public Behavior GetBehaviorByID(string id) - { - return Behaviors.FirstOrDefault(n => n.Config.ID == id); - } - - public Behavior GetBehaviorByBankAddress(int bankAddress) - { - return Behaviors.FirstOrDefault(n => n.Config.BankAddress == bankAddress); - } - - public void CalculateBehaviorBankAddresses(int bankStartAddress, RomManager rommgr) - { - var length = 0; - var addressUpdates = new Dictionary(); - foreach (var behav in Behaviors) { - if (behav.Config.IsVanilla) - length += behav.Config.FixedLength; - else + foreach (var dest in behav.BehaviorAddressDestinations) { - var newBankAddress = bankStartAddress + length; - addressUpdates.AddIfNotContainsKey(behav.Config.BankAddress, newBankAddress); - behav.Config.BankAddress = newBankAddress; - length += (int)behav.Script.Length; + data.Position = dest; + data.Write(behav.Config.BankAddress); } } - - // Update addresses - UpdateBehaviorAddresses(rommgr, addressUpdates); } } + + public Behavior GetBehaviorByID(string id) + { + return Behaviors.FirstOrDefault(n => n.Config.ID == id); + } + + public Behavior GetBehaviorByBankAddress(int bankAddress) + { + return Behaviors.FirstOrDefault(n => n.Config.BankAddress == bankAddress); + } + + public void CalculateBehaviorBankAddresses(int bankStartAddress, RomManager rommgr) + { + var length = 0; + var addressUpdates = new Dictionary(); + + foreach (var behav in Behaviors) + { + if (behav.Config.IsVanilla) + length += behav.Config.FixedLength; + else + { + var newBankAddress = bankStartAddress + length; + addressUpdates.AddIfNotContainsKey(behav.Config.BankAddress, newBankAddress); + behav.Config.BankAddress = newBankAddress; + length += (int)behav.Script.Length; + } + } + + // Update addresses + UpdateBehaviorAddresses(rommgr, addressUpdates); + } } diff --git a/SM64Lib/Behaviors/BehaviorBankConfig.cs b/SM64Lib/Behaviors/BehaviorBankConfig.cs index 48fef6f..218f4b9 100644 --- a/SM64Lib/Behaviors/BehaviorBankConfig.cs +++ b/SM64Lib/Behaviors/BehaviorBankConfig.cs @@ -1,36 +1,31 @@ using Newtonsoft.Json; -using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace SM64Lib.Behaviors +namespace SM64Lib.Behaviors; + +public class BehaviorBankConfig { - public class BehaviorBankConfig + public bool IsVanilla { get; set; } = true; + public List BehaviorConfigs { get; } = new List(); + + [JsonProperty(nameof(Enabled))] + private bool enabled = false; + public void Enable() => enabled = true; + internal void Disable() { - public bool IsVanilla { get; set; } = true; - public List BehaviorConfigs { get; } = new List(); + enabled = false; + IsVanilla = true; + BehaviorConfigs.Clear(); + } - [JsonProperty(nameof(Enabled))] - private bool enabled = false; - public void Enable() => enabled = true; - internal void Disable() + [JsonIgnore] + public bool Enabled + { + get { - enabled = false; - IsVanilla = true; - BehaviorConfigs.Clear(); - } - - [JsonIgnore] - public bool Enabled - { - get - { - if (!enabled && !IsVanilla) - enabled = true; - return enabled; - } + if (!enabled && !IsVanilla) + enabled = true; + return enabled; } } } diff --git a/SM64Lib/Behaviors/BehaviorConfig.cs b/SM64Lib/Behaviors/BehaviorConfig.cs index 53e2cc2..944d915 100644 --- a/SM64Lib/Behaviors/BehaviorConfig.cs +++ b/SM64Lib/Behaviors/BehaviorConfig.cs @@ -1,39 +1,34 @@ using Newtonsoft.Json; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Pilz.Cryptography; using Pilz.Json.Converters; +using System.Collections.Generic; -namespace SM64Lib.Behaviors +namespace SM64Lib.Behaviors; + +public class BehaviorConfig { - public class BehaviorConfig + internal delegate void RequestModelEventHandler(BehaviorConfig config, RequestBehaviorEventArgs request); + internal static event RequestModelEventHandler RequestBehavior; + + [JsonConverter(typeof(UniquieIDStringJsonConverter))] + public UniquieID ID { get; set; } = new(); + public int BankAddress { get; set; } = -1; + public bool IsVanilla { get; set; } = false; + public string Name { get; set; } = string.Empty; + public int FixedLength { get; set; } = -1; + public int ExpectedLength { get; set; } = -1; + public List CustomAsmLinks { get; } = new List(); + public BehaviorParamsInfo ParamsInfo { get; } = new BehaviorParamsInfo(); + + public Behavior FindBehavior() { - internal delegate void RequestModelEventHandler(BehaviorConfig config, RequestBehaviorEventArgs request); - internal static event RequestModelEventHandler RequestBehavior; + var args = new RequestBehaviorEventArgs(); + RequestBehavior?.Invoke(this, args); + return args.Behavior; + } - [JsonConverter(typeof(UniquieIDStringJsonConverter))] - public UniquieID ID { get; set; } = new(); - public int BankAddress { get; set; } = -1; - public bool IsVanilla { get; set; } = false; - public string Name { get; set; } = string.Empty; - public int FixedLength { get; set; } = -1; - public int ExpectedLength { get; set; } = -1; - public List CustomAsmLinks { get; } = new List(); - public BehaviorParamsInfo ParamsInfo { get; } = new BehaviorParamsInfo(); - - public Behavior FindBehavior() - { - var args = new RequestBehaviorEventArgs(); - RequestBehavior?.Invoke(this, args); - return args.Behavior; - } - - internal class RequestBehaviorEventArgs - { - public Behavior Behavior { get; set; } - } + internal class RequestBehaviorEventArgs + { + public Behavior Behavior { get; set; } } } diff --git a/SM64Lib/Behaviors/BehaviorCreationTypes.cs b/SM64Lib/Behaviors/BehaviorCreationTypes.cs index a626d09..cce8350 100644 --- a/SM64Lib/Behaviors/BehaviorCreationTypes.cs +++ b/SM64Lib/Behaviors/BehaviorCreationTypes.cs @@ -1,13 +1,6 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +namespace SM64Lib.Behaviors; -namespace SM64Lib.Behaviors +public enum BehaviorCreationTypes { - public enum BehaviorCreationTypes - { - SolidObject - } + SolidObject } diff --git a/SM64Lib/Behaviors/BehaviorParamInfo.cs b/SM64Lib/Behaviors/BehaviorParamInfo.cs index 8bd9927..30fb7eb 100644 --- a/SM64Lib/Behaviors/BehaviorParamInfo.cs +++ b/SM64Lib/Behaviors/BehaviorParamInfo.cs @@ -1,15 +1,10 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Collections.Generic; -namespace SM64Lib.Behaviors +namespace SM64Lib.Behaviors; + +public class BehaviorParamInfo { - public class BehaviorParamInfo - { - public string Name { get; set; } = string.Empty; - public string Description { get; set; } = string.Empty; - public List Values { get; } = new List(); - } + public string Name { get; set; } = string.Empty; + public string Description { get; set; } = string.Empty; + public List Values { get; } = new List(); } diff --git a/SM64Lib/Behaviors/BehaviorParamValue.cs b/SM64Lib/Behaviors/BehaviorParamValue.cs index e76106b..0adad8b 100644 --- a/SM64Lib/Behaviors/BehaviorParamValue.cs +++ b/SM64Lib/Behaviors/BehaviorParamValue.cs @@ -1,14 +1,7 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +namespace SM64Lib.Behaviors; -namespace SM64Lib.Behaviors +public class BehaviorParamValue { - public class BehaviorParamValue - { - public string Name { get; set; } = ""; - public byte Value { get; set; } = 0; - } + public string Name { get; set; } = ""; + public byte Value { get; set; } = 0; } diff --git a/SM64Lib/Behaviors/BehaviorParamsInfo.cs b/SM64Lib/Behaviors/BehaviorParamsInfo.cs index fe682f3..83e361e 100644 --- a/SM64Lib/Behaviors/BehaviorParamsInfo.cs +++ b/SM64Lib/Behaviors/BehaviorParamsInfo.cs @@ -1,16 +1,9 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +namespace SM64Lib.Behaviors; -namespace SM64Lib.Behaviors +public class BehaviorParamsInfo { - public class BehaviorParamsInfo - { - public BehaviorParamInfo Param1 { get; } = new(); - public BehaviorParamInfo Param2 { get; } = new(); - public BehaviorParamInfo Param3 { get; } = new(); - public BehaviorParamInfo Param4 { get; } = new(); - } + public BehaviorParamInfo Param1 { get; } = new(); + public BehaviorParamInfo Param2 { get; } = new(); + public BehaviorParamInfo Param3 { get; } = new(); + public BehaviorParamInfo Param4 { get; } = new(); } diff --git a/SM64Lib/Behaviors/CustomAsmAreaLinkOptions.cs b/SM64Lib/Behaviors/CustomAsmAreaLinkOptions.cs index 1720f61..e34fe51 100644 --- a/SM64Lib/Behaviors/CustomAsmAreaLinkOptions.cs +++ b/SM64Lib/Behaviors/CustomAsmAreaLinkOptions.cs @@ -1,25 +1,19 @@ using Newtonsoft.Json; using SM64Lib.ASM; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace SM64Lib.Behaviors +namespace SM64Lib.Behaviors; + +public class CustomAsmAreaLinkOptions { - public class CustomAsmAreaLinkOptions + // Temporary fix - Remove custom property code and make it auto property in v1.? + private CustomAsmAreaConfig customAsmAreaConfig; + public CustomAsmAreaConfig CustomAsmAreaConfig { - // Temporary fix - Remove custom property code and make it auto property in v1.? - private CustomAsmAreaConfig customAsmAreaConfig; - public CustomAsmAreaConfig CustomAsmAreaConfig - { - get => customAsmAreaConfig ?? CustomAsm?.Config; - set => customAsmAreaConfig = value; - } - // Temporary fix for old files - Remove property in v1.? - [JsonProperty] - public CustomAsmArea CustomAsm { get; private set; } - public bool Loop { get; set; } + get => customAsmAreaConfig ?? CustomAsm?.Config; + set => customAsmAreaConfig = value; } + // Temporary fix for old files - Remove property in v1.? + [JsonProperty] + public CustomAsmArea CustomAsm { get; private set; } + public bool Loop { get; set; } } diff --git a/SM64Lib/Behaviors/Script/Behaviorscript.cs b/SM64Lib/Behaviors/Script/Behaviorscript.cs index 57216a4..d016b68 100644 --- a/SM64Lib/Behaviors/Script/Behaviorscript.cs +++ b/SM64Lib/Behaviors/Script/Behaviorscript.cs @@ -1,106 +1,104 @@ using SM64Lib.Data; using System; -using System.Collections; using System.Collections.Generic; using System.Linq; -namespace SM64Lib.Behaviors.Script +namespace SM64Lib.Behaviors.Script; + +public class Behaviorscript : BehaviorscriptCommandCollection { - public class Behaviorscript : BehaviorscriptCommandCollection + public bool Read(BinaryData data, int address, bool detectJumpsAsEnd = false, bool ignoreEndCmds = false, int expectedLength = -1) { - public bool Read(BinaryData data, int address, bool detectJumpsAsEnd = false, bool ignoreEndCmds = false, int expectedLength = -1) + bool ende = false; + bool success = true; + var newCmds = new List(); + + data.Position = address; + + if (expectedLength < 0) + expectedLength = (int)data.Length; + else + expectedLength += address; + + while (!ende) { - bool ende = false; - bool success = true; - var newCmds = new List(); - - data.Position = address; - - if (expectedLength < 0) - expectedLength = (int)data.Length; - else - expectedLength += address; - - while (!ende) + if (expectedLength - data.Position >= 4) { - if (expectedLength - data.Position >= 4) + // Get command infos + var cmdType = (BehaviorscriptCommandTypes)data.ReadByte(); + int cmdLength = BehaviorscriptCommand.GetCommandLength(cmdType); + var unknownCmd = cmdLength == -1; + bool isEndCmd = ignoreEndCmds ? false : (unknownCmd || BehaviorscriptCommand.IsEndCommand(cmdType, detectJumpsAsEnd)); + + if (!unknownCmd) { - // Get command infos - var cmdType = (BehaviorscriptCommandTypes)data.ReadByte(); - int cmdLength = BehaviorscriptCommand.GetCommandLength(cmdType); - var unknownCmd = cmdLength == -1; - bool isEndCmd = ignoreEndCmds ? false : (unknownCmd || BehaviorscriptCommand.IsEndCommand(cmdType, detectJumpsAsEnd)); + // Reset position + data.Position -= 1; - if (!unknownCmd) + if (data.Position + cmdLength <= expectedLength) { - // Reset position - data.Position -= 1; + // Read full command + byte[] buf = new byte[cmdLength]; + data.Read(buf); - if (data.Position + cmdLength <= expectedLength) + // Create & add command + try { - // Read full command - byte[] buf = new byte[cmdLength]; - data.Read(buf); - - // Create & add command - try - { - newCmds.Add(new BehaviorscriptCommand(buf)); - } - catch (Exception) - { - success = false; - } - - ende = isEndCmd; + newCmds.Add(new BehaviorscriptCommand(buf)); } - else - ende = true; - } - else - { - data.Position += 3; + catch (Exception) + { + success = false; + } + ende = isEndCmd; } + else + ende = true; } else - ende = true; + { + data.Position += 3; + ende = isEndCmd; + } } - - // Add new Cmds - if (success && newCmds.Any()) - { - Close(); - AddRange(newCmds.ToArray()); - } - - return success; + else + ende = true; } - public int Write(BinaryData data, int address) + // Add new Cmds + if (success && newCmds.Any()) { - data.Position = address; - - foreach (BehaviorscriptCommand command in this) - { - var cmdLength = BehaviorscriptCommand.GetCommandLength(command.CommandType); - if (command.Length != cmdLength) - command.SetLength(cmdLength); - data.Write(command.ToArray()); - } - - return (int)data.Position - address; - } - - public int IndexOfType(BehaviorscriptCommandTypes cmdType) - { - return IndexOf(this.FirstOrDefault(n => n.CommandType == cmdType)); - } - - public BehaviorscriptCommand FirstOfType(BehaviorscriptCommandTypes cmdType) - { - return (BehaviorscriptCommand)this.FirstOrDefault(n => n.CommandType == cmdType); + Close(); + AddRange(newCmds.ToArray()); } + return success; } + + public int Write(BinaryData data, int address) + { + data.Position = address; + + foreach (BehaviorscriptCommand command in this) + { + var cmdLength = BehaviorscriptCommand.GetCommandLength(command.CommandType); + if (command.Length != cmdLength) + command.SetLength(cmdLength); + data.Write(command.ToArray()); + } + + return (int)data.Position - address; + } + + public int IndexOfType(BehaviorscriptCommandTypes cmdType) + { + return IndexOf(this.FirstOrDefault(n => n.CommandType == cmdType)); + } + + public BehaviorscriptCommand FirstOfType(BehaviorscriptCommandTypes cmdType) + { + return (BehaviorscriptCommand)this.FirstOrDefault(n => n.CommandType == cmdType); + } + } \ No newline at end of file diff --git a/SM64Lib/Behaviors/Script/BehaviorscriptCommand.cs b/SM64Lib/Behaviors/Script/BehaviorscriptCommand.cs index 9e42486..094dc61 100644 --- a/SM64Lib/Behaviors/Script/BehaviorscriptCommand.cs +++ b/SM64Lib/Behaviors/Script/BehaviorscriptCommand.cs @@ -2,119 +2,118 @@ using Newtonsoft.Json; using SM64Lib.Json; -namespace SM64Lib.Behaviors.Script +namespace SM64Lib.Behaviors.Script; + +[JsonConverter(typeof(BehaviorscriptCommandJsonConverter))] +public class BehaviorscriptCommand : SM64Lib.Script.BaseCommand { - [JsonConverter(typeof(BehaviorscriptCommandJsonConverter))] - public class BehaviorscriptCommand : SM64Lib.Script.BaseCommand + + public override BehaviorscriptCommandTypes CommandType { - - public override BehaviorscriptCommandTypes CommandType + get { - get - { - Position = 0; - return (BehaviorscriptCommandTypes)ReadByte(); - } - - set - { - Position = 0; - WriteByte((byte)value); - } + Position = 0; + return (BehaviorscriptCommandTypes)ReadByte(); } - public BehaviorscriptCommand() : base() + set { + Position = 0; + WriteByte((byte)value); } - - public BehaviorscriptCommand(byte[] cmd) : base(cmd) - { - } - - public BehaviorscriptCommand(string cmd) : base(cmd, true) - { - } - - public static int GetCommandLength(BehaviorscriptCommandTypes type) - { - switch (type) - { - case BehaviorscriptCommandTypes.x00_Start: return 4; - case BehaviorscriptCommandTypes.x01_StateLoop: return 4; - case BehaviorscriptCommandTypes.x02_JumpandLink: return 8; - case BehaviorscriptCommandTypes.x03_Return: return 4; - case BehaviorscriptCommandTypes.x04_Jump: return 8; - case BehaviorscriptCommandTypes.x05_LoopN: return 4; - case BehaviorscriptCommandTypes.x06_EndLoopN: return 4; - case BehaviorscriptCommandTypes.x07_InfiniteLoop: return 4; - case BehaviorscriptCommandTypes.x08_LoopStart: return 4; - case BehaviorscriptCommandTypes.x09_LoopEnd: return 4; - case BehaviorscriptCommandTypes.x0A_EndBehaviorscript: return 4; - case BehaviorscriptCommandTypes.x0B_EndBehaviorscript_Unused: return 4; - case BehaviorscriptCommandTypes.x0C_CallFunction: return 8; - case BehaviorscriptCommandTypes.x0D_OffsetbyFloat: return 4; - case BehaviorscriptCommandTypes.x0E_SettoFloat: return 4; - case BehaviorscriptCommandTypes.x0F_OffsetbyInteger: return 4; - case BehaviorscriptCommandTypes.x10_SettoInteger: return 4; - case BehaviorscriptCommandTypes.x11_BitSet: return 4; - case BehaviorscriptCommandTypes.x12_BitClear: return 4; - case BehaviorscriptCommandTypes.x13_AddRNG: return 8; - case BehaviorscriptCommandTypes.x14_ObjectType: return 8; - case BehaviorscriptCommandTypes.x15_FloatMultiply: return 8; - case BehaviorscriptCommandTypes.x16_FloatAdd: return 8; - case BehaviorscriptCommandTypes.x17_AddRNG2: return 8; - case BehaviorscriptCommandTypes.x18_NoOperation: return 4; - case BehaviorscriptCommandTypes.x19_NoOperation: return 4; - case BehaviorscriptCommandTypes.x1A_NoOperation: return 4; - case BehaviorscriptCommandTypes.x1B_ChangeModelID: return 4; - case BehaviorscriptCommandTypes.x1C_LoadChildObject: return 0xC; - case BehaviorscriptCommandTypes.x1D_Deactivate: return 4; - case BehaviorscriptCommandTypes.x1E_DroptoGround: return 4; - case BehaviorscriptCommandTypes.x1F_UsedforWaves: return 4; - case BehaviorscriptCommandTypes.x20_Unused: return 4; - case BehaviorscriptCommandTypes.x21_SetBillboarding: return 4; - case BehaviorscriptCommandTypes.x22_SetRenderInvisibleflag: return 4; - case BehaviorscriptCommandTypes.x23_Collisioncylindersize: return 8; - case BehaviorscriptCommandTypes.x24_Nothing: return 4; - case BehaviorscriptCommandTypes.x25_StateCycle: return 4; - case BehaviorscriptCommandTypes.x26_Loop: return 4; - case BehaviorscriptCommandTypes.x27_SetWord: return 8; - case BehaviorscriptCommandTypes.x28_Animates: return 4; - case BehaviorscriptCommandTypes.x29_LoadChildObject: return 0xC; - case BehaviorscriptCommandTypes.x2A_SetCollision: return 8; - case BehaviorscriptCommandTypes.x2B_SetCollisionSphere: return 0xC; - case BehaviorscriptCommandTypes.x2C_SpawnObject: return 0xC; - case BehaviorscriptCommandTypes.x2D_SetInitPosition: return 4; - case BehaviorscriptCommandTypes.x2E_SetHurtbox: return 8; - case BehaviorscriptCommandTypes.x2F_SetInteraction: return 8; - case BehaviorscriptCommandTypes.x30_SetGravity: return 0x14; - case BehaviorscriptCommandTypes.x31_SetInteractionSubType: return 8; - case BehaviorscriptCommandTypes.x32_ScaleObject: return 4; - case BehaviorscriptCommandTypes.x33_ChildObjectChange: return 8; - case BehaviorscriptCommandTypes.x34_TextureAnimateRate: return 4; - case BehaviorscriptCommandTypes.x35_ClearGraphFlag: return 4; - case BehaviorscriptCommandTypes.x36_SetValue: return 8; - case BehaviorscriptCommandTypes.x37_SpawnSomething: return 8; - default: return -1; //throw new System.Exception("Command type not found!"); - } - } - - public static bool IsEndCommand(BehaviorscriptCommandTypes type, bool detectJumpsAsEnd = true) - { - switch (type) - { - case BehaviorscriptCommandTypes.x02_JumpandLink: - case BehaviorscriptCommandTypes.x04_Jump: - return detectJumpsAsEnd; - case BehaviorscriptCommandTypes.x06_EndLoopN: - case BehaviorscriptCommandTypes.x0A_EndBehaviorscript: - case BehaviorscriptCommandTypes.x0B_EndBehaviorscript_Unused: - case BehaviorscriptCommandTypes.x09_LoopEnd: - return true; - default: - return false; - } - } - } + + public BehaviorscriptCommand() : base() + { + } + + public BehaviorscriptCommand(byte[] cmd) : base(cmd) + { + } + + public BehaviorscriptCommand(string cmd) : base(cmd, true) + { + } + + public static int GetCommandLength(BehaviorscriptCommandTypes type) + { + switch (type) + { + case BehaviorscriptCommandTypes.x00_Start: return 4; + case BehaviorscriptCommandTypes.x01_StateLoop: return 4; + case BehaviorscriptCommandTypes.x02_JumpandLink: return 8; + case BehaviorscriptCommandTypes.x03_Return: return 4; + case BehaviorscriptCommandTypes.x04_Jump: return 8; + case BehaviorscriptCommandTypes.x05_LoopN: return 4; + case BehaviorscriptCommandTypes.x06_EndLoopN: return 4; + case BehaviorscriptCommandTypes.x07_InfiniteLoop: return 4; + case BehaviorscriptCommandTypes.x08_LoopStart: return 4; + case BehaviorscriptCommandTypes.x09_LoopEnd: return 4; + case BehaviorscriptCommandTypes.x0A_EndBehaviorscript: return 4; + case BehaviorscriptCommandTypes.x0B_EndBehaviorscript_Unused: return 4; + case BehaviorscriptCommandTypes.x0C_CallFunction: return 8; + case BehaviorscriptCommandTypes.x0D_OffsetbyFloat: return 4; + case BehaviorscriptCommandTypes.x0E_SettoFloat: return 4; + case BehaviorscriptCommandTypes.x0F_OffsetbyInteger: return 4; + case BehaviorscriptCommandTypes.x10_SettoInteger: return 4; + case BehaviorscriptCommandTypes.x11_BitSet: return 4; + case BehaviorscriptCommandTypes.x12_BitClear: return 4; + case BehaviorscriptCommandTypes.x13_AddRNG: return 8; + case BehaviorscriptCommandTypes.x14_ObjectType: return 8; + case BehaviorscriptCommandTypes.x15_FloatMultiply: return 8; + case BehaviorscriptCommandTypes.x16_FloatAdd: return 8; + case BehaviorscriptCommandTypes.x17_AddRNG2: return 8; + case BehaviorscriptCommandTypes.x18_NoOperation: return 4; + case BehaviorscriptCommandTypes.x19_NoOperation: return 4; + case BehaviorscriptCommandTypes.x1A_NoOperation: return 4; + case BehaviorscriptCommandTypes.x1B_ChangeModelID: return 4; + case BehaviorscriptCommandTypes.x1C_LoadChildObject: return 0xC; + case BehaviorscriptCommandTypes.x1D_Deactivate: return 4; + case BehaviorscriptCommandTypes.x1E_DroptoGround: return 4; + case BehaviorscriptCommandTypes.x1F_UsedforWaves: return 4; + case BehaviorscriptCommandTypes.x20_Unused: return 4; + case BehaviorscriptCommandTypes.x21_SetBillboarding: return 4; + case BehaviorscriptCommandTypes.x22_SetRenderInvisibleflag: return 4; + case BehaviorscriptCommandTypes.x23_Collisioncylindersize: return 8; + case BehaviorscriptCommandTypes.x24_Nothing: return 4; + case BehaviorscriptCommandTypes.x25_StateCycle: return 4; + case BehaviorscriptCommandTypes.x26_Loop: return 4; + case BehaviorscriptCommandTypes.x27_SetWord: return 8; + case BehaviorscriptCommandTypes.x28_Animates: return 4; + case BehaviorscriptCommandTypes.x29_LoadChildObject: return 0xC; + case BehaviorscriptCommandTypes.x2A_SetCollision: return 8; + case BehaviorscriptCommandTypes.x2B_SetCollisionSphere: return 0xC; + case BehaviorscriptCommandTypes.x2C_SpawnObject: return 0xC; + case BehaviorscriptCommandTypes.x2D_SetInitPosition: return 4; + case BehaviorscriptCommandTypes.x2E_SetHurtbox: return 8; + case BehaviorscriptCommandTypes.x2F_SetInteraction: return 8; + case BehaviorscriptCommandTypes.x30_SetGravity: return 0x14; + case BehaviorscriptCommandTypes.x31_SetInteractionSubType: return 8; + case BehaviorscriptCommandTypes.x32_ScaleObject: return 4; + case BehaviorscriptCommandTypes.x33_ChildObjectChange: return 8; + case BehaviorscriptCommandTypes.x34_TextureAnimateRate: return 4; + case BehaviorscriptCommandTypes.x35_ClearGraphFlag: return 4; + case BehaviorscriptCommandTypes.x36_SetValue: return 8; + case BehaviorscriptCommandTypes.x37_SpawnSomething: return 8; + default: return -1; //throw new System.Exception("Command type not found!"); + } + } + + public static bool IsEndCommand(BehaviorscriptCommandTypes type, bool detectJumpsAsEnd = true) + { + switch (type) + { + case BehaviorscriptCommandTypes.x02_JumpandLink: + case BehaviorscriptCommandTypes.x04_Jump: + return detectJumpsAsEnd; + case BehaviorscriptCommandTypes.x06_EndLoopN: + case BehaviorscriptCommandTypes.x0A_EndBehaviorscript: + case BehaviorscriptCommandTypes.x0B_EndBehaviorscript_Unused: + case BehaviorscriptCommandTypes.x09_LoopEnd: + return true; + default: + return false; + } + } + } \ No newline at end of file diff --git a/SM64Lib/Behaviors/Script/BehaviorscriptCommandCollection.cs b/SM64Lib/Behaviors/Script/BehaviorscriptCommandCollection.cs index f2a4c84..9f80c27 100644 --- a/SM64Lib/Behaviors/Script/BehaviorscriptCommandCollection.cs +++ b/SM64Lib/Behaviors/Script/BehaviorscriptCommandCollection.cs @@ -1,7 +1,6 @@  -namespace SM64Lib.Behaviors.Script +namespace SM64Lib.Behaviors.Script; + +public class BehaviorscriptCommandCollection : SM64Lib.Script.BaseCommandCollection { - public class BehaviorscriptCommandCollection : SM64Lib.Script.BaseCommandCollection - { - } } \ No newline at end of file diff --git a/SM64Lib/Behaviors/Script/BehaviorscriptCommandFactory.cs b/SM64Lib/Behaviors/Script/BehaviorscriptCommandFactory.cs index 6383b0a..755a79b 100644 --- a/SM64Lib/Behaviors/Script/BehaviorscriptCommandFactory.cs +++ b/SM64Lib/Behaviors/Script/BehaviorscriptCommandFactory.cs @@ -1,32 +1,25 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +namespace SM64Lib.Behaviors.Script; -namespace SM64Lib.Behaviors.Script +public static class BehaviorscriptCommandFactory { - public static class BehaviorscriptCommandFactory + public static BehaviorscriptCommand Build_x2A(int collisionPointer = -1) { - public static BehaviorscriptCommand Build_x2A(int collisionPointer = -1) - { - var cmd = new BehaviorscriptCommand("2a 00 00 00 00 00 00 00"); - if (collisionPointer != -1) - BehaviorscriptCommandFunctions.X2A.SetCollisionPointer(cmd, collisionPointer); - return cmd; - } + var cmd = new BehaviorscriptCommand("2a 00 00 00 00 00 00 00"); + if (collisionPointer != -1) + BehaviorscriptCommandFunctions.X2A.SetCollisionPointer(cmd, collisionPointer); + return cmd; + } - public static BehaviorscriptCommand Build_x08() - { - return new BehaviorscriptCommand("08 00 00 00"); - } + public static BehaviorscriptCommand Build_x08() + { + return new BehaviorscriptCommand("08 00 00 00"); + } - public static BehaviorscriptCommand Build_x0C(int asmPointer = -1) - { - var cmd = new BehaviorscriptCommand("0C 00 00 00 00 00 00 00"); - if (asmPointer != -1) - BehaviorscriptCommandFunctions.X2A.SetCollisionPointer(cmd, asmPointer); - return cmd; - } + public static BehaviorscriptCommand Build_x0C(int asmPointer = -1) + { + var cmd = new BehaviorscriptCommand("0C 00 00 00 00 00 00 00"); + if (asmPointer != -1) + BehaviorscriptCommandFunctions.X2A.SetCollisionPointer(cmd, asmPointer); + return cmd; } } diff --git a/SM64Lib/Behaviors/Script/BehaviorscriptCommandFunctions.cs b/SM64Lib/Behaviors/Script/BehaviorscriptCommandFunctions.cs index 5265762..4130a40 100644 --- a/SM64Lib/Behaviors/Script/BehaviorscriptCommandFunctions.cs +++ b/SM64Lib/Behaviors/Script/BehaviorscriptCommandFunctions.cs @@ -1,39 +1,31 @@ -using SM64Lib.Data; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +namespace SM64Lib.Behaviors.Script; -namespace SM64Lib.Behaviors.Script +public class BehaviorscriptCommandFunctions { - public class BehaviorscriptCommandFunctions + public class X2A { - public class X2A + public static int GetCollisionPointer(BehaviorscriptCommand cmd) { - public static int GetCollisionPointer(BehaviorscriptCommand cmd) - { - cmd.Position = 4; - return cmd.ReadInt32(); - } - public static void SetCollisionPointer(BehaviorscriptCommand cmd, int pointer) - { - cmd.Position = 4; - cmd.Write(pointer); - } + cmd.Position = 4; + return cmd.ReadInt32(); } - public class X0C + public static void SetCollisionPointer(BehaviorscriptCommand cmd, int pointer) { - public static int GetAsmPointer(BehaviorscriptCommand cmd) - { - cmd.Position = 4; - return cmd.ReadInt32(); - } - public static void SetAsmPointer(BehaviorscriptCommand cmd, int pointer) - { - cmd.Position = 4; - cmd.Write(pointer); - } + cmd.Position = 4; + cmd.Write(pointer); + } + } + public class X0C + { + public static int GetAsmPointer(BehaviorscriptCommand cmd) + { + cmd.Position = 4; + return cmd.ReadInt32(); + } + public static void SetAsmPointer(BehaviorscriptCommand cmd, int pointer) + { + cmd.Position = 4; + cmd.Write(pointer); } } } diff --git a/SM64Lib/Behaviors/Script/BehaviorscriptCommandTypes.cs b/SM64Lib/Behaviors/Script/BehaviorscriptCommandTypes.cs index 9bcb9fd..ffd6f23 100644 --- a/SM64Lib/Behaviors/Script/BehaviorscriptCommandTypes.cs +++ b/SM64Lib/Behaviors/Script/BehaviorscriptCommandTypes.cs @@ -1,62 +1,61 @@ -namespace SM64Lib.Behaviors.Script +namespace SM64Lib.Behaviors.Script; + +public enum BehaviorscriptCommandTypes { - public enum BehaviorscriptCommandTypes - { - x00_Start, - x01_StateLoop, - x02_JumpandLink, - x03_Return, - x04_Jump, - x05_LoopN, - x06_EndLoopN, - x07_InfiniteLoop, - x08_LoopStart, - x09_LoopEnd, - x0A_EndBehaviorscript, - x0B_EndBehaviorscript_Unused, - x0C_CallFunction, - x0D_OffsetbyFloat, - x0E_SettoFloat, - x0F_OffsetbyInteger, - x10_SettoInteger, - x11_BitSet, - x12_BitClear, - x13_AddRNG, - x14_ObjectType, - x15_FloatMultiply, - x16_FloatAdd, - x17_AddRNG2, - x18_NoOperation, - x19_NoOperation, - x1A_NoOperation, - x1B_ChangeModelID, - x1C_LoadChildObject, - x1D_Deactivate, - x1E_DroptoGround, - x1F_UsedforWaves, - x20_Unused, - x21_SetBillboarding, - x22_SetRenderInvisibleflag, - x23_Collisioncylindersize, - x24_Nothing, - x25_StateCycle, - x26_Loop, - x27_SetWord, - x28_Animates, - x29_LoadChildObject, - x2A_SetCollision, - x2B_SetCollisionSphere, - x2C_SpawnObject, - x2D_SetInitPosition, - x2E_SetHurtbox, - x2F_SetInteraction, - x30_SetGravity, - x31_SetInteractionSubType, - x32_ScaleObject, - x33_ChildObjectChange, - x34_TextureAnimateRate, - x35_ClearGraphFlag, - x36_SetValue, - x37_SpawnSomething - } + x00_Start, + x01_StateLoop, + x02_JumpandLink, + x03_Return, + x04_Jump, + x05_LoopN, + x06_EndLoopN, + x07_InfiniteLoop, + x08_LoopStart, + x09_LoopEnd, + x0A_EndBehaviorscript, + x0B_EndBehaviorscript_Unused, + x0C_CallFunction, + x0D_OffsetbyFloat, + x0E_SettoFloat, + x0F_OffsetbyInteger, + x10_SettoInteger, + x11_BitSet, + x12_BitClear, + x13_AddRNG, + x14_ObjectType, + x15_FloatMultiply, + x16_FloatAdd, + x17_AddRNG2, + x18_NoOperation, + x19_NoOperation, + x1A_NoOperation, + x1B_ChangeModelID, + x1C_LoadChildObject, + x1D_Deactivate, + x1E_DroptoGround, + x1F_UsedforWaves, + x20_Unused, + x21_SetBillboarding, + x22_SetRenderInvisibleflag, + x23_Collisioncylindersize, + x24_Nothing, + x25_StateCycle, + x26_Loop, + x27_SetWord, + x28_Animates, + x29_LoadChildObject, + x2A_SetCollision, + x2B_SetCollisionSphere, + x2C_SpawnObject, + x2D_SetInitPosition, + x2E_SetHurtbox, + x2F_SetInteraction, + x30_SetGravity, + x31_SetInteractionSubType, + x32_ScaleObject, + x33_ChildObjectChange, + x34_TextureAnimateRate, + x35_ClearGraphFlag, + x36_SetValue, + x37_SpawnSomething } \ No newline at end of file diff --git a/SM64Lib/Configuration/CollisionBasicConfig.cs b/SM64Lib/Configuration/CollisionBasicConfig.cs index b21fded..38ee63c 100644 --- a/SM64Lib/Configuration/CollisionBasicConfig.cs +++ b/SM64Lib/Configuration/CollisionBasicConfig.cs @@ -1,22 +1,18 @@ using Newtonsoft.Json; -using System; using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace SM64Lib.Configuration +namespace SM64Lib.Configuration; + +public class CollisionBasicConfig { - public class CollisionBasicConfig - { - private List collisionTypesWithParams = new List() - { 4, 14, 44, 36, 37, 39, 45 }; + private List collisionTypesWithParams = new List() + { 4, 14, 44, 36, 37, 39, 45 }; - [JsonProperty("CollisionTypesWithParamsV2", ObjectCreationHandling = ObjectCreationHandling.Replace)] - public List CollisionTypesWithParams - { - get => collisionTypesWithParams; - private set => collisionTypesWithParams = value.Distinct().ToList(); - } + [JsonProperty("CollisionTypesWithParamsV2", ObjectCreationHandling = ObjectCreationHandling.Replace)] + public List CollisionTypesWithParams + { + get => collisionTypesWithParams; + private set => collisionTypesWithParams = value.Distinct().ToList(); } } diff --git a/SM64Lib/Configuration/CustomModelConfig.cs b/SM64Lib/Configuration/CustomModelConfig.cs index 38067a7..89b3842 100644 --- a/SM64Lib/Configuration/CustomModelConfig.cs +++ b/SM64Lib/Configuration/CustomModelConfig.cs @@ -1,31 +1,30 @@ using Newtonsoft.Json; -using SM64Lib.Objects.ModelBanks; -using System.Collections.Generic; using Pilz.Cryptography; using Pilz.Json.Converters; +using SM64Lib.Objects.ModelBanks; +using System.Collections.Generic; -namespace SM64Lib.Configuration +namespace SM64Lib.Configuration; + +public class CustomModelConfig { - public class CustomModelConfig + internal delegate void RequestModelEventHandler(CustomModelConfig config, RequestModelEventArgs request); + internal static event RequestModelEventHandler RequestModel; + + [JsonConverter(typeof(UniquieIDStringJsonConverter))] + public UniquieID ID { get; set; } = new(); + public string Name { get; set; } = string.Empty; + public List CollisionPointerDestinations { get; private set; } = new List(); + + public CustomModel FindModel() { - internal delegate void RequestModelEventHandler(CustomModelConfig config, RequestModelEventArgs request); - internal static event RequestModelEventHandler RequestModel; + var args = new RequestModelEventArgs(); + RequestModel?.Invoke(this, args); + return args.Model; + } - [JsonConverter(typeof(UniquieIDStringJsonConverter))] - public UniquieID ID { get; set; } = new(); - public string Name { get; set; } = string.Empty; - public List CollisionPointerDestinations { get; private set; } = new List(); - - public CustomModel FindModel() - { - var args = new RequestModelEventArgs(); - RequestModel?.Invoke(this, args); - return args.Model; - } - - internal class RequestModelEventArgs - { - public CustomModel Model { get; set; } - } + internal class RequestModelEventArgs + { + public CustomModel Model { get; set; } } } \ No newline at end of file diff --git a/SM64Lib/Configuration/LevelAreaConfig.cs b/SM64Lib/Configuration/LevelAreaConfig.cs index ac99b0f..338c0a6 100644 --- a/SM64Lib/Configuration/LevelAreaConfig.cs +++ b/SM64Lib/Configuration/LevelAreaConfig.cs @@ -1,10 +1,9 @@ using System.Collections.Generic; -namespace SM64Lib.Configuration +namespace SM64Lib.Configuration; + +public class LevelAreaConfig { - public class LevelAreaConfig - { - public string AreaName { get; set; } - public Dictionary ScrollingNames { get; set; } = new Dictionary(); - } + public string AreaName { get; set; } + public Dictionary ScrollingNames { get; set; } = new Dictionary(); } \ No newline at end of file diff --git a/SM64Lib/Configuration/LevelConfig.cs b/SM64Lib/Configuration/LevelConfig.cs index d761a2b..8743b88 100644 --- a/SM64Lib/Configuration/LevelConfig.cs +++ b/SM64Lib/Configuration/LevelConfig.cs @@ -1,26 +1,25 @@ using System.Collections.Generic; -namespace SM64Lib.Configuration -{ - public class LevelConfig - { - public string LevelName { get; set; } - public bool EnableLocalObjectBank { get; set; } = false; - public ObjectModelConfig LocalObjectBank { get; set; } = new ObjectModelConfig(); - public Dictionary AreaConfigs { get; private set; } = new Dictionary(); +namespace SM64Lib.Configuration; - public LevelAreaConfig GetLevelAreaConfig(byte areaID) +public class LevelConfig +{ + public string LevelName { get; set; } + public bool EnableLocalObjectBank { get; set; } = false; + public ObjectModelConfig LocalObjectBank { get; set; } = new ObjectModelConfig(); + public Dictionary AreaConfigs { get; private set; } = new Dictionary(); + + public LevelAreaConfig GetLevelAreaConfig(byte areaID) + { + if (AreaConfigs.ContainsKey(areaID)) { - if (AreaConfigs.ContainsKey(areaID)) - { - return AreaConfigs[areaID]; - } - else - { - var conf = new LevelAreaConfig(); - AreaConfigs.Add(areaID, conf); - return conf; - } + return AreaConfigs[areaID]; + } + else + { + var conf = new LevelAreaConfig(); + AreaConfigs.Add(areaID, conf); + return conf; } } } \ No newline at end of file diff --git a/SM64Lib/Configuration/MusicConfiguration.cs b/SM64Lib/Configuration/MusicConfiguration.cs index be25ccd..03ac8b2 100644 --- a/SM64Lib/Configuration/MusicConfiguration.cs +++ b/SM64Lib/Configuration/MusicConfiguration.cs @@ -1,9 +1,8 @@ using System.Collections.Generic; -namespace SM64Lib.Configuration +namespace SM64Lib.Configuration; + +public class MusicConfiguration { - public class MusicConfiguration - { - public List SqeuenceNames { get; private set; } = new List(); - } + public List SqeuenceNames { get; private set; } = new List(); } \ No newline at end of file diff --git a/SM64Lib/Configuration/NPCConfig.cs b/SM64Lib/Configuration/NPCConfig.cs index d14d6d6..863dfa9 100644 --- a/SM64Lib/Configuration/NPCConfig.cs +++ b/SM64Lib/Configuration/NPCConfig.cs @@ -1,13 +1,6 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +namespace SM64Lib.Configuration; -namespace SM64Lib.Configuration +public class NPCConfig { - public class NPCConfig - { - public bool Enabled3DCoins { get; set; } = false; - } + public bool Enabled3DCoins { get; set; } = false; } diff --git a/SM64Lib/Configuration/ObjectModelConfig.cs b/SM64Lib/Configuration/ObjectModelConfig.cs index d28d25e..f2bb2ad 100644 --- a/SM64Lib/Configuration/ObjectModelConfig.cs +++ b/SM64Lib/Configuration/ObjectModelConfig.cs @@ -1,20 +1,19 @@ using System.Collections.Generic; -namespace SM64Lib.Configuration +namespace SM64Lib.Configuration; + +public class ObjectModelConfig { - public class ObjectModelConfig + public Dictionary CustomObjectConfigs { get; private set; } = new Dictionary(); + + public CustomModelConfig GetCustomObjectConfig(int id) { - public Dictionary CustomObjectConfigs { get; private set; } = new Dictionary(); - - public CustomModelConfig GetCustomObjectConfig(int id) + CustomModelConfig conf = null; + if (!CustomObjectConfigs.TryGetValue(id, out conf)) { - CustomModelConfig conf = null; - if (!CustomObjectConfigs.TryGetValue(id, out conf)) - { - conf = new CustomModelConfig(); - } - - return conf; + conf = new CustomModelConfig(); } + + return conf; } } \ No newline at end of file diff --git a/SM64Lib/Configuration/PatchingConfig.cs b/SM64Lib/Configuration/PatchingConfig.cs index 78b30b4..82874a5 100644 --- a/SM64Lib/Configuration/PatchingConfig.cs +++ b/SM64Lib/Configuration/PatchingConfig.cs @@ -1,15 +1,9 @@ using Pilz.IO; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace SM64Lib.Configuration +namespace SM64Lib.Configuration; + +public class PatchingConfig { - public class PatchingConfig - { - public EmbeddedFilesContainer TweakBackups { get; } = new EmbeddedFilesContainer(); - public bool Patched2DCamera { get; set; } = false; - } + public EmbeddedFilesContainer TweakBackups { get; } = new EmbeddedFilesContainer(); + public bool Patched2DCamera { get; set; } = false; } diff --git a/SM64Lib/Configuration/RomConfig.cs b/SM64Lib/Configuration/RomConfig.cs index 6fc300e..c590005 100644 --- a/SM64Lib/Configuration/RomConfig.cs +++ b/SM64Lib/Configuration/RomConfig.cs @@ -1,78 +1,76 @@ -using System.Collections.Generic; +using global::Newtonsoft.Json.Linq; using global::System.IO; -using Microsoft.VisualBasic.CompilerServices; -using global::Newtonsoft.Json.Linq; using Newtonsoft.Json; +using SM64Lib.ASM; using SM64Lib.Behaviors; using SM64Lib.Objects.ObjectBanks; -using SM64Lib.ASM; using SM64Lib.Objects.ObjectBanks.Data; using System; +using System.Collections.Generic; -namespace SM64Lib.Configuration +namespace SM64Lib.Configuration; + +public class RomConfig { - public class RomConfig + // Levels + public Dictionary LevelConfigs { get; } = new Dictionary(); + + // Global Banks + [JsonProperty("GlobalObjectBankConfig")] + public ObjectModelConfig GlobalModelBank { get; } = new ObjectModelConfig(); + public CustomAsmBankConfig GlobalCustomAsmBank { get; } = new CustomAsmBankConfig(); + public BehaviorBankConfig GlobalBehaviorBank { get; } = new BehaviorBankConfig(); + public CustomObjectCollection GlobalObjectBank { get; } = new CustomObjectCollection(); + + // Music + public MusicConfiguration MusicConfig { get; } = new MusicConfiguration(); + + // Texts + public Text.Profiles.TextProfileInfo TextProfileInfo { get; set; } = null; + + // Patching + public PatchingConfig PatchingConfig { get; set; } = new PatchingConfig(); + + // Other + public ScrollTexConfig ScrollTexConfig { get; set; } = new ScrollTexConfig(); + public ObjectBankDataListCollection ObjectBankInfoData { get; } = new ObjectBankDataListCollection(); + public NPCConfig NPCConfig { get; } = new NPCConfig(); + public CollisionBasicConfig CollisionBaseConfig { get; } = new CollisionBasicConfig(); + + /// + /// Contains custom configuration that isn't used by SM64Lib. E.g. Extra Object Combos. + /// + public Dictionary CustomConfigs { get; } = new Dictionary(); + + // F e a t u r e s + + public LevelConfig GetLevelConfig(ushort levelID) { - // Levels - public Dictionary LevelConfigs { get; } = new Dictionary(); - - // Global Banks - [JsonProperty("GlobalObjectBankConfig")] - public ObjectModelConfig GlobalModelBank { get; } = new ObjectModelConfig(); - public CustomAsmBankConfig GlobalCustomAsmBank { get; } = new CustomAsmBankConfig(); - public BehaviorBankConfig GlobalBehaviorBank { get; } = new BehaviorBankConfig(); - public CustomObjectCollection GlobalObjectBank { get; } = new CustomObjectCollection(); - - // Music - public MusicConfiguration MusicConfig { get; } = new MusicConfiguration(); - - // Texts - public Text.Profiles.TextProfileInfo TextProfileInfo { get; set; } = null; - - // Patching - public PatchingConfig PatchingConfig { get; set; } = new PatchingConfig(); - - // Other - public ScrollTexConfig ScrollTexConfig { get; set; } = new ScrollTexConfig(); - public ObjectBankDataListCollection ObjectBankInfoData { get; } = new ObjectBankDataListCollection(); - public NPCConfig NPCConfig { get; } = new NPCConfig(); - public CollisionBasicConfig CollisionBaseConfig { get; } = new CollisionBasicConfig(); - - /// - /// Contains custom configuration that isn't used by SM64Lib. E.g. Extra Object Combos. - /// - public Dictionary CustomConfigs { get; } = new Dictionary(); - - // F e a t u r e s - - public LevelConfig GetLevelConfig(ushort levelID) + if (LevelConfigs.ContainsKey(Convert.ToByte(levelID))) { - if (LevelConfigs.ContainsKey(Convert.ToByte(levelID))) - { - return LevelConfigs[Convert.ToByte(levelID)]; - } - else - { - var conf = new LevelConfig(); - LevelConfigs.Add(Convert.ToByte(levelID), conf); - return conf; - } + return LevelConfigs[Convert.ToByte(levelID)]; } - - // L o a d / S a v e - - public static RomConfig Load(string filePath) + else { - var serializer = JsonSerializer.CreateDefault(); - serializer.PreserveReferencesHandling = PreserveReferencesHandling.All; - return JObject.Parse(File.ReadAllText(filePath)).ToObject(serializer); - } - - public void Save(string filePath) - { - var serializer = JsonSerializer.CreateDefault(); - serializer.PreserveReferencesHandling = PreserveReferencesHandling.All; - File.WriteAllText(filePath, JObject.FromObject(this, serializer).ToString()); + var conf = new LevelConfig(); + LevelConfigs.Add(Convert.ToByte(levelID), conf); + return conf; } } + + // L o a d / S a v e + + public static RomConfig Load(string filePath) + { + var serializer = JsonSerializer.CreateDefault(); + serializer.PreserveReferencesHandling = PreserveReferencesHandling.All; + return JObject.Parse(File.ReadAllText(filePath)).ToObject(serializer); + } + + public void Save(string filePath) + { + var serializer = JsonSerializer.CreateDefault(); + serializer.PreserveReferencesHandling = PreserveReferencesHandling.All; + File.WriteAllText(filePath, JObject.FromObject(this, serializer).ToString()); + } } \ No newline at end of file diff --git a/SM64Lib/Configuration/ScrollTexConfig.cs b/SM64Lib/Configuration/ScrollTexConfig.cs index 898d160..e800c69 100644 --- a/SM64Lib/Configuration/ScrollTexConfig.cs +++ b/SM64Lib/Configuration/ScrollTexConfig.cs @@ -1,14 +1,7 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +namespace SM64Lib.Configuration; -namespace SM64Lib.Configuration +public class ScrollTexConfig { - public class ScrollTexConfig - { - public bool UseCustomBehavior { get; set; } = false; - public int CustomBehaviorAddress { get; set; } = -1; - } + public bool UseCustomBehavior { get; set; } = false; + public int CustomBehaviorAddress { get; set; } = -1; } diff --git a/SM64Lib/Data/BinaryArrayData.cs b/SM64Lib/Data/BinaryArrayData.cs index 8cfd2d8..1032e31 100644 --- a/SM64Lib/Data/BinaryArrayData.cs +++ b/SM64Lib/Data/BinaryArrayData.cs @@ -1,28 +1,27 @@ using global::System.IO; -namespace SM64Lib.Data +namespace SM64Lib.Data; + +public class BinaryArrayData : BinaryStreamData { - public class BinaryArrayData : BinaryStreamData + public FileAccess RomAccess { get; private set; } = FileAccess.Read; + + public BinaryArrayData(byte[] buffer) : base(new MemoryStream(buffer)) { - public FileAccess RomAccess { get; private set; } = FileAccess.Read; - - public BinaryArrayData(byte[] buffer) : base(new MemoryStream(buffer)) - { - } - - // Inherits BinaryData - - // Private ReadOnly myBaseStream As Stream - - // Public ReadOnly Property RomAccess As FileAccess = FileAccess.Read - - // Public Sub New(buffer As Byte()) - // myBaseStream = New MemoryStream(buffer) - // End Sub - - // Protected Overrides Function GetBaseStream() As Stream - // Return myBaseStream - // End Function - } + + // Inherits BinaryData + + // Private ReadOnly myBaseStream As Stream + + // Public ReadOnly Property RomAccess As FileAccess = FileAccess.Read + + // Public Sub New(buffer As Byte()) + // myBaseStream = New MemoryStream(buffer) + // End Sub + + // Protected Overrides Function GetBaseStream() As Stream + // Return myBaseStream + // End Function + } \ No newline at end of file diff --git a/SM64Lib/Data/BinaryData.cs b/SM64Lib/Data/BinaryData.cs index 6fd8ff1..6523a04 100644 --- a/SM64Lib/Data/BinaryData.cs +++ b/SM64Lib/Data/BinaryData.cs @@ -2,279 +2,278 @@ using SM64Lib.Data.System; using System; -namespace SM64Lib.Data +namespace SM64Lib.Data; + +public abstract class BinaryData : IDisposable { - public abstract class BinaryData : IDisposable + public delegate void AnyBinaryDataEventHandler(BinaryData data); + + public static event AnyBinaryDataEventHandler AnyBinaryDataOpened; + public static event AnyBinaryDataEventHandler AnyBinaryDataClosing; + public static event AnyBinaryDataEventHandler AnyBinaryDataClosed; + public static event AnyBinaryDataDisposedEventHandler AnyBinaryDataDisposed; + + public delegate void AnyBinaryDataDisposedEventHandler(); + + private Stream _BaseStream = null; + private BinaryWriter _writer = null; + private BinaryReader _reader = null; + + public RomManager RomManager { get; private set; } + + protected abstract Stream GetBaseStream(); + + protected BinaryWriter Writer { - public delegate void AnyBinaryDataEventHandler(BinaryData data); - - public static event AnyBinaryDataEventHandler AnyBinaryDataOpened; - public static event AnyBinaryDataEventHandler AnyBinaryDataClosing; - public static event AnyBinaryDataEventHandler AnyBinaryDataClosed; - public static event AnyBinaryDataDisposedEventHandler AnyBinaryDataDisposed; - - public delegate void AnyBinaryDataDisposedEventHandler(); - - private Stream _BaseStream = null; - private BinaryWriter _writer = null; - private BinaryReader _reader = null; - - public RomManager RomManager { get; private set; } - - protected abstract Stream GetBaseStream(); - - protected BinaryWriter Writer + get { - get + if (_writer is null) { - if (_writer is null) - { - _writer = new BinaryWriter(BaseStream); - } - - return _writer; - } - } - - protected BinaryReader Reader - { - get - { - if (_reader is null) - { - _reader = new BinaryReader(BaseStream); - } - - return _reader; - } - } - - public long Position - { - get - { - return BaseStream.Position; + _writer = new BinaryWriter(BaseStream); } - set - { - BaseStream.Position = value; - } - } - - public long Length - { - get - { - return BaseStream.Length; - } - } - - public Stream BaseStream - { - get - { - if (_BaseStream is null) - { - _BaseStream = GetBaseStream(); - RaiseAnyBinaryDataOpened(this); - } - - return _BaseStream; - } - } - - ~BinaryData() - { - AnyBinaryDataDisposed?.Invoke(); - } - - public void RoundUpPosition() - { - Position = General.HexRoundUp1(Position); - } - - public void RoundUpPosition(int add) - { - Position = General.HexRoundUp1(Position + add); - } - - protected void SetRomManager(RomManager rommgr) - { - RomManager = rommgr; - } - - public void Write(sbyte value) - { - Writer.Write(value); - } - - public void Write(byte value) - { - Writer.Write(value); - } - - public void WriteByte(byte value) - { - Write(value); - } - - public void Write(short value) - { - Writer.Write(SwapInts.SwapInt16(value)); - } - - public void Write(ushort value) - { - Writer.Write(SwapInts.SwapUInt16(value)); - } - - public void Write(int value) - { - Writer.Write(SwapInts.SwapInt32(value)); - } - - public void Write(uint value) - { - Writer.Write(SwapInts.SwapUInt32(value)); - } - - public void Write(long value) - { - Writer.Write(SwapInts.SwapInt64(value)); - } - - public void Write(ulong value) - { - Writer.Write(SwapInts.SwapUInt64(value)); - } - - public void Write(float value, bool isHalf = false) - { - if (isHalf) - Writer.Write(SwapInts.SwapHalf(value)); - else - Writer.Write(SwapInts.SwapFloat32(value)); - } - - public void Write(string value) - { - Writer.Write(value); - } - - public void Write(byte[] buffer) - { - Write(buffer, 0, buffer.Length); - } - - public void Write(byte[] buffer, int index, int count) - { - Writer.Write(buffer, index, count); - } - - public byte ReadByte() - { - return Reader.ReadByte(); - } - - public sbyte ReadSByte() - { - return Reader.ReadSByte(); - } - - public short ReadInt16() - { - return SwapInts.SwapInt16(Reader.ReadInt16()); - } - - public ushort ReadUInt16() - { - return SwapInts.SwapUInt16(Reader.ReadUInt16()); - } - - public int ReadInt32() - { - return SwapInts.SwapInt32(Reader.ReadInt32()); - } - - public uint ReadUInt32() - { - return SwapInts.SwapUInt32(Reader.ReadUInt32()); - } - - public long ReadInt64() - { - return SwapInts.SwapInt64(Reader.ReadInt64()); - } - - public ulong ReadUInt64() - { - return SwapInts.SwapUInt64(Reader.ReadUInt64()); - } - - public float ReadSingle() - { - return SwapInts.SwapFloat32(Reader.ReadSingle()); - } - - public string ReadString() - { - return Reader.ReadString(); - } - - public void Read(byte[] buffer) - { - Read(buffer, 0, buffer.Length); - } - - public void Read(byte[] buffer, int index, int count) - { - Reader.Read(buffer, index, count); - } - - public byte[] Read(int count) - { - var buf = new byte[count]; - Read(buf, 0, count); - return buf; - } - - public void Close() - { - AnyBinaryDataClosing?.Invoke(this); - BaseStream.Close(); - AnyBinaryDataClosed?.Invoke(this); - } - - public bool CanRead - { - get - { - return BaseStream.CanRead; - } - } - - public bool CanWrite - { - get - { - return BaseStream.CanWrite; - } - } - - public void SetLength(long length) - { - BaseStream.SetLength(length); - } - - internal static void RaiseAnyBinaryDataOpened(BinaryData data) - { - AnyBinaryDataOpened?.Invoke(data); - } - - public void Dispose() - { - Close(); + return _writer; } } + + protected BinaryReader Reader + { + get + { + if (_reader is null) + { + _reader = new BinaryReader(BaseStream); + } + + return _reader; + } + } + + public long Position + { + get + { + return BaseStream.Position; + } + + set + { + BaseStream.Position = value; + } + } + + public long Length + { + get + { + return BaseStream.Length; + } + } + + public Stream BaseStream + { + get + { + if (_BaseStream is null) + { + _BaseStream = GetBaseStream(); + RaiseAnyBinaryDataOpened(this); + } + + return _BaseStream; + } + } + + ~BinaryData() + { + AnyBinaryDataDisposed?.Invoke(); + } + + public void RoundUpPosition() + { + Position = General.HexRoundUp1(Position); + } + + public void RoundUpPosition(int add) + { + Position = General.HexRoundUp1(Position + add); + } + + protected void SetRomManager(RomManager rommgr) + { + RomManager = rommgr; + } + + public void Write(sbyte value) + { + Writer.Write(value); + } + + public void Write(byte value) + { + Writer.Write(value); + } + + public void WriteByte(byte value) + { + Write(value); + } + + public void Write(short value) + { + Writer.Write(SwapInts.SwapInt16(value)); + } + + public void Write(ushort value) + { + Writer.Write(SwapInts.SwapUInt16(value)); + } + + public void Write(int value) + { + Writer.Write(SwapInts.SwapInt32(value)); + } + + public void Write(uint value) + { + Writer.Write(SwapInts.SwapUInt32(value)); + } + + public void Write(long value) + { + Writer.Write(SwapInts.SwapInt64(value)); + } + + public void Write(ulong value) + { + Writer.Write(SwapInts.SwapUInt64(value)); + } + + public void Write(float value, bool isHalf = false) + { + if (isHalf) + Writer.Write(SwapInts.SwapHalf(value)); + else + Writer.Write(SwapInts.SwapFloat32(value)); + } + + public void Write(string value) + { + Writer.Write(value); + } + + public void Write(byte[] buffer) + { + Write(buffer, 0, buffer.Length); + } + + public void Write(byte[] buffer, int index, int count) + { + Writer.Write(buffer, index, count); + } + + public byte ReadByte() + { + return Reader.ReadByte(); + } + + public sbyte ReadSByte() + { + return Reader.ReadSByte(); + } + + public short ReadInt16() + { + return SwapInts.SwapInt16(Reader.ReadInt16()); + } + + public ushort ReadUInt16() + { + return SwapInts.SwapUInt16(Reader.ReadUInt16()); + } + + public int ReadInt32() + { + return SwapInts.SwapInt32(Reader.ReadInt32()); + } + + public uint ReadUInt32() + { + return SwapInts.SwapUInt32(Reader.ReadUInt32()); + } + + public long ReadInt64() + { + return SwapInts.SwapInt64(Reader.ReadInt64()); + } + + public ulong ReadUInt64() + { + return SwapInts.SwapUInt64(Reader.ReadUInt64()); + } + + public float ReadSingle() + { + return SwapInts.SwapFloat32(Reader.ReadSingle()); + } + + public string ReadString() + { + return Reader.ReadString(); + } + + public void Read(byte[] buffer) + { + Read(buffer, 0, buffer.Length); + } + + public void Read(byte[] buffer, int index, int count) + { + Reader.Read(buffer, index, count); + } + + public byte[] Read(int count) + { + var buf = new byte[count]; + Read(buf, 0, count); + return buf; + } + + public void Close() + { + AnyBinaryDataClosing?.Invoke(this); + BaseStream.Close(); + AnyBinaryDataClosed?.Invoke(this); + } + + public bool CanRead + { + get + { + return BaseStream.CanRead; + } + } + + public bool CanWrite + { + get + { + return BaseStream.CanWrite; + } + } + + public void SetLength(long length) + { + BaseStream.SetLength(length); + } + + internal static void RaiseAnyBinaryDataOpened(BinaryData data) + { + AnyBinaryDataOpened?.Invoke(data); + } + + public void Dispose() + { + Close(); + } } \ No newline at end of file diff --git a/SM64Lib/Data/BinaryFile.cs b/SM64Lib/Data/BinaryFile.cs index 3e2c31a..019376a 100644 --- a/SM64Lib/Data/BinaryFile.cs +++ b/SM64Lib/Data/BinaryFile.cs @@ -1,11 +1,10 @@ using global::System.IO; -namespace SM64Lib.Data +namespace SM64Lib.Data; + +public class BinaryFile : BinaryStreamData { - public class BinaryFile : BinaryStreamData + public BinaryFile(string filePath, FileMode fileMode, FileAccess fileAccess) : base(new FileStream(filePath, fileMode, fileAccess)) { - public BinaryFile(string filePath, FileMode fileMode, FileAccess fileAccess) : base(new FileStream(filePath, fileMode, fileAccess)) - { - } } } \ No newline at end of file diff --git a/SM64Lib/Data/BinaryRom.cs b/SM64Lib/Data/BinaryRom.cs index 9784dec..43810de 100644 --- a/SM64Lib/Data/BinaryRom.cs +++ b/SM64Lib/Data/BinaryRom.cs @@ -1,26 +1,25 @@ using global::System.IO; -namespace SM64Lib.Data +namespace SM64Lib.Data; + +public class BinaryRom : BinaryFile { - public class BinaryRom : BinaryFile + public BinaryRom(RomManager rommgr, FileAccess romAccess) : base(rommgr.RomFile, FileMode.Open, romAccess) { - public BinaryRom(RomManager rommgr, FileAccess romAccess) : base(rommgr.RomFile, FileMode.Open, romAccess) - { - SetRomManager(rommgr); - } - - // Inherits BinaryData - - // Public ReadOnly Property RomAccess As FileAccess = FileAccess.Read - - // Public Sub New(rommgr As RomManager, romAccess As FileAccess) - // SetRomManager(rommgr) - // Me.RomAccess = romAccess - // End Sub - - // Protected Overrides Function GetBaseStream() As Stream - // Return RomManager.GetStream(RomAccess) - // End Function - + SetRomManager(rommgr); } + + // Inherits BinaryData + + // Public ReadOnly Property RomAccess As FileAccess = FileAccess.Read + + // Public Sub New(rommgr As RomManager, romAccess As FileAccess) + // SetRomManager(rommgr) + // Me.RomAccess = romAccess + // End Sub + + // Protected Overrides Function GetBaseStream() As Stream + // Return RomManager.GetStream(RomAccess) + // End Function + } \ No newline at end of file diff --git a/SM64Lib/Data/BinarySegBank.cs b/SM64Lib/Data/BinarySegBank.cs index 8ca6d83..c93275d 100644 --- a/SM64Lib/Data/BinarySegBank.cs +++ b/SM64Lib/Data/BinarySegBank.cs @@ -1,33 +1,32 @@ -using global::System.IO; -using global::SM64Lib.SegmentedBanking; +using global::SM64Lib.SegmentedBanking; +using global::System.IO; -namespace SM64Lib.Data +namespace SM64Lib.Data; + +public class BinarySegBank : BinaryData { - public class BinarySegBank : BinaryData + public SegmentedBank SegBank { get; private set; } + + public BinarySegBank(SegmentedBank segBank, RomManager rommgr) { - public SegmentedBank SegBank { get; private set; } + SegBank = segBank; + SetRomManager(rommgr); + } - public BinarySegBank(SegmentedBank segBank, RomManager rommgr) + public BinarySegBank(SegmentedBank segBank) + { + SegBank = segBank; + } + + protected override Stream GetBaseStream() + { + if (RomManager is not null) { - SegBank = segBank; - SetRomManager(rommgr); + var s = RomManager.GetBinaryRom(FileAccess.Read); + SegBank.ReadDataIfNull(s.BaseStream); + s.Close(); } - public BinarySegBank(SegmentedBank segBank) - { - SegBank = segBank; - } - - protected override Stream GetBaseStream() - { - if (RomManager is not null) - { - var s = RomManager.GetBinaryRom(FileAccess.Read); - SegBank.ReadDataIfNull(s.BaseStream); - s.Close(); - } - - return SegBank.Data; - } + return SegBank.Data; } } \ No newline at end of file diff --git a/SM64Lib/Data/BinaryStreamData.cs b/SM64Lib/Data/BinaryStreamData.cs index dd9c568..4c38b10 100644 --- a/SM64Lib/Data/BinaryStreamData.cs +++ b/SM64Lib/Data/BinaryStreamData.cs @@ -1,20 +1,19 @@ using global::System.IO; -namespace SM64Lib.Data +namespace SM64Lib.Data; + +public class BinaryStreamData : BinaryData { - public class BinaryStreamData : BinaryData + protected readonly Stream myBaseStream; + + public BinaryStreamData(Stream stream) { - protected readonly Stream myBaseStream; + myBaseStream = stream; + //RaiseAnyBinaryDataOpened(this); + } - public BinaryStreamData(Stream stream) - { - myBaseStream = stream; - //RaiseAnyBinaryDataOpened(this); - } - - protected override Stream GetBaseStream() - { - return myBaseStream; - } + protected override Stream GetBaseStream() + { + return myBaseStream; } } \ No newline at end of file diff --git a/SM64Lib/Data/System/Bits.cs b/SM64Lib/Data/System/Bits.cs index 33b9727..5e67349 100644 --- a/SM64Lib/Data/System/Bits.cs +++ b/SM64Lib/Data/System/Bits.cs @@ -1,98 +1,96 @@ using System; using System.Collections; using System.Linq; -using Microsoft.VisualBasic.CompilerServices; -namespace SM64Lib.Data.System +namespace SM64Lib.Data.System; + +public class Bits { - public class Bits + public static byte[] ByteToBitArray(byte b) { - public static byte[] ByteToBitArray(byte b) + var bitarray = new BitArray(new[] { b }); + var temp = new byte[bitarray.Length]; + for (int i = 0, loopTo = bitarray.Length - 1; i <= loopTo; i++) + temp[i] = Convert.ToByte(bitarray[i]); + int tindex = 0; + var temp2 = new byte[(temp.Count())]; + for (int i = temp.Length - 1; i >= 0; i += -1) { - var bitarray = new BitArray(new[] { b }); - var temp = new byte[bitarray.Length]; - for (int i = 0, loopTo = bitarray.Length - 1; i <= loopTo; i++) - temp[i] = Convert.ToByte(bitarray[i]); - int tindex = 0; - var temp2 = new byte[(temp.Count())]; - for (int i = temp.Length - 1; i >= 0; i += -1) - { - temp2[tindex] = temp[i]; - tindex += 1; - } - - return temp2; + temp2[tindex] = temp[i]; + tindex += 1; } - public static bool[] ByteToBoolArray(byte b) - { - var bitarray = new BitArray(new[] { b }); - var temp = new bool[bitarray.Length]; - for (int i = 0, loopTo = bitarray.Length - 1; i <= loopTo; i++) - temp[i] = Convert.ToBoolean(bitarray[i]); - int tindex = 0; - var temp2 = new bool[(temp.Count())]; - for (int i = temp.Length - 1; i >= 0; i += -1) - { - temp2[tindex] = temp[i]; - tindex += 1; - } + return temp2; + } - return temp2; + public static bool[] ByteToBoolArray(byte b) + { + var bitarray = new BitArray(new[] { b }); + var temp = new bool[bitarray.Length]; + for (int i = 0, loopTo = bitarray.Length - 1; i <= loopTo; i++) + temp[i] = Convert.ToBoolean(bitarray[i]); + int tindex = 0; + var temp2 = new bool[(temp.Count())]; + for (int i = temp.Length - 1; i >= 0; i += -1) + { + temp2[tindex] = temp[i]; + tindex += 1; } - public static byte ArrayToByte(byte[] ba) + return temp2; + } + + public static byte ArrayToByte(byte[] ba) + { + // ODER: BitArray.ToByte() + + byte endval = 0; + int index = ba.Count() - 1; + foreach (var bit in ba) { - // ODER: BitArray.ToByte() - - byte endval = 0; - int index = ba.Count() - 1; - foreach (var bit in ba) - { - endval += (byte)(bit * Math.Pow(2, index)); - index -= 1; - } - - return endval; + endval += (byte)(bit * Math.Pow(2, index)); + index -= 1; } - public static byte ArrayToByte(bool[] ba) + return endval; + } + + public static byte ArrayToByte(bool[] ba) + { + // ODER: BitArray.ToByte() + + byte endval = 0; + int index = ba.Count() - 1; + foreach (var bit in ba) { - // ODER: BitArray.ToByte() - - byte endval = 0; - int index = ba.Count() - 1; - foreach (var bit in ba) - { - endval += (byte)((bit ? 1 : 0) * Math.Pow(2, index)); - index -= 1; - } - - return endval; + endval += (byte)((bit ? 1 : 0) * Math.Pow(2, index)); + index -= 1; } - public static byte SetInByte(byte b, int index, byte value) - { - var temp = ByteToBitArray(b); - temp[index] = value; - return ArrayToByte(temp); - } + return endval; + } - public static byte SetInByte(byte b, int index, bool value) - { - var temp = ByteToBoolArray(b); - temp[index] = value; - return ArrayToByte(temp); - } + public static byte SetInByte(byte b, int index, byte value) + { + var temp = ByteToBitArray(b); + temp[index] = value; + return ArrayToByte(temp); + } - public static byte GetBitOfByte(byte b, int index) - { - return ByteToBitArray(b)[index]; - } + public static byte SetInByte(byte b, int index, bool value) + { + var temp = ByteToBoolArray(b); + temp[index] = value; + return ArrayToByte(temp); + } - public static bool GetBoolOfByte(byte b, int index) - { - return ByteToBoolArray(b)[index]; - } + public static byte GetBitOfByte(byte b, int index) + { + return ByteToBitArray(b)[index]; + } + + public static bool GetBoolOfByte(byte b, int index) + { + return ByteToBoolArray(b)[index]; } } \ No newline at end of file diff --git a/SM64Lib/Data/System/SwapInts.cs b/SM64Lib/Data/System/SwapInts.cs index ac0d32a..6fb0e11 100644 --- a/SM64Lib/Data/System/SwapInts.cs +++ b/SM64Lib/Data/System/SwapInts.cs @@ -1,62 +1,61 @@ using System; -namespace SM64Lib.Data.System +namespace SM64Lib.Data.System; + +internal static class SwapInts { - internal static class SwapInts + public static short SwapInt16(short value) { - public static short SwapInt16(short value) - { - var bytes = BitConverter.GetBytes(value); - Array.Reverse(bytes); - return BitConverter.ToInt16(bytes, 0); - } + var bytes = BitConverter.GetBytes(value); + Array.Reverse(bytes); + return BitConverter.ToInt16(bytes, 0); + } - public static ushort SwapUInt16(ushort value) - { - var bytes = BitConverter.GetBytes(value); - Array.Reverse(bytes); - return BitConverter.ToUInt16(bytes, 0); - } + public static ushort SwapUInt16(ushort value) + { + var bytes = BitConverter.GetBytes(value); + Array.Reverse(bytes); + return BitConverter.ToUInt16(bytes, 0); + } - public static int SwapInt32(int value) - { - var bytes = BitConverter.GetBytes(value); - Array.Reverse(bytes); - return BitConverter.ToInt32(bytes, 0); - } + public static int SwapInt32(int value) + { + var bytes = BitConverter.GetBytes(value); + Array.Reverse(bytes); + return BitConverter.ToInt32(bytes, 0); + } - public static uint SwapUInt32(uint value) - { - var bytes = BitConverter.GetBytes(value); - Array.Reverse(bytes); - return BitConverter.ToUInt32(bytes, 0); - } + public static uint SwapUInt32(uint value) + { + var bytes = BitConverter.GetBytes(value); + Array.Reverse(bytes); + return BitConverter.ToUInt32(bytes, 0); + } - public static long SwapInt64(long value) - { - var bytes = BitConverter.GetBytes(value); - Array.Reverse(bytes); - return BitConverter.ToInt64(bytes, 0); - } + public static long SwapInt64(long value) + { + var bytes = BitConverter.GetBytes(value); + Array.Reverse(bytes); + return BitConverter.ToInt64(bytes, 0); + } - public static ulong SwapUInt64(ulong value) - { - var bytes = BitConverter.GetBytes(value); - Array.Reverse(bytes); - return BitConverter.ToUInt64(bytes, 0); - } + public static ulong SwapUInt64(ulong value) + { + var bytes = BitConverter.GetBytes(value); + Array.Reverse(bytes); + return BitConverter.ToUInt64(bytes, 0); + } - public static short SwapHalf(float value) - { - byte[] bytes = BitConverter.GetBytes(value); - return (short)(BitConverter.ToInt32(bytes, 0) >> 16); - } + public static short SwapHalf(float value) + { + byte[] bytes = BitConverter.GetBytes(value); + return (short)(BitConverter.ToInt32(bytes, 0) >> 16); + } - public static float SwapFloat32(float value) - { - byte[] bytes = BitConverter.GetBytes(value); - Array.Reverse(bytes); - return BitConverter.ToSingle(bytes, 0); - } + public static float SwapFloat32(float value) + { + byte[] bytes = BitConverter.GetBytes(value); + Array.Reverse(bytes); + return BitConverter.ToSingle(bytes, 0); } } \ No newline at end of file diff --git a/SM64Lib/Datatypecastes.cs b/SM64Lib/Datatypecastes.cs index fc61fc5..1c30b73 100644 --- a/SM64Lib/Datatypecastes.cs +++ b/SM64Lib/Datatypecastes.cs @@ -1,39 +1,38 @@ using global::System.Runtime.InteropServices; -namespace SM64Lib +namespace SM64Lib; + +static class Datatypecastes { - static class Datatypecastes + public static short LongToInt16(long value) { - public static short LongToInt16(long value) - { - var cast = default(CasterLongInt16); - cast.LongValue = value; - return cast.Int16Value; - } + var cast = default(CasterLongInt16); + cast.LongValue = value; + return cast.Int16Value; + } - [StructLayout(LayoutKind.Explicit)] - private struct CasterLongInt16 - { - [FieldOffset(0)] - public long LongValue; - [FieldOffset(0)] - public short Int16Value; - } + [StructLayout(LayoutKind.Explicit)] + private struct CasterLongInt16 + { + [FieldOffset(0)] + public long LongValue; + [FieldOffset(0)] + public short Int16Value; + } - public static byte LongToByte(long value) - { - var cast = default(CasterLongByte); - cast.LongValue = value; - return cast.ByteValue; - } + public static byte LongToByte(long value) + { + var cast = default(CasterLongByte); + cast.LongValue = value; + return cast.ByteValue; + } - [StructLayout(LayoutKind.Explicit)] - private struct CasterLongByte - { - [FieldOffset(0)] - public long LongValue; - [FieldOffset(0)] - public byte ByteValue; - } + [StructLayout(LayoutKind.Explicit)] + private struct CasterLongByte + { + [FieldOffset(0)] + public long LongValue; + [FieldOffset(0)] + public byte ByteValue; } } \ No newline at end of file diff --git a/SM64Lib/EventArguments/GetTextProfileInfoEventArgs.cs b/SM64Lib/EventArguments/GetTextProfileInfoEventArgs.cs index 0766d46..4824e9e 100644 --- a/SM64Lib/EventArguments/GetTextProfileInfoEventArgs.cs +++ b/SM64Lib/EventArguments/GetTextProfileInfoEventArgs.cs @@ -1,13 +1,8 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace SM64Lib.EventArguments +namespace SM64Lib.EventArguments; + +public class GetTextProfileInfoEventArgs : EventArgs { - public class GetTextProfileInfoEventArgs : EventArgs - { - public Text.Profiles.TextProfileInfo ProfileInfo { get; set; } - } + public Text.Profiles.TextProfileInfo ProfileInfo { get; set; } } diff --git a/SM64Lib/EventArguments/PrepairingRomEventArgs.cs b/SM64Lib/EventArguments/PrepairingRomEventArgs.cs index 6f519a6..9418690 100644 --- a/SM64Lib/EventArguments/PrepairingRomEventArgs.cs +++ b/SM64Lib/EventArguments/PrepairingRomEventArgs.cs @@ -1,13 +1,9 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace SM64Lib.EventArguments +namespace SM64Lib.EventArguments; + +public class PrepairingRomEventArgs : EventArgs { - public class PrepairingRomEventArgs : EventArgs - { - public IEnumerable ScriptInfos { get; set; } - } + public IEnumerable ScriptInfos { get; set; } } diff --git a/SM64Lib/EventArguments/RomVersionEventArgs.cs b/SM64Lib/EventArguments/RomVersionEventArgs.cs index 121f8f8..1cd20f7 100644 --- a/SM64Lib/EventArguments/RomVersionEventArgs.cs +++ b/SM64Lib/EventArguments/RomVersionEventArgs.cs @@ -1,14 +1,13 @@ using System; -namespace SM64Lib.EventArguments -{ - public class RomVersionEventArgs : EventArgs - { - public RomVersion RomVersion { get; set; } +namespace SM64Lib.EventArguments; - internal RomVersionEventArgs(RomVersion romVersion) - { - RomVersion = romVersion; - } +public class RomVersionEventArgs : EventArgs +{ + public RomVersion RomVersion { get; set; } + + internal RomVersionEventArgs(RomVersion romVersion) + { + RomVersion = romVersion; } } \ No newline at end of file diff --git a/SM64Lib/Exceptions/InvalidMD5HashException.cs b/SM64Lib/Exceptions/InvalidMD5HashException.cs index 2788c67..a8f1f39 100644 --- a/SM64Lib/Exceptions/InvalidMD5HashException.cs +++ b/SM64Lib/Exceptions/InvalidMD5HashException.cs @@ -1,8 +1,7 @@ using System; -namespace SM64Lib.Exceptions +namespace SM64Lib.Exceptions; + +public class InvalidMD5HashException : Exception { - public class InvalidMD5HashException : Exception - { - } } \ No newline at end of file diff --git a/SM64Lib/Exceptions/RomCompatiblityException.cs b/SM64Lib/Exceptions/RomCompatiblityException.cs index b41d182..5b8e92f 100644 --- a/SM64Lib/Exceptions/RomCompatiblityException.cs +++ b/SM64Lib/Exceptions/RomCompatiblityException.cs @@ -1,11 +1,10 @@ using System; -namespace SM64Lib.Exceptions +namespace SM64Lib.Exceptions; + +public class RomCompatiblityException : Exception { - public class RomCompatiblityException : Exception + public RomCompatiblityException(string msg) : base(msg) { - public RomCompatiblityException(string msg) : base(msg) - { - } } } \ No newline at end of file diff --git a/SM64Lib/ExtensionMethods.cs b/SM64Lib/ExtensionMethods.cs index a2fa437..e5aa686 100644 --- a/SM64Lib/ExtensionMethods.cs +++ b/SM64Lib/ExtensionMethods.cs @@ -2,32 +2,31 @@ using Newtonsoft.Json; using Newtonsoft.Json.Linq; -namespace SM64Lib.Extensions +namespace SM64Lib.Extensions; + +public static class Int16Extensions { - public static class Int16Extensions + public static bool IsInRange(this short value, short min, short max) { - public static bool IsInRange(this short value, short min, short max) - { - return value >= min && value <= max; - } + return value >= min && value <= max; } +} - public static class ObjectExtensions +public static class ObjectExtensions +{ + public static void CloneTo(this T source, T destination) where T : class { - public static void CloneTo(this T source, T destination) where T : class - { - var json = JsonSerializer.CreateDefault(); - var jobj = JObject.FromObject(source); - jobj.Populate(destination); - } + var json = JsonSerializer.CreateDefault(); + var jobj = JObject.FromObject(source); + jobj.Populate(destination); } +} - public static class JsonExtensions +public static class JsonExtensions +{ + public static void Populate(this JToken value, object target) { - public static void Populate(this JToken value, object target) - { - using (var sr = value.CreateReader()) - JsonSerializer.CreateDefault().Populate(sr, target); - } + using (var sr = value.CreateReader()) + JsonSerializer.CreateDefault().Populate(sr, target); } } \ No newline at end of file diff --git a/SM64Lib/FilePathsConfiguration.cs b/SM64Lib/FilePathsConfiguration.cs index 48386fc..92448f7 100644 --- a/SM64Lib/FilePathsConfiguration.cs +++ b/SM64Lib/FilePathsConfiguration.cs @@ -1,49 +1,48 @@ using System.Collections.Generic; -namespace SM64Lib +namespace SM64Lib; + +public class FilePathsConfiguration { - public class FilePathsConfiguration + + // S T A T I C M E M B E R S + + public static FilePathsConfiguration DefaultConfiguration { get; private set; } = new FilePathsConfiguration(); + + public static string[] AllFileKeys { - - // S T A T I C M E M B E R S - - public static FilePathsConfiguration DefaultConfiguration { get; private set; } = new FilePathsConfiguration(); - - public static string[] AllFileKeys + get { - get - { - return new[] { "rn64crc.exe","ApplyPPF3.exe", "Level Tabel.json", "Update-Patches.json", "Update Patches Folder", "Text Profiles.json", "BaseTweak", "sm64extend.exe", "Original Level Pointers.bin", "armips.exe", "Flips.exe", "nconvert.exe" }; - } - } - - // F I E L D S - - private readonly Dictionary dic = new Dictionary(); - - // P R O P E R T I E S - - public IReadOnlyDictionary Files - { - get - { - return dic; - } - } - - // C O N S T R U C T O R - - public FilePathsConfiguration() - { - foreach (string key in AllFileKeys) - dic.Add(key, string.Empty); - } - - // M E T H O D S - - public void SetFilePath(string key, string path) - { - dic[key] = path; + return new[] { "rn64crc.exe", "ApplyPPF3.exe", "Level Tabel.json", "Update-Patches.json", "Update Patches Folder", "Text Profiles.json", "BaseTweak", "sm64extend.exe", "Original Level Pointers.bin", "armips.exe", "Flips.exe", "nconvert.exe" }; } } + + // F I E L D S + + private readonly Dictionary dic = new Dictionary(); + + // P R O P E R T I E S + + public IReadOnlyDictionary Files + { + get + { + return dic; + } + } + + // C O N S T R U C T O R + + public FilePathsConfiguration() + { + foreach (string key in AllFileKeys) + dic.Add(key, string.Empty); + } + + // M E T H O D S + + public void SetFilePath(string key, string path) + { + dic[key] = path; + } } \ No newline at end of file diff --git a/SM64Lib/General.cs b/SM64Lib/General.cs index 85e1cdc..003be5e 100644 --- a/SM64Lib/General.cs +++ b/SM64Lib/General.cs @@ -8,596 +8,595 @@ using System.IO.Compression; using System.Linq; using System.Security.Cryptography; -namespace SM64Lib +namespace SM64Lib; + +public static class General { - public static class General + public static byte[] DisplayListCommandsWithPointerList { get; private set; } = new byte[] { 0x1, 0x3, 0x4, 0x6, 0xFD }; + public static bool[] ActSelectorDefaultValues { get; private set; } = new bool[] { false, false, false, true, true, false, true, true, true, true, true, true, true, true, true, false, false, false, false, false, false, true, true, true, false, false, false, false, false, false, false, false, false, false, false }; + public static PatchClass PatchClass { get; private set; } = new PatchClass(); + + public static bool IsDebugging { - public static byte[] DisplayListCommandsWithPointerList { get; private set; } = new byte[] { 0x1, 0x3, 0x4, 0x6, 0xFD }; - public static bool[] ActSelectorDefaultValues { get; private set; } = new bool[] { false, false, false, true, true, false, true, true, true, true, true, true, true, true, true, false, false, false, false, false, false, true, true, true, false, false, false, false, false, false, false, false, false, false, false }; - public static PatchClass PatchClass { get; private set; } = new PatchClass(); - - public static bool IsDebugging + get { - get - { - return Debugger.IsAttached; - } + return Debugger.IsAttached; + } + } + + public static short KeepInInt16Range(double value) + { + if (value > short.MaxValue) + { + value = short.MaxValue; + } + else if (value < short.MinValue) + { + value = short.MinValue; } - public static short KeepInInt16Range(double value) - { - if (value > short.MaxValue) - { - value = short.MaxValue; - } - else if (value < short.MinValue) - { - value = short.MinValue; - } + return Convert.ToInt16(value); + } - return Convert.ToInt16(value); + internal static IReadOnlyDictionary MyFilePaths + { + get + { + return FilePathsConfiguration.DefaultConfiguration.Files; + } + } + + public static string ComputeMD5Hash(string filePath) + { + var md5 = MD5.Create(); + string res; + FileStream fs; + + try + { + fs = new FileStream(filePath, FileMode.Open, FileAccess.Read); + res = BitConverter.ToString(md5.ComputeHash(fs)).Replace("-", string.Empty).ToLowerInvariant(); + } + catch (Exception) + { + fs = null; + res = string.Empty; } - internal static IReadOnlyDictionary MyFilePaths + fs?.Close(); + md5.Dispose(); + return res; + } + + public static void CopyBitmap(Bitmap src, Bitmap dest) + { + for (int y = 0, loopTo = src.Height - 1; y <= loopTo; y++) { - get - { - return FilePathsConfiguration.DefaultConfiguration.Files; - } + for (int x = 0, loopTo1 = src.Width - 1; x <= loopTo1; x++) + dest.SetPixel(x, y, src.GetPixel(x, y)); + } + } + + public static Bitmap CopyBitmap(Bitmap src) + { + return CopyBitmap(src, src.PixelFormat); + } + + public static Bitmap CopyBitmap(Bitmap src, System.Drawing.Imaging.PixelFormat pixelFormat) + { + var dest = new Bitmap(src.Width, src.Height, pixelFormat); + CopyBitmap(src, dest); + return dest; + } + + public static double Round(double d) + { + return Math.Round(d, MidpointRounding.AwayFromZero); + } + + public static bool CompareTwoByteArrays(byte[] arr1, byte[] arr2, uint size = 0) + { + if (arr2.Length != arr1.Length) return false; + + int loopTo = size != 0 ? (int)size : arr1.Length; + + for (int i = 0; i < loopTo; i++) + { + if (arr1[i] != arr2[i]) + return false; } - public static string ComputeMD5Hash(string filePath) + return true; + } + + public static byte GetLevelIndexFromID(byte LevelID) + { + switch (LevelID) { - var md5 = MD5.Create(); - string res; - FileStream fs; - - try - { - fs = new FileStream(filePath, FileMode.Open, FileAccess.Read); - res = BitConverter.ToString(md5.ComputeHash(fs)).Replace("-", string.Empty).ToLowerInvariant(); - } - catch (Exception) - { - fs = null; - res = string.Empty; - } - - fs?.Close(); - md5.Dispose(); - return res; - } - - public static void CopyBitmap(Bitmap src, Bitmap dest) - { - for (int y = 0, loopTo = src.Height - 1; y <= loopTo; y++) - { - for (int x = 0, loopTo1 = src.Width - 1; x <= loopTo1; x++) - dest.SetPixel(x, y, src.GetPixel(x, y)); - } - } - - public static Bitmap CopyBitmap(Bitmap src) - { - return CopyBitmap(src, src.PixelFormat); - } - - public static Bitmap CopyBitmap(Bitmap src, System.Drawing.Imaging.PixelFormat pixelFormat) - { - var dest = new Bitmap(src.Width, src.Height, pixelFormat); - CopyBitmap(src, dest); - return dest; - } - - public static double Round(double d) - { - return Math.Round(d, MidpointRounding.AwayFromZero); - } - - public static bool CompareTwoByteArrays(byte[] arr1, byte[] arr2, uint size = 0) - { - if (arr2.Length != arr1.Length) return false; - - int loopTo = size != 0 ? (int)size : arr1.Length; - - for (int i = 0; i < loopTo; i++) - { - if (arr1[i] != arr2[i]) - return false; - } - - return true; - } - - public static byte GetLevelIndexFromID(byte LevelID) - { - switch (LevelID) - { - case 0x4: - { - return 0; - } - - case 0x5: - { - return 1; - } - - case 0x6: - { - return 2; - } - - case 0x7: - { - return 3; - } - - case 0x8: - { - return 4; - } - - case 0x9: - { - return 5; - } - - case 0xA: - { - return 6; - } - - case 0xB: - { - return 7; - } - - case 0xC: - { - return 8; - } - - case 0xD: - { - return 9; - } - - case 0xE: - { - return 10; - } - - case 0xF: - { - return 11; - } - - case 0x10: - { - return 12; - } - - case 0x11: - { - return 13; - } - - case 0x12: - { - return 14; - } - - case 0x13: - { - return 15; - } - - case 0x14: - { - return 16; - } - - case 0x15: - { - return 17; - } - - case 0x16: - { - return 18; - } - - case 0x17: - { - return 19; - } - - case 0x18: - { - return 20; - } - - case 0x19: - { - return 21; - } - - case 0x1A: - { - return 22; - } - - case 0x1B: - { - return 23; - } - - case 0x1C: - { - return 24; - } - - case 0x1D: - { - return 25; - } - - case 0x1E: - { - return 26; - } - - case 0x1F: - { - return 27; - } - - case 0x21: - { - return 28; - } - - case 0x22: - { - return 29; - } - - case 0x24: - { - return 30; - } - - default: - { - return 5; - } - } - } - - public static byte GetLevelIDFromIndex(byte LevelID) - { - switch (LevelID) - { - case 0: - { - return 0x4; - } - - case 1: - { - return 0x5; - } - - case 2: - { - return 0x6; - } - - case 3: - { - return 0x7; - } - - case 4: - { - return 0x8; - } - - case 5: - { - return 0x9; - } - - case 6: - { - return 0xA; - } - - case 7: - { - return 0xB; - } - - case 8: - { - return 0xC; - } - - case 9: - { - return 0xD; - } - - case 10: - { - return 0xE; - } - - case 11: - { - return 0xF; - } - - case 12: - { - return 0x10; - } - - case 13: - { - return 0x11; - } - - case 14: - { - return 0x12; - } - - case 15: - { - return 0x13; - } - - case 16: - { - return 0x14; - } - - case 17: - { - return 0x15; - } - - case 18: - { - return 0x16; - } - - case 19: - { - return 0x17; - } - - case 20: - { - return 0x18; - } - - case 21: - { - return 0x19; - } - - case 22: - { - return 0x1A; - } - - case 23: - { - return 0x1B; - } - - case 24: - { - return 0x1C; - } - - case 25: - { - return 0x1D; - } - - case 26: - { - return 0x1E; - } - - case 27: - { - return 0x1F; - } - - case 28: - { - return 0x21; - } - - case 29: - { - return 0x22; - } - - case 30: - { - return 0x24; - } - - default: - { - return 5; - } - } - } - - public static int HexRoundUp1(int value) - { - while (value % 0x10 != 0) - value += 1; - return value; - } - - public static long HexRoundUp1(long value) - { - while (value % 0x10 != 0) - value += 1; - return value; - } - - public static void HexRoundUp2(ref long value) - { - while (value % 0x10 != 0) - value += 1; - } - - public static void HexRoundUp2(ref uint value) - { - while (value % 0x10 != 0) - value += 1; - } - - public static void HexRoundUp2(ref int value) - { - while (value % 0x10 != 0) - value += 1; - } - - public static string FillStrToCharCount(string str, int charCount, string fillVal = "0") - { - if (fillVal.Count() == 0) - return str; - if (charCount == 0) - return str; - while (str.Count() < charCount) - str = fillVal + str; - return str; - } - - public static Geolayout.BackgroundPointers GetBackgroundAddressOfID(Geolayout.BackgroundIDs ID, bool EndAddr) - { - switch (ID) - { - case Geolayout.BackgroundIDs.AboveClouds: - { - if (EndAddr) - return Geolayout.BackgroundPointers.AboveCloudsEnd; - return Geolayout.BackgroundPointers.AboveCloudsStart; - } - - case Geolayout.BackgroundIDs.BelowClouds: - { - if (EndAddr) - return Geolayout.BackgroundPointers.BelowCloudsEnd; - return Geolayout.BackgroundPointers.BelowCloudsStart; - } - - case Geolayout.BackgroundIDs.Cavern: - { - if (EndAddr) - return Geolayout.BackgroundPointers.CavernEnd; - return Geolayout.BackgroundPointers.CavernStart; - } - - case Geolayout.BackgroundIDs.Desert: - { - if (EndAddr) - return Geolayout.BackgroundPointers.DesertEnd; - return Geolayout.BackgroundPointers.DesertStart; - } - - case Geolayout.BackgroundIDs.FlamingSky: - { - if (EndAddr) - return Geolayout.BackgroundPointers.FlamingSkyEnd; - return Geolayout.BackgroundPointers.FlamingSkyStart; - } - - case Geolayout.BackgroundIDs.HauntedForest: - { - if (EndAddr) - return Geolayout.BackgroundPointers.HauntedForestEnd; - return Geolayout.BackgroundPointers.HauntedForestStart; - } - - case Geolayout.BackgroundIDs.Ocean: - { - if (EndAddr) - return Geolayout.BackgroundPointers.OceanEnd; - return Geolayout.BackgroundPointers.OceanStart; - } - - case Geolayout.BackgroundIDs.PurpleClouds: - { - if (EndAddr) - return Geolayout.BackgroundPointers.PurpleCloudsEnd; - return Geolayout.BackgroundPointers.PurpleCloudsStart; - } - - case Geolayout.BackgroundIDs.SnowyMountains: - { - if (EndAddr) - return Geolayout.BackgroundPointers.SnowyMountainsEnd; - return Geolayout.BackgroundPointers.SnowyMountainsStart; - } - - case Geolayout.BackgroundIDs.UnderwaterCity: - { - if (EndAddr) - return Geolayout.BackgroundPointers.UnderwaterCityEnd; - return Geolayout.BackgroundPointers.UnderwaterCityStart; - } - } - - return EndAddr ? Geolayout.BackgroundPointers.OceanEnd : Geolayout.BackgroundPointers.OceanStart; - } - - public static string CommandByteArrayToString(byte[] bytes) - { - string res = string.Empty; - foreach (byte b in bytes) - { - if (!string.IsNullOrEmpty(res)) + case 0x4: { - res += " "; + return 0; } - res += b.ToString("X2"); - } + case 0x5: + { + return 1; + } - return res; + case 0x6: + { + return 2; + } + + case 0x7: + { + return 3; + } + + case 0x8: + { + return 4; + } + + case 0x9: + { + return 5; + } + + case 0xA: + { + return 6; + } + + case 0xB: + { + return 7; + } + + case 0xC: + { + return 8; + } + + case 0xD: + { + return 9; + } + + case 0xE: + { + return 10; + } + + case 0xF: + { + return 11; + } + + case 0x10: + { + return 12; + } + + case 0x11: + { + return 13; + } + + case 0x12: + { + return 14; + } + + case 0x13: + { + return 15; + } + + case 0x14: + { + return 16; + } + + case 0x15: + { + return 17; + } + + case 0x16: + { + return 18; + } + + case 0x17: + { + return 19; + } + + case 0x18: + { + return 20; + } + + case 0x19: + { + return 21; + } + + case 0x1A: + { + return 22; + } + + case 0x1B: + { + return 23; + } + + case 0x1C: + { + return 24; + } + + case 0x1D: + { + return 25; + } + + case 0x1E: + { + return 26; + } + + case 0x1F: + { + return 27; + } + + case 0x21: + { + return 28; + } + + case 0x22: + { + return 29; + } + + case 0x24: + { + return 30; + } + + default: + { + return 5; + } + } + } + + public static byte GetLevelIDFromIndex(byte LevelID) + { + switch (LevelID) + { + case 0: + { + return 0x4; + } + + case 1: + { + return 0x5; + } + + case 2: + { + return 0x6; + } + + case 3: + { + return 0x7; + } + + case 4: + { + return 0x8; + } + + case 5: + { + return 0x9; + } + + case 6: + { + return 0xA; + } + + case 7: + { + return 0xB; + } + + case 8: + { + return 0xC; + } + + case 9: + { + return 0xD; + } + + case 10: + { + return 0xE; + } + + case 11: + { + return 0xF; + } + + case 12: + { + return 0x10; + } + + case 13: + { + return 0x11; + } + + case 14: + { + return 0x12; + } + + case 15: + { + return 0x13; + } + + case 16: + { + return 0x14; + } + + case 17: + { + return 0x15; + } + + case 18: + { + return 0x16; + } + + case 19: + { + return 0x17; + } + + case 20: + { + return 0x18; + } + + case 21: + { + return 0x19; + } + + case 22: + { + return 0x1A; + } + + case 23: + { + return 0x1B; + } + + case 24: + { + return 0x1C; + } + + case 25: + { + return 0x1D; + } + + case 26: + { + return 0x1E; + } + + case 27: + { + return 0x1F; + } + + case 28: + { + return 0x21; + } + + case 29: + { + return 0x22; + } + + case 30: + { + return 0x24; + } + + default: + { + return 5; + } + } + } + + public static int HexRoundUp1(int value) + { + while (value % 0x10 != 0) + value += 1; + return value; + } + + public static long HexRoundUp1(long value) + { + while (value % 0x10 != 0) + value += 1; + return value; + } + + public static void HexRoundUp2(ref long value) + { + while (value % 0x10 != 0) + value += 1; + } + + public static void HexRoundUp2(ref uint value) + { + while (value % 0x10 != 0) + value += 1; + } + + public static void HexRoundUp2(ref int value) + { + while (value % 0x10 != 0) + value += 1; + } + + public static string FillStrToCharCount(string str, int charCount, string fillVal = "0") + { + if (fillVal.Count() == 0) + return str; + if (charCount == 0) + return str; + while (str.Count() < charCount) + str = fillVal + str; + return str; + } + + public static Geolayout.BackgroundPointers GetBackgroundAddressOfID(Geolayout.BackgroundIDs ID, bool EndAddr) + { + switch (ID) + { + case Geolayout.BackgroundIDs.AboveClouds: + { + if (EndAddr) + return Geolayout.BackgroundPointers.AboveCloudsEnd; + return Geolayout.BackgroundPointers.AboveCloudsStart; + } + + case Geolayout.BackgroundIDs.BelowClouds: + { + if (EndAddr) + return Geolayout.BackgroundPointers.BelowCloudsEnd; + return Geolayout.BackgroundPointers.BelowCloudsStart; + } + + case Geolayout.BackgroundIDs.Cavern: + { + if (EndAddr) + return Geolayout.BackgroundPointers.CavernEnd; + return Geolayout.BackgroundPointers.CavernStart; + } + + case Geolayout.BackgroundIDs.Desert: + { + if (EndAddr) + return Geolayout.BackgroundPointers.DesertEnd; + return Geolayout.BackgroundPointers.DesertStart; + } + + case Geolayout.BackgroundIDs.FlamingSky: + { + if (EndAddr) + return Geolayout.BackgroundPointers.FlamingSkyEnd; + return Geolayout.BackgroundPointers.FlamingSkyStart; + } + + case Geolayout.BackgroundIDs.HauntedForest: + { + if (EndAddr) + return Geolayout.BackgroundPointers.HauntedForestEnd; + return Geolayout.BackgroundPointers.HauntedForestStart; + } + + case Geolayout.BackgroundIDs.Ocean: + { + if (EndAddr) + return Geolayout.BackgroundPointers.OceanEnd; + return Geolayout.BackgroundPointers.OceanStart; + } + + case Geolayout.BackgroundIDs.PurpleClouds: + { + if (EndAddr) + return Geolayout.BackgroundPointers.PurpleCloudsEnd; + return Geolayout.BackgroundPointers.PurpleCloudsStart; + } + + case Geolayout.BackgroundIDs.SnowyMountains: + { + if (EndAddr) + return Geolayout.BackgroundPointers.SnowyMountainsEnd; + return Geolayout.BackgroundPointers.SnowyMountainsStart; + } + + case Geolayout.BackgroundIDs.UnderwaterCity: + { + if (EndAddr) + return Geolayout.BackgroundPointers.UnderwaterCityEnd; + return Geolayout.BackgroundPointers.UnderwaterCityStart; + } } - internal static byte[] CompressData(Stream input, CompressionLevel compressionLevel) + return EndAddr ? Geolayout.BackgroundPointers.OceanEnd : Geolayout.BackgroundPointers.OceanStart; + } + + public static string CommandByteArrayToString(byte[] bytes) + { + string res = string.Empty; + foreach (byte b in bytes) { - var output = new MemoryStream(); - input.Position = 0; - - using (var compressor = new DeflateStream(output, compressionLevel, true)) - input.CopyTo(compressor); - - var res = output.ToArray(); - output.Close(); - return res; - } - - internal static void DecompressData(byte[] input, Stream output) - { - using (var sInput = new MemoryStream(input)) + if (!string.IsNullOrEmpty(res)) { - using (var decompressor = new DeflateStream(sInput, CompressionMode.Decompress, true)) - decompressor.CopyTo(output); + res += " "; } + + res += b.ToString("X2"); + } + + return res; + } + + internal static byte[] CompressData(Stream input, CompressionLevel compressionLevel) + { + var output = new MemoryStream(); + input.Position = 0; + + using (var compressor = new DeflateStream(output, compressionLevel, true)) + input.CopyTo(compressor); + + var res = output.ToArray(); + output.Close(); + return res; + } + + internal static void DecompressData(byte[] input, Stream output) + { + using (var sInput = new MemoryStream(input)) + { + using (var decompressor = new DeflateStream(sInput, CompressionMode.Decompress, true)) + decompressor.CopyTo(output); } } } \ No newline at end of file diff --git a/SM64Lib/Geolayout/BackgroundIDs.cs b/SM64Lib/Geolayout/BackgroundIDs.cs index f4560ce..67accd6 100644 --- a/SM64Lib/Geolayout/BackgroundIDs.cs +++ b/SM64Lib/Geolayout/BackgroundIDs.cs @@ -1,18 +1,17 @@  -namespace SM64Lib.Geolayout +namespace SM64Lib.Geolayout; + +public enum BackgroundIDs : byte { - public enum BackgroundIDs : byte - { - HauntedForest = 0x6, - SnowyMountains = 0x4, - Desert = 0x5, - Ocean = 0x0, - UnderwaterCity = 0x2, - BelowClouds = 0x8, - AboveClouds = 0x3, - Cavern = 0x7, - FlamingSky = 0x1, - PurpleClouds = 0x9, - Custom = 0xA - } + HauntedForest = 0x6, + SnowyMountains = 0x4, + Desert = 0x5, + Ocean = 0x0, + UnderwaterCity = 0x2, + BelowClouds = 0x8, + AboveClouds = 0x3, + Cavern = 0x7, + FlamingSky = 0x1, + PurpleClouds = 0x9, + Custom = 0xA } \ No newline at end of file diff --git a/SM64Lib/Geolayout/BackgroundPointers.cs b/SM64Lib/Geolayout/BackgroundPointers.cs index 3dd546c..139fa8e 100644 --- a/SM64Lib/Geolayout/BackgroundPointers.cs +++ b/SM64Lib/Geolayout/BackgroundPointers.cs @@ -1,27 +1,26 @@  -namespace SM64Lib.Geolayout +namespace SM64Lib.Geolayout; + +public enum BackgroundPointers { - public enum BackgroundPointers - { - HauntedForestStart = 0xC3B030, // &HC3AFD5 - HauntedForestEnd = 0xC4F970, // &HC4F915 - SnowyMountainsStart = 0xB5D8B0, // &HB5D855 - SnowyMountainsEnd = 0xB7D9F0, // &HB7D995 - DesertStart = 0xC12EF0, // &HC12E95 - DesertEnd = 0xC33030, // &HC32FD5 - OceanStart = 0xB35770, // &HB35715 - OceanEnd = 0xB558B0, // &HB55855 - UnderwaterCityStart = 0xBC2C70, // &HBC2C15 - UnderwaterCityEnd = 0xBE2DB0, // &HBE2D55 - BelowCloudsStart = 0xB859F0, // &HB85995 - BelowCloudsEnd = 0xB9A330, // &HB9A2D5 - AboveCloudsStart = 0xBEADB0, // &HBEAD55 - AboveCloudsEnd = 0xC0AEF0, // &HC0AE95 - CavernStart = 0xC57970, // &HC57915 - CavernEnd = 0xC77AB0, // &HC77A55 - FlamingSkyStart = 0xBA2330, // &HBA22D5 - FlamingSkyEnd = 0xBBAC70, // &HBBAC15 - PurpleCloudsStart = 0xC7FAB0, // &HC7FA55 - PurpleCloudsEnd = 0xC9FBF0 // &HC9FB95 - } + HauntedForestStart = 0xC3B030, // &HC3AFD5 + HauntedForestEnd = 0xC4F970, // &HC4F915 + SnowyMountainsStart = 0xB5D8B0, // &HB5D855 + SnowyMountainsEnd = 0xB7D9F0, // &HB7D995 + DesertStart = 0xC12EF0, // &HC12E95 + DesertEnd = 0xC33030, // &HC32FD5 + OceanStart = 0xB35770, // &HB35715 + OceanEnd = 0xB558B0, // &HB55855 + UnderwaterCityStart = 0xBC2C70, // &HBC2C15 + UnderwaterCityEnd = 0xBE2DB0, // &HBE2D55 + BelowCloudsStart = 0xB859F0, // &HB85995 + BelowCloudsEnd = 0xB9A330, // &HB9A2D5 + AboveCloudsStart = 0xBEADB0, // &HBEAD55 + AboveCloudsEnd = 0xC0AEF0, // &HC0AE95 + CavernStart = 0xC57970, // &HC57915 + CavernEnd = 0xC77AB0, // &HC77A55 + FlamingSkyStart = 0xBA2330, // &HBA22D5 + FlamingSkyEnd = 0xBBAC70, // &HBBAC15 + PurpleCloudsStart = 0xC7FAB0, // &HC7FA55 + PurpleCloudsEnd = 0xC9FBF0 // &HC9FB95 } \ No newline at end of file diff --git a/SM64Lib/Geolayout/CameraFrustrum.cs b/SM64Lib/Geolayout/CameraFrustrum.cs index 78738d5..81d6a8f 100644 --- a/SM64Lib/Geolayout/CameraFrustrum.cs +++ b/SM64Lib/Geolayout/CameraFrustrum.cs @@ -1,20 +1,13 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +namespace SM64Lib.Geolayout; -namespace SM64Lib.Geolayout +public class CameraFrustrum { - public class CameraFrustrum - { - /// - /// This is essentially render distance of geometry. - /// - public short CameraFar { get; set; } = 0x7530; - /// - /// Defines how close to the camera geometry will render. - /// - public short CameraNear { get; set; } = 0x64; - } + /// + /// This is essentially render distance of geometry. + /// + public short CameraFar { get; set; } = 0x7530; + /// + /// Defines how close to the camera geometry will render. + /// + public short CameraNear { get; set; } = 0x64; } diff --git a/SM64Lib/Geolayout/CameraPresets.cs b/SM64Lib/Geolayout/CameraPresets.cs index 3ffd72d..c1e1148 100644 --- a/SM64Lib/Geolayout/CameraPresets.cs +++ b/SM64Lib/Geolayout/CameraPresets.cs @@ -1,23 +1,22 @@  -namespace SM64Lib.Geolayout +namespace SM64Lib.Geolayout; + +public enum CameraPresets { - public enum CameraPresets - { - OpenCamera = 0x1, - TickTockClock, - SecretAquarium, - InsideCastle, - Unmoving, - MarioFacingObject, - Unmoving1, - UnderwaterCamera, - PeachSlideCamera, - InsideCannon, - BowserFightsDistant, - CloseCameraCrashes, - FixedReferencePoint, - PlattfromLevels, - Unmoving2, - FreeRoamCamera - } + OpenCamera = 0x1, + TickTockClock, + SecretAquarium, + InsideCastle, + Unmoving, + MarioFacingObject, + Unmoving1, + UnderwaterCamera, + PeachSlideCamera, + InsideCannon, + BowserFightsDistant, + CloseCameraCrashes, + FixedReferencePoint, + PlattfromLevels, + Unmoving2, + FreeRoamCamera } \ No newline at end of file diff --git a/SM64Lib/Geolayout/DefaultGeolayers.cs b/SM64Lib/Geolayout/DefaultGeolayers.cs index f6c6797..3c48fa0 100644 --- a/SM64Lib/Geolayout/DefaultGeolayers.cs +++ b/SM64Lib/Geolayout/DefaultGeolayers.cs @@ -1,15 +1,14 @@  -namespace SM64Lib.Geolayout +namespace SM64Lib.Geolayout; + +public enum DefaultGeolayers { - public enum DefaultGeolayers - { - SolidNoAntiAlias, - Solid, - SolidDecal, - TranslucentDecal, - Alpha, - Translucent, - TranslucentDecal2, - TranslucentDecal3 - } + SolidNoAntiAlias, + Solid, + SolidDecal, + TranslucentDecal, + Alpha, + Translucent, + TranslucentDecal2, + TranslucentDecal3 } \ No newline at end of file diff --git a/SM64Lib/Geolayout/EnvironmentEffects.cs b/SM64Lib/Geolayout/EnvironmentEffects.cs index 9504db9..334c2d2 100644 --- a/SM64Lib/Geolayout/EnvironmentEffects.cs +++ b/SM64Lib/Geolayout/EnvironmentEffects.cs @@ -1,14 +1,13 @@  -namespace SM64Lib.Geolayout +namespace SM64Lib.Geolayout; + +public enum EnvironmentEffects { - public enum EnvironmentEffects - { - NoEffect = 0x0, - Snow = 0x1, - Bllizard = 0x3, - BetaFlower = 0xB, - Lava = 0xC, - WaterRelated1 = 0xD, - WaterRelated2 = 0x2 - } + NoEffect = 0x0, + Snow = 0x1, + Bllizard = 0x3, + BetaFlower = 0xB, + Lava = 0xC, + WaterRelated1 = 0xD, + WaterRelated2 = 0x2 } \ No newline at end of file diff --git a/SM64Lib/Geolayout/GeoAsmPointer.cs b/SM64Lib/Geolayout/GeoAsmPointer.cs index 8ae265c..726fd32 100644 --- a/SM64Lib/Geolayout/GeoAsmPointer.cs +++ b/SM64Lib/Geolayout/GeoAsmPointer.cs @@ -1,10 +1,9 @@  -namespace SM64Lib.Geolayout +namespace SM64Lib.Geolayout; + +public enum GeoAsmPointer : uint { - public enum GeoAsmPointer : uint - { - EnvironmentEffect = 0x802761D0, - Water = 0x802D104C, - Unknown = 0x802CD1E8 - } + EnvironmentEffect = 0x802761D0, + Water = 0x802D104C, + Unknown = 0x802CD1E8 } \ No newline at end of file diff --git a/SM64Lib/Geolayout/Geolayout.cs b/SM64Lib/Geolayout/Geolayout.cs index d2751da..bd5c2ca 100644 --- a/SM64Lib/Geolayout/Geolayout.cs +++ b/SM64Lib/Geolayout/Geolayout.cs @@ -1,380 +1,378 @@ -using System.Collections.Generic; +using global::SM64Lib.Geolayout.Script; +using global::SM64Lib.Geolayout.Script.Commands; using global::System.IO; using Microsoft.VisualBasic; -using Microsoft.VisualBasic.CompilerServices; -using global::SM64Lib.Geolayout.Script; -using global::SM64Lib.Geolayout.Script.Commands; using Newtonsoft.Json; using System; +using System.Collections.Generic; -namespace SM64Lib.Geolayout +namespace SM64Lib.Geolayout; + +public class Geolayout { - public class Geolayout + [JsonProperty] + private int IndexForGeopointers = -1; + + public Geolayoutscript Geolayoutscript { get; set; } = new Geolayoutscript(); + public CameraPresets CameraPreset { get; set; } = CameraPresets.OpenCamera; + public EnvironmentEffects EnvironmentEffect { get; set; } = default; + public List GeopointerOffsets { get; set; } = new List(); + public List Geopointers { get; set; } = new List(); + public int NewGeoOffset { get; set; } = 0; + public bool Closed { get; set; } = false; + public ObjectShadow ObjectShadow { get; set; } = new ObjectShadow(); + public CameraFrustrum CameraFrustrum { get; set; } = new CameraFrustrum(); + + public int Length { - [JsonProperty] - private int IndexForGeopointers = -1; - - public Geolayoutscript Geolayoutscript { get; set; } = new Geolayoutscript(); - public CameraPresets CameraPreset { get; set; } = CameraPresets.OpenCamera; - public EnvironmentEffects EnvironmentEffect { get; set; } = default; - public List GeopointerOffsets { get; set; } = new List(); - public List Geopointers { get; set; } = new List(); - public int NewGeoOffset { get; set; } = 0; - public bool Closed { get; set; } = false; - public ObjectShadow ObjectShadow { get; set; } = new ObjectShadow(); - public CameraFrustrum CameraFrustrum { get; set; } = new CameraFrustrum(); - - public int Length - { - get - { - int tLength = Geopointers.Count * 8; - foreach (var c in Geolayoutscript) - tLength += (int)c.Length; - return tLength; - } - } - - private void RemoveOldGeopointerCommands() - { - var ToRemove = new List(); - foreach (GeolayoutCommand c in Geolayoutscript) - { - if (c.CommandType == GeolayoutCommandTypes.LoadDisplaylist) - { - ToRemove.Add(c); - } - } - - foreach (GeolayoutCommand cmd in ToRemove) - { - Geolayoutscript.Remove(cmd); - cmd.Close(); - } - } - - private List GetGeopointersFromGeolayoutScript(Geolayoutscript script) - { - List geopointers = new List(); - int geolayoutCommandIndex = 0; - var curMdlScale = System.Numerics.Vector3.One; - var curMdlOffset = System.Numerics.Vector3.Zero; - foreach (GeolayoutCommand geolayoutCommand in script) - { - var referenceCommand = geolayoutCommand; - if (geolayoutCommand.CommandType == GeolayoutCommandTypes.LoadDisplaylist) - { - geopointers.Add(new Geopointer( - cgLoadDisplayList.GetDrawingLayer(ref referenceCommand), - cgLoadDisplayList.GetSegGeopointer(ref referenceCommand), - curMdlScale, - curMdlOffset, - geolayoutCommandIndex - )); - } - geolayoutCommandIndex += 1; - } - return geopointers; - } - - public Geolayout(NewScriptCreationMode mode) - { - switch (mode) - { - case NewScriptCreationMode.Level: - { - { - var withBlock = Geolayoutscript; - withBlock.Add(new GeolayoutCommand(new byte[] { 0x8, 0x0, 0x0, 0xA, 0x0, 0xA0, 0x0, 0x78, 0x0, 0xA0, 0x0, 0x78 })); - withBlock.Add(new GeolayoutCommand(new byte[] { 0x4, 0x0, 0x0, 0x0 })); - withBlock.Add(new GeolayoutCommand(new byte[] { 0xC, 0x0, 0x0, 0x0 })); - withBlock.Add(new GeolayoutCommand(new byte[] { 0x4, 0x0, 0x0, 0x0 })); - withBlock.Add(new GeolayoutCommand(new byte[] { 0x9, 0x0, 0x0, 0x64 })); - withBlock.Add(new GeolayoutCommand(new byte[] { 0x4, 0x0, 0x0, 0x0 })); - withBlock.Add(new GeolayoutCommand(new byte[] { 0x19, 0x0, 0x0, 0x0, 0x80, 0x27, 0x63, 0xD4 })); - withBlock.Add(new GeolayoutCommand(new byte[] { 0x5, 0x0, 0x0, 0x0 })); - withBlock.Add(new GeolayoutCommand(new byte[] { 0x5, 0x0, 0x0, 0x0 })); - withBlock.Add(new GeolayoutCommand(new byte[] { 0xC, 0x1, 0x0, 0x0 })); - withBlock.Add(new GeolayoutCommand(new byte[] { 0x4, 0x0, 0x0, 0x0 })); - withBlock.Add(new GeolayoutCommand(new byte[] { 0xA, 0x1, 0x0, 0x2D, 0x0, 0x64, 0x75, 0x30, 0x80, 0x29, 0xAA, 0x3C })); - withBlock.Add(new GeolayoutCommand(new byte[] { 0x4, 0x0, 0x0, 0x0 })); - withBlock.Add(new GeolayoutCommand("0F 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 80 28 7D 30")); - withBlock.Add(new GeolayoutCommand(new byte[] { 0x4, 0x0, 0x0, 0x0 })); - IndexForGeopointers = 15; - // .Add(New GeolayoutCommand({&H15, &H1, &H0, &H0, &H0, &H0, &H0, &H0})) - withBlock.Add(new GeolayoutCommand(new byte[] { 0x17, 0x0, 0x0, 0x0 })); - withBlock.Add(new GeolayoutCommand(new byte[] { 0x18, 0x0, 0x0, 0x0, 0x80, 0x27, 0x61, 0xD0 })); - withBlock.Add(new GeolayoutCommand(new byte[] { 0x18, 0x0, 0x50, 0x0, 0x80, 0x2D, 0x10, 0x4C })); // Water - withBlock.Add(new GeolayoutCommand(new byte[] { 0x18, 0x0, 0x50, 0x1, 0x80, 0x2D, 0x10, 0x4C })); // Toxic Haze - withBlock.Add(new GeolayoutCommand(new byte[] { 0x18, 0x0, 0x50, 0x2, 0x80, 0x2D, 0x10, 0x4C })); // Mist - withBlock.Add(new GeolayoutCommand(new byte[] { 0x5, 0x0, 0x0, 0x0 })); - withBlock.Add(new GeolayoutCommand(new byte[] { 0x5, 0x0, 0x0, 0x0 })); - withBlock.Add(new GeolayoutCommand(new byte[] { 0x5, 0x0, 0x0, 0x0 })); - withBlock.Add(new GeolayoutCommand(new byte[] { 0xC, 0x0, 0x0, 0x0 })); - withBlock.Add(new GeolayoutCommand(new byte[] { 0x4, 0x0, 0x0, 0x0 })); - withBlock.Add(new GeolayoutCommand(new byte[] { 0x18, 0x0, 0x0, 0x0, 0x80, 0x2C, 0xD1, 0xE8 })); - withBlock.Add(new GeolayoutCommand(new byte[] { 0x5, 0x0, 0x0, 0x0 })); - withBlock.Add(new GeolayoutCommand(new byte[] { 0x5, 0x0, 0x0, 0x0 })); - withBlock.Add(new GeolayoutCommand(new byte[] { 0x1, 0x0, 0x0, 0x0 })); - } - - break; - } - - case NewScriptCreationMode.Object: - { - { - var withBlock1 = Geolayoutscript; - withBlock1.Add(new GeolayoutCommand("20 00 0F A0")); - withBlock1.Add(new GeolayoutCommand("04 00 00 00")); - IndexForGeopointers = 2; - withBlock1.Add(new GeolayoutCommand("05 00 00 00")); - withBlock1.Add(new GeolayoutCommand("01 00 00 00")); - } - - break; - } - } - } - - public void Read(byte[] data, byte bankID) - { - RenewGeolayout(); - Geolayoutscript.Read(data, bankID); - ParseGeolayout(); - } - - public void Read(RomManager rommgr, int segAddress) - { - RenewGeolayout(); - Geolayoutscript.Read(rommgr, segAddress); - ParseGeolayout(); - } - - private void RenewGeolayout() - { - if (!Closed) Close(); - Closed = false; - Geolayoutscript.Clear(); - Geopointers.Clear(); - GeopointerOffsets.Clear(); - Geolayoutscript = new Geolayoutscript(); - ObjectShadow = new ObjectShadow(); - CameraFrustrum = new CameraFrustrum(); - } - - public void ParseGeolayout() - { - var ToRemove = new List(); - int cIndex = 0; - var curMdlScale = System.Numerics.Vector3.One; - var curMdlOffset = System.Numerics.Vector3.Zero; - - foreach (GeolayoutCommand fec in Geolayoutscript) - { - var c = fec; - var switchExpr = c.CommandType; - - switch (switchExpr) - { - case GeolayoutCommandTypes.CameraPreset: - CameraPreset = (CameraPresets)cgCameraPreset.GetCameraPreset(ref c); - break; - case GeolayoutCommandTypes.x18: - var switchExpr1 = (uint)cgx18.GetAsmPointer(ref c); - switch (switchExpr1) - { - case 0x802761D0: - EnvironmentEffect = (EnvironmentEffects)cgx18.GetParam1(ref c); - break; - } - break; - case GeolayoutCommandTypes.LoadDisplaylist: - if (Geopointers.Count == 0) - IndexForGeopointers = cIndex; - Geopointers.Add(new Geopointer(cgLoadDisplayList.GetDrawingLayer(ref c), cgLoadDisplayList.GetSegGeopointer(ref c), curMdlScale, curMdlOffset, cIndex)); - break; - case GeolayoutCommandTypes.ObjectShadown: - cgObjectShadow.GetShadow(c, ObjectShadow); - ObjectShadow.Enabled = true; - break; - case GeolayoutCommandTypes.DrawingDistance: - ObjectShadow.Enabled = false; - break; - case GeolayoutCommandTypes.CameraFrustrum: - cgCameraFrustrum.GetCameraFrustrum(c, CameraFrustrum); - break; - } - - cIndex += 1; - } - - // Remove Geopointercommands - RemoveOldGeopointerCommands(); - } - - public void Write(Stream s, int StartOffset) - { - NewGeoOffset = StartOffset; - var commandsToRemove = new List(); - GeolayoutCommand cmdObjectShadow = null; - GeolayoutCommand cmdDrawingDistance = null; - int tIndexForGeoPointer = IndexForGeopointers; - var isForLevel = false; - - // Einstellungen übernehmen - int currentPosition = 0; - foreach (GeolayoutCommand fec in Geolayoutscript) - { - var c = fec; - var switchExpr = c.CommandType; - - switch (switchExpr) - { - case GeolayoutCommandTypes.CameraPreset: - cgCameraPreset.SetCameraPreset(ref c, Convert.ToByte(CameraPreset)); - break; - case GeolayoutCommandTypes.x18: - var switchExpr1 = cgx18.GetAsmPointer(ref c); - switch ((GeoAsmPointer)switchExpr1) - { - case GeoAsmPointer.EnvironmentEffect: - cgx18.SetParam1(ref c, (ushort)EnvironmentEffect); - break; - } - break; - case GeolayoutCommandTypes.ObjectShadown: - if (ObjectShadow.Enabled) - cmdObjectShadow = c; - else - commandsToRemove.Add(c); - break; - case GeolayoutCommandTypes.DrawingDistance: - if (ObjectShadow.Enabled) - commandsToRemove.Add(c); - else - cmdDrawingDistance = c; - break; - case GeolayoutCommandTypes.CameraFrustrum: - cgCameraFrustrum.SetCameraFrustrum(c, CameraFrustrum); - isForLevel = true; - break; - case GeolayoutCommandTypes.SetScreenRenderArea: - isForLevel = true; - break; - } - - currentPosition += (int)c.Length; - } - - // Insert Geopointers - foreach (Geopointer g in Geopointers) - { - var tcommand = new GeolayoutCommand(new byte[] { 0x15, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }); - cgLoadDisplayList.SetDrawingLayer(ref tcommand, g.Layer); - cgLoadDisplayList.SetSegGeopointer(ref tcommand, g.SegPointer); - if (g.Index == -1) - { - Geolayoutscript.Insert(tIndexForGeoPointer, tcommand); - } - else - { - Geolayoutscript.Insert(g.Index, tcommand); - } - - tIndexForGeoPointer += 1; - } - - // Remove all other commands to remove - foreach (var cmd in commandsToRemove) - { - Geolayoutscript.Remove(cmd); - cmd.Close(); - } - - // Add Geolayout Start command for non-level geolayouts - if (!isForLevel) - { - if (ObjectShadow.Enabled) - { - // Add Object Shadow - if (cmdObjectShadow is null) - { - cmdObjectShadow = new GeolayoutCommand("16 00 00 00 00 00 00 00"); - Geolayoutscript.Insert(0, cmdObjectShadow); - } - cgObjectShadow.SetShadow(cmdObjectShadow, ObjectShadow); - } - else - { - if (cmdDrawingDistance == null) - Geolayoutscript.Insert(0, new GeolayoutCommand("20 00 0F A0")); - } - } - - // Update Geopointer indexes after adding and removing other commands - Geopointers = GetGeopointersFromGeolayoutScript(Geolayoutscript); - - // Write Geolayout to ROM - Geolayoutscript.Write(s, StartOffset); - - // Remove Geopointercommands again - RemoveOldGeopointerCommands(); - } - - public void Close() + get { + int tLength = Geopointers.Count * 8; foreach (var c in Geolayoutscript) - c.Close(); - } - - public override string ToString() - { - string output = ""; - foreach (var cmd in Geolayoutscript) - { - string tbytelist = ""; - foreach (byte b in cmd.ToArray()) - { - if (tbytelist != string.Empty) - tbytelist += " "; - tbytelist += Conversion.Hex(b); - } - - if (output != string.Empty) - output += Environment.NewLine; - output += tbytelist; - } - - return output; - } - - public string ToString(GeolayoutCommandCollection Geolayoutscript) - { - string output = ""; - foreach (var cmd in Geolayoutscript) - { - string tbytelist = ""; - foreach (byte b in cmd.ToArray()) - { - if (tbytelist != string.Empty) - tbytelist += " "; - tbytelist += Conversion.Hex(b); - } - - if (output != string.Empty) - output += Environment.NewLine; - output += tbytelist; - } - - return output; - } - - public enum NewScriptCreationMode - { - None, - Level, - Object + tLength += (int)c.Length; + return tLength; } } + + private void RemoveOldGeopointerCommands() + { + var ToRemove = new List(); + foreach (GeolayoutCommand c in Geolayoutscript) + { + if (c.CommandType == GeolayoutCommandTypes.LoadDisplaylist) + { + ToRemove.Add(c); + } + } + + foreach (GeolayoutCommand cmd in ToRemove) + { + Geolayoutscript.Remove(cmd); + cmd.Close(); + } + } + + private List GetGeopointersFromGeolayoutScript(Geolayoutscript script) + { + List geopointers = new List(); + int geolayoutCommandIndex = 0; + var curMdlScale = System.Numerics.Vector3.One; + var curMdlOffset = System.Numerics.Vector3.Zero; + foreach (GeolayoutCommand geolayoutCommand in script) + { + var referenceCommand = geolayoutCommand; + if (geolayoutCommand.CommandType == GeolayoutCommandTypes.LoadDisplaylist) + { + geopointers.Add(new Geopointer( + cgLoadDisplayList.GetDrawingLayer(ref referenceCommand), + cgLoadDisplayList.GetSegGeopointer(ref referenceCommand), + curMdlScale, + curMdlOffset, + geolayoutCommandIndex + )); + } + geolayoutCommandIndex += 1; + } + return geopointers; + } + + public Geolayout(NewScriptCreationMode mode) + { + switch (mode) + { + case NewScriptCreationMode.Level: + { + { + var withBlock = Geolayoutscript; + withBlock.Add(new GeolayoutCommand(new byte[] { 0x8, 0x0, 0x0, 0xA, 0x0, 0xA0, 0x0, 0x78, 0x0, 0xA0, 0x0, 0x78 })); + withBlock.Add(new GeolayoutCommand(new byte[] { 0x4, 0x0, 0x0, 0x0 })); + withBlock.Add(new GeolayoutCommand(new byte[] { 0xC, 0x0, 0x0, 0x0 })); + withBlock.Add(new GeolayoutCommand(new byte[] { 0x4, 0x0, 0x0, 0x0 })); + withBlock.Add(new GeolayoutCommand(new byte[] { 0x9, 0x0, 0x0, 0x64 })); + withBlock.Add(new GeolayoutCommand(new byte[] { 0x4, 0x0, 0x0, 0x0 })); + withBlock.Add(new GeolayoutCommand(new byte[] { 0x19, 0x0, 0x0, 0x0, 0x80, 0x27, 0x63, 0xD4 })); + withBlock.Add(new GeolayoutCommand(new byte[] { 0x5, 0x0, 0x0, 0x0 })); + withBlock.Add(new GeolayoutCommand(new byte[] { 0x5, 0x0, 0x0, 0x0 })); + withBlock.Add(new GeolayoutCommand(new byte[] { 0xC, 0x1, 0x0, 0x0 })); + withBlock.Add(new GeolayoutCommand(new byte[] { 0x4, 0x0, 0x0, 0x0 })); + withBlock.Add(new GeolayoutCommand(new byte[] { 0xA, 0x1, 0x0, 0x2D, 0x0, 0x64, 0x75, 0x30, 0x80, 0x29, 0xAA, 0x3C })); + withBlock.Add(new GeolayoutCommand(new byte[] { 0x4, 0x0, 0x0, 0x0 })); + withBlock.Add(new GeolayoutCommand("0F 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 80 28 7D 30")); + withBlock.Add(new GeolayoutCommand(new byte[] { 0x4, 0x0, 0x0, 0x0 })); + IndexForGeopointers = 15; + // .Add(New GeolayoutCommand({&H15, &H1, &H0, &H0, &H0, &H0, &H0, &H0})) + withBlock.Add(new GeolayoutCommand(new byte[] { 0x17, 0x0, 0x0, 0x0 })); + withBlock.Add(new GeolayoutCommand(new byte[] { 0x18, 0x0, 0x0, 0x0, 0x80, 0x27, 0x61, 0xD0 })); + withBlock.Add(new GeolayoutCommand(new byte[] { 0x18, 0x0, 0x50, 0x0, 0x80, 0x2D, 0x10, 0x4C })); // Water + withBlock.Add(new GeolayoutCommand(new byte[] { 0x18, 0x0, 0x50, 0x1, 0x80, 0x2D, 0x10, 0x4C })); // Toxic Haze + withBlock.Add(new GeolayoutCommand(new byte[] { 0x18, 0x0, 0x50, 0x2, 0x80, 0x2D, 0x10, 0x4C })); // Mist + withBlock.Add(new GeolayoutCommand(new byte[] { 0x5, 0x0, 0x0, 0x0 })); + withBlock.Add(new GeolayoutCommand(new byte[] { 0x5, 0x0, 0x0, 0x0 })); + withBlock.Add(new GeolayoutCommand(new byte[] { 0x5, 0x0, 0x0, 0x0 })); + withBlock.Add(new GeolayoutCommand(new byte[] { 0xC, 0x0, 0x0, 0x0 })); + withBlock.Add(new GeolayoutCommand(new byte[] { 0x4, 0x0, 0x0, 0x0 })); + withBlock.Add(new GeolayoutCommand(new byte[] { 0x18, 0x0, 0x0, 0x0, 0x80, 0x2C, 0xD1, 0xE8 })); + withBlock.Add(new GeolayoutCommand(new byte[] { 0x5, 0x0, 0x0, 0x0 })); + withBlock.Add(new GeolayoutCommand(new byte[] { 0x5, 0x0, 0x0, 0x0 })); + withBlock.Add(new GeolayoutCommand(new byte[] { 0x1, 0x0, 0x0, 0x0 })); + } + + break; + } + + case NewScriptCreationMode.Object: + { + { + var withBlock1 = Geolayoutscript; + withBlock1.Add(new GeolayoutCommand("20 00 0F A0")); + withBlock1.Add(new GeolayoutCommand("04 00 00 00")); + IndexForGeopointers = 2; + withBlock1.Add(new GeolayoutCommand("05 00 00 00")); + withBlock1.Add(new GeolayoutCommand("01 00 00 00")); + } + + break; + } + } + } + + public void Read(byte[] data, byte bankID) + { + RenewGeolayout(); + Geolayoutscript.Read(data, bankID); + ParseGeolayout(); + } + + public void Read(RomManager rommgr, int segAddress) + { + RenewGeolayout(); + Geolayoutscript.Read(rommgr, segAddress); + ParseGeolayout(); + } + + private void RenewGeolayout() + { + if (!Closed) Close(); + Closed = false; + Geolayoutscript.Clear(); + Geopointers.Clear(); + GeopointerOffsets.Clear(); + Geolayoutscript = new Geolayoutscript(); + ObjectShadow = new ObjectShadow(); + CameraFrustrum = new CameraFrustrum(); + } + + public void ParseGeolayout() + { + var ToRemove = new List(); + int cIndex = 0; + var curMdlScale = System.Numerics.Vector3.One; + var curMdlOffset = System.Numerics.Vector3.Zero; + + foreach (GeolayoutCommand fec in Geolayoutscript) + { + var c = fec; + var switchExpr = c.CommandType; + + switch (switchExpr) + { + case GeolayoutCommandTypes.CameraPreset: + CameraPreset = (CameraPresets)cgCameraPreset.GetCameraPreset(ref c); + break; + case GeolayoutCommandTypes.x18: + var switchExpr1 = (uint)cgx18.GetAsmPointer(ref c); + switch (switchExpr1) + { + case 0x802761D0: + EnvironmentEffect = (EnvironmentEffects)cgx18.GetParam1(ref c); + break; + } + break; + case GeolayoutCommandTypes.LoadDisplaylist: + if (Geopointers.Count == 0) + IndexForGeopointers = cIndex; + Geopointers.Add(new Geopointer(cgLoadDisplayList.GetDrawingLayer(ref c), cgLoadDisplayList.GetSegGeopointer(ref c), curMdlScale, curMdlOffset, cIndex)); + break; + case GeolayoutCommandTypes.ObjectShadown: + cgObjectShadow.GetShadow(c, ObjectShadow); + ObjectShadow.Enabled = true; + break; + case GeolayoutCommandTypes.DrawingDistance: + ObjectShadow.Enabled = false; + break; + case GeolayoutCommandTypes.CameraFrustrum: + cgCameraFrustrum.GetCameraFrustrum(c, CameraFrustrum); + break; + } + + cIndex += 1; + } + + // Remove Geopointercommands + RemoveOldGeopointerCommands(); + } + + public void Write(Stream s, int StartOffset) + { + NewGeoOffset = StartOffset; + var commandsToRemove = new List(); + GeolayoutCommand cmdObjectShadow = null; + GeolayoutCommand cmdDrawingDistance = null; + int tIndexForGeoPointer = IndexForGeopointers; + var isForLevel = false; + + // Einstellungen übernehmen + int currentPosition = 0; + foreach (GeolayoutCommand fec in Geolayoutscript) + { + var c = fec; + var switchExpr = c.CommandType; + + switch (switchExpr) + { + case GeolayoutCommandTypes.CameraPreset: + cgCameraPreset.SetCameraPreset(ref c, Convert.ToByte(CameraPreset)); + break; + case GeolayoutCommandTypes.x18: + var switchExpr1 = cgx18.GetAsmPointer(ref c); + switch ((GeoAsmPointer)switchExpr1) + { + case GeoAsmPointer.EnvironmentEffect: + cgx18.SetParam1(ref c, (ushort)EnvironmentEffect); + break; + } + break; + case GeolayoutCommandTypes.ObjectShadown: + if (ObjectShadow.Enabled) + cmdObjectShadow = c; + else + commandsToRemove.Add(c); + break; + case GeolayoutCommandTypes.DrawingDistance: + if (ObjectShadow.Enabled) + commandsToRemove.Add(c); + else + cmdDrawingDistance = c; + break; + case GeolayoutCommandTypes.CameraFrustrum: + cgCameraFrustrum.SetCameraFrustrum(c, CameraFrustrum); + isForLevel = true; + break; + case GeolayoutCommandTypes.SetScreenRenderArea: + isForLevel = true; + break; + } + + currentPosition += (int)c.Length; + } + + // Insert Geopointers + foreach (Geopointer g in Geopointers) + { + var tcommand = new GeolayoutCommand(new byte[] { 0x15, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }); + cgLoadDisplayList.SetDrawingLayer(ref tcommand, g.Layer); + cgLoadDisplayList.SetSegGeopointer(ref tcommand, g.SegPointer); + if (g.Index == -1) + { + Geolayoutscript.Insert(tIndexForGeoPointer, tcommand); + } + else + { + Geolayoutscript.Insert(g.Index, tcommand); + } + + tIndexForGeoPointer += 1; + } + + // Remove all other commands to remove + foreach (var cmd in commandsToRemove) + { + Geolayoutscript.Remove(cmd); + cmd.Close(); + } + + // Add Geolayout Start command for non-level geolayouts + if (!isForLevel) + { + if (ObjectShadow.Enabled) + { + // Add Object Shadow + if (cmdObjectShadow is null) + { + cmdObjectShadow = new GeolayoutCommand("16 00 00 00 00 00 00 00"); + Geolayoutscript.Insert(0, cmdObjectShadow); + } + cgObjectShadow.SetShadow(cmdObjectShadow, ObjectShadow); + } + else + { + if (cmdDrawingDistance == null) + Geolayoutscript.Insert(0, new GeolayoutCommand("20 00 0F A0")); + } + } + + // Update Geopointer indexes after adding and removing other commands + Geopointers = GetGeopointersFromGeolayoutScript(Geolayoutscript); + + // Write Geolayout to ROM + Geolayoutscript.Write(s, StartOffset); + + // Remove Geopointercommands again + RemoveOldGeopointerCommands(); + } + + public void Close() + { + foreach (var c in Geolayoutscript) + c.Close(); + } + + public override string ToString() + { + string output = ""; + foreach (var cmd in Geolayoutscript) + { + string tbytelist = ""; + foreach (byte b in cmd.ToArray()) + { + if (tbytelist != string.Empty) + tbytelist += " "; + tbytelist += Conversion.Hex(b); + } + + if (output != string.Empty) + output += Environment.NewLine; + output += tbytelist; + } + + return output; + } + + public string ToString(GeolayoutCommandCollection Geolayoutscript) + { + string output = ""; + foreach (var cmd in Geolayoutscript) + { + string tbytelist = ""; + foreach (byte b in cmd.ToArray()) + { + if (tbytelist != string.Empty) + tbytelist += " "; + tbytelist += Conversion.Hex(b); + } + + if (output != string.Empty) + output += Environment.NewLine; + output += tbytelist; + } + + return output; + } + + public enum NewScriptCreationMode + { + None, + Level, + Object + } } \ No newline at end of file diff --git a/SM64Lib/Geolayout/Geopointer.cs b/SM64Lib/Geolayout/Geopointer.cs index 22e2a7e..ee432d3 100644 --- a/SM64Lib/Geolayout/Geopointer.cs +++ b/SM64Lib/Geolayout/Geopointer.cs @@ -1,42 +1,41 @@  using Newtonsoft.Json; -namespace SM64Lib.Geolayout +namespace SM64Lib.Geolayout; + +public class Geopointer { - public class Geopointer + public byte Layer { get; set; } = default; + public int SegPointer { get; set; } = 0; + public int Index { get; set; } = -1; + public System.Numerics.Vector3 ModelScale { get; set; } = System.Numerics.Vector3.One; + public System.Numerics.Vector3 ModelOffset { get; set; } = System.Numerics.Vector3.Zero; + + [JsonConstructor] + private Geopointer() { - public byte Layer { get; set; } = default; - public int SegPointer { get; set; } = 0; - public int Index { get; set; } = -1; - public System.Numerics.Vector3 ModelScale { get; set; } = System.Numerics.Vector3.One; - public System.Numerics.Vector3 ModelOffset { get; set; } = System.Numerics.Vector3.Zero; + } - [JsonConstructor] - private Geopointer() - { - } + public Geopointer(byte Layer) : this() + { + this.Layer = Layer; + } - public Geopointer(byte Layer) : this() - { - this.Layer = Layer; - } + public Geopointer(byte Layer, int SegPointer) : this(Layer) + { + this.SegPointer = SegPointer; + } - public Geopointer(byte Layer, int SegPointer) : this(Layer) - { - this.SegPointer = SegPointer; - } + public Geopointer(byte Layer, int SegPointer, System.Numerics.Vector3 mdlscale, System.Numerics.Vector3 mdloffset) : this(Layer, SegPointer) + { + ModelScale = mdlscale; + ModelOffset = mdloffset; + } - public Geopointer(byte Layer, int SegPointer, System.Numerics.Vector3 mdlscale, System.Numerics.Vector3 mdloffset) : this(Layer, SegPointer) - { - ModelScale = mdlscale; - ModelOffset = mdloffset; - } - - public Geopointer(byte Layer, int SegPointer, System.Numerics.Vector3 mdlscale, System.Numerics.Vector3 mdloffset, int index) : this(Layer, SegPointer) - { - ModelScale = mdlscale; - ModelOffset = mdloffset; - Index = index; - } + public Geopointer(byte Layer, int SegPointer, System.Numerics.Vector3 mdlscale, System.Numerics.Vector3 mdloffset, int index) : this(Layer, SegPointer) + { + ModelScale = mdlscale; + ModelOffset = mdloffset; + Index = index; } } \ No newline at end of file diff --git a/SM64Lib/Geolayout/ObjectShadow.cs b/SM64Lib/Geolayout/ObjectShadow.cs index 1ac5dce..8cb61b2 100644 --- a/SM64Lib/Geolayout/ObjectShadow.cs +++ b/SM64Lib/Geolayout/ObjectShadow.cs @@ -1,16 +1,9 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +namespace SM64Lib.Geolayout; -namespace SM64Lib.Geolayout +public class ObjectShadow { - public class ObjectShadow - { - public bool Enabled { get; set; } = false; - public ObjectShadowType Type { get; set; } = ObjectShadowType.Circle_9Verts; - public short Scale { get; set; } - public byte Solidity { get; set; } = 0xFF; - } + public bool Enabled { get; set; } = false; + public ObjectShadowType Type { get; set; } = ObjectShadowType.Circle_9Verts; + public short Scale { get; set; } + public byte Solidity { get; set; } = 0xFF; } diff --git a/SM64Lib/Geolayout/ObjectShadowType.cs b/SM64Lib/Geolayout/ObjectShadowType.cs index 000e4c6..9058fa7 100644 --- a/SM64Lib/Geolayout/ObjectShadowType.cs +++ b/SM64Lib/Geolayout/ObjectShadowType.cs @@ -1,24 +1,17 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +namespace SM64Lib.Geolayout; -namespace SM64Lib.Geolayout +public enum ObjectShadowType { - public enum ObjectShadowType - { - Circle_9Verts = 0, - Circle_4Verts = 1, - Circle_4Verts_Flat_Unused = 2, - SquarePermanent = 10, - SquareScaleable = 11, - SquareTooglable = 12, - /** - * This defines an offset after which rectangular shadows with custom - * widths and heights can be defined. - */ - RectangleHardcodedOffset = 50, - CirclePlayer = 99 - } + Circle_9Verts = 0, + Circle_4Verts = 1, + Circle_4Verts_Flat_Unused = 2, + SquarePermanent = 10, + SquareScaleable = 11, + SquareTooglable = 12, + /** + * This defines an offset after which rectangular shadows with custom + * widths and heights can be defined. + */ + RectangleHardcodedOffset = 50, + CirclePlayer = 99 } diff --git a/SM64Lib/Geolayout/Script/GeolayoutCommand.cs b/SM64Lib/Geolayout/Script/GeolayoutCommand.cs index 038b8b9..30d1109 100644 --- a/SM64Lib/Geolayout/Script/GeolayoutCommand.cs +++ b/SM64Lib/Geolayout/Script/GeolayoutCommand.cs @@ -2,39 +2,38 @@ using Newtonsoft.Json; using SM64Lib.Json; -namespace SM64Lib.Geolayout.Script +namespace SM64Lib.Geolayout.Script; + +[JsonConverter(typeof(GeolayoutscriptCommandJsonConverter))] +public class GeolayoutCommand : BaseCommand { - [JsonConverter(typeof(GeolayoutscriptCommandJsonConverter))] - public class GeolayoutCommand : BaseCommand + public GeolayoutCommand(byte[] bytes) : base(bytes) { - public GeolayoutCommand(byte[] bytes) : base(bytes) + } + + public GeolayoutCommand() : base() + { + } + + public GeolayoutCommand(string bytes, bool enabledHex = true) : base(bytes, enabledHex) + { + } + + public override GeolayoutCommandTypes CommandType + { + get { + Position = 0; + GeolayoutCommandTypes t = (GeolayoutCommandTypes)ReadByte(); + Position = 0; + return t; } - public GeolayoutCommand() : base() + set { - } - - public GeolayoutCommand(string bytes, bool enabledHex = true) : base(bytes, enabledHex) - { - } - - public override GeolayoutCommandTypes CommandType - { - get - { - Position = 0; - GeolayoutCommandTypes t = (GeolayoutCommandTypes)ReadByte(); - Position = 0; - return t; - } - - set - { - Position = 0; - WriteByte((byte)value); - Position = 0; - } + Position = 0; + WriteByte((byte)value); + Position = 0; } } } \ No newline at end of file diff --git a/SM64Lib/Geolayout/Script/GeolayoutCommandCollection.cs b/SM64Lib/Geolayout/Script/GeolayoutCommandCollection.cs index 962f77f..da20439 100644 --- a/SM64Lib/Geolayout/Script/GeolayoutCommandCollection.cs +++ b/SM64Lib/Geolayout/Script/GeolayoutCommandCollection.cs @@ -1,18 +1,17 @@ using global::SM64Lib.Script; -namespace SM64Lib.Geolayout.Script -{ - public class GeolayoutCommandCollection : BaseCommandCollection - { - public int IndexOfFirst(GeolayoutCommandTypes cmdType) - { - for (int index = 0, loopTo = Count - 1; index <= loopTo; index++) - { - if (this[index].CommandType == cmdType) - return index; - } +namespace SM64Lib.Geolayout.Script; - return -1; +public class GeolayoutCommandCollection : BaseCommandCollection +{ + public int IndexOfFirst(GeolayoutCommandTypes cmdType) + { + for (int index = 0, loopTo = Count - 1; index <= loopTo; index++) + { + if (this[index].CommandType == cmdType) + return index; } + + return -1; } } \ No newline at end of file diff --git a/SM64Lib/Geolayout/Script/GeolayoutCommandFunctions.cs b/SM64Lib/Geolayout/Script/GeolayoutCommandFunctions.cs index 08bb254..f33ef06 100644 --- a/SM64Lib/Geolayout/Script/GeolayoutCommandFunctions.cs +++ b/SM64Lib/Geolayout/Script/GeolayoutCommandFunctions.cs @@ -1,5 +1,4 @@ using global::System.Numerics; -using Microsoft.VisualBasic.CompilerServices; using System; namespace SM64Lib.Geolayout.Script diff --git a/SM64Lib/Geolayout/Script/GeolayoutCommandTypes.cs b/SM64Lib/Geolayout/Script/GeolayoutCommandTypes.cs index f05aa9d..9c2890a 100644 --- a/SM64Lib/Geolayout/Script/GeolayoutCommandTypes.cs +++ b/SM64Lib/Geolayout/Script/GeolayoutCommandTypes.cs @@ -1,37 +1,36 @@  -namespace SM64Lib.Geolayout.Script +namespace SM64Lib.Geolayout.Script; + +public enum GeolayoutCommandTypes { - public enum GeolayoutCommandTypes - { - BranchAndStore = 0x0, - EndOfGeolayout = 0x1, - JumpToSegAddr = 0x2, - JumpBack = 0x3, - StartOfNode = 0x4, - EndOfNode = 0x5, - SetScreenRenderArea = 0x8, - Scale1 = 0x9, - CameraFrustrum = 0xA, - x0B = 0xB, - x0C = 0xC, - x0D = 0xD, - x0E = 0xE, - CameraPreset = 0xF, - x10 = 0x10, - x11 = 0x11, - x12 = 0x12, - LoadDisplaylistWithOffset = 0x13, - BillboardModel = 0x14, - LoadDisplaylist = 0x15, - ObjectShadown = 0x16, - x17 = 0x17, - x18 = 0x18, - Background = 0x19, - x1A = 0x1A, - x1C = 0x1C, - Scale2 = 0x1D, - x1E = 0xE, - x1f = 0xF, - DrawingDistance = 0x20 - } + BranchAndStore = 0x0, + EndOfGeolayout = 0x1, + JumpToSegAddr = 0x2, + JumpBack = 0x3, + StartOfNode = 0x4, + EndOfNode = 0x5, + SetScreenRenderArea = 0x8, + Scale1 = 0x9, + CameraFrustrum = 0xA, + x0B = 0xB, + x0C = 0xC, + x0D = 0xD, + x0E = 0xE, + CameraPreset = 0xF, + x10 = 0x10, + x11 = 0x11, + x12 = 0x12, + LoadDisplaylistWithOffset = 0x13, + BillboardModel = 0x14, + LoadDisplaylist = 0x15, + ObjectShadown = 0x16, + x17 = 0x17, + x18 = 0x18, + Background = 0x19, + x1A = 0x1A, + x1C = 0x1C, + Scale2 = 0x1D, + x1E = 0xE, + x1f = 0xF, + DrawingDistance = 0x20 } \ No newline at end of file diff --git a/SM64Lib/Geolayout/Script/Geolayoutscript.cs b/SM64Lib/Geolayout/Script/Geolayoutscript.cs index 2ca3969..fb7da9a 100644 --- a/SM64Lib/Geolayout/Script/Geolayoutscript.cs +++ b/SM64Lib/Geolayout/Script/Geolayoutscript.cs @@ -1,239 +1,237 @@ -using System.Collections.Generic; +using global::SM64Lib.Data; using global::System.IO; -using System.Threading.Tasks; -using Microsoft.VisualBasic.CompilerServices; -using global::SM64Lib.Data; using SM64Lib.SegmentedBanking; using System; +using System.Collections.Generic; +using System.Threading.Tasks; -namespace SM64Lib.Geolayout.Script +namespace SM64Lib.Geolayout.Script; + +public class Geolayoutscript : GeolayoutCommandCollection { - public class Geolayoutscript : GeolayoutCommandCollection + public List GeopointerOffsets = new List(); + + public Geolayoutscript() { - public List GeopointerOffsets = new List(); + } - public Geolayoutscript() - { - } + public Task ReadAsync(RomManager rommgr, int segAddress) + { + var t = new Task(() => Read(rommgr, segAddress)); + t.Start(); + return t; + } - 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(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(RomManager rommgr, int segAddress) + public void Read(SegmentedBank segBank, int offset) + { + Close(); + Clear(); + GeopointerOffsets.Clear(); + if (segBank is null) + return; + var data = new BinaryStreamData(segBank.Data); + data.Position = offset; + var tb = new List(); + GeolayoutCommandTypes cb = default; + int subNodeIndex = 0; + bool ende = false; + while (!ende) { - 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); - 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) { - if (data.Position >= data.Length) + case GeolayoutCommandTypes.Background: + lenth = 0x8; 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) + 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; + } - for (int i = 1, loopTo = lenth; i <= loopTo; i++) - tb.Add(data.ReadByte()); + 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; + } - 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; + segBank.Data.Position -= 1; break; - case GeolayoutCommandTypes.EndOfNode: - subNodeIndex -= 1; - break; - case GeolayoutCommandTypes.StartOfNode: - subNodeIndex += 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; } - } - public void Write(Stream s, int GeolayoutStart) - { - var bw = new BinaryWriter(s); + segBank.Data.Position -= 1; + if (lenth == 0 || segBank.Data.Position + lenth > segBank.Data.Length) + break; - // Write new Levelscript - s.Position = GeolayoutStart; - foreach (GeolayoutCommand c in this) + 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) { - if (c.CommandType == GeolayoutCommandTypes.LoadDisplaylist) - GeopointerOffsets.Add((int)(s.Position + 0x4)); - foreach (byte b in c.ToArray()) - bw.Write(b); + case GeolayoutCommandTypes.EndOfGeolayout: + ende = true; + break; + case GeolayoutCommandTypes.EndOfNode: + subNodeIndex -= 1; + break; + case GeolayoutCommandTypes.StartOfNode: + subNodeIndex += 1; + break; } } - - public GeolayoutCommand GetFirst(GeolayoutCommandTypes cmdType) - { - foreach (GeolayoutCommand cmd in this) - { - if (cmd.CommandType == cmdType) - { - return cmd; - } - } - - return null; - } + } + + 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; } } \ No newline at end of file diff --git a/SM64Lib/Geolayout/TerrainType.cs b/SM64Lib/Geolayout/TerrainType.cs index 47c57a0..d9389c9 100644 --- a/SM64Lib/Geolayout/TerrainType.cs +++ b/SM64Lib/Geolayout/TerrainType.cs @@ -1,14 +1,13 @@  -namespace SM64Lib.Geolayout +namespace SM64Lib.Geolayout; + +public enum TerrainTypes { - public enum TerrainTypes - { - NoramlA = 0x0, - NoramlB, - SnowTerrain, - SandTerrain, - BigBoosHount, - WaterLevels, - SlipperySlide - } + NoramlA = 0x0, + NoramlB, + SnowTerrain, + SandTerrain, + BigBoosHount, + WaterLevels, + SlipperySlide } \ No newline at end of file diff --git a/SM64Lib/Json/ArrayReferencePreservngConverter.cs b/SM64Lib/Json/ArrayReferencePreservngConverter.cs index 258f5a9..6486cb7 100644 --- a/SM64Lib/Json/ArrayReferencePreservngConverter.cs +++ b/SM64Lib/Json/ArrayReferencePreservngConverter.cs @@ -1,87 +1,83 @@ using Newtonsoft.Json; -using System; -using System.Collections.Generic; -using System.Collections; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Newtonsoft.Json.Linq; +using System; +using System.Collections; +using System.Collections.Generic; -namespace SM64Lib.Json +namespace SM64Lib.Json; + +public class ArrayReferencePreservngConverter : JsonConverter { - public class ArrayReferencePreservngConverter : JsonConverter + const string refProperty = "$ref"; + const string idProperty = "$id"; + const string valuesProperty = "$values"; + + public override bool CanConvert(Type objectType) { - const string refProperty = "$ref"; - const string idProperty = "$id"; - const string valuesProperty = "$values"; + return objectType.IsArray; + } - public override bool CanConvert(Type objectType) + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + if (reader.TokenType == JsonToken.Null) + return null; + else if (reader.TokenType == JsonToken.StartArray) { - return objectType.IsArray; - } - - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) - { - if (reader.TokenType == JsonToken.Null) + // No $ref. Deserialize as a List to avoid infinite recursion and return as an array. + var elementType = objectType.GetElementType(); + var listType = typeof(List<>).MakeGenericType(elementType); + var list = (IList)serializer.Deserialize(reader, listType); + if (list == null) return null; - else if (reader.TokenType == JsonToken.StartArray) - { - // No $ref. Deserialize as a List to avoid infinite recursion and return as an array. - var elementType = objectType.GetElementType(); - var listType = typeof(List<>).MakeGenericType(elementType); - var list = (IList)serializer.Deserialize(reader, listType); - if (list == null) - return null; - var array = Array.CreateInstance(elementType, list.Count); - list.CopyTo(array, 0); - return array; - } - else - { - var obj = JObject.Load(reader); - var refId = (string)obj[refProperty]; - if (refId != null) - { - var reference = serializer.ReferenceResolver.ResolveReference(serializer, refId); - if (reference != null) - return reference; - } - var values = obj[valuesProperty]; - if (values == null || values.Type == JTokenType.Null) - return null; - if (!(values is JArray)) - { - throw new JsonSerializationException(string.Format("{0} was not an array", values)); - } - var count = ((JArray)values).Count; - - var elementType = objectType.GetElementType(); - var array = Array.CreateInstance(elementType, count); - - var objId = (string)obj[idProperty]; - if (objId != null) - { - // Add the empty array into the reference table BEFORE poppulating it, - // to handle recursive references. - serializer.ReferenceResolver.AddReference(serializer, objId, array); - } - - var listType = typeof(List<>).MakeGenericType(elementType); - using (var subReader = values.CreateReader()) - { - var list = (IList)serializer.Deserialize(subReader, listType); - list.CopyTo(array, 0); - } - - return array; - } + var array = Array.CreateInstance(elementType, list.Count); + list.CopyTo(array, 0); + return array; } - - public override bool CanWrite { get { return false; } } - - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + else { - throw new NotImplementedException(); + var obj = JObject.Load(reader); + var refId = (string)obj[refProperty]; + if (refId != null) + { + var reference = serializer.ReferenceResolver.ResolveReference(serializer, refId); + if (reference != null) + return reference; + } + var values = obj[valuesProperty]; + if (values == null || values.Type == JTokenType.Null) + return null; + if (!(values is JArray)) + { + throw new JsonSerializationException(string.Format("{0} was not an array", values)); + } + var count = ((JArray)values).Count; + + var elementType = objectType.GetElementType(); + var array = Array.CreateInstance(elementType, count); + + var objId = (string)obj[idProperty]; + if (objId != null) + { + // Add the empty array into the reference table BEFORE poppulating it, + // to handle recursive references. + serializer.ReferenceResolver.AddReference(serializer, objId, array); + } + + var listType = typeof(List<>).MakeGenericType(elementType); + using (var subReader = values.CreateReader()) + { + var list = (IList)serializer.Deserialize(subReader, listType); + list.CopyTo(array, 0); + } + + return array; } } + + public override bool CanWrite { get { return false; } } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + throw new NotImplementedException(); + } } diff --git a/SM64Lib/Json/BaseCommandJsonConverter.cs b/SM64Lib/Json/BaseCommandJsonConverter.cs index 9970213..9cdaae0 100644 --- a/SM64Lib/Json/BaseCommandJsonConverter.cs +++ b/SM64Lib/Json/BaseCommandJsonConverter.cs @@ -1,61 +1,54 @@ using Newtonsoft.Json; -using SM64Lib.Behaviors.Script; using SM64Lib.Geolayout.Script; -using SM64Lib.Model.Fast3D; using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace SM64Lib.Json +namespace SM64Lib.Json; + +internal class BaseCommandJsonConverter : JsonConverter { - internal class BaseCommandJsonConverter : JsonConverter + public override bool CanConvert(Type objectType) { - public override bool CanConvert(Type objectType) + return typeof(GeolayoutscriptCommandJsonConverter).IsAssignableFrom(objectType); + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + var export = serializer.Deserialize(reader); + GeolayoutCommand c; + + if (existingValue is not null) + c = (GeolayoutCommand)existingValue; + else + c = new GeolayoutCommand(); + + if (export?.Buffer is not null) { - return typeof(GeolayoutscriptCommandJsonConverter).IsAssignableFrom(objectType); + c.Position = 0; + c.Write(export.Buffer, 0, export.Buffer.Length); + c.Position = 0; } - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + c.BankAddress = export.BankAddress; + + return c; + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + var cmd = (GeolayoutCommand)value; + + var export = new CmdExport { - var export = serializer.Deserialize(reader); - GeolayoutCommand c; + Buffer = cmd.ToArray(), + BankAddress = cmd.BankAddress + }; - if (existingValue is not null) - c = (GeolayoutCommand)existingValue; - else - c = new GeolayoutCommand(); + serializer.Serialize(writer, export); + } - if (export?.Buffer is not null) - { - c.Position = 0; - c.Write(export.Buffer, 0, export.Buffer.Length); - c.Position = 0; - } - - c.BankAddress = export.BankAddress; - - return c; - } - - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) - { - var cmd = (GeolayoutCommand)value; - - var export = new CmdExport - { - Buffer = cmd.ToArray(), - BankAddress = cmd.BankAddress - }; - - serializer.Serialize(writer, export); - } - - private class CmdExport - { - public byte[] Buffer { get; set; } - public int BankAddress { get; set; } - } + private class CmdExport + { + public byte[] Buffer { get; set; } + public int BankAddress { get; set; } } } diff --git a/SM64Lib/Json/BehaviorscriptCommandJsonConverter.cs b/SM64Lib/Json/BehaviorscriptCommandJsonConverter.cs index 914a3d1..4e07e46 100644 --- a/SM64Lib/Json/BehaviorscriptCommandJsonConverter.cs +++ b/SM64Lib/Json/BehaviorscriptCommandJsonConverter.cs @@ -1,60 +1,54 @@ using Newtonsoft.Json; using SM64Lib.Behaviors.Script; -using SM64Lib.Model.Fast3D; using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace SM64Lib.Json +namespace SM64Lib.Json; + +internal class BehaviorscriptCommandJsonConverter : JsonConverter { - internal class BehaviorscriptCommandJsonConverter : JsonConverter + public override bool CanConvert(Type objectType) { - public override bool CanConvert(Type objectType) + return typeof(BehaviorscriptCommand).IsAssignableFrom(objectType); + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + var export = serializer.Deserialize(reader); + BehaviorscriptCommand c; + + if (existingValue is not null) + c = (BehaviorscriptCommand)existingValue; + else + c = new BehaviorscriptCommand(); + + if (export?.Buffer is not null) { - return typeof(BehaviorscriptCommand).IsAssignableFrom(objectType); + c.Position = 0; + c.Write(export.Buffer, 0, export.Buffer.Length); + c.Position = 0; } - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + c.BankAddress = export.BankAddress; + + return c; + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + var cmd = (BehaviorscriptCommand)value; + + var export = new CmdExport { - var export = serializer.Deserialize(reader); - BehaviorscriptCommand c; + Buffer = cmd.ToArray(), + BankAddress = cmd.BankAddress + }; - if (existingValue is not null) - c = (BehaviorscriptCommand)existingValue; - else - c = new BehaviorscriptCommand(); + serializer.Serialize(writer, export); + } - if (export?.Buffer is not null) - { - c.Position = 0; - c.Write(export.Buffer, 0, export.Buffer.Length); - c.Position = 0; - } - - c.BankAddress = export.BankAddress; - - return c; - } - - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) - { - var cmd = (BehaviorscriptCommand)value; - - var export = new CmdExport - { - Buffer = cmd.ToArray(), - BankAddress = cmd.BankAddress - }; - - serializer.Serialize(writer, export); - } - - private class CmdExport - { - public byte[] Buffer { get; set; } - public int BankAddress { get; set; } - } + private class CmdExport + { + public byte[] Buffer { get; set; } + public int BankAddress { get; set; } } } diff --git a/SM64Lib/Json/ComplexDictionarJsonConverter.cs b/SM64Lib/Json/ComplexDictionarJsonConverter.cs index f8f4189..1624a52 100644 --- a/SM64Lib/Json/ComplexDictionarJsonConverter.cs +++ b/SM64Lib/Json/ComplexDictionarJsonConverter.cs @@ -1,35 +1,30 @@ using Newtonsoft.Json; -using SM64Lib.Model.Fast3D; using System; -using System.Collections; using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; using Z.Collections.Extensions; -namespace SM64Lib.Json +namespace SM64Lib.Json; + +internal class ComplexDictionarJsonConverter : JsonConverter { - internal class ComplexDictionarJsonConverter : JsonConverter + public override bool CanConvert(Type objectType) { - public override bool CanConvert(Type objectType) - { - return typeof(List>).IsAssignableFrom(objectType); - } + return typeof(List>).IsAssignableFrom(objectType); + } - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) - { - var list = serializer.Deserialize>>(reader); - var dic = new Dictionary(); - dic.AddRange(list.ToArray()); + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + var list = serializer.Deserialize>>(reader); + var dic = new Dictionary(); + dic.AddRange(list.ToArray()); - return dic; - } + return dic; + } - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) - { - if (value is Dictionary) - serializer.Serialize(writer, ((Dictionary)value).ToArray()); - } + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + if (value is Dictionary) + serializer.Serialize(writer, ((Dictionary)value).ToArray()); } } diff --git a/SM64Lib/Json/Fast3DBufferJsonConverter.cs b/SM64Lib/Json/Fast3DBufferJsonConverter.cs index 5fe3117..5632be3 100644 --- a/SM64Lib/Json/Fast3DBufferJsonConverter.cs +++ b/SM64Lib/Json/Fast3DBufferJsonConverter.cs @@ -2,70 +2,66 @@ using SM64Lib.Model.Fast3D; using System; using System.Collections.Generic; -using System.IO; using System.IO.Compression; using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace SM64Lib.Json +namespace SM64Lib.Json; + +internal class Fast3DBufferJsonConverter : JsonConverter { - internal class Fast3DBufferJsonConverter : JsonConverter + public override bool CanConvert(Type objectType) { - public override bool CanConvert(Type objectType) - { - return typeof(Fast3DBuffer).IsAssignableFrom(objectType); - } + return typeof(Fast3DBuffer).IsAssignableFrom(objectType); + } - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) - { - var export = serializer.Deserialize(reader); - Fast3DBuffer c; + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + var export = serializer.Deserialize(reader); + Fast3DBuffer c; - if (existingValue is not null) - c = (Fast3DBuffer)existingValue; + if (existingValue is not null) + c = (Fast3DBuffer)existingValue; + else + c = new Fast3DBuffer(); + + if (export?.Buffer is not null) + { + c.Position = 0; + + if (export.IsDeflateStream) + General.DecompressData(export.Buffer, c); else - c = new Fast3DBuffer(); + c.Write(export.Buffer, 0, export.Buffer.Length); - if (export?.Buffer is not null) - { - c.Position = 0; - - if (export.IsDeflateStream) - General.DecompressData(export.Buffer, c); - else - c.Write(export.Buffer, 0, export.Buffer.Length); - - c.Position = 0; - } - - c.Fast3DBankStart = export.Fast3DBankStart; - c.DLPointers = export.DLPointers.ToArray(); - - return c; + c.Position = 0; } - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + c.Fast3DBankStart = export.Fast3DBankStart; + c.DLPointers = export.DLPointers.ToArray(); + + return c; + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + var buffer = (Fast3DBuffer)value; + var export = new Fast3DBufferExport { - var buffer = (Fast3DBuffer)value; - var export = new Fast3DBufferExport - { - Buffer = General.CompressData(buffer, CompressionLevel.Fastest), - Fast3DBankStart = buffer.Fast3DBankStart, - DLPointers = buffer.DLPointers.ToList(), - IsDeflateStream = true - }; - buffer.Position = 0; + Buffer = General.CompressData(buffer, CompressionLevel.Fastest), + Fast3DBankStart = buffer.Fast3DBankStart, + DLPointers = buffer.DLPointers.ToList(), + IsDeflateStream = true + }; + buffer.Position = 0; - serializer.Serialize(writer, export); - } + serializer.Serialize(writer, export); + } - private class Fast3DBufferExport - { - public byte[] Buffer { get; set; } - public int Fast3DBankStart { get; set; } - public List DLPointers { get; set; } - public bool IsDeflateStream { get; set; } = false; - } + private class Fast3DBufferExport + { + public byte[] Buffer { get; set; } + public int Fast3DBankStart { get; set; } + public List DLPointers { get; set; } + public bool IsDeflateStream { get; set; } = false; } } diff --git a/SM64Lib/Json/GeolayoutscriptCommandJsonConverter.cs b/SM64Lib/Json/GeolayoutscriptCommandJsonConverter.cs index 1349575..c359e20 100644 --- a/SM64Lib/Json/GeolayoutscriptCommandJsonConverter.cs +++ b/SM64Lib/Json/GeolayoutscriptCommandJsonConverter.cs @@ -1,61 +1,54 @@ using Newtonsoft.Json; -using SM64Lib.Behaviors.Script; using SM64Lib.Geolayout.Script; -using SM64Lib.Model.Fast3D; using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace SM64Lib.Json +namespace SM64Lib.Json; + +internal class GeolayoutscriptCommandJsonConverter : JsonConverter { - internal class GeolayoutscriptCommandJsonConverter : JsonConverter + public override bool CanConvert(Type objectType) { - public override bool CanConvert(Type objectType) + return typeof(GeolayoutCommand).IsAssignableFrom(objectType); + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + var export = serializer.Deserialize(reader); + GeolayoutCommand c; + + if (existingValue is not null) + c = (GeolayoutCommand)existingValue; + else + c = new GeolayoutCommand(); + + if (export?.Buffer is not null) { - return typeof(GeolayoutCommand).IsAssignableFrom(objectType); + c.Position = 0; + c.Write(export.Buffer, 0, export.Buffer.Length); + c.Position = 0; } - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + c.BankAddress = export.BankAddress; + + return c; + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + var cmd = (GeolayoutCommand)value; + + var export = new CmdExport { - var export = serializer.Deserialize(reader); - GeolayoutCommand c; + Buffer = cmd.ToArray(), + BankAddress = cmd.BankAddress + }; - if (existingValue is not null) - c = (GeolayoutCommand)existingValue; - else - c = new GeolayoutCommand(); + serializer.Serialize(writer, export); + } - if (export?.Buffer is not null) - { - c.Position = 0; - c.Write(export.Buffer, 0, export.Buffer.Length); - c.Position = 0; - } - - c.BankAddress = export.BankAddress; - - return c; - } - - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) - { - var cmd = (GeolayoutCommand)value; - - var export = new CmdExport - { - Buffer = cmd.ToArray(), - BankAddress = cmd.BankAddress - }; - - serializer.Serialize(writer, export); - } - - private class CmdExport - { - public byte[] Buffer { get; set; } - public int BankAddress { get; set; } - } + private class CmdExport + { + public byte[] Buffer { get; set; } + public int BankAddress { get; set; } } } diff --git a/SM64Lib/Json/JsonHelper.cs b/SM64Lib/Json/JsonHelper.cs index 73439ec..041afce 100644 --- a/SM64Lib/Json/JsonHelper.cs +++ b/SM64Lib/Json/JsonHelper.cs @@ -1,36 +1,30 @@ using Newtonsoft.Json; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace SM64Lib.Json +namespace SM64Lib.Json; + +internal class JsonHelper { - internal class JsonHelper + public static JsonSerializer CreateJsonSerializer( + bool allowReferences = false, + bool rememberTypeNames = false, + bool enableIndentedFormatting = true) { - public static JsonSerializer CreateJsonSerializer( - bool allowReferences = false, - bool rememberTypeNames = false, - bool enableIndentedFormatting = true) + var serializer = JsonSerializer.CreateDefault(); + + if (enableIndentedFormatting) + serializer.Formatting = Formatting.Indented; + + if (rememberTypeNames) + serializer.TypeNameHandling = TypeNameHandling.Auto; + + if (allowReferences) { - var serializer = JsonSerializer.CreateDefault(); - - if (enableIndentedFormatting) - serializer.Formatting = Formatting.Indented; - - if (rememberTypeNames) - serializer.TypeNameHandling = TypeNameHandling.Auto; - - if (allowReferences) - { - serializer.PreserveReferencesHandling = PreserveReferencesHandling.All; - serializer.ReferenceLoopHandling = ReferenceLoopHandling.Serialize; - } - - serializer.Converters.Add(new MemoryStreamJsonConverter()); - - return serializer; + serializer.PreserveReferencesHandling = PreserveReferencesHandling.All; + serializer.ReferenceLoopHandling = ReferenceLoopHandling.Serialize; } + + serializer.Converters.Add(new MemoryStreamJsonConverter()); + + return serializer; } } diff --git a/SM64Lib/Json/LevelscriptCommandJsonConverter.cs b/SM64Lib/Json/LevelscriptCommandJsonConverter.cs index fcc71cb..4ae62b0 100644 --- a/SM64Lib/Json/LevelscriptCommandJsonConverter.cs +++ b/SM64Lib/Json/LevelscriptCommandJsonConverter.cs @@ -1,62 +1,54 @@ using Newtonsoft.Json; -using SM64Lib.Behaviors.Script; -using SM64Lib.Geolayout.Script; using SM64Lib.Levels.Script; -using SM64Lib.Model.Fast3D; using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace SM64Lib.Json +namespace SM64Lib.Json; + +internal class LevelscriptCommandJsonConverter : JsonConverter { - internal class LevelscriptCommandJsonConverter : JsonConverter + public override bool CanConvert(Type objectType) { - public override bool CanConvert(Type objectType) + return typeof(LevelscriptCommand).IsAssignableFrom(objectType); + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + var export = serializer.Deserialize(reader); + LevelscriptCommand c; + + if (existingValue is not null) + c = (LevelscriptCommand)existingValue; + else + c = new LevelscriptCommand(); + + if (export?.Buffer is not null) { - return typeof(LevelscriptCommand).IsAssignableFrom(objectType); + c.Position = 0; + c.Write(export.Buffer, 0, export.Buffer.Length); + c.Position = 0; } - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + c.BankAddress = export.BankAddress; + + return c; + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + var cmd = (LevelscriptCommand)value; + + var export = new CmdExport { - var export = serializer.Deserialize(reader); - LevelscriptCommand c; + Buffer = cmd.ToArray(), + BankAddress = cmd.BankAddress + }; - if (existingValue is not null) - c = (LevelscriptCommand)existingValue; - else - c = new LevelscriptCommand(); + serializer.Serialize(writer, export); + } - if (export?.Buffer is not null) - { - c.Position = 0; - c.Write(export.Buffer, 0, export.Buffer.Length); - c.Position = 0; - } - - c.BankAddress = export.BankAddress; - - return c; - } - - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) - { - var cmd = (LevelscriptCommand)value; - - var export = new CmdExport - { - Buffer = cmd.ToArray(), - BankAddress = cmd.BankAddress - }; - - serializer.Serialize(writer, export); - } - - private class CmdExport - { - public byte[] Buffer { get; set; } - public int BankAddress { get; set; } - } + private class CmdExport + { + public byte[] Buffer { get; set; } + public int BankAddress { get; set; } } } diff --git a/SM64Lib/Json/MemoryStreamJsonConverter.cs b/SM64Lib/Json/MemoryStreamJsonConverter.cs index d473ae0..841cf0c 100644 --- a/SM64Lib/Json/MemoryStreamJsonConverter.cs +++ b/SM64Lib/Json/MemoryStreamJsonConverter.cs @@ -1,37 +1,28 @@ using Newtonsoft.Json; -using SM64Lib.Behaviors.Script; -using SM64Lib.Geolayout.Script; -using SM64Lib.Levels.Script; -using SM64Lib.Model.Fast3D; using System; -using System.Collections.Generic; using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace SM64Lib.Json +namespace SM64Lib.Json; + +internal class MemoryStreamJsonConverter : JsonConverter { - internal class MemoryStreamJsonConverter : JsonConverter + public override bool CanConvert(Type objectType) { - public override bool CanConvert(Type objectType) - { - return typeof(MemoryStream).IsAssignableFrom(objectType); - } + return typeof(MemoryStream).IsAssignableFrom(objectType); + } - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) - { - var msData = serializer.Deserialize(reader); - var ms = new MemoryStream(); - ms.Write(msData, 0, msData.Length); - ms.Position = 0; - return ms; - } + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + var msData = serializer.Deserialize(reader); + var ms = new MemoryStream(); + ms.Write(msData, 0, msData.Length); + ms.Position = 0; + return ms; + } - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) - { - var ms = (MemoryStream)value; - serializer.Serialize(writer, ms.ToArray()); - } + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + var ms = (MemoryStream)value; + serializer.Serialize(writer, ms.ToArray()); } } diff --git a/SM64Lib/Level/AreaBG.cs b/SM64Lib/Level/AreaBG.cs index 548e406..81b8fc4 100644 --- a/SM64Lib/Level/AreaBG.cs +++ b/SM64Lib/Level/AreaBG.cs @@ -1,16 +1,15 @@ using global::System.Drawing; -namespace SM64Lib.Levels -{ - public class AreaBG - { - public AreaBGs Type { get; set; } = AreaBGs.Levelbackground; - public Color Color { get; set; } = Color.Black; - } +namespace SM64Lib.Levels; - public enum AreaBGs - { - Levelbackground, - Color - } +public class AreaBG +{ + public AreaBGs Type { get; set; } = AreaBGs.Levelbackground; + public Color Color { get; set; } = Color.Black; +} + +public enum AreaBGs +{ + Levelbackground, + Color } \ No newline at end of file diff --git a/SM64Lib/Level/AreaReverbLevel.cs b/SM64Lib/Level/AreaReverbLevel.cs index 3669380..b06c948 100644 --- a/SM64Lib/Level/AreaReverbLevel.cs +++ b/SM64Lib/Level/AreaReverbLevel.cs @@ -1,23 +1,16 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +namespace SM64Lib.Levels; -namespace SM64Lib.Levels +public enum AreaReverbLevel : byte { - public enum AreaReverbLevel : byte - { - None, - Level01 = 0x8, - Level02 = 0xC, - Level03 = 0x10, - Level04 = 0x18, - Level05 = 0x20, - Level06 = 0x28, - Level07 = 0x30, - Level08 = 0x38, - Level09 = 0x40, - Level10 = 0x70 - } + None, + Level01 = 0x8, + Level02 = 0xC, + Level03 = 0x10, + Level04 = 0x18, + Level05 = 0x20, + Level06 = 0x28, + Level07 = 0x30, + Level08 = 0x38, + Level09 = 0x40, + Level10 = 0x70 } diff --git a/SM64Lib/Level/Enums.cs b/SM64Lib/Level/Enums.cs index c4a809b..312852c 100644 --- a/SM64Lib/Level/Enums.cs +++ b/SM64Lib/Level/Enums.cs @@ -1,123 +1,122 @@  -namespace SM64Lib.Levels +namespace SM64Lib.Levels; + +public enum ObjectBank0x0C { - public enum ObjectBank0x0C - { - Disabled, - HauntedObjects, - SnowObjects, - AssortedEnemies1, - DesertObjects, - BigBobOmbBoss, - AssortedEnemies2, - WaterObjects, - AssortedEnemies3, - PeachYoshi, - Switches, - LavaObjects - } + Disabled, + HauntedObjects, + SnowObjects, + AssortedEnemies1, + DesertObjects, + BigBobOmbBoss, + AssortedEnemies2, + WaterObjects, + AssortedEnemies3, + PeachYoshi, + Switches, + LavaObjects +} - public enum ObjectBank0x0D - { - Disabled, - AssortedEnemies4, - Moneybags, - CastleObjects, - GroundEnemies, - WaterObjects2, - Bowser - } +public enum ObjectBank0x0D +{ + Disabled, + AssortedEnemies4, + Moneybags, + CastleObjects, + GroundEnemies, + WaterObjects2, + Bowser +} - public enum ObjectBank0x0E - { - Disabled, - HaundetHouse, - CoolCoolMountain, - InsideCastle, - HazyMazeCave, - ShiftingSandLand, - BobOmbBattlefield, - SnowandsLand, - WetDryWorld, - JollyRogerBay, - TinyHugeIsland, - TickTockClock, - RainbowRide, - CastleGrounds, - Bowser1Course, - VanishCap, - Bowser2Course, - Bowser3Course, - LethalLavaLand, - DireDireDocks, - WhompsFortress, - CastleCourtyard, - WingCap, - Bowser2Battle, - Bowser3Battle, - TallTallMountain - } +public enum ObjectBank0x0E +{ + Disabled, + HaundetHouse, + CoolCoolMountain, + InsideCastle, + HazyMazeCave, + ShiftingSandLand, + BobOmbBattlefield, + SnowandsLand, + WetDryWorld, + JollyRogerBay, + TinyHugeIsland, + TickTockClock, + RainbowRide, + CastleGrounds, + Bowser1Course, + VanishCap, + Bowser2Course, + Bowser3Course, + LethalLavaLand, + DireDireDocks, + WhompsFortress, + CastleCourtyard, + WingCap, + Bowser2Battle, + Bowser3Battle, + TallTallMountain +} - public enum ObjectBanks - { - Bank0x0C, - Bank0x0D, - Bank0x0E - } +public enum ObjectBanks +{ + Bank0x0C, + Bank0x0D, + Bank0x0E +} - public enum Levels : byte - { - HaundetHouse = 0x4, - CoolCoolMountain, - InsideCastle, - HazyMazeCave, - ShiftingSandLand, - BobOmbsBattlefield, - SnowManLand, - WetDryWorld, - JollyRogerBay, - TinyHugeIsland, - TickTockClock, - RainbowRide, - CastleGrounds, - Bowser1Course, - VanishCap, - Bowser2Course, - SecretAquarium, - Bowser3Course, - LethalLavaLand, - DireDireDocks, - WhompsFortress, - EndCakePicture, - CastleCourtyard, - PeachsSecretSlide, - MetalCap, - WingCap, - Bowser1Battle, - RainbowClouds, - Bowser2Battle = 0x21, - Bowser3Battle, - TallTallMountain = 0x24 - } +public enum Levels : byte +{ + HaundetHouse = 0x4, + CoolCoolMountain, + InsideCastle, + HazyMazeCave, + ShiftingSandLand, + BobOmbsBattlefield, + SnowManLand, + WetDryWorld, + JollyRogerBay, + TinyHugeIsland, + TickTockClock, + RainbowRide, + CastleGrounds, + Bowser1Course, + VanishCap, + Bowser2Course, + SecretAquarium, + Bowser3Course, + LethalLavaLand, + DireDireDocks, + WhompsFortress, + EndCakePicture, + CastleCourtyard, + PeachsSecretSlide, + MetalCap, + WingCap, + Bowser1Battle, + RainbowClouds, + Bowser2Battle = 0x21, + Bowser3Battle, + TallTallMountain = 0x24 +} - public enum ScrollingTextureAxis - { - X, - Y - } +public enum ScrollingTextureAxis +{ + X, + Y +} - public enum SpecialBoxType - { - Water, - ToxicHaze, - Mist - } +public enum SpecialBoxType +{ + Water, + ToxicHaze, + Mist +} - public enum WaterType - { - Default = 0x0, - JRBWater = 0x20000, - GreenWater = 0x30000, - LavaWater = 0x40000 - } +public enum WaterType +{ + Default = 0x0, + JRBWater = 0x20000, + GreenWater = 0x30000, + LavaWater = 0x40000 } \ No newline at end of file diff --git a/SM64Lib/Level/ILevelManager.cs b/SM64Lib/Level/ILevelManager.cs index 05421ba..96ec1cb 100644 --- a/SM64Lib/Level/ILevelManager.cs +++ b/SM64Lib/Level/ILevelManager.cs @@ -1,10 +1,9 @@ using global::SM64Lib.Data; -namespace SM64Lib.Levels +namespace SM64Lib.Levels; + +public interface ILevelManager { - public interface ILevelManager - { - void LoadLevel(Level lvl, RomManager rommgr, ushort LevelID, uint segAddress); - LevelSaveResult SaveLevel(Level lvl, RomManager rommgr, BinaryData output, ref uint curOff); - } + void LoadLevel(Level lvl, RomManager rommgr, ushort LevelID, uint segAddress); + LevelSaveResult SaveLevel(Level lvl, RomManager rommgr, BinaryData output, ref uint curOff); } \ No newline at end of file diff --git a/SM64Lib/Level/Level.cs b/SM64Lib/Level/Level.cs index fa8474b..bc5f105 100644 --- a/SM64Lib/Level/Level.cs +++ b/SM64Lib/Level/Level.cs @@ -1,329 +1,326 @@ -using System.Collections.Generic; -using System.Data; -using global::System.IO; -using System.Linq; -using Microsoft.VisualBasic; -using Microsoft.VisualBasic.CompilerServices; -using global::SM64Lib.Levels.Script; +using global::SM64Lib.Levels.Script; using global::SM64Lib.Levels.Script.Commands; using global::SM64Lib.Objects.ObjectBanks.Data; using global::SM64Lib.SegmentedBanking; -using SM64Lib.Objects.ModelBanks; +using Microsoft.VisualBasic; using Newtonsoft.Json; +using SM64Lib.Objects.ModelBanks; using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; -namespace SM64Lib.Levels +namespace SM64Lib.Levels; + +public abstract class Level { - public abstract class Level + + // S h a r e d M e m b e r s + + internal static readonly byte[] LevelscriptStart = new byte[] { 0x80, 0x8, 0x0, 0x0, 0x19, 0x0, 0x0, 0x1C, 0x8, 0x0, 0x0, 0xA, 0x0, 0xA0, 0x0, 0x78, 0x0, 0xA0, 0x0, 0x78, 0x4, 0x0, 0x0, 0x0, 0xC, 0x0, 0x0, 0x0 }; + + // F i e l d s + + protected SegmentedBank _Bank0x19 = null; + + // A u t o P r o p e r t i e s + + internal LevelscriptCommand LastGobCmdSegLoad { get; set; } = null; + internal LevelscriptCommand LastLobCmdSegLoad { get; set; } = null; + [JsonIgnore] + internal Dictionary MyObjectBanks { get; private set; } = new Dictionary(); + public Levelscript Levelscript { get; set; } = new Levelscript(); + public List Areas { get; private set; } = new List(); + public ushort LevelID { get; set; } = 0; + public LevelBG Background { get; private set; } = new LevelBG(); + public bool ActSelector { get; set; } = false; + public bool HardcodedCameraSettings { get; set; } = false; + public bool Closed { get; set; } = false; + public int LastRomOffset { get; set; } = -1; + public bool NeedToSaveLevelscript { get; set; } = false; + public bool NeedToSaveBanks0E { get; set; } = false; + public bool OneBank0xESystemEnabled { get; set; } = true; + public bool EnableGlobalObjectBank { get; set; } = false; + public bool EnableLocalObjectBank { get; set; } = false; + public CustomModelBank LocalObjectBank { get; private set; } = new CustomModelBank(); + [JsonIgnore] + public RomManager RomManager { get; set; } + + // O t h e r P r o p e r t i e s + + [JsonIgnore] + public IReadOnlyDictionary LoadedObjectBanks { - - // S h a r e d M e m b e r s - - internal static readonly byte[] LevelscriptStart = new byte[] { 0x80, 0x8, 0x0, 0x0, 0x19, 0x0, 0x0, 0x1C, 0x8, 0x0, 0x0, 0xA, 0x0, 0xA0, 0x0, 0x78, 0x0, 0xA0, 0x0, 0x78, 0x4, 0x0, 0x0, 0x0, 0xC, 0x0, 0x0, 0x0 }; - - // F i e l d s - - protected SegmentedBank _Bank0x19 = null; - - // A u t o P r o p e r t i e s - - internal LevelscriptCommand LastGobCmdSegLoad { get; set; } = null; - internal LevelscriptCommand LastLobCmdSegLoad { get; set; } = null; - [JsonIgnore] - internal Dictionary MyObjectBanks { get; private set; } = new Dictionary(); - public Levelscript Levelscript { get; set; } = new Levelscript(); - public List Areas { get; private set; } = new List(); - public ushort LevelID { get; set; } = 0; - public LevelBG Background { get; private set; } = new LevelBG(); - public bool ActSelector { get; set; } = false; - public bool HardcodedCameraSettings { get; set; } = false; - public bool Closed { get; set; } = false; - public int LastRomOffset { get; set; } = -1; - public bool NeedToSaveLevelscript { get; set; } = false; - public bool NeedToSaveBanks0E { get; set; } = false; - public bool OneBank0xESystemEnabled { get; set; } = true; - public bool EnableGlobalObjectBank { get; set; } = false; - public bool EnableLocalObjectBank { get; set; } = false; - public CustomModelBank LocalObjectBank { get; private set; } = new CustomModelBank(); - [JsonIgnore] - public RomManager RomManager { get; set; } - - // O t h e r P r o p e r t i e s - - [JsonIgnore] - public IReadOnlyDictionary LoadedObjectBanks + get { - get - { - return MyObjectBanks; - } - } - - [JsonIgnore] - public SegmentedBank Bank0x19 - { - get - { - return _Bank0x19; - } - - internal set - { - _Bank0x19 = value; - } - } - - [JsonIgnore] - public int ObjectsCount - { - get - { - int tcount = 0; - foreach (var a in Areas) - tcount += a.Objects.Count; - return tcount; - } - } - - [JsonIgnore] - public int WarpsCount - { - get - { - int tcount = 0; - foreach (var a in Areas) - tcount += a.Warps.Count; - return tcount; - } - } - - [JsonIgnore] - public long Length - { - get - { - long length = 0; - - if (Bank0x19 is not null) - length += Bank0x19.Length; - else - length += RomManagerSettings.DefaultLevelscriptSize; - - if (LocalObjectBank is not null) - length += LocalObjectBank.Length; - - foreach (var area in Areas) - { - length += area.AreaModel.Length; - if (OneBank0xESystemEnabled) - length += area.Levelscript.Length; - } - - return length; - } - } - - // C o n s t r u c t o r s - - [JsonConstructor] - protected Level(JsonConstructorAttribute attr) - { - } - - protected Level(ushort LevelID, int LevelIndex, RomManager rommgr) : this(rommgr) - { - this.LevelID = LevelID; - CreateNewLevelscript(); - HardcodedCameraSettings = false; - ActSelector = General.ActSelectorDefaultValues[LevelIndex]; - } - - protected Level(RomManager rommgr) - { - RomManager = rommgr; - } - - // M e t h o d s - - public void CreateNewLevelscript() - { - { - var withBlock = Levelscript; - withBlock.Close(); - withBlock.Clear(); - - // Start Loading Commands - withBlock.Add(new LevelscriptCommand(new byte[] { 0x1B, 0x4, 0x0, 0x0 })); - - // Loading Commands - withBlock.Add(new LevelscriptCommand(new byte[] { 0x17, 0xC, 0x1, 0xE, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 })); - - // Start Model Commands - withBlock.Add(new LevelscriptCommand(new byte[] { 0x1D, 0x4, 0x0, 0x0 })); - - // Load Marios Model - withBlock.Add(new LevelscriptCommand(new byte[] { 0x25, 0xC, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1, 0x13, 0x0, 0x2E, 0xC0 })); - - // Start End-Of-Level Commands - withBlock.Add(new LevelscriptCommand(new byte[] { 0x1E, 0x4, 0x0, 0x0 })); - - // End-Of-Level Commands - withBlock.Add(new LevelscriptCommand(new byte[] { 0x2B, 0xC, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 })); - withBlock.Add(new LevelscriptCommand(new byte[] { 0x11, 0x8, 0x0, 0x0, 0x80, 0x24, 0xBC, 0xD8 })); - withBlock.Add(new LevelscriptCommand(new byte[] { 0x12, 0x8, 0x0, 0x1, 0x80, 0x24, 0xBC, 0xD8 })); - withBlock.Add(new LevelscriptCommand(new byte[] { 0x1C, 0x4, 0x0, 0x0 })); - withBlock.Add(new LevelscriptCommand(new byte[] { 0x4, 0x4, 0x0, 0x1 })); - withBlock.Add(new LevelscriptCommand(new byte[] { 0x2, 0x4, 0x0, 0x0 })); - - // Add the general object bank - ChangeObjectBank(null, RomManager.RomConfig.ObjectBankInfoData[Convert.ToByte(0xB)]?.FirstOrDefault()); - } - - foreach (LevelscriptCommand c in Levelscript) - { - if (c.CommandType != LevelscriptCommandTypes.LoadRomToRam) - continue; - if (clLoadRomToRam.GetSegmentedID(c) != 0xE) - continue; - } - } - - public void SetSegmentedBanks(RomManager rommgr) - { - foreach (LevelscriptCommand cmd in Levelscript) - { - var switchExpr = cmd.CommandType; - switch (switchExpr) - { - case LevelscriptCommandTypes.LoadRomToRam: - case LevelscriptCommandTypes.x1A: - case LevelscriptCommandTypes.x18: - { - cmd.Position = 0; - byte bankID = clLoadRomToRam.GetSegmentedID(cmd); - int startAddr = clLoadRomToRam.GetRomStart(cmd); - int endAddr = clLoadRomToRam.GetRomEnd(cmd); - var seg = rommgr.SetSegBank(bankID, startAddr, endAddr); - if (cmd.CommandType == LevelscriptCommandTypes.x1A) - seg.MakeAsMIO0(); - break; - } - } - } - - if (Bank0x19 is not null) - { - rommgr.SetSegBank(Bank0x19); - } - } - - public LevelscriptCommand GetDefaultPositionCmd() - { - return (LevelscriptCommand)Levelscript.FirstOrDefault(n => n.CommandType == LevelscriptCommandTypes.DefaultPosition); - } - - public void ChangeObjectBankData(byte bankID, ObjectBankData newObd) - { - ChangeObjectBank(GetObjectBankData(bankID), newObd); - MyObjectBanks[bankID] = newObd; - } - - public ObjectBankData GetObjectBankData(byte bankID) - { - if (MyObjectBanks.ContainsKey(bankID)) - { - return MyObjectBanks[bankID]; - } - else - { - var obd = FindObjectBankData(bankID); - MyObjectBanks.Add(bankID, obd); - return obd; - } - } - - protected void ChangeObjectBank(ObjectBankData oldObd, ObjectBankData newObd) - { - // Remove old commands - if (oldObd is not null) - { - foreach (ObjectBankDataCommand obdCmd in oldObd.Commands) - { - foreach (var cmd in Levelscript.Where(n => General.CompareTwoByteArrays(n.ToArray(), obdCmd.Command)).ToArray()) - { - cmd.Close(); - Levelscript.Remove(cmd); - } - } - } - - // Add new commands - if (newObd is not null) - { - foreach (ObjectBankDataCommand obdCmd in newObd.Commands) - { - int startIndex = Levelscript.IndexOfFirst(LevelscriptCommandTypes.x1D); - if (!(obdCmd.CommandType == 0x1A || obdCmd.CommandType == 0x17)) - { - startIndex += 1; - } - - var cmd = new LevelscriptCommand(obdCmd.Command); - Levelscript.Insert(startIndex, cmd); - startIndex += 1; - } - } - } - - protected ObjectBankData FindObjectBankData(byte bankID) - { - var list = RomManager.RomConfig.ObjectBankInfoData[bankID]; - var Found = new List(); - foreach (ObjectBankData obd in list) - { - foreach (ObjectBankDataCommand obdCmd in obd.Commands) - Found.Add(Levelscript.Where(n => General.CompareTwoByteArrays(n.ToArray(), obdCmd.Command)).Any()); - if (!Found.Contains(false)) - { - return obd; - } - - Found.Clear(); - } - - return null; - } - - public void Close() - { - foreach (var c in Levelscript) - c.Close(); - Levelscript.Clear(); - foreach (var a in Areas) - a.Close(); - Areas.Clear(); - Closed = true; - } - - public override string ToString() - { - string output = ""; - foreach (var cmd in Levelscript) - { - string tbytelist = ""; - foreach (byte b in cmd.ToArray()) - { - if (tbytelist != string.Empty) - tbytelist += " "; - tbytelist += Conversion.Hex(b); - } - - if (output != string.Empty) - output += Environment.NewLine; - output += tbytelist; - } - - return output; + return MyObjectBanks; } } + + [JsonIgnore] + public SegmentedBank Bank0x19 + { + get + { + return _Bank0x19; + } + + internal set + { + _Bank0x19 = value; + } + } + + [JsonIgnore] + public int ObjectsCount + { + get + { + int tcount = 0; + foreach (var a in Areas) + tcount += a.Objects.Count; + return tcount; + } + } + + [JsonIgnore] + public int WarpsCount + { + get + { + int tcount = 0; + foreach (var a in Areas) + tcount += a.Warps.Count; + return tcount; + } + } + + [JsonIgnore] + public long Length + { + get + { + long length = 0; + + if (Bank0x19 is not null) + length += Bank0x19.Length; + else + length += RomManagerSettings.DefaultLevelscriptSize; + + if (LocalObjectBank is not null) + length += LocalObjectBank.Length; + + foreach (var area in Areas) + { + length += area.AreaModel.Length; + if (OneBank0xESystemEnabled) + length += area.Levelscript.Length; + } + + return length; + } + } + + // C o n s t r u c t o r s + + [JsonConstructor] + protected Level(JsonConstructorAttribute attr) + { + } + + protected Level(ushort LevelID, int LevelIndex, RomManager rommgr) : this(rommgr) + { + this.LevelID = LevelID; + CreateNewLevelscript(); + HardcodedCameraSettings = false; + ActSelector = General.ActSelectorDefaultValues[LevelIndex]; + } + + protected Level(RomManager rommgr) + { + RomManager = rommgr; + } + + // M e t h o d s + + public void CreateNewLevelscript() + { + { + var withBlock = Levelscript; + withBlock.Close(); + withBlock.Clear(); + + // Start Loading Commands + withBlock.Add(new LevelscriptCommand(new byte[] { 0x1B, 0x4, 0x0, 0x0 })); + + // Loading Commands + withBlock.Add(new LevelscriptCommand(new byte[] { 0x17, 0xC, 0x1, 0xE, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 })); + + // Start Model Commands + withBlock.Add(new LevelscriptCommand(new byte[] { 0x1D, 0x4, 0x0, 0x0 })); + + // Load Marios Model + withBlock.Add(new LevelscriptCommand(new byte[] { 0x25, 0xC, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1, 0x13, 0x0, 0x2E, 0xC0 })); + + // Start End-Of-Level Commands + withBlock.Add(new LevelscriptCommand(new byte[] { 0x1E, 0x4, 0x0, 0x0 })); + + // End-Of-Level Commands + withBlock.Add(new LevelscriptCommand(new byte[] { 0x2B, 0xC, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 })); + withBlock.Add(new LevelscriptCommand(new byte[] { 0x11, 0x8, 0x0, 0x0, 0x80, 0x24, 0xBC, 0xD8 })); + withBlock.Add(new LevelscriptCommand(new byte[] { 0x12, 0x8, 0x0, 0x1, 0x80, 0x24, 0xBC, 0xD8 })); + withBlock.Add(new LevelscriptCommand(new byte[] { 0x1C, 0x4, 0x0, 0x0 })); + withBlock.Add(new LevelscriptCommand(new byte[] { 0x4, 0x4, 0x0, 0x1 })); + withBlock.Add(new LevelscriptCommand(new byte[] { 0x2, 0x4, 0x0, 0x0 })); + + // Add the general object bank + ChangeObjectBank(null, RomManager.RomConfig.ObjectBankInfoData[Convert.ToByte(0xB)]?.FirstOrDefault()); + } + + foreach (LevelscriptCommand c in Levelscript) + { + if (c.CommandType != LevelscriptCommandTypes.LoadRomToRam) + continue; + if (clLoadRomToRam.GetSegmentedID(c) != 0xE) + continue; + } + } + + public void SetSegmentedBanks(RomManager rommgr) + { + foreach (LevelscriptCommand cmd in Levelscript) + { + var switchExpr = cmd.CommandType; + switch (switchExpr) + { + case LevelscriptCommandTypes.LoadRomToRam: + case LevelscriptCommandTypes.x1A: + case LevelscriptCommandTypes.x18: + { + cmd.Position = 0; + byte bankID = clLoadRomToRam.GetSegmentedID(cmd); + int startAddr = clLoadRomToRam.GetRomStart(cmd); + int endAddr = clLoadRomToRam.GetRomEnd(cmd); + var seg = rommgr.SetSegBank(bankID, startAddr, endAddr); + if (cmd.CommandType == LevelscriptCommandTypes.x1A) + seg.MakeAsMIO0(); + break; + } + } + } + + if (Bank0x19 is not null) + { + rommgr.SetSegBank(Bank0x19); + } + } + + public LevelscriptCommand GetDefaultPositionCmd() + { + return (LevelscriptCommand)Levelscript.FirstOrDefault(n => n.CommandType == LevelscriptCommandTypes.DefaultPosition); + } + + public void ChangeObjectBankData(byte bankID, ObjectBankData newObd) + { + ChangeObjectBank(GetObjectBankData(bankID), newObd); + MyObjectBanks[bankID] = newObd; + } + + public ObjectBankData GetObjectBankData(byte bankID) + { + if (MyObjectBanks.ContainsKey(bankID)) + { + return MyObjectBanks[bankID]; + } + else + { + var obd = FindObjectBankData(bankID); + MyObjectBanks.Add(bankID, obd); + return obd; + } + } + + protected void ChangeObjectBank(ObjectBankData oldObd, ObjectBankData newObd) + { + // Remove old commands + if (oldObd is not null) + { + foreach (ObjectBankDataCommand obdCmd in oldObd.Commands) + { + foreach (var cmd in Levelscript.Where(n => General.CompareTwoByteArrays(n.ToArray(), obdCmd.Command)).ToArray()) + { + cmd.Close(); + Levelscript.Remove(cmd); + } + } + } + + // Add new commands + if (newObd is not null) + { + foreach (ObjectBankDataCommand obdCmd in newObd.Commands) + { + int startIndex = Levelscript.IndexOfFirst(LevelscriptCommandTypes.x1D); + if (!(obdCmd.CommandType == 0x1A || obdCmd.CommandType == 0x17)) + { + startIndex += 1; + } + + var cmd = new LevelscriptCommand(obdCmd.Command); + Levelscript.Insert(startIndex, cmd); + startIndex += 1; + } + } + } + + protected ObjectBankData FindObjectBankData(byte bankID) + { + var list = RomManager.RomConfig.ObjectBankInfoData[bankID]; + var Found = new List(); + foreach (ObjectBankData obd in list) + { + foreach (ObjectBankDataCommand obdCmd in obd.Commands) + Found.Add(Levelscript.Where(n => General.CompareTwoByteArrays(n.ToArray(), obdCmd.Command)).Any()); + if (!Found.Contains(false)) + { + return obd; + } + + Found.Clear(); + } + + return null; + } + + public void Close() + { + foreach (var c in Levelscript) + c.Close(); + Levelscript.Clear(); + foreach (var a in Areas) + a.Close(); + Areas.Clear(); + Closed = true; + } + + public override string ToString() + { + string output = ""; + foreach (var cmd in Levelscript) + { + string tbytelist = ""; + foreach (byte b in cmd.ToArray()) + { + if (tbytelist != string.Empty) + tbytelist += " "; + tbytelist += Conversion.Hex(b); + } + + if (output != string.Empty) + output += Environment.NewLine; + output += tbytelist; + } + + return output; + } } \ No newline at end of file diff --git a/SM64Lib/Level/LevelArea.cs b/SM64Lib/Level/LevelArea.cs index 8a29a2b..eb491c9 100644 --- a/SM64Lib/Level/LevelArea.cs +++ b/SM64Lib/Level/LevelArea.cs @@ -1,178 +1,175 @@ -using System.Collections.Generic; -using System.Linq; -using Microsoft.VisualBasic.CompilerServices; -using global::SM64Lib.Levels.Script; +using global::SM64Lib.Levels.Script; using global::SM64Lib.Levels.Script.Commands; using global::SM64Lib.Levels.ScrolTex; using global::SM64Lib.Model; using Newtonsoft.Json; using System; +using System.Collections.Generic; -namespace SM64Lib.Levels +namespace SM64Lib.Levels; + +public abstract class LevelArea { - public abstract class LevelArea + + // S h a r e d M e m b e r s + + public static readonly byte[] DefaultNormal3DObject = new byte[] { 0x24, 0x18, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x13, 0x0, 0x0, 0x0 }; + + // F i e l d s + + protected bool _GettingAreaCollision = false; + + // A u t o P r o p e r t i e s + + public SpecialBoxList SpecialBoxes { get; private set; } = new SpecialBoxList(); + public List ScrollingTextures { get; private set; } = new List(); + public List Objects { get; private set; } = new List(); + public List MacroObjects { get; private set; } = new List(); + public List Warps { get; private set; } = new List(); + public List WarpsForGame { get; private set; } = new List(); + public ShowMessage ShowMessage { get; private set; } = new ShowMessage(); + public AreaBG Background { get; private set; } = new AreaBG(); + public LevelscriptCommandCollection Levelscript { get; set; } = new LevelscriptCommandCollection(); + public Geolayout.Geolayout Geolayout { get; set; } = new Geolayout.Geolayout(SM64Lib.Geolayout.Geolayout.NewScriptCreationMode.None); + public Geolayout.TerrainTypes TerrainType { get; set; } = SM64Lib.Geolayout.TerrainTypes.NoramlA; + public byte BGMusic { get; set; } = 0; + public byte AreaID { get; set; } = 0; + public uint GeolayoutOffset { get; set; } = 0; + public ObjectModel AreaModel { get; set; } = new ObjectModel(); + public bool Enable2DCamera { get; set; } = false; + public uint Bank0x0EOffset { get; set; } = 0; + public int Bank0xELength { get; set; } + + // O t h e r P r o p e r t i e s + + [JsonIgnore] + public int Fast3DBankRomStart { - - // S h a r e d M e m b e r s - - public static readonly byte[] DefaultNormal3DObject = new byte[] { 0x24, 0x18, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x13, 0x0, 0x0, 0x0 }; - - // F i e l d s - - protected bool _GettingAreaCollision = false; - - // A u t o P r o p e r t i e s - - public SpecialBoxList SpecialBoxes { get; private set; } = new SpecialBoxList(); - public List ScrollingTextures { get; private set; } = new List(); - public List Objects { get; private set; } = new List(); - public List MacroObjects { get; private set; } = new List(); - public List Warps { get; private set; } = new List(); - public List WarpsForGame { get; private set; } = new List(); - public ShowMessage ShowMessage { get; private set; } = new ShowMessage(); - public AreaBG Background { get; private set; } = new AreaBG(); - public LevelscriptCommandCollection Levelscript { get; set; } = new LevelscriptCommandCollection(); - public Geolayout.Geolayout Geolayout { get; set; } = new Geolayout.Geolayout(SM64Lib.Geolayout.Geolayout.NewScriptCreationMode.None); - public Geolayout.TerrainTypes TerrainType { get; set; } = SM64Lib.Geolayout.TerrainTypes.NoramlA; - public byte BGMusic { get; set; } = 0; - public byte AreaID { get; set; } = 0; - public uint GeolayoutOffset { get; set; } = 0; - public ObjectModel AreaModel { get; set; } = new ObjectModel(); - public bool Enable2DCamera { get; set; } = false; - public uint Bank0x0EOffset { get; set; } = 0; - public int Bank0xELength { get; set; } - - // O t h e r P r o p e r t i e s - - [JsonIgnore] - public int Fast3DBankRomStart - { - get - { - return Convert.ToInt32(Bank0x0EOffset); - } - } - - [JsonIgnore] - public int Fast3DLength - { - get - { - return CollisionPointer - 0xE000000; - } - } - - [JsonIgnore] - public bool IsCamera2D - { - get - { - return Enable2DCamera && Geolayout.CameraPreset == SM64Lib.Geolayout.CameraPresets.PlattfromLevels; - } - } - - [JsonIgnore] - public int CollisionPointer - { - get - { - int CollisionPointerRet = default; - _GettingAreaCollision = true; - foreach (var cmd in Levelscript) - { - if (cmd.CommandType == LevelscriptCommandTypes.AreaCollision) - { - CollisionPointerRet = Convert.ToInt32(clAreaCollision.GetAreaCollision((LevelscriptCommand)cmd)); - } - } - - _GettingAreaCollision = false; - return CollisionPointerRet; - } - - set - { - if (_GettingAreaCollision) - return; - foreach (var cmd in Levelscript) - { - if (cmd.CommandType == LevelscriptCommandTypes.AreaCollision) - { - clAreaCollision.SetAreaCollision((LevelscriptCommand)cmd, Convert.ToUInt32(value)); - } - } - } - } - - // M e t h o d s - - public void SetSegmentedBanks(RomManager rommgr) - { - var bank0xE = rommgr.SetSegBank(0xE, Convert.ToInt32(Bank0x0EOffset), (int)(Bank0x0EOffset + Bank0xELength), AreaID); - bank0xE.Data = AreaModel.Fast3DBuffer; - } - - internal void UpdateScrollingTextureVertexPointer(int offset) - { - foreach (ManagedScrollingTexture scrollText in ScrollingTextures) - scrollText.VertexPointer += offset; - } - - public void Close() - { - Levelscript.Close(); - Geolayout.Close(); - } - - // C o n s t r u c t o r s - - protected LevelArea(byte AreaID) : this(AreaID, 9) - { - } - - protected LevelArea(byte AreaID, byte LevelID) : this(AreaID, LevelID, true, true) - { - } - - protected LevelArea(byte AreaID, byte LevelID, bool AddWarps, bool AddObjects) - { - Geolayout = new Geolayout.Geolayout(SM64Lib.Geolayout.Geolayout.NewScriptCreationMode.Level); - this.AreaID = AreaID; - { - var withBlock = Levelscript; - withBlock.Add(new LevelscriptCommand(new byte[] { 0x1F, 0x8, AreaID, 0x0, 0x0, 0x0, 0x0, 0x0 })); - withBlock.Add(new LevelscriptCommand(new byte[] { 0x2E, 0x8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 })); - withBlock.Add(new LevelscriptCommand(new byte[] { 0x36, 0x8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 })); - withBlock.Add(new LevelscriptCommand(new byte[] { 0x31, 0x4, 0x0, 0x2 })); - withBlock.Add(new LevelscriptCommand(new byte[] { 0x20, 0x4, 0x0, 0x0 })); - } - - if (AddWarps) - { - Objects.Add(new LevelscriptCommand(new byte[] { 0x24, 0x18, 0x1F, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xA, 0x0, 0x0, 0x13, 0x0, 0x2F, 0x74 })); - Warps.Add(new LevelscriptCommand(new byte[] { 0x26, 0x8, 0xA, LevelID, AreaID, 0x0, 0x0, 0x0 })); - WarpsForGame.Add(new LevelscriptCommand(new byte[] { 0x26, 0x8, 0xF0, 0x6, 0x1, 0x32, 0x0, 0x0 })); - WarpsForGame.Add(new LevelscriptCommand(new byte[] { 0x26, 0x8, 0xF1, 0x6, 0x1, 0x64, 0x0, 0x0 })); - } - - if (AddObjects) - { - //for (int i = 1; i <= 15; i++) - //{ - // var newObj = new LevelscriptCommand(DefaultNormal3DObject); - // Objects.Add(newObj); - //} - } - } - - protected LevelArea() - { - Geolayout = new Geolayout.Geolayout(SM64Lib.Geolayout.Geolayout.NewScriptCreationMode.Level); - } - - [JsonConstructor] - protected LevelArea(JsonConstructorAttribute attr) + get { + return Convert.ToInt32(Bank0x0EOffset); } } + + [JsonIgnore] + public int Fast3DLength + { + get + { + return CollisionPointer - 0xE000000; + } + } + + [JsonIgnore] + public bool IsCamera2D + { + get + { + return Enable2DCamera && Geolayout.CameraPreset == SM64Lib.Geolayout.CameraPresets.PlattfromLevels; + } + } + + [JsonIgnore] + public int CollisionPointer + { + get + { + int CollisionPointerRet = default; + _GettingAreaCollision = true; + foreach (var cmd in Levelscript) + { + if (cmd.CommandType == LevelscriptCommandTypes.AreaCollision) + { + CollisionPointerRet = Convert.ToInt32(clAreaCollision.GetAreaCollision((LevelscriptCommand)cmd)); + } + } + + _GettingAreaCollision = false; + return CollisionPointerRet; + } + + set + { + if (_GettingAreaCollision) + return; + foreach (var cmd in Levelscript) + { + if (cmd.CommandType == LevelscriptCommandTypes.AreaCollision) + { + clAreaCollision.SetAreaCollision((LevelscriptCommand)cmd, Convert.ToUInt32(value)); + } + } + } + } + + // M e t h o d s + + public void SetSegmentedBanks(RomManager rommgr) + { + var bank0xE = rommgr.SetSegBank(0xE, Convert.ToInt32(Bank0x0EOffset), (int)(Bank0x0EOffset + Bank0xELength), AreaID); + bank0xE.Data = AreaModel.Fast3DBuffer; + } + + internal void UpdateScrollingTextureVertexPointer(int offset) + { + foreach (ManagedScrollingTexture scrollText in ScrollingTextures) + scrollText.VertexPointer += offset; + } + + public void Close() + { + Levelscript.Close(); + Geolayout.Close(); + } + + // C o n s t r u c t o r s + + protected LevelArea(byte AreaID) : this(AreaID, 9) + { + } + + protected LevelArea(byte AreaID, byte LevelID) : this(AreaID, LevelID, true, true) + { + } + + protected LevelArea(byte AreaID, byte LevelID, bool AddWarps, bool AddObjects) + { + Geolayout = new Geolayout.Geolayout(SM64Lib.Geolayout.Geolayout.NewScriptCreationMode.Level); + this.AreaID = AreaID; + { + var withBlock = Levelscript; + withBlock.Add(new LevelscriptCommand(new byte[] { 0x1F, 0x8, AreaID, 0x0, 0x0, 0x0, 0x0, 0x0 })); + withBlock.Add(new LevelscriptCommand(new byte[] { 0x2E, 0x8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 })); + withBlock.Add(new LevelscriptCommand(new byte[] { 0x36, 0x8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 })); + withBlock.Add(new LevelscriptCommand(new byte[] { 0x31, 0x4, 0x0, 0x2 })); + withBlock.Add(new LevelscriptCommand(new byte[] { 0x20, 0x4, 0x0, 0x0 })); + } + + if (AddWarps) + { + Objects.Add(new LevelscriptCommand(new byte[] { 0x24, 0x18, 0x1F, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xA, 0x0, 0x0, 0x13, 0x0, 0x2F, 0x74 })); + Warps.Add(new LevelscriptCommand(new byte[] { 0x26, 0x8, 0xA, LevelID, AreaID, 0x0, 0x0, 0x0 })); + WarpsForGame.Add(new LevelscriptCommand(new byte[] { 0x26, 0x8, 0xF0, 0x6, 0x1, 0x32, 0x0, 0x0 })); + WarpsForGame.Add(new LevelscriptCommand(new byte[] { 0x26, 0x8, 0xF1, 0x6, 0x1, 0x64, 0x0, 0x0 })); + } + + if (AddObjects) + { + //for (int i = 1; i <= 15; i++) + //{ + // var newObj = new LevelscriptCommand(DefaultNormal3DObject); + // Objects.Add(newObj); + //} + } + } + + protected LevelArea() + { + Geolayout = new Geolayout.Geolayout(SM64Lib.Geolayout.Geolayout.NewScriptCreationMode.Level); + } + + [JsonConstructor] + protected LevelArea(JsonConstructorAttribute attr) + { + } } \ No newline at end of file diff --git a/SM64Lib/Level/LevelBG.cs b/SM64Lib/Level/LevelBG.cs index 80b501f..25f05f1 100644 --- a/SM64Lib/Level/LevelBG.cs +++ b/SM64Lib/Level/LevelBG.cs @@ -1,234 +1,232 @@ -using global::System.Drawing; +using global::SM64Lib.Model.Fast3D; +using global::System.Drawing; using global::System.IO; -using Microsoft.VisualBasic.CompilerServices; -using SM64Lib.Data.System; -using global::SM64Lib.Model.Fast3D; using Newtonsoft.Json; +using SM64Lib.Data.System; using System; -namespace SM64Lib.Levels +namespace SM64Lib.Levels; + +public class LevelBG { - public class LevelBG + private Bitmap _Image = null; + + // A u t o P r o p e r t i e s + + public byte[] ImageData { get; set; } = null; + public bool Enabled { get; set; } = true; + public bool IsCustom { get; set; } = false; + public Geolayout.BackgroundIDs ID { get; set; } = Geolayout.BackgroundIDs.Ocean; + + // A u t o P r o p e r t i e s + + [JsonIgnore] + public Bitmap Image { - private Bitmap _Image = null; - - // A u t o P r o p e r t i e s - - public byte[] ImageData { get; set; } = null; - public bool Enabled { get; set; } = true; - public bool IsCustom { get; set; } = false; - public Geolayout.BackgroundIDs ID { get; set; } = Geolayout.BackgroundIDs.Ocean; - - // A u t o P r o p e r t i e s - - [JsonIgnore] - public Bitmap Image + get { - get + if (_Image is not null) { - if (_Image is not null) - { - return _Image; - } - else - { - var img = GetImage(); - _Image = (Bitmap)img; - return (Bitmap)img; - } - } - } - - [JsonIgnore] - public int ImageLength - { - get - { - return ImageData?.Length ?? 0; - } - } - - [JsonIgnore] - public bool HasImage - { - get - { - return ImageData is object; - } - } - - // C o n s t r c u t o r s - - public LevelBG() - { - } - - public LevelBG(Geolayout.BackgroundIDs ID) - { - this.ID = ID; - } - - public LevelBG(Image Image) - { - ID = Geolayout.BackgroundIDs.Custom; - SetImage(Image); - } - - // M e t h o d s - - public void WriteImage(Stream s, int offset) - { - // Write Image Data - s.Position = offset; - if (ImageData is not null) - { - s.Write(ImageData, 0, ImageData.Length); - } - } - - public void ReadImage(Stream s, int offset) - { - // Read Image Data - ImageData = new byte[131072]; - s.Position = offset; - s.Read(ImageData, 0, ImageData.Length); - _Image = null; - } - - public void SetImage(Image image) - { - SetImage(new Bitmap(image)); - } - - public void SetImage(Bitmap bmp) - { - var s = new Size(248, 248); // ((&H20140 - &H140) / 256 / 2 / 32) * 31) - if (bmp.Size != s) - { - bmp = (Bitmap)TextureManager.ResizeImage(bmp, s, false); - } - - ImageData = BackgroundImageConverter.GetBytes(bmp); - _Image = null; - } - - public Image GetImage() - { - if (ImageData is not null) - { - var s = new Size(248, 248); // ((_ImageByts.Length - &H140) / 256 / 2 / 32) * 31) - var img = BackgroundImageConverter.GetImage(ImageData, s); - _Image = img; - return img; + return _Image; } else { - return null; + var img = GetImage(); + _Image = (Bitmap)img; + return (Bitmap)img; + } + } + } + + [JsonIgnore] + public int ImageLength + { + get + { + return ImageData?.Length ?? 0; + } + } + + [JsonIgnore] + public bool HasImage + { + get + { + return ImageData is object; + } + } + + // C o n s t r c u t o r s + + public LevelBG() + { + } + + public LevelBG(Geolayout.BackgroundIDs ID) + { + this.ID = ID; + } + + public LevelBG(Image Image) + { + ID = Geolayout.BackgroundIDs.Custom; + SetImage(Image); + } + + // M e t h o d s + + public void WriteImage(Stream s, int offset) + { + // Write Image Data + s.Position = offset; + if (ImageData is not null) + { + s.Write(ImageData, 0, ImageData.Length); + } + } + + public void ReadImage(Stream s, int offset) + { + // Read Image Data + ImageData = new byte[131072]; + s.Position = offset; + s.Read(ImageData, 0, ImageData.Length); + _Image = null; + } + + public void SetImage(Image image) + { + SetImage(new Bitmap(image)); + } + + public void SetImage(Bitmap bmp) + { + var s = new Size(248, 248); // ((&H20140 - &H140) / 256 / 2 / 32) * 31) + if (bmp.Size != s) + { + bmp = (Bitmap)TextureManager.ResizeImage(bmp, s, false); + } + + ImageData = BackgroundImageConverter.GetBytes(bmp); + _Image = null; + } + + public Image GetImage() + { + if (ImageData is not null) + { + var s = new Size(248, 248); // ((_ImageByts.Length - &H140) / 256 / 2 / 32) * 31) + var img = BackgroundImageConverter.GetImage(ImageData, s); + _Image = img; + return img; + } + else + { + return null; + } + } + + public static byte[] GetBackgroundPointerTable() + { + return new byte[] { 0xA, 0x0, 0x0, 0x0, 0xA, 0x0, 0x8, 0x0, 0xA, 0x0, 0x10, 0x0, 0xA, 0x0, 0x18, 0x0, 0xA, 0x0, 0x20, 0x0, 0xA, 0x0, 0x28, 0x0, 0xA, 0x0, 0x30, 0x0, 0xA, 0x0, 0x38, 0x0, 0xA, 0x0, 0x0, 0x0, 0xA, 0x0, 0x8, 0x0, 0xA, 0x0, 0x40, 0x0, 0xA, 0x0, 0x48, 0x0, 0xA, 0x0, 0x50, 0x0, 0xA, 0x0, 0x58, 0x0, 0xA, 0x0, 0x60, 0x0, 0xA, 0x0, 0x68, 0x0, 0xA, 0x0, 0x70, 0x0, 0xA, 0x0, 0x78, 0x0, 0xA, 0x0, 0x40, 0x0, 0xA, 0x0, 0x48, 0x0, 0xA, 0x0, 0x80, 0x0, 0xA, 0x0, 0x88, 0x0, 0xA, 0x0, 0x90, 0x0, 0xA, 0x0, 0x98, 0x0, 0xA, 0x0, 0xA0, 0x0, 0xA, 0x0, 0xA8, 0x0, 0xA, 0x0, 0xB0, 0x0, 0xA, 0x0, 0xB8, 0x0, 0xA, 0x0, 0x80, 0x0, 0xA, 0x0, 0x88, 0x0, 0xA, 0x0, 0xC0, 0x0, 0xA, 0x0, 0xC8, 0x0, 0xA, 0x0, 0xD0, 0x0, 0xA, 0x0, 0xD8, 0x0, 0xA, 0x0, 0xE0, 0x0, 0xA, 0x0, 0xE8, 0x0, 0xA, 0x0, 0xF0, 0x0, 0xA, 0x0, 0xF8, 0x0, 0xA, 0x0, 0xC0, 0x0, 0xA, 0x0, 0xC8, 0x0, 0xA, 0x1, 0x0, 0x0, 0xA, 0x1, 0x8, 0x0, 0xA, 0x1, 0x10, 0x0, 0xA, 0x1, 0x18, 0x0, 0xA, 0x1, 0x20, 0x0, 0xA, 0x1, 0x28, 0x0, 0xA, 0x1, 0x30, 0x0, 0xA, 0x1, 0x38, 0x0, 0xA, 0x1, 0x0, 0x0, 0xA, 0x1, 0x8, 0x0, 0xA, 0x1, 0x40, 0x0, 0xA, 0x1, 0x48, 0x0, 0xA, 0x1, 0x50, 0x0, 0xA, 0x1, 0x58, 0x0, 0xA, 0x1, 0x60, 0x0, 0xA, 0x1, 0x68, 0x0, 0xA, 0x1, 0x70, 0x0, 0xA, 0x1, 0x78, 0x0, 0xA, 0x1, 0x40, 0x0, 0xA, 0x1, 0x48, 0x0, 0xA, 0x1, 0x80, 0x0, 0xA, 0x1, 0x88, 0x0, 0xA, 0x1, 0x90, 0x0, 0xA, 0x1, 0x98, 0x0, 0xA, 0x1, 0xA0, 0x0, 0xA, 0x1, 0xA8, 0x0, 0xA, 0x1, 0xB0, 0x0, 0xA, 0x1, 0xB8, 0x0, 0xA, 0x1, 0x80, 0x0, 0xA, 0x1, 0x88, 0x0, 0xA, 0x1, 0xC0, 0x0, 0xA, 0x1, 0xC8, 0x0, 0xA, 0x1, 0xD0, 0x0, 0xA, 0x1, 0xD8, 0x0, 0xA, 0x1, 0xE0, 0x0, 0xA, 0x1, 0xE8, 0x0, 0xA, 0x1, 0xF0, 0x0, 0xA, 0x1, 0xF8, 0x0, 0xA, 0x1, 0xC0, 0x0, 0xA, 0x1, 0xC8, 0x0 }; + } + + // C l a s s e s + + private class BackgroundImageConverter + { + public static Bitmap GetImage(byte[] data, Size size) + { + var ms = new MemoryStream(data); + var br = new BinaryReader(ms); + var img = new Bitmap(size.Width, size.Height); + uint current_address = 0; + for (int y = 0, loopTo = (int)(size.Height / (double)31 - 1); y <= loopTo; y++) + { + for (int x = 0, loopTo1 = (int)(size.Width / (double)31 - 1); x <= loopTo1; x++) + { + ParseBlock(br, img, current_address, new Rectangle(x * 31, y * 31, 31, 31)); + current_address += 2048; + } + } + + ms.Close(); + return img; + } + + private static void ParseBlock(BinaryReader br, Bitmap map, uint address, Rectangle rect) + { + for (int yy = 0, loopTo = rect.Height - 1; yy <= loopTo; yy++) + { + for (int xx = 0, loopTo1 = rect.Width - 1; xx <= loopTo1; xx++) + { + int offset = (int)(address + (yy * (rect.Width + 1) + xx) * 2); + br.BaseStream.Position = offset; + ushort pixel = SwapInts.SwapUInt16(br.ReadUInt16()); + byte red = Convert.ToByte((pixel >> 11 & 0x1F) * 8); + byte green = Convert.ToByte((pixel >> 6 & 0x1F) * 8); + byte blue = Convert.ToByte((pixel >> 1 & 0x1F) * 8); + byte alpha = Convert.ToByte((pixel & 1) > 0 ? 0xFF : 0); + var pixcol = Color.FromArgb(alpha, red, green, blue); + map.SetPixel(rect.X + xx, rect.Y + yy, pixcol); + } } } - public static byte[] GetBackgroundPointerTable() + public static byte[] GetBytes(Bitmap img) { - return new byte[] { 0xA, 0x0, 0x0, 0x0, 0xA, 0x0, 0x8, 0x0, 0xA, 0x0, 0x10, 0x0, 0xA, 0x0, 0x18, 0x0, 0xA, 0x0, 0x20, 0x0, 0xA, 0x0, 0x28, 0x0, 0xA, 0x0, 0x30, 0x0, 0xA, 0x0, 0x38, 0x0, 0xA, 0x0, 0x0, 0x0, 0xA, 0x0, 0x8, 0x0, 0xA, 0x0, 0x40, 0x0, 0xA, 0x0, 0x48, 0x0, 0xA, 0x0, 0x50, 0x0, 0xA, 0x0, 0x58, 0x0, 0xA, 0x0, 0x60, 0x0, 0xA, 0x0, 0x68, 0x0, 0xA, 0x0, 0x70, 0x0, 0xA, 0x0, 0x78, 0x0, 0xA, 0x0, 0x40, 0x0, 0xA, 0x0, 0x48, 0x0, 0xA, 0x0, 0x80, 0x0, 0xA, 0x0, 0x88, 0x0, 0xA, 0x0, 0x90, 0x0, 0xA, 0x0, 0x98, 0x0, 0xA, 0x0, 0xA0, 0x0, 0xA, 0x0, 0xA8, 0x0, 0xA, 0x0, 0xB0, 0x0, 0xA, 0x0, 0xB8, 0x0, 0xA, 0x0, 0x80, 0x0, 0xA, 0x0, 0x88, 0x0, 0xA, 0x0, 0xC0, 0x0, 0xA, 0x0, 0xC8, 0x0, 0xA, 0x0, 0xD0, 0x0, 0xA, 0x0, 0xD8, 0x0, 0xA, 0x0, 0xE0, 0x0, 0xA, 0x0, 0xE8, 0x0, 0xA, 0x0, 0xF0, 0x0, 0xA, 0x0, 0xF8, 0x0, 0xA, 0x0, 0xC0, 0x0, 0xA, 0x0, 0xC8, 0x0, 0xA, 0x1, 0x0, 0x0, 0xA, 0x1, 0x8, 0x0, 0xA, 0x1, 0x10, 0x0, 0xA, 0x1, 0x18, 0x0, 0xA, 0x1, 0x20, 0x0, 0xA, 0x1, 0x28, 0x0, 0xA, 0x1, 0x30, 0x0, 0xA, 0x1, 0x38, 0x0, 0xA, 0x1, 0x0, 0x0, 0xA, 0x1, 0x8, 0x0, 0xA, 0x1, 0x40, 0x0, 0xA, 0x1, 0x48, 0x0, 0xA, 0x1, 0x50, 0x0, 0xA, 0x1, 0x58, 0x0, 0xA, 0x1, 0x60, 0x0, 0xA, 0x1, 0x68, 0x0, 0xA, 0x1, 0x70, 0x0, 0xA, 0x1, 0x78, 0x0, 0xA, 0x1, 0x40, 0x0, 0xA, 0x1, 0x48, 0x0, 0xA, 0x1, 0x80, 0x0, 0xA, 0x1, 0x88, 0x0, 0xA, 0x1, 0x90, 0x0, 0xA, 0x1, 0x98, 0x0, 0xA, 0x1, 0xA0, 0x0, 0xA, 0x1, 0xA8, 0x0, 0xA, 0x1, 0xB0, 0x0, 0xA, 0x1, 0xB8, 0x0, 0xA, 0x1, 0x80, 0x0, 0xA, 0x1, 0x88, 0x0, 0xA, 0x1, 0xC0, 0x0, 0xA, 0x1, 0xC8, 0x0, 0xA, 0x1, 0xD0, 0x0, 0xA, 0x1, 0xD8, 0x0, 0xA, 0x1, 0xE0, 0x0, 0xA, 0x1, 0xE8, 0x0, 0xA, 0x1, 0xF0, 0x0, 0xA, 0x1, 0xF8, 0x0, 0xA, 0x1, 0xC0, 0x0, 0xA, 0x1, 0xC8, 0x0 }; + var ms = new MemoryStream(); + var bw = new BinaryWriter(ms); + int wTiles = (int)(img.Width / (double)31); + int hTiles = (int)(img.Height / (double)31); + int current_address = 0; + for (int y = 0, loopTo = hTiles - 1; y <= loopTo; y++) + { + for (int x = 0, loopTo1 = wTiles - 1; x <= loopTo1; x++) + { + ConvertBlock(bw, img, Convert.ToUInt32(current_address), x * 31, y * 31, 0, 0, 0, 0, 31, 31, 32); + if (x < wTiles - 1) + { + ConvertBlock(bw, img, Convert.ToUInt32(current_address), (x + 1) * 31 - 30, y * 31, 30, 0, 1, 0, 31, 31, 32); + ConvertBlock(bw, img, Convert.ToUInt32(current_address), (x + 1) * 31 - 30, y * 31, 30, 30, 1, 1, 31, 31, 32); + } + else + { + ConvertBlock(bw, img, Convert.ToUInt32(current_address), -30, y * 31, 30, 0, 1, 0, 31, 31, 32); + ConvertBlock(bw, img, Convert.ToUInt32(current_address), -30, y * 31, 30, 30, 1, 1, 31, 31, 32); + } + + if (y < hTiles - 1) + { + ConvertBlock(bw, img, Convert.ToUInt32(current_address), x * 31, (y + 1) * 31 - 30, 0, 30, 0, 1, 31, 31, 32); + } + else + { + ConvertBlock(bw, img, Convert.ToUInt32(current_address), x * 31, -30, 0, 30, 0, 1, 31, 31, 32); + } + + current_address += 2048; + } + } + + var temp = ms.ToArray(); + ms.Close(); + return temp; } - // C l a s s e s - - private class BackgroundImageConverter + private static void ConvertBlock(BinaryWriter bw, Bitmap map, uint address, int src_x, int src_y, int start_x, int start_y, int offset_x, int offset_y, int w, int h, int lineWidth) { - public static Bitmap GetImage(byte[] data, Size size) + for (int yy = start_y, loopTo = h - 1; yy <= loopTo; yy++) { - var ms = new MemoryStream(data); - var br = new BinaryReader(ms); - var img = new Bitmap(size.Width, size.Height); - uint current_address = 0; - for (int y = 0, loopTo = (int)(size.Height / (double)31 - 1); y <= loopTo; y++) + for (int xx = start_x, loopTo1 = w - 1; xx <= loopTo1; xx++) { - for (int x = 0, loopTo1 = (int)(size.Width / (double)31 - 1); x <= loopTo1; x++) - { - ParseBlock(br, img, current_address, new Rectangle(x * 31, y * 31, 31, 31)); - current_address += 2048; - } - } - - ms.Close(); - return img; - } - - private static void ParseBlock(BinaryReader br, Bitmap map, uint address, Rectangle rect) - { - for (int yy = 0, loopTo = rect.Height - 1; yy <= loopTo; yy++) - { - for (int xx = 0, loopTo1 = rect.Width - 1; xx <= loopTo1; xx++) - { - int offset = (int)(address + (yy * (rect.Width + 1) + xx) * 2); - br.BaseStream.Position = offset; - ushort pixel = SwapInts.SwapUInt16(br.ReadUInt16()); - byte red = Convert.ToByte((pixel >> 11 & 0x1F) * 8); - byte green = Convert.ToByte((pixel >> 6 & 0x1F) * 8); - byte blue = Convert.ToByte((pixel >> 1 & 0x1F) * 8); - byte alpha = Convert.ToByte((pixel & 1) > 0 ? 0xFF : 0); - var pixcol = Color.FromArgb(alpha, red, green, blue); - map.SetPixel(rect.X + xx, rect.Y + yy, pixcol); - } - } - } - - public static byte[] GetBytes(Bitmap img) - { - var ms = new MemoryStream(); - var bw = new BinaryWriter(ms); - int wTiles = (int)(img.Width / (double)31); - int hTiles = (int)(img.Height / (double)31); - int current_address = 0; - for (int y = 0, loopTo = hTiles - 1; y <= loopTo; y++) - { - for (int x = 0, loopTo1 = wTiles - 1; x <= loopTo1; x++) - { - ConvertBlock(bw, img, Convert.ToUInt32(current_address), x * 31, y * 31, 0, 0, 0, 0, 31, 31, 32); - if (x < wTiles - 1) - { - ConvertBlock(bw, img, Convert.ToUInt32(current_address), (x + 1) * 31 - 30, y * 31, 30, 0, 1, 0, 31, 31, 32); - ConvertBlock(bw, img, Convert.ToUInt32(current_address), (x + 1) * 31 - 30, y * 31, 30, 30, 1, 1, 31, 31, 32); - } - else - { - ConvertBlock(bw, img, Convert.ToUInt32(current_address), -30, y * 31, 30, 0, 1, 0, 31, 31, 32); - ConvertBlock(bw, img, Convert.ToUInt32(current_address), -30, y * 31, 30, 30, 1, 1, 31, 31, 32); - } - - if (y < hTiles - 1) - { - ConvertBlock(bw, img, Convert.ToUInt32(current_address), x * 31, (y + 1) * 31 - 30, 0, 30, 0, 1, 31, 31, 32); - } - else - { - ConvertBlock(bw, img, Convert.ToUInt32(current_address), x * 31, -30, 0, 30, 0, 1, 31, 31, 32); - } - - current_address += 2048; - } - } - - var temp = ms.ToArray(); - ms.Close(); - return temp; - } - - private static void ConvertBlock(BinaryWriter bw, Bitmap map, uint address, int src_x, int src_y, int start_x, int start_y, int offset_x, int offset_y, int w, int h, int lineWidth) - { - for (int yy = start_y, loopTo = h - 1; yy <= loopTo; yy++) - { - for (int xx = start_x, loopTo1 = w - 1; xx <= loopTo1; xx++) - { - var pixel = map.GetPixel(src_x + xx, src_y + yy); - int r = pixel.R / 8; - int g = pixel.G / 8; - int b = pixel.B / 8; - int a = pixel.A == 0xFF ? 1 : 0; - bw.BaseStream.Position = address + ((yy + offset_y) * lineWidth + xx + offset_x) * 2; - bw.Write(SwapInts.SwapUInt16(Convert.ToUInt16(r << 11 | g << 6 | b << 1 | a))); - } + var pixel = map.GetPixel(src_x + xx, src_y + yy); + int r = pixel.R / 8; + int g = pixel.G / 8; + int b = pixel.B / 8; + int a = pixel.A == 0xFF ? 1 : 0; + bw.BaseStream.Position = address + ((yy + offset_y) * lineWidth + xx + offset_x) * 2; + bw.Write(SwapInts.SwapUInt16(Convert.ToUInt16(r << 11 | g << 6 | b << 1 | a))); } } } diff --git a/SM64Lib/Level/LevelExport.cs b/SM64Lib/Level/LevelExport.cs index 0497a39..4c3cf32 100644 --- a/SM64Lib/Level/LevelExport.cs +++ b/SM64Lib/Level/LevelExport.cs @@ -1,79 +1,74 @@ using Newtonsoft.Json; using SM64Lib.Levels.Script; -using System; using System.Collections.Generic; using System.IO; using System.IO.Compression; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace SM64Lib.Levels +namespace SM64Lib.Levels; + +public class LevelExport { - public class LevelExport + // P r o p e r t i e s + + [JsonProperty] + public object Content { get; protected set; } + [JsonProperty] + public LevelExportContentType ContentType { get; set; } + + // C o n s t r u c t o r s + + private LevelExport(object content, LevelExportContentType type) : this() { - // P r o p e r t i e s + Content = content; + ContentType = type; + } - [JsonProperty] - public object Content { get; protected set; } - [JsonProperty] - public LevelExportContentType ContentType { get; set; } + public LevelExport(Level level) : this(new List { level }) { } + public LevelExport(List levels) : this(levels, LevelExportContentType.Level) { } + public LevelExport(LevelArea area) : this(new List { area }) { } + public LevelExport(List areas) : this(areas, LevelExportContentType.Area) { } + public LevelExport(List cmds, LevelExportContentType contentType) : this((object)cmds, contentType) { } - // C o n s t r u c t o r s + [JsonConstructor] + private LevelExport() { } - private LevelExport(object content, LevelExportContentType type) : this() - { - Content = content; - ContentType = type; - } + // F e a t u r e s - public LevelExport(Level level) : this(new List { level }) { } - public LevelExport(List levels) : this(levels, LevelExportContentType.Level) { } - public LevelExport(LevelArea area) : this(new List { area }) { } - public LevelExport(List areas) : this(areas, LevelExportContentType.Area) { } - public LevelExport(List cmds, LevelExportContentType contentType) : this((object)cmds, contentType) { } + public void WriteToFile(string filePath, CompressionLevel compressionLevel) + { + var plainText = compressionLevel == CompressionLevel.NoCompression; - [JsonConstructor] - private LevelExport() { } + // Open streams + var fs = new FileStream(filePath, FileMode.Create, FileAccess.ReadWrite); + var output = new DeflateStream(fs, compressionLevel, true); + var sw = new StreamWriter(output); - // F e a t u r e s + // Create serializer + var serializer = Json.JsonHelper.CreateJsonSerializer(true, true, plainText); - public void WriteToFile(string filePath, CompressionLevel compressionLevel) - { - var plainText = compressionLevel == CompressionLevel.NoCompression; + // Serialize + serializer.Serialize(sw, this); - // Open streams - var fs = new FileStream(filePath, FileMode.Create, FileAccess.ReadWrite); - var output = new DeflateStream(fs, compressionLevel, true); - var sw = new StreamWriter(output); + sw.Flush(); + output.Close(); + fs.Close(); + } - // Create serializer - var serializer = Json.JsonHelper.CreateJsonSerializer(true, true, plainText); + public static LevelExport ReadFromFile(string filePath) + { + // Open streams + var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read); + var input = new DeflateStream(fs, CompressionMode.Decompress); + var sr = new StreamReader(input); - // Serialize - serializer.Serialize(sw, this); + // Create serializer + var serializer = Json.JsonHelper.CreateJsonSerializer(true, true); - sw.Flush(); - output.Close(); - fs.Close(); - } + // Deserialize + var export = (LevelExport)serializer.Deserialize(sr, typeof(LevelExport)); - public static LevelExport ReadFromFile(string filePath) - { - // Open streams - var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read); - var input = new DeflateStream(fs, CompressionMode.Decompress); - var sr = new StreamReader(input); - - // Create serializer - var serializer = Json.JsonHelper.CreateJsonSerializer(true, true); + fs.Close(); - // Deserialize - var export = (LevelExport)serializer.Deserialize(sr, typeof(LevelExport)); - - fs.Close(); - - return export; - } + return export; } } diff --git a/SM64Lib/Level/LevelExportContentType.cs b/SM64Lib/Level/LevelExportContentType.cs index 95c2c17..caf3a95 100644 --- a/SM64Lib/Level/LevelExportContentType.cs +++ b/SM64Lib/Level/LevelExportContentType.cs @@ -1,17 +1,10 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +namespace SM64Lib.Levels; -namespace SM64Lib.Levels +public enum LevelExportContentType { - public enum LevelExportContentType - { - Unknown, - Level, - Area, - Objects, - Warps - } + Unknown, + Level, + Area, + Objects, + Warps } diff --git a/SM64Lib/Level/LevelExportFileFormat.cs b/SM64Lib/Level/LevelExportFileFormat.cs index 90452d0..9b90c75 100644 --- a/SM64Lib/Level/LevelExportFileFormat.cs +++ b/SM64Lib/Level/LevelExportFileFormat.cs @@ -1,14 +1,7 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +namespace SM64Lib.Levels; -namespace SM64Lib.Levels +public enum LevelExportFileFormat { - public enum LevelExportFileFormat - { - JSON, - PlainText - } + JSON, + PlainText } diff --git a/SM64Lib/Level/LevelExportImporter.cs b/SM64Lib/Level/LevelExportImporter.cs index a269533..2f1da83 100644 --- a/SM64Lib/Level/LevelExportImporter.cs +++ b/SM64Lib/Level/LevelExportImporter.cs @@ -2,74 +2,71 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace SM64Lib.Levels +namespace SM64Lib.Levels; + +public static class LevelExportImporter { - public static class LevelExportImporter + public static void ImportLevel(LevelExport export, RomManager destRomManager, KeyValuePair[] levelIDs) { - public static void ImportLevel(LevelExport export, RomManager destRomManager, KeyValuePair[] levelIDs) + var levels = export.Content as Level[]; + if (levels != null) { - var levels = export.Content as Level[]; - if (levels != null) + foreach (var level in levels) { - foreach (var level in levels) + var id = (ushort?)levelIDs.FirstOrDefault(n => n.Key == level).Value; + if (id is not null) { - var id = (ushort?)levelIDs.FirstOrDefault(n => n.Key == level).Value; - if (id is not null) - { - level.LevelID = (ushort)id; - destRomManager.Levels.Add(level); - } + level.LevelID = (ushort)id; + destRomManager.Levels.Add(level); } } - else - throw new NotSupportedException(); } + else + throw new NotSupportedException(); + } - public static void ImportArea(LevelExport export, Level destLevel, KeyValuePair[] areaIDs) + public static void ImportArea(LevelExport export, Level destLevel, KeyValuePair[] areaIDs) + { + var areas = export.Content as LevelArea[]; + if (areas != null) { - var areas = export.Content as LevelArea[]; - if (areas != null) + foreach (var area in areas) { - foreach (var area in areas) + var id = (byte?)areaIDs.FirstOrDefault(n => n.Key == area).Value; + if (id is not null) { - var id = (byte?)areaIDs.FirstOrDefault(n => n.Key == area).Value; - if (id is not null) - { - area.AreaID = (byte)id; - destLevel.Areas.Add(area); - } + area.AreaID = (byte)id; + destLevel.Areas.Add(area); } } - else - throw new NotSupportedException(); } + else + throw new NotSupportedException(); + } - public static void ImportScript(LevelExport export, LevelArea destArea, List allowedCommands) + public static void ImportScript(LevelExport export, LevelArea destArea, List allowedCommands) + { + var cmds = export.Content as List; + if (cmds is not null) { - var cmds = export.Content as List; - if (cmds is not null) + foreach (var cmd in cmds) { - foreach (var cmd in cmds) + if (allowedCommands.Contains(cmd)) { - if (allowedCommands.Contains(cmd)) + switch (export.ContentType) { - switch (export.ContentType) - { - case LevelExportContentType.Objects: - destArea.Objects.Add(cmd); - break; - case LevelExportContentType.Warps: - destArea.Warps.Add(cmd); - break; - } + case LevelExportContentType.Objects: + destArea.Objects.Add(cmd); + break; + case LevelExportContentType.Warps: + destArea.Warps.Add(cmd); + break; } } } - else - throw new NotSupportedException(); } + else + throw new NotSupportedException(); } } diff --git a/SM64Lib/Level/LevelInfoDataTabel.cs b/SM64Lib/Level/LevelInfoDataTabel.cs index 074f749..39a489e 100644 --- a/SM64Lib/Level/LevelInfoDataTabel.cs +++ b/SM64Lib/Level/LevelInfoDataTabel.cs @@ -1,143 +1,142 @@ -using System.Collections.Generic; +using global::Newtonsoft.Json.Linq; using global::System.IO; +using System.Collections.Generic; using System.Linq; -using global::Newtonsoft.Json.Linq; using static SM64Lib.TextValueConverter.TextValueConverter; -namespace SM64Lib.Levels +namespace SM64Lib.Levels; + +public class LevelInfoDataTabelList : List { - public class LevelInfoDataTabelList : List + public void ReadFromFile(string FileName) { - public void ReadFromFile(string FileName) + var jobj = JObject.Parse(File.ReadAllText(FileName)); + if (jobj["Levels"] is not null) { - var jobj = JObject.Parse(File.ReadAllText(FileName)); - if (jobj["Levels"] is not null) + foreach (JObject entry in (JArray)jobj["Levels"]) { - foreach (JObject entry in (JArray)jobj["Levels"]) + Add(new Level { - Add(new Level - { - Name = entry?["Name"].ToString(), - Number = entry?["Number"].ToString(), - TypeString = entry?["Type"].ToString(), - ID = (ushort)ValueFromText(entry?["ID"].ToString()), - Pointer = (uint)ValueFromText(entry?["Pointer"].ToString()), - Index = entry["Index"].Value() - }); - } + Name = entry?["Name"].ToString(), + Number = entry?["Number"].ToString(), + TypeString = entry?["Type"].ToString(), + ID = (ushort)ValueFromText(entry?["ID"].ToString()), + Pointer = (uint)ValueFromText(entry?["Pointer"].ToString()), + Index = entry["Index"].Value() + }); } } - - public Level GetByLevelID(ushort ID) - { - return this.FirstOrDefault(n => n.ID == ID); - } - - public class Level - { - public ushort ID { get; set; } = 0; - public uint Pointer { get; set; } = 0; - public string Name { get; set; } = ""; - public string Number { get; set; } = ""; - public LevelTypes Type { get; set; } = LevelTypes.Level; - public int Index { get; set; } = -1; - - public string TypeString - { - get - { - var switchExpr = Type; - switch (switchExpr) - { - case LevelTypes.Level: - { - return "Level"; - } - - case LevelTypes.Sidelevel: - { - return "Side"; - } - - case LevelTypes.Overworld: - { - return "OW"; - } - - case LevelTypes.Bowsercourse: - { - return "BC"; - } - - case LevelTypes.Bowserbattle: - { - return "BB"; - } - - case LevelTypes.Switchpalace: - { - return "Switch"; - } - - default: - { - return ""; - } - } - } - - set - { - switch (value) - { - case "Level": - { - Type = LevelTypes.Level; - break; - } - - case "Side": - { - Type = LevelTypes.Sidelevel; - break; - } - - case "OW": - { - Type = LevelTypes.Overworld; - break; - } - - case "BC": - { - Type = LevelTypes.Bowsercourse; - break; - } - - case "BB": - { - Type = LevelTypes.Bowserbattle; - break; - } - - case "Switch": - { - Type = LevelTypes.Switchpalace; - break; - } - } - } - } - } - - public enum LevelTypes - { - Level, - Sidelevel, - Overworld, - Switchpalace, - Bowsercourse, - Bowserbattle - } + } + + public Level GetByLevelID(ushort ID) + { + return this.FirstOrDefault(n => n.ID == ID); + } + + public class Level + { + public ushort ID { get; set; } = 0; + public uint Pointer { get; set; } = 0; + public string Name { get; set; } = ""; + public string Number { get; set; } = ""; + public LevelTypes Type { get; set; } = LevelTypes.Level; + public int Index { get; set; } = -1; + + public string TypeString + { + get + { + var switchExpr = Type; + switch (switchExpr) + { + case LevelTypes.Level: + { + return "Level"; + } + + case LevelTypes.Sidelevel: + { + return "Side"; + } + + case LevelTypes.Overworld: + { + return "OW"; + } + + case LevelTypes.Bowsercourse: + { + return "BC"; + } + + case LevelTypes.Bowserbattle: + { + return "BB"; + } + + case LevelTypes.Switchpalace: + { + return "Switch"; + } + + default: + { + return ""; + } + } + } + + set + { + switch (value) + { + case "Level": + { + Type = LevelTypes.Level; + break; + } + + case "Side": + { + Type = LevelTypes.Sidelevel; + break; + } + + case "OW": + { + Type = LevelTypes.Overworld; + break; + } + + case "BC": + { + Type = LevelTypes.Bowsercourse; + break; + } + + case "BB": + { + Type = LevelTypes.Bowserbattle; + break; + } + + case "Switch": + { + Type = LevelTypes.Switchpalace; + break; + } + } + } + } + } + + public enum LevelTypes + { + Level, + Sidelevel, + Overworld, + Switchpalace, + Bowsercourse, + Bowserbattle } } \ No newline at end of file diff --git a/SM64Lib/Level/LevelList.cs b/SM64Lib/Level/LevelList.cs index 778b681..895bc0a 100644 --- a/SM64Lib/Level/LevelList.cs +++ b/SM64Lib/Level/LevelList.cs @@ -2,21 +2,20 @@ using System.Data; using System.Linq; -namespace SM64Lib.Levels -{ - public class LevelList : List - { - public bool NeedToSave - { - get - { - return this.Where(n => n.NeedToSaveLevelscript || n.NeedToSaveBanks0E).Count() > 0; - } - } +namespace SM64Lib.Levels; - public long Length +public class LevelList : List +{ + public bool NeedToSave + { + get { - get => this.Sum(n => n.Length); + return this.Where(n => n.NeedToSaveLevelscript || n.NeedToSaveBanks0E).Count() > 0; } } + + public long Length + { + get => this.Sum(n => n.Length); + } } \ No newline at end of file diff --git a/SM64Lib/Level/LevelManager.cs b/SM64Lib/Level/LevelManager.cs index a51b088..bda2a30 100644 --- a/SM64Lib/Level/LevelManager.cs +++ b/SM64Lib/Level/LevelManager.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Data; -using global::System.IO; -using System.Linq; -using Microsoft.VisualBasic.CompilerServices; -using global::SM64Lib.Data; +using global::SM64Lib.Data; using global::SM64Lib.Data.System; using global::SM64Lib.Geolayout.Script; using global::SM64Lib.Geolayout.Script.Commands; @@ -13,882 +7,886 @@ using global::SM64Lib.Levels.Script.Commands; using global::SM64Lib.Levels.ScrolTex; using global::SM64Lib.Model; using global::SM64Lib.SegmentedBanking; +using global::System.IO; +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; -namespace SM64Lib.Levels +namespace SM64Lib.Levels; + +public class LevelManager : ILevelManager { - public class LevelManager : ILevelManager + public bool EnableLoadingAreaReverb { get; set; } = true; + public bool SortSpecialBoxesByHeight { get; set; } = true; + + /// + /// Loads a ROM Manager Level from ROM. + /// + /// + /// + /// + /// + public virtual void LoadLevel(Level lvl, RomManager rommgr, ushort LevelID, uint segAddress) { - public bool EnableLoadingAreaReverb { get; set; } = true; - public bool SortSpecialBoxesByHeight { get; set; } = true; + int customBGStart = 0; + int customBGEnd = 0; + lvl.LevelID = LevelID; - /// - /// Loads a ROM Manager Level from ROM. - /// - /// - /// - /// - /// - public virtual void LoadLevel(Level lvl, RomManager rommgr, ushort LevelID, uint segAddress) + // Load Bank 0x19 + lvl.Bank0x19 = rommgr.GetSegBank(0x19); + lvl.Bank0x19.ReadDataIfNull(rommgr.RomFile); + + // Close if not closed & re-open + if (!lvl.Closed) lvl.Close(); + lvl.Closed = false; + + // Lade Levelscript + lvl.Levelscript = new Levelscript(); + lvl.Levelscript.Read(rommgr, Convert.ToInt32(segAddress)); + + // Erstelle Areas / Lade Einstellungen + bool AreaOnFly = false; + LevelArea tArea = null; + var CurrentLevelScriptCommands = lvl.Levelscript.ToArray(); + var cmdsToRemove = new List(); + foreach (LevelscriptCommand c in CurrentLevelScriptCommands) { - int customBGStart = 0; - int customBGEnd = 0; - lvl.LevelID = LevelID; - - // Load Bank 0x19 - lvl.Bank0x19 = rommgr.GetSegBank(0x19); - lvl.Bank0x19.ReadDataIfNull(rommgr.RomFile); - - // Close if not closed & re-open - if (!lvl.Closed) lvl.Close(); - lvl.Closed = false; - - // Lade Levelscript - lvl.Levelscript = new Levelscript(); - lvl.Levelscript.Read(rommgr, Convert.ToInt32(segAddress)); - - // Erstelle Areas / Lade Einstellungen - bool AreaOnFly = false; - LevelArea tArea = null; - var CurrentLevelScriptCommands = lvl.Levelscript.ToArray(); - var cmdsToRemove = new List(); - foreach (LevelscriptCommand c in CurrentLevelScriptCommands) + var switchExpr = c.CommandType; + switch (switchExpr) { - var switchExpr = c.CommandType; - switch (switchExpr) - { - case LevelscriptCommandTypes.StartArea: - AreaOnFly = true; - tArea = new RMLevelArea(); - tArea.AreaID = clStartArea.GetAreaID(c); - tArea.GeolayoutOffset = clStartArea.GetSegGeolayoutAddr(c); // - bank0x19.BankAddress + bank0x19.RomStart - tArea.Geolayout.Read(rommgr, Convert.ToInt32(tArea.GeolayoutOffset)); - break; - case LevelscriptCommandTypes.EndOfArea: - tArea.Levelscript.Add(c); - lvl.Levelscript.Remove(c); - lvl.Areas.Add(tArea); - AreaOnFly = false; - break; - case LevelscriptCommandTypes.AreaMusic: - tArea.BGMusic = clAreaMusic.GetMusicID(c); - break; - case LevelscriptCommandTypes.AreaMusicSimple: - tArea.BGMusic = clAreaMusicSimple.GetMusicID(c); - break; - case LevelscriptCommandTypes.Tarrain: - tArea.TerrainType = (Geolayout.TerrainTypes)clTerrian.GetTerrainType(c); - break; - case LevelscriptCommandTypes.Normal3DObject: - var scrollTexAddrs = new List(new[] { 0x400000, 0x401700 }); - if (rommgr.RomConfig.ScrollTexConfig.UseCustomBehavior) - scrollTexAddrs.Add(rommgr.RomConfig.ScrollTexConfig.CustomBehaviorAddress); - if (scrollTexAddrs.Contains((int)clNormal3DObject.GetSegBehaviorAddr(c))) - tArea.ScrollingTextures.Add(new ManagedScrollingTexture(c)); - else - tArea.Objects.Add(c); - break; - case LevelscriptCommandTypes.ConnectedWarp: - if ((new[] { 0xF0, 0xF1 }).Contains(clWarp.GetWarpID(c))) - tArea.WarpsForGame.Add(c); - else - tArea.Warps.Add(c); - break; - case LevelscriptCommandTypes.PaintingWarp: - case LevelscriptCommandTypes.InstantWarp: + case LevelscriptCommandTypes.StartArea: + AreaOnFly = true; + tArea = new RMLevelArea(); + tArea.AreaID = clStartArea.GetAreaID(c); + tArea.GeolayoutOffset = clStartArea.GetSegGeolayoutAddr(c); // - bank0x19.BankAddress + bank0x19.RomStart + tArea.Geolayout.Read(rommgr, Convert.ToInt32(tArea.GeolayoutOffset)); + break; + case LevelscriptCommandTypes.EndOfArea: + tArea.Levelscript.Add(c); + lvl.Levelscript.Remove(c); + lvl.Areas.Add(tArea); + AreaOnFly = false; + break; + case LevelscriptCommandTypes.AreaMusic: + tArea.BGMusic = clAreaMusic.GetMusicID(c); + break; + case LevelscriptCommandTypes.AreaMusicSimple: + tArea.BGMusic = clAreaMusicSimple.GetMusicID(c); + break; + case LevelscriptCommandTypes.Tarrain: + tArea.TerrainType = (Geolayout.TerrainTypes)clTerrian.GetTerrainType(c); + break; + case LevelscriptCommandTypes.Normal3DObject: + var scrollTexAddrs = new List(new[] { 0x400000, 0x401700 }); + if (rommgr.RomConfig.ScrollTexConfig.UseCustomBehavior) + scrollTexAddrs.Add(rommgr.RomConfig.ScrollTexConfig.CustomBehaviorAddress); + if (scrollTexAddrs.Contains((int)clNormal3DObject.GetSegBehaviorAddr(c))) + tArea.ScrollingTextures.Add(new ManagedScrollingTexture(c)); + else + tArea.Objects.Add(c); + break; + case LevelscriptCommandTypes.ConnectedWarp: + if ((new[] { 0xF0, 0xF1 }).Contains(clWarp.GetWarpID(c))) + tArea.WarpsForGame.Add(c); + else tArea.Warps.Add(c); + break; + case LevelscriptCommandTypes.PaintingWarp: + case LevelscriptCommandTypes.InstantWarp: + tArea.Warps.Add(c); + break; + case LevelscriptCommandTypes.LoadRomToRam: + byte bankID = clLoadRomToRam.GetSegmentedID(c); + int startAddr = clLoadRomToRam.GetRomStart(c); + int endAddr = clLoadRomToRam.GetRomEnd(c); + switch (bankID) + { + case 0xA: // Background-Image + customBGStart = startAddr; + customBGEnd = endAddr - 0x140; + break; + case 0x7: // Global Object Bank + if (rommgr.GlobalModelBank?.CurSeg is not null && startAddr == rommgr.GlobalModelBank.CurSeg.RomStart && endAddr == rommgr.GlobalModelBank.CurSeg.RomEnd) + { + lvl.EnableGlobalObjectBank = true; + lvl.LastGobCmdSegLoad = c; + } + break; + case 0x9: + if (((RMLevel)lvl).Config.EnableLocalObjectBank) + { + lvl.EnableLocalObjectBank = true; + } + lvl.LastLobCmdSegLoad = c; + break; + } + break; + case LevelscriptCommandTypes.ShowDialog: + if (AreaOnFly) + { + tArea.ShowMessage.Enabled = true; + tArea.ShowMessage.DialogID = clShowDialog.GetDialogID(c); + } + break; + case LevelscriptCommandTypes.JumpBack: + case LevelscriptCommandTypes.JumpToSegAddr: + if (tArea is not null) + cmdsToRemove.Add(c); + break; + } + + if (AreaOnFly && !cmdsToRemove.Contains(c)) + { + lvl.Levelscript.Remove(c); + tArea.Levelscript.Add(c); + } + } + + // Lösche alle Jump-Commands aus dem Levelscript + foreach (LevelscriptCommand cmd in cmdsToRemove) + { + lvl.Levelscript.Remove(cmd); + cmd.Close(); + } + + // Lösche alle Objekte und Warps aus dem Levelscript + var lvlscrptidstoremove = new[] { LevelscriptCommandTypes.Normal3DObject, LevelscriptCommandTypes.ConnectedWarp, LevelscriptCommandTypes.PaintingWarp, LevelscriptCommandTypes.InstantWarp }; + foreach (var a in lvl.Areas) + { + foreach (var c in a.Levelscript.Where(n => lvlscrptidstoremove.Contains(n.CommandType)).ToArray()) + a.Levelscript.Remove(c); + } + + // Load Local Object Bank + if (lvl.LastLobCmdSegLoad is not null) + { + var seg = new SegmentedBank() + { + BankID = clLoadRomToRam.GetSegmentedID(lvl.LastLobCmdSegLoad), + RomStart = clLoadRomToRam.GetRomStart(lvl.LastLobCmdSegLoad), + RomEnd = clLoadRomToRam.GetRomEnd(lvl.LastLobCmdSegLoad) + }; + lvl.LocalObjectBank.ReadFromSeg(rommgr, seg, ((RMLevel)lvl).Config.LocalObjectBank); + } + + // Lese Custom Background Image + var fs = new FileStream(rommgr.RomFile, FileMode.Open, FileAccess.Read); + var br2 = new BinaryReader(fs); + lvl.Background.Enabled = false; + foreach (LevelArea a in lvl.Areas) + { + var bgglcmd = a.Geolayout.Geolayoutscript.GetFirst(GeolayoutCommandTypes.Background); + if (cgBackground.GetBackgroundPointer(bgglcmd) == 0) + { + a.Background.Type = AreaBGs.Color; + a.Background.Color = cgBackground.GetRrgbaColor(bgglcmd); + } + else + { + a.Background.Type = AreaBGs.Levelbackground; + lvl.Background.ID = (Geolayout.BackgroundIDs)cgBackground.GetBackgroundID(bgglcmd); + lvl.Background.Enabled = true; + } + } + + if (customBGStart != 0) + { + lvl.Background.IsCustom = true; + } + + foreach (int val in Enum.GetValues(typeof(Geolayout.BackgroundPointers))) + { + if (val != 0 && customBGStart == val) + { + lvl.Background.IsCustom = false; + } + } + + if (lvl.Background.Enabled && lvl.Background.IsCustom) // .ID = Geolayout.BackgroundIDs.Custom Then + { + fs.Position = customBGStart; + lvl.Background.ReadImage(fs, customBGStart); + } + + int bank0x19RomStart; + int bank0x19RomEnd; + BinaryReader brToUse; + bank0x19RomStart = 0; + bank0x19RomEnd = lvl.Bank0x19.Length; + brToUse = new BinaryReader(lvl.Bank0x19.Data); + + // Lese Area-Table + foreach (LevelArea a in lvl.Areas) + { + // Fast3D-Daten + brToUse.BaseStream.Position = bank0x19RomStart + 0x5F00 + a.AreaID * 0x10; + a.Bank0x0EOffset = Convert.ToUInt32(SwapInts.SwapInt32(brToUse.ReadInt32())); + int romEnd0xE = SwapInts.SwapInt32(brToUse.ReadInt32()); + rommgr.SetSegBank(0xE, Convert.ToInt32(a.Bank0x0EOffset), romEnd0xE, a.AreaID); + + // 2D-Kamera + brToUse.BaseStream.Position = bank0x19RomStart + 0x5F0F + a.AreaID * 0x10; + a.Enable2DCamera = Bits.GetBoolOfByte(brToUse.ReadByte(), 7); + } + + // Lese Area-Modelle + foreach (LevelArea a in lvl.Areas) + { + a.AreaModel.FromStream(fs, Convert.ToInt32(a.Bank0x0EOffset), 0xE000000, a.Fast3DBankRomStart, a.Fast3DLength, a.Geolayout.Geopointers.ToArray(), a.CollisionPointer, rommgr.RomConfig.CollisionBaseConfig); + } + + // Lese alle Box-Daten + int CurrentBoxOffset = bank0x19RomStart + 0x6A00; + foreach (LevelArea a in lvl.Areas.Where(n => n.AreaID < 8)) + { + // Clear special boxes + a.SpecialBoxes.Clear(); + + // Load special boxes + a.SpecialBoxes.AddRange(SpecialBoxList.ReadTable(brToUse.BaseStream, SpecialBoxType.Water, bank0x19RomStart, bank0x19RomStart + 0x6000 + 0x50 * a.AreaID)); + a.SpecialBoxes.AddRange(SpecialBoxList.ReadTable(brToUse.BaseStream, SpecialBoxType.ToxicHaze, bank0x19RomStart, bank0x19RomStart + 0x6280 + 0x50 * a.AreaID)); + a.SpecialBoxes.AddRange(SpecialBoxList.ReadTable(brToUse.BaseStream, SpecialBoxType.Mist, bank0x19RomStart, bank0x19RomStart + 0x6500 + 0x50 * a.AreaID)); + + for (int i = 0; i < a.SpecialBoxes.Count; i++) + { + var boxdata = a.AreaModel.Collision.SpecialBoxes.ElementAtOrDefault(i); + if (boxdata is not null) + { + a.SpecialBoxes[i].Y = boxdata.Y; + } + } + } + + // One-Bank-0xE-System + lvl.OneBank0xESystemEnabled = true; + + // Act Selector + General.PatchClass.Open(fs); + lvl.ActSelector = General.PatchClass.get_ActSelector_Enabled(LevelID); + + // Hardcoded Camera + lvl.HardcodedCameraSettings = General.PatchClass.get_HardcodedCamera_Enabled(LevelID); + + // Area Reverb + if (EnableLoadingAreaReverb) + { + foreach (var area in lvl.Areas) + { + if (area is RMLevelArea && area.AreaID >= 1 && area.AreaID <= 3) + { + fs.Position = 0xEE0C0 + lvl.LevelID * 3 + area.AreaID - 1; + ((RMLevelArea)area).ReverbLevel = (AreaReverbLevel)fs.ReadByte(); + } + } + } + + fs.Close(); + } + + /// + /// Saves a ROM Manager Level to ROM. + /// + /// + /// + /// + /// + /// + public virtual LevelSaveResult SaveLevel(Level lvl, RomManager rommgr, BinaryData output, ref uint curOff) + { + var saveres = new LevelSaveResult(); + BinaryData data0x19; + var lid = rommgr.LevelInfoData.GetByLevelID(lvl.LevelID); + + // Write Area Model & Update Scrolling Texture Vertex Pointers & Write Custom Object Bank + foreach (LevelArea a in lvl.Areas) + { + var CollisionBoxTableIndex = new[] { 0, 0x32, 0x33 }; + a.Bank0x0EOffset = curOff; + + if (SortSpecialBoxesByHeight) + a.SpecialBoxes.SortByHeight(); + + int oldModelStart = a.AreaModel.Fast3DBuffer.Fast3DBankStart; + int newModelStart; + int modelOffset; + + // Add the new water boxes + a.AreaModel.Collision.SpecialBoxes.Clear(); + foreach (SpecialBox sp in a.SpecialBoxes) + { + var boxdata = new Model.Collision.BoxData + { + X1 = sp.X1, + X2 = sp.X2, + Z1 = sp.Z1, + Z2 = sp.Z2, + Y = sp.Y, + Index = (short)CollisionBoxTableIndex[(int)sp.Type] + }; + + switch (sp.Type) + { + case SpecialBoxType.Water: + boxdata.Type = Model.Collision.BoxDataType.Water; + CollisionBoxTableIndex[(int)sp.Type] += 1; break; - case LevelscriptCommandTypes.LoadRomToRam: - byte bankID = clLoadRomToRam.GetSegmentedID(c); - int startAddr = clLoadRomToRam.GetRomStart(c); - int endAddr = clLoadRomToRam.GetRomEnd(c); - switch (bankID) + case SpecialBoxType.Mist: + boxdata.Type = Model.Collision.BoxDataType.Mist; + CollisionBoxTableIndex[(int)sp.Type] += 1; + break; + case SpecialBoxType.ToxicHaze: + boxdata.Type = Model.Collision.BoxDataType.ToxicHaze; + CollisionBoxTableIndex[(int)sp.Type] += 10; + break; + } + + a.AreaModel.Collision.SpecialBoxes.Add(boxdata); + } + + // Write Area Model + ObjectModel.SaveResult res; + res = a.AreaModel.ToBinaryData(output, (int)curOff, (int)curOff, 0xE000000, rommgr.RomConfig.CollisionBaseConfig); + + // Calculate Model Offset & Update Scrolling Texture Vertex Pointers + newModelStart = a.AreaModel.Fast3DBuffer.Fast3DBankStart; + modelOffset = newModelStart - oldModelStart; + if (modelOffset != 0) + { + a.UpdateScrollingTextureVertexPointer(modelOffset); + } + + a.CollisionPointer = res.CollisionPointer; + a.Geolayout.Geopointers.Clear(); + a.Geolayout.Geopointers.AddRange(res.GeoPointers.ToArray()); + curOff += (uint)(res.Length + 0x20); + General.HexRoundUp2(ref curOff); + + a.Bank0xELength = (int)(curOff - a.Bank0x0EOffset); + } + + // Write Background Image + output.RoundUpPosition(); + int customBGStart = Convert.ToInt32(curOff); + int customBGEnd = 0; + if (lvl.Background.IsCustom) // .ID = Geolayout.BackgroundIDs.Custom Then + { + // Write Custom Background + lvl.Background.WriteImage(output.BaseStream, customBGStart); + + // Write Pointer Table + var bgPtrTable = LevelBG.GetBackgroundPointerTable(); + output.Write(bgPtrTable, 0, bgPtrTable.Length); + customBGEnd = customBGStart + lvl.Background.ImageLength + bgPtrTable.Length; + curOff += (uint)lvl.Background.ImageLength + (uint)bgPtrTable.Length; + General.HexRoundUp2(ref curOff); + } + + // Generate & Write Local Object Bank + uint localObjectBankRomStart = 0; + uint localObjectBankRomEnd = 0; + bool writeLocalObjectBank = lvl.LocalObjectBank.Models.Count > 0 && lvl.EnableLocalObjectBank; + if (writeLocalObjectBank) + { + localObjectBankRomStart = curOff; + curOff += (uint)lvl.LocalObjectBank.WriteToSeg(output, (int)curOff, 0x9, rommgr.RomConfig.CollisionBaseConfig); + localObjectBankRomEnd = curOff; + ((RMLevel)lvl).Config.LocalObjectBank = lvl.LocalObjectBank.Config; + lvl.LocalObjectBank.WriteCollisionPointers(output); + } + ((RMLevel)lvl).Config.EnableLocalObjectBank = writeLocalObjectBank; + + // Get Bank 0x19 + if (lvl.Bank0x19 is null) + { + lvl.Bank0x19 = rommgr.SetSegBank(0x19, Convert.ToInt32(curOff), (int)RomManagerSettings.DefaultLevelscriptSize); + lvl.Bank0x19.Data = new MemoryStream(); + lvl.Bank0x19.Length = (int)RomManagerSettings.DefaultLevelscriptSize; + } + else + { + var oldData = lvl.Bank0x19.Data; + lvl.Bank0x19 = rommgr.SetSegBank(0x19, Convert.ToInt32(curOff), (int)(curOff + lvl.Bank0x19.Length)); + lvl.Bank0x19.Data = oldData; + } + + data0x19 = new BinaryStreamData(lvl.Bank0x19.Data); + saveres.Bank0x19 = lvl.Bank0x19; + curOff += (uint)lvl.Bank0x19.Data.Length; + General.HexRoundUp2(ref curOff); + + // Update Geolayouts + foreach (LevelArea a in lvl.Areas) + { + // Update Backcolor Command + var cmd = a.Geolayout.Geolayoutscript.GetFirst(GeolayoutCommandTypes.Background); + if (a.Background.Type == AreaBGs.Levelbackground && lvl.Background.Enabled) + { + cgBackground.SetBackgroundPointer(cmd, unchecked((int)0x802763D4)); + cgBackground.SetBackgroundID(cmd, (short)lvl.Background.ID); + } + else + { + cgBackground.SetBackgroundPointer(cmd, 0); + cgBackground.SetRgbaColor(cmd, a.Background.Color); + } + } + + // Write Geolayouts + int geoOffset = 0x5F00; + foreach (LevelArea a in lvl.Areas) + { + geoOffset -= General.HexRoundUp1(a.Geolayout.Length) + 0x50; + a.GeolayoutOffset = (uint)(lvl.Bank0x19.BankAddress + geoOffset); + a.Geolayout.Write(lvl.Bank0x19.Data, geoOffset); + a.Geolayout.NewGeoOffset = lvl.Bank0x19.RomStart + geoOffset; + } + + // Füge Show-Dialog-Command & 2D-Camera-Object ein + foreach (LevelArea a in lvl.Areas) + { + // Show-Dialog-Command + if (a.ShowMessage.Enabled) + { + var cmdShowMsg = new LevelscriptCommand($"30 04 00 {a.ShowMessage.DialogID.ToString("X2")}"); + int indexOf1E = a.Levelscript.IndexOfFirst(LevelscriptCommandTypes.EndOfArea); + a.Levelscript.Insert(indexOf1E, cmdShowMsg); + } + + // 2D-Camera-Object + if (rommgr.RomConfig.PatchingConfig.Patched2DCamera) + { + var cmds2d = new List(); + foreach (LevelscriptCommand obj in a.Objects) + { + if (obj.CommandType == LevelscriptCommandTypes.Normal3DObject) + { + if (clNormal3DObject.GetSegBehaviorAddr(obj) == (long)0x130053C4) // Behav-ID: '0x130053C4 { - case 0xA: // Background-Image - customBGStart = startAddr; - customBGEnd = endAddr - 0x140; + cmds2d.Add(obj); + } + } + } + + if (a.Enable2DCamera) + { + if (cmds2d.Count == 0) + { + var cmd = new LevelscriptCommand("24 18 1F 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 13 00 53 C4"); + a.Objects.Add(cmd); + } + } + else if (cmds2d.Count > 0) + { + foreach (LevelscriptCommand cmd in cmds2d) + a.Objects.Remove(cmd); + } + } + } + + Levelscript lvlScript0E = null; + Dictionary areaobjwarpoffsetdic = null; + SegmentedBank firstBank0xE = null; + uint curFirstBank0xEOffset = 0; + + // Add Objects and Warps to new Levelscript + lvlScript0E = new Levelscript(); + firstBank0xE = rommgr.SetSegBank(0xE, Convert.ToInt32(curOff), 0); + areaobjwarpoffsetdic = new Dictionary(); + foreach (LevelArea a in lvl.Areas) + { + areaobjwarpoffsetdic.Add(a.AreaID, (uint)(firstBank0xE.BankAddress + curFirstBank0xEOffset)); + foreach (LevelscriptCommand c in a.Objects) + { + lvlScript0E.Add(c); + curFirstBank0xEOffset += (uint)c.Length; + } + + foreach (ManagedScrollingTexture c in a.ScrollingTextures) + { + c.SaveProperties(rommgr.RomConfig.ScrollTexConfig); + lvlScript0E.Add(c.Command); + curFirstBank0xEOffset += (uint)c.Command.Length; + } + + foreach (LevelscriptCommand c in a.Warps) + { + lvlScript0E.Add(c); + curFirstBank0xEOffset += (uint)c.Length; + } + + foreach (LevelscriptCommand c in a.WarpsForGame) + { + lvlScript0E.Add(c); + curFirstBank0xEOffset += (uint)c.Length; + } + + lvlScript0E.Add(new LevelscriptCommand("07 04 00 00")); + curFirstBank0xEOffset += 4; + } + + firstBank0xE.Length = (int)General.HexRoundUp1(curFirstBank0xEOffset); + lvlScript0E.Write(output, firstBank0xE.RomStart); + curOff += (uint)firstBank0xE.Length; + + // Füge Area dem Levelscript hinzu + int cIndex2 = lvl.Levelscript.IndexOfFirst(LevelscriptCommandTypes.x1E); + foreach (var a in lvl.Areas) + { + foreach (var c in a.Levelscript) + { + lvl.Levelscript.Insert(cIndex2, c); + cIndex2 += 1; + } + } + + // Übernehme Level- und Areaeinstellungen + int CurrentAreaIndex = 0; + var areaobjwarpindextoinsertdic = new Dictionary(); + var areaidindex = new Dictionary(); + LevelArea tArea = null; + bool foundCmdShowMsg = false; + LevelscriptCommand cmdBgSegLoad = null; + LevelscriptCommand cmdGobSegLoad = null; + LevelscriptCommand cmdGobJump = null; + LevelscriptCommand cmdLobSegLoad = null; + LevelscriptCommand cmdLobJump = null; + var cmdsToInsertAt = new Dictionary(); + var cmdsToRemove = new List(); + foreach (var c in lvl.Levelscript) + { + var switchExpr1 = c.CommandType; + switch (switchExpr1) + { + case LevelscriptCommandTypes.StartArea: + { + tArea = lvl.Areas[CurrentAreaIndex]; + byte areaid = tArea.AreaID; + areaidindex.Add(areaid, Convert.ToByte(areaidindex.Count)); + clStartArea.SetSegGeolayoutAddr(c, (uint)(lvl.Areas[CurrentAreaIndex].Geolayout.NewGeoOffset - lvl.Bank0x19.RomStart + lvl.Bank0x19.BankAddress)); + clStartArea.SetAreaID(c, areaid); + areaobjwarpindextoinsertdic.Add(areaid, lvl.Levelscript.IndexOf(c) + 1); + break; + } + + case LevelscriptCommandTypes.EndOfArea: + { + if (!foundCmdShowMsg && tArea.ShowMessage.Enabled) + { + var cmdShowMsg = new LevelscriptCommand($"30 04 00 {tArea.ShowMessage.DialogID.ToString("X2")}"); + cmdsToInsertAt.Add((LevelscriptCommand)c, cmdShowMsg); + } + + foundCmdShowMsg = false; + CurrentAreaIndex += 1; + tArea = null; + break; + } + + case LevelscriptCommandTypes.AreaMusic: + { + clAreaMusic.SetMusicID((LevelscriptCommand)c, lvl.Areas[CurrentAreaIndex].BGMusic); + break; + } + + case LevelscriptCommandTypes.AreaMusicSimple: + { + clAreaMusicSimple.SetMusicID((LevelscriptCommand)c, lvl.Areas[CurrentAreaIndex].BGMusic); + break; + } + + case LevelscriptCommandTypes.Tarrain: + { + clTerrian.SetTerrainType((LevelscriptCommand)c, (byte)lvl.Areas[CurrentAreaIndex].TerrainType); + break; + } + + case LevelscriptCommandTypes.LoadRomToRam: + { + var switchExpr2 = clLoadRomToRam.GetSegmentedID((LevelscriptCommand)c); + switch (switchExpr2) + { + case 0xE: // Bank 0xE + clLoadRomToRam.SetRomStart((LevelscriptCommand)c, firstBank0xE.RomStart); + clLoadRomToRam.SetRomEnd((LevelscriptCommand)c, firstBank0xE.RomEnd); break; - case 0x7: // Global Object Bank - if (rommgr.GlobalModelBank?.CurSeg is not null && startAddr == rommgr.GlobalModelBank.CurSeg.RomStart && endAddr == rommgr.GlobalModelBank.CurSeg.RomEnd) + case 0xA: + cmdBgSegLoad = (LevelscriptCommand)c; + break; + case 0x7: + if (lvl.LastGobCmdSegLoad == c) { - lvl.EnableGlobalObjectBank = true; - lvl.LastGobCmdSegLoad = c; + cmdGobSegLoad = (LevelscriptCommand)c; } break; case 0x9: - if (((RMLevel)lvl).Config.EnableLocalObjectBank) + if (lvl.LastLobCmdSegLoad == c) { - lvl.EnableLocalObjectBank = true; + cmdLobSegLoad = (LevelscriptCommand)c; } - lvl.LastLobCmdSegLoad = c; + break; + } + + break; + } + + case LevelscriptCommandTypes.ShowDialog: + { + if ((bool)tArea?.ShowMessage.Enabled && !foundCmdShowMsg) + { + clShowDialog.SetDialogID((LevelscriptCommand)c, tArea.ShowMessage.DialogID); + foundCmdShowMsg = true; + } + else + { + cmdsToRemove.Add((LevelscriptCommand)c); + } + + break; + } + + case LevelscriptCommandTypes.JumpToSegAddr: + { + int bankID = clJumpToSegAddr.GetSegJumpAddr((LevelscriptCommand)c) >> 24; + switch (bankID) + { + case 0x7: + cmdGobJump = (LevelscriptCommand)c; + break; + case 0x9: + cmdLobJump = (LevelscriptCommand)c; break; } break; - case LevelscriptCommandTypes.ShowDialog: - if (AreaOnFly) - { - tArea.ShowMessage.Enabled = true; - tArea.ShowMessage.DialogID = clShowDialog.GetDialogID(c); - } - break; - case LevelscriptCommandTypes.JumpBack: - case LevelscriptCommandTypes.JumpToSegAddr: - if (tArea is not null) - cmdsToRemove.Add(c); - break; - } - - if (AreaOnFly && !cmdsToRemove.Contains(c)) - { - lvl.Levelscript.Remove(c); - tArea.Levelscript.Add(c); - } - } - - // Lösche alle Jump-Commands aus dem Levelscript - foreach (LevelscriptCommand cmd in cmdsToRemove) - { - lvl.Levelscript.Remove(cmd); - cmd.Close(); - } - - // Lösche alle Objekte und Warps aus dem Levelscript - var lvlscrptidstoremove = new[] { LevelscriptCommandTypes.Normal3DObject, LevelscriptCommandTypes.ConnectedWarp, LevelscriptCommandTypes.PaintingWarp, LevelscriptCommandTypes.InstantWarp }; - foreach (var a in lvl.Areas) - { - foreach (var c in a.Levelscript.Where(n => lvlscrptidstoremove.Contains(n.CommandType)).ToArray()) - a.Levelscript.Remove(c); - } - - // Load Local Object Bank - if (lvl.LastLobCmdSegLoad is not null) - { - var seg = new SegmentedBank() - { - BankID = clLoadRomToRam.GetSegmentedID(lvl.LastLobCmdSegLoad), - RomStart = clLoadRomToRam.GetRomStart(lvl.LastLobCmdSegLoad), - RomEnd = clLoadRomToRam.GetRomEnd(lvl.LastLobCmdSegLoad) - }; - lvl.LocalObjectBank.ReadFromSeg(rommgr, seg, ((RMLevel)lvl).Config.LocalObjectBank); - } - - // Lese Custom Background Image - var fs = new FileStream(rommgr.RomFile, FileMode.Open, FileAccess.Read); - var br2 = new BinaryReader(fs); - lvl.Background.Enabled = false; - foreach (LevelArea a in lvl.Areas) - { - var bgglcmd = a.Geolayout.Geolayoutscript.GetFirst(GeolayoutCommandTypes.Background); - if (cgBackground.GetBackgroundPointer(bgglcmd) == 0) - { - a.Background.Type = AreaBGs.Color; - a.Background.Color = cgBackground.GetRrgbaColor(bgglcmd); - } - else - { - a.Background.Type = AreaBGs.Levelbackground; - lvl.Background.ID = (Geolayout.BackgroundIDs)cgBackground.GetBackgroundID(bgglcmd); - lvl.Background.Enabled = true; - } - } - - if (customBGStart != 0) - { - lvl.Background.IsCustom = true; - } - - foreach (int val in Enum.GetValues(typeof(Geolayout.BackgroundPointers))) - { - if (val != 0 && customBGStart == val) - { - lvl.Background.IsCustom = false; - } - } - - if (lvl.Background.Enabled && lvl.Background.IsCustom) // .ID = Geolayout.BackgroundIDs.Custom Then - { - fs.Position = customBGStart; - lvl.Background.ReadImage(fs, customBGStart); - } - - int bank0x19RomStart; - int bank0x19RomEnd; - BinaryReader brToUse; - bank0x19RomStart = 0; - bank0x19RomEnd = lvl.Bank0x19.Length; - brToUse = new BinaryReader(lvl.Bank0x19.Data); - - // Lese Area-Table - foreach (LevelArea a in lvl.Areas) - { - // Fast3D-Daten - brToUse.BaseStream.Position = bank0x19RomStart + 0x5F00 + a.AreaID * 0x10; - a.Bank0x0EOffset = Convert.ToUInt32(SwapInts.SwapInt32(brToUse.ReadInt32())); - int romEnd0xE = SwapInts.SwapInt32(brToUse.ReadInt32()); - rommgr.SetSegBank(0xE, Convert.ToInt32(a.Bank0x0EOffset), romEnd0xE, a.AreaID); - - // 2D-Kamera - brToUse.BaseStream.Position = bank0x19RomStart + 0x5F0F + a.AreaID * 0x10; - a.Enable2DCamera = Bits.GetBoolOfByte(brToUse.ReadByte(), 7); - } - - // Lese Area-Modelle - foreach (LevelArea a in lvl.Areas) - { - a.AreaModel.FromStream(fs, Convert.ToInt32(a.Bank0x0EOffset), 0xE000000, a.Fast3DBankRomStart, a.Fast3DLength, a.Geolayout.Geopointers.ToArray(), a.CollisionPointer, rommgr.RomConfig.CollisionBaseConfig); - } - - // Lese alle Box-Daten - int CurrentBoxOffset = bank0x19RomStart + 0x6A00; - foreach (LevelArea a in lvl.Areas.Where(n => n.AreaID < 8)) - { - // Clear special boxes - a.SpecialBoxes.Clear(); - - // Load special boxes - a.SpecialBoxes.AddRange(SpecialBoxList.ReadTable(brToUse.BaseStream, SpecialBoxType.Water, bank0x19RomStart, bank0x19RomStart + 0x6000 + 0x50 * a.AreaID)); - a.SpecialBoxes.AddRange(SpecialBoxList.ReadTable(brToUse.BaseStream, SpecialBoxType.ToxicHaze, bank0x19RomStart, bank0x19RomStart + 0x6280 + 0x50 * a.AreaID)); - a.SpecialBoxes.AddRange(SpecialBoxList.ReadTable(brToUse.BaseStream, SpecialBoxType.Mist, bank0x19RomStart, bank0x19RomStart + 0x6500 + 0x50 * a.AreaID)); - - for (int i = 0; i < a.SpecialBoxes.Count; i++) - { - var boxdata = a.AreaModel.Collision.SpecialBoxes.ElementAtOrDefault(i); - if (boxdata is not null) - { - a.SpecialBoxes[i].Y = boxdata.Y; } - } } - - // One-Bank-0xE-System - lvl.OneBank0xESystemEnabled = true; - - // Act Selector - General.PatchClass.Open(fs); - lvl.ActSelector = General.PatchClass.get_ActSelector_Enabled(LevelID); - - // Hardcoded Camera - lvl.HardcodedCameraSettings = General.PatchClass.get_HardcodedCamera_Enabled(LevelID); - - // Area Reverb - if (EnableLoadingAreaReverb) - { - foreach (var area in lvl.Areas) - { - if (area is RMLevelArea && area.AreaID >= 1 && area.AreaID <= 3) - { - fs.Position = 0xEE0C0 + lvl.LevelID * 3 + area.AreaID - 1; - ((RMLevelArea)area).ReverbLevel = (AreaReverbLevel)fs.ReadByte(); - } - } - } - - fs.Close(); } - /// - /// Saves a ROM Manager Level to ROM. - /// - /// - /// - /// - /// - /// - public virtual LevelSaveResult SaveLevel(Level lvl, RomManager rommgr, BinaryData output, ref uint curOff) + // Füge Jump Commands zur ersten 0xE-Bank hinzu + foreach (var e in areaobjwarpindextoinsertdic.OrderByDescending(n => n.Value)) { - var saveres = new LevelSaveResult(); - BinaryData data0x19; - var lid = rommgr.LevelInfoData.GetByLevelID(lvl.LevelID); - - // Write Area Model & Update Scrolling Texture Vertex Pointers & Write Custom Object Bank - foreach (LevelArea a in lvl.Areas) - { - var CollisionBoxTableIndex = new[] { 0, 0x32, 0x33 }; - a.Bank0x0EOffset = curOff; - - if (SortSpecialBoxesByHeight) - a.SpecialBoxes.SortByHeight(); - - int oldModelStart = a.AreaModel.Fast3DBuffer.Fast3DBankStart; - int newModelStart; - int modelOffset; - - // Add the new water boxes - a.AreaModel.Collision.SpecialBoxes.Clear(); - foreach (SpecialBox sp in a.SpecialBoxes) - { - var boxdata = new Model.Collision.BoxData - { - X1 = sp.X1, - X2 = sp.X2, - Z1 = sp.Z1, - Z2 = sp.Z2, - Y = sp.Y, - Index = (short)CollisionBoxTableIndex[(int)sp.Type] - }; - - switch (sp.Type) - { - case SpecialBoxType.Water: - boxdata.Type = Model.Collision.BoxDataType.Water; - CollisionBoxTableIndex[(int)sp.Type] += 1; - break; - case SpecialBoxType.Mist: - boxdata.Type = Model.Collision.BoxDataType.Mist; - CollisionBoxTableIndex[(int)sp.Type] += 1; - break; - case SpecialBoxType.ToxicHaze: - boxdata.Type = Model.Collision.BoxDataType.ToxicHaze; - CollisionBoxTableIndex[(int)sp.Type] += 10; - break; - } - - a.AreaModel.Collision.SpecialBoxes.Add(boxdata); - } - - // Write Area Model - ObjectModel.SaveResult res; - res = a.AreaModel.ToBinaryData(output, (int)curOff, (int)curOff, 0xE000000, rommgr.RomConfig.CollisionBaseConfig); - - // Calculate Model Offset & Update Scrolling Texture Vertex Pointers - newModelStart = a.AreaModel.Fast3DBuffer.Fast3DBankStart; - modelOffset = newModelStart - oldModelStart; - if (modelOffset != 0) - { - a.UpdateScrollingTextureVertexPointer(modelOffset); - } - - a.CollisionPointer = res.CollisionPointer; - a.Geolayout.Geopointers.Clear(); - a.Geolayout.Geopointers.AddRange(res.GeoPointers.ToArray()); - curOff += (uint)(res.Length + 0x20); - General.HexRoundUp2(ref curOff); - - a.Bank0xELength = (int)(curOff - a.Bank0x0EOffset); - } - - // Write Background Image - output.RoundUpPosition(); - int customBGStart = Convert.ToInt32(curOff); - int customBGEnd = 0; - if (lvl.Background.IsCustom) // .ID = Geolayout.BackgroundIDs.Custom Then - { - // Write Custom Background - lvl.Background.WriteImage(output.BaseStream, customBGStart); - - // Write Pointer Table - var bgPtrTable = LevelBG.GetBackgroundPointerTable(); - output.Write(bgPtrTable, 0, bgPtrTable.Length); - customBGEnd = customBGStart + lvl.Background.ImageLength + bgPtrTable.Length; - curOff += (uint)lvl.Background.ImageLength + (uint)bgPtrTable.Length; - General.HexRoundUp2(ref curOff); - } - - // Generate & Write Local Object Bank - uint localObjectBankRomStart = 0; - uint localObjectBankRomEnd = 0; - bool writeLocalObjectBank = lvl.LocalObjectBank.Models.Count > 0 && lvl.EnableLocalObjectBank; - if (writeLocalObjectBank) - { - localObjectBankRomStart = curOff; - curOff += (uint)lvl.LocalObjectBank.WriteToSeg(output, (int)curOff, 0x9, rommgr.RomConfig.CollisionBaseConfig); - localObjectBankRomEnd = curOff; - ((RMLevel)lvl).Config.LocalObjectBank = lvl.LocalObjectBank.Config; - lvl.LocalObjectBank.WriteCollisionPointers(output); - } - ((RMLevel)lvl).Config.EnableLocalObjectBank = writeLocalObjectBank; - - // Get Bank 0x19 - if (lvl.Bank0x19 is null) - { - lvl.Bank0x19 = rommgr.SetSegBank(0x19, Convert.ToInt32(curOff), (int)RomManagerSettings.DefaultLevelscriptSize); - lvl.Bank0x19.Data = new MemoryStream(); - lvl.Bank0x19.Length = (int)RomManagerSettings.DefaultLevelscriptSize; - } - else - { - var oldData = lvl.Bank0x19.Data; - lvl.Bank0x19 = rommgr.SetSegBank(0x19, Convert.ToInt32(curOff), (int)(curOff + lvl.Bank0x19.Length)); - lvl.Bank0x19.Data = oldData; - } - - data0x19 = new BinaryStreamData(lvl.Bank0x19.Data); - saveres.Bank0x19 = lvl.Bank0x19; - curOff += (uint)lvl.Bank0x19.Data.Length; - General.HexRoundUp2(ref curOff); - - // Update Geolayouts - foreach (LevelArea a in lvl.Areas) - { - // Update Backcolor Command - var cmd = a.Geolayout.Geolayoutscript.GetFirst(GeolayoutCommandTypes.Background); - if (a.Background.Type == AreaBGs.Levelbackground && lvl.Background.Enabled) - { - cgBackground.SetBackgroundPointer(cmd, unchecked((int)0x802763D4)); - cgBackground.SetBackgroundID(cmd, (short)lvl.Background.ID); - } - else - { - cgBackground.SetBackgroundPointer(cmd, 0); - cgBackground.SetRgbaColor(cmd, a.Background.Color); - } - } - - // Write Geolayouts - int geoOffset = 0x5F00; - foreach (LevelArea a in lvl.Areas) - { - geoOffset -= General.HexRoundUp1(a.Geolayout.Length) + 0x50; - a.GeolayoutOffset = (uint)(lvl.Bank0x19.BankAddress + geoOffset); - a.Geolayout.Write(lvl.Bank0x19.Data, geoOffset); - a.Geolayout.NewGeoOffset = lvl.Bank0x19.RomStart + geoOffset; - } - - // Füge Show-Dialog-Command & 2D-Camera-Object ein - foreach (LevelArea a in lvl.Areas) - { - // Show-Dialog-Command - if (a.ShowMessage.Enabled) - { - var cmdShowMsg = new LevelscriptCommand($"30 04 00 {a.ShowMessage.DialogID.ToString("X2")}"); - int indexOf1E = a.Levelscript.IndexOfFirst(LevelscriptCommandTypes.EndOfArea); - a.Levelscript.Insert(indexOf1E, cmdShowMsg); - } - - // 2D-Camera-Object - if (rommgr.RomConfig.PatchingConfig.Patched2DCamera) - { - var cmds2d = new List(); - foreach (LevelscriptCommand obj in a.Objects) - { - if (obj.CommandType == LevelscriptCommandTypes.Normal3DObject) - { - if (clNormal3DObject.GetSegBehaviorAddr(obj) == (long)0x130053C4) // Behav-ID: '0x130053C4 - { - cmds2d.Add(obj); - } - } - } - - if (a.Enable2DCamera) - { - if (cmds2d.Count == 0) - { - var cmd = new LevelscriptCommand("24 18 1F 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 13 00 53 C4"); - a.Objects.Add(cmd); - } - } - else if (cmds2d.Count > 0) - { - foreach (LevelscriptCommand cmd in cmds2d) - a.Objects.Remove(cmd); - } - } - } - - Levelscript lvlScript0E = null; - Dictionary areaobjwarpoffsetdic = null; - SegmentedBank firstBank0xE = null; - uint curFirstBank0xEOffset = 0; - - // Add Objects and Warps to new Levelscript - lvlScript0E = new Levelscript(); - firstBank0xE = rommgr.SetSegBank(0xE, Convert.ToInt32(curOff), 0); - areaobjwarpoffsetdic = new Dictionary(); - foreach (LevelArea a in lvl.Areas) - { - areaobjwarpoffsetdic.Add(a.AreaID, (uint)(firstBank0xE.BankAddress + curFirstBank0xEOffset)); - foreach (LevelscriptCommand c in a.Objects) - { - lvlScript0E.Add(c); - curFirstBank0xEOffset += (uint)c.Length; - } - - foreach (ManagedScrollingTexture c in a.ScrollingTextures) - { - c.SaveProperties(rommgr.RomConfig.ScrollTexConfig); - lvlScript0E.Add(c.Command); - curFirstBank0xEOffset += (uint)c.Command.Length; - } - - foreach (LevelscriptCommand c in a.Warps) - { - lvlScript0E.Add(c); - curFirstBank0xEOffset += (uint)c.Length; - } - - foreach (LevelscriptCommand c in a.WarpsForGame) - { - lvlScript0E.Add(c); - curFirstBank0xEOffset += (uint)c.Length; - } - - lvlScript0E.Add(new LevelscriptCommand("07 04 00 00")); - curFirstBank0xEOffset += 4; - } - - firstBank0xE.Length = (int)General.HexRoundUp1(curFirstBank0xEOffset); - lvlScript0E.Write(output, firstBank0xE.RomStart); - curOff += (uint)firstBank0xE.Length; - - // Füge Area dem Levelscript hinzu - int cIndex2 = lvl.Levelscript.IndexOfFirst(LevelscriptCommandTypes.x1E); - foreach (var a in lvl.Areas) - { - foreach (var c in a.Levelscript) - { - lvl.Levelscript.Insert(cIndex2, c); - cIndex2 += 1; - } - } - - // Übernehme Level- und Areaeinstellungen - int CurrentAreaIndex = 0; - var areaobjwarpindextoinsertdic = new Dictionary(); - var areaidindex = new Dictionary(); - LevelArea tArea = null; - bool foundCmdShowMsg = false; - LevelscriptCommand cmdBgSegLoad = null; - LevelscriptCommand cmdGobSegLoad = null; - LevelscriptCommand cmdGobJump = null; - LevelscriptCommand cmdLobSegLoad = null; - LevelscriptCommand cmdLobJump = null; - var cmdsToInsertAt = new Dictionary(); - var cmdsToRemove = new List(); - foreach (var c in lvl.Levelscript) - { - var switchExpr1 = c.CommandType; - switch (switchExpr1) - { - case LevelscriptCommandTypes.StartArea: - { - tArea = lvl.Areas[CurrentAreaIndex]; - byte areaid = tArea.AreaID; - areaidindex.Add(areaid, Convert.ToByte(areaidindex.Count)); - clStartArea.SetSegGeolayoutAddr(c, (uint)(lvl.Areas[CurrentAreaIndex].Geolayout.NewGeoOffset - lvl.Bank0x19.RomStart + lvl.Bank0x19.BankAddress)); - clStartArea.SetAreaID(c, areaid); - areaobjwarpindextoinsertdic.Add(areaid, lvl.Levelscript.IndexOf(c) + 1); - break; - } - - case LevelscriptCommandTypes.EndOfArea: - { - if (!foundCmdShowMsg && tArea.ShowMessage.Enabled) - { - var cmdShowMsg = new LevelscriptCommand($"30 04 00 {tArea.ShowMessage.DialogID.ToString("X2")}"); - cmdsToInsertAt.Add((LevelscriptCommand)c, cmdShowMsg); - } - - foundCmdShowMsg = false; - CurrentAreaIndex += 1; - tArea = null; - break; - } - - case LevelscriptCommandTypes.AreaMusic: - { - clAreaMusic.SetMusicID((LevelscriptCommand)c, lvl.Areas[CurrentAreaIndex].BGMusic); - break; - } - - case LevelscriptCommandTypes.AreaMusicSimple: - { - clAreaMusicSimple.SetMusicID((LevelscriptCommand)c, lvl.Areas[CurrentAreaIndex].BGMusic); - break; - } - - case LevelscriptCommandTypes.Tarrain: - { - clTerrian.SetTerrainType((LevelscriptCommand)c, (byte)lvl.Areas[CurrentAreaIndex].TerrainType); - break; - } - - case LevelscriptCommandTypes.LoadRomToRam: - { - var switchExpr2 = clLoadRomToRam.GetSegmentedID((LevelscriptCommand)c); - switch (switchExpr2) - { - case 0xE: // Bank 0xE - clLoadRomToRam.SetRomStart((LevelscriptCommand)c, firstBank0xE.RomStart); - clLoadRomToRam.SetRomEnd((LevelscriptCommand)c, firstBank0xE.RomEnd); - break; - case 0xA: - cmdBgSegLoad = (LevelscriptCommand)c; - break; - case 0x7: - if (lvl.LastGobCmdSegLoad == c) - { - cmdGobSegLoad = (LevelscriptCommand)c; - } - break; - case 0x9: - if (lvl.LastLobCmdSegLoad == c) - { - cmdLobSegLoad = (LevelscriptCommand)c; - } - break; - } - - break; - } - - case LevelscriptCommandTypes.ShowDialog: - { - if ((bool)tArea?.ShowMessage.Enabled && !foundCmdShowMsg) - { - clShowDialog.SetDialogID((LevelscriptCommand)c, tArea.ShowMessage.DialogID); - foundCmdShowMsg = true; - } - else - { - cmdsToRemove.Add((LevelscriptCommand)c); - } - - break; - } - - case LevelscriptCommandTypes.JumpToSegAddr: - { - int bankID = clJumpToSegAddr.GetSegJumpAddr((LevelscriptCommand)c) >> 24; - switch(bankID) - { - case 0x7: - cmdGobJump = (LevelscriptCommand)c; - break; - case 0x9: - cmdLobJump = (LevelscriptCommand)c; - break; - } - break; - } - } - } - - // Füge Jump Commands zur ersten 0xE-Bank hinzu - foreach (var e in areaobjwarpindextoinsertdic.OrderByDescending(n => n.Value)) - { - uint segStartAddr = areaobjwarpoffsetdic[e.Key]; - lvl.Levelscript.Insert(e.Value, new LevelscriptCommand(new byte[] { 0x6, 8, 0, 0, Convert.ToByte((long)(segStartAddr >> 24) & (long)0xFF), Convert.ToByte((long)(segStartAddr >> 16) & (long)0xFF), Convert.ToByte((long)(segStartAddr >> 8) & (long)0xFF), Convert.ToByte((long)segStartAddr & (long)0xFF) })); - } - - // Lösche Commands - foreach (LevelscriptCommand cmd in cmdsToRemove) - lvl.Levelscript.Remove(cmd); - - // Füge neue Commands ein - foreach (KeyValuePair kvp in cmdsToInsertAt) - { - int index = lvl.Levelscript.IndexOf(kvp.Key); - lvl.Levelscript.Insert(index, kvp.Value); - } - - // Füge Background-Command ein - if (lvl.Background.Enabled) - { - var newbgcmd = cmdBgSegLoad ?? new LevelscriptCommand(new byte[] { 0x17, 0xC, 0, 0xA, 0, 0, 0, 0, 0, 0, 0, 0 }); - if (lvl.Background.IsCustom && lvl.Background.HasImage) // .ID = Geolayout.BackgroundIDs.Custom Then - { - clLoadRomToRam.SetRomStart(newbgcmd, customBGStart); - clLoadRomToRam.SetRomEnd(newbgcmd, customBGEnd); - } - else - { - clLoadRomToRam.SetRomStart(newbgcmd, (int)General.GetBackgroundAddressOfID(lvl.Background.ID, false)); - clLoadRomToRam.SetRomEnd(newbgcmd, (int)General.GetBackgroundAddressOfID(lvl.Background.ID, true)); - } - - if (!lvl.Levelscript.Contains(newbgcmd)) - { - int indexoffirstx1e = lvl.Levelscript.IndexOfFirst(LevelscriptCommandTypes.x1D); - lvl.Levelscript.Insert(indexoffirstx1e, newbgcmd); - } - } - else if (cmdBgSegLoad is not null) - { - lvl.Levelscript.Remove(cmdBgSegLoad); - } - - // Füge Global Model Bank Command ein - if (lvl.EnableGlobalObjectBank) - { - var newgobjumpcmd = cmdGobJump ?? new LevelscriptCommand("06 08 00 00 07 00 00 00"); - var newgobcmd = cmdGobSegLoad ?? new LevelscriptCommand("17 0C 00 07 00 00 00 00 00 00 00 00"); - clLoadRomToRam.SetRomStart(newgobcmd, rommgr.GlobalModelBank.CurSeg.RomStart); - clLoadRomToRam.SetRomEnd(newgobcmd, rommgr.GlobalModelBank.CurSeg.RomEnd); - - if (!lvl.Levelscript.Contains(newgobcmd)) - { - int indexoffirstx1d = lvl.Levelscript.IndexOfFirst(LevelscriptCommandTypes.x1D); - lvl.Levelscript.Insert(indexoffirstx1d, newgobcmd); - lvl.LastGobCmdSegLoad = newgobcmd; - } - - if (!lvl.Levelscript.Contains(newgobjumpcmd)) - { - int indexoffirstx1e = lvl.Levelscript.IndexOfFirst(LevelscriptCommandTypes.x25); - if (writeLocalObjectBank && cmdLobJump is not null && lvl.Levelscript.IndexOf(cmdLobJump) == indexoffirstx1e - 1) - indexoffirstx1e -= 1; - lvl.Levelscript.Insert(indexoffirstx1e, newgobjumpcmd); - } - } - else - { - if (cmdGobJump is not null) - lvl.Levelscript.Remove(cmdGobJump); - - if (cmdGobSegLoad is not null) - lvl.Levelscript.Remove(cmdGobSegLoad); - } - - // Füge Local Model Bank Command ein - if (writeLocalObjectBank) - { - var newlobjumpcmd = cmdLobJump ?? new LevelscriptCommand("06 08 00 00 09 00 00 00"); - var newlobcmd = cmdLobSegLoad ?? new LevelscriptCommand("17 0C 00 09 00 00 00 00 00 00 00 00"); - clLoadRomToRam.SetRomStart(newlobcmd, (int)localObjectBankRomStart); - clLoadRomToRam.SetRomEnd(newlobcmd, (int)localObjectBankRomEnd); - - if (!lvl.Levelscript.Contains(newlobcmd)) - { - int indexoffirstx1d = lvl.Levelscript.IndexOfFirst(LevelscriptCommandTypes.x1D); - lvl.Levelscript.Insert(indexoffirstx1d, newlobcmd); - lvl.LastLobCmdSegLoad = newlobcmd; - } - - if (!lvl.Levelscript.Contains(newlobjumpcmd)) - { - int indexoffirstx1e = lvl.Levelscript.IndexOfFirst(LevelscriptCommandTypes.x25); - lvl.Levelscript.Insert(indexoffirstx1e, newlobjumpcmd); - } - } - else - { - if (cmdLobJump is not null) - lvl.Levelscript.Remove(cmdLobJump); - - if (cmdLobSegLoad is not null) - lvl.Levelscript.Remove(cmdLobSegLoad); - } - - // Write Level Start (Start of Bank 0x19) - lvl.Bank0x19.Data.Position = 0; - foreach (byte b in Level.LevelscriptStart) - data0x19.Write(b); - - // Write Levelscript - lvl.Levelscript.Write(lvl.Bank0x19.Data, Convert.ToInt32(data0x19.Position)); - - // Parse Levelscript again! - bool AreaOnFly = false; - foreach (var c in lvl.Levelscript.ToArray()) - { - var switchExpr3 = c.CommandType; - switch (switchExpr3) - { - case LevelscriptCommandTypes.StartArea: - { - AreaOnFly = true; - break; - } - - case LevelscriptCommandTypes.EndOfArea: - { - AreaOnFly = false; - lvl.Levelscript.Remove(c); - break; - } - } - - if (AreaOnFly) - lvl.Levelscript.Remove(c); - } - - var bwToUse = data0x19 ?? output; - - // Write 4 checkbytes for the One-0xE-Bank-Per-Area-Code - lvl.Bank0x19.Data.Position = 0x5FFC; - bwToUse.Write(Convert.ToInt32(0x4BC9189A)); - - // Write Area Table - foreach (LevelArea a in lvl.Areas) - { - uint off = (uint)(0x5F00 + a.AreaID * 0x10); - lvl.Bank0x19.Data.Position = off; - bwToUse.Write(Convert.ToUInt32(a.Bank0x0EOffset)); - bwToUse.Write(Convert.ToUInt32(a.Bank0x0EOffset + a.Bank0xELength)); - bwToUse.Write(Convert.ToUInt32(0)); - bwToUse.Write(Convert.ToByte(0x0)); - bwToUse.Write(Convert.ToByte(0x0)); - bwToUse.Write(Convert.ToByte(0x0)); - bwToUse.Write(Bits.ArrayToByte(new[] { false, false, false, false, false, false, false, a.Enable2DCamera })); - } - - // Write SpecialBoxes - int CurrentBoxOffset = 0x6A00; - foreach (LevelArea a in lvl.Areas.Where(n => n.AreaID < 8)) - { - var TableIndex = new[] { 0, 0x32, 0x33 }; - var TableOffset = new[] { 0x6000 + 0x50 * a.AreaID, 0x6280 + 0x50 * a.AreaID, 0x6500 + 0x50 * a.AreaID }; - - foreach (SpecialBoxType t in Enum.GetValues(typeof(SpecialBoxType))) - { - foreach (SpecialBox w in a.SpecialBoxes.Where(n => n.Type == t)) - { - // Write Table Entry - bwToUse.Position = TableOffset[(int)w.Type]; - bwToUse.Write(Convert.ToInt16(TableIndex[(int)w.Type])); - bwToUse.Write(Convert.ToInt16(0x0)); - bwToUse.Write(Convert.ToInt32(CurrentBoxOffset + lvl.Bank0x19.BankAddress)); - TableOffset[(int)w.Type] = Convert.ToInt32(bwToUse.Position); - - // Write Box Data - bwToUse.Position = CurrentBoxOffset; - w.ToBoxData(bwToUse); - CurrentBoxOffset = (int)bwToUse.Position; - - if (w.Type == SpecialBoxType.ToxicHaze) - TableIndex[(int)w.Type] += 10; - else - TableIndex[(int)w.Type] += 1; - } - } - - foreach (int i in TableOffset) - { - bwToUse.Position = i; - bwToUse.Write((ushort)0xFFFF); - } - } - - // Write Bank0x19 - lvl.Bank0x19.WriteData(output); - - // Hardcoded Camera Settings & Act Selector - General.PatchClass.Open(output); - General.PatchClass.set_HardcodedCamera_Enabled(lvl.LevelID, lvl.HardcodedCameraSettings); - General.PatchClass.set_ActSelector_Enabled(lvl.LevelID, lvl.ActSelector); - - // Write Pointer to Levelscript - output.Position = lid.Pointer; - output.Write(Convert.ToInt32(0x100019)); - output.Write(Convert.ToUInt32(lvl.Bank0x19.RomStart)); - output.Write(Convert.ToUInt32(lvl.Bank0x19.RomEnd)); - output.Write(Convert.ToUInt32(0x1900001C)); - output.Write(Convert.ToUInt32(0x7040000)); - - // Write Area Reverb - if (EnableLoadingAreaReverb) - { - foreach (var area in lvl.Areas) - { - if (area is RMLevelArea && area.AreaID >= 1 && area.AreaID <= 3) - { - output.Position = 0xEE0C0 + lvl.LevelID * 3 + area.AreaID - 1; - output.Write((byte)((RMLevelArea)area).ReverbLevel); - } - } - } - - return saveres; + uint segStartAddr = areaobjwarpoffsetdic[e.Key]; + lvl.Levelscript.Insert(e.Value, new LevelscriptCommand(new byte[] { 0x6, 8, 0, 0, Convert.ToByte((long)(segStartAddr >> 24) & (long)0xFF), Convert.ToByte((long)(segStartAddr >> 16) & (long)0xFF), Convert.ToByte((long)(segStartAddr >> 8) & (long)0xFF), Convert.ToByte((long)segStartAddr & (long)0xFF) })); } + + // Lösche Commands + foreach (LevelscriptCommand cmd in cmdsToRemove) + lvl.Levelscript.Remove(cmd); + + // Füge neue Commands ein + foreach (KeyValuePair kvp in cmdsToInsertAt) + { + int index = lvl.Levelscript.IndexOf(kvp.Key); + lvl.Levelscript.Insert(index, kvp.Value); + } + + // Füge Background-Command ein + if (lvl.Background.Enabled) + { + var newbgcmd = cmdBgSegLoad ?? new LevelscriptCommand(new byte[] { 0x17, 0xC, 0, 0xA, 0, 0, 0, 0, 0, 0, 0, 0 }); + if (lvl.Background.IsCustom && lvl.Background.HasImage) // .ID = Geolayout.BackgroundIDs.Custom Then + { + clLoadRomToRam.SetRomStart(newbgcmd, customBGStart); + clLoadRomToRam.SetRomEnd(newbgcmd, customBGEnd); + } + else + { + clLoadRomToRam.SetRomStart(newbgcmd, (int)General.GetBackgroundAddressOfID(lvl.Background.ID, false)); + clLoadRomToRam.SetRomEnd(newbgcmd, (int)General.GetBackgroundAddressOfID(lvl.Background.ID, true)); + } + + if (!lvl.Levelscript.Contains(newbgcmd)) + { + int indexoffirstx1e = lvl.Levelscript.IndexOfFirst(LevelscriptCommandTypes.x1D); + lvl.Levelscript.Insert(indexoffirstx1e, newbgcmd); + } + } + else if (cmdBgSegLoad is not null) + { + lvl.Levelscript.Remove(cmdBgSegLoad); + } + + // Füge Global Model Bank Command ein + if (lvl.EnableGlobalObjectBank) + { + var newgobjumpcmd = cmdGobJump ?? new LevelscriptCommand("06 08 00 00 07 00 00 00"); + var newgobcmd = cmdGobSegLoad ?? new LevelscriptCommand("17 0C 00 07 00 00 00 00 00 00 00 00"); + clLoadRomToRam.SetRomStart(newgobcmd, rommgr.GlobalModelBank.CurSeg.RomStart); + clLoadRomToRam.SetRomEnd(newgobcmd, rommgr.GlobalModelBank.CurSeg.RomEnd); + + if (!lvl.Levelscript.Contains(newgobcmd)) + { + int indexoffirstx1d = lvl.Levelscript.IndexOfFirst(LevelscriptCommandTypes.x1D); + lvl.Levelscript.Insert(indexoffirstx1d, newgobcmd); + lvl.LastGobCmdSegLoad = newgobcmd; + } + + if (!lvl.Levelscript.Contains(newgobjumpcmd)) + { + int indexoffirstx1e = lvl.Levelscript.IndexOfFirst(LevelscriptCommandTypes.x25); + if (writeLocalObjectBank && cmdLobJump is not null && lvl.Levelscript.IndexOf(cmdLobJump) == indexoffirstx1e - 1) + indexoffirstx1e -= 1; + lvl.Levelscript.Insert(indexoffirstx1e, newgobjumpcmd); + } + } + else + { + if (cmdGobJump is not null) + lvl.Levelscript.Remove(cmdGobJump); + + if (cmdGobSegLoad is not null) + lvl.Levelscript.Remove(cmdGobSegLoad); + } + + // Füge Local Model Bank Command ein + if (writeLocalObjectBank) + { + var newlobjumpcmd = cmdLobJump ?? new LevelscriptCommand("06 08 00 00 09 00 00 00"); + var newlobcmd = cmdLobSegLoad ?? new LevelscriptCommand("17 0C 00 09 00 00 00 00 00 00 00 00"); + clLoadRomToRam.SetRomStart(newlobcmd, (int)localObjectBankRomStart); + clLoadRomToRam.SetRomEnd(newlobcmd, (int)localObjectBankRomEnd); + + if (!lvl.Levelscript.Contains(newlobcmd)) + { + int indexoffirstx1d = lvl.Levelscript.IndexOfFirst(LevelscriptCommandTypes.x1D); + lvl.Levelscript.Insert(indexoffirstx1d, newlobcmd); + lvl.LastLobCmdSegLoad = newlobcmd; + } + + if (!lvl.Levelscript.Contains(newlobjumpcmd)) + { + int indexoffirstx1e = lvl.Levelscript.IndexOfFirst(LevelscriptCommandTypes.x25); + lvl.Levelscript.Insert(indexoffirstx1e, newlobjumpcmd); + } + } + else + { + if (cmdLobJump is not null) + lvl.Levelscript.Remove(cmdLobJump); + + if (cmdLobSegLoad is not null) + lvl.Levelscript.Remove(cmdLobSegLoad); + } + + // Write Level Start (Start of Bank 0x19) + lvl.Bank0x19.Data.Position = 0; + foreach (byte b in Level.LevelscriptStart) + data0x19.Write(b); + + // Write Levelscript + lvl.Levelscript.Write(lvl.Bank0x19.Data, Convert.ToInt32(data0x19.Position)); + + // Parse Levelscript again! + bool AreaOnFly = false; + foreach (var c in lvl.Levelscript.ToArray()) + { + var switchExpr3 = c.CommandType; + switch (switchExpr3) + { + case LevelscriptCommandTypes.StartArea: + { + AreaOnFly = true; + break; + } + + case LevelscriptCommandTypes.EndOfArea: + { + AreaOnFly = false; + lvl.Levelscript.Remove(c); + break; + } + } + + if (AreaOnFly) + lvl.Levelscript.Remove(c); + } + + var bwToUse = data0x19 ?? output; + + // Write 4 checkbytes for the One-0xE-Bank-Per-Area-Code + lvl.Bank0x19.Data.Position = 0x5FFC; + bwToUse.Write(Convert.ToInt32(0x4BC9189A)); + + // Write Area Table + foreach (LevelArea a in lvl.Areas) + { + uint off = (uint)(0x5F00 + a.AreaID * 0x10); + lvl.Bank0x19.Data.Position = off; + bwToUse.Write(Convert.ToUInt32(a.Bank0x0EOffset)); + bwToUse.Write(Convert.ToUInt32(a.Bank0x0EOffset + a.Bank0xELength)); + bwToUse.Write(Convert.ToUInt32(0)); + bwToUse.Write(Convert.ToByte(0x0)); + bwToUse.Write(Convert.ToByte(0x0)); + bwToUse.Write(Convert.ToByte(0x0)); + bwToUse.Write(Bits.ArrayToByte(new[] { false, false, false, false, false, false, false, a.Enable2DCamera })); + } + + // Write SpecialBoxes + int CurrentBoxOffset = 0x6A00; + foreach (LevelArea a in lvl.Areas.Where(n => n.AreaID < 8)) + { + var TableIndex = new[] { 0, 0x32, 0x33 }; + var TableOffset = new[] { 0x6000 + 0x50 * a.AreaID, 0x6280 + 0x50 * a.AreaID, 0x6500 + 0x50 * a.AreaID }; + + foreach (SpecialBoxType t in Enum.GetValues(typeof(SpecialBoxType))) + { + foreach (SpecialBox w in a.SpecialBoxes.Where(n => n.Type == t)) + { + // Write Table Entry + bwToUse.Position = TableOffset[(int)w.Type]; + bwToUse.Write(Convert.ToInt16(TableIndex[(int)w.Type])); + bwToUse.Write(Convert.ToInt16(0x0)); + bwToUse.Write(Convert.ToInt32(CurrentBoxOffset + lvl.Bank0x19.BankAddress)); + TableOffset[(int)w.Type] = Convert.ToInt32(bwToUse.Position); + + // Write Box Data + bwToUse.Position = CurrentBoxOffset; + w.ToBoxData(bwToUse); + CurrentBoxOffset = (int)bwToUse.Position; + + if (w.Type == SpecialBoxType.ToxicHaze) + TableIndex[(int)w.Type] += 10; + else + TableIndex[(int)w.Type] += 1; + } + } + + foreach (int i in TableOffset) + { + bwToUse.Position = i; + bwToUse.Write((ushort)0xFFFF); + } + } + + // Write Bank0x19 + lvl.Bank0x19.WriteData(output); + + // Hardcoded Camera Settings & Act Selector + General.PatchClass.Open(output); + General.PatchClass.set_HardcodedCamera_Enabled(lvl.LevelID, lvl.HardcodedCameraSettings); + General.PatchClass.set_ActSelector_Enabled(lvl.LevelID, lvl.ActSelector); + + // Write Pointer to Levelscript + output.Position = lid.Pointer; + output.Write(Convert.ToInt32(0x100019)); + output.Write(Convert.ToUInt32(lvl.Bank0x19.RomStart)); + output.Write(Convert.ToUInt32(lvl.Bank0x19.RomEnd)); + output.Write(Convert.ToUInt32(0x1900001C)); + output.Write(Convert.ToUInt32(0x7040000)); + + // Write Area Reverb + if (EnableLoadingAreaReverb) + { + foreach (var area in lvl.Areas) + { + if (area is RMLevelArea && area.AreaID >= 1 && area.AreaID <= 3) + { + output.Position = 0xEE0C0 + lvl.LevelID * 3 + area.AreaID - 1; + output.Write((byte)((RMLevelArea)area).ReverbLevel); + } + } + } + + return saveres; } } \ No newline at end of file diff --git a/SM64Lib/Level/LevelNumberTable.cs b/SM64Lib/Level/LevelNumberTable.cs index 0860bba..1b1da38 100644 --- a/SM64Lib/Level/LevelNumberTable.cs +++ b/SM64Lib/Level/LevelNumberTable.cs @@ -1,27 +1,25 @@ -using System; +using global::System.IO; +using System; using System.Collections.Generic; -using global::System.IO; -using Microsoft.VisualBasic.CompilerServices; -namespace SM64Lib.Levels +namespace SM64Lib.Levels; + +public class LevelNumberTable : List { - public class LevelNumberTable : List + public void ReadFromROM(string Romfile, int Address = 0xE8D98) { - public void ReadFromROM(string Romfile, int Address = 0xE8D98) - { - var fs = new FileStream(Romfile, FileMode.Open, FileAccess.Read); - ReadFromROM(ref fs); - fs.Close(); - } + var fs = new FileStream(Romfile, FileMode.Open, FileAccess.Read); + ReadFromROM(ref fs); + fs.Close(); + } - public void ReadFromROM(ref FileStream fs, int Address = 0xE8D98) + public void ReadFromROM(ref FileStream fs, int Address = 0xE8D98) + { + Clear(); + for (int i = 0; i <= 30; i++) { - Clear(); - for (int i = 0; i <= 30; i++) - { - fs.Position = Address + General.GetLevelIDFromIndex(Convert.ToByte(i)); - Add(Convert.ToByte(fs.ReadByte())); - } + fs.Position = Address + General.GetLevelIDFromIndex(Convert.ToByte(i)); + Add(Convert.ToByte(fs.ReadByte())); } } } \ No newline at end of file diff --git a/SM64Lib/Level/LevelSaveResult.cs b/SM64Lib/Level/LevelSaveResult.cs index d4a2839..b45f5d1 100644 --- a/SM64Lib/Level/LevelSaveResult.cs +++ b/SM64Lib/Level/LevelSaveResult.cs @@ -1,9 +1,8 @@ using global::SM64Lib.SegmentedBanking; -namespace SM64Lib.Levels +namespace SM64Lib.Levels; + +public class LevelSaveResult { - public class LevelSaveResult - { - public SegmentedBank Bank0x19 { get; set; } = null; - } + public SegmentedBank Bank0x19 { get; set; } = null; } \ No newline at end of file diff --git a/SM64Lib/Level/LevelType.cs b/SM64Lib/Level/LevelType.cs index f401fa1..74700b2 100644 --- a/SM64Lib/Level/LevelType.cs +++ b/SM64Lib/Level/LevelType.cs @@ -1,10 +1,9 @@  -namespace SM64Lib.Levels +namespace SM64Lib.Levels; + +public enum LevelType { - public enum LevelType - { - Original, - SM64RomManager, - SM64Editor - } + Original, + SM64RomManager, + SM64Editor } \ No newline at end of file diff --git a/SM64Lib/Level/OriginalLevel.cs b/SM64Lib/Level/OriginalLevel.cs index 7dcd7cb..ffab463 100644 --- a/SM64Lib/Level/OriginalLevel.cs +++ b/SM64Lib/Level/OriginalLevel.cs @@ -1,14 +1,13 @@  -namespace SM64Lib.Levels -{ - public class OriginalLevel : Level - { - public OriginalLevel(ushort LevelID, int LevelIndex, RomManager rommgr) : base(LevelID, LevelIndex, rommgr) - { - } +namespace SM64Lib.Levels; - public OriginalLevel(RomManager rommgr) : base(rommgr) - { - } +public class OriginalLevel : Level +{ + public OriginalLevel(ushort LevelID, int LevelIndex, RomManager rommgr) : base(LevelID, LevelIndex, rommgr) + { + } + + public OriginalLevel(RomManager rommgr) : base(rommgr) + { } } \ No newline at end of file diff --git a/SM64Lib/Level/OriginalLevelArea.cs b/SM64Lib/Level/OriginalLevelArea.cs index b87296c..0446701 100644 --- a/SM64Lib/Level/OriginalLevelArea.cs +++ b/SM64Lib/Level/OriginalLevelArea.cs @@ -1,22 +1,21 @@  -namespace SM64Lib.Levels +namespace SM64Lib.Levels; + +public class OriginalLevelArea : LevelArea { - public class OriginalLevelArea : LevelArea + public OriginalLevelArea(byte AreaID) : base(AreaID) { - public OriginalLevelArea(byte AreaID) : base(AreaID) - { - } + } - public OriginalLevelArea(byte AreaID, byte LevelID) : base(AreaID, LevelID) - { - } + public OriginalLevelArea(byte AreaID, byte LevelID) : base(AreaID, LevelID) + { + } - public OriginalLevelArea(byte AreaID, byte LevelID, bool AddWarps, bool AddObjects) : base(AreaID, LevelID, AddWarps, AddObjects) - { - } + public OriginalLevelArea(byte AreaID, byte LevelID, bool AddWarps, bool AddObjects) : base(AreaID, LevelID, AddWarps, AddObjects) + { + } - public OriginalLevelArea() : base() - { - } + public OriginalLevelArea() : base() + { } } \ No newline at end of file diff --git a/SM64Lib/Level/OriginalLevelManager.cs b/SM64Lib/Level/OriginalLevelManager.cs index 082921e..ba8ecbe 100644 --- a/SM64Lib/Level/OriginalLevelManager.cs +++ b/SM64Lib/Level/OriginalLevelManager.cs @@ -1,18 +1,17 @@ -using System; -using global::SM64Lib.Data; +using global::SM64Lib.Data; +using System; -namespace SM64Lib.Levels +namespace SM64Lib.Levels; + +public class OriginalLevelManager : ILevelManager { - public class OriginalLevelManager : ILevelManager + public void LoadLevel(Level lvl, RomManager rommgr, ushort LevelID, uint segAddress) { - public void LoadLevel(Level lvl, RomManager rommgr, ushort LevelID, uint segAddress) - { - throw new NotImplementedException(); - } + throw new NotImplementedException(); + } - public LevelSaveResult SaveLevel(Level lvl, RomManager rommgr, BinaryData output, ref uint curOff) - { - throw new NotImplementedException(); - } + public LevelSaveResult SaveLevel(Level lvl, RomManager rommgr, BinaryData output, ref uint curOff) + { + throw new NotImplementedException(); } } \ No newline at end of file diff --git a/SM64Lib/Level/RMLevel.cs b/SM64Lib/Level/RMLevel.cs index 8db75d6..bf064d3 100644 --- a/SM64Lib/Level/RMLevel.cs +++ b/SM64Lib/Level/RMLevel.cs @@ -2,33 +2,32 @@ using Newtonsoft.Json; using SM64Lib.Configuration; -namespace SM64Lib.Levels +namespace SM64Lib.Levels; + +public class RMLevel : Level { - public class RMLevel : Level + [JsonProperty] + public LevelConfig Config { get; private set; } + + [JsonIgnore] + public string Name { - [JsonProperty] - public LevelConfig Config { get; private set; } + get => Config.LevelName; + set => Config.LevelName = value; + } - [JsonIgnore] - public string Name - { - get => Config.LevelName; - set => Config.LevelName = value; - } + public RMLevel(ushort LevelID, int LevelIndex, RomManager rommgr) : base(LevelID, LevelIndex, rommgr) + { + Config = new LevelConfig(); + } - public RMLevel(ushort LevelID, int LevelIndex, RomManager rommgr) : base(LevelID, LevelIndex, rommgr) - { - Config = new LevelConfig(); - } + public RMLevel(LevelConfig config, RomManager rommgr) : base(rommgr) + { + Config = config; + } - public RMLevel(LevelConfig config, RomManager rommgr) : base(rommgr) - { - Config = config; - } - - [JsonConstructor] - private RMLevel(JsonConstructorAttribute attr) : base(attr) - { - } + [JsonConstructor] + private RMLevel(JsonConstructorAttribute attr) : base(attr) + { } } \ No newline at end of file diff --git a/SM64Lib/Level/RMLevelArea.cs b/SM64Lib/Level/RMLevelArea.cs index 66541f2..9e15c09 100644 --- a/SM64Lib/Level/RMLevelArea.cs +++ b/SM64Lib/Level/RMLevelArea.cs @@ -1,35 +1,34 @@  using Newtonsoft.Json; -namespace SM64Lib.Levels +namespace SM64Lib.Levels; + +public class RMLevelArea : LevelArea { - public class RMLevelArea : LevelArea + // P r o p e r t i e s + + public AreaReverbLevel ReverbLevel { get; set; } = AreaReverbLevel.None; + + // C o n s t r u c t o r s + + public RMLevelArea(byte AreaID) : base(AreaID) { - // P r o p e r t i e s + } - public AreaReverbLevel ReverbLevel { get; set; } = AreaReverbLevel.None; + public RMLevelArea(byte AreaID, byte LevelID) : base(AreaID, LevelID) + { + } - // C o n s t r u c t o r s + public RMLevelArea(byte AreaID, byte LevelID, bool AddWarps, bool AddObjects) : base(AreaID, LevelID, AddWarps, AddObjects) + { + } - public RMLevelArea(byte AreaID) : base(AreaID) - { - } + public RMLevelArea() : base() + { + } - public RMLevelArea(byte AreaID, byte LevelID) : base(AreaID, LevelID) - { - } - - public RMLevelArea(byte AreaID, byte LevelID, bool AddWarps, bool AddObjects) : base(AreaID, LevelID, AddWarps, AddObjects) - { - } - - public RMLevelArea() : base() - { - } - - [JsonConstructor] - private RMLevelArea(JsonConstructorAttribute attr) : base(attr) - { - } + [JsonConstructor] + private RMLevelArea(JsonConstructorAttribute attr) : base(attr) + { } } \ No newline at end of file diff --git a/SM64Lib/Level/SM64ELevel.cs b/SM64Lib/Level/SM64ELevel.cs index e7e437d..212e8c9 100644 --- a/SM64Lib/Level/SM64ELevel.cs +++ b/SM64Lib/Level/SM64ELevel.cs @@ -1,14 +1,13 @@  -namespace SM64Lib.Levels -{ - public class SM64ELevel : Level - { - public SM64ELevel(ushort LevelID, int LevelIndex, RomManager rommgr) : base(LevelID, LevelIndex, rommgr) - { - } +namespace SM64Lib.Levels; - public SM64ELevel(RomManager rommgr) : base(rommgr) - { - } +public class SM64ELevel : Level +{ + public SM64ELevel(ushort LevelID, int LevelIndex, RomManager rommgr) : base(LevelID, LevelIndex, rommgr) + { + } + + public SM64ELevel(RomManager rommgr) : base(rommgr) + { } } \ No newline at end of file diff --git a/SM64Lib/Level/SM64ELevelArea.cs b/SM64Lib/Level/SM64ELevelArea.cs index 9ff50ce..a64a4a2 100644 --- a/SM64Lib/Level/SM64ELevelArea.cs +++ b/SM64Lib/Level/SM64ELevelArea.cs @@ -1,22 +1,21 @@  -namespace SM64Lib.Levels +namespace SM64Lib.Levels; + +public class SM64ELevelArea : LevelArea { - public class SM64ELevelArea : LevelArea + public SM64ELevelArea(byte AreaID) : base(AreaID) { - public SM64ELevelArea(byte AreaID) : base(AreaID) - { - } + } - public SM64ELevelArea(byte AreaID, byte LevelID) : base(AreaID, LevelID) - { - } + public SM64ELevelArea(byte AreaID, byte LevelID) : base(AreaID, LevelID) + { + } - public SM64ELevelArea(byte AreaID, byte LevelID, bool AddWarps, bool AddObjects) : base(AreaID, LevelID, AddWarps, AddObjects) - { - } + public SM64ELevelArea(byte AreaID, byte LevelID, bool AddWarps, bool AddObjects) : base(AreaID, LevelID, AddWarps, AddObjects) + { + } - public SM64ELevelArea() : base() - { - } + public SM64ELevelArea() : base() + { } } \ No newline at end of file diff --git a/SM64Lib/Level/SM64EditorLevelManager.cs b/SM64Lib/Level/SM64EditorLevelManager.cs index 70c2b2a..09a21f0 100644 --- a/SM64Lib/Level/SM64EditorLevelManager.cs +++ b/SM64Lib/Level/SM64EditorLevelManager.cs @@ -1,330 +1,328 @@ -using System; -using System.Collections.Generic; -using System.Data; -using global::System.IO; -using System.Linq; -using Microsoft.VisualBasic.CompilerServices; -using global::SM64Lib.Data; +using global::SM64Lib.Data; using global::SM64Lib.Geolayout.Script; using global::SM64Lib.Geolayout.Script.Commands; using global::SM64Lib.Levels.Script; using global::SM64Lib.Levels.Script.Commands; +using global::System.IO; using SM64Lib.Configuration; +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; -namespace SM64Lib.Levels +namespace SM64Lib.Levels; + +public class SM64EditorLevelManager : ILevelManager { - public class SM64EditorLevelManager : ILevelManager + + /// + /// Loads a SM64 Editor Level from ROM. + /// + /// + /// + /// + /// + public void LoadLevel(Level lvl, RomManager rommgr, ushort LevelID, uint segAddress) { + int customBGStart = 0; + int customBGEnd = 0; + lvl.LevelID = LevelID; - /// - /// Loads a SM64 Editor Level from ROM. - /// - /// - /// - /// - /// - public void LoadLevel(Level lvl, RomManager rommgr, ushort LevelID, uint segAddress) + // Load Bank 0x19 + lvl.Bank0x19 = rommgr.GetSegBank(0x19); + lvl.Bank0x19.ReadDataIfNull(rommgr.RomFile); + if (lvl.Bank0x19.Length < 0x10000) { - int customBGStart = 0; - int customBGEnd = 0; - lvl.LevelID = LevelID; + lvl.Bank0x19.Length = 0x10000; + } - // Load Bank 0x19 - lvl.Bank0x19 = rommgr.GetSegBank(0x19); - lvl.Bank0x19.ReadDataIfNull(rommgr.RomFile); - if (lvl.Bank0x19.Length < 0x10000) + if (!lvl.Closed) + lvl.Close(); + lvl.Closed = false; + + // Lade Levelscript + lvl.Levelscript = new Levelscript(); + lvl.Levelscript.Read(rommgr, Convert.ToInt32(segAddress)); + + // Erstelle Areas / Lade Einstellungen + bool AreaOnFly = false; + LevelArea tArea = null; + var CurrentLevelScriptCommands = lvl.Levelscript.ToArray(); + var cmdsToRemove = new List(); + LevelArea firstArea = null; + foreach (LevelscriptCommand c in CurrentLevelScriptCommands) + { + var switchExpr = c.CommandType; + switch (switchExpr) { - lvl.Bank0x19.Length = 0x10000; - } + case LevelscriptCommandTypes.StartArea: + { + AreaOnFly = true; + tArea = new SM64ELevelArea(); + if (firstArea is null) + firstArea = tArea; + tArea.AreaID = clStartArea.GetAreaID(c); + tArea.GeolayoutOffset = clStartArea.GetSegGeolayoutAddr(c); + tArea.Geolayout.Read(rommgr, Convert.ToInt32(tArea.GeolayoutOffset)); + break; + } - if (!lvl.Closed) - lvl.Close(); - lvl.Closed = false; + case LevelscriptCommandTypes.EndOfArea: + { + tArea.Levelscript.Add(c); + lvl.Levelscript.Remove(c); + lvl.Areas.Add(tArea); + AreaOnFly = false; + break; + } - // Lade Levelscript - lvl.Levelscript = new Levelscript(); - lvl.Levelscript.Read(rommgr, Convert.ToInt32(segAddress)); + case LevelscriptCommandTypes.AreaMusic: + { + tArea.BGMusic = clAreaMusic.GetMusicID(c); + break; + } - // Erstelle Areas / Lade Einstellungen - bool AreaOnFly = false; - LevelArea tArea = null; - var CurrentLevelScriptCommands = lvl.Levelscript.ToArray(); - var cmdsToRemove = new List(); - LevelArea firstArea = null; - foreach (LevelscriptCommand c in CurrentLevelScriptCommands) - { - var switchExpr = c.CommandType; - switch (switchExpr) - { - case LevelscriptCommandTypes.StartArea: + case LevelscriptCommandTypes.AreaMusicSimple: + { + tArea.BGMusic = clAreaMusicSimple.GetMusicID(c); + break; + } + + case LevelscriptCommandTypes.Tarrain: + { + tArea.TerrainType = (Geolayout.TerrainTypes)clTerrian.GetTerrainType(c); + break; + } + + case LevelscriptCommandTypes.Normal3DObject: + { + if (clNormal3DObject.GetSegBehaviorAddr(c) == (long)0x13003420) { - AreaOnFly = true; - tArea = new SM64ELevelArea(); - if (firstArea is null) - firstArea = tArea; - tArea.AreaID = clStartArea.GetAreaID(c); - tArea.GeolayoutOffset = clStartArea.GetSegGeolayoutAddr(c); - tArea.Geolayout.Read(rommgr, Convert.ToInt32(tArea.GeolayoutOffset)); - break; + tArea.ScrollingTextures.Add(new ScrolTex.ManagedScrollingTexture(c)); + } + else + { + tArea.Objects.Add(c); } - case LevelscriptCommandTypes.EndOfArea: + break; + } + + case LevelscriptCommandTypes.ConnectedWarp: + { + if ((new[] { 0xF0, 0xF1 }).Contains(clWarp.GetWarpID(c))) { - tArea.Levelscript.Add(c); - lvl.Levelscript.Remove(c); - lvl.Areas.Add(tArea); - AreaOnFly = false; - break; + tArea.WarpsForGame.Add(c); } - - case LevelscriptCommandTypes.AreaMusic: - { - tArea.BGMusic = clAreaMusic.GetMusicID(c); - break; - } - - case LevelscriptCommandTypes.AreaMusicSimple: - { - tArea.BGMusic = clAreaMusicSimple.GetMusicID(c); - break; - } - - case LevelscriptCommandTypes.Tarrain: - { - tArea.TerrainType = (Geolayout.TerrainTypes)clTerrian.GetTerrainType(c); - break; - } - - case LevelscriptCommandTypes.Normal3DObject: - { - if (clNormal3DObject.GetSegBehaviorAddr(c) == (long)0x13003420) - { - tArea.ScrollingTextures.Add(new ScrolTex.ManagedScrollingTexture(c)); - } - else - { - tArea.Objects.Add(c); - } - - break; - } - - case LevelscriptCommandTypes.ConnectedWarp: - { - if ((new[] { 0xF0, 0xF1 }).Contains(clWarp.GetWarpID(c))) - { - tArea.WarpsForGame.Add(c); - } - else - { - tArea.Warps.Add(c); - } - - break; - } - - case LevelscriptCommandTypes.PaintingWarp: - case LevelscriptCommandTypes.InstantWarp: + else { tArea.Warps.Add(c); - break; } - case LevelscriptCommandTypes.LoadRomToRam: - { - byte bankID = clLoadRomToRam.GetSegmentedID(c); - int startAddr = clLoadRomToRam.GetRomStart(c); - int endAddr = clLoadRomToRam.GetRomEnd(c); - switch (bankID) - { - case 0xA: // Background-Image - { - customBGStart = startAddr; - customBGEnd = endAddr - 0x140; - break; - } - - case 0xE: - { - rommgr.SetSegBank(bankID, startAddr, endAddr); - break; - } - } - - break; - } - - case LevelscriptCommandTypes.ShowDialog: - { - if (AreaOnFly) - { - tArea.ShowMessage.Enabled = true; - tArea.ShowMessage.DialogID = clShowDialog.GetDialogID(c); - } - - break; - } - - case LevelscriptCommandTypes.JumpBack: - case LevelscriptCommandTypes.JumpToSegAddr: - { - if (tArea is not null) - cmdsToRemove.Add(c); - break; - } - } - - if (AreaOnFly && !cmdsToRemove.Contains(c)) - { - lvl.Levelscript.Remove(c); - tArea.Levelscript.Add(c); - } - } - - // Lösche alle Jump-Commands aus dem Levelscript - foreach (LevelscriptCommand cmd in cmdsToRemove) - { - lvl.Levelscript.Remove(cmd); - cmd.Close(); - } - - // Stelle frisches Levelscript wieder her - lvl.CreateNewLevelscript(); - - // Lösche alle Objekte und Warps aus dem Levelscript - var lvlscrptidstoremove = new[] { LevelscriptCommandTypes.Normal3DObject, LevelscriptCommandTypes.ConnectedWarp, LevelscriptCommandTypes.PaintingWarp, LevelscriptCommandTypes.InstantWarp }; - foreach (var a in lvl.Areas) - { - foreach (var c in a.Levelscript.Where(n => lvlscrptidstoremove.Contains(n.CommandType)).ToArray()) - a.Levelscript.Remove(c); - } - - // Lese Custom Background Image - var fs = new FileStream(rommgr.RomFile, FileMode.Open, FileAccess.Read); - var br2 = new BinaryReader(fs); - lvl.Background.Enabled = false; - foreach (LevelArea a in lvl.Areas) - { - var bgglcmd = a.Geolayout.Geolayoutscript.GetFirst(GeolayoutCommandTypes.Background); - if (cgBackground.GetBackgroundPointer(bgglcmd) == 0) - { - a.Background.Type = AreaBGs.Color; - a.Background.Color = cgBackground.GetRrgbaColor(bgglcmd); - } - else - { - a.Background.Type = AreaBGs.Levelbackground; - lvl.Background.ID = (Geolayout.BackgroundIDs)cgBackground.GetBackgroundID(bgglcmd); - lvl.Background.Enabled = true; - } - } - - if (lvl.Background.Enabled && lvl.Background.ID == Geolayout.BackgroundIDs.Custom) - { - fs.Position = customBGStart; - lvl.Background.ReadImage(fs, customBGStart); - } - - int bank0x19RomStart; - int bank0x19RomEnd; - BinaryReader brToUse; - bank0x19RomStart = 0; - bank0x19RomEnd = lvl.Bank0x19.Length; - brToUse = new BinaryReader(lvl.Bank0x19.Data); - - // Lese Area-Modelle - var modelBank = rommgr.GetSegBank(0xE); - int curMdlStartOffset = modelBank.RomStart; - for (int i = 0, loopTo = lvl.Areas.Count - 1; i <= loopTo; i++) - { - var a = lvl.Areas[i]; - int newEndOffset = GetModelEnd(fs, modelBank.RomStart, Convert.ToByte(i)); - a.Bank0x0EOffset = Convert.ToUInt32(curMdlStartOffset); - rommgr.SetSegBank(0xE, Convert.ToInt32(a.Bank0x0EOffset), newEndOffset, a.AreaID); - a.AreaModel.Collision = new Model.Collision.CollisionMap(); - a.AreaModel.Collision.FromStream(fs, modelBank.SegToRomAddr(a.CollisionPointer), new CollisionBasicConfig()); - a.AreaModel.Fast3DBuffer = new Model.Fast3D.Fast3DBuffer(); - a.AreaModel.FromStream(fs, modelBank.RomStart, 0xE000000, curMdlStartOffset, newEndOffset - curMdlStartOffset, a.Geolayout.Geopointers.ToArray(), a.CollisionPointer, rommgr.RomConfig.CollisionBaseConfig); - a.AreaModel.Collision.SpecialBoxes.Clear(); - curMdlStartOffset = newEndOffset; - } - - // Lese alle Box-Daten - firstArea.SpecialBoxes.Clear(); - firstArea.SpecialBoxes.AddRange(SpecialBoxList.ReadTable(brToUse.BaseStream, SpecialBoxType.Water, bank0x19RomStart, bank0x19RomStart + 0x1810)); - firstArea.SpecialBoxes.AddRange(SpecialBoxList.ReadTable(brToUse.BaseStream, SpecialBoxType.ToxicHaze, bank0x19RomStart, bank0x19RomStart + 0x1850)); - firstArea.SpecialBoxes.AddRange(SpecialBoxList.ReadTable(brToUse.BaseStream, SpecialBoxType.Mist, bank0x19RomStart, bank0x19RomStart + 0x18A0)); - var areaWithBoxData = lvl.Areas.FirstOrDefault(n => n.AreaModel.Collision.SpecialBoxes.Any()); - if (areaWithBoxData is not null) - { - for (int i = 0, loopTo1 = firstArea.SpecialBoxes.Count - 1; i <= loopTo1; i++) - { - var boxdata = firstArea.AreaModel.Collision.SpecialBoxes.ElementAtOrDefault(i); - if (boxdata is not null) - { - firstArea.SpecialBoxes[i].Y = boxdata.Y; + break; + } + + case LevelscriptCommandTypes.PaintingWarp: + case LevelscriptCommandTypes.InstantWarp: + { + tArea.Warps.Add(c); + break; + } + + case LevelscriptCommandTypes.LoadRomToRam: + { + byte bankID = clLoadRomToRam.GetSegmentedID(c); + int startAddr = clLoadRomToRam.GetRomStart(c); + int endAddr = clLoadRomToRam.GetRomEnd(c); + switch (bankID) + { + case 0xA: // Background-Image + { + customBGStart = startAddr; + customBGEnd = endAddr - 0x140; + break; + } + + case 0xE: + { + rommgr.SetSegBank(bankID, startAddr, endAddr); + break; + } + } + + break; + } + + case LevelscriptCommandTypes.ShowDialog: + { + if (AreaOnFly) + { + tArea.ShowMessage.Enabled = true; + tArea.ShowMessage.DialogID = clShowDialog.GetDialogID(c); + } + + break; + } + + case LevelscriptCommandTypes.JumpBack: + case LevelscriptCommandTypes.JumpToSegAddr: + { + if (tArea is not null) + cmdsToRemove.Add(c); + break; } - } } - // One-Bank-0xE-System - lvl.OneBank0xESystemEnabled = true; - - // Act Selector - General.PatchClass.Open(fs); - lvl.ActSelector = General.PatchClass.get_ActSelector_Enabled(LevelID); - - // Hardcoded Camera - lvl.HardcodedCameraSettings = General.PatchClass.get_HardcodedCamera_Enabled(LevelID); - fs.Close(); - - // Object-Banks - lvl.MyObjectBanks.Clear(); - lvl.MyObjectBanks.Add(0xC, null); - lvl.MyObjectBanks.Add(0xD, null); - lvl.MyObjectBanks.Add(0x9, null); + if (AreaOnFly && !cmdsToRemove.Contains(c)) + { + lvl.Levelscript.Remove(c); + tArea.Levelscript.Add(c); + } } - public LevelSaveResult SaveLevel(Level lvl, RomManager rommgr, BinaryData output, ref uint curOff) + // Lösche alle Jump-Commands aus dem Levelscript + foreach (LevelscriptCommand cmd in cmdsToRemove) { - throw new NotImplementedException(); + lvl.Levelscript.Remove(cmd); + cmd.Close(); } - private static int GetModelEnd(Stream s, int startPos, byte areaIndex) + // Stelle frisches Levelscript wieder her + lvl.CreateNewLevelscript(); + + // Lösche alle Objekte und Warps aus dem Levelscript + var lvlscrptidstoremove = new[] { LevelscriptCommandTypes.Normal3DObject, LevelscriptCommandTypes.ConnectedWarp, LevelscriptCommandTypes.PaintingWarp, LevelscriptCommandTypes.InstantWarp }; + foreach (var a in lvl.Areas) { - byte cb = 0; - int Ausnahmen = 0; - s.Position = startPos; - bool ende = false; + foreach (var c in a.Levelscript.Where(n => lvlscrptidstoremove.Contains(n.CommandType)).ToArray()) + a.Levelscript.Remove(c); + } - do + // Lese Custom Background Image + var fs = new FileStream(rommgr.RomFile, FileMode.Open, FileAccess.Read); + var br2 = new BinaryReader(fs); + lvl.Background.Enabled = false; + foreach (LevelArea a in lvl.Areas) + { + var bgglcmd = a.Geolayout.Geolayoutscript.GetFirst(GeolayoutCommandTypes.Background); + if (cgBackground.GetBackgroundPointer(bgglcmd) == 0) { - cb = Convert.ToByte(s.ReadByte()); - if (s.Position >= s.Length - 1) - return Convert.ToInt32(s.Length); - else if (cb == 0x1) + a.Background.Type = AreaBGs.Color; + a.Background.Color = cgBackground.GetRrgbaColor(bgglcmd); + } + else + { + a.Background.Type = AreaBGs.Levelbackground; + lvl.Background.ID = (Geolayout.BackgroundIDs)cgBackground.GetBackgroundID(bgglcmd); + lvl.Background.Enabled = true; + } + } + + if (lvl.Background.Enabled && lvl.Background.ID == Geolayout.BackgroundIDs.Custom) + { + fs.Position = customBGStart; + lvl.Background.ReadImage(fs, customBGStart); + } + + int bank0x19RomStart; + int bank0x19RomEnd; + BinaryReader brToUse; + bank0x19RomStart = 0; + bank0x19RomEnd = lvl.Bank0x19.Length; + brToUse = new BinaryReader(lvl.Bank0x19.Data); + + // Lese Area-Modelle + var modelBank = rommgr.GetSegBank(0xE); + int curMdlStartOffset = modelBank.RomStart; + for (int i = 0, loopTo = lvl.Areas.Count - 1; i <= loopTo; i++) + { + var a = lvl.Areas[i]; + int newEndOffset = GetModelEnd(fs, modelBank.RomStart, Convert.ToByte(i)); + a.Bank0x0EOffset = Convert.ToUInt32(curMdlStartOffset); + rommgr.SetSegBank(0xE, Convert.ToInt32(a.Bank0x0EOffset), newEndOffset, a.AreaID); + a.AreaModel.Collision = new Model.Collision.CollisionMap(); + a.AreaModel.Collision.FromStream(fs, modelBank.SegToRomAddr(a.CollisionPointer), new CollisionBasicConfig()); + a.AreaModel.Fast3DBuffer = new Model.Fast3D.Fast3DBuffer(); + a.AreaModel.FromStream(fs, modelBank.RomStart, 0xE000000, curMdlStartOffset, newEndOffset - curMdlStartOffset, a.Geolayout.Geopointers.ToArray(), a.CollisionPointer, rommgr.RomConfig.CollisionBaseConfig); + a.AreaModel.Collision.SpecialBoxes.Clear(); + curMdlStartOffset = newEndOffset; + } + + // Lese alle Box-Daten + firstArea.SpecialBoxes.Clear(); + firstArea.SpecialBoxes.AddRange(SpecialBoxList.ReadTable(brToUse.BaseStream, SpecialBoxType.Water, bank0x19RomStart, bank0x19RomStart + 0x1810)); + firstArea.SpecialBoxes.AddRange(SpecialBoxList.ReadTable(brToUse.BaseStream, SpecialBoxType.ToxicHaze, bank0x19RomStart, bank0x19RomStart + 0x1850)); + firstArea.SpecialBoxes.AddRange(SpecialBoxList.ReadTable(brToUse.BaseStream, SpecialBoxType.Mist, bank0x19RomStart, bank0x19RomStart + 0x18A0)); + var areaWithBoxData = lvl.Areas.FirstOrDefault(n => n.AreaModel.Collision.SpecialBoxes.Any()); + if (areaWithBoxData is not null) + { + for (int i = 0, loopTo1 = firstArea.SpecialBoxes.Count - 1; i <= loopTo1; i++) + { + var boxdata = firstArea.AreaModel.Collision.SpecialBoxes.ElementAtOrDefault(i); + if (boxdata is not null) { - var haveFound = true; - s.Position -= 1; - - for (int i = 1; i <= 0x100; i++) - { - if (haveFound && s.ReadByte() != 0x1) - haveFound = false; - } - - if (haveFound) - { - if (Ausnahmen == areaIndex) - ende = true; - else - Ausnahmen += 1; - } + firstArea.SpecialBoxes[i].Y = boxdata.Y; } } - while (!ende); - - return Convert.ToInt32(s.Position); } + + // One-Bank-0xE-System + lvl.OneBank0xESystemEnabled = true; + + // Act Selector + General.PatchClass.Open(fs); + lvl.ActSelector = General.PatchClass.get_ActSelector_Enabled(LevelID); + + // Hardcoded Camera + lvl.HardcodedCameraSettings = General.PatchClass.get_HardcodedCamera_Enabled(LevelID); + fs.Close(); + + // Object-Banks + lvl.MyObjectBanks.Clear(); + lvl.MyObjectBanks.Add(0xC, null); + lvl.MyObjectBanks.Add(0xD, null); + lvl.MyObjectBanks.Add(0x9, null); + } + + public LevelSaveResult SaveLevel(Level lvl, RomManager rommgr, BinaryData output, ref uint curOff) + { + throw new NotImplementedException(); + } + + private static int GetModelEnd(Stream s, int startPos, byte areaIndex) + { + byte cb = 0; + int Ausnahmen = 0; + s.Position = startPos; + bool ende = false; + + do + { + cb = Convert.ToByte(s.ReadByte()); + if (s.Position >= s.Length - 1) + return Convert.ToInt32(s.Length); + else if (cb == 0x1) + { + var haveFound = true; + s.Position -= 1; + + for (int i = 1; i <= 0x100; i++) + { + if (haveFound && s.ReadByte() != 0x1) + haveFound = false; + } + + if (haveFound) + { + if (Ausnahmen == areaIndex) + ende = true; + else + Ausnahmen += 1; + } + } + } + while (!ende); + + return Convert.ToInt32(s.Position); } } \ No newline at end of file diff --git a/SM64Lib/Level/Script/Levelscript.cs b/SM64Lib/Level/Script/Levelscript.cs index f4cf148..ad42085 100644 --- a/SM64Lib/Level/Script/Levelscript.cs +++ b/SM64Lib/Level/Script/Levelscript.cs @@ -1,203 +1,201 @@ -using System; -using System.Collections.Generic; -using global::System.IO; -using System.Linq; -using Microsoft.VisualBasic.CompilerServices; -using global::SM64Lib.Data; +using global::SM64Lib.Data; using global::SM64Lib.Levels.Script.Commands; using global::SM64Lib.SegmentedBanking; +using global::System.IO; +using System; +using System.Collections.Generic; +using System.Linq; -namespace SM64Lib.Levels.Script +namespace SM64Lib.Levels.Script; + +public class Levelscript : LevelscriptCommandCollection { - public class Levelscript : LevelscriptCommandCollection + public new void Close() { - public new void Close() - { - for (int i = 0, loopTo = Count - 1; i <= loopTo; i++) - this[i].Close(); - Clear(); - } + for (int i = 0, loopTo = Count - 1; i <= loopTo; i++) + this[i].Close(); + Clear(); + } - public Levelscript() - { - } + public Levelscript() + { + } - public void Read(RomManager rommgr, int scriptStartInBank, LevelscriptCommandTypes EndAtCommands = LevelscriptCommandTypes.EndOfLevel, Dictionary segDic = null, bool storeToRommgr = true) + public void Read(RomManager rommgr, int scriptStartInBank, LevelscriptCommandTypes EndAtCommands = LevelscriptCommandTypes.EndOfLevel, Dictionary segDic = null, bool storeToRommgr = true) + { + Stream s = null; + BinaryReader br = null; + FileStream fs = null; + BinaryReader brfs = null; + var tb = new List(); + LevelscriptCommandTypes cb = default; + bool enableDo = true; + SegmentedBank curSegBank = null; + var dicBankBinaryReaders = new Dictionary(); + var brStack = new Stack(); + var sStack = new Stack(); + var jumpStack = new Stack(); + var segStack = new Stack(); + Close(); + Read_GetStream(ref curSegBank, ref s, ref br, ref fs, ref brfs, rommgr, scriptStartInBank, dicBankBinaryReaders, segDic); + while (enableDo) { - Stream s = null; - BinaryReader br = null; - FileStream fs = null; - BinaryReader brfs = null; - var tb = new List(); - LevelscriptCommandTypes cb = default; - bool enableDo = true; - SegmentedBank curSegBank = null; - var dicBankBinaryReaders = new Dictionary(); - var brStack = new Stack(); - var sStack = new Stack(); - var jumpStack = new Stack(); - var segStack = new Stack(); - Close(); - Read_GetStream(ref curSegBank, ref s, ref br, ref fs, ref brfs, rommgr, scriptStartInBank, dicBankBinaryReaders, segDic); - while (enableDo) + try { - try + cb = (LevelscriptCommandTypes)br.ReadByte(); + byte lenth = 0; + lenth = br.ReadByte(); + if (lenth == 0) + lenth = 4; + tb.Add((byte)cb); + tb.Add(lenth); + for (int i = 3, loopTo = lenth; i <= loopTo; i++) + tb.Add(br.ReadByte()); + var curLvlCmd = new LevelscriptCommand(tb.ToArray()); + int bankOffset = (int)(br.BaseStream.Position - lenth); + curLvlCmd.RomAddress = (int)(curSegBank?.RomStart + bankOffset); + curLvlCmd.BankAddress = (int)(curSegBank?.BankAddress + bankOffset); + Add(curLvlCmd); + tb.Clear(); + var switchExpr = curLvlCmd.CommandType; + switch (switchExpr) { - cb = (LevelscriptCommandTypes)br.ReadByte(); - byte lenth = 0; - lenth = br.ReadByte(); - if (lenth == 0) - lenth = 4; - tb.Add((byte)cb); - tb.Add(lenth); - for (int i = 3, loopTo = lenth; i <= loopTo; i++) - tb.Add(br.ReadByte()); - var curLvlCmd = new LevelscriptCommand(tb.ToArray()); - int bankOffset = (int)(br.BaseStream.Position - lenth); - curLvlCmd.RomAddress = (int)(curSegBank?.RomStart + bankOffset); - curLvlCmd.BankAddress = (int)(curSegBank?.BankAddress + bankOffset); - Add(curLvlCmd); - tb.Clear(); - var switchExpr = curLvlCmd.CommandType; - switch (switchExpr) - { - case LevelscriptCommandTypes.LoadRomToRam: - case LevelscriptCommandTypes.x1A: - case LevelscriptCommandTypes.x18: - case LevelscriptCommandTypes.x00: - case LevelscriptCommandTypes.x01: + case LevelscriptCommandTypes.LoadRomToRam: + case LevelscriptCommandTypes.x1A: + case LevelscriptCommandTypes.x18: + case LevelscriptCommandTypes.x00: + case LevelscriptCommandTypes.x01: + { + var bank = new SegmentedBank() { - var bank = new SegmentedBank() + BankID = clLoadRomToRam.GetSegmentedID(curLvlCmd), + RomStart = clLoadRomToRam.GetRomStart(curLvlCmd), + RomEnd = clLoadRomToRam.GetRomEnd(curLvlCmd) + }; + if (curLvlCmd.CommandType == LevelscriptCommandTypes.x1A) + bank.MakeAsMIO0(); + if (storeToRommgr) + rommgr?.SetSegBank(bank); + if (segDic is not null) + { + if (segDic.ContainsKey(bank.BankID)) { - BankID = clLoadRomToRam.GetSegmentedID(curLvlCmd), - RomStart = clLoadRomToRam.GetRomStart(curLvlCmd), - RomEnd = clLoadRomToRam.GetRomEnd(curLvlCmd) - }; - if (curLvlCmd.CommandType == LevelscriptCommandTypes.x1A) - bank.MakeAsMIO0(); - if (storeToRommgr) - rommgr?.SetSegBank(bank); - if (segDic is not null) - { - if (segDic.ContainsKey(bank.BankID)) - { - segDic[bank.BankID] = bank; - } - else - { - segDic.Add(bank.BankID, bank); - } + segDic[bank.BankID] = bank; } - - if (new[] { LevelscriptCommandTypes.x00, LevelscriptCommandTypes.x01 }.Contains(curLvlCmd.CommandType)) + else { - int SegAddr = clLoadRomToRam.GetSegmentedAddressToJump(curLvlCmd); - JumpTo(jumpStack, sStack, brStack, segStack, ref curSegBank, ref s, ref br, ref fs, ref brfs, rommgr, SegAddr, dicBankBinaryReaders, segDic); + segDic.Add(bank.BankID, bank); } - - break; } - case LevelscriptCommandTypes.JumpToSegAddr: + if (new[] { LevelscriptCommandTypes.x00, LevelscriptCommandTypes.x01 }.Contains(curLvlCmd.CommandType)) { - int SegAddr = clJumpToSegAddr.GetSegJumpAddr(curLvlCmd); - if (new[] { 0x19, 0xE }.Contains(SegAddr >> 24)) - { - JumpTo(jumpStack, sStack, brStack, segStack, ref curSegBank, ref s, ref br, ref fs, ref brfs, rommgr, SegAddr, dicBankBinaryReaders, segDic); - } - - break; + int SegAddr = clLoadRomToRam.GetSegmentedAddressToJump(curLvlCmd); + JumpTo(jumpStack, sStack, brStack, segStack, ref curSegBank, ref s, ref br, ref fs, ref brfs, rommgr, SegAddr, dicBankBinaryReaders, segDic); } - case LevelscriptCommandTypes.JumpBack: - case (LevelscriptCommandTypes)0xA: // Jump back - { - curSegBank = segStack.Pop(); - s = sStack.Pop(); - br = brStack.Pop(); - s.Position = jumpStack.Pop(); - break; - } - } + break; + } - if (curLvlCmd.CommandType == LevelscriptCommandTypes.EndOfLevel || curLvlCmd.CommandType == EndAtCommands) - { - enableDo = false; - } + case LevelscriptCommandTypes.JumpToSegAddr: + { + int SegAddr = clJumpToSegAddr.GetSegJumpAddr(curLvlCmd); + if (new[] { 0x19, 0xE }.Contains(SegAddr >> 24)) + { + JumpTo(jumpStack, sStack, brStack, segStack, ref curSegBank, ref s, ref br, ref fs, ref brfs, rommgr, SegAddr, dicBankBinaryReaders, segDic); + } + + break; + } + + case LevelscriptCommandTypes.JumpBack: + case (LevelscriptCommandTypes)0xA: // Jump back + { + curSegBank = segStack.Pop(); + s = sStack.Pop(); + br = brStack.Pop(); + s.Position = jumpStack.Pop(); + break; + } } - catch (Exception) + + if (curLvlCmd.CommandType == LevelscriptCommandTypes.EndOfLevel || curLvlCmd.CommandType == EndAtCommands) { enableDo = false; } } - - // If s Is fs Then s?.Close() - fs?.Close(); - } - - private void JumpTo(Stack jumpStack, Stack sStack, Stack brStack, Stack segStack, ref SegmentedBank curSegBank, ref Stream s, ref BinaryReader br, ref FileStream fs, ref BinaryReader brfs, RomManager rommgr, int scriptStartInBank, Dictionary dicBankBinaryReaders, Dictionary segDic) - { - jumpStack.Push(Convert.ToInt32(s.Position)); - sStack.Push(s); - brStack.Push(br); - segStack.Push(curSegBank); - Read_GetStream(ref curSegBank, ref s, ref br, ref fs, ref brfs, rommgr, scriptStartInBank, dicBankBinaryReaders, segDic); - } - - private void Read_GetStream(ref SegmentedBank curSegBank, ref Stream s, ref BinaryReader br, ref FileStream fs, ref BinaryReader brfs, RomManager rommgr, int scriptStartInBank, Dictionary dicBankBinaryReaders, Dictionary segDic) - { - byte bankID = Convert.ToByte(scriptStartInBank >> 24); - curSegBank = rommgr.GetSegBank(bankID); - if (curSegBank is null && segDic?.ContainsKey(bankID) == true) + catch (Exception) { - curSegBank = segDic[bankID]; + enableDo = false; } + } - if (curSegBank?.Data is not null) + // If s Is fs Then s?.Close() + fs?.Close(); + } + + private void JumpTo(Stack jumpStack, Stack sStack, Stack brStack, Stack segStack, ref SegmentedBank curSegBank, ref Stream s, ref BinaryReader br, ref FileStream fs, ref BinaryReader brfs, RomManager rommgr, int scriptStartInBank, Dictionary dicBankBinaryReaders, Dictionary segDic) + { + jumpStack.Push(Convert.ToInt32(s.Position)); + sStack.Push(s); + brStack.Push(br); + segStack.Push(curSegBank); + Read_GetStream(ref curSegBank, ref s, ref br, ref fs, ref brfs, rommgr, scriptStartInBank, dicBankBinaryReaders, segDic); + } + + private void Read_GetStream(ref SegmentedBank curSegBank, ref Stream s, ref BinaryReader br, ref FileStream fs, ref BinaryReader brfs, RomManager rommgr, int scriptStartInBank, Dictionary dicBankBinaryReaders, Dictionary segDic) + { + byte bankID = Convert.ToByte(scriptStartInBank >> 24); + curSegBank = rommgr.GetSegBank(bankID); + if (curSegBank is null && segDic?.ContainsKey(bankID) == true) + { + curSegBank = segDic[bankID]; + } + + if (curSegBank?.Data is not null) + { + s = curSegBank.Data; + if (dicBankBinaryReaders.ContainsKey(curSegBank.BankID)) { - s = curSegBank.Data; - if (dicBankBinaryReaders.ContainsKey(curSegBank.BankID)) - { - br = dicBankBinaryReaders[curSegBank.BankID]; - } - else - { - br = new BinaryReader(curSegBank.Data); - dicBankBinaryReaders.Add(curSegBank.BankID, br); - } + br = dicBankBinaryReaders[curSegBank.BankID]; } else { - if (fs is null) - fs = new FileStream(rommgr.RomFile, FileMode.Open, FileAccess.Read); - if (brfs is null) - brfs = new BinaryReader(fs); - s = fs; - br = brfs; - } - - if (curSegBank is not null) - { - s.Position = s == fs ? curSegBank.SegToRomAddr(scriptStartInBank) : curSegBank.BankOffsetFromSegAddr(scriptStartInBank); + br = new BinaryReader(curSegBank.Data); + dicBankBinaryReaders.Add(curSegBank.BankID, br); } } - - public void Write(Stream s, int LevelscriptStart) + else { - Write(new BinaryStreamData(s), LevelscriptStart); + if (fs is null) + fs = new FileStream(rommgr.RomFile, FileMode.Open, FileAccess.Read); + if (brfs is null) + brfs = new BinaryReader(fs); + s = fs; + br = brfs; } - public void Write(BinaryData data, int LevelscriptStart) + if (curSegBank is not null) { - var JumpList = new List(); + s.Position = s == fs ? curSegBank.SegToRomAddr(scriptStartInBank) : curSegBank.BankOffsetFromSegAddr(scriptStartInBank); + } + } - // Write new Levelscript - data.Position = LevelscriptStart; - foreach (LevelscriptCommand c in this) - { - foreach (byte b in c.ToArray()) - data.Write(b); - } + public void Write(Stream s, int LevelscriptStart) + { + Write(new BinaryStreamData(s), LevelscriptStart); + } + + public void Write(BinaryData data, int LevelscriptStart) + { + var JumpList = new List(); + + // Write new Levelscript + data.Position = LevelscriptStart; + foreach (LevelscriptCommand c in this) + { + foreach (byte b in c.ToArray()) + data.Write(b); } } } \ No newline at end of file diff --git a/SM64Lib/Level/Script/LevelscriptCommand.cs b/SM64Lib/Level/Script/LevelscriptCommand.cs index b6b138a..5b65d44 100644 --- a/SM64Lib/Level/Script/LevelscriptCommand.cs +++ b/SM64Lib/Level/Script/LevelscriptCommand.cs @@ -1,40 +1,38 @@ -using System; -using global::SM64Lib.Script; +using global::SM64Lib.Script; using Newtonsoft.Json; -namespace SM64Lib.Levels.Script +namespace SM64Lib.Levels.Script; + +[JsonConverter(typeof(Json.LevelscriptCommandJsonConverter))] +public class LevelscriptCommand : BaseCommand { - [JsonConverter(typeof(Json.LevelscriptCommandJsonConverter))] - public class LevelscriptCommand : BaseCommand + public LevelscriptCommand(byte[] bytes) : base(bytes) { - public LevelscriptCommand(byte[] bytes) : base(bytes) + } + + public LevelscriptCommand() : base() + { + } + + public LevelscriptCommand(string bytes, bool enabledHex = true) : base(bytes, enabledHex) + { + } + + public override LevelscriptCommandTypes CommandType + { + get { + Position = 0; + LevelscriptCommandTypes t = (LevelscriptCommandTypes)ReadByte(); + Position = 0; + return t; } - public LevelscriptCommand() : base() + set { - } - - public LevelscriptCommand(string bytes, bool enabledHex = true) : base(bytes, enabledHex) - { - } - - public override LevelscriptCommandTypes CommandType - { - get - { - Position = 0; - LevelscriptCommandTypes t = (LevelscriptCommandTypes)ReadByte(); - Position = 0; - return t; - } - - set - { - Position = 0; - WriteByte((byte)value); - Position = 0; - } + Position = 0; + WriteByte((byte)value); + Position = 0; } } } \ No newline at end of file diff --git a/SM64Lib/Level/Script/LevelscriptCommandCollection.cs b/SM64Lib/Level/Script/LevelscriptCommandCollection.cs index ba107b9..e45fba3 100644 --- a/SM64Lib/Level/Script/LevelscriptCommandCollection.cs +++ b/SM64Lib/Level/Script/LevelscriptCommandCollection.cs @@ -1,18 +1,17 @@ using global::SM64Lib.Script; -namespace SM64Lib.Levels.Script -{ - public class LevelscriptCommandCollection : BaseCommandCollection - { - public int IndexOfFirst(LevelscriptCommandTypes cmdType) - { - for (int index = 0, loopTo = Count - 1; index <= loopTo; index++) - { - if (this[index].CommandType == cmdType) - return index; - } +namespace SM64Lib.Levels.Script; - return -1; +public class LevelscriptCommandCollection : BaseCommandCollection +{ + public int IndexOfFirst(LevelscriptCommandTypes cmdType) + { + for (int index = 0, loopTo = Count - 1; index <= loopTo; index++) + { + if (this[index].CommandType == cmdType) + return index; } + + return -1; } } \ No newline at end of file diff --git a/SM64Lib/Level/Script/LevelscriptCommandFunctions.cs b/SM64Lib/Level/Script/LevelscriptCommandFunctions.cs index 24e7663..ecd86eb 100644 --- a/SM64Lib/Level/Script/LevelscriptCommandFunctions.cs +++ b/SM64Lib/Level/Script/LevelscriptCommandFunctions.cs @@ -1,8 +1,7 @@ -using System; -using global::System.Numerics; +using global::System.Numerics; using Microsoft.VisualBasic; -using Microsoft.VisualBasic.CompilerServices; using SM64Lib.Data.System; +using System; namespace SM64Lib.Levels.Script { diff --git a/SM64Lib/Level/Script/LevelscriptCommandTypes.cs b/SM64Lib/Level/Script/LevelscriptCommandTypes.cs index 071feba..98d6930 100644 --- a/SM64Lib/Level/Script/LevelscriptCommandTypes.cs +++ b/SM64Lib/Level/Script/LevelscriptCommandTypes.cs @@ -1,49 +1,48 @@ using System; -namespace SM64Lib.Levels.Script +namespace SM64Lib.Levels.Script; + +[Serializable] +public enum LevelscriptCommandTypes { - [Serializable] - public enum LevelscriptCommandTypes - { - x00 = 0x0, - x01 = 0x1, - EndOfLevel = 0x2, - x03 = 0x3, - x04 = 0x4, - x05 = 0x5, - JumpToSegAddr = 0x6, - JumpBack = 0x7, - x0A = 0xA, - x0C = 0xC, - x10 = 0x10, - x11 = 0x11, - x12 = 0x12, - x16 = 0x16, - LoadRomToRam = 0x17, - x18 = 0x18, - x19 = 0x19, - x1A = 0x1A, - x1B = 0x1B, - x1C = 0x1C, - x1D = 0x1D, - x1E = 0x1E, - StartArea = 0x1F, - EndOfArea = 0x20, - LoadPolygonWithGeo = 0x22, - LoadPolygonWithoutGeo = 0x21, - Normal3DObject = 0x24, - x25 = 0x25, - ConnectedWarp = 0x26, - PaintingWarp = 0x27, - InstantWarp = 0x28, - DefaultPosition = 0x2B, - AreaCollision = 0x2E, - ShowDialog = 0x30, - Tarrain = 0x31, - x34 = 0x34, - AreaMusic = 0x36, - AreaMusicSimple = 0x37, - Macro3DObject = 0x39, - x3B = 0x3B - } + x00 = 0x0, + x01 = 0x1, + EndOfLevel = 0x2, + x03 = 0x3, + x04 = 0x4, + x05 = 0x5, + JumpToSegAddr = 0x6, + JumpBack = 0x7, + x0A = 0xA, + x0C = 0xC, + x10 = 0x10, + x11 = 0x11, + x12 = 0x12, + x16 = 0x16, + LoadRomToRam = 0x17, + x18 = 0x18, + x19 = 0x19, + x1A = 0x1A, + x1B = 0x1B, + x1C = 0x1C, + x1D = 0x1D, + x1E = 0x1E, + StartArea = 0x1F, + EndOfArea = 0x20, + LoadPolygonWithGeo = 0x22, + LoadPolygonWithoutGeo = 0x21, + Normal3DObject = 0x24, + x25 = 0x25, + ConnectedWarp = 0x26, + PaintingWarp = 0x27, + InstantWarp = 0x28, + DefaultPosition = 0x2B, + AreaCollision = 0x2E, + ShowDialog = 0x30, + Tarrain = 0x31, + x34 = 0x34, + AreaMusic = 0x36, + AreaMusicSimple = 0x37, + Macro3DObject = 0x39, + x3B = 0x3B } \ No newline at end of file diff --git a/SM64Lib/Level/Script/Managed Commands/IManagedLevelscriptCommand.cs b/SM64Lib/Level/Script/Managed Commands/IManagedLevelscriptCommand.cs index f9465a2..129905e 100644 --- a/SM64Lib/Level/Script/Managed Commands/IManagedLevelscriptCommand.cs +++ b/SM64Lib/Level/Script/Managed Commands/IManagedLevelscriptCommand.cs @@ -1,12 +1,11 @@  -namespace SM64Lib.Levels.Script -{ - public interface IManagedLevelscriptCommand - { - LevelscriptCommand Command { get; } +namespace SM64Lib.Levels.Script; - void LoadProperties(); - void SaveProperties(); - void SaveProperties(LevelscriptCommand Command); - } +public interface IManagedLevelscriptCommand +{ + LevelscriptCommand Command { get; } + + void LoadProperties(); + void SaveProperties(); + void SaveProperties(LevelscriptCommand Command); } \ No newline at end of file diff --git a/SM64Lib/Level/Script/Managed Commands/ManagedScrollingTextures.cs b/SM64Lib/Level/Script/Managed Commands/ManagedScrollingTextures.cs index 6409b37..2fab57c 100644 --- a/SM64Lib/Level/Script/Managed Commands/ManagedScrollingTextures.cs +++ b/SM64Lib/Level/Script/Managed Commands/ManagedScrollingTextures.cs @@ -1,252 +1,250 @@ -using global::System.ComponentModel; -using Microsoft.VisualBasic.CompilerServices; -using SM64Lib.Data.System; -using global::SM64Lib.Levels.Script; +using global::SM64Lib.Levels.Script; using global::SM64Lib.Levels.Script.Commands; -using SM64Lib.Configuration; +using global::System.ComponentModel; using Newtonsoft.Json; +using SM64Lib.Configuration; +using SM64Lib.Data.System; using System; -namespace SM64Lib.Levels.ScrolTex +namespace SM64Lib.Levels.ScrolTex; + +public class ManagedScrollingTexture : IManagedLevelscriptCommand { - public class ManagedScrollingTexture : IManagedLevelscriptCommand + + /// + /// The underlying levelscript command which provide all the properties. + /// + /// + [JsonProperty] + public LevelscriptCommand Command { get; private set; } = null; + + [JsonConstructor] + private ManagedScrollingTexture(JsonConstructorAttribute attr) { + } - /// - /// The underlying levelscript command which provide all the properties. - /// - /// - [JsonProperty] - public LevelscriptCommand Command { get; private set; } = null; + /// + /// Creates a new managed scrolling texture instance with an new levelscript command. + /// + public ManagedScrollingTexture() + { + Command = new LevelscriptCommand("24 18 1F 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 40 17 00"); + SaveProperties(); + } - [JsonConstructor] - private ManagedScrollingTexture(JsonConstructorAttribute attr) + /// + /// Creates a new managed scrolling texture instance using some data with an new levelscript command. + /// + /// Amount of faces to count. + /// Pointer to the Vertices. + /// + public ManagedScrollingTexture(ushort facesCount, int vertexPtr, short groupID) : this() + { + FacesCount = facesCount; + VertexPointer = vertexPtr; + GroupID = groupID; + } + + /// + /// Creates a new managed scrolling texture instance using an existing levelscript command. + /// + /// The levelscript command to use. + public ManagedScrollingTexture(LevelscriptCommand cmd) + { + Command = cmd; + LoadProperties(); + } + + /// + /// Indicates the group (by default deticted to the used texture). + /// + /// + [DisplayName("Group ID")] + [Description("Indicates the group ID (by default deticted to the used texture).")] + [Category("Grouping")] + public short GroupID { get; set; } = 0; + + /// + /// Indicates the cycle duration of sine wave or jumping scrolling. + /// + /// + [DisplayName("Behavior")] + [Description("Indicates the axis and behavior.")] + [Category("Behavior")] + public ScrollBehavior Behavior { get; set; } = ScrollBehavior.ScrollUVBackAndForth; + + /// + /// Indicates the scroll behavior. + /// + /// + [DisplayName("Type")] + [Description("Indicates the scroll type.")] + [Category("Behavior")] + public ScrollType Type { get; set; } = ScrollType.NormalScrolling; + + /// + /// The Scrolling Speed per Frame (less then 0x1000). + /// + /// + [DisplayName("Scrolling Speed")] + [Description("The Scrolling Speed per Frame (less then 0x1000).")] + [Category("Params")] + public short ScrollingSpeed { get; set; } = 60; + + /// + /// Indicates the duration of a cycle in frames. + /// + /// + [DisplayName("Cycle Duration")] + [Description("Cycle duration of the sine wave or jumpy scrolling in frames.")] + [Category("Params")] + public byte CycleDuration { get; set; } = 20; + + /// + /// Amount of faces to count. + /// + /// + [DisplayName("Vertex Data")] + [Description("Amount of vertices to count.")] + [Category("Data")] + public ushort FacesCount { get; set; } = 0; + + /// + /// Pointer to the vertices. + /// + /// + [DisplayName("Vertex Data")] + [Description("Pointer to the vertices.")] + [Category("Data")] + public int VertexPointer { get; set; } = 0; + [DisplayName("Act 1")] + [Category("Acts")] + [Description("If Yes, the Object will be visible if you select Star 1.")] + public bool Act1 { get; set; } = true; + [DisplayName("Act 2")] + [Category("Acts")] + [Description("If Yes, the Object will be visible if you select Star 2.")] + public bool Act2 { get; set; } = true; + [DisplayName("Act 3")] + [Category("Acts")] + [Description("If Yes, the Object will be visible if you select Star 3.")] + public bool Act3 { get; set; } = true; + [DisplayName("Act 4")] + [Category("Acts")] + [Description("If Yes, the Object will be visible if you select Star 4.")] + public bool Act4 { get; set; } = true; + [DisplayName("Act 5")] + [Category("Acts")] + [Description("If Yes, the Object will be visible if you select Star 5.")] + public bool Act5 { get; set; } = true; + [DisplayName("Act 6")] + [Category("Acts")] + [Description("If Yes, the Object will be visible if you select Star 6.")] + public bool Act6 { get; set; } = false; + + [DisplayName("All Acts")] + [Category("Acts")] + [Description("If Yes, the Object will be visible always.")] + public bool AllActs + { + get { + return Act1 && Act2 && Act3 && Act4 && Act5 && !Act6; } - /// - /// Creates a new managed scrolling texture instance with an new levelscript command. - /// - public ManagedScrollingTexture() + set { - Command = new LevelscriptCommand("24 18 1F 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 40 17 00"); - SaveProperties(); - } - - /// - /// Creates a new managed scrolling texture instance using some data with an new levelscript command. - /// - /// Amount of faces to count. - /// Pointer to the Vertices. - /// - public ManagedScrollingTexture(ushort facesCount, int vertexPtr, short groupID) : this() - { - FacesCount = facesCount; - VertexPointer = vertexPtr; - GroupID = groupID; - } - - /// - /// Creates a new managed scrolling texture instance using an existing levelscript command. - /// - /// The levelscript command to use. - public ManagedScrollingTexture(LevelscriptCommand cmd) - { - Command = cmd; - LoadProperties(); - } - - /// - /// Indicates the group (by default deticted to the used texture). - /// - /// - [DisplayName("Group ID")] - [Description("Indicates the group ID (by default deticted to the used texture).")] - [Category("Grouping")] - public short GroupID { get; set; } = 0; - - /// - /// Indicates the cycle duration of sine wave or jumping scrolling. - /// - /// - [DisplayName("Behavior")] - [Description("Indicates the axis and behavior.")] - [Category("Behavior")] - public ScrollBehavior Behavior { get; set; } = ScrollBehavior.ScrollUVBackAndForth; - - /// - /// Indicates the scroll behavior. - /// - /// - [DisplayName("Type")] - [Description("Indicates the scroll type.")] - [Category("Behavior")] - public ScrollType Type { get; set; } = ScrollType.NormalScrolling; - - /// - /// The Scrolling Speed per Frame (less then 0x1000). - /// - /// - [DisplayName("Scrolling Speed")] - [Description("The Scrolling Speed per Frame (less then 0x1000).")] - [Category("Params")] - public short ScrollingSpeed { get; set; } = 60; - - /// - /// Indicates the duration of a cycle in frames. - /// - /// - [DisplayName("Cycle Duration")] - [Description("Cycle duration of the sine wave or jumpy scrolling in frames.")] - [Category("Params")] - public byte CycleDuration { get; set; } = 20; - - /// - /// Amount of faces to count. - /// - /// - [DisplayName("Vertex Data")] - [Description("Amount of vertices to count.")] - [Category("Data")] - public ushort FacesCount { get; set; } = 0; - - /// - /// Pointer to the vertices. - /// - /// - [DisplayName("Vertex Data")] - [Description("Pointer to the vertices.")] - [Category("Data")] - public int VertexPointer { get; set; } = 0; - [DisplayName("Act 1")] - [Category("Acts")] - [Description("If Yes, the Object will be visible if you select Star 1.")] - public bool Act1 { get; set; } = true; - [DisplayName("Act 2")] - [Category("Acts")] - [Description("If Yes, the Object will be visible if you select Star 2.")] - public bool Act2 { get; set; } = true; - [DisplayName("Act 3")] - [Category("Acts")] - [Description("If Yes, the Object will be visible if you select Star 3.")] - public bool Act3 { get; set; } = true; - [DisplayName("Act 4")] - [Category("Acts")] - [Description("If Yes, the Object will be visible if you select Star 4.")] - public bool Act4 { get; set; } = true; - [DisplayName("Act 5")] - [Category("Acts")] - [Description("If Yes, the Object will be visible if you select Star 5.")] - public bool Act5 { get; set; } = true; - [DisplayName("Act 6")] - [Category("Acts")] - [Description("If Yes, the Object will be visible if you select Star 6.")] - public bool Act6 { get; set; } = false; - - [DisplayName("All Acts")] - [Category("Acts")] - [Description("If Yes, the Object will be visible always.")] - public bool AllActs - { - get - { - return Act1 && Act2 && Act3 && Act4 && Act5 && !Act6; - } - - set - { - Act1 = value; - Act2 = value; - Act3 = value; - Act4 = value; - Act5 = value; - Act6 = false; - } - } - - public void LoadProperties() - { - CycleDuration = clScrollingTexture.GetCycleDuration(Command); - VertexPointer = Convert.ToInt32(clScrollingTexture.GetVertexPointer(Command)); - FacesCount = clScrollingTexture.GetCountOfFaces(Command); - ScrollingSpeed = clScrollingTexture.GetScrollSpeed(Command); - Type = (ScrollType)clScrollingTexture.GetScrollType(Command); - Behavior = (ScrollBehavior)clScrollingTexture.GetScrollBehavior(Command); - GroupID = clScrollingTexture.GetGroupID(Command); - var acts = Bits.ByteToBoolArray(clNormal3DObject.GetActs(Command)); - Act1 = acts[7]; - Act2 = acts[6]; - Act3 = acts[5]; - Act4 = acts[4]; - Act5 = acts[3]; - Act6 = acts[2]; - } - - public void SaveProperties() - { - SaveProperties((ScrollTexConfig)null); - } - - public void SaveProperties(ScrollTexConfig config) - { - SaveProperties(Command, config); - } - - public void SaveProperties(LevelscriptCommand Command) - { - SaveProperties(Command, null); - } - - public void SaveProperties(LevelscriptCommand Command, ScrollTexConfig config) - { - clScrollingTexture.SetCycleDuration(Command, CycleDuration); - clScrollingTexture.SetVertexPointer(Command, Convert.ToUInt32(VertexPointer)); - clScrollingTexture.SetCountOfFaces(Command, FacesCount); - clScrollingTexture.SetScrollSpeed(Command, ScrollingSpeed); - clScrollingTexture.SetScrollType(Command, (byte)Type); - clScrollingTexture.SetScrollBehavior(Command, (byte)Behavior); - clScrollingTexture.SetGroupID(Command, GroupID); - clNormal3DObject.SetSegBehaviorAddr(Command, - config is not null && config.UseCustomBehavior && config.CustomBehaviorAddress > -1 ? (uint)config.CustomBehaviorAddress : 0x401700); - var acts = new[] { false, false, false, false, false, false, false, false }; - acts[7] = Act1; - acts[6] = Act2; - acts[5] = Act3; - acts[4] = Act4; - acts[3] = Act5; - acts[2] = Act6; - clNormal3DObject.SetActs(Command, Bits.ArrayToByte(acts)); - } - - public void CopyPropsTo(ManagedScrollingTexture mst) - { - mst.CycleDuration = CycleDuration; - mst.ScrollingSpeed = ScrollingSpeed; - mst.Type = Type; - mst.Behavior = Behavior; - - mst.Act1 = Act1; - mst.Act2 = Act2; - mst.Act3 = Act3; - mst.Act4 = Act4; - mst.Act5 = Act5; - mst.Act6 = Act6; + Act1 = value; + Act2 = value; + Act3 = value; + Act4 = value; + Act5 = value; + Act6 = false; } } - public enum ScrollBehavior + public void LoadProperties() { - ScrollingX = 0x0, - ScrollingY = 0x20, - ScrollingZ = 0x40, - ScrollUVBackAndForth = 0x80, - ScrollUVLeftAndRight = 0xA0 + CycleDuration = clScrollingTexture.GetCycleDuration(Command); + VertexPointer = Convert.ToInt32(clScrollingTexture.GetVertexPointer(Command)); + FacesCount = clScrollingTexture.GetCountOfFaces(Command); + ScrollingSpeed = clScrollingTexture.GetScrollSpeed(Command); + Type = (ScrollType)clScrollingTexture.GetScrollType(Command); + Behavior = (ScrollBehavior)clScrollingTexture.GetScrollBehavior(Command); + GroupID = clScrollingTexture.GetGroupID(Command); + var acts = Bits.ByteToBoolArray(clNormal3DObject.GetActs(Command)); + Act1 = acts[7]; + Act2 = acts[6]; + Act3 = acts[5]; + Act4 = acts[4]; + Act5 = acts[3]; + Act6 = acts[2]; } - public enum ScrollType + public void SaveProperties() { - NormalScrolling = 0x0, - SineWave = 0x1, - JumpingScroll = 0x2 + SaveProperties((ScrollTexConfig)null); } + + public void SaveProperties(ScrollTexConfig config) + { + SaveProperties(Command, config); + } + + public void SaveProperties(LevelscriptCommand Command) + { + SaveProperties(Command, null); + } + + public void SaveProperties(LevelscriptCommand Command, ScrollTexConfig config) + { + clScrollingTexture.SetCycleDuration(Command, CycleDuration); + clScrollingTexture.SetVertexPointer(Command, Convert.ToUInt32(VertexPointer)); + clScrollingTexture.SetCountOfFaces(Command, FacesCount); + clScrollingTexture.SetScrollSpeed(Command, ScrollingSpeed); + clScrollingTexture.SetScrollType(Command, (byte)Type); + clScrollingTexture.SetScrollBehavior(Command, (byte)Behavior); + clScrollingTexture.SetGroupID(Command, GroupID); + clNormal3DObject.SetSegBehaviorAddr(Command, + config is not null && config.UseCustomBehavior && config.CustomBehaviorAddress > -1 ? (uint)config.CustomBehaviorAddress : 0x401700); + var acts = new[] { false, false, false, false, false, false, false, false }; + acts[7] = Act1; + acts[6] = Act2; + acts[5] = Act3; + acts[4] = Act4; + acts[3] = Act5; + acts[2] = Act6; + clNormal3DObject.SetActs(Command, Bits.ArrayToByte(acts)); + } + + public void CopyPropsTo(ManagedScrollingTexture mst) + { + mst.CycleDuration = CycleDuration; + mst.ScrollingSpeed = ScrollingSpeed; + mst.Type = Type; + mst.Behavior = Behavior; + + mst.Act1 = Act1; + mst.Act2 = Act2; + mst.Act3 = Act3; + mst.Act4 = Act4; + mst.Act5 = Act5; + mst.Act6 = Act6; + } +} + +public enum ScrollBehavior +{ + ScrollingX = 0x0, + ScrollingY = 0x20, + ScrollingZ = 0x40, + ScrollUVBackAndForth = 0x80, + ScrollUVLeftAndRight = 0xA0 +} + +public enum ScrollType +{ + NormalScrolling = 0x0, + SineWave = 0x1, + JumpingScroll = 0x2 } \ No newline at end of file diff --git a/SM64Lib/Level/ShowMessage.cs b/SM64Lib/Level/ShowMessage.cs index 31fa78f..0565ecf 100644 --- a/SM64Lib/Level/ShowMessage.cs +++ b/SM64Lib/Level/ShowMessage.cs @@ -1,9 +1,8 @@  -namespace SM64Lib.Levels +namespace SM64Lib.Levels; + +public class ShowMessage { - public class ShowMessage - { - public bool Enabled { get; set; } = false; - public byte DialogID { get; set; } = 0; - } + public bool Enabled { get; set; } = false; + public byte DialogID { get; set; } = 0; } \ No newline at end of file diff --git a/SM64Lib/Level/SpecialBox.cs b/SM64Lib/Level/SpecialBox.cs index f21db16..375f960 100644 --- a/SM64Lib/Level/SpecialBox.cs +++ b/SM64Lib/Level/SpecialBox.cs @@ -1,48 +1,45 @@ -using global::System.IO; -using SM64Lib.Data; -using SM64Lib.Data.System; +using SM64Lib.Data; -namespace SM64Lib.Levels +namespace SM64Lib.Levels; + +public class SpecialBox { - public class SpecialBox + public SpecialBoxType Type { get; set; } = SpecialBoxType.Water; + public short X1 { get; set; } = 8192; + public short Z1 { get; set; } = 8192; + public short X2 { get; set; } = -8192; + public short Z2 { get; set; } = -8192; + public short Y { get; set; } = 0; + public short Scale { get; set; } = 16; + public bool InvisibleWater { get; set; } = false; + public WaterType WaterType { get; set; } = WaterType.Default; + public byte Alpha { get; set; } = 78; + + public void ToBoxData(BinaryData data) { - public SpecialBoxType Type { get; set; } = SpecialBoxType.Water; - public short X1 { get; set; } = 8192; - public short Z1 { get; set; } = 8192; - public short X2 { get; set; } = -8192; - public short Z2 { get; set; } = -8192; - public short Y { get; set; } = 0; - public short Scale { get; set; } = 16; - public bool InvisibleWater { get; set; } = false; - public WaterType WaterType { get; set; } = WaterType.Default; - public byte Alpha { get; set; } = 78; + // Stand: SM64 Editor v2.0.7 - public void ToBoxData(BinaryData data) + data.Write(InvisibleWater ? 0x0 : 0x10000); // Type = SpecialBoxType.ToxicHaze OrElse + data.Write((short)0xF); + data.Write(Scale); + data.Write(X1); + data.Write(Z1); + data.Write(X2); + data.Write(Z1); + data.Write(X2); + data.Write(Z2); + data.Write(X1); + data.Write(Z2); + + if (Type == SpecialBoxType.ToxicHaze) { - // Stand: SM64 Editor v2.0.7 - - data.Write(InvisibleWater ? 0x0 : 0x10000); // Type = SpecialBoxType.ToxicHaze OrElse - data.Write((short)0xF); - data.Write(Scale); - data.Write(X1); - data.Write(Z1); - data.Write(X2); - data.Write(Z1); - data.Write(X2); - data.Write(Z2); - data.Write(X1); - data.Write(Z2); - - if (Type == SpecialBoxType.ToxicHaze) - { - data.Write(Alpha); // &HB4 - data.Write(0x10000); - } - else - { - data.Write(0x10000 | Alpha); - data.Write((int)WaterType); - } + data.Write(Alpha); // &HB4 + data.Write(0x10000); + } + else + { + data.Write(0x10000 | Alpha); + data.Write((int)WaterType); } } } \ No newline at end of file diff --git a/SM64Lib/Level/SpecialBoxList.cs b/SM64Lib/Level/SpecialBoxList.cs index ad2dd9b..a74179d 100644 --- a/SM64Lib/Level/SpecialBoxList.cs +++ b/SM64Lib/Level/SpecialBoxList.cs @@ -1,67 +1,66 @@ -using System; -using System.Collections.Generic; -using global::System.IO; -using System.Linq; +using global::System.IO; using SM64Lib.Data.System; +using System; +using System.Collections.Generic; +using System.Linq; -namespace SM64Lib.Levels +namespace SM64Lib.Levels; + +public class SpecialBoxList : List { - public class SpecialBoxList : List + public void SortByHeight() { - public void SortByHeight() - { - var boxes = this.OrderByDescending(n => n.Y).ToArray(); - Clear(); - base.AddRange(boxes); - } + var boxes = this.OrderByDescending(n => n.Y).ToArray(); + Clear(); + base.AddRange(boxes); + } - public static SpecialBox[] ReadTable(string Romfile, SpecialBoxType Type, int Levelscriptstart, int TabelStart) - { - var fs = new FileStream(Romfile, FileMode.Open, FileAccess.Read); - var temp = ReadTable(fs, Type, Levelscriptstart, TabelStart); - fs.Close(); - return temp; - } + public static SpecialBox[] ReadTable(string Romfile, SpecialBoxType Type, int Levelscriptstart, int TabelStart) + { + var fs = new FileStream(Romfile, FileMode.Open, FileAccess.Read); + var temp = ReadTable(fs, Type, Levelscriptstart, TabelStart); + fs.Close(); + return temp; + } - public static SpecialBox[] ReadTable(Stream s, SpecialBoxType Type, int Levelscriptstart, int TabelStart) - { - var br = new BinaryReader(s); - var boxlist = new List(); - s.Position = TabelStart; + public static SpecialBox[] ReadTable(Stream s, SpecialBoxType Type, int Levelscriptstart, int TabelStart) + { + var br = new BinaryReader(s); + var boxlist = new List(); + s.Position = TabelStart; - if (SwapInts.SwapInt32(br.ReadInt32()) == 0x1010101) - return Array.Empty(); + if (SwapInts.SwapInt32(br.ReadInt32()) == 0x1010101) + return Array.Empty(); + else + s.Position -= 0x4; + + while (SwapInts.SwapUInt16(br.ReadUInt16()) != 0xFFFF) + { + s.Position += 0x2; + var tbox = new SpecialBox(); + tbox.Type = Type; + int lastpos = (int)(s.Position + 0x4); + s.Position = SwapInts.SwapInt32(br.ReadInt32()) - 0x19000000 + Levelscriptstart; + + if (Type == SpecialBoxType.Water) + tbox.InvisibleWater = SwapInts.SwapInt32(br.ReadInt32()) == 0x0; else - s.Position -= 0x4; - - while (SwapInts.SwapUInt16(br.ReadUInt16()) != 0xFFFF) - { - s.Position += 0x2; - var tbox = new SpecialBox(); - tbox.Type = Type; - int lastpos = (int)(s.Position + 0x4); - s.Position = SwapInts.SwapInt32(br.ReadInt32()) - 0x19000000 + Levelscriptstart; - - if (Type == SpecialBoxType.Water) - tbox.InvisibleWater = SwapInts.SwapInt32(br.ReadInt32()) == 0x0; - else - s.Position += 0x4; - - s.Position += 0x2; - tbox.Scale = SwapInts.SwapInt16(br.ReadInt16()); - tbox.X1 = SwapInts.SwapInt16(br.ReadInt16()); - tbox.Z1 = SwapInts.SwapInt16(br.ReadInt16()); - tbox.X2 = SwapInts.SwapInt16(br.ReadInt16()); s.Position += 0x4; - tbox.Z2 = SwapInts.SwapInt16(br.ReadInt16()); - s.Position += 0x7; - tbox.Alpha = br.ReadByte(); - tbox.WaterType = (WaterType)SwapInts.SwapInt32(br.ReadInt32()); - s.Position = lastpos; - boxlist.Add(tbox); - } - return boxlist.ToArray(); + s.Position += 0x2; + tbox.Scale = SwapInts.SwapInt16(br.ReadInt16()); + tbox.X1 = SwapInts.SwapInt16(br.ReadInt16()); + tbox.Z1 = SwapInts.SwapInt16(br.ReadInt16()); + tbox.X2 = SwapInts.SwapInt16(br.ReadInt16()); + s.Position += 0x4; + tbox.Z2 = SwapInts.SwapInt16(br.ReadInt16()); + s.Position += 0x7; + tbox.Alpha = br.ReadByte(); + tbox.WaterType = (WaterType)SwapInts.SwapInt32(br.ReadInt32()); + s.Position = lastpos; + boxlist.Add(tbox); } + + return boxlist.ToArray(); } } \ No newline at end of file diff --git a/SM64Lib/Level/WarpTools.cs b/SM64Lib/Level/WarpTools.cs index 7a70b66..e464005 100644 --- a/SM64Lib/Level/WarpTools.cs +++ b/SM64Lib/Level/WarpTools.cs @@ -1,43 +1,41 @@ -using System.Collections.Generic; -using System.Data; -using System.Linq; -using Microsoft.VisualBasic.CompilerServices; -using global::SM64Lib.Levels.Script; +using global::SM64Lib.Levels.Script; using global::SM64Lib.Levels.Script.Commands; using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; -namespace SM64Lib.Levels +namespace SM64Lib.Levels; + +public class WarpTools { - public class WarpTools + public static int GetWarpsCountInArea(LevelArea cArea) { - public static int GetWarpsCountInArea(LevelArea cArea) + int count = 0; + count += cArea.Warps.Where(n => new[] { LevelscriptCommandTypes.PaintingWarp, LevelscriptCommandTypes.ConnectedWarp }.Contains(n.CommandType)).Count(); + count += cArea.WarpsForGame.Concat(cArea.Warps).Count(); + return count; + } + + public static int GetWarpsCountInLevel(Level cLevel) + { + int count = 0; + foreach (LevelArea a in cLevel.Areas) + count += GetWarpsCountInArea(a); + return count; + } + + public static byte GetNextUnusedWarpID(LevelArea cArea) + { + var forbitten = new List(); + foreach (LevelscriptCommand cmd in cArea.WarpsForGame.Concat(cArea.Warps)) + forbitten.Add(clWarp.GetWarpID(cmd)); + for (int i = byte.MinValue; i <= byte.MaxValue; i++) { - int count = 0; - count += cArea.Warps.Where(n => new[] { LevelscriptCommandTypes.PaintingWarp, LevelscriptCommandTypes.ConnectedWarp }.Contains(n.CommandType)).Count(); - count += cArea.WarpsForGame.Concat(cArea.Warps).Count(); - return count; + if (!forbitten.Contains(Convert.ToByte(i))) + return Convert.ToByte(i); } - public static int GetWarpsCountInLevel(Level cLevel) - { - int count = 0; - foreach (LevelArea a in cLevel.Areas) - count += GetWarpsCountInArea(a); - return count; - } - - public static byte GetNextUnusedWarpID(LevelArea cArea) - { - var forbitten = new List(); - foreach (LevelscriptCommand cmd in cArea.WarpsForGame.Concat(cArea.Warps)) - forbitten.Add(clWarp.GetWarpID(cmd)); - for (int i = byte.MinValue; i <= byte.MaxValue; i++) - { - if (!forbitten.Contains(Convert.ToByte(i))) - return Convert.ToByte(i); - } - - return byte.MaxValue; - } + return byte.MaxValue; } } \ No newline at end of file diff --git a/SM64Lib/Model/Collision/BoxData.cs b/SM64Lib/Model/Collision/BoxData.cs index 04b33fd..5c976d5 100644 --- a/SM64Lib/Model/Collision/BoxData.cs +++ b/SM64Lib/Model/Collision/BoxData.cs @@ -1,42 +1,41 @@  -namespace SM64Lib.Model.Collision +namespace SM64Lib.Model.Collision; + +public class BoxData { - public class BoxData + public BoxDataType Type { get; set; } = BoxDataType.Water; + public short X1 { get; set; } + public short X2 { get; set; } + public short Z1 { get; set; } + public short Z2 { get; set; } + public short Y { get; set; } + public short Index { get; set; } + + public BoxData() { - public BoxDataType Type { get; set; } = BoxDataType.Water; - public short X1 { get; set; } - public short X2 { get; set; } - public short Z1 { get; set; } - public short Z2 { get; set; } - public short Y { get; set; } - public short Index { get; set; } + X1 = 8192; + X2 = -8192; + Z1 = 8192; + Z2 = -8192; + Y = 0; + Index = 0; + } - public BoxData() - { - X1 = 8192; - X2 = -8192; - Z1 = 8192; - Z2 = -8192; - Y = 0; - Index = 0; - } + public BoxData(Levels.SpecialBox SpecialBox, short Y) + { + X1 = SpecialBox.X1; + X2 = SpecialBox.X2; + Z1 = SpecialBox.Z1; + Z2 = SpecialBox.Z2; + this.Y = Y; + } - public BoxData(Levels.SpecialBox SpecialBox, short Y) - { - X1 = SpecialBox.X1; - X2 = SpecialBox.X2; - Z1 = SpecialBox.Z1; - Z2 = SpecialBox.Z2; - this.Y = Y; - } - - public BoxData(BoxData WaterBox) - { - X1 = WaterBox.X1; - X2 = WaterBox.X2; - Z1 = WaterBox.Z1; - Z2 = WaterBox.Z2; - Y = WaterBox.Y; - } + public BoxData(BoxData WaterBox) + { + X1 = WaterBox.X1; + X2 = WaterBox.X2; + Z1 = WaterBox.Z1; + Z2 = WaterBox.Z2; + Y = WaterBox.Y; } } \ No newline at end of file diff --git a/SM64Lib/Model/Collision/BoxDataType.cs b/SM64Lib/Model/Collision/BoxDataType.cs index dc90567..42e87cf 100644 --- a/SM64Lib/Model/Collision/BoxDataType.cs +++ b/SM64Lib/Model/Collision/BoxDataType.cs @@ -1,10 +1,9 @@  -namespace SM64Lib.Model.Collision +namespace SM64Lib.Model.Collision; + +public enum BoxDataType : short { - public enum BoxDataType : short - { - Water = 0, - ToxicHaze = 0x32, - Mist = 0x33 - } + Water = 0, + ToxicHaze = 0x32, + Mist = 0x33 } \ No newline at end of file diff --git a/SM64Lib/Model/Collision/ColMesh.cs b/SM64Lib/Model/Collision/ColMesh.cs index 540e4e4..b840b49 100644 --- a/SM64Lib/Model/Collision/ColMesh.cs +++ b/SM64Lib/Model/Collision/ColMesh.cs @@ -1,68 +1,67 @@ using System.Collections.Generic; -namespace SM64Lib.Model.Collision +namespace SM64Lib.Model.Collision; + +public class ColMesh { - public class ColMesh + public VertexList Vertices { get; set; } = new VertexList(); + public TriangleList Triangles { get; set; } = new TriangleList(); + + public ColMesh[] SplitMesh() { - public VertexList Vertices { get; set; } = new VertexList(); - public TriangleList Triangles { get; set; } = new TriangleList(); + return SplitMesh(this); + } - public ColMesh[] SplitMesh() + public static ColMesh[] SplitMesh(ColMesh mesh) + { + var meshes = new List(); + if (mesh.Vertices.Count > short.MaxValue || mesh.Triangles.Count > short.MaxValue) { - return SplitMesh(this); - } - - public static ColMesh[] SplitMesh(ColMesh mesh) - { - var meshes = new List(); - if (mesh.Vertices.Count > short.MaxValue || mesh.Triangles.Count > short.MaxValue) + var curMesh = new ColMesh(); + var curVertCopies = new Dictionary(); + foreach (Triangle t in mesh.Triangles) { - var curMesh = new ColMesh(); - var curVertCopies = new Dictionary(); - foreach (Triangle t in mesh.Triangles) + var newTri = new Triangle(); + newTri.CollisionType = t.CollisionType; + for (int i = 0, loopTo = t.ColParams.Length - 1; i <= loopTo; i++) + newTri.ColParams[i] = t.ColParams[i]; + for (int i = 0, loopTo1 = t.Vertices.Length - 1; i <= loopTo1; i++) { - var newTri = new Triangle(); - newTri.CollisionType = t.CollisionType; - for (int i = 0, loopTo = t.ColParams.Length - 1; i <= loopTo; i++) - newTri.ColParams[i] = t.ColParams[i]; - for (int i = 0, loopTo1 = t.Vertices.Length - 1; i <= loopTo1; i++) + var v = t.Vertices[i]; + if (curVertCopies.ContainsKey(v)) { - var v = t.Vertices[i]; - if (curVertCopies.ContainsKey(v)) - { - newTri.Vertices[i] = curVertCopies[v]; - } - else - { - var newVert = new Vertex(); - newVert.X = v.X; - newVert.Y = v.Y; - newVert.Z = v.Z; - curMesh.Vertices.Add(newVert); - curVertCopies.Add(v, newVert); - newTri.Vertices[i] = newVert; - } + newTri.Vertices[i] = curVertCopies[v]; } - - if (curMesh.Vertices.Count > short.MaxValue - 3 || curMesh.Triangles.Count >= short.MaxValue) + else { - meshes.Add(curMesh); - curMesh = new ColMesh(); - curVertCopies.Clear(); + var newVert = new Vertex(); + newVert.X = v.X; + newVert.Y = v.Y; + newVert.Z = v.Z; + curMesh.Vertices.Add(newVert); + curVertCopies.Add(v, newVert); + newTri.Vertices[i] = newVert; } } - if (!meshes.Contains(curMesh) && curMesh.Triangles.Count > 0 && curMesh.Vertices.Count > 0) + if (curMesh.Vertices.Count > short.MaxValue - 3 || curMesh.Triangles.Count >= short.MaxValue) { meshes.Add(curMesh); + curMesh = new ColMesh(); + curVertCopies.Clear(); } } - else - { - meshes.Add(mesh); - } - return meshes.ToArray(); + if (!meshes.Contains(curMesh) && curMesh.Triangles.Count > 0 && curMesh.Vertices.Count > 0) + { + meshes.Add(curMesh); + } } + else + { + meshes.Add(mesh); + } + + return meshes.ToArray(); } } \ No newline at end of file diff --git a/SM64Lib/Model/Collision/CollisionMap.cs b/SM64Lib/Model/Collision/CollisionMap.cs index 37632fa..6c1dd78 100644 --- a/SM64Lib/Model/Collision/CollisionMap.cs +++ b/SM64Lib/Model/Collision/CollisionMap.cs @@ -1,469 +1,467 @@ -using System; +using global::Pilz.S3DFileParser; +using global::SM64Lib.Data; +using global::SM64Lib.Extensions; +using global::System.IO; +using global::System.Numerics; +using SM64Lib.Configuration; +using System; using System.Collections.Generic; using System.Data; -using global::System.IO; using System.Linq; -using global::System.Numerics; using System.Threading.Tasks; -using Microsoft.VisualBasic.CompilerServices; -using global::Pilz.S3DFileParser; -using global::SM64Lib.Extensions; -using global::SM64Lib.Data; -using SM64Lib.Configuration; -namespace SM64Lib.Model.Collision +namespace SM64Lib.Model.Collision; + +public class CollisionMap : IToObject3D { - public class CollisionMap : IToObject3D + private int _Length = 0; + + public ColMesh Mesh { get; set; } = new ColMesh(); + public List SpecialBoxes { get; set; } = new List(); + + public void FromRom(string FileName, int RomOffset, CollisionBasicConfig config) { - private int _Length = 0; + var fs = new FileStream(FileName, FileMode.Open, FileAccess.Read); + FromStream(fs, RomOffset, config); + fs.Close(); + } - public ColMesh Mesh { get; set; } = new ColMesh(); - public List SpecialBoxes { get; set; } = new List(); + public Task FromRomAsync(string FileName, int RomOffset, CollisionBasicConfig config) + { + var t = new Task(() => FromRom(FileName, RomOffset, config)); + t.Start(); + return t; + } - public void FromRom(string FileName, int RomOffset, CollisionBasicConfig config) + public void FromStream(Stream s, int RomOffset, CollisionBasicConfig config) + { + FromBinaryData(new BinaryStreamData(s), RomOffset, config); + } + + public void FromBinaryData(BinaryData s, int dataOffset, CollisionBasicConfig config) + { + bool endlessOn = true; + Mesh = new ColMesh(); + SpecialBoxes.Clear(); + s.Position = dataOffset; + + do { - var fs = new FileStream(FileName, FileMode.Open, FileAccess.Read); - FromStream(fs, RomOffset, config); - fs.Close(); - } - - public Task FromRomAsync(string FileName, int RomOffset, CollisionBasicConfig config) - { - var t = new Task(() => FromRom(FileName, RomOffset, config)); - t.Start(); - return t; - } - - public void FromStream(Stream s, int RomOffset, CollisionBasicConfig config) - { - FromBinaryData(new BinaryStreamData(s), RomOffset, config); - } - - public void FromBinaryData(BinaryData s, int dataOffset, CollisionBasicConfig config) - { - bool endlessOn = true; - Mesh = new ColMesh(); - SpecialBoxes.Clear(); - s.Position = dataOffset; - - do + short curVal = s.ReadInt16(); + switch (curVal) { - short curVal = s.ReadInt16(); - switch (curVal) - { - case 0x40: // S T A R T O F V E R T I C E S - // Lese Eckpunkte / Read Vertices - for (int i = 1, loopTo = s.ReadUInt16(); i <= loopTo; i++) - { - var nVert = new Vertex() - { - X = s.ReadInt16(), - Y = s.ReadInt16(), - Z = s.ReadInt16() - }; - Mesh.Vertices.Add(nVert); - } - - // Lese und erstelle Polygone / Read and build polygones - if (Mesh.Vertices.Count > 0) - { - bool ende = false; - while (!ende) - { - short Coltype = s.ReadInt16(); - if (!Coltype.IsInRange(0x40, 0x44)) - { - for (int i = 1, loopTo1 = s.ReadUInt16(); i <= loopTo1; i++) - { - var pol = new Triangle() { CollisionType = Convert.ToByte(Coltype) }; - for (int iv = 0, loopTo2 = pol.Vertices.Count() - 1; iv <= loopTo2; iv++) - pol.Vertices[iv] = Mesh.Vertices[s.ReadInt16()]; - if (config.CollisionTypesWithParams.Contains(Convert.ToByte(Coltype))) - { - for (int ip = 0, loopTo3 = pol.ColParams.Count() - 1; ip <= loopTo3; ip++) - pol.ColParams[ip] = s.ReadByte(); - } - - Mesh.Triangles.Add(pol); - } - } - else - { - ende = true; - } - } - } - - break; - case 0x41: // E N D O F 0 x 4 0 C O M M A N D - break; - case 0x42: // E N D O F C O L L I S I O N D A T A - endlessOn = false; - break; - case 0x43: // S P E C I A L O B J E C T - break; - case 0x44: // W A T E R B O X E S - SpecialBoxes.AddRange(ReadBoxData(s)); - break; - case 0x33: // M I S T - Compatibility with old buggy RM versions - SpecialBoxes.AddRange(ReadBoxData(s)); - break; - case 0x32: // T O X I C H A Z E - Compatibility with old buggy RM versions - SpecialBoxes.AddRange(ReadBoxData(s)); - break; - } - } - while (endlessOn); - _Length = (int)(s.Position - dataOffset); - } - - public Task FromStreamAsync(Stream s, int RomOffset, CollisionBasicConfig config) - { - var t = new Task(() => FromStream(s, RomOffset, config)); - t.Start(); - return t; - } - - private static BoxData[] ReadBoxData(BinaryData s) - { - var spBoxes = new List(); - - for (int i = 1, loopTo = s.ReadInt16(); i <= loopTo; i++) - { - var wb = new BoxData(); - short type = s.ReadInt16(); - if (type < 0) // Compatibility with old buggy RM versions - { - if (type < 0x32) - type = 0; - else if (type > 0x33) - type = 0x33; - } - wb.Type = (BoxDataType)type; - wb.X1 = s.ReadInt16(); - wb.Z1 = s.ReadInt16(); - wb.X2 = s.ReadInt16(); - wb.Z2 = s.ReadInt16(); - wb.Y = s.ReadInt16(); - spBoxes.Add(wb); - } - - return spBoxes.ToArray(); - } - - public void FromObject3D(ObjectInputSettings ObjSettings, Object3D model, CollisionSettings colSettings = null) - { - var dicMatNames = new Dictionary(); - - // Clear Lists - Mesh.Vertices.Clear(); - Mesh.Triangles.Clear(); - - // Create MatNames - foreach (KeyValuePair kvp in model.Materials) - dicMatNames.Add(kvp.Value, kvp.Key); - - // Add Faces - var dicVertices = new Dictionary(); - foreach (Mesh m in model.Meshes) - { - foreach (Face f in m.Faces.OrderBy(n => n.Material)) - { - var cs = colSettings.GetEntry(dicMatNames[f.Material]); - if (!cs.IsNonSolid) + case 0x40: // S T A R T O F V E R T I C E S + // Lese Eckpunkte / Read Vertices + for (int i = 1, loopTo = s.ReadUInt16(); i <= loopTo; i++) { - var t = new Triangle(); - t.CollisionType = cs.CollisionType; - t.ColParams[0] = cs.CollisionParam1; - t.ColParams[1] = cs.CollisionParam2; - for (int i = 0, loopTo = Math.Min(f.Points.Count - 1, 2); i <= loopTo; i++) + var nVert = new Vertex() { - Vertex v; - var curVert = f.Points[i].Vertex; - if (dicVertices.ContainsKey(curVert)) + X = s.ReadInt16(), + Y = s.ReadInt16(), + Z = s.ReadInt16() + }; + Mesh.Vertices.Add(nVert); + } + + // Lese und erstelle Polygone / Read and build polygones + if (Mesh.Vertices.Count > 0) + { + bool ende = false; + while (!ende) + { + short Coltype = s.ReadInt16(); + if (!Coltype.IsInRange(0x40, 0x44)) { - v = dicVertices[curVert]; + for (int i = 1, loopTo1 = s.ReadUInt16(); i <= loopTo1; i++) + { + var pol = new Triangle() { CollisionType = Convert.ToByte(Coltype) }; + for (int iv = 0, loopTo2 = pol.Vertices.Count() - 1; iv <= loopTo2; iv++) + pol.Vertices[iv] = Mesh.Vertices[s.ReadInt16()]; + if (config.CollisionTypesWithParams.Contains(Convert.ToByte(Coltype))) + { + for (int ip = 0, loopTo3 = pol.ColParams.Count() - 1; ip <= loopTo3; ip++) + pol.ColParams[ip] = s.ReadByte(); + } + + Mesh.Triangles.Add(pol); + } } else { - v = new Vertex(); - v.X = General.KeepInInt16Range(General.Round(curVert.X * ObjSettings.Scaling)); - v.Y = General.KeepInInt16Range(General.Round(curVert.Y * ObjSettings.Scaling)); - v.Z = General.KeepInInt16Range(General.Round(curVert.Z * ObjSettings.Scaling)); - Mesh.Vertices.Add(v); - dicVertices.Add(curVert, v); + ende = true; } - - t.Vertices[i] = v; } - - Mesh.Triangles.Add(t); } - } + + break; + case 0x41: // E N D O F 0 x 4 0 C O M M A N D + break; + case 0x42: // E N D O F C O L L I S I O N D A T A + endlessOn = false; + break; + case 0x43: // S P E C I A L O B J E C T + break; + case 0x44: // W A T E R B O X E S + SpecialBoxes.AddRange(ReadBoxData(s)); + break; + case 0x33: // M I S T - Compatibility with old buggy RM versions + SpecialBoxes.AddRange(ReadBoxData(s)); + break; + case 0x32: // T O X I C H A Z E - Compatibility with old buggy RM versions + SpecialBoxes.AddRange(ReadBoxData(s)); + break; } } + while (endlessOn); + _Length = (int)(s.Position - dataOffset); + } - public Task FromObject3DAsync(ObjectInputSettings ObjSettings, Object3D model, CollisionSettings colSettings = null) - { - var t = new Task(() => FromObject3D(ObjSettings, model, colSettings)); - t.Start(); - return t; - } + public Task FromStreamAsync(Stream s, int RomOffset, CollisionBasicConfig config) + { + var t = new Task(() => FromStream(s, RomOffset, config)); + t.Start(); + return t; + } - public void ToStream(Stream s, int RomOffset, CollisionBasicConfig config) - { - ToBinaryData(new BinaryStreamData(s), RomOffset, config); - } + private static BoxData[] ReadBoxData(BinaryData s) + { + var spBoxes = new List(); - public void ToBinaryData(BinaryData data, int dataOffset, CollisionBasicConfig config) + for (int i = 1, loopTo = s.ReadInt16(); i <= loopTo; i++) { - data.Position = dataOffset; - foreach (ColMesh mesh in Mesh.SplitMesh()) + var wb = new BoxData(); + short type = s.ReadInt16(); + if (type < 0) // Compatibility with old buggy RM versions { + if (type < 0x32) + type = 0; + else if (type > 0x33) + type = 0x33; + } + wb.Type = (BoxDataType)type; + wb.X1 = s.ReadInt16(); + wb.Z1 = s.ReadInt16(); + wb.X2 = s.ReadInt16(); + wb.Z2 = s.ReadInt16(); + wb.Y = s.ReadInt16(); + spBoxes.Add(wb); + } - // V E R T I C E S + return spBoxes.ToArray(); + } - if (mesh.Vertices.Count > 0) + public void FromObject3D(ObjectInputSettings ObjSettings, Object3D model, CollisionSettings colSettings = null) + { + var dicMatNames = new Dictionary(); + + // Clear Lists + Mesh.Vertices.Clear(); + Mesh.Triangles.Clear(); + + // Create MatNames + foreach (KeyValuePair kvp in model.Materials) + dicMatNames.Add(kvp.Value, kvp.Key); + + // Add Faces + var dicVertices = new Dictionary(); + foreach (Mesh m in model.Meshes) + { + foreach (Face f in m.Faces.OrderBy(n => n.Material)) + { + var cs = colSettings.GetEntry(dicMatNames[f.Material]); + if (!cs.IsNonSolid) { - // Start vertices - data.Write(Convert.ToInt16(0x40)); - data.Write(Convert.ToInt16(mesh.Vertices.Count)); - - // Write vertices data - foreach (var vert in mesh.Vertices) + var t = new Triangle(); + t.CollisionType = cs.CollisionType; + t.ColParams[0] = cs.CollisionParam1; + t.ColParams[1] = cs.CollisionParam2; + for (int i = 0, loopTo = Math.Min(f.Points.Count - 1, 2); i <= loopTo; i++) { - data.Write(vert.X); - data.Write(vert.Y); - data.Write(vert.Z); - } - } - - // P O L Y G O N E S - - foreach (byte curType in UsedPolytypes(mesh)) - { - // Search for all triangles with current collision type - var tries = mesh.Triangles.Where(n => n.CollisionType == curType).ToArray(); - if (tries.Length > 0) - { - // Write new collision type - data.Write(Convert.ToInt16(curType)); - - // Write count of triangles - data.Write(Convert.ToInt16(tries.Length)); - - // Check if collisiontype has params - bool hasParams = config.CollisionTypesWithParams.Contains(curType); - foreach (Triangle tri in tries) + Vertex v; + var curVert = f.Points[i].Vertex; + if (dicVertices.ContainsKey(curVert)) { - // Write Vertex Indicies - foreach (Vertex vert in tri.Vertices) - data.Write(Convert.ToInt16(vert.Index)); - - // Write Collision Params, if avaiable - if (hasParams) - { - for (int ip = 0, loopTo = tri.ColParams.Count() - 1; ip <= loopTo; ip++) - data.Write(tri.ColParams[ip]); - } + v = dicVertices[curVert]; } + else + { + v = new Vertex(); + v.X = General.KeepInInt16Range(General.Round(curVert.X * ObjSettings.Scaling)); + v.Y = General.KeepInInt16Range(General.Round(curVert.Y * ObjSettings.Scaling)); + v.Z = General.KeepInInt16Range(General.Round(curVert.Z * ObjSettings.Scaling)); + Mesh.Vertices.Add(v); + dicVertices.Add(curVert, v); + } + + t.Vertices[i] = v; } - } - // E N D 0 x 4 0 C O M M A N D - - data.Write(Convert.ToInt16(0x41)); - } - - // S P E C I A L O B J E C T S - - // Dont know what this is. - - // S P E C I A L B O X E S - - if (SpecialBoxes.Any()) - WriteBoxData(data, SpecialBoxes); - - // E N D C O L L I S I O N D A T A - - data.Write(Convert.ToInt16(0x42)); - } - - private static void WriteBoxData(BinaryData data, IEnumerable bodex) - { - data.Write((short)0x44); - data.Write(Convert.ToInt16(bodex.Count())); - - foreach (BoxDataType t in Enum.GetValues(typeof(BoxDataType))) - { - foreach (var wb in bodex.Where(n => n.Type == t)) - { - data.Write(wb.Index); - data.Write(wb.X1); - data.Write(wb.Z1); - data.Write(wb.X2); - data.Write(wb.Z2); - data.Write(wb.Y); + Mesh.Triangles.Add(t); } } } - - public long Length - { - get - { - long LengthRet = default; - LengthRet = _Length; - General.HexRoundUp2(ref LengthRet); - return LengthRet; - } - - set - { - _Length = Convert.ToInt32(value); - } - } - - public static byte[] UsedPolytypes(ColMesh mesh) - { - var types = new List(); - foreach (Triangle tri in mesh.Triangles) - { - if (!types.Contains(tri.CollisionType)) - { - types.Add(tri.CollisionType); - } - } - - return types.ToArray(); - } - - private float[] DropToGroud_GetFoundList(Vector3 pos) - { - var found = new List(); - foreach (Triangle tri in Mesh.Triangles) - { - var a = new Vector3(tri.Vertices[0].X, tri.Vertices[0].Y, tri.Vertices[0].Z); - var b = new Vector3(tri.Vertices[1].X, tri.Vertices[1].Y, tri.Vertices[1].Z); - var c = new Vector3(tri.Vertices[2].X, tri.Vertices[2].Y, tri.Vertices[2].Z); - if (PointInTriangle(new Vector2(pos.X, pos.Z), a, b, c)) - { - found.Add(barryCentric(a, b, c, pos)); - } - } - - return found.ToArray(); - } - - public float DropToButtom(Vector3 pos) - { - var found = DropToGroud_GetFoundList(pos); - if (found.Any()) - { - return found.Min(); - } - else - { - return pos.Y; - } - } - - public float DropToTop(Vector3 pos) - { - var found = DropToGroud_GetFoundList(pos); - if (found.Any()) - { - return found.Max(); - } - else - { - return pos.Y; - } - } - - public float DropToNearesGround(Vector3 pos) - { - var found = DropToGroud_GetFoundList(pos); - if (found.Count() == 0) - return pos.Y; - int closest_index = 0; - float closest_abs = 9999999.0F; - for (int i = 0, loopTo = found.Count() - 1; i <= loopTo; i++) - { - float abs = Math.Abs(pos.Y - found[i]); - if (abs < closest_abs) - { - closest_abs = abs; - closest_index = i; - } - } - - return found[closest_index]; - } - - private static bool PointInTriangle(Vector2 p, Vector3 p0, Vector3 p1, Vector3 p2) - { - float s = p0.Z * p2.X - p0.X * p2.Z + (p2.Z - p0.Z) * p.X + (p0.X - p2.X) * p.Y; - float t = p0.X * p1.Z - p0.Z * p1.X + (p0.Z - p1.Z) * p.X + (p1.X - p0.X) * p.Y; - if (s < 0 != t < 0) - return false; - float A = -p1.Z * p2.X + p0.Z * (p2.X - p1.X) + p0.X * (p1.Z - p2.Z) + p1.X * p2.Z; - if (A < 0.0) - { - s = -s; - t = -t; - A = -A; - } - - return s > 0 && t > 0 && s + t <= A; - } - - private static float barryCentric(Vector3 p1, Vector3 p2, Vector3 p3, Vector3 pos) - { - float det = (p2.Z - p3.Z) * (p1.X - p3.X) + (p3.X - p2.X) * (p1.Z - p3.Z); - float l1 = ((p2.Z - p3.Z) * (pos.X - p3.X) + (p3.X - p2.X) * (pos.Z - p3.Z)) / det; - float l2 = ((p3.Z - p1.Z) * (pos.X - p3.X) + (p1.X - p3.X) * (pos.Z - p3.Z)) / det; - float l3 = 1.0F - l1 - l2; - return l1 * p1.Y + l2 * p2.Y + l3 * p3.Y; - } - - public Object3D ToObject3D() - { - var obj = new Object3D(); - var m = new Mesh(); - - // Vertices - foreach (var vert in Mesh.Vertices) - m.Vertices.Add(new Pilz.S3DFileParser.Vertex() - { - X = vert.X, - Y = vert.Y, - Z = vert.Z - }); - - // Triangles - foreach (var tri in Mesh.Triangles) - { - var newTri = new Face(); - for (int i = 0; i <= 2; i++) - { - var p = new Point() { Vertex = m.Vertices[tri.Vertices[i].Index] }; - newTri.Points.Add(p); - } - - newTri.Tag = tri.CollisionType; - m.Faces.Add(newTri); - } - - obj.Meshes.Add(m); - return obj; - } - - public Task ToObject3DAsync() - { - var t = new Task(ToObject3D); - t.Start(); - return t; - } + } + + public Task FromObject3DAsync(ObjectInputSettings ObjSettings, Object3D model, CollisionSettings colSettings = null) + { + var t = new Task(() => FromObject3D(ObjSettings, model, colSettings)); + t.Start(); + return t; + } + + public void ToStream(Stream s, int RomOffset, CollisionBasicConfig config) + { + ToBinaryData(new BinaryStreamData(s), RomOffset, config); + } + + public void ToBinaryData(BinaryData data, int dataOffset, CollisionBasicConfig config) + { + data.Position = dataOffset; + foreach (ColMesh mesh in Mesh.SplitMesh()) + { + + // V E R T I C E S + + if (mesh.Vertices.Count > 0) + { + // Start vertices + data.Write(Convert.ToInt16(0x40)); + data.Write(Convert.ToInt16(mesh.Vertices.Count)); + + // Write vertices data + foreach (var vert in mesh.Vertices) + { + data.Write(vert.X); + data.Write(vert.Y); + data.Write(vert.Z); + } + } + + // P O L Y G O N E S + + foreach (byte curType in UsedPolytypes(mesh)) + { + // Search for all triangles with current collision type + var tries = mesh.Triangles.Where(n => n.CollisionType == curType).ToArray(); + if (tries.Length > 0) + { + // Write new collision type + data.Write(Convert.ToInt16(curType)); + + // Write count of triangles + data.Write(Convert.ToInt16(tries.Length)); + + // Check if collisiontype has params + bool hasParams = config.CollisionTypesWithParams.Contains(curType); + foreach (Triangle tri in tries) + { + // Write Vertex Indicies + foreach (Vertex vert in tri.Vertices) + data.Write(Convert.ToInt16(vert.Index)); + + // Write Collision Params, if avaiable + if (hasParams) + { + for (int ip = 0, loopTo = tri.ColParams.Count() - 1; ip <= loopTo; ip++) + data.Write(tri.ColParams[ip]); + } + } + } + } + + // E N D 0 x 4 0 C O M M A N D + + data.Write(Convert.ToInt16(0x41)); + } + + // S P E C I A L O B J E C T S + + // Dont know what this is. + + // S P E C I A L B O X E S + + if (SpecialBoxes.Any()) + WriteBoxData(data, SpecialBoxes); + + // E N D C O L L I S I O N D A T A + + data.Write(Convert.ToInt16(0x42)); + } + + private static void WriteBoxData(BinaryData data, IEnumerable bodex) + { + data.Write((short)0x44); + data.Write(Convert.ToInt16(bodex.Count())); + + foreach (BoxDataType t in Enum.GetValues(typeof(BoxDataType))) + { + foreach (var wb in bodex.Where(n => n.Type == t)) + { + data.Write(wb.Index); + data.Write(wb.X1); + data.Write(wb.Z1); + data.Write(wb.X2); + data.Write(wb.Z2); + data.Write(wb.Y); + } + } + } + + public long Length + { + get + { + long LengthRet = default; + LengthRet = _Length; + General.HexRoundUp2(ref LengthRet); + return LengthRet; + } + + set + { + _Length = Convert.ToInt32(value); + } + } + + public static byte[] UsedPolytypes(ColMesh mesh) + { + var types = new List(); + foreach (Triangle tri in mesh.Triangles) + { + if (!types.Contains(tri.CollisionType)) + { + types.Add(tri.CollisionType); + } + } + + return types.ToArray(); + } + + private float[] DropToGroud_GetFoundList(Vector3 pos) + { + var found = new List(); + foreach (Triangle tri in Mesh.Triangles) + { + var a = new Vector3(tri.Vertices[0].X, tri.Vertices[0].Y, tri.Vertices[0].Z); + var b = new Vector3(tri.Vertices[1].X, tri.Vertices[1].Y, tri.Vertices[1].Z); + var c = new Vector3(tri.Vertices[2].X, tri.Vertices[2].Y, tri.Vertices[2].Z); + if (PointInTriangle(new Vector2(pos.X, pos.Z), a, b, c)) + { + found.Add(barryCentric(a, b, c, pos)); + } + } + + return found.ToArray(); + } + + public float DropToButtom(Vector3 pos) + { + var found = DropToGroud_GetFoundList(pos); + if (found.Any()) + { + return found.Min(); + } + else + { + return pos.Y; + } + } + + public float DropToTop(Vector3 pos) + { + var found = DropToGroud_GetFoundList(pos); + if (found.Any()) + { + return found.Max(); + } + else + { + return pos.Y; + } + } + + public float DropToNearesGround(Vector3 pos) + { + var found = DropToGroud_GetFoundList(pos); + if (found.Count() == 0) + return pos.Y; + int closest_index = 0; + float closest_abs = 9999999.0F; + for (int i = 0, loopTo = found.Count() - 1; i <= loopTo; i++) + { + float abs = Math.Abs(pos.Y - found[i]); + if (abs < closest_abs) + { + closest_abs = abs; + closest_index = i; + } + } + + return found[closest_index]; + } + + private static bool PointInTriangle(Vector2 p, Vector3 p0, Vector3 p1, Vector3 p2) + { + float s = p0.Z * p2.X - p0.X * p2.Z + (p2.Z - p0.Z) * p.X + (p0.X - p2.X) * p.Y; + float t = p0.X * p1.Z - p0.Z * p1.X + (p0.Z - p1.Z) * p.X + (p1.X - p0.X) * p.Y; + if (s < 0 != t < 0) + return false; + float A = -p1.Z * p2.X + p0.Z * (p2.X - p1.X) + p0.X * (p1.Z - p2.Z) + p1.X * p2.Z; + if (A < 0.0) + { + s = -s; + t = -t; + A = -A; + } + + return s > 0 && t > 0 && s + t <= A; + } + + private static float barryCentric(Vector3 p1, Vector3 p2, Vector3 p3, Vector3 pos) + { + float det = (p2.Z - p3.Z) * (p1.X - p3.X) + (p3.X - p2.X) * (p1.Z - p3.Z); + float l1 = ((p2.Z - p3.Z) * (pos.X - p3.X) + (p3.X - p2.X) * (pos.Z - p3.Z)) / det; + float l2 = ((p3.Z - p1.Z) * (pos.X - p3.X) + (p1.X - p3.X) * (pos.Z - p3.Z)) / det; + float l3 = 1.0F - l1 - l2; + return l1 * p1.Y + l2 * p2.Y + l3 * p3.Y; + } + + public Object3D ToObject3D() + { + var obj = new Object3D(); + var m = new Mesh(); + + // Vertices + foreach (var vert in Mesh.Vertices) + m.Vertices.Add(new Pilz.S3DFileParser.Vertex() + { + X = vert.X, + Y = vert.Y, + Z = vert.Z + }); + + // Triangles + foreach (var tri in Mesh.Triangles) + { + var newTri = new Face(); + for (int i = 0; i <= 2; i++) + { + var p = new Point() { Vertex = m.Vertices[tri.Vertices[i].Index] }; + newTri.Points.Add(p); + } + + newTri.Tag = tri.CollisionType; + m.Faces.Add(newTri); + } + + obj.Meshes.Add(m); + return obj; + } + + public Task ToObject3DAsync() + { + var t = new Task(ToObject3D); + t.Start(); + return t; } } \ No newline at end of file diff --git a/SM64Lib/Model/Collision/CollisionSettings.cs b/SM64Lib/Model/Collision/CollisionSettings.cs index 1e9b1bc..eba04d0 100644 --- a/SM64Lib/Model/Collision/CollisionSettings.cs +++ b/SM64Lib/Model/Collision/CollisionSettings.cs @@ -1,83 +1,81 @@ -using System; +using global::System.IO; +using System; using System.Collections.Generic; -using global::System.IO; using System.Linq; using System.Threading.Tasks; -using Microsoft.VisualBasic.CompilerServices; -namespace SM64Lib.Model.Collision +namespace SM64Lib.Model.Collision; + +public class CollisionSettings { - public class CollisionSettings + public List Entries { get; private set; } = new List(); + + public async Task Load(string fileName) { - public List Entries { get; private set; } = new List(); - - public async Task Load(string fileName) + if (File.Exists(fileName)) { - if (File.Exists(fileName)) + var fs = new FileStream(fileName, FileMode.Open, FileAccess.Read); + var sr = new StreamReader(fs); + Entries.Clear(); + while (!sr.EndOfStream) { - var fs = new FileStream(fileName, FileMode.Open, FileAccess.Read); - var sr = new StreamReader(fs); - Entries.Clear(); - while (!sr.EndOfStream) - { - var e = new Entry(); - e.FromString(await sr.ReadLineAsync()); - Entries.Add(e); - } - - fs.Close(); + var e = new Entry(); + e.FromString(await sr.ReadLineAsync()); + Entries.Add(e); } - } - public async Task Save(string fileName) - { - var fs = new FileStream(fileName, FileMode.Create, FileAccess.ReadWrite); - var sw = new StreamWriter(fs); - foreach (Entry e in Entries) - await sw.WriteLineAsync(e.ToString()); - await sw.FlushAsync(); fs.Close(); } + } - public Entry GetEntry(string matName) + public async Task Save(string fileName) + { + var fs = new FileStream(fileName, FileMode.Create, FileAccess.ReadWrite); + var sw = new StreamWriter(fs); + foreach (Entry e in Entries) + await sw.WriteLineAsync(e.ToString()); + await sw.FlushAsync(); + fs.Close(); + } + + public Entry GetEntry(string matName) + { + foreach (Entry e in Entries) { - foreach (Entry e in Entries) + if ((e.MaterialName ?? "") == (matName ?? "")) { - if ((e.MaterialName ?? "") == (matName ?? "")) - { - return e; - } + return e; } - - var ne = new Entry(); - ne.MaterialName = matName; - Entries.Add(ne); - return ne; } - public class Entry + var ne = new Entry(); + ne.MaterialName = matName; + Entries.Add(ne); + return ne; + } + + public class Entry + { + public string MaterialName { get; set; } = ""; + public byte CollisionType { get; set; } = 0; + public byte CollisionParam1 { get; set; } = 0; + public byte CollisionParam2 { get; set; } = 0; + public bool IsNonSolid { get; set; } = false; + + public new string ToString() { - public string MaterialName { get; set; } = ""; - public byte CollisionType { get; set; } = 0; - public byte CollisionParam1 { get; set; } = 0; - public byte CollisionParam2 { get; set; } = 0; - public bool IsNonSolid { get; set; } = false; + return $"{MaterialName};{CollisionType};{CollisionParam1};{CollisionParam2};{IsNonSolid.ToString()}"; + } - public new string ToString() - { - return $"{MaterialName};{CollisionType};{CollisionParam1};{CollisionParam2};{IsNonSolid.ToString()}"; - } - - public void FromString(string str) - { - var parts = str.Split(';'); - MaterialName = parts[0]; - CollisionType = Convert.ToByte(parts[1]); - CollisionParam1 = Convert.ToByte(parts[2]); - CollisionParam2 = Convert.ToByte(parts[3]); - if (parts.Count() > 4) - IsNonSolid = Convert.ToBoolean(parts[4]); - } + public void FromString(string str) + { + var parts = str.Split(';'); + MaterialName = parts[0]; + CollisionType = Convert.ToByte(parts[1]); + CollisionParam1 = Convert.ToByte(parts[2]); + CollisionParam2 = Convert.ToByte(parts[3]); + if (parts.Count() > 4) + IsNonSolid = Convert.ToBoolean(parts[4]); } } } \ No newline at end of file diff --git a/SM64Lib/Model/Collision/Triangel.cs b/SM64Lib/Model/Collision/Triangel.cs index bdb4855..8a11720 100644 --- a/SM64Lib/Model/Collision/Triangel.cs +++ b/SM64Lib/Model/Collision/Triangel.cs @@ -1,24 +1,23 @@  using Newtonsoft.Json; -namespace SM64Lib.Model.Collision +namespace SM64Lib.Model.Collision; + +public class Triangle { - public class Triangle + public byte CollisionType { get; set; } = 0; + + public byte[] ColParams { get; set; } = new byte[] { 0, 0 }; + [JsonConverter(typeof(Json.ArrayReferencePreservngConverter))] + public Vertex[] Vertices { get; set; } = new Vertex[3]; + + public TriangleList ParentList { get; set; } = null; + + public int Index { - public byte CollisionType { get; set; } = 0; - - public byte[] ColParams { get; set; } = new byte[] { 0, 0 }; - [JsonConverter(typeof(Json.ArrayReferencePreservngConverter))] - public Vertex[] Vertices { get; set; } = new Vertex[3]; - - public TriangleList ParentList { get; set; } = null; - - public int Index + get { - get - { - return ParentList.IndexOf(this); - } + return ParentList.IndexOf(this); } } } \ No newline at end of file diff --git a/SM64Lib/Model/Collision/TriangelList.cs b/SM64Lib/Model/Collision/TriangelList.cs index b507255..dfac7c5 100644 --- a/SM64Lib/Model/Collision/TriangelList.cs +++ b/SM64Lib/Model/Collision/TriangelList.cs @@ -1,26 +1,25 @@ using System.Collections.Generic; -namespace SM64Lib.Model.Collision +namespace SM64Lib.Model.Collision; + +public class TriangleList : List { - public class TriangleList : List + public new void Add(Triangle item) { - public new void Add(Triangle item) - { - base.Add(item); - item.ParentList = this; - } + base.Add(item); + item.ParentList = this; + } - public new void Insert(int index, Triangle item) - { - base.Insert(index, item); - item.ParentList = this; - } + public new void Insert(int index, Triangle item) + { + base.Insert(index, item); + item.ParentList = this; + } - public new void AddRange(IEnumerable collection) - { - foreach (Triangle v in collection) - v.ParentList = this; - base.AddRange(collection); - } + public new void AddRange(IEnumerable collection) + { + foreach (Triangle v in collection) + v.ParentList = this; + base.AddRange(collection); } } \ No newline at end of file diff --git a/SM64Lib/Model/Collision/Vertex.cs b/SM64Lib/Model/Collision/Vertex.cs index e490dab..a2d5a44 100644 --- a/SM64Lib/Model/Collision/Vertex.cs +++ b/SM64Lib/Model/Collision/Vertex.cs @@ -1,21 +1,17 @@ - -using Newtonsoft.Json; +namespace SM64Lib.Model.Collision; -namespace SM64Lib.Model.Collision +public class Vertex { - public class Vertex - { - public short X { get; set; } = 0; - public short Y { get; set; } = 0; - public short Z { get; set; } = 0; - public VertexList ParentList { get; set; } = null; + public short X { get; set; } = 0; + public short Y { get; set; } = 0; + public short Z { get; set; } = 0; + public VertexList ParentList { get; set; } = null; - public int Index + public int Index + { + get { - get - { - return ParentList.IndexOf(this); - } + return ParentList.IndexOf(this); } } } \ No newline at end of file diff --git a/SM64Lib/Model/Collision/VertexList.cs b/SM64Lib/Model/Collision/VertexList.cs index 9d5b2f9..3e6853b 100644 --- a/SM64Lib/Model/Collision/VertexList.cs +++ b/SM64Lib/Model/Collision/VertexList.cs @@ -1,26 +1,25 @@ using System.Collections.Generic; -namespace SM64Lib.Model.Collision +namespace SM64Lib.Model.Collision; + +public class VertexList : List { - public class VertexList : List + public new void Add(Vertex item) { - public new void Add(Vertex item) - { - base.Add(item); - item.ParentList = this; - } + base.Add(item); + item.ParentList = this; + } - public new void Insert(int index, Vertex item) - { - base.Insert(index, item); - item.ParentList = this; - } + public new void Insert(int index, Vertex item) + { + base.Insert(index, item); + item.ParentList = this; + } - public new void AddRange(IEnumerable collection) - { - foreach (Vertex v in collection) - v.ParentList = this; - base.AddRange(collection); - } + public new void AddRange(IEnumerable collection) + { + foreach (Vertex v in collection) + v.ParentList = this; + base.AddRange(collection); } } \ No newline at end of file diff --git a/SM64Lib/Model/Conversion/FaceCullingMode.cs b/SM64Lib/Model/Conversion/FaceCullingMode.cs index 3e7b46a..14f65c3 100644 --- a/SM64Lib/Model/Conversion/FaceCullingMode.cs +++ b/SM64Lib/Model/Conversion/FaceCullingMode.cs @@ -1,11 +1,10 @@  -namespace SM64Lib.Model.Conversion +namespace SM64Lib.Model.Conversion; + +public enum FaceCullingMode { - public enum FaceCullingMode - { - NoCulling, - Front, - Back, - FrontAndBack = Front | Back - } + NoCulling, + Front, + Back, + FrontAndBack = Front | Back } \ No newline at end of file diff --git a/SM64Lib/Model/Conversion/Fast3DParsing/Fast3DParser.cs b/SM64Lib/Model/Conversion/Fast3DParsing/Fast3DParser.cs index ad733e3..93c64f4 100644 --- a/SM64Lib/Model/Conversion/Fast3DParsing/Fast3DParser.cs +++ b/SM64Lib/Model/Conversion/Fast3DParsing/Fast3DParser.cs @@ -1,485 +1,482 @@ -using System; -using System.Collections.Generic; -using global::System.Drawing; -using global::System.IO; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.VisualBasic; -using Microsoft.VisualBasic.CompilerServices; -using global::Pilz.S3DFileParser; +using global::Pilz.S3DFileParser; using global::SM64Lib.Data; using global::SM64Lib.Model.Fast3D.DisplayLists; using global::SM64Lib.Model.Fast3D.DisplayLists.Script; using global::SM64Lib.Model.Fast3D.DisplayLists.Script.Commands; using global::SM64Lib.SegmentedBanking; +using global::System.Drawing; +using global::System.IO; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; using Converts = System.Convert; -namespace SM64Lib.Model.Conversion.Fast3DParsing +namespace SM64Lib.Model.Conversion.Fast3DParsing; + +public class Fast3DParser { - public class Fast3DParser + + /// Parse a Displaylist to an Object3D. + /// The Object3D where the model should be parsed to. + /// The Displaylist which should be parsed. + /// The RomManager Instance to use. + /// The Area ID if avaiable. + public static void Convert(Object3D obj, DisplayList dl, RomManager rommgr, byte? AreaID) { + if (dl.Script.Count == 0 || dl.GeoPointer is null) + return; + int cmdIndex = 0; + DisplayListCommand cmd = null; + byte[] cmdarr = null; + var knownTextures = new Dictionary(); + var knownColors = new Dictionary(); + var knownVertices = new Dictionary(); + var knownNormals = new Dictionary(); + var knownUVs = new Dictionary(); + var knownVertexColors = new Dictionary(); + var knownShading = new Dictionary(); + var dicVertexColorShading = new Dictionary(); + var pointbuffer = new Pilz.S3DFileParser.Point[16]; + var scaledVertices = new List(); + Material curTexture = null; + Size curTexSize = default; + int curTexSegAddr = -1; + int curTexWrapT = 10497; + int curTexWrapS = 10497; + var curTexScale = new System.Numerics.Vector2(1.0F, 1.0F); + var curTexPalette = Array.Empty(); + int curTexPaletteSegAddr = -1; + N64Graphics.N64Codec? curTexFormat = default; + uint curGeometryMode = 0x22205; + Mesh curMesh = null; + Color? curColor = default; + TextureLoadedInfos curTexLoadedInfos = null; + bool useUVOffsetFix = true; + int dlDepth = 0; - /// Parse a Displaylist to an Object3D. - /// The Object3D where the model should be parsed to. - /// The Displaylist which should be parsed. - /// The RomManager Instance to use. - /// The Area ID if avaiable. - public static void Convert(Object3D obj, DisplayList dl, RomManager rommgr, byte? AreaID) + // Load Main Segmented Bank + var curSeg = GetSegBank(rommgr, dl.GeoPointer.SegPointer, AreaID); + if (curSeg is null) return; + + curMesh = new Mesh(); + + while (cmdIndex < dl.Script.Count /*&& dl.Script[cmdIndex].CommandType != CommandTypes.EndDisplaylist*/) { - if (dl.Script.Count == 0 || dl.GeoPointer is null) - return; - int cmdIndex = 0; - DisplayListCommand cmd = null; - byte[] cmdarr = null; - var knownTextures = new Dictionary(); - var knownColors = new Dictionary(); - var knownVertices = new Dictionary(); - var knownNormals = new Dictionary(); - var knownUVs = new Dictionary(); - var knownVertexColors = new Dictionary(); - var knownShading = new Dictionary(); - var dicVertexColorShading = new Dictionary(); - var pointbuffer = new Pilz.S3DFileParser.Point[16]; - var scaledVertices = new List(); - Material curTexture = null; - Size curTexSize = default; - int curTexSegAddr = -1; - int curTexWrapT = 10497; - int curTexWrapS = 10497; - var curTexScale = new System.Numerics.Vector2(1.0F, 1.0F); - var curTexPalette = Array.Empty(); - int curTexPaletteSegAddr = -1; - N64Graphics.N64Codec? curTexFormat = default; - uint curGeometryMode = 0x22205; - Mesh curMesh = null; - Color? curColor = default; - TextureLoadedInfos curTexLoadedInfos = null; - bool useUVOffsetFix = true; - int dlDepth = 0; - - // Load Main Segmented Bank - var curSeg = GetSegBank(rommgr, dl.GeoPointer.SegPointer, AreaID); - if (curSeg is null) return; - - curMesh = new Mesh(); - - while (cmdIndex < dl.Script.Count /*&& dl.Script[cmdIndex].CommandType != CommandTypes.EndDisplaylist*/) + cmd = dl.Script[cmdIndex]; + cmdarr = cmd.ToArray(); + var switchExpr = cmd.CommandType; // &H20000 + switch (switchExpr) { - cmd = dl.Script[cmdIndex]; - cmdarr = cmd.ToArray(); - var switchExpr = cmd.CommandType; // &H20000 - switch (switchExpr) - { - case CommandTypes.DisplayList: - if (cmdarr[1] != 1) - dlDepth += 1; + case CommandTypes.DisplayList: + if (cmdarr[1] != 1) + dlDepth += 1; + break; + + case CommandTypes.EndDisplaylist: + if (dlDepth > 0) + dlDepth -= 1; + break; + + case CommandTypes.ClearGeometryMode: + { + curGeometryMode = curGeometryMode & ~F3D_CLEARGEOMETRYMODE.GetGeometryMode(cmd); break; + } - case CommandTypes.EndDisplaylist: - if (dlDepth > 0) - dlDepth -= 1; + case CommandTypes.SetGeometryMode: + { + curGeometryMode = curGeometryMode | F3D_CLEARGEOMETRYMODE.GetGeometryMode(cmd); break; + } - case CommandTypes.ClearGeometryMode: + case CommandTypes.Movemem: + { + int segAddr = F3D_MOVEMEM.GetSegmentedOffset(cmd); + byte smode = F3D_MOVEMEM.GetLightValueMode(cmd); + if (smode == 0x86) // Load Shading Light (Diffuse) Color { - curGeometryMode = curGeometryMode & ~F3D_CLEARGEOMETRYMODE.GetGeometryMode(cmd); - break; - } - - case CommandTypes.SetGeometryMode: - { - curGeometryMode = curGeometryMode | F3D_CLEARGEOMETRYMODE.GetGeometryMode(cmd); - break; - } - - case CommandTypes.Movemem: - { - int segAddr = F3D_MOVEMEM.GetSegmentedOffset(cmd); - byte smode = F3D_MOVEMEM.GetLightValueMode(cmd); - if (smode == 0x86) // Load Shading Light (Diffuse) Color + if (knownShading.ContainsKey(segAddr)) { - if (knownShading.ContainsKey(segAddr)) - { - curColor = knownShading[segAddr]; - } - else - { - var colordata = new byte[4]; - var seg = rommgr.GetSegBank(Converts.ToByte(segAddr >> 24), AreaID); - - // Read Color Data - seg.Data.Position = segAddr & 0xFFFFFF; - seg.Data.Read(colordata, 0, colordata.Length); - curColor = Color.FromArgb(0xFF, colordata[0], colordata[1], colordata[2]); - if (!dicVertexColorShading.ContainsKey((Color)curColor)) - { - // Create new Vertex Color - var vc = new VertexColor() { R = colordata[0] / 256.0F, G = colordata[1] / 256.0F, B = colordata[2] / 256.0F, A = 1.0F }; - dicVertexColorShading.Add((Color)curColor, vc); - } - - // Set as Vertex Color - knownShading.Add(segAddr, (Color)curColor); - } - } - - break; - } - - case CommandTypes.Loadtlut: - { - byte paletteTileDescritpr = cmdarr[4]; - ushort numColorsToLoadInPalette; - curTexPaletteSegAddr = curTexSegAddr; - cmd.Position = 5; - numColorsToLoadInPalette = (ushort)(cmd.ReadUInt16() >> 6); - var seg = rommgr.GetSegBank(Converts.ToByte(curTexPaletteSegAddr >> 24), AreaID); - curTexPalette = new byte[numColorsToLoadInPalette * 2 + 1 + 1]; - int offset = curTexPaletteSegAddr & 0xFFFFFF; - for (int i = 1, loopTo = numColorsToLoadInPalette + 1; i <= loopTo; i++) - { - int ii = i * 2 - 2; - seg.Data.Position = offset + ii; - curTexPalette[ii] = Converts.ToByte(seg.Data.ReadByte()); - curTexPalette[ii + 1] = Converts.ToByte(seg.Data.ReadByte()); - } - - break; - } - - case CommandTypes.Triangle1: - { - var f = new Face(); - if (curTexFormat is not null) - { - ProcessTexture(obj, rommgr, AreaID, dl, (N64Graphics.N64Codec)curTexFormat, knownTextures, ref curTexture, curTexSegAddr, curTexSize, curTexWrapT, curTexWrapS, curTexScale, curTexPalette, curTexPaletteSegAddr, curColor, ref curTexLoadedInfos); - f.Material = curTexture; - } - - for (int i = 1; i <= 3; i++) - { - byte pindex = F3D_TRI1.GetVertice(cmd, Converts.ToByte(i)); - if (pindex >= pointbuffer.Length) - return; - var p = pointbuffer[pindex]; - if (p is not null) - f.Points.Add(p); - } - - // Shading (as Vertex Color) - if (curTexture?.Color is not null && (curGeometryMode & (long)0x20000) != 0) - { - var vc = dicVertexColorShading[(Color)curTexture.Color]; - foreach (Pilz.S3DFileParser.Point p in f.Points) - { - if (p.VertexColor is null) - { - if (dicVertexColorShading.ContainsKey((Color)curTexture.Color)) - { - p.VertexColor = vc; - if (!curMesh.VertexColors.Contains(vc)) - { - curMesh.VertexColors.Add(vc); - } - } - } - } - } - - curMesh.Faces.Add(f); - break; - } - - case CommandTypes.Vertex: - { - byte num = F3D_VTX.GetNumberOfVertices(cmd); - byte startindex = F3D_VTX.GetStartIndexInVertexBuffer(cmd); - short datalength = F3D_VTX.GetLengthOfVertexData(cmd); - int segAddr = F3D_VTX.GetSegmentedAddress(cmd); - if (num > 0) - { - for (int i = 0, loopTo1 = num; i <= loopTo1; i++) - { - var p = new Pilz.S3DFileParser.Point(); - int curSegAddr = segAddr + i * 0x10; - var cs = GetSegBank(rommgr, curSegAddr, AreaID); - if (cs is null) - continue; - - // Vertex - if (knownVertices.ContainsKey(curSegAddr)) - { - p.Vertex = knownVertices[curSegAddr]; - } - else - { - var vert = GetVertexFromStream(cs.Data, cs.BankOffsetFromSegAddr(curSegAddr), dl.GeoPointer.ModelOffset, dl.GeoPointer.ModelScale); - p.Vertex = vert; - curMesh.Vertices.Add(vert); - knownVertices.Add(curSegAddr, vert); - } - - // UV - if (knownUVs.ContainsKey(curSegAddr)) - { - p.UV = knownUVs[curSegAddr]; - } - else - { - var uv = GetUVFromStream(cs.Data, cs.BankOffsetFromSegAddr(curSegAddr), curTexScale, curTexSize, useUVOffsetFix); - p.UV = uv; - curMesh.UVs.Add(uv); - knownUVs.Add(curSegAddr, uv); - } - - if ((curGeometryMode & (long)0x20000) == 0) - { - // Vertex Color - if (knownVertexColors.ContainsKey(curSegAddr)) - { - p.VertexColor = knownVertexColors[curSegAddr]; - } - else - { - var vc = GetVertexColorFromStream(cs.Data, cs.BankOffsetFromSegAddr(curSegAddr)); - p.VertexColor = vc; - curMesh.VertexColors.Add(vc); - knownVertexColors.Add(curSegAddr, vc); - } - } - // Normal - else if (knownNormals.ContainsKey(curSegAddr)) - { - p.Normal = knownNormals[curSegAddr]; - } - else - { - var n = GetNormalFromStream(cs.Data, cs.BankOffsetFromSegAddr(curSegAddr)); - p.Normal = n; - curMesh.Normals.Add(n); - knownNormals.Add(curSegAddr, n); - } - - pointbuffer[startindex + i] = p; - } - } - - break; - } - - case CommandTypes.SetImage: - { - int newAddr = F3D_SETIMG.GetSegmentedAddress(cmd); - if ((uint)newAddr != 0xFFFFFFFF) - { - curTexSegAddr = newAddr; - } - - break; - } - - case CommandTypes.SetTileSize: - { - curTexSize = F3D_SETTILESIZE.GetSize(cmd); - break; - } - - case CommandTypes.SetTile: - { - cmd.Position = 4; - int checkVal = cmd.ReadInt32(); - cmd.Position = 0; - if (checkVal != 0x7000000) - { - if (cmdarr[4] == 0) - { - curTexFormat = F3D_SETTILE.GetTextureFormat(cmd); - } - - curTexWrapT = F3D_SETTILE.GetWrapT(cmd); - curTexWrapS = F3D_SETTILE.GetWrapS(cmd); - } - - break; - } - - case CommandTypes.Texture: - { - if ((curGeometryMode & (long)0x40000) == 0x40000) - { - curTexSize = F3D_TEXTURE.GetTextureSize(cmd); + curColor = knownShading[segAddr]; } else { - curTexScale = F3D_TEXTURE.GetTextureScaling(cmd); + var colordata = new byte[4]; + var seg = rommgr.GetSegBank(Converts.ToByte(segAddr >> 24), AreaID); + + // Read Color Data + seg.Data.Position = segAddr & 0xFFFFFF; + seg.Data.Read(colordata, 0, colordata.Length); + curColor = Color.FromArgb(0xFF, colordata[0], colordata[1], colordata[2]); + if (!dicVertexColorShading.ContainsKey((Color)curColor)) + { + // Create new Vertex Color + var vc = new VertexColor() { R = colordata[0] / 256.0F, G = colordata[1] / 256.0F, B = colordata[2] / 256.0F, A = 1.0F }; + dicVertexColorShading.Add((Color)curColor, vc); + } + + // Set as Vertex Color + knownShading.Add(segAddr, (Color)curColor); + } + } + + break; + } + + case CommandTypes.Loadtlut: + { + byte paletteTileDescritpr = cmdarr[4]; + ushort numColorsToLoadInPalette; + curTexPaletteSegAddr = curTexSegAddr; + cmd.Position = 5; + numColorsToLoadInPalette = (ushort)(cmd.ReadUInt16() >> 6); + var seg = rommgr.GetSegBank(Converts.ToByte(curTexPaletteSegAddr >> 24), AreaID); + curTexPalette = new byte[numColorsToLoadInPalette * 2 + 1 + 1]; + int offset = curTexPaletteSegAddr & 0xFFFFFF; + for (int i = 1, loopTo = numColorsToLoadInPalette + 1; i <= loopTo; i++) + { + int ii = i * 2 - 2; + seg.Data.Position = offset + ii; + curTexPalette[ii] = Converts.ToByte(seg.Data.ReadByte()); + curTexPalette[ii + 1] = Converts.ToByte(seg.Data.ReadByte()); + } + + break; + } + + case CommandTypes.Triangle1: + { + var f = new Face(); + if (curTexFormat is not null) + { + ProcessTexture(obj, rommgr, AreaID, dl, (N64Graphics.N64Codec)curTexFormat, knownTextures, ref curTexture, curTexSegAddr, curTexSize, curTexWrapT, curTexWrapS, curTexScale, curTexPalette, curTexPaletteSegAddr, curColor, ref curTexLoadedInfos); + f.Material = curTexture; + } + + for (int i = 1; i <= 3; i++) + { + byte pindex = F3D_TRI1.GetVertice(cmd, Converts.ToByte(i)); + if (pindex >= pointbuffer.Length) + return; + var p = pointbuffer[pindex]; + if (p is not null) + f.Points.Add(p); + } + + // Shading (as Vertex Color) + if (curTexture?.Color is not null && (curGeometryMode & (long)0x20000) != 0) + { + var vc = dicVertexColorShading[(Color)curTexture.Color]; + foreach (Pilz.S3DFileParser.Point p in f.Points) + { + if (p.VertexColor is null) + { + if (dicVertexColorShading.ContainsKey((Color)curTexture.Color)) + { + p.VertexColor = vc; + if (!curMesh.VertexColors.Contains(vc)) + { + curMesh.VertexColors.Add(vc); + } + } + } + } + } + + curMesh.Faces.Add(f); + break; + } + + case CommandTypes.Vertex: + { + byte num = F3D_VTX.GetNumberOfVertices(cmd); + byte startindex = F3D_VTX.GetStartIndexInVertexBuffer(cmd); + short datalength = F3D_VTX.GetLengthOfVertexData(cmd); + int segAddr = F3D_VTX.GetSegmentedAddress(cmd); + if (num > 0) + { + for (int i = 0, loopTo1 = num; i <= loopTo1; i++) + { + var p = new Pilz.S3DFileParser.Point(); + int curSegAddr = segAddr + i * 0x10; + var cs = GetSegBank(rommgr, curSegAddr, AreaID); + if (cs is null) + continue; + + // Vertex + if (knownVertices.ContainsKey(curSegAddr)) + { + p.Vertex = knownVertices[curSegAddr]; + } + else + { + var vert = GetVertexFromStream(cs.Data, cs.BankOffsetFromSegAddr(curSegAddr), dl.GeoPointer.ModelOffset, dl.GeoPointer.ModelScale); + p.Vertex = vert; + curMesh.Vertices.Add(vert); + knownVertices.Add(curSegAddr, vert); + } + + // UV + if (knownUVs.ContainsKey(curSegAddr)) + { + p.UV = knownUVs[curSegAddr]; + } + else + { + var uv = GetUVFromStream(cs.Data, cs.BankOffsetFromSegAddr(curSegAddr), curTexScale, curTexSize, useUVOffsetFix); + p.UV = uv; + curMesh.UVs.Add(uv); + knownUVs.Add(curSegAddr, uv); + } + + if ((curGeometryMode & (long)0x20000) == 0) + { + // Vertex Color + if (knownVertexColors.ContainsKey(curSegAddr)) + { + p.VertexColor = knownVertexColors[curSegAddr]; + } + else + { + var vc = GetVertexColorFromStream(cs.Data, cs.BankOffsetFromSegAddr(curSegAddr)); + p.VertexColor = vc; + curMesh.VertexColors.Add(vc); + knownVertexColors.Add(curSegAddr, vc); + } + } + // Normal + else if (knownNormals.ContainsKey(curSegAddr)) + { + p.Normal = knownNormals[curSegAddr]; + } + else + { + var n = GetNormalFromStream(cs.Data, cs.BankOffsetFromSegAddr(curSegAddr)); + p.Normal = n; + curMesh.Normals.Add(n); + knownNormals.Add(curSegAddr, n); + } + + pointbuffer[startindex + i] = p; + } + } + + break; + } + + case CommandTypes.SetImage: + { + int newAddr = F3D_SETIMG.GetSegmentedAddress(cmd); + if ((uint)newAddr != 0xFFFFFFFF) + { + curTexSegAddr = newAddr; + } + + break; + } + + case CommandTypes.SetTileSize: + { + curTexSize = F3D_SETTILESIZE.GetSize(cmd); + break; + } + + case CommandTypes.SetTile: + { + cmd.Position = 4; + int checkVal = cmd.ReadInt32(); + cmd.Position = 0; + if (checkVal != 0x7000000) + { + if (cmdarr[4] == 0) + { + curTexFormat = F3D_SETTILE.GetTextureFormat(cmd); } - break; + curTexWrapT = F3D_SETTILE.GetWrapT(cmd); + curTexWrapS = F3D_SETTILE.GetWrapS(cmd); } - case CommandTypes.SetOtherMode_H: + break; + } + + case CommandTypes.Texture: + { + if ((curGeometryMode & (long)0x40000) == 0x40000) { - uint bits = F3D_SETOTHERMODE_H.GetModeBits(cmd); - bool nearestNeighbor = (bits & (long)0x2000) == 0; - useUVOffsetFix = !nearestNeighbor; - break; + curTexSize = F3D_TEXTURE.GetTextureSize(cmd); + } + else + { + curTexScale = F3D_TEXTURE.GetTextureScaling(cmd); } - } - cmdIndex += 1; - } - - //if (curMesh.Faces.Any()) - obj.Meshes.Add(curMesh); - } - - /// Parse a Displaylist to an Object3D. - /// The Object3D where the model should be parsed to. - /// The Displaylist which should be parsed. - /// The RomManager Instance to use. - /// The Area ID if avaiable. - public static Task ConvertAsync(Object3D obj, DisplayList dl, RomManager rommgr, byte? AreaID) - { - var t = new Task(() => Convert(obj, dl, rommgr, AreaID)); - t.Start(); - return t; - } - - private static SegmentedBank GetSegBank(RomManager rommgr, int segAddr, byte? AreaID) - { - var seg = rommgr.GetSegBank(Converts.ToByte(segAddr >> 24), AreaID); - seg.ReadDataIfNull(rommgr.RomFile); - return seg; - } - - private static void ProcessTexture(Object3D obj, RomManager rommgr, byte? AreaID, DisplayList dl, N64Graphics.N64Codec texFormat, Dictionary knownTextures, ref Material curTexture, int curTexSegAddr, Size curTexSize, int curTexWrapT, int curTexWrapS, System.Numerics.Vector2 curTexScale, byte[] curTexPalette, int curTexPaletteSegAddr, Color? curColor, ref TextureLoadedInfos curTexLoadedInfos) - { - if (curTexSegAddr == 0 && curTexScale.X == 0 && curTexScale.Y == 0) - return; - if (knownTextures.ContainsKey(curTexSegAddr)) - { - curTexture = knownTextures[curTexSegAddr]; - } - else - { - try - { - var mat = new Material(); - mat.Wrap = new System.Numerics.Vector2(curTexWrapT, curTexWrapS); - mat.Scale = curTexScale; - mat.Color = curColor; - var seg = GetSegBank(rommgr, curTexSegAddr, AreaID); - if (seg is null) - return; - GetTextureImage(seg.Data, seg.BankOffsetFromSegAddr(curTexSegAddr), mat, texFormat, curTexSize, curTexPalette); - if (mat.Image is not null) - { - mat.Tag = new TextureLoadedInfos(Microsoft.VisualBasic.Conversion.Hex(curTexSegAddr), texFormat, curTexSegAddr, curTexPaletteSegAddr, seg.SegToRomAddr(curTexSegAddr), seg.SegToRomAddr(curTexPaletteSegAddr), mat.Image.Size); + break; } - curTexture = mat; - knownTextures.Add(curTexSegAddr, mat); - if (!obj.Materials.ContainsKey(Converts.ToString(curTexSegAddr))) + case CommandTypes.SetOtherMode_H: { - obj.Materials.Add(Converts.ToString(curTexSegAddr), mat); + uint bits = F3D_SETOTHERMODE_H.GetModeBits(cmd); + bool nearestNeighbor = (bits & (long)0x2000) == 0; + useUVOffsetFix = !nearestNeighbor; + break; } - } - catch (Exception /*ex*/) + } + + cmdIndex += 1; + } + + //if (curMesh.Faces.Any()) + obj.Meshes.Add(curMesh); + } + + /// Parse a Displaylist to an Object3D. + /// The Object3D where the model should be parsed to. + /// The Displaylist which should be parsed. + /// The RomManager Instance to use. + /// The Area ID if avaiable. + public static Task ConvertAsync(Object3D obj, DisplayList dl, RomManager rommgr, byte? AreaID) + { + var t = new Task(() => Convert(obj, dl, rommgr, AreaID)); + t.Start(); + return t; + } + + private static SegmentedBank GetSegBank(RomManager rommgr, int segAddr, byte? AreaID) + { + var seg = rommgr.GetSegBank(Converts.ToByte(segAddr >> 24), AreaID); + seg.ReadDataIfNull(rommgr.RomFile); + return seg; + } + + private static void ProcessTexture(Object3D obj, RomManager rommgr, byte? AreaID, DisplayList dl, N64Graphics.N64Codec texFormat, Dictionary knownTextures, ref Material curTexture, int curTexSegAddr, Size curTexSize, int curTexWrapT, int curTexWrapS, System.Numerics.Vector2 curTexScale, byte[] curTexPalette, int curTexPaletteSegAddr, Color? curColor, ref TextureLoadedInfos curTexLoadedInfos) + { + if (curTexSegAddr == 0 && curTexScale.X == 0 && curTexScale.Y == 0) + return; + if (knownTextures.ContainsKey(curTexSegAddr)) + { + curTexture = knownTextures[curTexSegAddr]; + } + else + { + try + { + var mat = new Material(); + mat.Wrap = new System.Numerics.Vector2(curTexWrapT, curTexWrapS); + mat.Scale = curTexScale; + mat.Color = curColor; + var seg = GetSegBank(rommgr, curTexSegAddr, AreaID); + if (seg is null) + return; + GetTextureImage(seg.Data, seg.BankOffsetFromSegAddr(curTexSegAddr), mat, texFormat, curTexSize, curTexPalette); + if (mat.Image is not null) { - //Interaction.MsgBox(ex.Message); + mat.Tag = new TextureLoadedInfos(Microsoft.VisualBasic.Conversion.Hex(curTexSegAddr), texFormat, curTexSegAddr, curTexPaletteSegAddr, seg.SegToRomAddr(curTexSegAddr), seg.SegToRomAddr(curTexPaletteSegAddr), mat.Image.Size); + } + + curTexture = mat; + knownTextures.Add(curTexSegAddr, mat); + if (!obj.Materials.ContainsKey(Converts.ToString(curTexSegAddr))) + { + obj.Materials.Add(Converts.ToString(curTexSegAddr), mat); } } - } - - private static void GetTextureImage(Stream s, int pos, Material mat, N64Graphics.N64Codec texFormat, Size curTexSize, byte[] curTexPalette) - { - //// Create Image & Graphics - //mat.Image = new Bitmap(curTexSize.Width, curTexSize.Height); - //var g = Graphics.FromImage(mat.Image); - - //// Get Texture Data - //var bytes = new byte[(N64Graphics.N64Graphics.PixelsToBytes(texFormat, curTexSize.Width * curTexSize.Height))]; - //s.Position = pos; - //s.Read(bytes, 0, bytes.Length); - //try - //{ - // // Decode Texture - // N64Graphics.N64Graphics.RenderTexture(g, bytes.ToArray(), curTexPalette, 0, curTexSize.Width, curTexSize.Height, 1, texFormat, N64Graphics.N64IMode.AlphaCopyIntensity); - //} - //catch (Exception) - //{ - //} - - // Get Texture Data - var bytes = new byte[(N64Graphics.N64Graphics.PixelsToBytes(texFormat, curTexSize.Width * curTexSize.Height))]; - s.Position = pos; - s.Read(bytes, 0, bytes.Length); - - // Convert texture palette - var palette = new List(); - if (curTexPalette != null && curTexPalette.Length >= 2) + catch (Exception /*ex*/) { - for (int i = 0; i + 1 < curTexPalette.Length; i+=2) - palette.Add((ushort)((curTexPalette[i] << 8) | curTexPalette[i + 1])); + //Interaction.MsgBox(ex.Message); } - - // Create Image & Graphics - mat.Image = N64Graphics.TextureFormats.decodeTexture(texFormat, bytes.ToArray(), curTexSize.Width, curTexSize.Height, palette.ToArray()); - } - - private static Vertex GetVertexFromStream(Stream s, int vtStart, System.Numerics.Vector3 modelOffset, System.Numerics.Vector3 modelScale) - { - var vert = new Vertex(); - var br = new BinaryStreamData(s); - s.Position = vtStart; - vert.X = br.ReadInt16() + modelOffset.X; - vert.Y = br.ReadInt16() + modelOffset.Y; - vert.Z = br.ReadInt16() + modelOffset.Z; - vert.X *= modelScale.X; - vert.Y *= modelScale.Y; - vert.Z *= modelScale.Z; - return vert; - } - - private static UV GetUVFromStream(Stream s, int vtStart, System.Numerics.Vector2 curTexScale, Size curTexSize, bool useUVOffsetFix) - { - var uv = new UV(); - var br = new BinaryStreamData(s); - s.Position = vtStart + 8; - uv.U = br.ReadInt16() * curTexScale.X; - uv.V = br.ReadInt16() * curTexScale.Y; - if (useUVOffsetFix) // Fixes UVs offset - { - uv.U += 16; - uv.V += 16; - } - - uv.U /= curTexSize.Width * 32.0F; - uv.V /= curTexSize.Height * 32.0F; - return uv; - } - - private static Normal GetNormalFromStream(Stream s, int vtStart) - { - var normal = new Normal(); - s.Position = vtStart + 12; - normal.X = s.ReadByte() / 255.0F; - normal.Y = s.ReadByte() / 255.0F; - normal.Z = s.ReadByte() / 255.0F; - // normal.A = s.ReadByte ??? - - return normal; - } - - private static VertexColor GetVertexColorFromStream(Stream s, int vtStart) - { - var normal = new VertexColor(); - s.Position = vtStart + 12; - normal.R = s.ReadByte() / 255.0F; - normal.G = s.ReadByte() / 255.0F; - normal.B = s.ReadByte() / 255.0F; - normal.A = s.ReadByte() / 255.0F; - return normal; } } + + private static void GetTextureImage(Stream s, int pos, Material mat, N64Graphics.N64Codec texFormat, Size curTexSize, byte[] curTexPalette) + { + //// Create Image & Graphics + //mat.Image = new Bitmap(curTexSize.Width, curTexSize.Height); + //var g = Graphics.FromImage(mat.Image); + + //// Get Texture Data + //var bytes = new byte[(N64Graphics.N64Graphics.PixelsToBytes(texFormat, curTexSize.Width * curTexSize.Height))]; + //s.Position = pos; + //s.Read(bytes, 0, bytes.Length); + //try + //{ + // // Decode Texture + // N64Graphics.N64Graphics.RenderTexture(g, bytes.ToArray(), curTexPalette, 0, curTexSize.Width, curTexSize.Height, 1, texFormat, N64Graphics.N64IMode.AlphaCopyIntensity); + //} + //catch (Exception) + //{ + //} + + // Get Texture Data + var bytes = new byte[(N64Graphics.N64Graphics.PixelsToBytes(texFormat, curTexSize.Width * curTexSize.Height))]; + s.Position = pos; + s.Read(bytes, 0, bytes.Length); + + // Convert texture palette + var palette = new List(); + if (curTexPalette != null && curTexPalette.Length >= 2) + { + for (int i = 0; i + 1 < curTexPalette.Length; i += 2) + palette.Add((ushort)((curTexPalette[i] << 8) | curTexPalette[i + 1])); + } + + // Create Image & Graphics + mat.Image = N64Graphics.TextureFormats.decodeTexture(texFormat, bytes.ToArray(), curTexSize.Width, curTexSize.Height, palette.ToArray()); + } + + private static Vertex GetVertexFromStream(Stream s, int vtStart, System.Numerics.Vector3 modelOffset, System.Numerics.Vector3 modelScale) + { + var vert = new Vertex(); + var br = new BinaryStreamData(s); + s.Position = vtStart; + vert.X = br.ReadInt16() + modelOffset.X; + vert.Y = br.ReadInt16() + modelOffset.Y; + vert.Z = br.ReadInt16() + modelOffset.Z; + vert.X *= modelScale.X; + vert.Y *= modelScale.Y; + vert.Z *= modelScale.Z; + return vert; + } + + private static UV GetUVFromStream(Stream s, int vtStart, System.Numerics.Vector2 curTexScale, Size curTexSize, bool useUVOffsetFix) + { + var uv = new UV(); + var br = new BinaryStreamData(s); + s.Position = vtStart + 8; + uv.U = br.ReadInt16() * curTexScale.X; + uv.V = br.ReadInt16() * curTexScale.Y; + if (useUVOffsetFix) // Fixes UVs offset + { + uv.U += 16; + uv.V += 16; + } + + uv.U /= curTexSize.Width * 32.0F; + uv.V /= curTexSize.Height * 32.0F; + return uv; + } + + private static Normal GetNormalFromStream(Stream s, int vtStart) + { + var normal = new Normal(); + s.Position = vtStart + 12; + normal.X = s.ReadByte() / 255.0F; + normal.Y = s.ReadByte() / 255.0F; + normal.Z = s.ReadByte() / 255.0F; + // normal.A = s.ReadByte ??? + + return normal; + } + + private static VertexColor GetVertexColorFromStream(Stream s, int vtStart) + { + var normal = new VertexColor(); + s.Position = vtStart + 12; + normal.R = s.ReadByte() / 255.0F; + normal.G = s.ReadByte() / 255.0F; + normal.B = s.ReadByte() / 255.0F; + normal.A = s.ReadByte() / 255.0F; + return normal; + } } \ No newline at end of file diff --git a/SM64Lib/Model/Conversion/Fast3DParsing/TextureLoadedInfos.cs b/SM64Lib/Model/Conversion/Fast3DParsing/TextureLoadedInfos.cs index 4de8e54..ec7a2b8 100644 --- a/SM64Lib/Model/Conversion/Fast3DParsing/TextureLoadedInfos.cs +++ b/SM64Lib/Model/Conversion/Fast3DParsing/TextureLoadedInfos.cs @@ -1,32 +1,31 @@ using global::System.Drawing; -namespace SM64Lib.Model.Conversion.Fast3DParsing +namespace SM64Lib.Model.Conversion.Fast3DParsing; + +public class TextureLoadedInfos { - public class TextureLoadedInfos + public string Name { get; private set; } + public N64Graphics.N64Codec TextureFormat { get; private set; } + public int TextureSegAddress { get; private set; } + public int TexturePaletteSegAddress { get; private set; } + public int TextureRomAddress { get; private set; } + public int TexturePaletteRomAddress { get; private set; } + public Size TextureSize { get; private set; } + public bool IsReadOnly { get; private set; } + + public TextureLoadedInfos(string name, N64Graphics.N64Codec textureFormat, int textureSegAddress, int texturePaletteSegAddress, int textureRomAddress, int texturePaletteRomAddress, Size textureSize) : this(name, textureFormat, textureSegAddress, texturePaletteSegAddress, textureRomAddress, texturePaletteRomAddress, textureSize, false) { - public string Name { get; private set; } - public N64Graphics.N64Codec TextureFormat { get; private set; } - public int TextureSegAddress { get; private set; } - public int TexturePaletteSegAddress { get; private set; } - public int TextureRomAddress { get; private set; } - public int TexturePaletteRomAddress { get; private set; } - public Size TextureSize { get; private set; } - public bool IsReadOnly { get; private set; } + } - public TextureLoadedInfos(string name, N64Graphics.N64Codec textureFormat, int textureSegAddress, int texturePaletteSegAddress, int textureRomAddress, int texturePaletteRomAddress, Size textureSize) : this(name, textureFormat, textureSegAddress, texturePaletteSegAddress, textureRomAddress, texturePaletteRomAddress, textureSize, false) - { - } - - public TextureLoadedInfos(string name, N64Graphics.N64Codec textureFormat, int textureSegAddress, int texturePaletteSegAddress, int textureRomAddress, int texturePaletteRomAddress, Size textureSize, bool isReadOnly) - { - Name = name; - TextureFormat = textureFormat; - TextureSegAddress = textureSegAddress; - TexturePaletteSegAddress = texturePaletteSegAddress; - TextureRomAddress = textureRomAddress; - TexturePaletteRomAddress = texturePaletteRomAddress; - TextureSize = textureSize; - IsReadOnly = isReadOnly; - } + public TextureLoadedInfos(string name, N64Graphics.N64Codec textureFormat, int textureSegAddress, int texturePaletteSegAddress, int textureRomAddress, int texturePaletteRomAddress, Size textureSize, bool isReadOnly) + { + Name = name; + TextureFormat = textureFormat; + TextureSegAddress = textureSegAddress; + TexturePaletteSegAddress = texturePaletteSegAddress; + TextureRomAddress = textureRomAddress; + TexturePaletteRomAddress = texturePaletteRomAddress; + TextureSize = textureSize; + IsReadOnly = isReadOnly; } } \ No newline at end of file diff --git a/SM64Lib/Model/Conversion/Fast3DWriting/DisplaylistProps.cs b/SM64Lib/Model/Conversion/Fast3DWriting/DisplaylistProps.cs index f0fd3d6..b0fecb3 100644 --- a/SM64Lib/Model/Conversion/Fast3DWriting/DisplaylistProps.cs +++ b/SM64Lib/Model/Conversion/Fast3DWriting/DisplaylistProps.cs @@ -1,15 +1,14 @@ using global::SM64Lib.Geolayout; -namespace SM64Lib.Model.Conversion.Fast3DWriting -{ - public class DisplaylistProps - { - public int ID { get; set; } - public DefaultGeolayers Layer { get; set; } = DefaultGeolayers.Solid; +namespace SM64Lib.Model.Conversion.Fast3DWriting; - public DisplaylistProps(int ID) - { - this.ID = ID; - } +public class DisplaylistProps +{ + public int ID { get; set; } + public DefaultGeolayers Layer { get; set; } = DefaultGeolayers.Solid; + + public DisplaylistProps(int ID) + { + this.ID = ID; } } \ No newline at end of file diff --git a/SM64Lib/Model/Conversion/Fast3DWriting/DisplaylistSelectionMode.cs b/SM64Lib/Model/Conversion/Fast3DWriting/DisplaylistSelectionMode.cs index ef19839..67ccd55 100644 --- a/SM64Lib/Model/Conversion/Fast3DWriting/DisplaylistSelectionMode.cs +++ b/SM64Lib/Model/Conversion/Fast3DWriting/DisplaylistSelectionMode.cs @@ -1,19 +1,18 @@  -namespace SM64Lib.Model.Conversion.Fast3DWriting +namespace SM64Lib.Model.Conversion.Fast3DWriting; + +public enum DisplaylistSelectionMode { - public enum DisplaylistSelectionMode - { - /// - /// Automaticly choose a default Displaylist. - /// - Automatic, - /// - /// Force Material to be on a selected default Displaylist. - /// - Default, - /// - /// Force Material to be on a custom defined Displaylist. - /// - Custom - } + /// + /// Automaticly choose a default Displaylist. + /// + Automatic, + /// + /// Force Material to be on a selected default Displaylist. + /// + Default, + /// + /// Force Material to be on a custom defined Displaylist. + /// + Custom } \ No newline at end of file diff --git a/SM64Lib/Model/Conversion/Fast3DWriting/DisplaylistSelectionSettings.cs b/SM64Lib/Model/Conversion/Fast3DWriting/DisplaylistSelectionSettings.cs index 4ea006e..392573e 100644 --- a/SM64Lib/Model/Conversion/Fast3DWriting/DisplaylistSelectionSettings.cs +++ b/SM64Lib/Model/Conversion/Fast3DWriting/DisplaylistSelectionSettings.cs @@ -1,15 +1,14 @@ using global::SM64Lib.Geolayout; -using Newtonsoft.Json.Converters; using Newtonsoft.Json; +using Newtonsoft.Json.Converters; -namespace SM64Lib.Model.Conversion.Fast3DWriting +namespace SM64Lib.Model.Conversion.Fast3DWriting; + +public class DisplaylistSelectionSettings { - public class DisplaylistSelectionSettings - { - [JsonConverter(typeof(StringEnumConverter))] - public DisplaylistSelectionMode SelectionMode { get; set; } = DisplaylistSelectionMode.Automatic; - [JsonConverter(typeof(StringEnumConverter))] - public DefaultGeolayers DefaultGeolayer { get; set; } = DefaultGeolayers.Solid; - public int CustomDisplaylistID { get; set; } = 0; - } + [JsonConverter(typeof(StringEnumConverter))] + public DisplaylistSelectionMode SelectionMode { get; set; } = DisplaylistSelectionMode.Automatic; + [JsonConverter(typeof(StringEnumConverter))] + public DefaultGeolayers DefaultGeolayer { get; set; } = DefaultGeolayers.Solid; + public int CustomDisplaylistID { get; set; } = 0; } \ No newline at end of file diff --git a/SM64Lib/Model/Conversion/Fast3DWriting/Fast3DWriter.cs b/SM64Lib/Model/Conversion/Fast3DWriting/Fast3DWriter.cs index 8d9e9b0..ee77b54 100644 --- a/SM64Lib/Model/Conversion/Fast3DWriting/Fast3DWriter.cs +++ b/SM64Lib/Model/Conversion/Fast3DWriting/Fast3DWriter.cs @@ -1,2343 +1,2342 @@ -using System; -using System.Collections.Generic; -using System.Data; +using global::SM64Lib.N64Graphics; using global::System.Drawing; using global::System.IO; -using System.Linq; using global::System.Numerics; -using System.Threading.Tasks; using Microsoft.VisualBasic.CompilerServices; -using global::SM64Lib.N64Graphics; -using Z.Collections.Extensions; +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; using System.Runtime.CompilerServices; +using System.Threading.Tasks; +using Z.Collections.Extensions; using static Microsoft.VisualBasic.Conversion; -namespace SM64Lib.Model.Conversion.Fast3DWriting +namespace SM64Lib.Model.Conversion.Fast3DWriting; + + +public enum TextureFilter { + Point = 0, + Bilerp = 2, + Average = 3 +} - public enum TextureFilter - { - Point = 0, - Bilerp = 2, - Average = 3 - } - - public enum PaletteColorStorageType - { - None = 0, - RGBA16 = 2, - IA16 = 3 - } +public enum PaletteColorStorageType +{ + None = 0, + RGBA16 = 2, + IA16 = 3 +} +/// +/// Reduces the number of duplicate verticies. +/// +public enum ReduceVericesLevel : byte +{ /// - /// Reduces the number of duplicate verticies. + /// No reduction. /// - public enum ReduceVericesLevel : byte + Level0 = 0, + /// + /// Reduce only in the same 0x04 group. (Best choise!) + /// + Level1 = 1, + /// + /// Reduce and push up. (A little buggy!) + /// + Level2 = 2 +} + +public class ConvertResult +{ + public States State { get; set; } = States.Successfully; + public uint PtrStart { get; set; } = 0; + public uint PtrVertex { get; set; } = 0; + public List PtrGeometry { get; private set; } = new List(); + public List ScrollingCommands { get; private set; } = new List(); + public Dictionary ScrollingNames { get; private set; } = new Dictionary(); + public MemoryStream Data { get; private set; } = new MemoryStream(); + + public enum States { - /// - /// No reduction. - /// - Level0 = 0, - /// - /// Reduce only in the same 0x04 group. (Best choise!) - /// - Level1 = 1, - /// - /// Reduce and push up. (A little buggy!) - /// - Level2 = 2 + Successfully, + Error } +} - public class ConvertResult +public class ConvertSettings +{ + public uint? SegmentedAddress { get; set; } + public uint SizeLimit { get; set; } = 0x150000; + public double Scale { get; set; } = 500; + public Vector3 OffsetPosition { get; set; } = Vector3.Zero; + public ReduceVericesLevel ReduceVertLevel { get; set; } = ReduceVericesLevel.Level1; + public string ColorTexData { get; set; } = ""; + public string GeoModeData { get; set; } = ""; + public string TexTypeData { get; set; } = ""; + public bool ResizeTextures { get; set; } = false; + public bool CenterModel { get; set; } = false; + public Model.Fog Fog { get; set; } = null; + public string CollisionData { get; set; } = ""; + public sbyte ForceDisplaylist { get; set; } = -1; + public float TransparencyLimit { get; set; } = 0.5f; + public Model.Fast3D.TextureFormatSettings TextureFormatSettings { get; set; } = null; + + public bool EnableFog { - public States State { get; set; } = States.Successfully; - public uint PtrStart { get; set; } = 0; - public uint PtrVertex { get; set; } = 0; - public List PtrGeometry { get; private set; } = new List(); - public List ScrollingCommands { get; private set; } = new List(); - public Dictionary ScrollingNames { get; private set; } = new Dictionary(); - public MemoryStream Data { get; private set; } = new MemoryStream(); - - public enum States + get { - Successfully, - Error + return Fog is object; } } +} - public class ConvertSettings +public class SettingsException : Exception +{ + public SettingsException() : base("Undefined ConvertSettings error.") { - public uint? SegmentedAddress { get; set; } - public uint SizeLimit { get; set; } = 0x150000; - public double Scale { get; set; } = 500; - public Vector3 OffsetPosition { get; set; } = Vector3.Zero; - public ReduceVericesLevel ReduceVertLevel { get; set; } = ReduceVericesLevel.Level1; - public string ColorTexData { get; set; } = ""; - public string GeoModeData { get; set; } = ""; - public string TexTypeData { get; set; } = ""; - public bool ResizeTextures { get; set; } = false; - public bool CenterModel { get; set; } = false; - public Model.Fog Fog { get; set; } = null; - public string CollisionData { get; set; } = ""; - public sbyte ForceDisplaylist { get; set; } = -1; - public float TransparencyLimit { get; set; } = 0.5f; - public Model.Fast3D.TextureFormatSettings TextureFormatSettings { get; set; } = null; + } - public bool EnableFog + public SettingsException(string message) : base(message) + { + } +} + +public class Fast3DWriter +{ + + private enum MaterialType + { + None, + TextureSolid, + TextureAlpha, + TextureTransparent, + ColorSolid, + ColorTransparent + } + + private class Vertex + { + public short X { get; set; } = 0; + public short Y { get; set; } = 0; + public short Z { get; set; } = 0; + } + + private class Normal + { + public byte A { get; set; } = 0; + public byte B { get; set; } = 0; + public byte C { get; set; } = 0; + public byte D { get; set; } = 0; + } + + private class VertexColor + { + public byte R { get; set; } = 0; + public byte G { get; set; } = 0; + public byte B { get; set; } = 0; + public byte A { get; set; } = 0; + } + + private class TexCord + { + public float U { get; set; } = 0; + public float V { get; set; } = 0; + } + + private class Material + { + public string Name { get; set; } = ""; + public bool HasTexture { get; set; } + public bool HasPalette { get; set; } + public bool HasTextureAlpha { get; set; } + public bool HasTransparency { get; set; } + public bool EnableTextureColor { get; set; } + public bool EnableAlphaMask { get; set; } // For I4/I8 textures. + public bool CameFromBMP { get; set; } // For I4/I8 textures. + public uint Color { get; set; } = 0; + public byte Opacity { get; set; } = 0; + public byte OpacityOrg { get; set; } = 0; + public uint Offset { get; set; } = 0; + public uint PaletteOffset { get; set; } = 0; + public uint Size { get; set; } = 0; + public uint PaletteSize { get; set; } = 0; + public uint TexWidth { get; set; } = 0; + public uint TexHeight { get; set; } = 0; + public MaterialType Type { get; set; } = MaterialType.None; + public N64Codec TexType { get; set; } = N64Codec.RGBA16; + public ushort Collision { get; set; } = 0; + public byte Collisionp1 { get; set; } = 0; + public byte Collisionp2 { get; set; } = 0; + public bool EnableGeoMode { get; set; } + public uint GeoMode { get; set; } = 0; + public TextureEntry Texture { get; set; } = null; + public bool EnableScrolling { get; set; } = false; + public DisplaylistSelectionSettings DisplaylistSelection { get; set; } = new Fast3DWriting.DisplaylistSelectionSettings(); + public FaceCullingMode FaceCullingMode { get; set; } = Conversion.FaceCullingMode.Back; + public bool EnableMirrorS { get; set; } = false; + public bool EnableMirrorT { get; set; } = false; + public bool EnableClampS { get; set; } = false; + public bool EnableClampT { get; set; } = false; + public bool EnableCrystalEffect { get; set; } = false; + public float? TransparencyLimit { get; set; } = 0; + public TextureFilter TexFilter { get; set; } = TextureFilter.Bilerp; + } + + private class FinalVertexData + { + public byte[] Data { get; set; } = new byte[16]; + public bool EnableVertexColor { get; set; } = false; + + public bool EnableVertexTransparent { get { - return Fog is object; + byte db = Data.LastOrDefault(); + return db < 0xFF; } } } - public class SettingsException : Exception + private class FvGroup { - public SettingsException() : base("Undefined ConvertSettings error.") + public short NumTri { get; set; } = 0; + + public sbyte[] indexList = new sbyte[2049]; + + public List FinalVertexData { get; private set; } = new List(); + + public short VertexDataCount { + get + { + return Convert.ToInt16(FinalVertexData.Count); + } } - public SettingsException(string message) : base(message) + public bool EnableVertexColors { + get + { + foreach (FinalVertexData fvd in FinalVertexData) + { + if (fvd.EnableVertexColor) + return true; + } + + return false; + } + } + + public bool EnableVertexAlpha + { + get + { + foreach (FinalVertexData fvd in FinalVertexData) + { + if (fvd.EnableVertexTransparent) + return true; + } + + return false; + } } } - public class Fast3DWriter + private class F3D { + public byte[] data = new byte[8]; + } - private enum MaterialType + private class VertexGroupList + { + public int Position { get; set; } = 0; + public int Length { get; set; } = 0; + public Material Material { get; set; } = null; + + public int GroupsCount { - None, - TextureSolid, - TextureAlpha, - TextureTransparent, - ColorSolid, - ColorTransparent - } - - private class Vertex - { - public short X { get; set; } = 0; - public short Y { get; set; } = 0; - public short Z { get; set; } = 0; - } - - private class Normal - { - public byte A { get; set; } = 0; - public byte B { get; set; } = 0; - public byte C { get; set; } = 0; - public byte D { get; set; } = 0; - } - - private class VertexColor - { - public byte R { get; set; } = 0; - public byte G { get; set; } = 0; - public byte B { get; set; } = 0; - public byte A { get; set; } = 0; - } - - private class TexCord - { - public float U { get; set; } = 0; - public float V { get; set; } = 0; - } - - private class Material - { - public string Name { get; set; } = ""; - public bool HasTexture { get; set; } - public bool HasPalette { get; set; } - public bool HasTextureAlpha { get; set; } - public bool HasTransparency { get; set; } - public bool EnableTextureColor { get; set; } - public bool EnableAlphaMask { get; set; } // For I4/I8 textures. - public bool CameFromBMP { get; set; } // For I4/I8 textures. - public uint Color { get; set; } = 0; - public byte Opacity { get; set; } = 0; - public byte OpacityOrg { get; set; } = 0; - public uint Offset { get; set; } = 0; - public uint PaletteOffset { get; set; } = 0; - public uint Size { get; set; } = 0; - public uint PaletteSize { get; set; } = 0; - public uint TexWidth { get; set; } = 0; - public uint TexHeight { get; set; } = 0; - public MaterialType Type { get; set; } = MaterialType.None; - public N64Codec TexType { get; set; } = N64Codec.RGBA16; - public ushort Collision { get; set; } = 0; - public byte Collisionp1 { get; set; } = 0; - public byte Collisionp2 { get; set; } = 0; - public bool EnableGeoMode { get; set; } - public uint GeoMode { get; set; } = 0; - public TextureEntry Texture { get; set; } = null; - public bool EnableScrolling { get; set; } = false; - public DisplaylistSelectionSettings DisplaylistSelection { get; set; } = new Fast3DWriting.DisplaylistSelectionSettings(); - public FaceCullingMode FaceCullingMode { get; set; } = Conversion.FaceCullingMode.Back; - public bool EnableMirrorS { get; set; } = false; - public bool EnableMirrorT { get; set; } = false; - public bool EnableClampS { get; set; } = false; - public bool EnableClampT { get; set; } = false; - public bool EnableCrystalEffect { get; set; } = false; - public float? TransparencyLimit { get; set; } = 0; - public TextureFilter TexFilter { get; set; } = TextureFilter.Bilerp; - } - - private class FinalVertexData - { - public byte[] Data { get; set; } = new byte[16]; - public bool EnableVertexColor { get; set; } = false; - - public bool EnableVertexTransparent + get { - get - { - byte db = Data.LastOrDefault(); - return db < 0xFF; - } + return FinalVertexGroups.Count; } } - private class FvGroup + public int StartIndex { get; set; } = 0; + public List FinalVertexGroups { get; private set; } = new List(); + + public bool EnableVertexColors { - public short NumTri { get; set; } = 0; - - public sbyte[] indexList = new sbyte[2049]; - - public List FinalVertexData { get; private set; } = new List(); - - public short VertexDataCount + get { - get + foreach (FvGroup fvg in FinalVertexGroups) { - return Convert.ToInt16(FinalVertexData.Count); - } - } - - public bool EnableVertexColors - { - get - { - foreach (FinalVertexData fvd in FinalVertexData) + foreach (FinalVertexData fvd in fvg.FinalVertexData) { if (fvd.EnableVertexColor) return true; } - - return false; } - } - public bool EnableVertexAlpha - { - get - { - foreach (FinalVertexData fvd in FinalVertexData) - { - if (fvd.EnableVertexTransparent) - return true; - } - - return false; - } + return false; } } - private class F3D - { - public byte[] data = new byte[8]; - } - - private class VertexGroupList - { - public int Position { get; set; } = 0; - public int Length { get; set; } = 0; - public Material Material { get; set; } = null; - - public int GroupsCount - { - get - { - return FinalVertexGroups.Count; - } - } - - public int StartIndex { get; set; } = 0; - public List FinalVertexGroups { get; private set; } = new List(); - - public bool EnableVertexColors - { - get - { - foreach (FvGroup fvg in FinalVertexGroups) - { - foreach (FinalVertexData fvd in fvg.FinalVertexData) - { - if (fvd.EnableVertexColor) - return true; - } - } - - return false; - } - } - - public bool EnableVertexAlpha - { - get - { - if (!EnableVertexColors) - return false; - foreach (FvGroup fvg in FinalVertexGroups) - { - foreach (FinalVertexData fvd in fvg.FinalVertexData) - { - if (fvd.EnableVertexColor) - { - if (fvd.Data.LastOrDefault() < 0xFF) - return true; - } - } - } - - return false; - } - } - } - - private class TextureEntry - { - public uint Width { get; set; } = 0; - public uint Height { get; set; } = 0; - public byte[] Data { get; set; } = Array.Empty(); - public byte[] Palette { get; set; } = Array.Empty(); - public Image OriginalImage { get; set; } = null; - } - - private class ObjPtrs - { - public string name = Convert.ToString(0); - public uint start_ptr = 0; - public uint import_lenght = 0; - public uint solid_ptr = 0; - public uint alpha_ptr = 0; - public uint trans_ptr = 0; - public uint geo_ptr = 0; - public uint col_ptr = 0; - public uint vertex_start = 0; - } - - public struct ScrollTex - { - public int Offset { get; set; } - public int VertsCount { get; set; } - public int MaterialAddress { get; set; } - public string MaterialName { get; set; } - - public ScrollTex(int offset, byte faceCount, int matAddr, string matName) - { - Offset = offset; - VertsCount = faceCount; - MaterialAddress = matAddr; - MaterialName = matName; - } - } - - private List verts = new List(); - private List norms = new List(); - private List vertexColors = new List(); - private List uvs = new List(); - private List materials = new List(); - private List ignoreFacesWithMaterial = new List(); - private Dictionary materialBindings = new Dictionary(); - private List vertexGroups = new List(); - private List finalVertData = new List(); - private List textureBank = new List(); - private List scrollTexts = new List(); - private Material currentMaterial; - private int currentFace = 0; - private const byte GEOLAYER_SOLID = 1; - private const byte GEOLAYER_ALPHA = 4; - private const byte GEOLAYER_TRANSPARENT = 5; - private byte curSeg = 0; - private uint startSegOffset = 0; - private byte[] defaultColor = new byte[24]; - private ConvertSettings settings = null; - private SM64Lib.Data.BinaryData impdata = null; - private ConvertResult conRes = new ConvertResult(); - private readonly byte[] ColtypesWithParams = new byte[] { 14, 44, 36, 37, 39, 45 }; - - private uint CurSegAddress + public bool EnableVertexAlpha { get { - return Convert.ToUInt32(curSeg) << 24; - } - } - - private object TXL2WORDS(object txls, object b_txl) - { - return NewLateBinding.LateGet(null, typeof(Math), "Max", new object[] - { - 1, - Operators.DivideObject(Operators.MultiplyObject(txls, b_txl), 8) - }, null, null, null); - } - - private object CALC_DXT(object width, object b_txl) - { - return Operators.DivideObject(2048, this.TXL2WORDS(RuntimeHelpers.GetObjectValue(width), RuntimeHelpers.GetObjectValue(b_txl))); - } - - private object TXL2WORDS_4b(object txls) - { - return NewLateBinding.LateGet(null, typeof(Math), "Max", new object[] - { - 1, - Operators.DivideObject(txls, 16) - }, null, null, null); - } - - private object CALC_DXT_4b(object width) - { - return Operators.DivideObject(2048, this.TXL2WORDS_4b(RuntimeHelpers.GetObjectValue(width))); - } - - private void SetLightAndDarkValues(Pilz.S3DFileParser.Shading s) - { - // Ambient light color - defaultColor[0] = s.AmbientColor.R; - defaultColor[1] = s.AmbientColor.G; - defaultColor[2] = s.AmbientColor.B; - defaultColor[3] = 0; - defaultColor[4] = s.AmbientColor.R; - defaultColor[5] = s.AmbientColor.G; - defaultColor[6] = s.AmbientColor.B; - defaultColor[7] = 0; - - // Diffuse light color - defaultColor[8] = s.DiffuseColor.R; - defaultColor[9] = s.DiffuseColor.G; - defaultColor[10] = s.DiffuseColor.B; - defaultColor[11] = 0; - defaultColor[12] = s.DiffuseColor.R; - defaultColor[13] = s.DiffuseColor.G; - defaultColor[14] = s.DiffuseColor.B; - defaultColor[15] = 0; - - // Diffuse light direction - if (s.DiffusePosition is not null) - { - float d = (float)(127 / Math.Sqrt(s.DiffusePosition.X * s.DiffusePosition.X + s.DiffusePosition.Y * s.DiffusePosition.Y + s.DiffusePosition.Z * s.DiffusePosition.Z)); - - if (float.IsInfinity(d)) - d = 0; - defaultColor[16] = (byte)Convert.ToSByte(Math.Round(s.DiffusePosition.X * d)); - defaultColor[17] = (byte)Convert.ToSByte(Math.Round(s.DiffusePosition.Y * d)); - defaultColor[18] = (byte)Convert.ToSByte(Math.Round(s.DiffusePosition.Z * d)); - } - else - { - defaultColor[16] = 0x49; // = Most SM64E Like ||| Default by Nintendo: &H28 - defaultColor[17] = 0x49; - defaultColor[18] = 0x49; - } - - defaultColor[19] = 0; - defaultColor[20] = 0; - defaultColor[21] = 0; - defaultColor[22] = 0; - defaultColor[23] = 0; - } - - private void ResetVariables() - { - vertexGroups.Clear(); - verts.Clear(); - norms.Clear(); - vertexColors.Clear(); - uvs.Clear(); - materials.Clear(); - finalVertData.Clear(); - currentFace = 0; - } - - private void CheckGeoModeInfo(Material m) - { - m.GeoMode = 0; - var gma = settings.GeoModeData.Split(','); - foreach (string gme in gma) - { - var gmd = gme.Split(':'); - if (m.Name.Equals(gmd[0])) + if (!EnableVertexColors) + return false; + foreach (FvGroup fvg in FinalVertexGroups) { - m.GeoMode = Convert.ToUInt32(gmd[1]); - m.EnableGeoMode = true; - return; - } - } - } - - private void CheckColorTexInfo(Material m) - { - m.Color = 0; - var gma = settings.ColorTexData.Split(','); - foreach (string gme in gma) - { - var gmd = gme.Split(':'); - if (m.Name.Equals(gmd[0])) - { - m.Color = Convert.ToUInt32(gmd[1]); - m.EnableTextureColor = true; - return; - } - } - } - - private void processMaterialColor(string str, Material mat) - { - var splitColor = str.Replace(".", ",").Split(' '); - uint r = (uint)(Convert.ToSingle(splitColor[0]) * 255); - uint g = (uint)(Convert.ToSingle(splitColor[1]) * 255); - uint b = (uint)(Convert.ToSingle(splitColor[2]) * 255); - mat.Color = Convert.ToUInt32(r << 24 | g << 16 | b << 8 | (long)0xFF); - } - - private void processMaterialColorAlpha(float alpha, Material mat) - { - mat.Color = mat.Color & 0xFFFFFF00U; - mat.Color = mat.Color | Convert.ToByte(Convert.ToInt64(0xFF * alpha) & 0xFF); - if (alpha < 1.0F) - { - mat.Type = MaterialType.ColorTransparent; - mat.HasTransparency = true; - } - else if (!mat.HasTexture) - { - mat.Type = MaterialType.ColorSolid; - } - } - - private void checkN64CodecInfo(Material m) - { - var gma = settings.TexTypeData.Split(','); - foreach (string gme in gma) - { - var gmd = gme.Split(':'); - if (m.Name.Equals(gmd[0])) - { - var switchExpr = gmd[1]; - switch (switchExpr) + foreach (FinalVertexData fvd in fvg.FinalVertexData) { - case "rgba16": - { - m.TexType = N64Codec.RGBA16; - break; - } - - case "rgba32": - { - m.TexType = N64Codec.RGBA32; - break; - } - - case "ia4": - { - m.TexType = N64Codec.IA4; - break; - } - - case "ia8": - { - m.TexType = N64Codec.IA8; - break; - } - - case "ia16": - { - m.TexType = N64Codec.IA16; - break; - } - - case "i4": - { - m.TexType = N64Codec.I4; - if (gmd.Count() > 2 && (gmd[2] ?? "") == "a") - m.EnableAlphaMask = true; - break; - } - - case "i8": - { - m.TexType = N64Codec.I8; - if (gmd.Count() > 2 && (gmd[2] ?? "") == "a") - m.EnableAlphaMask = true; - break; - } - } - - return; - } - } - - m.TexType = N64Codec.RGBA16; - } - - private Material[] GetDuplicates(Material mat) - { - var foundCopies = new List(); - if (mat.HasTexture) - { - foreach (Material checkMat in materials) - { - if (checkMat != mat) - { - if (checkMat.HasTexture) + if (fvd.EnableVertexColor) { - if (mat.TexType == checkMat.TexType && SM64Lib.General.CompareTwoByteArrays(mat.Texture.Data, checkMat.Texture.Data)) - { - if (!foundCopies.Contains(checkMat)) - { - foundCopies.Add(checkMat); - } - } - } - } - } - } - - // For Each copyMat As Material In foundCopies - // copyMat.texture = mat.texture - // copyMat.offset = mat.offset - // copyMat.texWidth = mat.texWidth - // copyMat.texHeight = mat.texHeight - // copyMat.size = 0 - // copyMat.isTextureCopy = True - // Next - - return foundCopies.ToArray(); - } - - private void MergeDuplicatedTextures() - { - var matsToRemove = new List(); - - foreach (Material mat in materials) - { - if (!matsToRemove.Contains(mat)) - { - foreach (Material dup in GetDuplicates(mat)) - { - if (!matsToRemove.Contains(dup)) - { - // Remove material - matsToRemove.Add(dup); - - // Update material references for vertex group - foreach (VertexGroupList mp in vertexGroups) - { - if (mp.Material == dup) - mp.Material = mat; - } - - // Update material references for material bindings - foreach (var kvp in materialBindings) - { - if (kvp.Value == dup) - materialBindings[kvp.Key] = mat; - } - } - } - } - } - - foreach (Material mat in matsToRemove) - { - if (mat.HasTexture && textureBank.Contains(mat.Texture)) - textureBank.Remove(mat.Texture); - materials.Remove(mat); - } - } - - private void ProcessImage(Pilz.S3DFileParser.Object3D obj, Image img, Material mat) - { - TextureEntry entry = null; - foreach (TextureEntry tex in textureBank) - { - if (tex.OriginalImage == img) - { - entry = tex; - } - } - - // Create & Add texture entry - if (entry is null) - { - entry = new TextureEntry() - { - Width = mat.TexWidth, - Height = mat.TexHeight, - OriginalImage = img - }; - } - - // Load Texture from File - var bmp = new Bitmap(img); - - // Set texture size - mat.TexWidth = Convert.ToUInt32(bmp.Width); - mat.TexHeight = Convert.ToUInt32(bmp.Height); - - // Convert texture - var argimageData = entry.Data; - var argpaletteData = entry.Palette; - N64Graphics.N64Graphics.Convert(ref argimageData, ref argpaletteData, mat.TexType, (Bitmap)img); - entry.Data = argimageData; - entry.Palette = argpaletteData; - - mat.Type = MaterialType.TextureSolid; - - // Check for alpha and transparency - { - var transparentPixels = 0; - var setAsAlpha = false; - var setAsTransparent = false; - - // Check textures - for (int y = 0, loopTo = bmp.Height - 1; y <= loopTo; y++) - { - for (int x = 0, loopTo1 = bmp.Width - 1; x <= loopTo1; x++) - { - var pix = bmp.GetPixel(x, y); - switch (mat.TexType) - { - case N64Codec.RGBA16: - case N64Codec.RGBA32: - case N64Codec.IA4: - case N64Codec.IA8: - case N64Codec.IA16: - case N64Codec.CI4: - case N64Codec.CI8: - if (pix.A == 0) - setAsAlpha = true; - else if (pix.A < 0xFF) - transparentPixels++; - break; - case N64Codec.I4: - case N64Codec.I8: - if (pix.A < 0xFF || mat.EnableAlphaMask) - transparentPixels++; - break; + if (fvd.Data.LastOrDefault() < 0xFF) + return true; } } } - // Set as transparent if reached the limit - var transparentPixelsPercent = (float)transparentPixels / (mat.TexWidth * mat.TexHeight); - var reachedTransparentLimit = transparentPixelsPercent > (mat.TransparencyLimit ?? settings.TransparencyLimit); - switch (mat.TexType) - { - case N64Codec.RGBA16: - case N64Codec.RGBA32: - case N64Codec.IA4: - case N64Codec.IA8: - case N64Codec.IA16: - case N64Codec.CI4: - case N64Codec.CI8: - if (reachedTransparentLimit) - setAsTransparent = true; - break; - case N64Codec.I4: - case N64Codec.I8: - if (reachedTransparentLimit || mat.EnableAlphaMask) - setAsTransparent = true; - break; - } - if (setAsTransparent) - { - mat.Type = MaterialType.TextureTransparent; - mat.HasTransparency = true; - } - else if (setAsAlpha) - { - mat.HasTextureAlpha = true; - mat.Type = MaterialType.TextureAlpha; - } - } - - if (!textureBank.Contains(entry)) - textureBank.Add(entry); - mat.Texture = entry; - mat.HasTexture = true; - mat.HasPalette = entry.Palette.Any(); - } - - private void ProcessObject3DModel(Pilz.S3DFileParser.Object3D obj) - { - var texFormatSettings = settings.TextureFormatSettings; - - // Process Materials - ProcessObject3DMaterials(obj, texFormatSettings); - foreach (Pilz.S3DFileParser.Mesh mesh in obj.Meshes) - { - int curIndexStart = verts.Count; - - // Process Vertices - foreach (var vert in mesh.Vertices) - { - var v = new Vertex() - { - X = General.KeepInInt16Range(General.Round(vert.X * settings.Scale + settings.OffsetPosition.X)), - Y = General.KeepInInt16Range(General.Round(vert.Y * settings.Scale + settings.OffsetPosition.Y)), - Z = General.KeepInInt16Range(General.Round(vert.Z * settings.Scale + settings.OffsetPosition.Z)) - }; - verts.Add(v); - } - - // Process Normals - foreach (var norm in mesh.Normals) - { - var n = new Normal() - { - A = Datatypecastes.LongToByte((long)General.Round(norm.X * 0x7F)), - B = Datatypecastes.LongToByte((long)General.Round(norm.Y * 0x7F)), - C = Datatypecastes.LongToByte((long)General.Round(norm.Z * 0x7F)), - D = 0xFF - }; - norms.Add(n); - } - - // Process UVs - foreach (Pilz.S3DFileParser.UV tuv in mesh.UVs) - { - var uv = new TexCord() - { - U = (float)General.Round(tuv.U * 32F * 32F), - V = (float)General.Round(-((tuv.V - 1) * 32F * 32F)) - }; - uvs.Add(uv); - } - - // Process Vertex Colors - foreach (var vertcol in mesh.VertexColors) - { - var vc = new VertexColor() - { - R = Datatypecastes.LongToByte((long)General.Round(vertcol.R * 0xFF)), - G = Datatypecastes.LongToByte((long)General.Round(vertcol.G * 0xFF)), - B = Datatypecastes.LongToByte((long)General.Round(vertcol.B * 0xFF)), - A = Datatypecastes.LongToByte((long)General.Round(vertcol.A * 0xFF)) - }; - vertexColors.Add(vc); - } - - // Process Faces - object curTexture = null; - foreach (var face in mesh.Faces) // .OrderBy(Function(n) n.Texture) - { - if (!ignoreFacesWithMaterial.Contains(face.Material)) - { - if (curTexture is null || !curTexture.Equals(face.Material)) - { - curTexture = face.Material; - string curMatName = obj.Materials.FirstOrDefault(n => n.Value.Equals(face.Material)).Key; - var curMat = materials.FirstOrDefault(n => n.Name.Equals(curMatName)); - var mp = new VertexGroupList() - { - Position = currentFace, - Material = curMat - }; - currentMaterial = curMat; - mp.Length = 0; - vertexGroups.Add(mp); - } - - materialBindings.TryGetValue(face.Material, out Material mat); - - Vertex va = null; - TexCord ta = null; - var tanew = new TexCord(); - Normal na = null; - VertexColor vca = null; - Vertex vb = null; - TexCord tb = null; - var tbnew = new TexCord(); - Normal nb = null; - VertexColor vcb = null; - Vertex vc = null; - TexCord tc = null; - var tcnew = new TexCord(); - Normal nc = null; - VertexColor vcc = null; - void getVals(Pilz.S3DFileParser.Point point, ref Vertex vert, ref TexCord t, ref Normal normal, ref VertexColor vertcol) - { - if (point.Vertex is not null) - vert = verts[curIndexStart + mesh.Vertices.IndexOf(point.Vertex)]; - if (point.UV is not null) - t = uvs[curIndexStart + mesh.UVs.IndexOf(point.UV)]; - if (point.Normal is not null) - normal = norms[curIndexStart + mesh.Normals.IndexOf(point.Normal)]; - if (point.VertexColor is not null) - vertcol = vertexColors[curIndexStart + mesh.VertexColors.IndexOf(point.VertexColor)]; - }; - getVals(face.Points[0], ref va, ref ta, ref na, ref vca); - getVals(face.Points[1], ref vb, ref tb, ref nb, ref vcb); - getVals(face.Points[2], ref vc, ref tc, ref nc, ref vcc); - var fa = new FinalVertexData(); - var fb = new FinalVertexData(); - var fc = new FinalVertexData(); - - // Modify UV cordinates based on material. - void modifyUVCordinates(TexCord tnew, TexCord t) - { - tnew.U = (float)(t.U * (mat.TexWidth / 32.0) - 16); // "-16" fixes the UVs offset - tnew.V = (float)(t.V * (mat.TexHeight / 32.0) - 16); // "-16" fixes the UVs offset - }; - modifyUVCordinates(tanew, ta); - modifyUVCordinates(tbnew, tb); - modifyUVCordinates(tcnew, tc); - - // Fix UVs to reduce number of (large) faces with broken textures - FixUVs(tanew, tbnew, tcnew, Convert.ToInt32(mat.TexWidth), Convert.ToInt32(mat.TexHeight)); - - // Vertex Structure: xxxxyyyyzzzz0000uuuuvvvvrrggbbaa - void buildVertexStructure(FinalVertexData final, Vertex vert, VertexColor vertcol, TexCord tnew, Normal normal) - { - final.Data[0] = Convert.ToByte(vert.X >> 8 & 0xFF); - final.Data[1] = Convert.ToByte(vert.X & 0xFF); - final.Data[2] = Convert.ToByte(vert.Y >> 8 & 0xFF); - final.Data[3] = Convert.ToByte(vert.Y & 0xFF); - final.Data[4] = Convert.ToByte(vert.Z >> 8 & 0xFF); - final.Data[5] = Convert.ToByte(vert.Z & 0xFF); - final.Data[6] = 0; - final.Data[7] = 0; - int uInt, vInt; - uInt = Convert.ToInt32(Math.Round(tnew.U)); - vInt = Convert.ToInt32(Math.Round(tnew.V)); - final.Data[8] = Convert.ToByte(uInt >> 8 & 0xFF); - final.Data[9] = Convert.ToByte(uInt & 0xFF); - final.Data[10] = Convert.ToByte(vInt >> 8 & 0xFF); - final.Data[11] = Convert.ToByte(vInt & 0xFF); - if (vertcol is not null && !mat.EnableCrystalEffect) - { - final.Data[12] = vertcol.R; - final.Data[13] = vertcol.G; - final.Data[14] = vertcol.B; - final.Data[15] = vertcol.A; - final.EnableVertexColor = true; - // FIXME: Add warning if Type is not TextureSolid - if (final.EnableVertexTransparent) - { - mat.Type = MaterialType.TextureTransparent; - mat.HasTransparency = mat.HasTransparency || final.EnableVertexTransparent; - } - } - else - { - final.Data[12] = normal.A; - final.Data[13] = normal.B; - final.Data[14] = normal.C; - final.Data[15] = normal.D; - final.EnableVertexColor = false; - } - }; - buildVertexStructure(fa, va, vca, tanew, na); - buildVertexStructure(fb, vb, vcb, tbnew, nb); - buildVertexStructure(fc, vc, vcc, tcnew, nc); - finalVertData.AddRange(new[] { fa, fb, fc }); - currentFace += 1; - } - } - } - } - - private void ProcessObject3DMaterials(Pilz.S3DFileParser.Object3D obj, Model.Fast3D.TextureFormatSettings texFormatSettings) - { - var tasks = new List(); - - // Start converting each image - foreach (var kvp in obj.Materials) - { - ProcessObject3DMaterial(obj, kvp, texFormatSettings); - } - } - - private void ProcessObject3DMaterial(Pilz.S3DFileParser.Object3D obj, KeyValuePair kvp, Model.Fast3D.TextureFormatSettings texFormatSettings) - { - int size = 0; - var curEntry = texFormatSettings.GetEntry(kvp.Key); - - if (curEntry.Include) - { - // Create new Material - var m = new Material() - { - Type = MaterialType.ColorSolid, - Color = 0, - HasTexture = false, - HasTextureAlpha = false, - HasTransparency = false, - Name = kvp.Key, - Collision = 0, - Opacity = 0xFF, - OpacityOrg = 0xFF, - EnableGeoMode = false, - EnableTextureColor = false, - EnableAlphaMask = false, - CameFromBMP = false, - EnableScrolling = curEntry.IsScrollingTexture, - DisplaylistSelection = curEntry.DisplaylistSelection, - EnableMirrorS = curEntry.EnableMirrorS, - EnableMirrorT = curEntry.EnableMirrorT, - EnableClampS = curEntry.EnableClampS, - EnableClampT = curEntry.EnableClampT, - EnableCrystalEffect = curEntry.EnableCrystalEffect, - FaceCullingMode = curEntry.FaceCullingMode, - TransparencyLimit = curEntry.TransparencyLimit, - TexFilter = curEntry.TextureFilter - }; - - // Set default size - size = 0x10; - - // Check some things - CheckGeoModeInfo(m); - CheckColorTexInfo(m); - - // Add material - materials.Add(m); - materialBindings.Add(kvp.Value, m); - - // Process Material Color - if (!m.EnableTextureColor) - { - uint r = kvp.Value.Color.Value.R; - uint g = kvp.Value.Color.Value.G; - uint b = kvp.Value.Color.Value.B; - uint a = kvp.Value.Color.Value.A; - m.Color = r << 24 | g << 16 | b << 8 | a; - if (a == (long)0xFF) - { - m.Type = MaterialType.ColorSolid; - } - else - { - m.Type = MaterialType.ColorTransparent; - } - } - - // Check Texture Type - if (texFormatSettings is not null) - { - m.TexType = N64Graphics.N64Graphics.StringCodec(texFormatSettings.GetEntry(kvp.Key).TextureFormat); - } - - // Process Material Image - if (kvp.Value.Image is not null) - { - ProcessImage(obj, kvp.Value.Image, m); - size = m.Texture.Data.Length; - } - - // Process Material Color Alpha - if (kvp.Value.Opacity is not null) - { - float tempopacity = (float)kvp.Value.Opacity; - m.Opacity = Convert.ToByte(Convert.ToInt64(tempopacity * 0xFF) & 0xFF); - m.OpacityOrg = m.Opacity; - processMaterialColorAlpha(tempopacity, m); - } - - // Set offset and size - m.Size = Convert.ToUInt32(size); - if (m.Texture?.Palette is not null) - { - m.PaletteSize = Convert.ToUInt32(m.Texture.Palette.Length); - } - } - else - ignoreFacesWithMaterial.Add(kvp.Value); - } - - private void FixUVs(TexCord uv1, TexCord uv2, TexCord uv3, int matWidth, int matHeight) - { - if (matWidth <= 0 || matHeight <= 0) return; - - TexCord[] uvs = null; - int jump = 0; - - float RoundToJump(float val) - { - var mod = val % jump; - - if (mod >= 0.5 * jump) - val = jump * (float)Math.Ceiling(val / jump); // Round up - else - val = jump * (float)Math.Floor(val / jump); // Round down - - return val; - } - - jump = matWidth * 0x40; - uvs = new[] { uv1, uv2, uv3 }.OrderBy(n => n.U).ToArray(); - if (jump != 0) - { - // Move near 0 - float varM; - varM = RoundToJump((uvs[0].U + uvs[2].U) / 2); - uvs[0].U -= varM; - uvs[1].U -= varM; - uvs[2].U -= varM; - - // Keep in bounds (max bounds) - while (uvs.Last().U > short.MaxValue) - { - uvs[0].U -= jump; - uvs[1].U -= jump; - uvs[2].U -= jump; - } - - // Keep in bounds (min bounds) - while (uvs.First().U < short.MinValue) - { - uvs[0].U += jump; - uvs[1].U += jump; - uvs[2].U += jump; - } - } - - jump = matHeight * 0x40; - uvs = new[] { uv1, uv2, uv3 }.OrderBy(n => n.V).ToArray(); - if (jump != 0) - { - // Move near 0 - float varM; - varM = RoundToJump((uvs[0].V + uvs[2].V) / 2); - uvs[0].V -= varM; - uvs[1].V -= varM; - uvs[2].V -= varM; - - // Keep in bounds (max bounds) - while (uvs.Last().V > short.MaxValue) - { - uvs[0].V -= jump; - uvs[1].V -= jump; - uvs[2].V -= jump; - } - - // Keep in bounds (min bounds) - while (uvs.First().V < short.MinValue) - { - uvs[0].V += jump; - uvs[1].V += jump; - uvs[2].V += jump; - } - } - } - - private void removeDuplicateVertices(ReduceVericesLevel level) - { - if ((int)level < 1) - return; - int dupCnt = 0; - foreach (VertexGroupList mp in vertexGroups) - { - for (int g = 0; g < mp.GroupsCount; g++) - { - var fvg = mp.FinalVertexGroups[g]; - if (fvg.VertexDataCount < 1) continue; - - for (int i = 0; i < fvg.VertexDataCount; i++) - { - int j = i + 1; - while (j < fvg.VertexDataCount) - { - if (SM64Lib.General.CompareTwoByteArrays(fvg.FinalVertexData[i].Data, fvg.FinalVertexData[j].Data, 16)) - { - moveElementsInGroupUpward(fvg, 1, j); - UpdateIndexList(fvg, Convert.ToByte(j), Convert.ToByte(i)); - UpdatePositions(mp.StartIndex); - dupCnt += 1; - } - - j += 1; - } - } - - if (g < mp.GroupsCount - 1 && (int)level > 1) - { - if (MoveVertsBack(mp.FinalVertexGroups[g], mp.FinalVertexGroups[g + 1])) - { - g -= 1; - } - } - } - } - } - - private void UpdateIndexList(FvGroup grp, byte removed, byte replaceWith) - { - for (int i = 0; i < grp.NumTri * 3; i++) - { - if (grp.indexList[i] < removed) continue; - - if (grp.indexList[i] == removed) - { - grp.indexList[i] = Convert.ToSByte(replaceWith); - } - else - { - grp.indexList[i] -= 1; - } - } - } - - private void UpdatePositions(int vs) - { - foreach (VertexGroupList mp in vertexGroups) - { - if (mp.StartIndex <= vs) - continue; - if (mp.StartIndex < 0x10) - continue; - mp.StartIndex -= 0x10; - } - } - - private bool MoveVertsBack(FvGroup to, FvGroup from) - { - if (from.VertexDataCount < 3) return false; - if (to.VertexDataCount < 14) - { - to.FinalVertexData.Add(from.FinalVertexData[0]); - to.FinalVertexData.Add(from.FinalVertexData[1]); - to.FinalVertexData.Add(from.FinalVertexData[2]); - to.indexList[to.NumTri * 3] = Convert.ToSByte(to.VertexDataCount); - to.indexList[to.NumTri * 3 + 1] = Convert.ToSByte(to.VertexDataCount + 1); - to.indexList[to.NumTri * 3 + 2] = Convert.ToSByte(to.VertexDataCount + 2); - moveElementsInGroupUpward(from, 3, 0); - to.NumTri += 1; - return true; } - - return false; - } - - private void moveElementsInGroupUpward(FvGroup grp, int amount, int start) - { - for (int i = 0; i < amount; i++) - grp.FinalVertexData.RemoveAt(start); - } - - private void BuildVertexGroups() - { - int vs = 0; - for (int i = 0; i < vertexGroups.Count; i++) - { - { - var withBlock = vertexGroups[i]; - withBlock.StartIndex = vs; - int length = 0; - if (i < vertexGroups.Count - 1) - { - length = vertexGroups[i + 1].Position - withBlock.Position; - } - else - { - length = currentFace - withBlock.Position; - } - - int groupsCount = 0; - if (length % 5 == 0) - { - groupsCount = (int)(length / (double)5); - } - else - { - groupsCount = (int)(Math.Truncate(length / (double)5) + 1); - } - - for (int j = 0; j < groupsCount; j++) - withBlock.FinalVertexGroups.Add(new FvGroup() { NumTri = 0 }); - - for (int g = 0; g < groupsCount; g++) - { - int s = 5; - if (g == groupsCount - 1) - s = length % 5; - if (s == 0) - s = 5; - var curFvg = withBlock.FinalVertexGroups[g]; - curFvg.NumTri = Convert.ToInt16(s); - for (int j = 0; j < s; j++) - { - int from = (withBlock.Position + j + g * 5) * 3; - curFvg.FinalVertexData.Add(finalVertData[from]); - curFvg.FinalVertexData.Add(finalVertData[from + 1]); - curFvg.FinalVertexData.Add(finalVertData[from + 2]); - curFvg.indexList[j * 3] = Convert.ToSByte(j * 3); - curFvg.indexList[j * 3 + 1] = Convert.ToSByte(j * 3 + 1); - curFvg.indexList[j * 3 + 2] = Convert.ToSByte(j * 3 + 2); - } - - vs += curFvg.VertexDataCount * 0x10; - } - } - } - } - - private F3D StrToF3D(string str) - { - var cmd = new F3D(); - var b = str.Replace(".", ",").Split(' '); - for (int i = 0; i < b.Length; i++) - cmd.data[i] = Convert.ToByte($"&H{b[i]}"); - return cmd; - } - - private void ImpF3D(string str) - { - ImpF3D(StrToF3D(str)); - } - - private void ImpF3D(params byte[] data) - { - impdata.Write(data); - } - - private void ImpF3D(F3D f3d) - { - impdata.Write(f3d.data); - } - - private void ImpFogStart(int layer) - { - ImpF3D("BA 00 14 02 00 10 00 00"); - string cmdF8 = ""; - cmdF8 = $"F8 00 00 00 {Hex(settings.Fog.Color.R)} {Hex(settings.Fog.Color.G)} {Hex(settings.Fog.Color.B)} FF"; - ImpF3D(cmdF8); - switch (layer) - { - case 0: - { - ImpF3D("B9 00 03 1D C8 11 22 30"); - break; - } - - case 1: - { - ImpF3D("B9 00 03 1D C8 11 20 78"); - break; - } - - case 2: - { - ImpF3D("B9 00 03 1D C8 11 2D 58"); - break; - } - - case 3: - { - ImpF3D("B9 00 03 1D C8 10 4D D8"); - break; - } - // ImpF3D("B9 00 03 1D 00 11 24 78") - case 4: - { - ImpF3D("B9 00 03 1D C8 11 30 78"); - break; - } - - case 5: - { - ImpF3D("B9 00 03 1D C8 10 49 D8"); - break; - } - - case 6: - { - ImpF3D("B9 00 03 1D C8 10 4D D8"); - break; - } - - case 7: - { - ImpF3D("B9 00 03 1D C8 10 45 D8"); - break; - } - } - - var switchExpr = settings.Fog.Type; - switch (switchExpr) - { - case global::SM64Lib.Model.FogPreset.SubtleFog1: - { - ImpF3D("BC 00 00 08 19 00 E8 00"); - break; - } - - case global::SM64Lib.Model.FogPreset.SubtleFog2: - { - ImpF3D("BC 00 00 08 12 00 F0 00"); - break; - } - - case global::SM64Lib.Model.FogPreset.ModerateFog1: - { - ImpF3D("BC 00 00 08 0E 49 F2 B7"); - break; - } - - case global::SM64Lib.Model.FogPreset.ModerateFog2: - { - ImpF3D("BC 00 00 08 0C 80 F4 80"); - break; - } - - case global::SM64Lib.Model.FogPreset.ModerateFog3: - { - ImpF3D("BC 00 00 08 0A 00 F7 00"); - break; - } - - case global::SM64Lib.Model.FogPreset.ModerateFog4: - { - ImpF3D("BC 00 00 08 08 55 F8 AB"); - break; - } - - case global::SM64Lib.Model.FogPreset.IntenseFog: - { - ImpF3D("BC 00 00 08 07 24 F9 DC"); - break; - } - - case global::SM64Lib.Model.FogPreset.VeryIntenseFog: - { - ImpF3D("BC 00 00 08 05 00 FC 00"); - break; - } - - case global::SM64Lib.Model.FogPreset.HardcoreFog: - { - ImpF3D("BC 00 00 08 02 50 FF 00"); - break; - } - } - - ImpF3D("B7 00 00 00 00 01 00 00"); - } - - private void ImpFogEnd(int layer) - { - ImpF3D("BA 00 14 02 00 00 00 00"); - switch (layer) - { - case 0: - { - ImpF3D("B9 00 03 1D 00 44 22 30"); - break; - } - - case 1: - { - ImpF3D("B9 00 03 1D 00 44 20 78"); - break; - } - - case 2: - { - ImpF3D("B9 00 03 1D 00 44 2D 58"); - break; - } - - case 3: - { - ImpF3D("B9 00 03 1D 00 40 4D D8"); - break; - } - // ImpF3D("B9 00 03 1D 00 44 24 78") - case 4: - { - ImpF3D("B9 00 03 1D 00 44 30 78"); - break; - } - - case 5: - { - ImpF3D("B9 00 03 1D 00 40 49 D8"); - break; - } - - case 6: - { - ImpF3D("B9 00 03 1D 00 40 4D D8"); - break; - } - - case 7: - { - ImpF3D("B9 00 03 1D 00 40 45 D8"); - break; - } - } - - ImpF3D("B6 00 00 00 00 01 00 00"); // B6 00 00 00 00 01 02 00 --> Smoothen Shading? - } - - private byte GetTypeFromTexType(N64Codec texType, bool advanced = false) - { - switch (texType) - { - case N64Codec.CI4: - { - return Convert.ToByte(advanced ? 0x50 : 0x40); - } - - case N64Codec.CI8: - { - return Convert.ToByte(advanced ? 0x50 : 0x48); - } - - case N64Codec.I4: - { - return Convert.ToByte(advanced ? 0x90 : 0x80); - } - - case N64Codec.I8: - { - return Convert.ToByte(advanced ? 0x90 : 0x88); - } - - case N64Codec.IA4: - { - return Convert.ToByte(advanced ? 0x70 : 0x60); - } - - case N64Codec.IA8: - { - return Convert.ToByte(advanced ? 0x70 : 0x68); - } - - case N64Codec.IA16: - { - return 0x70; - } - - case N64Codec.RGBA16: - { - return 0x10; - } - - case N64Codec.RGBA32: - { - return 0x18; - } - - default: - { - return default; - } - } - } - - private byte BytesPerType(N64Codec type) - { - switch (type) - { - case N64Codec.RGBA16: - { - return 2; - } - - case N64Codec.RGBA32: - { - return 4; - } - - case N64Codec.I4: - case N64Codec.IA4: - case N64Codec.CI4: - { - return 0; // Special case - } - - case N64Codec.IA8: - case N64Codec.I8: - case N64Codec.CI8: - { - return 1; - } - - default: - { - return 2; - } - } - } - - private byte GetTexelIncrement(N64Codec type) - { - switch (type) - { - case N64Codec.I4: - case N64Codec.IA4: - { - return 3; - } - - case N64Codec.IA8: - case N64Codec.I8: - { - return 1; - } - - default: - { - return 0; - } - } - } - - private byte GetTexelShift(N64Codec type) - { - switch (type) - { - case N64Codec.I4: - case N64Codec.IA4: - case N64Codec.CI4: - { - return 2; - } - - case N64Codec.IA8: - case N64Codec.I8: - case N64Codec.CI8: - { - return 1; - } - - default: - { - return 0; - } - } - } - - private void ImpCmdFD(uint offset, N64Codec texType) - { - uint off = startSegOffset + offset; - byte type = GetTypeFromTexType(texType, true); - ImpF3D($"FD {Hex(type)} 00 00 {Hex(curSeg & 0xFF)} {Hex(off >> 16 & (long)0xFF)} {Hex(off >> 8 & (long)0xFF)} {Hex(off & (long)0xFF)}"); - } - - private void ImpCmdF5_First(N64Codec texType) - { - byte type = GetTypeFromTexType(texType, true); - ImpF3D($"F5 {Hex(type)} 00 00 07 00 00 00"); - } - - private void ImpCmdF5_Second(Material mat, uint texWidth, uint texHeight) - { - // Create upper - byte type = GetTypeFromTexType(mat.TexType); - float lineScale = 1.0F; - byte bpt = BytesPerType(mat.TexType); - if (bpt != 0) - { - lineScale = (float)(bpt / 4.0); - } - else - { - lineScale = 0.125F; - } - - if (mat.TexType == N64Codec.RGBA32) - { - lineScale /= 2; - } - - ushort line = Convert.ToUInt16(Convert.ToUInt16(Math.Truncate(texWidth * lineScale)) & 0x1FF); - uint upper = Convert.ToUInt32((Convert.ToUInt32(type) << 16 | Convert.ToUInt32(line) << 8) & (long)0xFFFFFF); - - // Create lower (shift) - byte maskS = Convert.ToByte(Convert.ToInt64(Math.Ceiling(Math.Log(texWidth, 2))) & 0xF); - byte maskT = Convert.ToByte(Convert.ToInt64(Math.Ceiling(Math.Log(texHeight, 2))) & 0xF); - uint lower = Convert.ToUInt32((Convert.ToUInt32(maskT) << 14 | Convert.ToUInt32(maskS) << 4) & (long)0xFFFFFF); // &HFFC3F0 for only shift - if (mat.EnableMirrorS) - { - lower = Convert.ToUInt32(lower | (long)0x100); // S axis - } - - if (mat.EnableMirrorT) - { - lower = Convert.ToUInt32(lower | (long)0x40000); // T axis - } - - if (mat.EnableClampS) - { - lower = Convert.ToUInt32(lower | (long)0x80000); // T axis - } - - if (mat.EnableClampT) - { - lower = Convert.ToUInt32(lower | (long)0x200); // S axis - } - - // Create Command - ImpF3D($"F5 {Hex(upper >> 16 & (long)0xFF)} {Hex(upper >> 8 & (long)0xFF)} {Hex(upper & (long)0xFF)} 00 {Hex(lower >> 16 & (long)0xFF)} {Hex(lower >> 8 & (long)0xFF)} {Hex(lower & (long)0xFF)}"); - } - - private void AddCmdF3(Material mat) - { - uint numTexels = (uint)((mat.TexWidth * mat.TexHeight + GetTexelIncrement(mat.TexType) >> GetTexelShift(mat.TexType)) - (long)1); - int bpt = BytesPerType(mat.TexType); - uint tl; - uint lower; - string cmd; - if (bpt != 0) - { - tl = Convert.ToUInt32(Operators.AndObject(CALC_DXT(mat.TexWidth, bpt), 4095)); - } - else - { - tl = Convert.ToUInt32(Operators.AndObject(CALC_DXT_4b(mat.TexWidth), 4095)); - } - - lower = Convert.ToUInt32((numTexels << 12 | tl) & (long)0xFFFFFF); - cmd = $"F3 00 00 00 07 {Hex(lower >> 16 & (long)0xFF)} {Hex(lower >> 8 & (long)0xFF)} {Hex(lower & (long)0xFF)}"; - ImpF3D(cmd); - } - - private void AddCmdF2(Material mat) - { - ushort width = Convert.ToUInt16(mat.TexWidth - (long)1 << 2 & 0xFFF); - ushort height = Convert.ToUInt16(mat.TexHeight - (long)1 << 2 & 0xFFF); - uint data = Convert.ToUInt32(Convert.ToInt32(width) << 12 | height); - string cmd = $"F2 00 00 00 00 {Hex(data >> 16 & (long)0xFF)} {Hex(data >> 8 & (long)0xFF)} {Hex(data & (long)0xFF)}"; - ImpF3D(cmd); - } - - private void AddCmdFC(Material mat, ref string lastCmd) - { - string cmd = string.Empty; - var colorFormula = Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.Formula.Output(Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.CCMUX.SHADE); - bool isColorPresent = Convert.ToDouble(Convert.ToString(mat.Color) + Convert.ToString(0xFFFFFF00U)) != 0xFFFFFF00U; - if (mat.HasTexture) - { - colorFormula = Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.Formula.Multiply(Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.CCMUX.TEXEL0, Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.CCMUX.SHADE); - } - else - { - var switchExpr1 = mat.Type; - switch (switchExpr1) - { - case MaterialType.None: - case MaterialType.TextureSolid: - case MaterialType.TextureAlpha: - case MaterialType.TextureTransparent: - { - colorFormula = Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.Formula.Output(Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.CCMUX.SHADE); - break; - } - - case MaterialType.ColorSolid: - case MaterialType.ColorTransparent: - { - if (isColorPresent) - { - colorFormula = Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.Formula.Multiply(Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.CCMUX.SHADE, Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.CCMUX.ENVIRONMENT); - } - else - { - colorFormula = Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.Formula.Output(Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.CCMUX.SHADE); - } - - break; - } - } - } - - var alphaFormula = Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.Formula.Output(Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.ACMUX.SHADE); - bool isTransPresent = Convert.ToDouble(Convert.ToString(mat.Color) + Convert.ToString(0xFFU)) != 0xFFU; - if (mat.HasTexture) - { - var switchExpr2 = mat.Type; - switch (switchExpr2) - { - case MaterialType.None: - case MaterialType.TextureSolid: - case MaterialType.ColorSolid: - { - alphaFormula = Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.Formula.Output(Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.ACMUX.ONE); - break; - } - - case MaterialType.TextureAlpha: - case MaterialType.TextureTransparent: - { - // With Fog multiplying SHADE is not something you want because it will be alpha fog so just output TEXEL0 and hope it is fine - if (settings.EnableFog) - { - alphaFormula = Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.Formula.Output(Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.ACMUX.TEXEL0); - } - else - { - alphaFormula = Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.Formula.Multiply((byte)Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.ACMUX.TEXEL0, (byte)Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.ACMUX.SHADE); - } - - break; - } - - case MaterialType.ColorTransparent: - { - if (isTransPresent) - { - alphaFormula = Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.Formula.Multiply((byte)Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.ACMUX.TEXEL0, (byte)Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.ACMUX.ENVIRONMENT); - } - else if (settings.EnableFog) - { - alphaFormula = Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.Formula.Output(Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.ACMUX.TEXEL0); - } - else - { - alphaFormula = Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.Formula.Multiply((byte)Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.ACMUX.TEXEL0, (byte)Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.ACMUX.SHADE); - } - - break; - } - } - } - else - { - var switchExpr3 = mat.Type; - switch (switchExpr3) - { - case MaterialType.None: - case MaterialType.TextureSolid: - case MaterialType.ColorSolid: - { - alphaFormula = Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.Formula.Output(Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.ACMUX.ONE); - break; - } - - case MaterialType.TextureAlpha: - case MaterialType.TextureTransparent: - { - // With Fog multiplying SHADE is not something you want because it will be alpha fog so just output TEXEL0 - if (settings.EnableFog) - { - alphaFormula = Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.Formula.Output(Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.ACMUX.ONE); - } - else - { - alphaFormula = Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.Formula.Output(Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.ACMUX.SHADE); - } - - break; - } - - case MaterialType.ColorTransparent: - { - if (isTransPresent) - { - // If there is no material, may as well provide more options for alpha modulate - if (settings.EnableFog) - { - alphaFormula = Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.Formula.Output(Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.ACMUX.ENVIRONMENT); - } - else - { - alphaFormula = Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.Formula.Multiply((byte)Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.ACMUX.ENVIRONMENT, (byte)Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.ACMUX.SHADE); - } - } - else if (settings.EnableFog) - { - alphaFormula = Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.Formula.Output(Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.ACMUX.ONE); - } - else - { - alphaFormula = Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.Formula.Output(Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.ACMUX.SHADE); - } - - break; - } - } - } - - cmd = Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.Make(colorFormula, alphaFormula, settings.EnableFog); - if (!string.IsNullOrEmpty(cmd) && (lastCmd ?? "") != (cmd ?? "")) - { - ImpF3D(cmd); - lastCmd = cmd; - } - } - - private void ImpTriCmds(Material mat, FvGroup grp, int offset, ref bool enabledVertexColors) - { - if (grp.VertexDataCount < 3) - return; - uint off = (uint)(startSegOffset + offset); - int amount = grp.VertexDataCount * 0x10; - if (mat.EnableScrolling) - { - AddScrollingTexture(grp, Convert.ToInt32(off), Convert.ToInt32(mat.Offset), mat.Name); - } - - if (grp.EnableVertexColors) - { - if (!enabledVertexColors) - { - ImpF3D("B6 00 00 00 00 02 00 00"); - enabledVertexColors = true; - } - } - else if (enabledVertexColors) - { - ImpF3D("B7 00 00 00 00 02 00 00"); - enabledVertexColors = false; - } - - ImpF3D($"04 {Hex(amount - 0x10 & 0xFF)} 00 {Hex(amount & 0xFF)} {Hex(curSeg)} {Hex(off >> 16 & (long)0xFF)} {Hex(off >> 8 & (long)0xFF)} {Hex(off & (long)0xFF)}"); - for (int i = 0, loopTo = grp.NumTri - 1; i <= loopTo; i++) - { - byte a = Convert.ToByte(grp.indexList[i * 3] * 0xA); - byte b = Convert.ToByte(grp.indexList[i * 3 + 1] * 0xA); - byte c = Convert.ToByte(grp.indexList[i * 3 + 2] * 0xA); - ImpF3D($"BF 00 00 00 00 {Hex(a)} {Hex(b)} {Hex(c)}"); - } - } - - private void ResetCrystalEffectCommands(ref bool hasCrystalEffectEnabled, ref bool needToResetCrystalEffectCommands) - { - ImpF3D("B6 00 00 00 00 04 00 00"); - ImpF3D("BB 00 00 01 FF FF FF FF"); - hasCrystalEffectEnabled = false; - needToResetCrystalEffectCommands = false; - } - - private void ImpMaterialCmds(Material mat, ref bool hasCrystalEffectEnabled, ref bool needToResetCrystalEffectCommands, ref bool disabledBackfaceCulling) - { - if (mat.EnableCrystalEffect) - { - if (!hasCrystalEffectEnabled) - { - ImpF3D($"B7 00 00 00 00 04 00 00"); - ImpF3D("BB 00 00 01 08 00 08 00"); - hasCrystalEffectEnabled = true; - needToResetCrystalEffectCommands = true; - } - } - else if (needToResetCrystalEffectCommands) - { - ResetCrystalEffectCommands(ref hasCrystalEffectEnabled, ref needToResetCrystalEffectCommands); - } - - if (mat.HasPalette) - { - ImpCmdFD(mat.PaletteOffset, N64Codec.RGBA16); - ImpF3D("F5 00 01 00 01 00 00 00"); - ushort num = Convert.ToUInt16(Convert.ToInt64(mat.PaletteSize / (double)2 - 1) << 6); - ImpF3D($"F0 00 00 00 01 {Hex((num >> 8) & 0xFF)} {Hex(num & 0xFF)} 00"); - } - - if (((mat.FaceCullingMode & FaceCullingMode.Back) != FaceCullingMode.Back)) - { - if (!disabledBackfaceCulling) - { - ImpF3D($"B6 00 00 00 00 00 20 00"); // Disable back face culling - disabledBackfaceCulling = true; - } - } - else if (disabledBackfaceCulling) - { - ImpF3D($"B7 00 00 00 00 00 20 00"); // Enable back face culling - disabledBackfaceCulling = false; - } - - if (mat.HasTexture) - { - ImpCmdFD(mat.Offset, mat.TexType); - ImpCmdF5_First(mat.TexType); - ImpF3D("E6 00 00 00 00 00 00 00"); - AddCmdF3(mat); - ImpF3D("E7 00 00 00 00 00 00 00"); - ImpCmdF5_Second(mat, mat.TexWidth, mat.TexHeight); - AddCmdF2(mat); - } - } - - private void AddScrollingTexture(FvGroup grp, int vertPtr, int matAddr, string matName) - { - var scrollTex = new ScrollTex(Convert.ToInt32(curSeg) << 24 | vertPtr, Convert.ToByte(grp.VertexDataCount), matAddr, matName); - scrollTexts.Add(scrollTex); - } - - private void MergeScrollingTextures() - { - short curScrollingGroupID = 0; - var scrollingGroups = new Dictionary(); - scrollTexts = new List(scrollTexts.OrderBy(n => n.Offset)); - - short getScrollingGroup(int curMatAddr) - { - if (scrollingGroups.ContainsKey(curMatAddr)) - return scrollingGroups[curMatAddr]; - else - { - short newID = curScrollingGroupID; - scrollingGroups.Add(curMatAddr, newID); - curScrollingGroupID += 1; - return newID; - } - }; - - while (scrollTexts.Count > 0) - { - int startOff = scrollTexts[0].Offset; - int endOff = startOff + scrollTexts[0].VertsCount * 0x10; - int count = 0; - int curMatAddr = scrollTexts[0].MaterialAddress; - string curMatName = scrollTexts[0].MaterialName; - - foreach (ScrollTex st in scrollTexts) - { - if (st.MaterialAddress == curMatAddr) - { - if (st.Offset <= endOff) - { - if ((endOff - startOff) / (double)0x10 <= ushort.MaxValue) - { - int newEndOffset = st.Offset + st.VertsCount * 0x10; - endOff = newEndOffset; - } - else - break; - } - else if (st.Offset > endOff) - break; - - count += 1; - } - else - break; - } - - int vertsCount = (int)((endOff - startOff) / (double)0x10); - if (vertsCount > 0) - { - short groupID = getScrollingGroup(curMatAddr); - scrollTexts.RemoveRange(0, count); - conRes.ScrollingCommands.Add(new SM64Lib.Levels.ScrolTex.ManagedScrollingTexture(Convert.ToUInt16(vertsCount), startOff, groupID)); - conRes.ScrollingNames.AddIfNotContainsKey(groupID, curMatName); - } - } - } - - private void ImpColorCmdFB(Material mat) - { - byte r = Convert.ToByte(mat.Color >> 24 & (long)0xFF); - byte g = Convert.ToByte(mat.Color >> 16 & (long)0xFF); - byte b = Convert.ToByte(mat.Color >> 8 & (long)0xFF); - ImpF3D($"FB 00 00 00 {Hex(r)} {Hex(g)} {Hex(b)} {Hex(mat.Opacity)}"); - } - - private void AlignPosition() - { - impdata.RoundUpPosition(); - } - - /// - /// Adds a command that is requied on the end of a display list if CI textures are enabled - /// - private void SetOtherMode_H_Revert() - { - // Reset CI texture palette color format - ImpF3D("BA 00 0E 02 00 00 00 00"); - - // If it ever is required, then use this command instead. It also reverts the texture filter to "Bilerp". - //ImpF3D("BA 00 0C 04 00 00 20 00"); - } - - /// - /// Adds a command to enable CI textures - /// - private void SetOtherMode_H(Material mat, ref bool ciEnabled, ref bool nonDefaultFilter) - { - var citextypes = new[] { N64Codec.CI4, N64Codec.CI8 }; - var iscitexture = citextypes.Contains(mat.TexType); - var paletteColorStorageType = iscitexture ? PaletteColorStorageType.RGBA16 : PaletteColorStorageType.None; - - byte ss = 0xC; - byte nn = 0x4; - int options = 0; - - // G_MDSFT_TEXTLUT (Palette color storage type) - ciEnabled = iscitexture; - options |= ((int)paletteColorStorageType) << 0xE; - - // G_MDSFT_TEXTFILT (Texture Filter) - nonDefaultFilter = mat.TexFilter != TextureFilter.Bilerp; - options |= ((int)mat.TexFilter) << 0xC; - - // Normally we need to set "ss" to E for G_MDSFT_TEXTLUT and to C for G_MDSFT_TEXTFILT. - // Because it they are nearby the other, we can combine them, so set to the lower value C and increase "nn" by the difference (+2 = 4). - // This saves one command. Else it would be two commands, for each option one command. - impdata.Write(new byte[] { 0xBA, 0, ss, nn }); - impdata.Write(options); - } - - private void ImportObj(Pilz.S3DFileParser.Object3D model) - { - bool enabledVertexColors; - bool enableForcing = settings.ForceDisplaylist != -1; - uint importStart = 0; - uint startVerts = 0; - Material lastMaterial = null; - uint lastFBColor = default; - bool hasCrystalEffectEnabled, needToResetCrystalEffectCommands, disabledBackfaceCulling; - bool ciEnabled; - bool nonDefaultFilter; - string lastCmdFC; - var dlsToCreate = new List(); - var dicMatDlIDs = new Dictionary(); - ProcessObject3DModel(model); - conRes.PtrStart = Convert.ToUInt32((long)CurSegAddress | impdata.Position); - importStart = Convert.ToUInt32(impdata.Position); - - // Write default color - impdata.Write(defaultColor); - - // Remove duplicated textures - // FIXME: This function does not account for materials properties like Opacity - // MergeDuplicatedTextures() - - // Write materials - foreach (Material mt in materials) - { - if (mt.HasTexture) - { - mt.Offset = Convert.ToUInt32(impdata.Position); - impdata.Write(mt.Texture.Data); - AlignPosition(); - if (mt.HasPalette) - { - mt.PaletteOffset = Convert.ToUInt32(impdata.Position); - impdata.Write(mt.Texture.Palette); - AlignPosition(); - } - } - } - - // Prepaire vertices - BuildVertexGroups(); - removeDuplicateVertices(settings.ReduceVertLevel); - - // Write vertices - conRes.PtrVertex = Convert.ToUInt32((long)CurSegAddress | impdata.Position); - startVerts = Convert.ToUInt32(impdata.Position); - foreach (VertexGroupList mp in vertexGroups) - { - for (int g = 0; g < mp.GroupsCount; g++) - { - if (mp.FinalVertexGroups[g].VertexDataCount >= 1) - { - for (int i = 0; i < mp.FinalVertexGroups[g].VertexDataCount; i++) - { - var data = mp.FinalVertexGroups[g].FinalVertexData[i].Data; - impdata.Write(data); - } - } - } - } - - int createDefaultDL(Geolayout.DefaultGeolayers layerID) - { - DisplaylistProps dlProp = null; - int newLayerID = ((int)layerID + 1) * -1; - foreach (DisplaylistProps dl in dlsToCreate) - { - if (dlProp is null && dl.ID == newLayerID) - dlProp = dl; - } - - if (dlProp is null) - dlProp = new DisplaylistProps(newLayerID); - - dlProp.Layer = layerID; - if (!dlsToCreate.Contains(dlProp)) - dlsToCreate.Add(dlProp); - - return dlProp.ID; - }; - int createCustomDL(int dlID) - { - DisplaylistProps dlProp = null; - - // Search dlProp - foreach (var prop in settings.TextureFormatSettings.CustomDisplayLists) - { - if (dlProp is null && prop.ID == dlID) - dlProp = prop; - } - - if (!dlsToCreate.Contains(dlProp)) - dlsToCreate.Add(dlProp); - - return dlProp.ID; - }; - - // Check which DLs should be created - if (enableForcing) - { - int dlID = createDefaultDL((Geolayout.DefaultGeolayers)settings.ForceDisplaylist); - foreach (Material mat in materials) - dicMatDlIDs.Add(mat, dlID); - } - else - { - foreach (Material mat in materials) - { - int dlID = -1; - var switchExpr = mat.DisplaylistSelection.SelectionMode; - - switch (switchExpr) - { - case DisplaylistSelectionMode.Automatic: - if (mat.HasTransparency) - dlID = createDefaultDL(Geolayout.DefaultGeolayers.Translucent); - else if (mat.HasTextureAlpha) - dlID = createDefaultDL(Geolayout.DefaultGeolayers.Alpha); - else - dlID = createDefaultDL(Geolayout.DefaultGeolayers.Solid); - break; - case DisplaylistSelectionMode.Default: - dlID = createDefaultDL(mat.DisplaylistSelection.DefaultGeolayer); - break; - case DisplaylistSelectionMode.Custom: - dlID = createCustomDL(mat.DisplaylistSelection.CustomDisplaylistID); - break; - } - - dicMatDlIDs.Add(mat, dlID); - } - } - - // Create DLs - foreach (DisplaylistProps dlProps in dlsToCreate) - { - // Add Geopointer - conRes.PtrGeometry.Add(new Geolayout.Geopointer((byte)dlProps.Layer, Convert.ToInt32(CurSegAddress | impdata.Position))); - - // Reset some stuff - enabledVertexColors = false; - hasCrystalEffectEnabled = false; - needToResetCrystalEffectCommands = false; - disabledBackfaceCulling = false; - ciEnabled = false; - nonDefaultFilter = false; - lastMaterial = null; - lastFBColor = default; - lastCmdFC = string.Empty; - - // Create DL - ImpF3D("E7 00 00 00 00 00 00 00"); - if (settings.EnableFog) - ImpF3D("B9 00 02 01 00 00 00 00"); - ImpF3D("B7 00 00 00 00 00 00 00"); - ImpF3D("BB 00 00 01 FF FF FF FF"); - ImpF3D("E8 00 00 00 00 00 00 00"); - ImpF3D("E6 00 00 00 00 00 00 00"); - ImpF3D("03 88 00 10 0E 00 00 00"); - ImpF3D("03 86 00 10 0E 00 00 08"); - if (settings.EnableFog) - ImpFogStart((int)dlProps.Layer); - - for (int i = 0, loopTo2 = vertexGroups.Count - 1; i <= loopTo2; i++) - { - var mp = vertexGroups[i]; - if (dicMatDlIDs[mp.Material] != dlProps.ID) - continue; - - // Geomode - if (mp.Material.EnableGeoMode) - { - ImpF3D("B6 00 00 00 FF FF FF FF"); - ImpF3D($"B7 00 00 00 {Hex(mp.Material.GeoMode >> 24 & (long)0xFF)} {Hex(mp.Material.GeoMode >> 16 & (long)0xFF)} {Hex(mp.Material.GeoMode >> 8 & (long)0xFF)} {Hex(mp.Material.GeoMode & (long)0xFF)}"); - } - - if (lastMaterial != mp.Material) - { - lastMaterial = mp.Material; - - AddCmdFC(mp.Material, ref lastCmdFC); - if ((mp.Material.Type == MaterialType.ColorSolid || mp.Material.Type == MaterialType.ColorTransparent) && lastFBColor != mp.Material.Color) - ImpColorCmdFB(mp.Material); - SetOtherMode_H(mp.Material, ref ciEnabled, ref nonDefaultFilter); - ImpMaterialCmds(mp.Material, ref hasCrystalEffectEnabled, ref needToResetCrystalEffectCommands, ref disabledBackfaceCulling); - } - - int grpOff = 0; - for (int ii = 0, loopTo3 = mp.GroupsCount - 1; ii <= loopTo3; ii++) - { - ImpTriCmds(mp.Material, mp.FinalVertexGroups[ii], (int)(startVerts + (mp.StartIndex + grpOff)), ref enabledVertexColors); - grpOff += mp.FinalVertexGroups[ii].VertexDataCount * 0x10; - } - - if (mp.Material.EnableGeoMode) - { - if (i + 1 < vertexGroups.Count && vertexGroups[i + 1].Material.EnableGeoMode) - continue; - ImpF3D("B6 00 00 00 FF FF FF FF"); - ImpF3D("B7 00 00 00 00 02 20 05"); - } - } - - if (enabledVertexColors) - ImpF3D("B7 00 00 00 00 02 00 00"); - if (settings.EnableFog) - ImpFogEnd((int)dlProps.Layer); - ImpF3D("FC FF FF FF FF FE 79 3C"); - ImpF3D("BB 00 00 00 FF FF FF FF"); - if (needToResetCrystalEffectCommands) - ResetCrystalEffectCommands(ref hasCrystalEffectEnabled, ref needToResetCrystalEffectCommands); - if (ciEnabled /*|| nonDefaultFilter*/) - SetOtherMode_H_Revert(); - ImpF3D("B8 00 00 00 00 00 00 00"); - MergeScrollingTextures(); - } - - ResetVariables(); - } - - /// - /// Converts a Object3D to an N64 Model and an SM64 Collision. - /// - /// The stream where to write the Fast3D and Collision data. - /// The convert settings. - /// The input model. - /// - public ConvertResult ConvertModel(Stream s, ConvertSettings settings, Pilz.S3DFileParser.Object3D input) - { - this.settings = settings; - impdata = new Data.BinaryStreamData(s); - - // Segmented Address - if (settings.SegmentedAddress is not null) - { - startSegOffset = (uint)(settings.SegmentedAddress & 0xFFFFFF); - curSeg = (byte)(settings.SegmentedAddress >> 24 & 0xFF); - } - - // Shading - SetLightAndDarkValues(input.Shading); - - // Convert - ImportObj(input); - ResetVariables(); - return conRes; } } + + private class TextureEntry + { + public uint Width { get; set; } = 0; + public uint Height { get; set; } = 0; + public byte[] Data { get; set; } = Array.Empty(); + public byte[] Palette { get; set; } = Array.Empty(); + public Image OriginalImage { get; set; } = null; + } + + private class ObjPtrs + { + public string name = Convert.ToString(0); + public uint start_ptr = 0; + public uint import_lenght = 0; + public uint solid_ptr = 0; + public uint alpha_ptr = 0; + public uint trans_ptr = 0; + public uint geo_ptr = 0; + public uint col_ptr = 0; + public uint vertex_start = 0; + } + + public struct ScrollTex + { + public int Offset { get; set; } + public int VertsCount { get; set; } + public int MaterialAddress { get; set; } + public string MaterialName { get; set; } + + public ScrollTex(int offset, byte faceCount, int matAddr, string matName) + { + Offset = offset; + VertsCount = faceCount; + MaterialAddress = matAddr; + MaterialName = matName; + } + } + + private List verts = new List(); + private List norms = new List(); + private List vertexColors = new List(); + private List uvs = new List(); + private List materials = new List(); + private List ignoreFacesWithMaterial = new List(); + private Dictionary materialBindings = new Dictionary(); + private List vertexGroups = new List(); + private List finalVertData = new List(); + private List textureBank = new List(); + private List scrollTexts = new List(); + private Material currentMaterial; + private int currentFace = 0; + private const byte GEOLAYER_SOLID = 1; + private const byte GEOLAYER_ALPHA = 4; + private const byte GEOLAYER_TRANSPARENT = 5; + private byte curSeg = 0; + private uint startSegOffset = 0; + private byte[] defaultColor = new byte[24]; + private ConvertSettings settings = null; + private SM64Lib.Data.BinaryData impdata = null; + private ConvertResult conRes = new ConvertResult(); + private readonly byte[] ColtypesWithParams = new byte[] { 14, 44, 36, 37, 39, 45 }; + + private uint CurSegAddress + { + get + { + return Convert.ToUInt32(curSeg) << 24; + } + } + + private object TXL2WORDS(object txls, object b_txl) + { + return NewLateBinding.LateGet(null, typeof(Math), "Max", new object[] + { + 1, + Operators.DivideObject(Operators.MultiplyObject(txls, b_txl), 8) + }, null, null, null); + } + + private object CALC_DXT(object width, object b_txl) + { + return Operators.DivideObject(2048, this.TXL2WORDS(RuntimeHelpers.GetObjectValue(width), RuntimeHelpers.GetObjectValue(b_txl))); + } + + private object TXL2WORDS_4b(object txls) + { + return NewLateBinding.LateGet(null, typeof(Math), "Max", new object[] + { + 1, + Operators.DivideObject(txls, 16) + }, null, null, null); + } + + private object CALC_DXT_4b(object width) + { + return Operators.DivideObject(2048, this.TXL2WORDS_4b(RuntimeHelpers.GetObjectValue(width))); + } + + private void SetLightAndDarkValues(Pilz.S3DFileParser.Shading s) + { + // Ambient light color + defaultColor[0] = s.AmbientColor.R; + defaultColor[1] = s.AmbientColor.G; + defaultColor[2] = s.AmbientColor.B; + defaultColor[3] = 0; + defaultColor[4] = s.AmbientColor.R; + defaultColor[5] = s.AmbientColor.G; + defaultColor[6] = s.AmbientColor.B; + defaultColor[7] = 0; + + // Diffuse light color + defaultColor[8] = s.DiffuseColor.R; + defaultColor[9] = s.DiffuseColor.G; + defaultColor[10] = s.DiffuseColor.B; + defaultColor[11] = 0; + defaultColor[12] = s.DiffuseColor.R; + defaultColor[13] = s.DiffuseColor.G; + defaultColor[14] = s.DiffuseColor.B; + defaultColor[15] = 0; + + // Diffuse light direction + if (s.DiffusePosition is not null) + { + float d = (float)(127 / Math.Sqrt(s.DiffusePosition.X * s.DiffusePosition.X + s.DiffusePosition.Y * s.DiffusePosition.Y + s.DiffusePosition.Z * s.DiffusePosition.Z)); + + if (float.IsInfinity(d)) + d = 0; + defaultColor[16] = (byte)Convert.ToSByte(Math.Round(s.DiffusePosition.X * d)); + defaultColor[17] = (byte)Convert.ToSByte(Math.Round(s.DiffusePosition.Y * d)); + defaultColor[18] = (byte)Convert.ToSByte(Math.Round(s.DiffusePosition.Z * d)); + } + else + { + defaultColor[16] = 0x49; // = Most SM64E Like ||| Default by Nintendo: &H28 + defaultColor[17] = 0x49; + defaultColor[18] = 0x49; + } + + defaultColor[19] = 0; + defaultColor[20] = 0; + defaultColor[21] = 0; + defaultColor[22] = 0; + defaultColor[23] = 0; + } + + private void ResetVariables() + { + vertexGroups.Clear(); + verts.Clear(); + norms.Clear(); + vertexColors.Clear(); + uvs.Clear(); + materials.Clear(); + finalVertData.Clear(); + currentFace = 0; + } + + private void CheckGeoModeInfo(Material m) + { + m.GeoMode = 0; + var gma = settings.GeoModeData.Split(','); + foreach (string gme in gma) + { + var gmd = gme.Split(':'); + if (m.Name.Equals(gmd[0])) + { + m.GeoMode = Convert.ToUInt32(gmd[1]); + m.EnableGeoMode = true; + return; + } + } + } + + private void CheckColorTexInfo(Material m) + { + m.Color = 0; + var gma = settings.ColorTexData.Split(','); + foreach (string gme in gma) + { + var gmd = gme.Split(':'); + if (m.Name.Equals(gmd[0])) + { + m.Color = Convert.ToUInt32(gmd[1]); + m.EnableTextureColor = true; + return; + } + } + } + + private void processMaterialColor(string str, Material mat) + { + var splitColor = str.Replace(".", ",").Split(' '); + uint r = (uint)(Convert.ToSingle(splitColor[0]) * 255); + uint g = (uint)(Convert.ToSingle(splitColor[1]) * 255); + uint b = (uint)(Convert.ToSingle(splitColor[2]) * 255); + mat.Color = Convert.ToUInt32(r << 24 | g << 16 | b << 8 | (long)0xFF); + } + + private void processMaterialColorAlpha(float alpha, Material mat) + { + mat.Color = mat.Color & 0xFFFFFF00U; + mat.Color = mat.Color | Convert.ToByte(Convert.ToInt64(0xFF * alpha) & 0xFF); + if (alpha < 1.0F) + { + mat.Type = MaterialType.ColorTransparent; + mat.HasTransparency = true; + } + else if (!mat.HasTexture) + { + mat.Type = MaterialType.ColorSolid; + } + } + + private void checkN64CodecInfo(Material m) + { + var gma = settings.TexTypeData.Split(','); + foreach (string gme in gma) + { + var gmd = gme.Split(':'); + if (m.Name.Equals(gmd[0])) + { + var switchExpr = gmd[1]; + switch (switchExpr) + { + case "rgba16": + { + m.TexType = N64Codec.RGBA16; + break; + } + + case "rgba32": + { + m.TexType = N64Codec.RGBA32; + break; + } + + case "ia4": + { + m.TexType = N64Codec.IA4; + break; + } + + case "ia8": + { + m.TexType = N64Codec.IA8; + break; + } + + case "ia16": + { + m.TexType = N64Codec.IA16; + break; + } + + case "i4": + { + m.TexType = N64Codec.I4; + if (gmd.Count() > 2 && (gmd[2] ?? "") == "a") + m.EnableAlphaMask = true; + break; + } + + case "i8": + { + m.TexType = N64Codec.I8; + if (gmd.Count() > 2 && (gmd[2] ?? "") == "a") + m.EnableAlphaMask = true; + break; + } + } + + return; + } + } + + m.TexType = N64Codec.RGBA16; + } + + private Material[] GetDuplicates(Material mat) + { + var foundCopies = new List(); + if (mat.HasTexture) + { + foreach (Material checkMat in materials) + { + if (checkMat != mat) + { + if (checkMat.HasTexture) + { + if (mat.TexType == checkMat.TexType && SM64Lib.General.CompareTwoByteArrays(mat.Texture.Data, checkMat.Texture.Data)) + { + if (!foundCopies.Contains(checkMat)) + { + foundCopies.Add(checkMat); + } + } + } + } + } + } + + // For Each copyMat As Material In foundCopies + // copyMat.texture = mat.texture + // copyMat.offset = mat.offset + // copyMat.texWidth = mat.texWidth + // copyMat.texHeight = mat.texHeight + // copyMat.size = 0 + // copyMat.isTextureCopy = True + // Next + + return foundCopies.ToArray(); + } + + private void MergeDuplicatedTextures() + { + var matsToRemove = new List(); + + foreach (Material mat in materials) + { + if (!matsToRemove.Contains(mat)) + { + foreach (Material dup in GetDuplicates(mat)) + { + if (!matsToRemove.Contains(dup)) + { + // Remove material + matsToRemove.Add(dup); + + // Update material references for vertex group + foreach (VertexGroupList mp in vertexGroups) + { + if (mp.Material == dup) + mp.Material = mat; + } + + // Update material references for material bindings + foreach (var kvp in materialBindings) + { + if (kvp.Value == dup) + materialBindings[kvp.Key] = mat; + } + } + } + } + } + + foreach (Material mat in matsToRemove) + { + if (mat.HasTexture && textureBank.Contains(mat.Texture)) + textureBank.Remove(mat.Texture); + materials.Remove(mat); + } + } + + private void ProcessImage(Pilz.S3DFileParser.Object3D obj, Image img, Material mat) + { + TextureEntry entry = null; + foreach (TextureEntry tex in textureBank) + { + if (tex.OriginalImage == img) + { + entry = tex; + } + } + + // Create & Add texture entry + if (entry is null) + { + entry = new TextureEntry() + { + Width = mat.TexWidth, + Height = mat.TexHeight, + OriginalImage = img + }; + } + + // Load Texture from File + var bmp = new Bitmap(img); + + // Set texture size + mat.TexWidth = Convert.ToUInt32(bmp.Width); + mat.TexHeight = Convert.ToUInt32(bmp.Height); + + // Convert texture + var argimageData = entry.Data; + var argpaletteData = entry.Palette; + N64Graphics.N64Graphics.Convert(ref argimageData, ref argpaletteData, mat.TexType, (Bitmap)img); + entry.Data = argimageData; + entry.Palette = argpaletteData; + + mat.Type = MaterialType.TextureSolid; + + // Check for alpha and transparency + { + var transparentPixels = 0; + var setAsAlpha = false; + var setAsTransparent = false; + + // Check textures + for (int y = 0, loopTo = bmp.Height - 1; y <= loopTo; y++) + { + for (int x = 0, loopTo1 = bmp.Width - 1; x <= loopTo1; x++) + { + var pix = bmp.GetPixel(x, y); + switch (mat.TexType) + { + case N64Codec.RGBA16: + case N64Codec.RGBA32: + case N64Codec.IA4: + case N64Codec.IA8: + case N64Codec.IA16: + case N64Codec.CI4: + case N64Codec.CI8: + if (pix.A == 0) + setAsAlpha = true; + else if (pix.A < 0xFF) + transparentPixels++; + break; + case N64Codec.I4: + case N64Codec.I8: + if (pix.A < 0xFF || mat.EnableAlphaMask) + transparentPixels++; + break; + } + } + } + + // Set as transparent if reached the limit + var transparentPixelsPercent = (float)transparentPixels / (mat.TexWidth * mat.TexHeight); + var reachedTransparentLimit = transparentPixelsPercent > (mat.TransparencyLimit ?? settings.TransparencyLimit); + switch (mat.TexType) + { + case N64Codec.RGBA16: + case N64Codec.RGBA32: + case N64Codec.IA4: + case N64Codec.IA8: + case N64Codec.IA16: + case N64Codec.CI4: + case N64Codec.CI8: + if (reachedTransparentLimit) + setAsTransparent = true; + break; + case N64Codec.I4: + case N64Codec.I8: + if (reachedTransparentLimit || mat.EnableAlphaMask) + setAsTransparent = true; + break; + } + if (setAsTransparent) + { + mat.Type = MaterialType.TextureTransparent; + mat.HasTransparency = true; + } + else if (setAsAlpha) + { + mat.HasTextureAlpha = true; + mat.Type = MaterialType.TextureAlpha; + } + } + + if (!textureBank.Contains(entry)) + textureBank.Add(entry); + mat.Texture = entry; + mat.HasTexture = true; + mat.HasPalette = entry.Palette.Any(); + } + + private void ProcessObject3DModel(Pilz.S3DFileParser.Object3D obj) + { + var texFormatSettings = settings.TextureFormatSettings; + + // Process Materials + ProcessObject3DMaterials(obj, texFormatSettings); + foreach (Pilz.S3DFileParser.Mesh mesh in obj.Meshes) + { + int curIndexStart = verts.Count; + + // Process Vertices + foreach (var vert in mesh.Vertices) + { + var v = new Vertex() + { + X = General.KeepInInt16Range(General.Round(vert.X * settings.Scale + settings.OffsetPosition.X)), + Y = General.KeepInInt16Range(General.Round(vert.Y * settings.Scale + settings.OffsetPosition.Y)), + Z = General.KeepInInt16Range(General.Round(vert.Z * settings.Scale + settings.OffsetPosition.Z)) + }; + verts.Add(v); + } + + // Process Normals + foreach (var norm in mesh.Normals) + { + var n = new Normal() + { + A = Datatypecastes.LongToByte((long)General.Round(norm.X * 0x7F)), + B = Datatypecastes.LongToByte((long)General.Round(norm.Y * 0x7F)), + C = Datatypecastes.LongToByte((long)General.Round(norm.Z * 0x7F)), + D = 0xFF + }; + norms.Add(n); + } + + // Process UVs + foreach (Pilz.S3DFileParser.UV tuv in mesh.UVs) + { + var uv = new TexCord() + { + U = (float)General.Round(tuv.U * 32F * 32F), + V = (float)General.Round(-((tuv.V - 1) * 32F * 32F)) + }; + uvs.Add(uv); + } + + // Process Vertex Colors + foreach (var vertcol in mesh.VertexColors) + { + var vc = new VertexColor() + { + R = Datatypecastes.LongToByte((long)General.Round(vertcol.R * 0xFF)), + G = Datatypecastes.LongToByte((long)General.Round(vertcol.G * 0xFF)), + B = Datatypecastes.LongToByte((long)General.Round(vertcol.B * 0xFF)), + A = Datatypecastes.LongToByte((long)General.Round(vertcol.A * 0xFF)) + }; + vertexColors.Add(vc); + } + + // Process Faces + object curTexture = null; + foreach (var face in mesh.Faces) // .OrderBy(Function(n) n.Texture) + { + if (!ignoreFacesWithMaterial.Contains(face.Material)) + { + if (curTexture is null || !curTexture.Equals(face.Material)) + { + curTexture = face.Material; + string curMatName = obj.Materials.FirstOrDefault(n => n.Value.Equals(face.Material)).Key; + var curMat = materials.FirstOrDefault(n => n.Name.Equals(curMatName)); + var mp = new VertexGroupList() + { + Position = currentFace, + Material = curMat + }; + currentMaterial = curMat; + mp.Length = 0; + vertexGroups.Add(mp); + } + + materialBindings.TryGetValue(face.Material, out Material mat); + + Vertex va = null; + TexCord ta = null; + var tanew = new TexCord(); + Normal na = null; + VertexColor vca = null; + Vertex vb = null; + TexCord tb = null; + var tbnew = new TexCord(); + Normal nb = null; + VertexColor vcb = null; + Vertex vc = null; + TexCord tc = null; + var tcnew = new TexCord(); + Normal nc = null; + VertexColor vcc = null; + void getVals(Pilz.S3DFileParser.Point point, ref Vertex vert, ref TexCord t, ref Normal normal, ref VertexColor vertcol) + { + if (point.Vertex is not null) + vert = verts[curIndexStart + mesh.Vertices.IndexOf(point.Vertex)]; + if (point.UV is not null) + t = uvs[curIndexStart + mesh.UVs.IndexOf(point.UV)]; + if (point.Normal is not null) + normal = norms[curIndexStart + mesh.Normals.IndexOf(point.Normal)]; + if (point.VertexColor is not null) + vertcol = vertexColors[curIndexStart + mesh.VertexColors.IndexOf(point.VertexColor)]; + }; + getVals(face.Points[0], ref va, ref ta, ref na, ref vca); + getVals(face.Points[1], ref vb, ref tb, ref nb, ref vcb); + getVals(face.Points[2], ref vc, ref tc, ref nc, ref vcc); + var fa = new FinalVertexData(); + var fb = new FinalVertexData(); + var fc = new FinalVertexData(); + + // Modify UV cordinates based on material. + void modifyUVCordinates(TexCord tnew, TexCord t) + { + tnew.U = (float)(t.U * (mat.TexWidth / 32.0) - 16); // "-16" fixes the UVs offset + tnew.V = (float)(t.V * (mat.TexHeight / 32.0) - 16); // "-16" fixes the UVs offset + }; + modifyUVCordinates(tanew, ta); + modifyUVCordinates(tbnew, tb); + modifyUVCordinates(tcnew, tc); + + // Fix UVs to reduce number of (large) faces with broken textures + FixUVs(tanew, tbnew, tcnew, Convert.ToInt32(mat.TexWidth), Convert.ToInt32(mat.TexHeight)); + + // Vertex Structure: xxxxyyyyzzzz0000uuuuvvvvrrggbbaa + void buildVertexStructure(FinalVertexData final, Vertex vert, VertexColor vertcol, TexCord tnew, Normal normal) + { + final.Data[0] = Convert.ToByte(vert.X >> 8 & 0xFF); + final.Data[1] = Convert.ToByte(vert.X & 0xFF); + final.Data[2] = Convert.ToByte(vert.Y >> 8 & 0xFF); + final.Data[3] = Convert.ToByte(vert.Y & 0xFF); + final.Data[4] = Convert.ToByte(vert.Z >> 8 & 0xFF); + final.Data[5] = Convert.ToByte(vert.Z & 0xFF); + final.Data[6] = 0; + final.Data[7] = 0; + int uInt, vInt; + uInt = Convert.ToInt32(Math.Round(tnew.U)); + vInt = Convert.ToInt32(Math.Round(tnew.V)); + final.Data[8] = Convert.ToByte(uInt >> 8 & 0xFF); + final.Data[9] = Convert.ToByte(uInt & 0xFF); + final.Data[10] = Convert.ToByte(vInt >> 8 & 0xFF); + final.Data[11] = Convert.ToByte(vInt & 0xFF); + if (vertcol is not null && !mat.EnableCrystalEffect) + { + final.Data[12] = vertcol.R; + final.Data[13] = vertcol.G; + final.Data[14] = vertcol.B; + final.Data[15] = vertcol.A; + final.EnableVertexColor = true; + // FIXME: Add warning if Type is not TextureSolid + if (final.EnableVertexTransparent) + { + mat.Type = MaterialType.TextureTransparent; + mat.HasTransparency = mat.HasTransparency || final.EnableVertexTransparent; + } + } + else + { + final.Data[12] = normal.A; + final.Data[13] = normal.B; + final.Data[14] = normal.C; + final.Data[15] = normal.D; + final.EnableVertexColor = false; + } + }; + buildVertexStructure(fa, va, vca, tanew, na); + buildVertexStructure(fb, vb, vcb, tbnew, nb); + buildVertexStructure(fc, vc, vcc, tcnew, nc); + finalVertData.AddRange(new[] { fa, fb, fc }); + currentFace += 1; + } + } + } + } + + private void ProcessObject3DMaterials(Pilz.S3DFileParser.Object3D obj, Model.Fast3D.TextureFormatSettings texFormatSettings) + { + var tasks = new List(); + + // Start converting each image + foreach (var kvp in obj.Materials) + { + ProcessObject3DMaterial(obj, kvp, texFormatSettings); + } + } + + private void ProcessObject3DMaterial(Pilz.S3DFileParser.Object3D obj, KeyValuePair kvp, Model.Fast3D.TextureFormatSettings texFormatSettings) + { + int size = 0; + var curEntry = texFormatSettings.GetEntry(kvp.Key); + + if (curEntry.Include) + { + // Create new Material + var m = new Material() + { + Type = MaterialType.ColorSolid, + Color = 0, + HasTexture = false, + HasTextureAlpha = false, + HasTransparency = false, + Name = kvp.Key, + Collision = 0, + Opacity = 0xFF, + OpacityOrg = 0xFF, + EnableGeoMode = false, + EnableTextureColor = false, + EnableAlphaMask = false, + CameFromBMP = false, + EnableScrolling = curEntry.IsScrollingTexture, + DisplaylistSelection = curEntry.DisplaylistSelection, + EnableMirrorS = curEntry.EnableMirrorS, + EnableMirrorT = curEntry.EnableMirrorT, + EnableClampS = curEntry.EnableClampS, + EnableClampT = curEntry.EnableClampT, + EnableCrystalEffect = curEntry.EnableCrystalEffect, + FaceCullingMode = curEntry.FaceCullingMode, + TransparencyLimit = curEntry.TransparencyLimit, + TexFilter = curEntry.TextureFilter + }; + + // Set default size + size = 0x10; + + // Check some things + CheckGeoModeInfo(m); + CheckColorTexInfo(m); + + // Add material + materials.Add(m); + materialBindings.Add(kvp.Value, m); + + // Process Material Color + if (!m.EnableTextureColor) + { + uint r = kvp.Value.Color.Value.R; + uint g = kvp.Value.Color.Value.G; + uint b = kvp.Value.Color.Value.B; + uint a = kvp.Value.Color.Value.A; + m.Color = r << 24 | g << 16 | b << 8 | a; + if (a == (long)0xFF) + { + m.Type = MaterialType.ColorSolid; + } + else + { + m.Type = MaterialType.ColorTransparent; + } + } + + // Check Texture Type + if (texFormatSettings is not null) + { + m.TexType = N64Graphics.N64Graphics.StringCodec(texFormatSettings.GetEntry(kvp.Key).TextureFormat); + } + + // Process Material Image + if (kvp.Value.Image is not null) + { + ProcessImage(obj, kvp.Value.Image, m); + size = m.Texture.Data.Length; + } + + // Process Material Color Alpha + if (kvp.Value.Opacity is not null) + { + float tempopacity = (float)kvp.Value.Opacity; + m.Opacity = Convert.ToByte(Convert.ToInt64(tempopacity * 0xFF) & 0xFF); + m.OpacityOrg = m.Opacity; + processMaterialColorAlpha(tempopacity, m); + } + + // Set offset and size + m.Size = Convert.ToUInt32(size); + if (m.Texture?.Palette is not null) + { + m.PaletteSize = Convert.ToUInt32(m.Texture.Palette.Length); + } + } + else + ignoreFacesWithMaterial.Add(kvp.Value); + } + + private void FixUVs(TexCord uv1, TexCord uv2, TexCord uv3, int matWidth, int matHeight) + { + if (matWidth <= 0 || matHeight <= 0) return; + + TexCord[] uvs = null; + int jump = 0; + + float RoundToJump(float val) + { + var mod = val % jump; + + if (mod >= 0.5 * jump) + val = jump * (float)Math.Ceiling(val / jump); // Round up + else + val = jump * (float)Math.Floor(val / jump); // Round down + + return val; + } + + jump = matWidth * 0x40; + uvs = new[] { uv1, uv2, uv3 }.OrderBy(n => n.U).ToArray(); + if (jump != 0) + { + // Move near 0 + float varM; + varM = RoundToJump((uvs[0].U + uvs[2].U) / 2); + uvs[0].U -= varM; + uvs[1].U -= varM; + uvs[2].U -= varM; + + // Keep in bounds (max bounds) + while (uvs.Last().U > short.MaxValue) + { + uvs[0].U -= jump; + uvs[1].U -= jump; + uvs[2].U -= jump; + } + + // Keep in bounds (min bounds) + while (uvs.First().U < short.MinValue) + { + uvs[0].U += jump; + uvs[1].U += jump; + uvs[2].U += jump; + } + } + + jump = matHeight * 0x40; + uvs = new[] { uv1, uv2, uv3 }.OrderBy(n => n.V).ToArray(); + if (jump != 0) + { + // Move near 0 + float varM; + varM = RoundToJump((uvs[0].V + uvs[2].V) / 2); + uvs[0].V -= varM; + uvs[1].V -= varM; + uvs[2].V -= varM; + + // Keep in bounds (max bounds) + while (uvs.Last().V > short.MaxValue) + { + uvs[0].V -= jump; + uvs[1].V -= jump; + uvs[2].V -= jump; + } + + // Keep in bounds (min bounds) + while (uvs.First().V < short.MinValue) + { + uvs[0].V += jump; + uvs[1].V += jump; + uvs[2].V += jump; + } + } + } + + private void removeDuplicateVertices(ReduceVericesLevel level) + { + if ((int)level < 1) + return; + int dupCnt = 0; + foreach (VertexGroupList mp in vertexGroups) + { + for (int g = 0; g < mp.GroupsCount; g++) + { + var fvg = mp.FinalVertexGroups[g]; + if (fvg.VertexDataCount < 1) continue; + + for (int i = 0; i < fvg.VertexDataCount; i++) + { + int j = i + 1; + while (j < fvg.VertexDataCount) + { + if (SM64Lib.General.CompareTwoByteArrays(fvg.FinalVertexData[i].Data, fvg.FinalVertexData[j].Data, 16)) + { + moveElementsInGroupUpward(fvg, 1, j); + UpdateIndexList(fvg, Convert.ToByte(j), Convert.ToByte(i)); + UpdatePositions(mp.StartIndex); + dupCnt += 1; + } + + j += 1; + } + } + + if (g < mp.GroupsCount - 1 && (int)level > 1) + { + if (MoveVertsBack(mp.FinalVertexGroups[g], mp.FinalVertexGroups[g + 1])) + { + g -= 1; + } + } + } + } + } + + private void UpdateIndexList(FvGroup grp, byte removed, byte replaceWith) + { + for (int i = 0; i < grp.NumTri * 3; i++) + { + if (grp.indexList[i] < removed) continue; + + if (grp.indexList[i] == removed) + { + grp.indexList[i] = Convert.ToSByte(replaceWith); + } + else + { + grp.indexList[i] -= 1; + } + } + } + + private void UpdatePositions(int vs) + { + foreach (VertexGroupList mp in vertexGroups) + { + if (mp.StartIndex <= vs) + continue; + if (mp.StartIndex < 0x10) + continue; + mp.StartIndex -= 0x10; + } + } + + private bool MoveVertsBack(FvGroup to, FvGroup from) + { + if (from.VertexDataCount < 3) + return false; + if (to.VertexDataCount < 14) + { + to.FinalVertexData.Add(from.FinalVertexData[0]); + to.FinalVertexData.Add(from.FinalVertexData[1]); + to.FinalVertexData.Add(from.FinalVertexData[2]); + to.indexList[to.NumTri * 3] = Convert.ToSByte(to.VertexDataCount); + to.indexList[to.NumTri * 3 + 1] = Convert.ToSByte(to.VertexDataCount + 1); + to.indexList[to.NumTri * 3 + 2] = Convert.ToSByte(to.VertexDataCount + 2); + moveElementsInGroupUpward(from, 3, 0); + to.NumTri += 1; + return true; + } + + return false; + } + + private void moveElementsInGroupUpward(FvGroup grp, int amount, int start) + { + for (int i = 0; i < amount; i++) + grp.FinalVertexData.RemoveAt(start); + } + + private void BuildVertexGroups() + { + int vs = 0; + for (int i = 0; i < vertexGroups.Count; i++) + { + { + var withBlock = vertexGroups[i]; + withBlock.StartIndex = vs; + int length = 0; + if (i < vertexGroups.Count - 1) + { + length = vertexGroups[i + 1].Position - withBlock.Position; + } + else + { + length = currentFace - withBlock.Position; + } + + int groupsCount = 0; + if (length % 5 == 0) + { + groupsCount = (int)(length / (double)5); + } + else + { + groupsCount = (int)(Math.Truncate(length / (double)5) + 1); + } + + for (int j = 0; j < groupsCount; j++) + withBlock.FinalVertexGroups.Add(new FvGroup() { NumTri = 0 }); + + for (int g = 0; g < groupsCount; g++) + { + int s = 5; + if (g == groupsCount - 1) + s = length % 5; + if (s == 0) + s = 5; + var curFvg = withBlock.FinalVertexGroups[g]; + curFvg.NumTri = Convert.ToInt16(s); + for (int j = 0; j < s; j++) + { + int from = (withBlock.Position + j + g * 5) * 3; + curFvg.FinalVertexData.Add(finalVertData[from]); + curFvg.FinalVertexData.Add(finalVertData[from + 1]); + curFvg.FinalVertexData.Add(finalVertData[from + 2]); + curFvg.indexList[j * 3] = Convert.ToSByte(j * 3); + curFvg.indexList[j * 3 + 1] = Convert.ToSByte(j * 3 + 1); + curFvg.indexList[j * 3 + 2] = Convert.ToSByte(j * 3 + 2); + } + + vs += curFvg.VertexDataCount * 0x10; + } + } + } + } + + private F3D StrToF3D(string str) + { + var cmd = new F3D(); + var b = str.Replace(".", ",").Split(' '); + for (int i = 0; i < b.Length; i++) + cmd.data[i] = Convert.ToByte($"&H{b[i]}"); + return cmd; + } + + private void ImpF3D(string str) + { + ImpF3D(StrToF3D(str)); + } + + private void ImpF3D(params byte[] data) + { + impdata.Write(data); + } + + private void ImpF3D(F3D f3d) + { + impdata.Write(f3d.data); + } + + private void ImpFogStart(int layer) + { + ImpF3D("BA 00 14 02 00 10 00 00"); + string cmdF8 = ""; + cmdF8 = $"F8 00 00 00 {Hex(settings.Fog.Color.R)} {Hex(settings.Fog.Color.G)} {Hex(settings.Fog.Color.B)} FF"; + ImpF3D(cmdF8); + switch (layer) + { + case 0: + { + ImpF3D("B9 00 03 1D C8 11 22 30"); + break; + } + + case 1: + { + ImpF3D("B9 00 03 1D C8 11 20 78"); + break; + } + + case 2: + { + ImpF3D("B9 00 03 1D C8 11 2D 58"); + break; + } + + case 3: + { + ImpF3D("B9 00 03 1D C8 10 4D D8"); + break; + } + // ImpF3D("B9 00 03 1D 00 11 24 78") + case 4: + { + ImpF3D("B9 00 03 1D C8 11 30 78"); + break; + } + + case 5: + { + ImpF3D("B9 00 03 1D C8 10 49 D8"); + break; + } + + case 6: + { + ImpF3D("B9 00 03 1D C8 10 4D D8"); + break; + } + + case 7: + { + ImpF3D("B9 00 03 1D C8 10 45 D8"); + break; + } + } + + var switchExpr = settings.Fog.Type; + switch (switchExpr) + { + case global::SM64Lib.Model.FogPreset.SubtleFog1: + { + ImpF3D("BC 00 00 08 19 00 E8 00"); + break; + } + + case global::SM64Lib.Model.FogPreset.SubtleFog2: + { + ImpF3D("BC 00 00 08 12 00 F0 00"); + break; + } + + case global::SM64Lib.Model.FogPreset.ModerateFog1: + { + ImpF3D("BC 00 00 08 0E 49 F2 B7"); + break; + } + + case global::SM64Lib.Model.FogPreset.ModerateFog2: + { + ImpF3D("BC 00 00 08 0C 80 F4 80"); + break; + } + + case global::SM64Lib.Model.FogPreset.ModerateFog3: + { + ImpF3D("BC 00 00 08 0A 00 F7 00"); + break; + } + + case global::SM64Lib.Model.FogPreset.ModerateFog4: + { + ImpF3D("BC 00 00 08 08 55 F8 AB"); + break; + } + + case global::SM64Lib.Model.FogPreset.IntenseFog: + { + ImpF3D("BC 00 00 08 07 24 F9 DC"); + break; + } + + case global::SM64Lib.Model.FogPreset.VeryIntenseFog: + { + ImpF3D("BC 00 00 08 05 00 FC 00"); + break; + } + + case global::SM64Lib.Model.FogPreset.HardcoreFog: + { + ImpF3D("BC 00 00 08 02 50 FF 00"); + break; + } + } + + ImpF3D("B7 00 00 00 00 01 00 00"); + } + + private void ImpFogEnd(int layer) + { + ImpF3D("BA 00 14 02 00 00 00 00"); + switch (layer) + { + case 0: + { + ImpF3D("B9 00 03 1D 00 44 22 30"); + break; + } + + case 1: + { + ImpF3D("B9 00 03 1D 00 44 20 78"); + break; + } + + case 2: + { + ImpF3D("B9 00 03 1D 00 44 2D 58"); + break; + } + + case 3: + { + ImpF3D("B9 00 03 1D 00 40 4D D8"); + break; + } + // ImpF3D("B9 00 03 1D 00 44 24 78") + case 4: + { + ImpF3D("B9 00 03 1D 00 44 30 78"); + break; + } + + case 5: + { + ImpF3D("B9 00 03 1D 00 40 49 D8"); + break; + } + + case 6: + { + ImpF3D("B9 00 03 1D 00 40 4D D8"); + break; + } + + case 7: + { + ImpF3D("B9 00 03 1D 00 40 45 D8"); + break; + } + } + + ImpF3D("B6 00 00 00 00 01 00 00"); // B6 00 00 00 00 01 02 00 --> Smoothen Shading? + } + + private byte GetTypeFromTexType(N64Codec texType, bool advanced = false) + { + switch (texType) + { + case N64Codec.CI4: + { + return Convert.ToByte(advanced ? 0x50 : 0x40); + } + + case N64Codec.CI8: + { + return Convert.ToByte(advanced ? 0x50 : 0x48); + } + + case N64Codec.I4: + { + return Convert.ToByte(advanced ? 0x90 : 0x80); + } + + case N64Codec.I8: + { + return Convert.ToByte(advanced ? 0x90 : 0x88); + } + + case N64Codec.IA4: + { + return Convert.ToByte(advanced ? 0x70 : 0x60); + } + + case N64Codec.IA8: + { + return Convert.ToByte(advanced ? 0x70 : 0x68); + } + + case N64Codec.IA16: + { + return 0x70; + } + + case N64Codec.RGBA16: + { + return 0x10; + } + + case N64Codec.RGBA32: + { + return 0x18; + } + + default: + { + return default; + } + } + } + + private byte BytesPerType(N64Codec type) + { + switch (type) + { + case N64Codec.RGBA16: + { + return 2; + } + + case N64Codec.RGBA32: + { + return 4; + } + + case N64Codec.I4: + case N64Codec.IA4: + case N64Codec.CI4: + { + return 0; // Special case + } + + case N64Codec.IA8: + case N64Codec.I8: + case N64Codec.CI8: + { + return 1; + } + + default: + { + return 2; + } + } + } + + private byte GetTexelIncrement(N64Codec type) + { + switch (type) + { + case N64Codec.I4: + case N64Codec.IA4: + { + return 3; + } + + case N64Codec.IA8: + case N64Codec.I8: + { + return 1; + } + + default: + { + return 0; + } + } + } + + private byte GetTexelShift(N64Codec type) + { + switch (type) + { + case N64Codec.I4: + case N64Codec.IA4: + case N64Codec.CI4: + { + return 2; + } + + case N64Codec.IA8: + case N64Codec.I8: + case N64Codec.CI8: + { + return 1; + } + + default: + { + return 0; + } + } + } + + private void ImpCmdFD(uint offset, N64Codec texType) + { + uint off = startSegOffset + offset; + byte type = GetTypeFromTexType(texType, true); + ImpF3D($"FD {Hex(type)} 00 00 {Hex(curSeg & 0xFF)} {Hex(off >> 16 & (long)0xFF)} {Hex(off >> 8 & (long)0xFF)} {Hex(off & (long)0xFF)}"); + } + + private void ImpCmdF5_First(N64Codec texType) + { + byte type = GetTypeFromTexType(texType, true); + ImpF3D($"F5 {Hex(type)} 00 00 07 00 00 00"); + } + + private void ImpCmdF5_Second(Material mat, uint texWidth, uint texHeight) + { + // Create upper + byte type = GetTypeFromTexType(mat.TexType); + float lineScale = 1.0F; + byte bpt = BytesPerType(mat.TexType); + if (bpt != 0) + { + lineScale = (float)(bpt / 4.0); + } + else + { + lineScale = 0.125F; + } + + if (mat.TexType == N64Codec.RGBA32) + { + lineScale /= 2; + } + + ushort line = Convert.ToUInt16(Convert.ToUInt16(Math.Truncate(texWidth * lineScale)) & 0x1FF); + uint upper = Convert.ToUInt32((Convert.ToUInt32(type) << 16 | Convert.ToUInt32(line) << 8) & (long)0xFFFFFF); + + // Create lower (shift) + byte maskS = Convert.ToByte(Convert.ToInt64(Math.Ceiling(Math.Log(texWidth, 2))) & 0xF); + byte maskT = Convert.ToByte(Convert.ToInt64(Math.Ceiling(Math.Log(texHeight, 2))) & 0xF); + uint lower = Convert.ToUInt32((Convert.ToUInt32(maskT) << 14 | Convert.ToUInt32(maskS) << 4) & (long)0xFFFFFF); // &HFFC3F0 for only shift + if (mat.EnableMirrorS) + { + lower = Convert.ToUInt32(lower | (long)0x100); // S axis + } + + if (mat.EnableMirrorT) + { + lower = Convert.ToUInt32(lower | (long)0x40000); // T axis + } + + if (mat.EnableClampS) + { + lower = Convert.ToUInt32(lower | (long)0x80000); // T axis + } + + if (mat.EnableClampT) + { + lower = Convert.ToUInt32(lower | (long)0x200); // S axis + } + + // Create Command + ImpF3D($"F5 {Hex(upper >> 16 & (long)0xFF)} {Hex(upper >> 8 & (long)0xFF)} {Hex(upper & (long)0xFF)} 00 {Hex(lower >> 16 & (long)0xFF)} {Hex(lower >> 8 & (long)0xFF)} {Hex(lower & (long)0xFF)}"); + } + + private void AddCmdF3(Material mat) + { + uint numTexels = (uint)((mat.TexWidth * mat.TexHeight + GetTexelIncrement(mat.TexType) >> GetTexelShift(mat.TexType)) - (long)1); + int bpt = BytesPerType(mat.TexType); + uint tl; + uint lower; + string cmd; + if (bpt != 0) + { + tl = Convert.ToUInt32(Operators.AndObject(CALC_DXT(mat.TexWidth, bpt), 4095)); + } + else + { + tl = Convert.ToUInt32(Operators.AndObject(CALC_DXT_4b(mat.TexWidth), 4095)); + } + + lower = Convert.ToUInt32((numTexels << 12 | tl) & (long)0xFFFFFF); + cmd = $"F3 00 00 00 07 {Hex(lower >> 16 & (long)0xFF)} {Hex(lower >> 8 & (long)0xFF)} {Hex(lower & (long)0xFF)}"; + ImpF3D(cmd); + } + + private void AddCmdF2(Material mat) + { + ushort width = Convert.ToUInt16(mat.TexWidth - (long)1 << 2 & 0xFFF); + ushort height = Convert.ToUInt16(mat.TexHeight - (long)1 << 2 & 0xFFF); + uint data = Convert.ToUInt32(Convert.ToInt32(width) << 12 | height); + string cmd = $"F2 00 00 00 00 {Hex(data >> 16 & (long)0xFF)} {Hex(data >> 8 & (long)0xFF)} {Hex(data & (long)0xFF)}"; + ImpF3D(cmd); + } + + private void AddCmdFC(Material mat, ref string lastCmd) + { + string cmd = string.Empty; + var colorFormula = Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.Formula.Output(Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.CCMUX.SHADE); + bool isColorPresent = Convert.ToDouble(Convert.ToString(mat.Color) + Convert.ToString(0xFFFFFF00U)) != 0xFFFFFF00U; + if (mat.HasTexture) + { + colorFormula = Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.Formula.Multiply(Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.CCMUX.TEXEL0, Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.CCMUX.SHADE); + } + else + { + var switchExpr1 = mat.Type; + switch (switchExpr1) + { + case MaterialType.None: + case MaterialType.TextureSolid: + case MaterialType.TextureAlpha: + case MaterialType.TextureTransparent: + { + colorFormula = Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.Formula.Output(Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.CCMUX.SHADE); + break; + } + + case MaterialType.ColorSolid: + case MaterialType.ColorTransparent: + { + if (isColorPresent) + { + colorFormula = Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.Formula.Multiply(Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.CCMUX.SHADE, Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.CCMUX.ENVIRONMENT); + } + else + { + colorFormula = Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.Formula.Output(Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.CCMUX.SHADE); + } + + break; + } + } + } + + var alphaFormula = Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.Formula.Output(Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.ACMUX.SHADE); + bool isTransPresent = Convert.ToDouble(Convert.ToString(mat.Color) + Convert.ToString(0xFFU)) != 0xFFU; + if (mat.HasTexture) + { + var switchExpr2 = mat.Type; + switch (switchExpr2) + { + case MaterialType.None: + case MaterialType.TextureSolid: + case MaterialType.ColorSolid: + { + alphaFormula = Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.Formula.Output(Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.ACMUX.ONE); + break; + } + + case MaterialType.TextureAlpha: + case MaterialType.TextureTransparent: + { + // With Fog multiplying SHADE is not something you want because it will be alpha fog so just output TEXEL0 and hope it is fine + if (settings.EnableFog) + { + alphaFormula = Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.Formula.Output(Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.ACMUX.TEXEL0); + } + else + { + alphaFormula = Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.Formula.Multiply((byte)Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.ACMUX.TEXEL0, (byte)Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.ACMUX.SHADE); + } + + break; + } + + case MaterialType.ColorTransparent: + { + if (isTransPresent) + { + alphaFormula = Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.Formula.Multiply((byte)Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.ACMUX.TEXEL0, (byte)Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.ACMUX.ENVIRONMENT); + } + else if (settings.EnableFog) + { + alphaFormula = Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.Formula.Output(Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.ACMUX.TEXEL0); + } + else + { + alphaFormula = Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.Formula.Multiply((byte)Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.ACMUX.TEXEL0, (byte)Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.ACMUX.SHADE); + } + + break; + } + } + } + else + { + var switchExpr3 = mat.Type; + switch (switchExpr3) + { + case MaterialType.None: + case MaterialType.TextureSolid: + case MaterialType.ColorSolid: + { + alphaFormula = Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.Formula.Output(Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.ACMUX.ONE); + break; + } + + case MaterialType.TextureAlpha: + case MaterialType.TextureTransparent: + { + // With Fog multiplying SHADE is not something you want because it will be alpha fog so just output TEXEL0 + if (settings.EnableFog) + { + alphaFormula = Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.Formula.Output(Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.ACMUX.ONE); + } + else + { + alphaFormula = Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.Formula.Output(Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.ACMUX.SHADE); + } + + break; + } + + case MaterialType.ColorTransparent: + { + if (isTransPresent) + { + // If there is no material, may as well provide more options for alpha modulate + if (settings.EnableFog) + { + alphaFormula = Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.Formula.Output(Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.ACMUX.ENVIRONMENT); + } + else + { + alphaFormula = Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.Formula.Multiply((byte)Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.ACMUX.ENVIRONMENT, (byte)Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.ACMUX.SHADE); + } + } + else if (settings.EnableFog) + { + alphaFormula = Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.Formula.Output(Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.ACMUX.ONE); + } + else + { + alphaFormula = Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.Formula.Output(Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.ACMUX.SHADE); + } + + break; + } + } + } + + cmd = Model.Fast3D.DisplayLists.Script.Commands.F3D_SETCOMBINE.Make(colorFormula, alphaFormula, settings.EnableFog); + if (!string.IsNullOrEmpty(cmd) && (lastCmd ?? "") != (cmd ?? "")) + { + ImpF3D(cmd); + lastCmd = cmd; + } + } + + private void ImpTriCmds(Material mat, FvGroup grp, int offset, ref bool enabledVertexColors) + { + if (grp.VertexDataCount < 3) + return; + uint off = (uint)(startSegOffset + offset); + int amount = grp.VertexDataCount * 0x10; + if (mat.EnableScrolling) + { + AddScrollingTexture(grp, Convert.ToInt32(off), Convert.ToInt32(mat.Offset), mat.Name); + } + + if (grp.EnableVertexColors) + { + if (!enabledVertexColors) + { + ImpF3D("B6 00 00 00 00 02 00 00"); + enabledVertexColors = true; + } + } + else if (enabledVertexColors) + { + ImpF3D("B7 00 00 00 00 02 00 00"); + enabledVertexColors = false; + } + + ImpF3D($"04 {Hex(amount - 0x10 & 0xFF)} 00 {Hex(amount & 0xFF)} {Hex(curSeg)} {Hex(off >> 16 & (long)0xFF)} {Hex(off >> 8 & (long)0xFF)} {Hex(off & (long)0xFF)}"); + for (int i = 0, loopTo = grp.NumTri - 1; i <= loopTo; i++) + { + byte a = Convert.ToByte(grp.indexList[i * 3] * 0xA); + byte b = Convert.ToByte(grp.indexList[i * 3 + 1] * 0xA); + byte c = Convert.ToByte(grp.indexList[i * 3 + 2] * 0xA); + ImpF3D($"BF 00 00 00 00 {Hex(a)} {Hex(b)} {Hex(c)}"); + } + } + + private void ResetCrystalEffectCommands(ref bool hasCrystalEffectEnabled, ref bool needToResetCrystalEffectCommands) + { + ImpF3D("B6 00 00 00 00 04 00 00"); + ImpF3D("BB 00 00 01 FF FF FF FF"); + hasCrystalEffectEnabled = false; + needToResetCrystalEffectCommands = false; + } + + private void ImpMaterialCmds(Material mat, ref bool hasCrystalEffectEnabled, ref bool needToResetCrystalEffectCommands, ref bool disabledBackfaceCulling) + { + if (mat.EnableCrystalEffect) + { + if (!hasCrystalEffectEnabled) + { + ImpF3D($"B7 00 00 00 00 04 00 00"); + ImpF3D("BB 00 00 01 08 00 08 00"); + hasCrystalEffectEnabled = true; + needToResetCrystalEffectCommands = true; + } + } + else if (needToResetCrystalEffectCommands) + { + ResetCrystalEffectCommands(ref hasCrystalEffectEnabled, ref needToResetCrystalEffectCommands); + } + + if (mat.HasPalette) + { + ImpCmdFD(mat.PaletteOffset, N64Codec.RGBA16); + ImpF3D("F5 00 01 00 01 00 00 00"); + ushort num = Convert.ToUInt16(Convert.ToInt64(mat.PaletteSize / (double)2 - 1) << 6); + ImpF3D($"F0 00 00 00 01 {Hex((num >> 8) & 0xFF)} {Hex(num & 0xFF)} 00"); + } + + if (((mat.FaceCullingMode & FaceCullingMode.Back) != FaceCullingMode.Back)) + { + if (!disabledBackfaceCulling) + { + ImpF3D($"B6 00 00 00 00 00 20 00"); // Disable back face culling + disabledBackfaceCulling = true; + } + } + else if (disabledBackfaceCulling) + { + ImpF3D($"B7 00 00 00 00 00 20 00"); // Enable back face culling + disabledBackfaceCulling = false; + } + + if (mat.HasTexture) + { + ImpCmdFD(mat.Offset, mat.TexType); + ImpCmdF5_First(mat.TexType); + ImpF3D("E6 00 00 00 00 00 00 00"); + AddCmdF3(mat); + ImpF3D("E7 00 00 00 00 00 00 00"); + ImpCmdF5_Second(mat, mat.TexWidth, mat.TexHeight); + AddCmdF2(mat); + } + } + + private void AddScrollingTexture(FvGroup grp, int vertPtr, int matAddr, string matName) + { + var scrollTex = new ScrollTex(Convert.ToInt32(curSeg) << 24 | vertPtr, Convert.ToByte(grp.VertexDataCount), matAddr, matName); + scrollTexts.Add(scrollTex); + } + + private void MergeScrollingTextures() + { + short curScrollingGroupID = 0; + var scrollingGroups = new Dictionary(); + scrollTexts = new List(scrollTexts.OrderBy(n => n.Offset)); + + short getScrollingGroup(int curMatAddr) + { + if (scrollingGroups.ContainsKey(curMatAddr)) + return scrollingGroups[curMatAddr]; + else + { + short newID = curScrollingGroupID; + scrollingGroups.Add(curMatAddr, newID); + curScrollingGroupID += 1; + return newID; + } + }; + + while (scrollTexts.Count > 0) + { + int startOff = scrollTexts[0].Offset; + int endOff = startOff + scrollTexts[0].VertsCount * 0x10; + int count = 0; + int curMatAddr = scrollTexts[0].MaterialAddress; + string curMatName = scrollTexts[0].MaterialName; + + foreach (ScrollTex st in scrollTexts) + { + if (st.MaterialAddress == curMatAddr) + { + if (st.Offset <= endOff) + { + if ((endOff - startOff) / (double)0x10 <= ushort.MaxValue) + { + int newEndOffset = st.Offset + st.VertsCount * 0x10; + endOff = newEndOffset; + } + else + break; + } + else if (st.Offset > endOff) + break; + + count += 1; + } + else + break; + } + + int vertsCount = (int)((endOff - startOff) / (double)0x10); + if (vertsCount > 0) + { + short groupID = getScrollingGroup(curMatAddr); + scrollTexts.RemoveRange(0, count); + conRes.ScrollingCommands.Add(new SM64Lib.Levels.ScrolTex.ManagedScrollingTexture(Convert.ToUInt16(vertsCount), startOff, groupID)); + conRes.ScrollingNames.AddIfNotContainsKey(groupID, curMatName); + } + } + } + + private void ImpColorCmdFB(Material mat) + { + byte r = Convert.ToByte(mat.Color >> 24 & (long)0xFF); + byte g = Convert.ToByte(mat.Color >> 16 & (long)0xFF); + byte b = Convert.ToByte(mat.Color >> 8 & (long)0xFF); + ImpF3D($"FB 00 00 00 {Hex(r)} {Hex(g)} {Hex(b)} {Hex(mat.Opacity)}"); + } + + private void AlignPosition() + { + impdata.RoundUpPosition(); + } + + /// + /// Adds a command that is requied on the end of a display list if CI textures are enabled + /// + private void SetOtherMode_H_Revert() + { + // Reset CI texture palette color format + ImpF3D("BA 00 0E 02 00 00 00 00"); + + // If it ever is required, then use this command instead. It also reverts the texture filter to "Bilerp". + //ImpF3D("BA 00 0C 04 00 00 20 00"); + } + + /// + /// Adds a command to enable CI textures + /// + private void SetOtherMode_H(Material mat, ref bool ciEnabled, ref bool nonDefaultFilter) + { + var citextypes = new[] { N64Codec.CI4, N64Codec.CI8 }; + var iscitexture = citextypes.Contains(mat.TexType); + var paletteColorStorageType = iscitexture ? PaletteColorStorageType.RGBA16 : PaletteColorStorageType.None; + + byte ss = 0xC; + byte nn = 0x4; + int options = 0; + + // G_MDSFT_TEXTLUT (Palette color storage type) + ciEnabled = iscitexture; + options |= ((int)paletteColorStorageType) << 0xE; + + // G_MDSFT_TEXTFILT (Texture Filter) + nonDefaultFilter = mat.TexFilter != TextureFilter.Bilerp; + options |= ((int)mat.TexFilter) << 0xC; + + // Normally we need to set "ss" to E for G_MDSFT_TEXTLUT and to C for G_MDSFT_TEXTFILT. + // Because it they are nearby the other, we can combine them, so set to the lower value C and increase "nn" by the difference (+2 = 4). + // This saves one command. Else it would be two commands, for each option one command. + impdata.Write(new byte[] { 0xBA, 0, ss, nn }); + impdata.Write(options); + } + + private void ImportObj(Pilz.S3DFileParser.Object3D model) + { + bool enabledVertexColors; + bool enableForcing = settings.ForceDisplaylist != -1; + uint importStart = 0; + uint startVerts = 0; + Material lastMaterial = null; + uint lastFBColor = default; + bool hasCrystalEffectEnabled, needToResetCrystalEffectCommands, disabledBackfaceCulling; + bool ciEnabled; + bool nonDefaultFilter; + string lastCmdFC; + var dlsToCreate = new List(); + var dicMatDlIDs = new Dictionary(); + ProcessObject3DModel(model); + conRes.PtrStart = Convert.ToUInt32((long)CurSegAddress | impdata.Position); + importStart = Convert.ToUInt32(impdata.Position); + + // Write default color + impdata.Write(defaultColor); + + // Remove duplicated textures + // FIXME: This function does not account for materials properties like Opacity + // MergeDuplicatedTextures() + + // Write materials + foreach (Material mt in materials) + { + if (mt.HasTexture) + { + mt.Offset = Convert.ToUInt32(impdata.Position); + impdata.Write(mt.Texture.Data); + AlignPosition(); + if (mt.HasPalette) + { + mt.PaletteOffset = Convert.ToUInt32(impdata.Position); + impdata.Write(mt.Texture.Palette); + AlignPosition(); + } + } + } + + // Prepaire vertices + BuildVertexGroups(); + removeDuplicateVertices(settings.ReduceVertLevel); + + // Write vertices + conRes.PtrVertex = Convert.ToUInt32((long)CurSegAddress | impdata.Position); + startVerts = Convert.ToUInt32(impdata.Position); + foreach (VertexGroupList mp in vertexGroups) + { + for (int g = 0; g < mp.GroupsCount; g++) + { + if (mp.FinalVertexGroups[g].VertexDataCount >= 1) + { + for (int i = 0; i < mp.FinalVertexGroups[g].VertexDataCount; i++) + { + var data = mp.FinalVertexGroups[g].FinalVertexData[i].Data; + impdata.Write(data); + } + } + } + } + + int createDefaultDL(Geolayout.DefaultGeolayers layerID) + { + DisplaylistProps dlProp = null; + int newLayerID = ((int)layerID + 1) * -1; + foreach (DisplaylistProps dl in dlsToCreate) + { + if (dlProp is null && dl.ID == newLayerID) + dlProp = dl; + } + + if (dlProp is null) + dlProp = new DisplaylistProps(newLayerID); + + dlProp.Layer = layerID; + if (!dlsToCreate.Contains(dlProp)) + dlsToCreate.Add(dlProp); + + return dlProp.ID; + }; + int createCustomDL(int dlID) + { + DisplaylistProps dlProp = null; + + // Search dlProp + foreach (var prop in settings.TextureFormatSettings.CustomDisplayLists) + { + if (dlProp is null && prop.ID == dlID) + dlProp = prop; + } + + if (!dlsToCreate.Contains(dlProp)) + dlsToCreate.Add(dlProp); + + return dlProp.ID; + }; + + // Check which DLs should be created + if (enableForcing) + { + int dlID = createDefaultDL((Geolayout.DefaultGeolayers)settings.ForceDisplaylist); + foreach (Material mat in materials) + dicMatDlIDs.Add(mat, dlID); + } + else + { + foreach (Material mat in materials) + { + int dlID = -1; + var switchExpr = mat.DisplaylistSelection.SelectionMode; + + switch (switchExpr) + { + case DisplaylistSelectionMode.Automatic: + if (mat.HasTransparency) + dlID = createDefaultDL(Geolayout.DefaultGeolayers.Translucent); + else if (mat.HasTextureAlpha) + dlID = createDefaultDL(Geolayout.DefaultGeolayers.Alpha); + else + dlID = createDefaultDL(Geolayout.DefaultGeolayers.Solid); + break; + case DisplaylistSelectionMode.Default: + dlID = createDefaultDL(mat.DisplaylistSelection.DefaultGeolayer); + break; + case DisplaylistSelectionMode.Custom: + dlID = createCustomDL(mat.DisplaylistSelection.CustomDisplaylistID); + break; + } + + dicMatDlIDs.Add(mat, dlID); + } + } + + // Create DLs + foreach (DisplaylistProps dlProps in dlsToCreate) + { + // Add Geopointer + conRes.PtrGeometry.Add(new Geolayout.Geopointer((byte)dlProps.Layer, Convert.ToInt32(CurSegAddress | impdata.Position))); + + // Reset some stuff + enabledVertexColors = false; + hasCrystalEffectEnabled = false; + needToResetCrystalEffectCommands = false; + disabledBackfaceCulling = false; + ciEnabled = false; + nonDefaultFilter = false; + lastMaterial = null; + lastFBColor = default; + lastCmdFC = string.Empty; + + // Create DL + ImpF3D("E7 00 00 00 00 00 00 00"); + if (settings.EnableFog) + ImpF3D("B9 00 02 01 00 00 00 00"); + ImpF3D("B7 00 00 00 00 00 00 00"); + ImpF3D("BB 00 00 01 FF FF FF FF"); + ImpF3D("E8 00 00 00 00 00 00 00"); + ImpF3D("E6 00 00 00 00 00 00 00"); + ImpF3D("03 88 00 10 0E 00 00 00"); + ImpF3D("03 86 00 10 0E 00 00 08"); + if (settings.EnableFog) + ImpFogStart((int)dlProps.Layer); + + for (int i = 0, loopTo2 = vertexGroups.Count - 1; i <= loopTo2; i++) + { + var mp = vertexGroups[i]; + if (dicMatDlIDs[mp.Material] != dlProps.ID) + continue; + + // Geomode + if (mp.Material.EnableGeoMode) + { + ImpF3D("B6 00 00 00 FF FF FF FF"); + ImpF3D($"B7 00 00 00 {Hex(mp.Material.GeoMode >> 24 & (long)0xFF)} {Hex(mp.Material.GeoMode >> 16 & (long)0xFF)} {Hex(mp.Material.GeoMode >> 8 & (long)0xFF)} {Hex(mp.Material.GeoMode & (long)0xFF)}"); + } + + if (lastMaterial != mp.Material) + { + lastMaterial = mp.Material; + + AddCmdFC(mp.Material, ref lastCmdFC); + if ((mp.Material.Type == MaterialType.ColorSolid || mp.Material.Type == MaterialType.ColorTransparent) && lastFBColor != mp.Material.Color) + ImpColorCmdFB(mp.Material); + SetOtherMode_H(mp.Material, ref ciEnabled, ref nonDefaultFilter); + ImpMaterialCmds(mp.Material, ref hasCrystalEffectEnabled, ref needToResetCrystalEffectCommands, ref disabledBackfaceCulling); + } + + int grpOff = 0; + for (int ii = 0, loopTo3 = mp.GroupsCount - 1; ii <= loopTo3; ii++) + { + ImpTriCmds(mp.Material, mp.FinalVertexGroups[ii], (int)(startVerts + (mp.StartIndex + grpOff)), ref enabledVertexColors); + grpOff += mp.FinalVertexGroups[ii].VertexDataCount * 0x10; + } + + if (mp.Material.EnableGeoMode) + { + if (i + 1 < vertexGroups.Count && vertexGroups[i + 1].Material.EnableGeoMode) + continue; + ImpF3D("B6 00 00 00 FF FF FF FF"); + ImpF3D("B7 00 00 00 00 02 20 05"); + } + } + + if (enabledVertexColors) + ImpF3D("B7 00 00 00 00 02 00 00"); + if (settings.EnableFog) + ImpFogEnd((int)dlProps.Layer); + ImpF3D("FC FF FF FF FF FE 79 3C"); + ImpF3D("BB 00 00 00 FF FF FF FF"); + if (needToResetCrystalEffectCommands) + ResetCrystalEffectCommands(ref hasCrystalEffectEnabled, ref needToResetCrystalEffectCommands); + if (ciEnabled /*|| nonDefaultFilter*/) + SetOtherMode_H_Revert(); + ImpF3D("B8 00 00 00 00 00 00 00"); + MergeScrollingTextures(); + } + + ResetVariables(); + } + + /// + /// Converts a Object3D to an N64 Model and an SM64 Collision. + /// + /// The stream where to write the Fast3D and Collision data. + /// The convert settings. + /// The input model. + /// + public ConvertResult ConvertModel(Stream s, ConvertSettings settings, Pilz.S3DFileParser.Object3D input) + { + this.settings = settings; + impdata = new Data.BinaryStreamData(s); + + // Segmented Address + if (settings.SegmentedAddress is not null) + { + startSegOffset = (uint)(settings.SegmentedAddress & 0xFFFFFF); + curSeg = (byte)(settings.SegmentedAddress >> 24 & 0xFF); + } + + // Shading + SetLightAndDarkValues(input.Shading); + + // Convert + ImportObj(input); + ResetVariables(); + return conRes; + } } \ No newline at end of file diff --git a/SM64Lib/Model/Fast3D/DisplayLists/DisplayList.cs b/SM64Lib/Model/Fast3D/DisplayLists/DisplayList.cs index 6c77bbd..ed1af8e 100644 --- a/SM64Lib/Model/Fast3D/DisplayLists/DisplayList.cs +++ b/SM64Lib/Model/Fast3D/DisplayLists/DisplayList.cs @@ -1,90 +1,89 @@ -using System; -using System.Threading.Tasks; -using global::Pilz.S3DFileParser; +using global::Pilz.S3DFileParser; using global::SM64Lib.Geolayout; using global::SM64Lib.Model.Fast3D.DisplayLists.Script; +using System; +using System.Threading.Tasks; -namespace SM64Lib.Model.Fast3D.DisplayLists +namespace SM64Lib.Model.Fast3D.DisplayLists; + +public class DisplayList { - public class DisplayList + public DisplayListScript Script { get; private set; } = new DisplayListScript(); + public Geopointer GeoPointer { get; set; } = null; + // Public Property Data As Stream = Nothing + + public DisplayList() { - public DisplayListScript Script { get; private set; } = new DisplayListScript(); - public Geopointer GeoPointer { get; set; } = null; - // Public Property Data As Stream = Nothing + } - public DisplayList() + public DisplayList(Geopointer gp) + { + GeoPointer = gp; + } + + public void TryFromStream(Geopointer gp, RomManager rommgr, byte? AreaID) + { + try { + FromStream(gp, rommgr, AreaID); } - - public DisplayList(Geopointer gp) + catch (Exception) { - GeoPointer = gp; - } - - public void TryFromStream(Geopointer gp, RomManager rommgr, byte? AreaID) - { - try - { - FromStream(gp, rommgr, AreaID); - } - catch (Exception) - { - } - } - - public Task TryFromStreamAsync(Geopointer gp, RomManager rommgr, byte? AreaID) - { - var t = new Task(() => TryFromStream(gp, rommgr, AreaID)); - t.Start(); - return t; - } - - public void FromStream(Geopointer gp, RomManager rommgr, byte? AreaID) - { - GeoPointer = gp; - Script.FromStream(rommgr, gp.SegPointer, AreaID); - } - - public Task FromStreamAsync(Geopointer gp, RomManager rommgr, byte? AreaID) - { - var t = new Task(() => FromStream(gp, rommgr, AreaID)); - t.Start(); - return t; - } - - public void TryToObject3D(Object3D obj, RomManager rommgr, byte? AreaID) - { - try - { - ToObject3D(obj, rommgr, AreaID); - } - catch (Exception) - { - } - } - - public Task TryToObject3DAsync(Object3D obj, RomManager rommgr, byte? AreaID) - { - var t = new Task(() => TryToObject3D(obj, rommgr, AreaID)); - t.Start(); - return t; - } - - public void ToObject3D(Object3D obj, RomManager rommgr, byte? AreaID) - { - Conversion.Fast3DParsing.Fast3DParser.Convert(obj, this, rommgr, AreaID); - } - - public Task ToObject3DAsync(Object3D obj, RomManager rommgr, byte? AreaID) - { - var t = new Task(() => ToObject3D(obj, rommgr, AreaID)); - t.Start(); - return t; - } - - public void Close() - { - Script.Close(); } } + + public Task TryFromStreamAsync(Geopointer gp, RomManager rommgr, byte? AreaID) + { + var t = new Task(() => TryFromStream(gp, rommgr, AreaID)); + t.Start(); + return t; + } + + public void FromStream(Geopointer gp, RomManager rommgr, byte? AreaID) + { + GeoPointer = gp; + Script.FromStream(rommgr, gp.SegPointer, AreaID); + } + + public Task FromStreamAsync(Geopointer gp, RomManager rommgr, byte? AreaID) + { + var t = new Task(() => FromStream(gp, rommgr, AreaID)); + t.Start(); + return t; + } + + public void TryToObject3D(Object3D obj, RomManager rommgr, byte? AreaID) + { + try + { + ToObject3D(obj, rommgr, AreaID); + } + catch (Exception) + { + } + } + + public Task TryToObject3DAsync(Object3D obj, RomManager rommgr, byte? AreaID) + { + var t = new Task(() => TryToObject3D(obj, rommgr, AreaID)); + t.Start(); + return t; + } + + public void ToObject3D(Object3D obj, RomManager rommgr, byte? AreaID) + { + Conversion.Fast3DParsing.Fast3DParser.Convert(obj, this, rommgr, AreaID); + } + + public Task ToObject3DAsync(Object3D obj, RomManager rommgr, byte? AreaID) + { + var t = new Task(() => ToObject3D(obj, rommgr, AreaID)); + t.Start(); + return t; + } + + public void Close() + { + Script.Close(); + } } \ No newline at end of file diff --git a/SM64Lib/Model/Fast3D/DisplayLists/DisplayListCollection.cs b/SM64Lib/Model/Fast3D/DisplayLists/DisplayListCollection.cs index 1a1282f..fcac548 100644 --- a/SM64Lib/Model/Fast3D/DisplayLists/DisplayListCollection.cs +++ b/SM64Lib/Model/Fast3D/DisplayLists/DisplayListCollection.cs @@ -1,28 +1,27 @@ -using System.Collections.Generic; -using global::Pilz.S3DFileParser; +using global::Pilz.S3DFileParser; +using System.Collections.Generic; -namespace SM64Lib.Model.Fast3D.DisplayLists +namespace SM64Lib.Model.Fast3D.DisplayLists; + +public class DisplayListCollection : List { - public class DisplayListCollection : List + public Object3D ToObject3D(RomManager rommgr, byte? AreaID) { - public Object3D ToObject3D(RomManager rommgr, byte? AreaID) - { - var obj = new Object3D(); - foreach (DisplayList dl in this) - dl.ToObject3D(obj, rommgr, AreaID); - return obj; - } + var obj = new Object3D(); + foreach (DisplayList dl in this) + dl.ToObject3D(obj, rommgr, AreaID); + return obj; + } - public new void Clear() - { - Close(); - base.Clear(); - } + public new void Clear() + { + Close(); + base.Clear(); + } - public void Close() - { - foreach (var dl in this) - dl.Close(); - } + public void Close() + { + foreach (var dl in this) + dl.Close(); } } \ No newline at end of file diff --git a/SM64Lib/Model/Fast3D/DisplayLists/Script/CommandTypes.cs b/SM64Lib/Model/Fast3D/DisplayLists/Script/CommandTypes.cs index 16c36cd..25a9f70 100644 --- a/SM64Lib/Model/Fast3D/DisplayLists/Script/CommandTypes.cs +++ b/SM64Lib/Model/Fast3D/DisplayLists/Script/CommandTypes.cs @@ -1,22 +1,21 @@  -namespace SM64Lib.Model.Fast3D.DisplayLists.Script +namespace SM64Lib.Model.Fast3D.DisplayLists.Script; + +public enum CommandTypes { - public enum CommandTypes - { - NOOP = 0x0, - Movemem = 0x3, - DisplayList = 0x6, - EndDisplaylist = 0xB8, - Vertex = 0x4, - SetOtherMode_H = 0xBA, - Triangle1 = 0xBF, - ClearGeometryMode = 0xB6, - SetGeometryMode = 0xB7, - Loadtlut = 0xF0, - SetTileSize = 0xF2, - SetImage = 0xFD, - Loadback = 0xF3, - SetTile = 0xF5, - Texture = 0xBB - } + NOOP = 0x0, + Movemem = 0x3, + DisplayList = 0x6, + EndDisplaylist = 0xB8, + Vertex = 0x4, + SetOtherMode_H = 0xBA, + Triangle1 = 0xBF, + ClearGeometryMode = 0xB6, + SetGeometryMode = 0xB7, + Loadtlut = 0xF0, + SetTileSize = 0xF2, + SetImage = 0xFD, + Loadback = 0xF3, + SetTile = 0xF5, + Texture = 0xBB } \ No newline at end of file diff --git a/SM64Lib/Model/Fast3D/DisplayLists/Script/Commands.cs b/SM64Lib/Model/Fast3D/DisplayLists/Script/Commands.cs index 8794fe7..dd82ba0 100644 --- a/SM64Lib/Model/Fast3D/DisplayLists/Script/Commands.cs +++ b/SM64Lib/Model/Fast3D/DisplayLists/Script/Commands.cs @@ -1,486 +1,484 @@ -using System; -using global::System.Drawing; +using global::System.Drawing; using global::System.Numerics; -using Microsoft.VisualBasic.CompilerServices; +using System; -namespace SM64Lib.Model.Fast3D.DisplayLists.Script.Commands +namespace SM64Lib.Model.Fast3D.DisplayLists.Script.Commands; + +public class F3D_VTX { - public class F3D_VTX + public static byte GetNumberOfVertices(DisplayListCommand cmd) { - public static byte GetNumberOfVertices(DisplayListCommand cmd) - { - cmd.Position = 1; - byte value = cmd.ReadByte(); - cmd.Position = 0; - return (byte)(value >> 4); - } + cmd.Position = 1; + byte value = cmd.ReadByte(); + cmd.Position = 0; + return (byte)(value >> 4); + } - public static byte GetStartIndexInVertexBuffer(DisplayListCommand cmd) - { - cmd.Position = 1; - byte value = cmd.ReadByte(); - cmd.Position = 0; - return Convert.ToByte(value & 0xF); - } + public static byte GetStartIndexInVertexBuffer(DisplayListCommand cmd) + { + cmd.Position = 1; + byte value = cmd.ReadByte(); + cmd.Position = 0; + return Convert.ToByte(value & 0xF); + } - public static short GetLengthOfVertexData(DisplayListCommand cmd) - { - cmd.Position = 2; - short value = cmd.ReadInt16(); - cmd.Position = 0; - return value; - } + public static short GetLengthOfVertexData(DisplayListCommand cmd) + { + cmd.Position = 2; + short value = cmd.ReadInt16(); + cmd.Position = 0; + return value; + } - public static int GetSegmentedAddress(DisplayListCommand cmd) - { - cmd.Position = 4; - int value = cmd.ReadInt32(); - cmd.Position = 0; - return value; - } + public static int GetSegmentedAddress(DisplayListCommand cmd) + { + cmd.Position = 4; + int value = cmd.ReadInt32(); + cmd.Position = 0; + return value; + } - public static void SetSegmentedAddress(DisplayListCommand cmd, int value) + public static void SetSegmentedAddress(DisplayListCommand cmd, int value) + { + cmd.Position = 4; + cmd.Write(value); + cmd.Position = 0; + } +} + +public class F3D_TRI1 +{ + public static byte GetVertice(DisplayListCommand cmd, byte VerticeNumber) + { + cmd.Position = 5 + VerticeNumber - 1; + byte value = cmd.ReadByte(); + cmd.Position = 0; + if (value > 0) + value = (byte)(value / (double)0xA); + return value; + } +} + +public class F3D_SETTILE +{ + public static N64Graphics.N64Codec GetTextureFormat(DisplayListCommand cmd) + { + cmd.Position = 1; + byte type = cmd.ReadByte(); + cmd.Position = 0; + switch (type) { - cmd.Position = 4; - cmd.Write(value); - cmd.Position = 0; + case 0x10: + { + return N64Graphics.N64Codec.RGBA16; + } + + case 0x18: + { + return N64Graphics.N64Codec.RGBA32; + } + + case 0x40: + { + return N64Graphics.N64Codec.CI4; + } + + case 0x48: + { + return N64Graphics.N64Codec.CI8; + } + + case 0x60: + { + return N64Graphics.N64Codec.IA4; + } + + case 0x68: + { + return N64Graphics.N64Codec.IA8; + } + + case 0x70: + { + return N64Graphics.N64Codec.IA16; + } + + case 0x80: + case 0x90: + { + return N64Graphics.N64Codec.I4; + } + + case 0x88: + { + return N64Graphics.N64Codec.I8; + } + + default: + { + return default; + } } } - public class F3D_TRI1 + public static byte GetWrapT(DisplayListCommand cmd) { - public static byte GetVertice(DisplayListCommand cmd, byte VerticeNumber) + cmd.Position = 5; + byte val = cmd.ReadByte(); + cmd.Position = 0; + return Convert.ToByte((val >> 2) & 0x2); + } + + public static byte GetWrapS(DisplayListCommand cmd) + { + cmd.Position = 6; + byte val = cmd.ReadByte(); + cmd.Position = 0; + return Convert.ToByte(val & 0x2); + } +} + +public class F3D_TEXTURE +{ + public static Size GetTextureSize(DisplayListCommand cmd) + { + cmd.Position = 4; + ushort tsX = cmd.ReadUInt16(); + ushort tsY = cmd.ReadUInt16(); + cmd.Position = 0; + tsX = (ushort)(tsX >> 6); + if (tsX == 31) { - cmd.Position = 5 + VerticeNumber - 1; - byte value = cmd.ReadByte(); - cmd.Position = 0; - if (value > 0) - value = (byte)(value / (double)0xA); - return value; + tsX = 32; + } + else if (tsX == 62) + { + tsX = 64; + } + + tsY = (ushort)(tsY >> 6); + if (tsY == 31) + { + tsY = 32; + } + else if (tsY == 62) + { + tsY = 64; + } + + return new Size(tsX, tsY); + } + + public static Vector2 GetTextureScaling(DisplayListCommand cmd) + { + cmd.Position = 4; + ushort tsX = cmd.ReadUInt16(); + ushort tsY = cmd.ReadUInt16(); + cmd.Position = 0; + var vec = new Vector2(); + if (tsX != 0xFFFF) + { + vec.X = tsX / 65536.0F; + } + else + { + vec.X = 1.0F; + } + + if (tsY != 0xFFFF) + { + vec.Y = tsY / 65536.0F; + } + else + { + vec.Y = 1.0F; + } + + return vec; + } +} + +public class F3D_SETIMG +{ + public static int GetSegmentedAddress(DisplayListCommand cmd) + { + cmd.Position = 4; + int value = cmd.ReadInt32(); + cmd.Position = 0; + return value; + } + + public static void SetSegmentedAddress(DisplayListCommand cmd, int value) + { + cmd.Position = 4; + cmd.Write(value); + cmd.Position = 0; + } + + public static ColorFormat GetColorFormat(DisplayListCommand cmd) + { + cmd.Position = 1; + byte val = cmd.ReadByte(); + cmd.Position = 0; + return (ColorFormat)(val >> 5); + } + + public static BitSize GetBitSize(DisplayListCommand cmd) + { + cmd.Position = 1; + byte val = cmd.ReadByte(); + cmd.Position = 0; + return (BitSize)(val >> 3 & 0x3); + } + + public enum ColorFormat : byte + { + /// + /// Color and alpha + /// + RGBA = 0, + /// + /// Luminance and Chrominance + /// + YUV = 1, + /// + /// Index and look-up palette + /// + CI = 2, + /// + /// Grayscale and alpha + /// + IA = 3, + /// + /// Grayscale + /// + I = 4 + } + + public enum BitSize : byte + { + _4 = 0, + _8 = 1, + _16 = 2, + _32 = 3 + } +} + +public class F3D_SETTILESIZE +{ + public static Size GetSize(DisplayListCommand cmd) + { + cmd.Position = 4; + int var = cmd.ReadInt32(); + cmd.Position = 0; + short w = Convert.ToInt16(var >> 12 & 0xFFF); + short h = Convert.ToInt16(var & 0xFFF); + w = Convert.ToInt16((w >> 2) + 1); + h = Convert.ToInt16((h >> 2) + 1); + return new Size(w, h); + } + + public static void SetSize(DisplayListCommand cmd, Size size) + { + int w = size.Width; + int h = size.Height; + w = w - 1 << 2; + h = h - 1 << 2; + int var = w << 12 | h; + cmd.Position = 4; + cmd.Write(var); + cmd.Position = 0; + } +} + +public class F3D_MOVEMEM +{ + public static int GetSegmentedOffset(DisplayListCommand cmd) + { + cmd.Position = 4; + int value = cmd.ReadInt32(); + cmd.Position = 0; + return value; + } + + public static void SetSegmentedOffset(DisplayListCommand cmd, int value) + { + cmd.Position = 4; + cmd.Write(value); + cmd.Position = 0; + } + + public static byte GetLightValueMode(DisplayListCommand cmd) + { + cmd.Position = 1; + byte value = cmd.ReadByte(); + cmd.Position = 0; + return value; + } +} + +public class F3D_CLEARGEOMETRYMODE +{ + public static uint GetGeometryMode(DisplayListCommand cmd) + { + cmd.Position = 4; + uint flag = cmd.ReadUInt32(); + cmd.Position = 0; + return flag; + } +} + +public class F3D_SETRGEOMETRYMODE : F3D_CLEARGEOMETRYMODE +{ +} + +public class F3D_SETOTHERMODE_H +{ + public static uint GetModeBits(DisplayListCommand cmd) + { + cmd.Position = 4; + uint bits = cmd.ReadUInt32(); + cmd.Position = 0; + return bits; + } +} + +public class F3D_SETCOMBINE +{ + public enum CCMUX : byte + { + COMBINED = 0, + TEXEL0, + TEXEL1, + PRIMITIVE, + SHADE, + ENVIRONMENT, + CENTER, + COMBINED_ALPHA, + TEXEL0_ALPHA, + TEXEL1_ALPHA, + PRIMITIVE_ALPHA, + SHADE_ALPHA, + ENV_ALPHA, + LOD_FRACTION, + PRIM_LOD_FRAC, + SCALE = 6, + NOISE = 7, + K4 = 7, + K5 = 15, + ONE = 6, + ZERO = 31 + } + + public enum ACMUX : byte + { + COMBINED = 0, + TEXEL0, + TEXEL1, + PRIMITIVE, + SHADE, + ENVIRONMENT, + PRIM_LOD_FRAC, + ONE = 6, + ZERO = 7, + LOD_FRACTION = 0 + } + + public class Formula + { + public readonly byte a; + public readonly byte b; + public readonly byte c; + public readonly byte d; + + public Formula(byte a, byte b, byte c, byte d) // CC formula is (a - b) * c + d + { + this.a = a; + this.b = b; + this.c = c; + this.d = d; + } + + public static Formula Output(CCMUX a) + { + return new Formula((byte)CCMUX.ZERO, (byte)CCMUX.ZERO, (byte)CCMUX.ZERO, (byte)a); // (0 - 0) * 0 + a = a + } + + public static Formula Output(ACMUX a) + { + return new Formula((byte)ACMUX.ZERO, (byte)ACMUX.ZERO, (byte)ACMUX.ZERO, (byte)a); + } + + public static Formula Multiply(CCMUX a, CCMUX b) + { + return new Formula((byte)a, (byte)CCMUX.ZERO, (byte)b, (byte)CCMUX.ZERO); // (a - 0) * b + 0 = a * b + } + + public static Formula Multiply(byte a, byte b) + { + return new Formula(a, (byte)ACMUX.ZERO, b, (byte)ACMUX.ZERO); // (a - 0) * b + 0 = a * b } } - public class F3D_SETTILE + private static uint _SHIFTL(uint v, uint s, uint w) { - public static N64Graphics.N64Codec GetTextureFormat(DisplayListCommand cmd) + return Convert.ToUInt32((v & (1 << Convert.ToInt32(w)) - 1) << Convert.ToInt32(s)); + } + + private static uint GCCc0w0(uint saRGB0, uint mRGB0, uint saA0, uint mA0) + { + return _SHIFTL(saRGB0, 20, 4) | _SHIFTL(mRGB0, 15, 5) | _SHIFTL(saA0, 12, 3) | _SHIFTL(mA0, 9, 3); + } + + private static uint GCCc1w0(uint saRGB1, uint mRGB1) + { + return _SHIFTL(saRGB1, 5, 4) | _SHIFTL(mRGB1, 0, 5); + } + + private static uint GCCc0w1(uint sbRGB0, uint aRGB0, uint sbA0, uint aA0) + { + return _SHIFTL(sbRGB0, 28, 4) | _SHIFTL(aRGB0, 15, 3) | _SHIFTL(sbA0, 12, 3) | _SHIFTL(aA0, 9, 3); + } + + private static uint GCCc1w1(uint sbRGB1, uint saA1, uint mA1, uint aRGB1, uint sbA1, uint aA1) + { + return _SHIFTL(sbRGB1, 24, 4) | _SHIFTL(saA1, 21, 3) | _SHIFTL(mA1, 18, 3) | _SHIFTL(aRGB1, 6, 3) | _SHIFTL(sbA1, 3, 3) | _SHIFTL(aA1, 0, 3); + } + + // For Jabo plugin you can't specify anything you want for 2nd cycle, only combined or the same as previous :( + public static string Make(Formula color, Formula alpha, bool isFog) + { + if (!isFog) { - cmd.Position = 1; - byte type = cmd.ReadByte(); - cmd.Position = 0; - switch (type) - { - case 0x10: - { - return N64Graphics.N64Codec.RGBA16; - } - - case 0x18: - { - return N64Graphics.N64Codec.RGBA32; - } - - case 0x40: - { - return N64Graphics.N64Codec.CI4; - } - - case 0x48: - { - return N64Graphics.N64Codec.CI8; - } - - case 0x60: - { - return N64Graphics.N64Codec.IA4; - } - - case 0x68: - { - return N64Graphics.N64Codec.IA8; - } - - case 0x70: - { - return N64Graphics.N64Codec.IA16; - } - - case 0x80: - case 0x90: - { - return N64Graphics.N64Codec.I4; - } - - case 0x88: - { - return N64Graphics.N64Codec.I8; - } - - default: - { - return default; - } - } + return Make(color, alpha, color, alpha); } - - public static byte GetWrapT(DisplayListCommand cmd) + else { - cmd.Position = 5; - byte val = cmd.ReadByte(); - cmd.Position = 0; - return Convert.ToByte((val >> 2) & 0x2); - } - - public static byte GetWrapS(DisplayListCommand cmd) - { - cmd.Position = 6; - byte val = cmd.ReadByte(); - cmd.Position = 0; - return Convert.ToByte(val & 0x2); + return Make(color, alpha, Formula.Output(CCMUX.COMBINED), Formula.Output(ACMUX.COMBINED)); } } - public class F3D_TEXTURE + // TODO: Let user specify custom combiner with this + public static string Make(Formula color0, Formula alpha0, Formula color1, Formula alpha1) { - public static Size GetTextureSize(DisplayListCommand cmd) - { - cmd.Position = 4; - ushort tsX = cmd.ReadUInt16(); - ushort tsY = cmd.ReadUInt16(); - cmd.Position = 0; - tsX = (ushort)(tsX >> 6); - if (tsX == 31) - { - tsX = 32; - } - else if (tsX == 62) - { - tsX = 64; - } - - tsY = (ushort)(tsY >> 6); - if (tsY == 31) - { - tsY = 32; - } - else if (tsY == 62) - { - tsY = 64; - } - - return new Size(tsX, tsY); - } - - public static Vector2 GetTextureScaling(DisplayListCommand cmd) - { - cmd.Position = 4; - ushort tsX = cmd.ReadUInt16(); - ushort tsY = cmd.ReadUInt16(); - cmd.Position = 0; - var vec = new Vector2(); - if (tsX != 0xFFFF) - { - vec.X = tsX / 65536.0F; - } - else - { - vec.X = 1.0F; - } - - if (tsY != 0xFFFF) - { - vec.Y = tsY / 65536.0F; - } - else - { - vec.Y = 1.0F; - } - - return vec; - } + return Make((CCMUX)color0.a, (CCMUX)color0.b, (CCMUX)color0.c, (CCMUX)color0.d, (ACMUX)alpha0.a, (ACMUX)alpha0.b, (ACMUX)alpha0.c, (ACMUX)alpha0.d, (CCMUX)color1.a, (CCMUX)color1.b, (CCMUX)color1.c, (CCMUX)color1.d, (ACMUX)alpha1.a, (ACMUX)alpha1.b, (ACMUX)alpha1.c, (ACMUX)alpha1.d); } - public class F3D_SETIMG + private static string Make(CCMUX a0, CCMUX b0, CCMUX c0, CCMUX d0, ACMUX Aa0, ACMUX Ab0, ACMUX Ac0, ACMUX Ad0, CCMUX a1, CCMUX b1, CCMUX c1, CCMUX d1, ACMUX Aa1, ACMUX Ab1, ACMUX Ac1, ACMUX Ad1) { - public static int GetSegmentedAddress(DisplayListCommand cmd) - { - cmd.Position = 4; - int value = cmd.ReadInt32(); - cmd.Position = 0; - return value; - } - - public static void SetSegmentedAddress(DisplayListCommand cmd, int value) - { - cmd.Position = 4; - cmd.Write(value); - cmd.Position = 0; - } - - public static ColorFormat GetColorFormat(DisplayListCommand cmd) - { - cmd.Position = 1; - byte val = cmd.ReadByte(); - cmd.Position = 0; - return (ColorFormat)(val >> 5); - } - - public static BitSize GetBitSize(DisplayListCommand cmd) - { - cmd.Position = 1; - byte val = cmd.ReadByte(); - cmd.Position = 0; - return (BitSize)(val >> 3 & 0x3); - } - - public enum ColorFormat : byte - { - /// - /// Color and alpha - /// - RGBA = 0, - /// - /// Luminance and Chrominance - /// - YUV = 1, - /// - /// Index and look-up palette - /// - CI = 2, - /// - /// Grayscale and alpha - /// - IA = 3, - /// - /// Grayscale - /// - I = 4 - } - - public enum BitSize : byte - { - _4 = 0, - _8 = 1, - _16 = 2, - _32 = 3 - } - } - - public class F3D_SETTILESIZE - { - public static Size GetSize(DisplayListCommand cmd) - { - cmd.Position = 4; - int var = cmd.ReadInt32(); - cmd.Position = 0; - short w = Convert.ToInt16(var >> 12 & 0xFFF); - short h = Convert.ToInt16(var & 0xFFF); - w = Convert.ToInt16((w >> 2) + 1); - h = Convert.ToInt16((h >> 2) + 1); - return new Size(w, h); - } - - public static void SetSize(DisplayListCommand cmd, Size size) - { - int w = size.Width; - int h = size.Height; - w = w - 1 << 2; - h = h - 1 << 2; - int var = w << 12 | h; - cmd.Position = 4; - cmd.Write(var); - cmd.Position = 0; - } - } - - public class F3D_MOVEMEM - { - public static int GetSegmentedOffset(DisplayListCommand cmd) - { - cmd.Position = 4; - int value = cmd.ReadInt32(); - cmd.Position = 0; - return value; - } - - public static void SetSegmentedOffset(DisplayListCommand cmd, int value) - { - cmd.Position = 4; - cmd.Write(value); - cmd.Position = 0; - } - - public static byte GetLightValueMode(DisplayListCommand cmd) - { - cmd.Position = 1; - byte value = cmd.ReadByte(); - cmd.Position = 0; - return value; - } - } - - public class F3D_CLEARGEOMETRYMODE - { - public static uint GetGeometryMode(DisplayListCommand cmd) - { - cmd.Position = 4; - uint flag = cmd.ReadUInt32(); - cmd.Position = 0; - return flag; - } - } - - public class F3D_SETRGEOMETRYMODE : F3D_CLEARGEOMETRYMODE - { - } - - public class F3D_SETOTHERMODE_H - { - public static uint GetModeBits(DisplayListCommand cmd) - { - cmd.Position = 4; - uint bits = cmd.ReadUInt32(); - cmd.Position = 0; - return bits; - } - } - - public class F3D_SETCOMBINE - { - public enum CCMUX : byte - { - COMBINED = 0, - TEXEL0, - TEXEL1, - PRIMITIVE, - SHADE, - ENVIRONMENT, - CENTER, - COMBINED_ALPHA, - TEXEL0_ALPHA, - TEXEL1_ALPHA, - PRIMITIVE_ALPHA, - SHADE_ALPHA, - ENV_ALPHA, - LOD_FRACTION, - PRIM_LOD_FRAC, - SCALE = 6, - NOISE = 7, - K4 = 7, - K5 = 15, - ONE = 6, - ZERO = 31 - } - - public enum ACMUX : byte - { - COMBINED = 0, - TEXEL0, - TEXEL1, - PRIMITIVE, - SHADE, - ENVIRONMENT, - PRIM_LOD_FRAC, - ONE = 6, - ZERO = 7, - LOD_FRACTION = 0 - } - - public class Formula - { - public readonly byte a; - public readonly byte b; - public readonly byte c; - public readonly byte d; - - public Formula(byte a, byte b, byte c, byte d) // CC formula is (a - b) * c + d - { - this.a = a; - this.b = b; - this.c = c; - this.d = d; - } - - public static Formula Output(CCMUX a) - { - return new Formula((byte)CCMUX.ZERO, (byte)CCMUX.ZERO, (byte)CCMUX.ZERO, (byte)a); // (0 - 0) * 0 + a = a - } - - public static Formula Output(ACMUX a) - { - return new Formula((byte)ACMUX.ZERO, (byte)ACMUX.ZERO, (byte)ACMUX.ZERO, (byte)a); - } - - public static Formula Multiply(CCMUX a, CCMUX b) - { - return new Formula((byte)a, (byte)CCMUX.ZERO, (byte)b, (byte)CCMUX.ZERO); // (a - 0) * b + 0 = a * b - } - - public static Formula Multiply(byte a, byte b) - { - return new Formula(a, (byte)ACMUX.ZERO, b, (byte)ACMUX.ZERO); // (a - 0) * b + 0 = a * b - } - } - - private static uint _SHIFTL(uint v, uint s, uint w) - { - return Convert.ToUInt32((v & (1 << Convert.ToInt32(w)) - 1) << Convert.ToInt32(s)); - } - - private static uint GCCc0w0(uint saRGB0, uint mRGB0, uint saA0, uint mA0) - { - return _SHIFTL(saRGB0, 20, 4) | _SHIFTL(mRGB0, 15, 5) | _SHIFTL(saA0, 12, 3) | _SHIFTL(mA0, 9, 3); - } - - private static uint GCCc1w0(uint saRGB1, uint mRGB1) - { - return _SHIFTL(saRGB1, 5, 4) | _SHIFTL(mRGB1, 0, 5); - } - - private static uint GCCc0w1(uint sbRGB0, uint aRGB0, uint sbA0, uint aA0) - { - return _SHIFTL(sbRGB0, 28, 4) | _SHIFTL(aRGB0, 15, 3) | _SHIFTL(sbA0, 12, 3) | _SHIFTL(aA0, 9, 3); - } - - private static uint GCCc1w1(uint sbRGB1, uint saA1, uint mA1, uint aRGB1, uint sbA1, uint aA1) - { - return _SHIFTL(sbRGB1, 24, 4) | _SHIFTL(saA1, 21, 3) | _SHIFTL(mA1, 18, 3) | _SHIFTL(aRGB1, 6, 3) | _SHIFTL(sbA1, 3, 3) | _SHIFTL(aA1, 0, 3); - } - - // For Jabo plugin you can't specify anything you want for 2nd cycle, only combined or the same as previous :( - public static string Make(Formula color, Formula alpha, bool isFog) - { - if (!isFog) - { - return Make(color, alpha, color, alpha); - } - else - { - return Make(color, alpha, Formula.Output(CCMUX.COMBINED), Formula.Output(ACMUX.COMBINED)); - } - } - - // TODO: Let user specify custom combiner with this - public static string Make(Formula color0, Formula alpha0, Formula color1, Formula alpha1) - { - return Make((CCMUX)color0.a, (CCMUX)color0.b, (CCMUX)color0.c, (CCMUX)color0.d, (ACMUX)alpha0.a, (ACMUX)alpha0.b, (ACMUX)alpha0.c, (ACMUX)alpha0.d, (CCMUX)color1.a, (CCMUX)color1.b, (CCMUX)color1.c, (CCMUX)color1.d, (ACMUX)alpha1.a, (ACMUX)alpha1.b, (ACMUX)alpha1.c, (ACMUX)alpha1.d); - } - - private static string Make(CCMUX a0, CCMUX b0, CCMUX c0, CCMUX d0, ACMUX Aa0, ACMUX Ab0, ACMUX Ac0, ACMUX Ad0, CCMUX a1, CCMUX b1, CCMUX c1, CCMUX d1, ACMUX Aa1, ACMUX Ab1, ACMUX Ac1, ACMUX Ad1) - { - uint w0 = _SHIFTL(0xFC, 24, 8) | _SHIFTL(GCCc0w0((uint)a0, (uint)c0, (uint)Aa0, (uint)Ac0) | GCCc1w0((uint)a1, (uint)c1), 0, 24); - uint w1 = GCCc0w1((uint)b0, (uint)d0, (uint)Ab0, (uint)Ad0) | GCCc1w1((uint)b1, (uint)Aa1, (uint)Ac1, (uint)d1, (uint)Ab1, (uint)Ad1); - var w0bytes = BitConverter.GetBytes(w0); - var w1bytes = BitConverter.GetBytes(w1); - // Little endian assumed - string ret = w0bytes[3].ToString("X"); - ret += " " + w0bytes[2].ToString("X"); - ret += " " + w0bytes[1].ToString("X"); - ret += " " + w0bytes[0].ToString("X"); - ret += " " + w1bytes[3].ToString("X"); - ret += " " + w1bytes[2].ToString("X"); - ret += " " + w1bytes[1].ToString("X"); - ret += " " + w1bytes[0].ToString("X"); - return ret; - } + uint w0 = _SHIFTL(0xFC, 24, 8) | _SHIFTL(GCCc0w0((uint)a0, (uint)c0, (uint)Aa0, (uint)Ac0) | GCCc1w0((uint)a1, (uint)c1), 0, 24); + uint w1 = GCCc0w1((uint)b0, (uint)d0, (uint)Ab0, (uint)Ad0) | GCCc1w1((uint)b1, (uint)Aa1, (uint)Ac1, (uint)d1, (uint)Ab1, (uint)Ad1); + var w0bytes = BitConverter.GetBytes(w0); + var w1bytes = BitConverter.GetBytes(w1); + // Little endian assumed + string ret = w0bytes[3].ToString("X"); + ret += " " + w0bytes[2].ToString("X"); + ret += " " + w0bytes[1].ToString("X"); + ret += " " + w0bytes[0].ToString("X"); + ret += " " + w1bytes[3].ToString("X"); + ret += " " + w1bytes[2].ToString("X"); + ret += " " + w1bytes[1].ToString("X"); + ret += " " + w1bytes[0].ToString("X"); + return ret; } } \ No newline at end of file diff --git a/SM64Lib/Model/Fast3D/DisplayLists/Script/DisplayListCommand.cs b/SM64Lib/Model/Fast3D/DisplayLists/Script/DisplayListCommand.cs index 1f9d0a2..6d8c640 100644 --- a/SM64Lib/Model/Fast3D/DisplayLists/Script/DisplayListCommand.cs +++ b/SM64Lib/Model/Fast3D/DisplayLists/Script/DisplayListCommand.cs @@ -1,59 +1,57 @@ -using System; +using global::SM64Lib.Script; using global::System.IO; +using System; using System.Linq; -using Microsoft.VisualBasic; -using global::SM64Lib.Script; -namespace SM64Lib.Model.Fast3D.DisplayLists.Script +namespace SM64Lib.Model.Fast3D.DisplayLists.Script; + +public class DisplayListCommand : Data.BinaryStreamData, ICommand { - public class DisplayListCommand : Data.BinaryStreamData, ICommand + public CommandTypes CommandType { get; set; } = CommandTypes.EndDisplaylist; + public int RomAddress { get; set; } = 0; + public int BankAddress { get; set; } = 0; + + public bool IsDirty { - public CommandTypes CommandType { get; set; } = CommandTypes.EndDisplaylist; - public int RomAddress { get; set; } = 0; - public int BankAddress { get; set; } = 0; - - public bool IsDirty + get { - get - { - throw new NotImplementedException(); - } - } - - private DisplayListCommand() : base(new MemoryStream()) - { - } - - public DisplayListCommand(byte CommandType) : this() - { - this.CommandType = (CommandTypes)CommandType; - SetLength(0x8); - Position = 0; - WriteByte(CommandType); - Position = 0; - } - - public DisplayListCommand(string CommandType) : this(Convert.ToByte(CommandType, 16)) - { - } - - public DisplayListCommand(byte[] bytes) : this() - { - CommandType = (CommandTypes)bytes[0]; - SetLength(bytes.Count()); - foreach (var b in bytes) - WriteByte(b); - Position = 0; - } - - public override string ToString() - { - return $"{RomAddress.ToString("X")} ({BankAddress.ToString("X")}): {General.CommandByteArrayToString(ToArray())}"; - } - - public byte[] ToArray() - { - return ((MemoryStream)BaseStream).ToArray(); + throw new NotImplementedException(); } } + + private DisplayListCommand() : base(new MemoryStream()) + { + } + + public DisplayListCommand(byte CommandType) : this() + { + this.CommandType = (CommandTypes)CommandType; + SetLength(0x8); + Position = 0; + WriteByte(CommandType); + Position = 0; + } + + public DisplayListCommand(string CommandType) : this(Convert.ToByte(CommandType, 16)) + { + } + + public DisplayListCommand(byte[] bytes) : this() + { + CommandType = (CommandTypes)bytes[0]; + SetLength(bytes.Count()); + foreach (var b in bytes) + WriteByte(b); + Position = 0; + } + + public override string ToString() + { + return $"{RomAddress.ToString("X")} ({BankAddress.ToString("X")}): {General.CommandByteArrayToString(ToArray())}"; + } + + public byte[] ToArray() + { + return ((MemoryStream)BaseStream).ToArray(); + } } \ No newline at end of file diff --git a/SM64Lib/Model/Fast3D/DisplayLists/Script/DisplayListScript.cs b/SM64Lib/Model/Fast3D/DisplayLists/Script/DisplayListScript.cs index 5cf9485..053100b 100644 --- a/SM64Lib/Model/Fast3D/DisplayLists/Script/DisplayListScript.cs +++ b/SM64Lib/Model/Fast3D/DisplayLists/Script/DisplayListScript.cs @@ -1,119 +1,117 @@ -using System.Collections.Generic; +using global::SM64Lib.SegmentedBanking; using global::System.IO; -using Microsoft.VisualBasic.CompilerServices; -using global::SM64Lib.SegmentedBanking; using SM64Lib.Data; using System; +using System.Collections.Generic; -namespace SM64Lib.Model.Fast3D.DisplayLists.Script +namespace SM64Lib.Model.Fast3D.DisplayLists.Script; + +public class DisplayListScript : List { - public class DisplayListScript : List + public void FromStream(object input, int segAddress, byte? AreaID) { - public void FromStream(object input, int segAddress, byte? AreaID) + Close(); + + var rommgr = input as RomManager; + var data = input as BinaryData; + var lastPositions = new Stack(); + SegmentedBank curSeg = null; + + void getSegBank(int segAddr) { - Close(); - - var rommgr = input as RomManager; - var data = input as BinaryData; - var lastPositions = new Stack(); - SegmentedBank curSeg = null; - - void getSegBank(int segAddr) - { - if (rommgr is not null) - { - curSeg = FromStream_GetSegBank(rommgr, segAddress, AreaID); - data = new BinaryStreamData(curSeg.Data); - } - } - - getSegBank(segAddress); - data.Position = curSeg is object ? curSeg.BankOffsetFromSegAddr(segAddress) : segAddress & 0xffffff; - - bool continueDo = true; - while (data.Position < curSeg.Length && continueDo) - { - // Read Command - var cmdbytes = new byte[8]; - data.Read(cmdbytes); - - // Create & Add Command - var cmd = new DisplayListCommand(cmdbytes) - { - RomAddress = (int)(curSeg?.RomStart ?? 0 + data.Position), - BankAddress = (int)(curSeg?.BankAddress ?? 0 + data.Position) - }; - Add(cmd); - - switch (cmd.CommandType) - { - case CommandTypes.NOOP: - { - cmd.Position = 0; - int checkVal = cmd.ReadInt32(); - cmd.Position = 0; - if (checkVal != 0) - break; - break; - } - - case CommandTypes.DisplayList: - { - cmd.Position = 4; - int segAddr = cmd.ReadInt32(); - cmd.Position = 0; - getSegBank(segAddr); - - if (curSeg is not null) - { - if (cmdbytes[1] != 1) - lastPositions.Push(Convert.ToInt32(data.Position)); - else - lastPositions.Clear(); - data.Position = curSeg.BankOffsetFromSegAddr(segAddr); - } - else - break; - - break; - } - - case CommandTypes.EndDisplaylist: - { - if (lastPositions.Count > 0) - curSeg.Data.Position = lastPositions.Pop(); - else - continueDo = false; - break; - } - } - } - } - - private SegmentedBank FromStream_GetSegBank(RomManager rommgr, int segAddr, byte? areaID) - { - SegmentedBank seg = null; - if (rommgr is not null) { - seg = rommgr.GetSegBank(Convert.ToByte(segAddr >> 24), areaID); - seg?.ReadDataIfNull(rommgr.RomFile); + curSeg = FromStream_GetSegBank(rommgr, segAddress, AreaID); + data = new BinaryStreamData(curSeg.Data); } - - return seg; } - public void ToStream(Stream s, uint pos) - { - s.Position = pos; - foreach (DisplayListCommand cmd in this) - s.Write(cmd.ToArray(), 0, Convert.ToInt32(cmd.Length)); - } + getSegBank(segAddress); + data.Position = curSeg is object ? curSeg.BankOffsetFromSegAddr(segAddress) : segAddress & 0xffffff; - public void Close() + bool continueDo = true; + while (data.Position < curSeg.Length && continueDo) { - foreach (var cmd in this) - cmd.Close(); + // Read Command + var cmdbytes = new byte[8]; + data.Read(cmdbytes); + + // Create & Add Command + var cmd = new DisplayListCommand(cmdbytes) + { + RomAddress = (int)(curSeg?.RomStart ?? 0 + data.Position), + BankAddress = (int)(curSeg?.BankAddress ?? 0 + data.Position) + }; + Add(cmd); + + switch (cmd.CommandType) + { + case CommandTypes.NOOP: + { + cmd.Position = 0; + int checkVal = cmd.ReadInt32(); + cmd.Position = 0; + if (checkVal != 0) + break; + break; + } + + case CommandTypes.DisplayList: + { + cmd.Position = 4; + int segAddr = cmd.ReadInt32(); + cmd.Position = 0; + getSegBank(segAddr); + + if (curSeg is not null) + { + if (cmdbytes[1] != 1) + lastPositions.Push(Convert.ToInt32(data.Position)); + else + lastPositions.Clear(); + data.Position = curSeg.BankOffsetFromSegAddr(segAddr); + } + else + break; + + break; + } + + case CommandTypes.EndDisplaylist: + { + if (lastPositions.Count > 0) + curSeg.Data.Position = lastPositions.Pop(); + else + continueDo = false; + break; + } + } } } + + private SegmentedBank FromStream_GetSegBank(RomManager rommgr, int segAddr, byte? areaID) + { + SegmentedBank seg = null; + + if (rommgr is not null) + { + seg = rommgr.GetSegBank(Convert.ToByte(segAddr >> 24), areaID); + seg?.ReadDataIfNull(rommgr.RomFile); + } + + return seg; + } + + public void ToStream(Stream s, uint pos) + { + s.Position = pos; + foreach (DisplayListCommand cmd in this) + s.Write(cmd.ToArray(), 0, Convert.ToInt32(cmd.Length)); + } + + public void Close() + { + foreach (var cmd in this) + cmd.Close(); + } } \ No newline at end of file diff --git a/SM64Lib/Model/Fast3D/Fast3DBuffer.cs b/SM64Lib/Model/Fast3D/Fast3DBuffer.cs index 29382ee..413e8b7 100644 --- a/SM64Lib/Model/Fast3D/Fast3DBuffer.cs +++ b/SM64Lib/Model/Fast3D/Fast3DBuffer.cs @@ -1,143 +1,139 @@ -using System; -using global::System.IO; -using System.Threading.Tasks; -using Microsoft.VisualBasic.CompilerServices; -using global::Pilz.S3DFileParser; +using global::Pilz.S3DFileParser; using global::SM64Lib.Data; using global::SM64Lib.Geolayout; -using System.Linq; +using global::System.IO; +using System.Threading.Tasks; -namespace SM64Lib.Model.Fast3D +namespace SM64Lib.Model.Fast3D; + +[Newtonsoft.Json.JsonConverter(typeof(Json.Fast3DBufferJsonConverter))] +public class Fast3DBuffer : MemoryStream { - [Newtonsoft.Json.JsonConverter(typeof(Json.Fast3DBufferJsonConverter))] - public class Fast3DBuffer : MemoryStream + public Conversion.Fast3DWriting.ConvertResult ConvertResult { get; set; } = null; + public int Fast3DBankStart { get; set; } = 0xE000000; + public Geopointer[] DLPointers { get; set; } = new Geopointer[] { }; + + /// + /// Creates a Fast3D Model from a Obj File + /// + public void FromModel(ObjectInputSettings ObjSettings, Object3D model, TextureFormatSettings texFormatSettings = null) { - public Conversion.Fast3DWriting.ConvertResult ConvertResult { get; set; } = null; - public int Fast3DBankStart { get; set; } = 0xE000000; - public Geopointer[] DLPointers { get; set; } = new Geopointer[] { }; - - /// - /// Creates a Fast3D Model from a Obj File - /// - public void FromModel(ObjectInputSettings ObjSettings, Object3D model, TextureFormatSettings texFormatSettings = null) + // Setup Settings + var conSettings = new Conversion.Fast3DWriting.ConvertSettings() { - // Setup Settings - var conSettings = new Conversion.Fast3DWriting.ConvertSettings() + CenterModel = ObjSettings.CenterModel, + Scale = ObjSettings.Scaling, + ResizeTextures = ObjSettings.ResizeTextures, + ReduceVertLevel = (Conversion.Fast3DWriting.ReduceVericesLevel)ObjSettings.ReduceDupVertLevel, + SegmentedAddress = (uint?)0xE000000, + ForceDisplaylist = ObjSettings.ForceDisplaylist, + Fog = ObjSettings.Fog, + TransparencyLimit = ObjSettings.TransparencyLimit, + TextureFormatSettings = texFormatSettings + }; + model.Shading = ObjSettings.Shading; + + // Convert Model + var con = new Conversion.Fast3DWriting.Fast3DWriter(); + ConvertResult = con.ConvertModel(this, conSettings, model); + + // Fit to align + base.SetLength(General.HexRoundUp1(base.Length)); + + // Copy Geopointer etc. + DLPointers = ConvertResult.PtrGeometry.ToArray(); + Fast3DBankStart = 0xE000000; + } + + public void FromStream(Stream s, int BankRomStart, int BankRamStart, int Fast3DStart, int Fast3DLength, Geopointer[] DisplayListpointer) + { + FromBinaryData(new BinaryStreamData(s), BankRomStart, BankRamStart, Fast3DStart, Fast3DLength, DisplayListpointer); + } + + public void FromBinaryData(BinaryData data, int BankRomStart, int BankRamStart, int Fast3DStart, int Fast3DLength, Geopointer[] DisplayListpointer) + { + DLPointers = DisplayListpointer; + Fast3DBankStart = Fast3DStart - BankRomStart + BankRamStart; + data.Position = Fast3DStart; + base.SetLength(Fast3DLength); + base.Position = 0; + for (int i = 1, loopTo = Fast3DLength; i <= loopTo; i++) + base.WriteByte(data.ReadByte()); + } + + public Task FromModelAsync(ObjectInputSettings ObjSettings, Object3D model, TextureFormatSettings texFormatSettings = null) + { + var t = new Task(() => FromModel(ObjSettings, model, texFormatSettings)); + t.Start(); + return t; + } + + public Task FromStreamAsync(Stream s, int BankRomStart, int BankRamStart, int Fast3DStart, int Fast3DLength, Geopointer[] DisplayListpointer) + { + var t = new Task(() => FromStream(s, BankRomStart, BankRamStart, Fast3DStart, Fast3DLength, DisplayListpointer)); + t.Start(); + return t; + } + + public void ToStream(Stream s, int RomPos, int BankRomStart, int BankRamStart) + { + ToBinaryData(new BinaryStreamData(s), RomPos, BankRomStart, BankRamStart); + } + + public void ToBinaryData(BinaryData data, int dataPos, int BankRomStart, int BankRamStart) + { + data.Position = dataPos; + + // Update all Pointers + int newBankStart = dataPos - BankRomStart + BankRamStart; + int tdif = newBankStart - Fast3DBankStart; + foreach (Geopointer geop in DLPointers) + { + var geopointerSegBank = geop.SegPointer >> 24; + if (geopointerSegBank == Fast3DBankStart >> 24) { - CenterModel = ObjSettings.CenterModel, - Scale = ObjSettings.Scaling, - ResizeTextures = ObjSettings.ResizeTextures, - ReduceVertLevel = (Conversion.Fast3DWriting.ReduceVericesLevel)ObjSettings.ReduceDupVertLevel, - SegmentedAddress = (uint?)0xE000000, - ForceDisplaylist = ObjSettings.ForceDisplaylist, - Fog = ObjSettings.Fog, - TransparencyLimit = ObjSettings.TransparencyLimit, - TextureFormatSettings = texFormatSettings - }; - model.Shading = ObjSettings.Shading; - - // Convert Model - var con = new Conversion.Fast3DWriting.Fast3DWriter(); - ConvertResult = con.ConvertModel(this, conSettings, model); - - // Fit to align - base.SetLength(General.HexRoundUp1(base.Length)); - - // Copy Geopointer etc. - DLPointers = ConvertResult.PtrGeometry.ToArray(); - Fast3DBankStart = 0xE000000; - } - - public void FromStream(Stream s, int BankRomStart, int BankRamStart, int Fast3DStart, int Fast3DLength, Geopointer[] DisplayListpointer) - { - FromBinaryData(new BinaryStreamData(s), BankRomStart, BankRamStart, Fast3DStart, Fast3DLength, DisplayListpointer); - } - - public void FromBinaryData(BinaryData data, int BankRomStart, int BankRamStart, int Fast3DStart, int Fast3DLength, Geopointer[] DisplayListpointer) - { - DLPointers = DisplayListpointer; - Fast3DBankStart = Fast3DStart - BankRomStart + BankRamStart; - data.Position = Fast3DStart; - base.SetLength(Fast3DLength); - base.Position = 0; - for (int i = 1, loopTo = Fast3DLength; i <= loopTo; i++) - base.WriteByte(data.ReadByte()); - } - - public Task FromModelAsync(ObjectInputSettings ObjSettings, Object3D model, TextureFormatSettings texFormatSettings = null) - { - var t = new Task(() => FromModel(ObjSettings, model, texFormatSettings)); - t.Start(); - return t; - } - - public Task FromStreamAsync(Stream s, int BankRomStart, int BankRamStart, int Fast3DStart, int Fast3DLength, Geopointer[] DisplayListpointer) - { - var t = new Task(() => FromStream(s, BankRomStart, BankRamStart, Fast3DStart, Fast3DLength, DisplayListpointer)); - t.Start(); - return t; - } - - public void ToStream(Stream s, int RomPos, int BankRomStart, int BankRamStart) - { - ToBinaryData(new BinaryStreamData(s), RomPos, BankRomStart, BankRamStart); - } - - public void ToBinaryData(BinaryData data, int dataPos, int BankRomStart, int BankRamStart) - { - data.Position = dataPos; - - // Update all Pointers - int newBankStart = dataPos - BankRomStart + BankRamStart; - int tdif = newBankStart - Fast3DBankStart; - foreach (Geopointer geop in DLPointers) - { - var geopointerSegBank = geop.SegPointer >> 24; - if (geopointerSegBank == Fast3DBankStart >> 24) + var ende = false; + Position = geop.SegPointer - Fast3DBankStart; + do { - var ende = false; - Position = geop.SegPointer - Fast3DBankStart; - do + var switchExpr = ReadByte(); + switch (switchExpr) { - var switchExpr = ReadByte(); - switch (switchExpr) - { - case 0xB8: - { - ende = true; - break; - } + case 0xB8: + { + ende = true; + break; + } - case 0x3: - case 0x4: - case 0x6: - case 0xFD: - { - base.Position += 3; - var sd = new BinaryStreamData(this); - int p = sd.ReadInt32(); - p += tdif; - base.Position -= 4; - sd.Write(p); - break; - } + case 0x3: + case 0x4: + case 0x6: + case 0xFD: + { + base.Position += 3; + var sd = new BinaryStreamData(this); + int p = sd.ReadInt32(); + p += tdif; + base.Position -= 4; + sd.Write(p); + break; + } - default: - { - base.Position += 7; - break; - } - } + default: + { + base.Position += 7; + break; + } } - while (!ende && base.Position < base.Length); - geop.SegPointer += tdif; } + while (!ende && base.Position < base.Length); + geop.SegPointer += tdif; } - - // Write Fast3D - foreach (byte b in base.ToArray()) - data.Write(b); - Fast3DBankStart = newBankStart; } + + // Write Fast3D + foreach (byte b in base.ToArray()) + data.Write(b); + Fast3DBankStart = newBankStart; } } \ No newline at end of file diff --git a/SM64Lib/Model/Fast3D/TextureConverters.cs b/SM64Lib/Model/Fast3D/TextureConverters.cs index 7a06978..c22909c 100644 --- a/SM64Lib/Model/Fast3D/TextureConverters.cs +++ b/SM64Lib/Model/Fast3D/TextureConverters.cs @@ -1,14 +1,7 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +namespace SM64Lib.Model.Fast3D; -namespace SM64Lib.Model.Fast3D +public enum TextureConverters { - public enum TextureConverters - { - Internal, - NConvert - } + Internal, + NConvert } diff --git a/SM64Lib/Model/Fast3D/TextureFormatSettings.cs b/SM64Lib/Model/Fast3D/TextureFormatSettings.cs index fadb744..8a8805f 100644 --- a/SM64Lib/Model/Fast3D/TextureFormatSettings.cs +++ b/SM64Lib/Model/Fast3D/TextureFormatSettings.cs @@ -1,100 +1,98 @@ -using System; -using System.Collections.Generic; +using global::Newtonsoft.Json.Linq; +using global::SM64Lib.Model.Conversion.Fast3DWriting; using global::System.Drawing; using global::System.IO; -using System.Linq; -using System.Threading.Tasks; -using global::Newtonsoft.Json.Linq; -using global::SM64Lib.Model.Conversion.Fast3DWriting; -using SM64Lib.Model.Conversion; using Newtonsoft.Json; using Newtonsoft.Json.Converters; +using SM64Lib.Model.Conversion; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; -namespace SM64Lib.Model.Fast3D +namespace SM64Lib.Model.Fast3D; + +public class TextureFormatSettings { - public class TextureFormatSettings - { - public List Entries { get; private set; } = new List(); - public List CustomDisplayLists { get; private set; } = new List(); + public List Entries { get; private set; } = new List(); + public List CustomDisplayLists { get; private set; } = new List(); - public async Task Load(string fileName) + public async Task Load(string fileName) + { + if (File.Exists(fileName)) { - if (File.Exists(fileName)) + bool success = false; + var streamReader = new StreamReader(fileName); + string content = await streamReader.ReadToEndAsync(); + streamReader.Close(); + Entries.Clear(); + CustomDisplayLists.Clear(); + try + { + var settings = JObject.Parse(content).ToObject(); + Entries.AddRange(settings.Entries); + CustomDisplayLists.AddRange(settings.CustomDisplayLists); + success = true; + } + catch (Exception) + { + } + + if (!success) { - bool success = false; - var streamReader = new StreamReader(fileName); - string content = await streamReader.ReadToEndAsync(); - streamReader.Close(); - Entries.Clear(); - CustomDisplayLists.Clear(); try { - var settings = JObject.Parse(content).ToObject(); - Entries.AddRange(settings.Entries); - CustomDisplayLists.AddRange(settings.CustomDisplayLists); + Entries.AddRange(JArray.Parse(content).ToObject()); success = true; } catch (Exception) { } - - if (!success) - { - try - { - Entries.AddRange(JArray.Parse(content).ToObject()); - success = true; - } - catch (Exception) - { - } - } } } - - public async Task Save(string fileName) - { - var sw = new StreamWriter(fileName); - await sw.WriteAsync(JObject.FromObject(this).ToString()); - sw.Flush(); - sw.Close(); - } - - public Entry GetEntry(string matName) - { - foreach (Entry e in Entries) - { - if ((e.MaterialName ?? "") == (matName ?? "")) - { - return e; - } - } - - var ne = new Entry(); - ne.MaterialName = matName; - Entries.Add(ne); - return ne; - } - - public class Entry - { - public bool Include { get; set; } = true; - public string MaterialName { get; set; } = ""; - public string TextureFormat { get; set; } = ""; - public bool IsScrollingTexture { get; set; } = false; - public DisplaylistSelectionSettings DisplaylistSelection { get; set; } = new DisplaylistSelectionSettings(); - [JsonConverter(typeof(StringEnumConverter))] - public FaceCullingMode FaceCullingMode { get; set; } = FaceCullingMode.Back; - public bool EnableMirrorS { get; set; } = false; - public bool EnableMirrorT { get; set; } = false; - public bool EnableClampS { get; set; } = false; - public bool EnableClampT { get; set; } = false; - public bool EnableCrystalEffect { get; set; } = false; - public float? TransparencyLimit { get; set; } = null; - [JsonConverter(typeof(StringEnumConverter))] - public RotateFlipType RotateFlip { get; set; } = RotateFlipType.RotateNoneFlipNone; - [JsonConverter(typeof(StringEnumConverter)), JsonProperty("TextureFilterV2")] - public TextureFilter TextureFilter { get; set; } = TextureFilter.Bilerp; - } + } + + public async Task Save(string fileName) + { + var sw = new StreamWriter(fileName); + await sw.WriteAsync(JObject.FromObject(this).ToString()); + sw.Flush(); + sw.Close(); + } + + public Entry GetEntry(string matName) + { + foreach (Entry e in Entries) + { + if ((e.MaterialName ?? "") == (matName ?? "")) + { + return e; + } + } + + var ne = new Entry(); + ne.MaterialName = matName; + Entries.Add(ne); + return ne; + } + + public class Entry + { + public bool Include { get; set; } = true; + public string MaterialName { get; set; } = ""; + public string TextureFormat { get; set; } = ""; + public bool IsScrollingTexture { get; set; } = false; + public DisplaylistSelectionSettings DisplaylistSelection { get; set; } = new DisplaylistSelectionSettings(); + [JsonConverter(typeof(StringEnumConverter))] + public FaceCullingMode FaceCullingMode { get; set; } = FaceCullingMode.Back; + public bool EnableMirrorS { get; set; } = false; + public bool EnableMirrorT { get; set; } = false; + public bool EnableClampS { get; set; } = false; + public bool EnableClampT { get; set; } = false; + public bool EnableCrystalEffect { get; set; } = false; + public float? TransparencyLimit { get; set; } = null; + [JsonConverter(typeof(StringEnumConverter))] + public RotateFlipType RotateFlip { get; set; } = RotateFlipType.RotateNoneFlipNone; + [JsonConverter(typeof(StringEnumConverter)), JsonProperty("TextureFilterV2")] + public TextureFilter TextureFilter { get; set; } = TextureFilter.Bilerp; } } \ No newline at end of file diff --git a/SM64Lib/Model/Fast3D/TextureManager.cs b/SM64Lib/Model/Fast3D/TextureManager.cs index 739e826..443a18f 100644 --- a/SM64Lib/Model/Fast3D/TextureManager.cs +++ b/SM64Lib/Model/Fast3D/TextureManager.cs @@ -1,175 +1,173 @@ -using System; +using global::System.Drawing; +using global::System.Drawing.Drawing2D; +using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; -using global::System.Drawing; -using global::System.Drawing.Drawing2D; -using Microsoft.VisualBasic.CompilerServices; -namespace SM64Lib.Model.Fast3D +namespace SM64Lib.Model.Fast3D; + +public static class TextureManager { - public static class TextureManager + public static void PrepaireImage(ref Bitmap bmp, RotateFlipType rotateFlipTexture, N64Graphics.N64Codec texFormat, bool fitImageSize, TextureConverters converterToUse = TextureConverters.Internal) { - public static void PrepaireImage(ref Bitmap bmp, RotateFlipType rotateFlipTexture, N64Graphics.N64Codec texFormat, bool fitImageSize, TextureConverters converterToUse = TextureConverters.Internal) + if (fitImageSize) { - if (fitImageSize) + int maxPixels = GetMaxPixls(texFormat); + + // Resize Texture + if (bmp.Height * bmp.Width > maxPixels) { - int maxPixels = GetMaxPixls(texFormat); - - // Resize Texture - if (bmp.Height * bmp.Width > maxPixels) - { - int curPixels = bmp.Height * bmp.Width; - float verhälltnis = Convert.ToSingle(Math.Sqrt(curPixels / (double)maxPixels)); - float newHeight = bmp.Height / verhälltnis; - float newWidth = bmp.Width / verhälltnis; - int nhlog = Convert.ToInt32(Math.Truncate(Math.Log(newHeight, 2))); - int nwlog = Convert.ToInt32(Math.Truncate(Math.Log(newWidth, 2))); - newHeight = Convert.ToSingle(Math.Pow(2, nhlog)); - newWidth = Convert.ToSingle(Math.Pow(2, nwlog)); - bmp = (Bitmap)ResizeImage(bmp, new Size(Convert.ToInt32(newWidth), Convert.ToInt32(newHeight)), converterToUse:converterToUse); - } + int curPixels = bmp.Height * bmp.Width; + float verhälltnis = Convert.ToSingle(Math.Sqrt(curPixels / (double)maxPixels)); + float newHeight = bmp.Height / verhälltnis; + float newWidth = bmp.Width / verhälltnis; + int nhlog = Convert.ToInt32(Math.Truncate(Math.Log(newHeight, 2))); + int nwlog = Convert.ToInt32(Math.Truncate(Math.Log(newWidth, 2))); + newHeight = Convert.ToSingle(Math.Pow(2, nhlog)); + newWidth = Convert.ToSingle(Math.Pow(2, nwlog)); + bmp = (Bitmap)ResizeImage(bmp, new Size(Convert.ToInt32(newWidth), Convert.ToInt32(newHeight)), converterToUse: converterToUse); } - - RotateFlipImage(bmp, rotateFlipTexture); } - public static Image ResizeImage(Image image, Size size, bool preserveAspectRatio = false, bool forceSize = false, TextureConverters converterToUse = TextureConverters.Internal) - { - var result = new Size(); + RotateFlipImage(bmp, rotateFlipTexture); + } - if (preserveAspectRatio) + public static Image ResizeImage(Image image, Size size, bool preserveAspectRatio = false, bool forceSize = false, TextureConverters converterToUse = TextureConverters.Internal) + { + var result = new Size(); + + if (preserveAspectRatio) + { + float val = (float)(image.Size.Width / (double)size.Width); + float num = (float)(image.Size.Height / (double)size.Height); + + if (num > val) { - float val = (float)(image.Size.Width / (double)size.Width); - float num = (float)(image.Size.Height / (double)size.Height); - - if (num > val) - { - result.Width = Convert.ToInt32(Math.Truncate(size.Width * val)); - result.Height = size.Height; - } - else if (num < val) - { - result.Width = size.Width; - result.Height = Convert.ToInt32(Math.Truncate(size.Height * num)); - } - else - result = size; + result.Width = Convert.ToInt32(Math.Truncate(size.Width * val)); + result.Height = size.Height; + } + else if (num < val) + { + result.Width = size.Width; + result.Height = Convert.ToInt32(Math.Truncate(size.Height * num)); } else result = size; - - var finalResult = forceSize ? size : result; - Image newImage = new Bitmap(image, finalResult); + } + else + result = size; - bool needsPointToDraw() => - forceSize && result.Width / (double)result.Height != size.Width / (double)size.Height; + var finalResult = forceSize ? size : result; + Image newImage = new Bitmap(image, finalResult); - Point getPointToDraw() - { - int px, py; - px = (int)((size.Width - result.Width) / (double)2); - py = (int)((size.Height - result.Height) / (double)2); - return new Point(px, py); - } + bool needsPointToDraw() => + forceSize && result.Width / (double)result.Height != size.Width / (double)size.Height; - switch (converterToUse) - { - case TextureConverters.Internal: + Point getPointToDraw() + { + int px, py; + px = (int)((size.Width - result.Width) / (double)2); + py = (int)((size.Height - result.Height) / (double)2); + return new Point(px, py); + } + + switch (converterToUse) + { + case TextureConverters.Internal: + { + using (var g = Graphics.FromImage(newImage)) + { + g.SmoothingMode = SmoothingMode.HighQuality; + g.PixelOffsetMode = PixelOffsetMode.HighQuality; + g.PageUnit = GraphicsUnit.Pixel; + g.InterpolationMode = InterpolationMode.HighQualityBicubic; + + Point pointToDraw; + if (needsPointToDraw()) + pointToDraw = getPointToDraw(); + else + pointToDraw = Point.Empty; + + g.Clear(Color.Transparent); + g.DrawImage(image, new Rectangle(pointToDraw, result)); + g.Dispose(); + } + } + break; + case TextureConverters.NConvert: + { + var arguments = new List(); + arguments.Add("-out png"); + arguments.Add($"-resize {result.Width} {result.Height}"); + arguments.Add("-overwrite"); + + var sourceFilePath = Path.GetTempFileName(); + using (var fs = new FileStream(sourceFilePath, FileMode.Create, FileAccess.ReadWrite)) + image.Save(fs, System.Drawing.Imaging.ImageFormat.Png); + arguments.Add($"-o \"{sourceFilePath}\""); + arguments.Add($"\"{sourceFilePath}\""); + + var p = new Process(); + p.StartInfo.CreateNoWindow = true; + p.StartInfo.FileName = FilePathsConfiguration.DefaultConfiguration.Files["nconvert.exe"]; + p.StartInfo.Arguments = string.Join(" ", arguments.ToArray()); + + p.Start(); + p.WaitForExit(); + + using (var fs = new FileStream(sourceFilePath, FileMode.Open, FileAccess.Read)) + image = Image.FromStream(fs); + + if (needsPointToDraw()) { using (var g = Graphics.FromImage(newImage)) { - g.SmoothingMode = SmoothingMode.HighQuality; - g.PixelOffsetMode = PixelOffsetMode.HighQuality; - g.PageUnit = GraphicsUnit.Pixel; - g.InterpolationMode = InterpolationMode.HighQualityBicubic; - - Point pointToDraw; - if (needsPointToDraw()) - pointToDraw = getPointToDraw(); - else - pointToDraw = Point.Empty; - + Point pointToDraw = getPointToDraw(); g.Clear(Color.Transparent); g.DrawImage(image, new Rectangle(pointToDraw, result)); g.Dispose(); } } - break; - case TextureConverters.NConvert: - { - var arguments = new List(); - arguments.Add("-out png"); - arguments.Add($"-resize {result.Width} {result.Height}"); - arguments.Add("-overwrite"); - - var sourceFilePath = Path.GetTempFileName(); - using (var fs = new FileStream(sourceFilePath, FileMode.Create, FileAccess.ReadWrite)) - image.Save(fs, System.Drawing.Imaging.ImageFormat.Png); - arguments.Add($"-o \"{sourceFilePath}\""); - arguments.Add($"\"{sourceFilePath}\""); - - var p = new Process(); - p.StartInfo.CreateNoWindow = true; - p.StartInfo.FileName = FilePathsConfiguration.DefaultConfiguration.Files["nconvert.exe"]; - p.StartInfo.Arguments = string.Join(" ", arguments.ToArray()); - - p.Start(); - p.WaitForExit(); - - using (var fs = new FileStream(sourceFilePath, FileMode.Open, FileAccess.Read)) - image = Image.FromStream(fs); - - if (needsPointToDraw()) - { - using (var g = Graphics.FromImage(newImage)) - { - Point pointToDraw = getPointToDraw(); - g.Clear(Color.Transparent); - g.DrawImage(image, new Rectangle(pointToDraw, result)); - g.Dispose(); - } - } - } - break; - } - - return newImage; + } + break; } - public static void RotateFlipImage(Bitmap bmp, RotateFlipType rotateFlipTexture) - { - if (rotateFlipTexture != RotateFlipType.RotateNoneFlipNone) - { - bmp.RotateFlip(rotateFlipTexture); - } - } + return newImage; + } - public static int GetMaxPixls(N64Graphics.N64Codec texFormat) + public static void RotateFlipImage(Bitmap bmp, RotateFlipType rotateFlipTexture) + { + if (rotateFlipTexture != RotateFlipType.RotateNoneFlipNone) { - switch (texFormat) - { - case N64Graphics.N64Codec.CI4: - return 64 * 64; - case N64Graphics.N64Codec.CI8: - return 32 * 64; - case N64Graphics.N64Codec.I4: - return 128 * 64; - case N64Graphics.N64Codec.I8: - return 64 * 64; - case N64Graphics.N64Codec.IA4: - return 128 * 64; - case N64Graphics.N64Codec.IA8: - return 64 * 64; - case N64Graphics.N64Codec.IA16: - return 32 * 64; - case N64Graphics.N64Codec.RGBA16: - return 32 * 64; - case N64Graphics.N64Codec.RGBA32: - return 32 * 32; - default: - return 32 * 32; - } + bmp.RotateFlip(rotateFlipTexture); + } + } + + public static int GetMaxPixls(N64Graphics.N64Codec texFormat) + { + switch (texFormat) + { + case N64Graphics.N64Codec.CI4: + return 64 * 64; + case N64Graphics.N64Codec.CI8: + return 32 * 64; + case N64Graphics.N64Codec.I4: + return 128 * 64; + case N64Graphics.N64Codec.I8: + return 64 * 64; + case N64Graphics.N64Codec.IA4: + return 128 * 64; + case N64Graphics.N64Codec.IA8: + return 64 * 64; + case N64Graphics.N64Codec.IA16: + return 32 * 64; + case N64Graphics.N64Codec.RGBA16: + return 32 * 64; + case N64Graphics.N64Codec.RGBA32: + return 32 * 32; + default: + return 32 * 32; } } } \ No newline at end of file diff --git a/SM64Lib/Model/Fog.cs b/SM64Lib/Model/Fog.cs index 5d67a2d..5c7c6b1 100644 --- a/SM64Lib/Model/Fog.cs +++ b/SM64Lib/Model/Fog.cs @@ -1,9 +1,8 @@  -namespace SM64Lib.Model +namespace SM64Lib.Model; + +public class Fog { - public class Fog - { - public System.Drawing.Color Color { get; set; } = System.Drawing.Color.White; - public FogPreset Type { get; set; } = new FogPreset(); - } + public System.Drawing.Color Color { get; set; } = System.Drawing.Color.White; + public FogPreset Type { get; set; } = new FogPreset(); } \ No newline at end of file diff --git a/SM64Lib/Model/FogPreset.cs b/SM64Lib/Model/FogPreset.cs index 14ec5bf..5edf6e6 100644 --- a/SM64Lib/Model/FogPreset.cs +++ b/SM64Lib/Model/FogPreset.cs @@ -1,16 +1,15 @@  -namespace SM64Lib.Model +namespace SM64Lib.Model; + +public enum FogPreset { - public enum FogPreset - { - SubtleFog1 = 0, - SubtleFog2, - ModerateFog1, - ModerateFog2, - ModerateFog3, - ModerateFog4, - IntenseFog, - VeryIntenseFog, - HardcoreFog - } + SubtleFog1 = 0, + SubtleFog2, + ModerateFog1, + ModerateFog2, + ModerateFog3, + ModerateFog4, + IntenseFog, + VeryIntenseFog, + HardcoreFog } \ No newline at end of file diff --git a/SM64Lib/Model/ObjectInputSettings.cs b/SM64Lib/Model/ObjectInputSettings.cs index edf08a7..7628c24 100644 --- a/SM64Lib/Model/ObjectInputSettings.cs +++ b/SM64Lib/Model/ObjectInputSettings.cs @@ -1,25 +1,24 @@  -namespace SM64Lib.Model -{ - public class ObjectInputSettings - { - public sbyte ForceDisplaylist { get; set; } = -1; - public double Scaling { get; set; } = 1.0F; - public ReduceDuplicateVerticesLevel ReduceDupVertLevel { get; set; } = ReduceDuplicateVerticesLevel.Level1; - public Fog Fog { get; set; } = null; - public bool ResizeTextures { get; set; } = true; - public bool CenterModel { get; set; } = false; - public Pilz.S3DFileParser.Shading Shading { get; private set; } = new Pilz.S3DFileParser.Shading(); - public float TransparencyLimit { get; set; } = 0; +namespace SM64Lib.Model; - public enum ReduceDuplicateVerticesLevel - { - /// Don't reduce vertices. - Level0, - /// Reduce only, if in the same 0x4 group. - Level1, - /// Reduce and push up. [Buggy] - Level2 - } +public class ObjectInputSettings +{ + public sbyte ForceDisplaylist { get; set; } = -1; + public double Scaling { get; set; } = 1.0F; + public ReduceDuplicateVerticesLevel ReduceDupVertLevel { get; set; } = ReduceDuplicateVerticesLevel.Level1; + public Fog Fog { get; set; } = null; + public bool ResizeTextures { get; set; } = true; + public bool CenterModel { get; set; } = false; + public Pilz.S3DFileParser.Shading Shading { get; private set; } = new Pilz.S3DFileParser.Shading(); + public float TransparencyLimit { get; set; } = 0; + + public enum ReduceDuplicateVerticesLevel + { + /// Don't reduce vertices. + Level0, + /// Reduce only, if in the same 0x4 group. + Level1, + /// Reduce and push up. [Buggy] + Level2 } } \ No newline at end of file diff --git a/SM64Lib/Model/ObjectModel.cs b/SM64Lib/Model/ObjectModel.cs index 2e07c7e..e5556f1 100644 --- a/SM64Lib/Model/ObjectModel.cs +++ b/SM64Lib/Model/ObjectModel.cs @@ -1,135 +1,133 @@ -using System.Collections.Generic; -using global::System.IO; -using System.Threading.Tasks; -using Microsoft.VisualBasic.CompilerServices; -using global::SM64Lib.Data; +using global::SM64Lib.Data; using global::SM64Lib.Geolayout; +using global::System.IO; using SM64Lib.Configuration; using System; +using System.Collections.Generic; +using System.Threading.Tasks; -namespace SM64Lib.Model +namespace SM64Lib.Model; + +public class ObjectModel { - public class ObjectModel + + public Collision.CollisionMap Collision { get; set; } = null; + public Fast3D.Fast3DBuffer Fast3DBuffer { get; set; } = null; + + public void FromROM(string Romfile, int BankRomStart, int BankRamStart, int Fast3DStart, int Fast3DLength, Geopointer[] DisplayListpointer, int Collisionpointer = -1, CollisionBasicConfig collisionConfig = null) { + var fs = new FileStream(Romfile, FileMode.Open, FileAccess.Read); + FromStream(fs, BankRomStart, BankRamStart, Fast3DStart, Fast3DLength, DisplayListpointer, Collisionpointer, collisionConfig); + fs.Close(); + } - public Collision.CollisionMap Collision { get; set; } = null; - public Fast3D.Fast3DBuffer Fast3DBuffer { get; set; } = null; - - public void FromROM(string Romfile, int BankRomStart, int BankRamStart, int Fast3DStart, int Fast3DLength, Geopointer[] DisplayListpointer, int Collisionpointer = -1, CollisionBasicConfig collisionConfig = null) + public void FromBinaryData(BinaryData data, int BankRomStart, int BankRamStart, int Fast3DStart, int Fast3DLength, Geopointer[] DisplayListpointer, int Collisionpointer = -1, CollisionBasicConfig collisionConfig = null) + { + // Load Collision + if (Collisionpointer > -1) { - var fs = new FileStream(Romfile, FileMode.Open, FileAccess.Read); - FromStream(fs, BankRomStart, BankRamStart, Fast3DStart, Fast3DLength, DisplayListpointer, Collisionpointer, collisionConfig); - fs.Close(); - } - - public void FromBinaryData(BinaryData data, int BankRomStart, int BankRamStart, int Fast3DStart, int Fast3DLength, Geopointer[] DisplayListpointer, int Collisionpointer = -1, CollisionBasicConfig collisionConfig = null) - { - // Load Collision - if (Collisionpointer > -1) - { - Collision = new Collision.CollisionMap(); - int cRomStart = Collisionpointer - BankRamStart + BankRomStart; - Collision.FromBinaryData(data, cRomStart, collisionConfig); - } - else - { - Collision = null; - } - - // Read Fast3D Buffer - if (Fast3DBuffer is not null) - Fast3DBuffer.Close(); - Fast3DBuffer = new Fast3D.Fast3DBuffer(); - Fast3DBuffer.FromBinaryData(data, BankRomStart, BankRamStart, Fast3DStart, Fast3DLength, DisplayListpointer); - } - - public void FromStream(Stream s, int BankRomStart, int BankRamStart, int Fast3DStart, int Fast3DLength, Geopointer[] DisplayListpointer, int Collisionpointer = -1, CollisionBasicConfig collisionConfig = null) - { - FromBinaryData(new BinaryStreamData(s), BankRomStart, BankRamStart, Fast3DStart, Fast3DLength, DisplayListpointer, Collisionpointer, collisionConfig); - } - - public void FromModel(ObjectInputSettings ObjSettings, Pilz.S3DFileParser.Object3D vmap, Pilz.S3DFileParser.Object3D colmap, Fast3D.TextureFormatSettings texFormatSettings, Collision.CollisionSettings colSettings = null) - { - // Add Collision Collision = new Collision.CollisionMap(); - Collision.FromObject3D(ObjSettings, colmap, colSettings); - - // Add Fast3DBuffer (replacement for 'Add Displaylists') - if (Fast3DBuffer is not null) - Fast3DBuffer.Close(); - Fast3DBuffer = new Fast3D.Fast3DBuffer(); - Fast3DBuffer.FromModel(ObjSettings, vmap, texFormatSettings); + int cRomStart = Collisionpointer - BankRamStart + BankRomStart; + Collision.FromBinaryData(data, cRomStart, collisionConfig); + } + else + { + Collision = null; } - public Task FromModelAsync(ObjectInputSettings ObjSettings, Pilz.S3DFileParser.Object3D vmap, Pilz.S3DFileParser.Object3D colmap, Fast3D.TextureFormatSettings texFormatSettings = null, Collision.CollisionSettings colSettings = null) + // Read Fast3D Buffer + if (Fast3DBuffer is not null) + Fast3DBuffer.Close(); + Fast3DBuffer = new Fast3D.Fast3DBuffer(); + Fast3DBuffer.FromBinaryData(data, BankRomStart, BankRamStart, Fast3DStart, Fast3DLength, DisplayListpointer); + } + + public void FromStream(Stream s, int BankRomStart, int BankRamStart, int Fast3DStart, int Fast3DLength, Geopointer[] DisplayListpointer, int Collisionpointer = -1, CollisionBasicConfig collisionConfig = null) + { + FromBinaryData(new BinaryStreamData(s), BankRomStart, BankRamStart, Fast3DStart, Fast3DLength, DisplayListpointer, Collisionpointer, collisionConfig); + } + + public void FromModel(ObjectInputSettings ObjSettings, Pilz.S3DFileParser.Object3D vmap, Pilz.S3DFileParser.Object3D colmap, Fast3D.TextureFormatSettings texFormatSettings, Collision.CollisionSettings colSettings = null) + { + // Add Collision + Collision = new Collision.CollisionMap(); + Collision.FromObject3D(ObjSettings, colmap, colSettings); + + // Add Fast3DBuffer (replacement for 'Add Displaylists') + if (Fast3DBuffer is not null) + Fast3DBuffer.Close(); + Fast3DBuffer = new Fast3D.Fast3DBuffer(); + Fast3DBuffer.FromModel(ObjSettings, vmap, texFormatSettings); + } + + public Task FromModelAsync(ObjectInputSettings ObjSettings, Pilz.S3DFileParser.Object3D vmap, Pilz.S3DFileParser.Object3D colmap, Fast3D.TextureFormatSettings texFormatSettings = null, Collision.CollisionSettings colSettings = null) + { + var t = new Task(() => FromModel(ObjSettings, vmap, colmap, texFormatSettings, colSettings)); + t.Start(); + return t; + } + + public SaveResult ToRom(string Romfile, int RomPos, int BankRomStart, int BankRamStart, CollisionBasicConfig collisionConfig) + { + var fs = new FileStream(Romfile, FileMode.Open, FileAccess.ReadWrite); + var treturn = ToStream(fs, RomPos, BankRomStart, BankRamStart, collisionConfig); + fs.Close(); + return treturn; + } + + public SaveResult ToStream(Stream s, int RomPos, int BankRomStart, int BankRamStart, CollisionBasicConfig collisionConfig) + { + return ToBinaryData(new BinaryStreamData(s), RomPos, BankRomStart, BankRamStart, collisionConfig); + } + + public SaveResult ToBinaryData(BinaryData data, int dataPos, int BankRomStart, int BankRamStart, CollisionBasicConfig collisionConfig) + { + var tresult = new SaveResult(); + data.Position = dataPos; + + // Write Fast3D + if (Fast3DBuffer is not null) { - var t = new Task(() => FromModel(ObjSettings, vmap, colmap, texFormatSettings, colSettings)); - t.Start(); - return t; + Fast3DBuffer.ToBinaryData(data, Convert.ToInt32(data.Position), BankRomStart, BankRamStart); + tresult.GeoPointers.AddRange(Fast3DBuffer.DLPointers); + tresult.Length += Fast3DBuffer.Length; + } + else + { + tresult.GeoPointers.Clear(); } - public SaveResult ToRom(string Romfile, int RomPos, int BankRomStart, int BankRamStart, CollisionBasicConfig collisionConfig) + // Write Collision + if (Collision is not null) { - var fs = new FileStream(Romfile, FileMode.Open, FileAccess.ReadWrite); - var treturn = ToStream(fs, RomPos, BankRomStart, BankRamStart, collisionConfig); - fs.Close(); - return treturn; + int colStart = (int)General.HexRoundUp1(data.Position); + tresult.CollisionPointer = colStart - BankRomStart + BankRamStart; + Collision.ToBinaryData(data, colStart, collisionConfig); + Collision.Length = data.Position - colStart; + tresult.Length += Collision.Length; + } + else + { + tresult.CollisionPointer = -1; } - public SaveResult ToStream(Stream s, int RomPos, int BankRomStart, int BankRamStart, CollisionBasicConfig collisionConfig) + return tresult; + } + + public int Length + { + get { - return ToBinaryData(new BinaryStreamData(s), RomPos, BankRomStart, BankRamStart, collisionConfig); - } - - public SaveResult ToBinaryData(BinaryData data, int dataPos, int BankRomStart, int BankRamStart, CollisionBasicConfig collisionConfig) - { - var tresult = new SaveResult(); - data.Position = dataPos; - - // Write Fast3D - if (Fast3DBuffer is not null) - { - Fast3DBuffer.ToBinaryData(data, Convert.ToInt32(data.Position), BankRomStart, BankRamStart); - tresult.GeoPointers.AddRange(Fast3DBuffer.DLPointers); - tresult.Length += Fast3DBuffer.Length; - } - else - { - tresult.GeoPointers.Clear(); - } - - // Write Collision - if (Collision is not null) - { - int colStart = (int)General.HexRoundUp1(data.Position); - tresult.CollisionPointer = colStart - BankRomStart + BankRamStart; - Collision.ToBinaryData(data, colStart, collisionConfig); - Collision.Length = data.Position - colStart; - tresult.Length += Collision.Length; - } - else - { - tresult.CollisionPointer = -1; - } - - return tresult; - } - - public int Length - { - get - { - return (int)( - (Fast3DBuffer is object ? General.HexRoundUp1(Fast3DBuffer.Length) : 0) + - (Collision is object ? General.HexRoundUp1(Collision.Length) : 0)); - } - } - - public class SaveResult - { - public int CollisionPointer { get; set; } = -1; - public List GeoPointers { get; set; } = new List(); - public long Length { get; set; } = 0; + return (int)( + (Fast3DBuffer is object ? General.HexRoundUp1(Fast3DBuffer.Length) : 0) + + (Collision is object ? General.HexRoundUp1(Collision.Length) : 0)); } } + + public class SaveResult + { + public int CollisionPointer { get; set; } = -1; + public List GeoPointers { get; set; } = new List(); + public long Length { get; set; } = 0; + } } \ No newline at end of file diff --git a/SM64Lib/Music/InstrumentSetList.cs b/SM64Lib/Music/InstrumentSetList.cs index ae75c93..44ad7c3 100644 --- a/SM64Lib/Music/InstrumentSetList.cs +++ b/SM64Lib/Music/InstrumentSetList.cs @@ -1,124 +1,121 @@ -using System.Collections.Generic; -using Microsoft.VisualBasic.CompilerServices; -using global::SM64Lib.Data; +using global::SM64Lib.Data; using System; +using System.Collections.Generic; -namespace SM64Lib.Music +namespace SM64Lib.Music; + +public class InstrumentSetList { - public class InstrumentSetList + public List Sets { get; private set; } = new List(); + + public int Count { - public List Sets { get; private set; } = new List(); - - public int Count + get { - get - { - return Sets.Count; - } - } - - public byte NInstLength - { - get - { - return Convert.ToByte(Sets.Count + 1); - } - } - - public void ReadNInst(BinaryData s, int RomAddress) - { - s.Position = RomAddress; - Sets.Clear(); - for (int i = 0, loopTo = s.ReadByte() - 1; i <= loopTo; i++) - Sets.Add(s.ReadByte()); - } - - public void WriteNInst(BinaryData s, int RomAddress) - { - s.Position = RomAddress; - s.WriteByte(Convert.ToByte(Sets.Count)); - foreach (byte b in Sets) - s.WriteByte(b); + return Sets.Count; } } - // Public Enum InstSets As Byte - // ''' NInst 00 - SFX - // NInst_00_SFX - // ''' NInst 01 - SFX - // NInst_01_SFX - // ''' NInst 02 - SFX - // NInst_02_SFX - // ''' NInst 03 - SFX - // NInst_03_SFX - // ''' NInst 04 - SFX - // NInst_04_SFX - // ''' NInst 05 - SFX - // NInst_05_SFX - // ''' NInst 06 - SFX - // NInst_06_SFX - // ''' NInst 07 - SFX - // NInst_07_SFX - // ''' NInst 08 - SFX - // NInst_08_SFX - // ''' NInst 09 - SFX - // NInst_09_SFX - // ''' NInst 10 - SFX - // NInst_10_SFX - // ''' NInst 11 - Snow - // NInst_11_Snow - // ''' NInst 12 - Unused - // NInst_12_Unused - // ''' NInst 13 - Slide - // NInst_13_Slide - // ''' NInst 14 - Inside Castle - // NInst_14_Inside_Castle - // ''' NInst 15 - Shifting Sand Land - // NInst_15_Shifting_Sand_Land - // ''' NInst 16 - Haunted House - // NInst_16_Haunted_House - // ''' NInst 17 - Title Screen - // NInst_17_Title_Screen - // ''' NInst 18 - Bowser Battle - // NInst_18_Bowser_Battle - // ''' NInst 19 - Water - // NInst_19_Water - // ''' NInst 20 - Piranha Plant - // NInst_20_Piranha_Plant - // ''' NInst 21 - Hazy Maze - // NInst_21_Hazy_Maze - // ''' NInst 22 - Star Select - // NInst_22_Star_Select - // ''' NInst 23 - Wing Cap - // NInst_23_Wing_Cap - // ''' NInst 24 - Metal Cap - // NInst_24_Metal_Cap - // ''' NInst 25 - Bowser Course - // NInst_25_Bowser_Course - // ''' NInst 26 - Fanfare - // NInst_26_Fanfare - // ''' NInst 27 - Boss Fight - // NInst_27_Boss_Fight - // ''' NInst 28 - Looping Stairs - // NInst_28_Looping_Stairs - // ''' NInst 29 - Final Bowser - // NInst_29_Final_Bowser - // ''' NInst 30 - Peach Message - // NInst_30_Peach_Message - // ''' NInst 31 - Star Catch - // NInst_31_Star_Catch - // ''' NInst 32 - Toad - // NInst_32_Toad - // ''' NInst 33 - Merry-Go-Round - // NInst_33_Merry_Go_Round - // ''' NInst 34 - Bob-Omb- Battlefield - // NInst_34_Bob_Omb_Battlefield - // ''' NInst 35 - Ending - // NInst_35_Ending - // ''' NInst 36 - File Select - // NInst_36_File_Select - // ''' NInst 37 - Credits - // NInst_37_Credits - // End Enum + public byte NInstLength + { + get + { + return Convert.ToByte(Sets.Count + 1); + } + } -} \ No newline at end of file + public void ReadNInst(BinaryData s, int RomAddress) + { + s.Position = RomAddress; + Sets.Clear(); + for (int i = 0, loopTo = s.ReadByte() - 1; i <= loopTo; i++) + Sets.Add(s.ReadByte()); + } + + public void WriteNInst(BinaryData s, int RomAddress) + { + s.Position = RomAddress; + s.WriteByte(Convert.ToByte(Sets.Count)); + foreach (byte b in Sets) + s.WriteByte(b); + } +} + +// Public Enum InstSets As Byte +// ''' NInst 00 - SFX +// NInst_00_SFX +// ''' NInst 01 - SFX +// NInst_01_SFX +// ''' NInst 02 - SFX +// NInst_02_SFX +// ''' NInst 03 - SFX +// NInst_03_SFX +// ''' NInst 04 - SFX +// NInst_04_SFX +// ''' NInst 05 - SFX +// NInst_05_SFX +// ''' NInst 06 - SFX +// NInst_06_SFX +// ''' NInst 07 - SFX +// NInst_07_SFX +// ''' NInst 08 - SFX +// NInst_08_SFX +// ''' NInst 09 - SFX +// NInst_09_SFX +// ''' NInst 10 - SFX +// NInst_10_SFX +// ''' NInst 11 - Snow +// NInst_11_Snow +// ''' NInst 12 - Unused +// NInst_12_Unused +// ''' NInst 13 - Slide +// NInst_13_Slide +// ''' NInst 14 - Inside Castle +// NInst_14_Inside_Castle +// ''' NInst 15 - Shifting Sand Land +// NInst_15_Shifting_Sand_Land +// ''' NInst 16 - Haunted House +// NInst_16_Haunted_House +// ''' NInst 17 - Title Screen +// NInst_17_Title_Screen +// ''' NInst 18 - Bowser Battle +// NInst_18_Bowser_Battle +// ''' NInst 19 - Water +// NInst_19_Water +// ''' NInst 20 - Piranha Plant +// NInst_20_Piranha_Plant +// ''' NInst 21 - Hazy Maze +// NInst_21_Hazy_Maze +// ''' NInst 22 - Star Select +// NInst_22_Star_Select +// ''' NInst 23 - Wing Cap +// NInst_23_Wing_Cap +// ''' NInst 24 - Metal Cap +// NInst_24_Metal_Cap +// ''' NInst 25 - Bowser Course +// NInst_25_Bowser_Course +// ''' NInst 26 - Fanfare +// NInst_26_Fanfare +// ''' NInst 27 - Boss Fight +// NInst_27_Boss_Fight +// ''' NInst 28 - Looping Stairs +// NInst_28_Looping_Stairs +// ''' NInst 29 - Final Bowser +// NInst_29_Final_Bowser +// ''' NInst 30 - Peach Message +// NInst_30_Peach_Message +// ''' NInst 31 - Star Catch +// NInst_31_Star_Catch +// ''' NInst 32 - Toad +// NInst_32_Toad +// ''' NInst 33 - Merry-Go-Round +// NInst_33_Merry_Go_Round +// ''' NInst 34 - Bob-Omb- Battlefield +// NInst_34_Bob_Omb_Battlefield +// ''' NInst 35 - Ending +// NInst_35_Ending +// ''' NInst 36 - File Select +// NInst_36_File_Select +// ''' NInst 37 - Credits +// NInst_37_Credits +// End Enum \ No newline at end of file diff --git a/SM64Lib/Music/MusicList.cs b/SM64Lib/Music/MusicList.cs index 6df384f..35b8d11 100644 --- a/SM64Lib/Music/MusicList.cs +++ b/SM64Lib/Music/MusicList.cs @@ -1,351 +1,349 @@ -using System; +using global::SM64Lib.Data; +using global::System.IO; +using System; using System.Collections.Generic; using System.Data; -using global::System.IO; using System.Linq; -using Microsoft.VisualBasic.CompilerServices; -using global::SM64Lib.Data; -namespace SM64Lib.Music +namespace SM64Lib.Music; + +public class MusicList : List { - public class MusicList : List + + // C o n s t s + + public const int addrMusicStart = 0x1210000; + + // A u t o P r o p e r t i e s + + public bool EnableMusicHack { get; set; } = false; + public bool NeedToSaveNInsts { get; set; } = false; + public bool NeedToSaveSequenceNames { get; set; } = false; + public bool NeedToSaveSequences { get; set; } = false; + public bool NeedToSaveMusicHackSettings { get; set; } = false; + + // O t h e r P r o p e r t i e s + + public bool NeedToSave { - - // C o n s t s - - public const int addrMusicStart = 0x1210000; - - // A u t o P r o p e r t i e s - - public bool EnableMusicHack { get; set; } = false; - public bool NeedToSaveNInsts { get; set; } = false; - public bool NeedToSaveSequenceNames { get; set; } = false; - public bool NeedToSaveSequences { get; set; } = false; - public bool NeedToSaveMusicHackSettings { get; set; } = false; - - // O t h e r P r o p e r t i e s - - public bool NeedToSave + get { - get - { - return NeedToSaveNInsts || NeedToSaveMusicHackSettings || NeedToSaveSequenceNames || NeedToSaveSequences; - } - } - - public long Length - { - get - { - return this.Sum(n => n.Lenght + 0x8) + 0x4; - } - } - - // M e t h o d s - - public void Read(RomManager rommgr) - { - BinaryData s = rommgr.GetBinaryRom(FileAccess.Read); - s.Position = 0x1210002; - short musicCount = s.ReadInt16(); - - // Read NInsts - var tNInstList = ReadNInsts(s, 0x7F0000, musicCount); - - // Read Sequence Names - var tNames = ReadSequenceNames(rommgr); - if (!tNames.Any()) - { - tNames = ReadSequenceNames(s, 0x7F1000, musicCount); - } - - // Read Sequences - Clear(); - AddRange(ReadSequences(s, addrMusicStart, musicCount, tNInstList, tNames)); - - // Check for Music Hack - s.Position = 0xD213A; - ushort t001 = s.ReadUInt16(); - s.Position = 0xD213E; - ushort t002 = s.ReadUInt16(); - EnableMusicHack = t001 == 0x807C & t002 == 0x0; - s.Close(); - } - - public void Write(RomManager rommgr, ref int lastPosition) - { - BinaryData s = rommgr.GetBinaryRom(FileAccess.ReadWrite); - - // Enable/Disable Music Hack - if (NeedToSaveMusicHackSettings) - { - s.Position = 0xD213A; - s.Write(Convert.ToUInt16(EnableMusicHack ? 0x807C : 0x801D)); - s.Position = 0xD213E; - s.Write(Convert.ToUInt16(EnableMusicHack ? 0x0 : 0xE000)); - s.Position = 0xD215A; - s.Write(Convert.ToUInt16(EnableMusicHack ? 0x807C : 0x801D)); - s.Position = 0xD215E; - s.Write(Convert.ToUInt16(EnableMusicHack ? 0x0 : 0xE000)); - s.Position = 0xD459A; - s.Write(Convert.ToUInt16(EnableMusicHack ? 0x807C : 0x801D)); - s.Position = 0xD459E; - s.Write(Convert.ToUInt16(EnableMusicHack ? 0x0 : 0xE000)); - s.Position = 0xEE2B0; - s.Write(Convert.ToUInt32(EnableMusicHack ? 0xBD00 : 0x6D00)); - s.Position = 0xD48B4; - s.Write(Convert.ToUInt32(EnableMusicHack ? 0x3C02803D : 0x3C02807C)); // &H3C02807C - s.Position = 0xD48B8; - s.Write(Convert.ToUInt32(EnableMusicHack ? 0x34420000 : 0x34420000)); - } - - var arrMe = ToArray(); - - // Write Music Names - if (NeedToSaveSequenceNames) - { - WriteSequenceNames(rommgr, arrMe); - } - - // Write NInsts - if (NeedToSaveNInsts) - { - WriteNInst(s, 0x7F0000, arrMe); - } - - // Write Music Sequences - lastPosition = WriteSequences(s, addrMusicStart, arrMe, NeedToSaveSequences); - - // Reset NeedToSave Properties - NeedToSaveSequences = false; - NeedToSaveNInsts = false; - NeedToSaveSequenceNames = false; - NeedToSaveMusicHackSettings = false; - s.Close(); - } - - // S h a r e d M e t h o d s - - private static InstrumentSetList[] ReadNInsts(BinaryData s, int TableStart, short Count) - { - var tNInstList = new List(); - s.Position = TableStart; - for (int i = 0, loopTo = Count - 1; i <= loopTo; i++) - { - ushort startoff = s.ReadUInt16(); - var n = new InstrumentSetList(); - tNInstList.Add(n); - int offBefore = Convert.ToInt32(s.Position); - n.ReadNInst(s, TableStart + startoff); - s.Position = offBefore; - } - - return tNInstList.ToArray(); - } - - private static string[] ReadSequenceNames(BinaryData s, int RomAddress, int Count) - { - s.Position = RomAddress; - var tNames = new List(); - for (int i = 0, loopTo = Count - 1; i <= loopTo; i++) - { - if (s.ReadByte() == 0xFF) - { - s.Position -= 1; - } - else - { - s.Position -= 1; - tNames.Add(s.ReadString()); - } - } - - return tNames.ToArray(); - } - - private static string[] ReadSequenceNames(RomManager rommgr) - { - return rommgr.RomConfig.MusicConfig.SqeuenceNames.ToArray(); - } - - private static MusicSequence[] ReadSequences(BinaryData s, int TableStart, int Count, InstrumentSetList[] tNInstList, string[] tNames) - { - s.Position = TableStart + 4; - var tSequences = new List(); - for (int i = 0, loopTo = Count - 1; i <= loopTo; i++) - { - uint startoff = s.ReadUInt32(); - uint len = s.ReadUInt32(); - var ms = new MusicSequence(); - tSequences.Add(ms); - if (tNames.Length > i) - ms.Name = tNames[i]; - if (tNInstList.Length > i) - ms.InstrumentSets = tNInstList[i]; - int offBefore = Convert.ToInt32(s.Position); - ms.ReadData(s, (int)(TableStart + startoff), Convert.ToInt32(len)); - s.Position = offBefore; - } - - return tSequences.ToArray(); - } - - public static void Prepaire(RomManager rommgr) - { - BinaryData s = rommgr.GetBinaryRom(FileAccess.ReadWrite); - s.Position = 0x7B0863; - byte musicCount = s.ReadByte(); - - // Set original Names - var tNames = new[] { - "No Music", - "Star Catch", - "Title Screen", - "Bob-Omb Battlefield", - "Inside Castle", - "Dire, Dire Docks", - "Lethal Lava Land", - "Bowser Battle", - "Snow", - "Slide", - "Haunted House", - "Piranha Plant Lullaby", - "Hazy Maze Cave", - "Star Select", - "Wing Cap", - "Metal Cap", - "Bowser Message", - "Bowser Course", - "High Score", - "Merry-Go-Round", - "Start and End Race with Koopa the Quick", - "Star Appears", - "Boss Fight", - "Take a Key", - "Endless Stairs", - "Final Boss", - "Staff Credits", - "Puzzle Solved", - "Toad Message", - "Peach Message", - "Introduction Scene", - "Last Star Fanfare", - "Ending Scene", - "File Select", - "Lakitu Appears" - }; - - // Read original sequences - var tSequences = ReadSequences(s, 0x7B0860, musicCount, Array.Empty(), tNames); - s.Position = 0xDC0B8; - s.Write(0); - - // Write sequences to the new Position - WriteSequences(s, addrMusicStart, tSequences, true); - - // Write new sequence names - WriteSequenceNames(rommgr, tSequences); - - // Write NInsts - WriteNInst(s, 0x7F0000, tSequences); - - // Edit ASM-Code to load from the new location - s.Position = 0x7B085F; - s.Write(17); - s.Position = 0xD4714; - s.Write(0x3C040121); - s.Position = 0xD471C; - s.Write(0x24840000); - s.Position = 0xD4768; - s.Write(0x3C040121); - s.Position = 0xD4770; - s.Write(0x24840000); - s.Position = 0xD4784; - s.Write(0x3C050121); - s.Position = 0xD4788; - s.Write(0x24A50000); - s.Position = 0xD48B4; - s.Write(0x3C02807C); - s.Position = 0xD48B8; - s.Write(0x34420000); - - // Edit ASM-Code to load from new location - s.Position = 0xD48C6; - s.Write(Convert.ToInt16(0x7F)); - s.Position = 0xD48CC; - s.Write(0x34840000); - s.Position = 0xD48DA; - s.Write(Convert.ToInt16(0x200)); - - // Check for Music Hack - s.Position = 0xD213A; - ushort t001 = s.ReadUInt16(); - s.Position = 0xD213E; - ushort t002 = s.ReadUInt16(); - if (t001 == 0x805D & t002 == 0xC000) - { - s.Position = 0xD213A; - s.Write(Convert.ToUInt16(0x807C)); - s.Position = 0xD213E; - s.Write(Convert.ToUInt16(0x0)); - s.Position = 0xD215A; - s.Write(Convert.ToUInt16(0x807C)); - s.Position = 0xD215E; - s.Write(Convert.ToUInt16(0x0)); - s.Position = 0xD459A; - s.Write(Convert.ToUInt16(0x807C)); - s.Position = 0xD459E; - s.Write(Convert.ToUInt16(0x0)); - s.Position = 0xEE2B0; - s.Write(Convert.ToUInt32(0xBD00)); - } - - s.Close(); - } - - private static void WriteSequenceNames(RomManager rommgr, MusicSequence[] sequences) - { - rommgr.RomConfig.MusicConfig.SqeuenceNames.Clear(); - rommgr.RomConfig.MusicConfig.SqeuenceNames.AddRange(sequences.Select(n => n.Name)); - } - - private static void WriteNInst(BinaryData s, int TableStart, MusicSequence[] sequences) - { - s.Position = TableStart; - int lastNInstDataOffset = TableStart + sequences.Length * 2; - foreach (MusicSequence ms in sequences) - { - s.Write(Convert.ToUInt16(lastNInstDataOffset - TableStart)); - int lastOff = Convert.ToInt32(s.Position); - ms.InstrumentSets.WriteNInst(s, lastNInstDataOffset); - lastNInstDataOffset += ms.InstrumentSets.NInstLength; - s.Position = lastOff; - } - } - - private static int WriteSequences(BinaryData s, int TableStart, MusicSequence[] sequences, bool WriteData) - { - s.Position = TableStart; - s.Write(Convert.ToInt16(3)); - s.Write(Convert.ToInt16(sequences.Length)); - - // Write sequences to the new Position - int curMsDataOff = General.HexRoundUp1(TableStart + 4 + sequences.Length * 0x8); - foreach (MusicSequence ms in sequences) - { - if (WriteData) - { - s.Write(Convert.ToUInt32(curMsDataOff - TableStart)); - s.Write(Convert.ToUInt32(ms.Lenght)); - int lastOff = Convert.ToInt32(s.Position); - ms.WriteData(s, curMsDataOff); - s.Position = lastOff; - } - - curMsDataOff += General.HexRoundUp1(ms.Lenght); - } - - return curMsDataOff; + return NeedToSaveNInsts || NeedToSaveMusicHackSettings || NeedToSaveSequenceNames || NeedToSaveSequences; } } + + public long Length + { + get + { + return this.Sum(n => n.Lenght + 0x8) + 0x4; + } + } + + // M e t h o d s + + public void Read(RomManager rommgr) + { + BinaryData s = rommgr.GetBinaryRom(FileAccess.Read); + s.Position = 0x1210002; + short musicCount = s.ReadInt16(); + + // Read NInsts + var tNInstList = ReadNInsts(s, 0x7F0000, musicCount); + + // Read Sequence Names + var tNames = ReadSequenceNames(rommgr); + if (!tNames.Any()) + { + tNames = ReadSequenceNames(s, 0x7F1000, musicCount); + } + + // Read Sequences + Clear(); + AddRange(ReadSequences(s, addrMusicStart, musicCount, tNInstList, tNames)); + + // Check for Music Hack + s.Position = 0xD213A; + ushort t001 = s.ReadUInt16(); + s.Position = 0xD213E; + ushort t002 = s.ReadUInt16(); + EnableMusicHack = t001 == 0x807C & t002 == 0x0; + s.Close(); + } + + public void Write(RomManager rommgr, ref int lastPosition) + { + BinaryData s = rommgr.GetBinaryRom(FileAccess.ReadWrite); + + // Enable/Disable Music Hack + if (NeedToSaveMusicHackSettings) + { + s.Position = 0xD213A; + s.Write(Convert.ToUInt16(EnableMusicHack ? 0x807C : 0x801D)); + s.Position = 0xD213E; + s.Write(Convert.ToUInt16(EnableMusicHack ? 0x0 : 0xE000)); + s.Position = 0xD215A; + s.Write(Convert.ToUInt16(EnableMusicHack ? 0x807C : 0x801D)); + s.Position = 0xD215E; + s.Write(Convert.ToUInt16(EnableMusicHack ? 0x0 : 0xE000)); + s.Position = 0xD459A; + s.Write(Convert.ToUInt16(EnableMusicHack ? 0x807C : 0x801D)); + s.Position = 0xD459E; + s.Write(Convert.ToUInt16(EnableMusicHack ? 0x0 : 0xE000)); + s.Position = 0xEE2B0; + s.Write(Convert.ToUInt32(EnableMusicHack ? 0xBD00 : 0x6D00)); + s.Position = 0xD48B4; + s.Write(Convert.ToUInt32(EnableMusicHack ? 0x3C02803D : 0x3C02807C)); // &H3C02807C + s.Position = 0xD48B8; + s.Write(Convert.ToUInt32(EnableMusicHack ? 0x34420000 : 0x34420000)); + } + + var arrMe = ToArray(); + + // Write Music Names + if (NeedToSaveSequenceNames) + { + WriteSequenceNames(rommgr, arrMe); + } + + // Write NInsts + if (NeedToSaveNInsts) + { + WriteNInst(s, 0x7F0000, arrMe); + } + + // Write Music Sequences + lastPosition = WriteSequences(s, addrMusicStart, arrMe, NeedToSaveSequences); + + // Reset NeedToSave Properties + NeedToSaveSequences = false; + NeedToSaveNInsts = false; + NeedToSaveSequenceNames = false; + NeedToSaveMusicHackSettings = false; + s.Close(); + } + + // S h a r e d M e t h o d s + + private static InstrumentSetList[] ReadNInsts(BinaryData s, int TableStart, short Count) + { + var tNInstList = new List(); + s.Position = TableStart; + for (int i = 0, loopTo = Count - 1; i <= loopTo; i++) + { + ushort startoff = s.ReadUInt16(); + var n = new InstrumentSetList(); + tNInstList.Add(n); + int offBefore = Convert.ToInt32(s.Position); + n.ReadNInst(s, TableStart + startoff); + s.Position = offBefore; + } + + return tNInstList.ToArray(); + } + + private static string[] ReadSequenceNames(BinaryData s, int RomAddress, int Count) + { + s.Position = RomAddress; + var tNames = new List(); + for (int i = 0, loopTo = Count - 1; i <= loopTo; i++) + { + if (s.ReadByte() == 0xFF) + { + s.Position -= 1; + } + else + { + s.Position -= 1; + tNames.Add(s.ReadString()); + } + } + + return tNames.ToArray(); + } + + private static string[] ReadSequenceNames(RomManager rommgr) + { + return rommgr.RomConfig.MusicConfig.SqeuenceNames.ToArray(); + } + + private static MusicSequence[] ReadSequences(BinaryData s, int TableStart, int Count, InstrumentSetList[] tNInstList, string[] tNames) + { + s.Position = TableStart + 4; + var tSequences = new List(); + for (int i = 0, loopTo = Count - 1; i <= loopTo; i++) + { + uint startoff = s.ReadUInt32(); + uint len = s.ReadUInt32(); + var ms = new MusicSequence(); + tSequences.Add(ms); + if (tNames.Length > i) + ms.Name = tNames[i]; + if (tNInstList.Length > i) + ms.InstrumentSets = tNInstList[i]; + int offBefore = Convert.ToInt32(s.Position); + ms.ReadData(s, (int)(TableStart + startoff), Convert.ToInt32(len)); + s.Position = offBefore; + } + + return tSequences.ToArray(); + } + + public static void Prepaire(RomManager rommgr) + { + BinaryData s = rommgr.GetBinaryRom(FileAccess.ReadWrite); + s.Position = 0x7B0863; + byte musicCount = s.ReadByte(); + + // Set original Names + var tNames = new[] { + "No Music", + "Star Catch", + "Title Screen", + "Bob-Omb Battlefield", + "Inside Castle", + "Dire, Dire Docks", + "Lethal Lava Land", + "Bowser Battle", + "Snow", + "Slide", + "Haunted House", + "Piranha Plant Lullaby", + "Hazy Maze Cave", + "Star Select", + "Wing Cap", + "Metal Cap", + "Bowser Message", + "Bowser Course", + "High Score", + "Merry-Go-Round", + "Start and End Race with Koopa the Quick", + "Star Appears", + "Boss Fight", + "Take a Key", + "Endless Stairs", + "Final Boss", + "Staff Credits", + "Puzzle Solved", + "Toad Message", + "Peach Message", + "Introduction Scene", + "Last Star Fanfare", + "Ending Scene", + "File Select", + "Lakitu Appears" + }; + + // Read original sequences + var tSequences = ReadSequences(s, 0x7B0860, musicCount, Array.Empty(), tNames); + s.Position = 0xDC0B8; + s.Write(0); + + // Write sequences to the new Position + WriteSequences(s, addrMusicStart, tSequences, true); + + // Write new sequence names + WriteSequenceNames(rommgr, tSequences); + + // Write NInsts + WriteNInst(s, 0x7F0000, tSequences); + + // Edit ASM-Code to load from the new location + s.Position = 0x7B085F; + s.Write(17); + s.Position = 0xD4714; + s.Write(0x3C040121); + s.Position = 0xD471C; + s.Write(0x24840000); + s.Position = 0xD4768; + s.Write(0x3C040121); + s.Position = 0xD4770; + s.Write(0x24840000); + s.Position = 0xD4784; + s.Write(0x3C050121); + s.Position = 0xD4788; + s.Write(0x24A50000); + s.Position = 0xD48B4; + s.Write(0x3C02807C); + s.Position = 0xD48B8; + s.Write(0x34420000); + + // Edit ASM-Code to load from new location + s.Position = 0xD48C6; + s.Write(Convert.ToInt16(0x7F)); + s.Position = 0xD48CC; + s.Write(0x34840000); + s.Position = 0xD48DA; + s.Write(Convert.ToInt16(0x200)); + + // Check for Music Hack + s.Position = 0xD213A; + ushort t001 = s.ReadUInt16(); + s.Position = 0xD213E; + ushort t002 = s.ReadUInt16(); + if (t001 == 0x805D & t002 == 0xC000) + { + s.Position = 0xD213A; + s.Write(Convert.ToUInt16(0x807C)); + s.Position = 0xD213E; + s.Write(Convert.ToUInt16(0x0)); + s.Position = 0xD215A; + s.Write(Convert.ToUInt16(0x807C)); + s.Position = 0xD215E; + s.Write(Convert.ToUInt16(0x0)); + s.Position = 0xD459A; + s.Write(Convert.ToUInt16(0x807C)); + s.Position = 0xD459E; + s.Write(Convert.ToUInt16(0x0)); + s.Position = 0xEE2B0; + s.Write(Convert.ToUInt32(0xBD00)); + } + + s.Close(); + } + + private static void WriteSequenceNames(RomManager rommgr, MusicSequence[] sequences) + { + rommgr.RomConfig.MusicConfig.SqeuenceNames.Clear(); + rommgr.RomConfig.MusicConfig.SqeuenceNames.AddRange(sequences.Select(n => n.Name)); + } + + private static void WriteNInst(BinaryData s, int TableStart, MusicSequence[] sequences) + { + s.Position = TableStart; + int lastNInstDataOffset = TableStart + sequences.Length * 2; + foreach (MusicSequence ms in sequences) + { + s.Write(Convert.ToUInt16(lastNInstDataOffset - TableStart)); + int lastOff = Convert.ToInt32(s.Position); + ms.InstrumentSets.WriteNInst(s, lastNInstDataOffset); + lastNInstDataOffset += ms.InstrumentSets.NInstLength; + s.Position = lastOff; + } + } + + private static int WriteSequences(BinaryData s, int TableStart, MusicSequence[] sequences, bool WriteData) + { + s.Position = TableStart; + s.Write(Convert.ToInt16(3)); + s.Write(Convert.ToInt16(sequences.Length)); + + // Write sequences to the new Position + int curMsDataOff = General.HexRoundUp1(TableStart + 4 + sequences.Length * 0x8); + foreach (MusicSequence ms in sequences) + { + if (WriteData) + { + s.Write(Convert.ToUInt32(curMsDataOff - TableStart)); + s.Write(Convert.ToUInt32(ms.Lenght)); + int lastOff = Convert.ToInt32(s.Position); + ms.WriteData(s, curMsDataOff); + s.Position = lastOff; + } + + curMsDataOff += General.HexRoundUp1(ms.Lenght); + } + + return curMsDataOff; + } } \ No newline at end of file diff --git a/SM64Lib/Music/MusicSequence.cs b/SM64Lib/Music/MusicSequence.cs index 07d95a1..c07e8b7 100644 --- a/SM64Lib/Music/MusicSequence.cs +++ b/SM64Lib/Music/MusicSequence.cs @@ -1,49 +1,48 @@ -using System; -using global::SM64Lib.Data; +using global::SM64Lib.Data; +using System; -namespace SM64Lib.Music +namespace SM64Lib.Music; + +public class MusicSequence { - public class MusicSequence + private InstrumentSetList _InstrumentSets = new InstrumentSetList(); + + public byte[] BinaryData { get; set; } = Array.Empty(); + public string Name { get; set; } = ""; + + public InstrumentSetList InstrumentSets { - private InstrumentSetList _InstrumentSets = new InstrumentSetList(); - - public byte[] BinaryData { get; set; } = Array.Empty(); - public string Name { get; set; } = ""; - - public InstrumentSetList InstrumentSets + get { - get - { - return _InstrumentSets; - } - - internal set - { - _InstrumentSets = value; - } + return _InstrumentSets; } - public int Lenght + internal set { - get - { - return (int)BinaryData?.Length; - } - } - - public void ReadData(BinaryData s, int RomAddress, int Length) - { - BinaryData = new byte[Length]; - s.Position = RomAddress; - s.Read(BinaryData, 0, Length); - } - - public void WriteData(BinaryData s, int RomAddress) - { - s.Position = RomAddress; - s.Write(BinaryData, 0, BinaryData.Length); - while (s.Position % 0x10 != 0) - s.WriteByte(0xFF); + _InstrumentSets = value; } } + + public int Lenght + { + get + { + return (int)BinaryData?.Length; + } + } + + public void ReadData(BinaryData s, int RomAddress, int Length) + { + BinaryData = new byte[Length]; + s.Position = RomAddress; + s.Read(BinaryData, 0, Length); + } + + public void WriteData(BinaryData s, int RomAddress) + { + s.Position = RomAddress; + s.Write(BinaryData, 0, BinaryData.Length); + while (s.Position % 0x10 != 0) + s.WriteByte(0xFF); + } } \ No newline at end of file diff --git a/SM64Lib/NPCs/CoinsManager.cs b/SM64Lib/NPCs/CoinsManager.cs index c78e92e..9e7d9f0 100644 --- a/SM64Lib/NPCs/CoinsManager.cs +++ b/SM64Lib/NPCs/CoinsManager.cs @@ -1,189 +1,186 @@ -using System; +using global::SM64Lib.Data; using global::System.IO; -using Microsoft.VisualBasic.CompilerServices; -using global::SM64Lib.Data; -using System.Collections.Generic; +using System; -namespace SM64Lib.NPCs +namespace SM64Lib.NPCs; + +public class CoinsManager { - public class CoinsManager + public RomManager RomManager { get; private set; } + public short CoinsForRedCoinsStar { get; set; } = 8; + public short CoinsForBowserRedCoinsStar { get; set; } = 8; + public byte CoinsFor100CoinsStar { get; set; } = 0; + public bool Enable100CoinsStar { get; set; } = true; + public bool EnableCoinCounterInHubs { get; set; } = false; + public bool CoinsRestoreHealth { get; set; } = true; + public bool EnableNewRedCoinsCounter { get; set; } = false; + public string NewRedCoinsCounterTextForCoins { get; set; } = ""; + public string NewRedCoinsCounterTextForCoin { get; set; } = ""; + + public CoinsManager(RomManager rommgr) { - public RomManager RomManager { get; private set; } - public short CoinsForRedCoinsStar { get; set; } = 8; - public short CoinsForBowserRedCoinsStar { get; set; } = 8; - public byte CoinsFor100CoinsStar { get; set; } = 0; - public bool Enable100CoinsStar { get; set; } = true; - public bool EnableCoinCounterInHubs { get; set; } = false; - public bool CoinsRestoreHealth { get; set; } = true; - public bool EnableNewRedCoinsCounter { get; set; } = false; - public string NewRedCoinsCounterTextForCoins { get; set; } = ""; - public string NewRedCoinsCounterTextForCoin { get; set; } = ""; + RomManager = rommgr; + } - public CoinsManager(RomManager rommgr) + /// + /// Loads all the properties from ROM. + /// + public void LoadCoinSettings() + { + BinaryData data = RomManager.GetBinaryRom(FileAccess.Read); + + // Coins for Red Coins Star + data.Position = 0xADDDE; + CoinsForRedCoinsStar = data.ReadInt16(); + + // Coins for Bowser Red Coins Star + data.Position = 0xADF82; + CoinsForBowserRedCoinsStar = data.ReadInt16(); + + // Coins for 100 Coins Star + data.Position = 0x8BB3; + CoinsFor100CoinsStar = data.ReadByte(); + + // Enable 100 Coins + data.Position = 0x8BC8; + Enable100CoinsStar = data.ReadInt32() != 0; + + // Enable Coins Counter in Hubs + data.Position = 0x61AB; + EnableCoinCounterInHubs = data.ReadByte() == 0xFF; + + // Coins restore health + data.Position = 0x8B70; + CoinsRestoreHealth = data.ReadInt32() != 0; + + // Enable New Red Coins Counter + data.Position = 0x966E8; + EnableNewRedCoinsCounter = data.ReadInt32() == 0x27BDFFE8; + + // New Red Coins Counter Text For Coins + if (EnableNewRedCoinsCounter) { - RomManager = rommgr; + data.Position = 0x69908; + NewRedCoinsCounterTextForCoins = System.Text.Encoding.ASCII.GetString(data.Read(0x10)).Trim(); + } + else + { + NewRedCoinsCounterTextForCoins = "%d RED COINS"; } - /// - /// Loads all the properties from ROM. - /// - public void LoadCoinSettings() + // New Red Coins Counter Text For Coins + if (EnableNewRedCoinsCounter) { - BinaryData data = RomManager.GetBinaryRom(FileAccess.Read); - - // Coins for Red Coins Star - data.Position = 0xADDDE; - CoinsForRedCoinsStar = data.ReadInt16(); - - // Coins for Bowser Red Coins Star - data.Position = 0xADF82; - CoinsForBowserRedCoinsStar = data.ReadInt16(); - - // Coins for 100 Coins Star - data.Position = 0x8BB3; - CoinsFor100CoinsStar = data.ReadByte(); - - // Enable 100 Coins - data.Position = 0x8BC8; - Enable100CoinsStar = data.ReadInt32() != 0; - - // Enable Coins Counter in Hubs - data.Position = 0x61AB; - EnableCoinCounterInHubs = data.ReadByte() == 0xFF; - - // Coins restore health - data.Position = 0x8B70; - CoinsRestoreHealth = data.ReadInt32() != 0; - - // Enable New Red Coins Counter - data.Position = 0x966E8; - EnableNewRedCoinsCounter = data.ReadInt32() == 0x27BDFFE8; - - // New Red Coins Counter Text For Coins - if (EnableNewRedCoinsCounter) - { - data.Position = 0x69908; - NewRedCoinsCounterTextForCoins = System.Text.Encoding.ASCII.GetString(data.Read(0x10)).Trim(); - } - else - { - NewRedCoinsCounterTextForCoins = "%d RED COINS"; - } - - // New Red Coins Counter Text For Coins - if (EnableNewRedCoinsCounter) - { - data.Position = 0x69918; - NewRedCoinsCounterTextForCoin = System.Text.Encoding.ASCII.GetString(data.Read(0x10)).Trim(); - } - else - { - NewRedCoinsCounterTextForCoin = "%d RED COIN"; - } - - data.Close(); + data.Position = 0x69918; + NewRedCoinsCounterTextForCoin = System.Text.Encoding.ASCII.GetString(data.Read(0x10)).Trim(); + } + else + { + NewRedCoinsCounterTextForCoin = "%d RED COIN"; } - /// - /// Saves all the properties to ROM and updates checksum. - /// - public void SaveCoinSettings() + data.Close(); + } + + /// + /// Saves all the properties to ROM and updates checksum. + /// + public void SaveCoinSettings() + { + SaveCoinSettings(true); + } + + /// + /// Saves all the properties to ROM and updates checksum if requested. + /// + public void SaveCoinSettings(bool updateChecksum) + { + BinaryData data = RomManager.GetBinaryRom(FileAccess.ReadWrite); + + // Coins for Red Coins Star + data.Position = 0xADDDE; + data.Write(CoinsForRedCoinsStar); + + // Coins for Bowser Red Coins Star + data.Position = 0xADF82; + data.Write(CoinsForBowserRedCoinsStar); + + // Coins for 100 Coins Star + data.Position = 0x8BB3; + data.Write(CoinsFor100CoinsStar); + data.Position = 0x8BBF; + data.Write(CoinsFor100CoinsStar); + data.Position = 0x8BB4; + data.Write(Convert.ToInt16(0x1020)); + + // Enable 100 Coins + data.Position = 0x8BC8; + if (Enable100CoinsStar) { - SaveCoinSettings(true); + data.Write(0xC0AAD56); + } + else + { + data.Write(0); } - /// - /// Saves all the properties to ROM and updates checksum if requested. - /// - public void SaveCoinSettings(bool updateChecksum) + // Enable Coins Counter in Hubs + data.Position = 0x61AB; + if (EnableCoinCounterInHubs) { - BinaryData data = RomManager.GetBinaryRom(FileAccess.ReadWrite); + data.WriteByte(0xFF); + } + else + { + data.WriteByte(0xFD); + } - // Coins for Red Coins Star - data.Position = 0xADDDE; - data.Write(CoinsForRedCoinsStar); + // Coins restore health + data.Position = 0x8B70; + if (CoinsRestoreHealth) + { + data.Write(0xA13800B3); + } + else + { + data.Write(0); + } - // Coins for Bowser Red Coins Star - data.Position = 0xADF82; - data.Write(CoinsForBowserRedCoinsStar); + // Enable New Red Coins Counter + data.Position = 0x966E8; + string nrccCode; + if (EnableNewRedCoinsCounter) + { + nrccCode = "27 BD FF E8 AF BF 00 14 3C 0E 80 36 81 C7 13 FE 10 E0 00 10 00 00 00 00 24 01 00 01 10 E1 00 08 00 00 00 00 24 05 00 24 3C 06 80 2A 34 C6 E9 08 0C 0B 58 B6 24 04 00 A0 10 00 00 06 00 00 00 00 24 05 00 24 3C 06 80 2A 34 C6 E9 18 0C 0B 58 B6 24 04 00 A0 8F BF 00 14 03 E0 00 08 27 BD 00 18"; + } + else + { + nrccCode = "27 BD FF E0 AF BF 00 14 3C 0E 80 36 81 CE 13 FE A3 A0 00 1F 19 C0 00 12 00 00 00 00 83 AF 00 1F 24 19 01 22 24 05 00 10 00 0F C0 80 03 0F C0 21 00 18 C0 80 0C 0B 6D 26 03 38 20 23 83 A8 00 1F 3C 0C 80 36 81 8C 13 FE 25 09 00 01 00 09 56 00 00 0A 5E 03 01 6C 08 2A 14 20 FF F0 A3 A9 00 1F"; + } - // Coins for 100 Coins Star - data.Position = 0x8BB3; - data.Write(CoinsFor100CoinsStar); - data.Position = 0x8BBF; - data.Write(CoinsFor100CoinsStar); - data.Position = 0x8BB4; - data.Write(Convert.ToInt16(0x1020)); + foreach (string b in nrccCode.Split(' ')) + data.Write(Convert.ToByte(b, 16)); - // Enable 100 Coins - data.Position = 0x8BC8; - if (Enable100CoinsStar) - { - data.Write(0xC0AAD56); - } - else - { - data.Write(0); - } + // New Red Coins Counter Text For Coins + if (EnableNewRedCoinsCounter) + { + data.Position = 0x69908; + data.Write(System.Text.Encoding.ASCII.GetBytes(General.FillStrToCharCount(NewRedCoinsCounterTextForCoins, 0x10, " "))); + } - // Enable Coins Counter in Hubs - data.Position = 0x61AB; - if (EnableCoinCounterInHubs) - { - data.WriteByte(0xFF); - } - else - { - data.WriteByte(0xFD); - } + // New Red Coins Counter Text For Coins + if (EnableNewRedCoinsCounter) + { + data.Position = 0x69918; + data.Write(System.Text.Encoding.ASCII.GetBytes(General.FillStrToCharCount(NewRedCoinsCounterTextForCoin, 0x10, " "))); + } - // Coins restore health - data.Position = 0x8B70; - if (CoinsRestoreHealth) - { - data.Write(0xA13800B3); - } - else - { - data.Write(0); - } + data.Close(); - // Enable New Red Coins Counter - data.Position = 0x966E8; - string nrccCode; - if (EnableNewRedCoinsCounter) - { - nrccCode = "27 BD FF E8 AF BF 00 14 3C 0E 80 36 81 C7 13 FE 10 E0 00 10 00 00 00 00 24 01 00 01 10 E1 00 08 00 00 00 00 24 05 00 24 3C 06 80 2A 34 C6 E9 08 0C 0B 58 B6 24 04 00 A0 10 00 00 06 00 00 00 00 24 05 00 24 3C 06 80 2A 34 C6 E9 18 0C 0B 58 B6 24 04 00 A0 8F BF 00 14 03 E0 00 08 27 BD 00 18"; - } - else - { - nrccCode = "27 BD FF E0 AF BF 00 14 3C 0E 80 36 81 CE 13 FE A3 A0 00 1F 19 C0 00 12 00 00 00 00 83 AF 00 1F 24 19 01 22 24 05 00 10 00 0F C0 80 03 0F C0 21 00 18 C0 80 0C 0B 6D 26 03 38 20 23 83 A8 00 1F 3C 0C 80 36 81 8C 13 FE 25 09 00 01 00 09 56 00 00 0A 5E 03 01 6C 08 2A 14 20 FF F0 A3 A9 00 1F"; - } - - foreach (string b in nrccCode.Split(' ')) - data.Write(Convert.ToByte(b, 16)); - - // New Red Coins Counter Text For Coins - if (EnableNewRedCoinsCounter) - { - data.Position = 0x69908; - data.Write(System.Text.Encoding.ASCII.GetBytes(General.FillStrToCharCount(NewRedCoinsCounterTextForCoins, 0x10, " "))); - } - - // New Red Coins Counter Text For Coins - if (EnableNewRedCoinsCounter) - { - data.Position = 0x69918; - data.Write(System.Text.Encoding.ASCII.GetBytes(General.FillStrToCharCount(NewRedCoinsCounterTextForCoin, 0x10, " "))); - } - - data.Close(); - - // Update checksum (because of code changes) - if (updateChecksum) - { - General.PatchClass.UpdateChecksum(RomManager.RomFile); - } + // Update checksum (because of code changes) + if (updateChecksum) + { + General.PatchClass.UpdateChecksum(RomManager.RomFile); } } } \ No newline at end of file diff --git a/SM64Lib/Objects/ItemBoxContents/ItemBoxContentEntry.cs b/SM64Lib/Objects/ItemBoxContents/ItemBoxContentEntry.cs index 19f89c4..9a1c959 100644 --- a/SM64Lib/Objects/ItemBoxContents/ItemBoxContentEntry.cs +++ b/SM64Lib/Objects/ItemBoxContents/ItemBoxContentEntry.cs @@ -1,13 +1,10 @@ -using System.ComponentModel; +namespace SM64Lib.Objects; -namespace SM64Lib.Objects +public class ItemBoxContentEntry { - public class ItemBoxContentEntry - { - public byte ID { get; set; } - public byte ModelID { get; set; } - public byte BParam1 { get; set; } - public byte BParam2 { get; set; } - public uint BehavAddress { get; set; } - } + public byte ID { get; set; } + public byte ModelID { get; set; } + public byte BParam1 { get; set; } + public byte BParam2 { get; set; } + public uint BehavAddress { get; set; } } \ No newline at end of file diff --git a/SM64Lib/Objects/ItemBoxContents/ItemBoxContentManager.cs b/SM64Lib/Objects/ItemBoxContents/ItemBoxContentManager.cs index 515a927..4f0cc57 100644 --- a/SM64Lib/Objects/ItemBoxContents/ItemBoxContentManager.cs +++ b/SM64Lib/Objects/ItemBoxContents/ItemBoxContentManager.cs @@ -1,263 +1,261 @@ -using System; -using global::System.IO; -using Microsoft.VisualBasic.CompilerServices; -using global::Newtonsoft.Json.Linq; +using global::Newtonsoft.Json.Linq; using global::SM64Lib.Data; +using global::System.IO; +using System; -namespace SM64Lib.Objects +namespace SM64Lib.Objects; + +public class ItemBoxContentManager { - public class ItemBoxContentManager + private const uint TableRamLocation = 0x80404000U; + private const uint TableRomLocationCustom = 0x1204000; + private const uint TableRomLocationOriginal = 0xEBBA0; + + public ItemBoxContentTable ContentTable { get; private set; } + + public ItemBoxContentManager() { - private const uint TableRamLocation = 0x80404000U; - private const uint TableRomLocationCustom = 0x1204000; - private const uint TableRomLocationOriginal = 0xEBBA0; + ContentTable = new ItemBoxContentTable(); + } - public ItemBoxContentTable ContentTable { get; private set; } + public ItemBoxContentManager(ItemBoxContentTable table) + { + ContentTable = table; + } - public ItemBoxContentManager() + public void Read(RomManager rommgr) + { + Read(rommgr, true); + } + + public void Read(RomManager rommgr, bool clearList) + { + try { - ContentTable = new ItemBoxContentTable(); - } - - public ItemBoxContentManager(ItemBoxContentTable table) - { - ContentTable = table; - } - - public void Read(RomManager rommgr) - { - Read(rommgr, true); - } - - public void Read(RomManager rommgr, bool clearList) - { - try - { - BinaryRom rom; - if (clearList) - ContentTable.Clear(); - rom = rommgr.GetBinaryRom(FileAccess.Read); - - // Get RAM location - uint address = GetRamLocation(rom); - - // Set ROM position - if (address == TableRamLocation) - { - address = TableRomLocationCustom; - } - else - { - address = TableRomLocationOriginal; - } - - // Read table - Read(rom, address); - rom.Close(); - } - catch (Exception ex) - { - throw new Exception("Error at reading table from ROM.", ex); - } - } - - private uint GetRamLocation(BinaryData rom) - { - uint address; - rom.Position = 0x7C8E2; - address = Convert.ToUInt32(rom.ReadUInt16()) << 16; - rom.Position = 0x7C8E6; - address = address | rom.ReadUInt16(); - return address; - } - - public void ResetToOriginal(RomManager rommgr) - { - try - { - var rom = rommgr.GetBinaryRom(FileAccess.Read); + BinaryRom rom; + if (clearList) ContentTable.Clear(); - Read(rom, TableRomLocationOriginal); - rom.Close(); - } - catch (Exception ex) - { - throw new Exception("Error at reading original content from ROM.", ex); - } - } + rom = rommgr.GetBinaryRom(FileAccess.Read); - private void Read(BinaryRom rom, uint location) - { - int curID = -1; - rom.Position = location; - while (rom.ReadUInt64() != (decimal)0x6300000000000000) - { - var entry = new ItemBoxContentEntry(); - rom.Position -= 8; - curID = rom.ReadByte(); - entry.ID = Convert.ToByte(curID); - entry.BParam1 = rom.ReadByte(); - entry.BParam2 = rom.ReadByte(); - entry.ModelID = rom.ReadByte(); - entry.BehavAddress = rom.ReadUInt32(); - ContentTable.Add(entry); - } - } - - public void Write(RomManager rommgr) - { - try - { - var rom = rommgr.GetBinaryRom(FileAccess.ReadWrite); - - // Set ROM position - rom.Position = TableRomLocationCustom; - - // Write data of each entry in the list - for (int i = 0, loopTo = ContentTable.Count - 1; i <= loopTo; i++) - { - var entry = ContentTable[i]; - rom.Write(Convert.ToByte(i)); - rom.Write(entry.BParam1); - rom.Write(entry.BParam2); - rom.Write(entry.ModelID); - rom.Write(entry.BehavAddress); - } - - // Finish table - rom.Write(0x6300000000000000); - - // Update RAM Pointer in the ASM Code - bool shouldUpdate = WriteNewPointer(rom); - rom.Close(); - - // Update Checksum - if (shouldUpdate) - { - General.PatchClass.UpdateChecksum(rommgr.RomFile); - } - } - catch (Exception ex) - { - throw new Exception("Error at writing table to ROM.", ex); - } - } - - private bool WriteNewPointer(BinaryRom rom) - { // Get RAM location uint address = GetRamLocation(rom); // Set ROM position - if (address != TableRamLocation) + if (address == TableRamLocation) { - rom.Position = 0x7C8E2; - rom.Write(Convert.ToUInt16(TableRamLocation >> 16 & (long)0xFFFF)); - rom.Position = 0x7C8E6; - rom.Write(Convert.ToUInt16(TableRamLocation & (long)0xFFFF)); - return true; + address = TableRomLocationCustom; + } + else + { + address = TableRomLocationOriginal; } - return false; + // Read table + Read(rom, address); + rom.Close(); } - - public void Read(string fileName) + catch (Exception ex) { - Read(fileName, true); - } - - public void Read(string fileName, bool clearList) - { - if (clearList) - ContentTable.Clear(); - try - { - var switchExpr = Path.GetExtension(fileName).ToLower(); - switch (switchExpr) - { - case ".ibc": - { - ReadFromJson(fileName); - break; - } - - case ".txt": - { - ReadFromTxt(fileName); - break; - } - } - } - catch (Exception ex) - { - throw new FormatException("Error at reading file. It probably has a wrong format.", ex); - } - } - - public void Write(string fileName) - { - try - { - var switchExpr = Path.GetExtension(fileName).ToLower(); - switch (switchExpr) - { - case ".ibc": - { - WriteToJson(fileName); - break; - } - - case ".txt": - { - WriteToTxt(fileName); - break; - } - } - } - catch (Exception ex) - { - throw new FormatException("Error at reading file. It probably has a wrong format.", ex); - } - } - - private void ReadFromJson(string fileName) - { - var ct = JToken.Parse(File.ReadAllText(fileName)).ToObject(); - ContentTable.AddRange(ct.ToArray()); - } - - private void ReadFromTxt(string fileName) - { - foreach (string line in File.ReadAllLines(fileName)) - { - var vals = line.Split(','); - var entry = new ItemBoxContentEntry(); - entry.ID = Convert.ToByte(vals[0].Trim(), 16); - vals[1] = vals[1].Trim(); - entry.BParam1 = Convert.ToByte(vals[1].Substring(0, 2), 16); - entry.BParam2 = Convert.ToByte(vals[1].Substring(2, 2), 16); - entry.ModelID = Convert.ToByte(vals[2].Trim(), 16); - entry.BehavAddress = Convert.ToUInt32(vals[3].Trim(), 16); - ContentTable.Add(entry); - } - } - - private void WriteToJson(string fileName) - { - File.WriteAllText(fileName, JToken.FromObject(ContentTable).ToString()); - } - - private void WriteToTxt(string fileName) - { - var sw = new StreamWriter(fileName); - foreach (ItemBoxContentEntry entry in ContentTable) - { - ushort bparams = (ushort)(Convert.ToUInt16(entry.BParam1) << 16 | entry.BParam2); - sw.WriteLine($"{entry.ID.ToString("X2")}, {bparams.ToString("X4")}, {entry.ModelID.ToString("X2")}, {entry.BehavAddress.ToString("X8")}"); - } - - sw.Flush(); - sw.Close(); + throw new Exception("Error at reading table from ROM.", ex); } } + + private uint GetRamLocation(BinaryData rom) + { + uint address; + rom.Position = 0x7C8E2; + address = Convert.ToUInt32(rom.ReadUInt16()) << 16; + rom.Position = 0x7C8E6; + address = address | rom.ReadUInt16(); + return address; + } + + public void ResetToOriginal(RomManager rommgr) + { + try + { + var rom = rommgr.GetBinaryRom(FileAccess.Read); + ContentTable.Clear(); + Read(rom, TableRomLocationOriginal); + rom.Close(); + } + catch (Exception ex) + { + throw new Exception("Error at reading original content from ROM.", ex); + } + } + + private void Read(BinaryRom rom, uint location) + { + int curID = -1; + rom.Position = location; + while (rom.ReadUInt64() != (decimal)0x6300000000000000) + { + var entry = new ItemBoxContentEntry(); + rom.Position -= 8; + curID = rom.ReadByte(); + entry.ID = Convert.ToByte(curID); + entry.BParam1 = rom.ReadByte(); + entry.BParam2 = rom.ReadByte(); + entry.ModelID = rom.ReadByte(); + entry.BehavAddress = rom.ReadUInt32(); + ContentTable.Add(entry); + } + } + + public void Write(RomManager rommgr) + { + try + { + var rom = rommgr.GetBinaryRom(FileAccess.ReadWrite); + + // Set ROM position + rom.Position = TableRomLocationCustom; + + // Write data of each entry in the list + for (int i = 0, loopTo = ContentTable.Count - 1; i <= loopTo; i++) + { + var entry = ContentTable[i]; + rom.Write(Convert.ToByte(i)); + rom.Write(entry.BParam1); + rom.Write(entry.BParam2); + rom.Write(entry.ModelID); + rom.Write(entry.BehavAddress); + } + + // Finish table + rom.Write(0x6300000000000000); + + // Update RAM Pointer in the ASM Code + bool shouldUpdate = WriteNewPointer(rom); + rom.Close(); + + // Update Checksum + if (shouldUpdate) + { + General.PatchClass.UpdateChecksum(rommgr.RomFile); + } + } + catch (Exception ex) + { + throw new Exception("Error at writing table to ROM.", ex); + } + } + + private bool WriteNewPointer(BinaryRom rom) + { + // Get RAM location + uint address = GetRamLocation(rom); + + // Set ROM position + if (address != TableRamLocation) + { + rom.Position = 0x7C8E2; + rom.Write(Convert.ToUInt16(TableRamLocation >> 16 & (long)0xFFFF)); + rom.Position = 0x7C8E6; + rom.Write(Convert.ToUInt16(TableRamLocation & (long)0xFFFF)); + return true; + } + + return false; + } + + public void Read(string fileName) + { + Read(fileName, true); + } + + public void Read(string fileName, bool clearList) + { + if (clearList) + ContentTable.Clear(); + try + { + var switchExpr = Path.GetExtension(fileName).ToLower(); + switch (switchExpr) + { + case ".ibc": + { + ReadFromJson(fileName); + break; + } + + case ".txt": + { + ReadFromTxt(fileName); + break; + } + } + } + catch (Exception ex) + { + throw new FormatException("Error at reading file. It probably has a wrong format.", ex); + } + } + + public void Write(string fileName) + { + try + { + var switchExpr = Path.GetExtension(fileName).ToLower(); + switch (switchExpr) + { + case ".ibc": + { + WriteToJson(fileName); + break; + } + + case ".txt": + { + WriteToTxt(fileName); + break; + } + } + } + catch (Exception ex) + { + throw new FormatException("Error at reading file. It probably has a wrong format.", ex); + } + } + + private void ReadFromJson(string fileName) + { + var ct = JToken.Parse(File.ReadAllText(fileName)).ToObject(); + ContentTable.AddRange(ct.ToArray()); + } + + private void ReadFromTxt(string fileName) + { + foreach (string line in File.ReadAllLines(fileName)) + { + var vals = line.Split(','); + var entry = new ItemBoxContentEntry(); + entry.ID = Convert.ToByte(vals[0].Trim(), 16); + vals[1] = vals[1].Trim(); + entry.BParam1 = Convert.ToByte(vals[1].Substring(0, 2), 16); + entry.BParam2 = Convert.ToByte(vals[1].Substring(2, 2), 16); + entry.ModelID = Convert.ToByte(vals[2].Trim(), 16); + entry.BehavAddress = Convert.ToUInt32(vals[3].Trim(), 16); + ContentTable.Add(entry); + } + } + + private void WriteToJson(string fileName) + { + File.WriteAllText(fileName, JToken.FromObject(ContentTable).ToString()); + } + + private void WriteToTxt(string fileName) + { + var sw = new StreamWriter(fileName); + foreach (ItemBoxContentEntry entry in ContentTable) + { + ushort bparams = (ushort)(Convert.ToUInt16(entry.BParam1) << 16 | entry.BParam2); + sw.WriteLine($"{entry.ID.ToString("X2")}, {bparams.ToString("X4")}, {entry.ModelID.ToString("X2")}, {entry.BehavAddress.ToString("X8")}"); + } + + sw.Flush(); + sw.Close(); + } } \ No newline at end of file diff --git a/SM64Lib/Objects/ItemBoxContents/ItemBoxContentTable.cs b/SM64Lib/Objects/ItemBoxContents/ItemBoxContentTable.cs index a5b672f..5025950 100644 --- a/SM64Lib/Objects/ItemBoxContents/ItemBoxContentTable.cs +++ b/SM64Lib/Objects/ItemBoxContents/ItemBoxContentTable.cs @@ -1,8 +1,7 @@ using System.Collections.Generic; -namespace SM64Lib.Objects +namespace SM64Lib.Objects; + +public class ItemBoxContentTable : List { - public class ItemBoxContentTable : List - { - } } \ No newline at end of file diff --git a/SM64Lib/Objects/ModelBanks/CustomModel.cs b/SM64Lib/Objects/ModelBanks/CustomModel.cs index acfdf0e..39b15dc 100644 --- a/SM64Lib/Objects/ModelBanks/CustomModel.cs +++ b/SM64Lib/Objects/ModelBanks/CustomModel.cs @@ -1,45 +1,44 @@ using global::SM64Lib.Configuration; using Newtonsoft.Json; -namespace SM64Lib.Objects.ModelBanks +namespace SM64Lib.Objects.ModelBanks; + +public class CustomModel { - public class CustomModel + public CustomModelConfig Config { get; set; } = new CustomModelConfig(); + public Geolayout.Geolayout Geolayout { get; set; } = null; + public Model.ObjectModel Model { get; set; } = null; + public byte ModelID { get; set; } = 0; + + [JsonProperty] + public int ModelBankOffset { get; internal set; } = 0; + [JsonProperty] + public int GeolayoutBankOffset { get; internal set; } = 0; + [JsonProperty] + public int CollisionPointer { get; internal set; } = 0; + + public CustomModel() { - public CustomModelConfig Config { get; set; } = new CustomModelConfig(); - public Geolayout.Geolayout Geolayout { get; set; } = null; - public Model.ObjectModel Model { get; set; } = null; - public byte ModelID { get; set; } = 0; + } - [JsonProperty] - public int ModelBankOffset { get; internal set; } = 0; - [JsonProperty] - public int GeolayoutBankOffset { get; internal set; } = 0; - [JsonProperty] - public int CollisionPointer { get; internal set; } = 0; + public CustomModel(Model.ObjectModel mdl) + { + Model = mdl; + } - public CustomModel() - { - } + public CustomModel(Geolayout.Geolayout geo) + { + Geolayout = geo; + } - public CustomModel(Model.ObjectModel mdl) - { - Model = mdl; - } + public CustomModel(Geolayout.Geolayout geo, Model.ObjectModel mdl) + { + Geolayout = geo; + Model = mdl; + } - public CustomModel(Geolayout.Geolayout geo) - { - Geolayout = geo; - } - - public CustomModel(Geolayout.Geolayout geo, Model.ObjectModel mdl) - { - Geolayout = geo; - Model = mdl; - } - - public void GenerateNewGeolayout() - { - Geolayout = new Geolayout.Geolayout(SM64Lib.Geolayout.Geolayout.NewScriptCreationMode.Object); - } + public void GenerateNewGeolayout() + { + Geolayout = new Geolayout.Geolayout(SM64Lib.Geolayout.Geolayout.NewScriptCreationMode.Object); } } \ No newline at end of file diff --git a/SM64Lib/Objects/ModelBanks/CustomModelBank.cs b/SM64Lib/Objects/ModelBanks/CustomModelBank.cs index da17281..0b1e9a4 100644 --- a/SM64Lib/Objects/ModelBanks/CustomModelBank.cs +++ b/SM64Lib/Objects/ModelBanks/CustomModelBank.cs @@ -1,201 +1,199 @@ -using System.Collections.Generic; -using global::System.IO; -using Microsoft.VisualBasic; -using Microsoft.VisualBasic.CompilerServices; -using global::SM64Lib.Configuration; +using global::SM64Lib.Configuration; using global::SM64Lib.Data; using global::SM64Lib.Levels.Script; using global::SM64Lib.Levels.Script.Commands; using global::SM64Lib.SegmentedBanking; +using global::System.IO; +using Microsoft.VisualBasic; using Newtonsoft.Json; using System; +using System.Collections.Generic; -namespace SM64Lib.Objects.ModelBanks +namespace SM64Lib.Objects.ModelBanks; + +public class CustomModelBank { - public class CustomModelBank + public ObjectModelConfig Config { get; private set; } = new ObjectModelConfig(); + public List Models { get; private set; } = new List(); + public SegmentedBank CurSeg { get; private set; } = null; + public bool NeedToSave { get; set; } = false; + public Levelscript Levelscript { get; private set; } = new Levelscript(); + + [JsonIgnore] + public int Length { - public ObjectModelConfig Config { get; private set; } = new ObjectModelConfig(); - public List Models { get; private set; } = new List(); - public SegmentedBank CurSeg { get; private set; } = null; - public bool NeedToSave { get; set; } = false; - public Levelscript Levelscript { get; private set; } = new Levelscript(); - - [JsonIgnore] - public int Length + get { - get - { - var length = General.HexRoundUp1(CalcLevelscriptLength()); + var length = General.HexRoundUp1(CalcLevelscriptLength()); - foreach (var mdl in Models) - length += General.HexRoundUp1(mdl.Model.Length) + General.HexRoundUp1(mdl.Geolayout.Length + 0x40); + foreach (var mdl in Models) + length += General.HexRoundUp1(mdl.Model.Length) + General.HexRoundUp1(mdl.Geolayout.Length + 0x40); - return length; - } + return length; } + } - private int CalcLevelscriptLength() + private int CalcLevelscriptLength() + { + return General.HexRoundUp1(Models.Count * 8 + 4); + } + + public SegmentedBank WriteToSeg(byte bankID, CollisionBasicConfig collisionConfig) + { + var segStream = new MemoryStream(); + var seg = new SegmentedBank(bankID, segStream); + int lastPos = WriteToSeg(seg, 0, collisionConfig); + seg.Length = lastPos; + return seg; + } + + public int WriteToSeg(SegmentedBank seg, int offset, CollisionBasicConfig collisionConfig) + { + var data = new BinaryStreamData(seg.Data); + int lastPos = WriteToSeg(data, offset, seg.BankID, collisionConfig); + CurSeg = seg; + return lastPos; + } + + public int WriteToSeg(BinaryData data, int offset, byte bankID, CollisionBasicConfig collisionConfig) + { + uint lvlScriptLength; + int bankAddr = Convert.ToInt32(Convert.ToUInt32(bankID) << 24); + + // Clear the old levelscript + Levelscript.Clear(); + + // Clear Configuration + Config.CustomObjectConfigs.Clear(); + + // Calculate space of Levelscript + lvlScriptLength = (uint)CalcLevelscriptLength(); + + // Start Custom Objects + data.Position = offset + lvlScriptLength; + for (int i = 0, loopTo = Models.Count - 1; i <= loopTo; i++) { - return General.HexRoundUp1(Models.Count * 8 + 4); - } + var obj = Models[i]; - public SegmentedBank WriteToSeg(byte bankID, CollisionBasicConfig collisionConfig) - { - var segStream = new MemoryStream(); - var seg = new SegmentedBank(bankID, segStream); - int lastPos = WriteToSeg(seg, 0, collisionConfig); - seg.Length = lastPos; - return seg; - } - - public int WriteToSeg(SegmentedBank seg, int offset, CollisionBasicConfig collisionConfig) - { - var data = new BinaryStreamData(seg.Data); - int lastPos = WriteToSeg(data, offset, seg.BankID, collisionConfig); - CurSeg = seg; - return lastPos; - } - - public int WriteToSeg(BinaryData data, int offset, byte bankID, CollisionBasicConfig collisionConfig) - { - uint lvlScriptLength; - int bankAddr = Convert.ToInt32(Convert.ToUInt32(bankID) << 24); - - // Clear the old levelscript - Levelscript.Clear(); - - // Clear Configuration - Config.CustomObjectConfigs.Clear(); - - // Calculate space of Levelscript - lvlScriptLength = (uint)CalcLevelscriptLength(); - - // Start Custom Objects - data.Position = offset + lvlScriptLength; - for (int i = 0, loopTo = Models.Count - 1; i <= loopTo; i++) - { - var obj = Models[i]; - - // Write Object Model - obj.ModelBankOffset = Convert.ToInt32(data.Position - offset); - var sr = obj.Model.ToBinaryData(data, Convert.ToInt32(data.Position), offset, bankAddr, collisionConfig); - data.RoundUpPosition(); - - // Write Model Offset & Length & Collision Offset - data.Write(obj.ModelBankOffset); - data.Write(Convert.ToInt32(obj.Model.Fast3DBuffer.Length)); - data.Write(sr.CollisionPointer == -1 ? -1 : sr.CollisionPointer & 0xFFFFFF); - obj.CollisionPointer = sr.CollisionPointer; - data.RoundUpPosition(); - - // Copy new Geopointer(s) - obj.Geolayout.Geopointers.Clear(); - obj.Geolayout.Geopointers.AddRange(sr.GeoPointers.ToArray()); - - // Write Geolayout - obj.GeolayoutBankOffset = Convert.ToInt32(data.Position - offset); - obj.Geolayout.Write(data.BaseStream, Convert.ToInt32(data.Position)); - data.RoundUpPosition(0x30); - - // Add object config to object bank config - Config.CustomObjectConfigs.Add(i, obj.Config); - } - - // Set length of segmented + // Write Object Model + obj.ModelBankOffset = Convert.ToInt32(data.Position - offset); + var sr = obj.Model.ToBinaryData(data, Convert.ToInt32(data.Position), offset, bankAddr, collisionConfig); data.RoundUpPosition(); - int lastPosition = Convert.ToInt32(data.Position); - // Create Levelscript - foreach (CustomModel obj in Models) - Levelscript.Add(new LevelscriptCommand($"22 08 00 {obj.ModelID.ToString("X")} {bankID.ToString("X")} {Conversion.Hex(obj.GeolayoutBankOffset >> 16 & 0xFF)} {Conversion.Hex(obj.GeolayoutBankOffset >> 8 & 0xFF)} {Conversion.Hex(obj.GeolayoutBankOffset & 0xFF)}")); - Levelscript.Add(new LevelscriptCommand("07 04 00 00")); - Levelscript.Write(data, offset); - NeedToSave = false; - return lastPosition - offset; - } - - public void WriteCollisionPointers(RomManager rommgr) - { - BinaryData data = rommgr.GetBinaryRom(FileAccess.ReadWrite); - WriteCollisionPointers(data); - data.Close(); + // Write Model Offset & Length & Collision Offset + data.Write(obj.ModelBankOffset); + data.Write(Convert.ToInt32(obj.Model.Fast3DBuffer.Length)); + data.Write(sr.CollisionPointer == -1 ? -1 : sr.CollisionPointer & 0xFFFFFF); + obj.CollisionPointer = sr.CollisionPointer; + data.RoundUpPosition(); + + // Copy new Geopointer(s) + obj.Geolayout.Geopointers.Clear(); + obj.Geolayout.Geopointers.AddRange(sr.GeoPointers.ToArray()); + + // Write Geolayout + obj.GeolayoutBankOffset = Convert.ToInt32(data.Position - offset); + obj.Geolayout.Write(data.BaseStream, Convert.ToInt32(data.Position)); + data.RoundUpPosition(0x30); + + // Add object config to object bank config + Config.CustomObjectConfigs.Add(i, obj.Config); } - public void WriteCollisionPointers(BinaryData data) - { - long posBefore = data.Position; + // Set length of segmented + data.RoundUpPosition(); + int lastPosition = Convert.ToInt32(data.Position); - foreach (CustomModel obj in Models) + // Create Levelscript + foreach (CustomModel obj in Models) + Levelscript.Add(new LevelscriptCommand($"22 08 00 {obj.ModelID.ToString("X")} {bankID.ToString("X")} {Conversion.Hex(obj.GeolayoutBankOffset >> 16 & 0xFF)} {Conversion.Hex(obj.GeolayoutBankOffset >> 8 & 0xFF)} {Conversion.Hex(obj.GeolayoutBankOffset & 0xFF)}")); + Levelscript.Add(new LevelscriptCommand("07 04 00 00")); + Levelscript.Write(data, offset); + NeedToSave = false; + return lastPosition - offset; + } + + public void WriteCollisionPointers(RomManager rommgr) + { + BinaryData data = rommgr.GetBinaryRom(FileAccess.ReadWrite); + WriteCollisionPointers(data); + data.Close(); + } + + public void WriteCollisionPointers(BinaryData data) + { + long posBefore = data.Position; + + foreach (CustomModel obj in Models) + { + foreach (int dest in obj.Config.CollisionPointerDestinations) { - foreach (int dest in obj.Config.CollisionPointerDestinations) - { - data.Position = dest; - data.Write(obj.CollisionPointer); - } + data.Position = dest; + data.Write(obj.CollisionPointer); } - - data.Position = posBefore; } - public void ReadFromSeg(RomManager rommgr, byte bankID, ObjectModelConfig config) + data.Position = posBefore; + } + + public void ReadFromSeg(RomManager rommgr, byte bankID, ObjectModelConfig config) + { + ReadFromSeg(rommgr, rommgr.GetSegBank(bankID), config); + } + + public void ReadFromSeg(RomManager rommgr, SegmentedBank seg, ObjectModelConfig config) + { + Stream s; + BinaryData data; + Levelscript.Clear(); + CurSeg = seg; + s = seg.ReadDataIfNull(rommgr); + data = new BinaryStreamData(s); + + // Get configuration + Config = config; + + // Read Levelscript + Levelscript.Read(rommgr, seg.BankAddress, LevelscriptCommandTypes.JumpBack, new Dictionary() { { seg.BankID, seg } }); + + // Parse Levelscript & Load Models + for (int i = 0, loopTo = Levelscript.Count - 1; i <= loopTo; i++) { - ReadFromSeg(rommgr, rommgr.GetSegBank(bankID), config); - } + LevelscriptCommand cmd = (LevelscriptCommand)Levelscript[i]; - public void ReadFromSeg(RomManager rommgr, SegmentedBank seg, ObjectModelConfig config) - { - Stream s; - BinaryData data; - Levelscript.Clear(); - CurSeg = seg; - s = seg.ReadDataIfNull(rommgr); - data = new BinaryStreamData(s); - - // Get configuration - Config = config; - - // Read Levelscript - Levelscript.Read(rommgr, seg.BankAddress, LevelscriptCommandTypes.JumpBack, new Dictionary() { { seg.BankID, seg } }); - - // Parse Levelscript & Load Models - for (int i = 0, loopTo = Levelscript.Count - 1; i <= loopTo; i++) + switch (cmd.CommandType) { - LevelscriptCommand cmd = (LevelscriptCommand)Levelscript[i]; + case LevelscriptCommandTypes.LoadPolygonWithGeo: + var obj = new CustomModel() { Config = config.GetCustomObjectConfig(i) }; - switch (cmd.CommandType) - { - case LevelscriptCommandTypes.LoadPolygonWithGeo: - var obj = new CustomModel() { Config = config.GetCustomObjectConfig(i) }; + // Load Model ID & Geolayout Offset + obj.ModelID = clLoadPolygonWithGeo.GetModelID(cmd); + int geoAddr = clLoadPolygonWithGeo.GetSegAddress(cmd); + obj.GeolayoutBankOffset = geoAddr & 0xFFFFFF; - // Load Model ID & Geolayout Offset - obj.ModelID = clLoadPolygonWithGeo.GetModelID(cmd); - int geoAddr = clLoadPolygonWithGeo.GetSegAddress(cmd); - obj.GeolayoutBankOffset = geoAddr & 0xFFFFFF; + if (geoAddr >> 24 == seg.BankID) + { + // Load Model Offset & Length + data.Position = obj.GeolayoutBankOffset - 0x10; + obj.ModelBankOffset = data.ReadInt32(); + int f3d_length = data.ReadInt32(); + int colOffset = data.ReadInt32(); + int colPointer = colOffset | seg.BankAddress; + obj.CollisionPointer = colPointer; - if (geoAddr >> 24 == seg.BankID) - { - // Load Model Offset & Length - data.Position = obj.GeolayoutBankOffset - 0x10; - obj.ModelBankOffset = data.ReadInt32(); - int f3d_length = data.ReadInt32(); - int colOffset = data.ReadInt32(); - int colPointer = colOffset | seg.BankAddress; - obj.CollisionPointer = colPointer; + // Load Geolayout + obj.Geolayout = new Geolayout.Geolayout(Geolayout.Geolayout.NewScriptCreationMode.None); + obj.Geolayout.Read(rommgr, geoAddr); - // Load Geolayout - obj.Geolayout = new Geolayout.Geolayout(Geolayout.Geolayout.NewScriptCreationMode.None); - obj.Geolayout.Read(rommgr, geoAddr); + // Load Model + obj.Model = new Model.ObjectModel(); + obj.Model.FromBinaryData(data, 0, seg.BankAddress, obj.ModelBankOffset, f3d_length, obj.Geolayout.Geopointers.ToArray(), colPointer, rommgr.RomConfig.CollisionBaseConfig); - // Load Model - obj.Model = new Model.ObjectModel(); - obj.Model.FromBinaryData(data, 0, seg.BankAddress, obj.ModelBankOffset, f3d_length, obj.Geolayout.Geopointers.ToArray(), colPointer, rommgr.RomConfig.CollisionBaseConfig); + // Add Object to list + Models.Add(obj); + } - // Add Object to list - Models.Add(obj); - } - - break; - } + break; } } } diff --git a/SM64Lib/Objects/ObjectBanks/CustomObject.cs b/SM64Lib/Objects/ObjectBanks/CustomObject.cs index 3e550a7..17bfdf5 100644 --- a/SM64Lib/Objects/ObjectBanks/CustomObject.cs +++ b/SM64Lib/Objects/ObjectBanks/CustomObject.cs @@ -1,35 +1,29 @@ using Newtonsoft.Json; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Pilz.Cryptography; using Pilz.Json.Converters; -namespace SM64Lib.Objects.ObjectBanks +namespace SM64Lib.Objects.ObjectBanks; + +public class CustomObject { - public class CustomObject + [JsonConverter(typeof(UniquieIDStringJsonConverter))] + public UniquieID ID { get; set; } = new(); + public string Name { get; set; } + public string Description { get; set; } + public CustomObjectBehaviorProps BehaviorProps { get; private set; } = new CustomObjectBehaviorProps(); + public CustomObjectModelProps ModelProps { get; private set; } = new CustomObjectModelProps(); + + public void TakeoverProperties(RomManager rommgr) { - [JsonConverter(typeof(UniquieIDStringJsonConverter))] - public UniquieID ID { get; set; } = new(); - public string Name { get; set; } - public string Description { get; set; } - public CustomObjectBehaviorProps BehaviorProps { get; private set; } = new CustomObjectBehaviorProps(); - public CustomObjectModelProps ModelProps { get; private set; } = new CustomObjectModelProps(); - - public void TakeoverProperties(RomManager rommgr) + var behav = BehaviorProps.Behavior?.FindBehavior(); + if (behav is not null && BehaviorProps.UseCollisionPointerOfModel && BehaviorProps.Behavior is not null && (!BehaviorProps.Behavior.IsVanilla || behav.EnableCollisionPointer) && ModelProps.Model is not null) { - var behav = BehaviorProps.Behavior?.FindBehavior(); - if (behav is not null && BehaviorProps.UseCollisionPointerOfModel && BehaviorProps.Behavior is not null && (!BehaviorProps.Behavior.IsVanilla || behav.EnableCollisionPointer) && ModelProps.Model is not null) - { - var mdl = ModelProps.Model?.FindModel(); + var mdl = ModelProps.Model?.FindModel(); - if (mdl?.Model?.Collision is not null && mdl.CollisionPointer != -1) - { - behav.CollisionPointer = mdl.CollisionPointer; - behav.EnableCollisionPointer = true; - } + if (mdl?.Model?.Collision is not null && mdl.CollisionPointer != -1) + { + behav.CollisionPointer = mdl.CollisionPointer; + behav.EnableCollisionPointer = true; } } } diff --git a/SM64Lib/Objects/ObjectBanks/CustomObjectBehaviorProps.cs b/SM64Lib/Objects/ObjectBanks/CustomObjectBehaviorProps.cs index 2ceaabb..1f9bdd9 100644 --- a/SM64Lib/Objects/ObjectBanks/CustomObjectBehaviorProps.cs +++ b/SM64Lib/Objects/ObjectBanks/CustomObjectBehaviorProps.cs @@ -1,39 +1,33 @@ using Newtonsoft.Json; using SM64Lib.Behaviors; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace SM64Lib.Objects.ObjectBanks +namespace SM64Lib.Objects.ObjectBanks; + +public class CustomObjectBehaviorProps { - public class CustomObjectBehaviorProps + public BehaviorConfig Behavior { get; set; } + public bool UseCustomAddress { get; set; } = true; + public bool UseCollisionPointerOfModel { get; set; } = true; + + [JsonProperty(nameof(BehaviorAddress))] + private int _behaviorAddress; + + [JsonIgnore] + public int BehaviorAddress { - public BehaviorConfig Behavior { get; set; } - public bool UseCustomAddress { get; set; } = true; - public bool UseCollisionPointerOfModel { get; set; } = true; - - [JsonProperty(nameof(BehaviorAddress))] - private int _behaviorAddress; - - [JsonIgnore] - public int BehaviorAddress + get { - get - { - if (UseCustomAddress || Behavior == null) - return _behaviorAddress; - else - return Behavior.BankAddress; - } - set - { - if (UseCustomAddress) - _behaviorAddress = value; - else - Behavior.BankAddress = value; - } + if (UseCustomAddress || Behavior == null) + return _behaviorAddress; + else + return Behavior.BankAddress; + } + set + { + if (UseCustomAddress) + _behaviorAddress = value; + else + Behavior.BankAddress = value; } } } diff --git a/SM64Lib/Objects/ObjectBanks/CustomObjectCollection.cs b/SM64Lib/Objects/ObjectBanks/CustomObjectCollection.cs index ee183f2..320fe27 100644 --- a/SM64Lib/Objects/ObjectBanks/CustomObjectCollection.cs +++ b/SM64Lib/Objects/ObjectBanks/CustomObjectCollection.cs @@ -1,157 +1,150 @@ using Newtonsoft.Json; using Newtonsoft.Json.Linq; using SM64Lib.ASM; -using SM64Lib.Behaviors; -using SM64Lib.Configuration; -using SM64Lib.Json; -using SM64Lib.Objects.ModelBanks; using System; using System.Collections.Generic; using System.IO; using System.Linq; -using System.Text; -using System.Threading.Tasks; using Z.Collections.Extensions; -namespace SM64Lib.Objects.ObjectBanks +namespace SM64Lib.Objects.ObjectBanks; + +public class CustomObjectCollection { - public class CustomObjectCollection + public List CustomObjects { get; } = new List(); + + public void TakeoverProperties(RomManager rommgr) { - public List CustomObjects { get; } = new List(); + foreach (var cobj in CustomObjects) + cobj.TakeoverProperties(rommgr); + } - public void TakeoverProperties(RomManager rommgr) - { - foreach (var cobj in CustomObjects) - cobj.TakeoverProperties(rommgr); - } + public void Export(string filePath, CustomObjectExportOptions options) + { + Export(filePath, CustomObjects.ToArray(), options); + } - public void Export(string filePath, CustomObjectExportOptions options) - { - Export(filePath, CustomObjects.ToArray(), options); - } + public static void Export(string filePath, CustomObject customObject, CustomObjectExportOptions options) + { + Export(filePath, new CustomObject[] { customObject }, options); + } - public static void Export(string filePath, CustomObject customObject, CustomObjectExportOptions options) + public static void Export(string filePath, CustomObject[] customObjects, CustomObjectExportOptions options) + { + var export = new CustomObjectExport() { - Export(filePath, new CustomObject[] { customObject }, options); - } + ExportDate = DateTime.UtcNow, + Name = options.ExportName + }; + export.Data.CustomObjects.AddRange(customObjects); + export.Data.EmbeddedFiles = options.EmbeddedFiles; + export.Data.Script = options.Script; - public static void Export(string filePath, CustomObject[] customObjects, CustomObjectExportOptions options) + foreach (var cobj in customObjects) { - var export = new CustomObjectExport() + if (cobj.BehaviorProps.Behavior is not null && !cobj.BehaviorProps.Behavior.IsVanilla) { - ExportDate = DateTime.UtcNow, - Name = options.ExportName - }; - export.Data.CustomObjects.AddRange(customObjects); - export.Data.EmbeddedFiles = options.EmbeddedFiles; - export.Data.Script = options.Script; - - foreach (var cobj in customObjects) - { - if (cobj.BehaviorProps.Behavior is not null && !cobj.BehaviorProps.Behavior.IsVanilla) + var behav = cobj.BehaviorProps.Behavior.FindBehavior(); + if (behav is not null) { - var behav = cobj.BehaviorProps.Behavior.FindBehavior(); - if (behav is not null) + export.Data.Behaviors.AddIfNotContainsKey(cobj.BehaviorProps.Behavior, behav); + foreach (var link in cobj.BehaviorProps.Behavior.CustomAsmLinks) { - export.Data.Behaviors.AddIfNotContainsKey(cobj.BehaviorProps.Behavior, behav); - foreach (var link in cobj.BehaviorProps.Behavior.CustomAsmLinks) - { - var asm = link.CustomAsmAreaConfig.FindCustomAsmArea(); - if (asm is not null) - export.Data.CustomAsmAreas.AddIfNotContainsKey(link.CustomAsmAreaConfig, asm); - } + var asm = link.CustomAsmAreaConfig.FindCustomAsmArea(); + if (asm is not null) + export.Data.CustomAsmAreas.AddIfNotContainsKey(link.CustomAsmAreaConfig, asm); } } - - if (cobj.ModelProps is not null) - { - var mdl = cobj.ModelProps.Model?.FindModel(); - if (mdl is not null) - export.Data.CustomModels.AddIfNotContainsKey(cobj.ModelProps.Model, mdl); - } } - export.Compress(); - export.ID.Generate(); - - File.WriteAllText(filePath, JObject.FromObject(export).ToString()); - } - - public static CustomObjectImport LoadImport(string filePath) - { - var ser = JsonSerializer.CreateDefault(); - ser.PreserveReferencesHandling = PreserveReferencesHandling.All; - return JObject.Parse(File.ReadAllText(filePath)).ToObject(ser); - } - - public static void DecompressImports(CustomObjectImport[] imports) - { - foreach (var import in imports) - DecompressImport(import); - } - - public static void DecompressImport(CustomObjectImport import) - { - import.Decompress(); - } - - public void Import(CustomObjectImport import) - { - // Decompress import - DecompressImport(import); - - foreach (var cobj in import.Data.CustomObjects) + if (cobj.ModelProps is not null) { - if (!import.IgnoreCustomObjects.Contains(cobj)) + var mdl = cobj.ModelProps.Model?.FindModel(); + if (mdl is not null) + export.Data.CustomModels.AddIfNotContainsKey(cobj.ModelProps.Model, mdl); + } + } + + export.Compress(); + export.ID.Generate(); + + File.WriteAllText(filePath, JObject.FromObject(export).ToString()); + } + + public static CustomObjectImport LoadImport(string filePath) + { + var ser = JsonSerializer.CreateDefault(); + ser.PreserveReferencesHandling = PreserveReferencesHandling.All; + return JObject.Parse(File.ReadAllText(filePath)).ToObject(ser); + } + + public static void DecompressImports(CustomObjectImport[] imports) + { + foreach (var import in imports) + DecompressImport(import); + } + + public static void DecompressImport(CustomObjectImport import) + { + import.Decompress(); + } + + public void Import(CustomObjectImport import) + { + // Decompress import + DecompressImport(import); + + foreach (var cobj in import.Data.CustomObjects) + { + if (!import.IgnoreCustomObjects.Contains(cobj)) + { + // Add Custom Behavior + if (cobj.BehaviorProps.Behavior is not null) { - // Add Custom Behavior - if (cobj.BehaviorProps.Behavior is not null) + if (cobj.BehaviorProps.Behavior.IsVanilla) { - if (cobj.BehaviorProps.Behavior.IsVanilla) - { - var behav = import.DestBehaviorBank.GetBehaviorByBankAddress(cobj.BehaviorProps.BehaviorAddress); - cobj.BehaviorProps.Behavior = behav.Config; - } - else if (import.Data.Behaviors.ContainsKey(cobj.BehaviorProps.Behavior)) - { - var behav = import.Data.Behaviors[cobj.BehaviorProps.Behavior]; - import.DestBehaviorBank.Behaviors.Add(behav); + var behav = import.DestBehaviorBank.GetBehaviorByBankAddress(cobj.BehaviorProps.BehaviorAddress); + cobj.BehaviorProps.Behavior = behav.Config; + } + else if (import.Data.Behaviors.ContainsKey(cobj.BehaviorProps.Behavior)) + { + var behav = import.Data.Behaviors[cobj.BehaviorProps.Behavior]; + import.DestBehaviorBank.Behaviors.Add(behav); - if (behav.Config.CustomAsmLinks.Any()) + if (behav.Config.CustomAsmLinks.Any()) + { + foreach (var link in behav.Config.CustomAsmLinks) { - foreach (var link in behav.Config.CustomAsmLinks) - { - CustomAsmArea asmArea = null; + CustomAsmArea asmArea = null; - if (import.Data.CustomAsmAreas.ContainsKey(link.CustomAsmAreaConfig)) - asmArea = import.Data.CustomAsmAreas[link.CustomAsmAreaConfig]; - else if (link.CustomAsm != null) // Temporary fix for old files - Remove property in v1.? - asmArea = link.CustomAsm; - - if (asmArea != null) - { - import.DestCustomAsmBank.Areas.Add(asmArea); - import.DestCustomAsmBank.UpdateAreaConfigCollection(); - } + if (import.Data.CustomAsmAreas.ContainsKey(link.CustomAsmAreaConfig)) + asmArea = import.Data.CustomAsmAreas[link.CustomAsmAreaConfig]; + else if (link.CustomAsm != null) // Temporary fix for old files - Remove property in v1.? + asmArea = link.CustomAsm; + + if (asmArea != null) + { + import.DestCustomAsmBank.Areas.Add(asmArea); + import.DestCustomAsmBank.UpdateAreaConfigCollection(); } } - - behav.ParseScript(); - cobj.BehaviorProps.BehaviorAddress = -1; } - } - // Add Custom Model - if (cobj.ModelProps.Model is not null && import.Data.CustomModels.ContainsKey(cobj.ModelProps.Model) && import.DestModelBanks.ContainsKey(cobj.ModelProps.Model)) - { - var destModelBank = import.DestModelBanks[cobj.ModelProps.Model]; - destModelBank.Models.Add(import.Data.CustomModels[cobj.ModelProps.Model]); - destModelBank.NeedToSave = true; + behav.ParseScript(); + cobj.BehaviorProps.BehaviorAddress = -1; } - - // Add Custom Object - CustomObjects.Add(cobj); } + + // Add Custom Model + if (cobj.ModelProps.Model is not null && import.Data.CustomModels.ContainsKey(cobj.ModelProps.Model) && import.DestModelBanks.ContainsKey(cobj.ModelProps.Model)) + { + var destModelBank = import.DestModelBanks[cobj.ModelProps.Model]; + destModelBank.Models.Add(import.Data.CustomModels[cobj.ModelProps.Model]); + destModelBank.NeedToSave = true; + } + + // Add Custom Object + CustomObjects.Add(cobj); } } } diff --git a/SM64Lib/Objects/ObjectBanks/CustomObjectExport.cs b/SM64Lib/Objects/ObjectBanks/CustomObjectExport.cs index 07bd4e3..ac46212 100644 --- a/SM64Lib/Objects/ObjectBanks/CustomObjectExport.cs +++ b/SM64Lib/Objects/ObjectBanks/CustomObjectExport.cs @@ -1,5 +1,7 @@ using Newtonsoft.Json; using Newtonsoft.Json.Linq; +using Pilz.Cryptography; +using Pilz.Json.Converters; using SM64Lib.Behaviors; using SM64Lib.Configuration; using SM64Lib.Json; @@ -8,73 +10,67 @@ using System; using System.Collections.Generic; using System.IO; using System.IO.Compression; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Pilz.Cryptography; -using Pilz.Json.Converters; -namespace SM64Lib.Objects.ObjectBanks +namespace SM64Lib.Objects.ObjectBanks; + +public class CustomObjectExport { - public class CustomObjectExport + public string Name { get; set; } = string.Empty; + public DateTime ExportDate { get; set; } + [JsonConverter(typeof(Newtonsoft.Json.Converters.VersionConverter))] + public Version Version { get; set; } = new Version("1.0.0.0"); + [JsonConverter(typeof(UniquieIDStringJsonConverter))] + public UniquieID ID { get; set; } = new(); + + [JsonIgnore] + public CustomObjectExportData Data { get; private set; } = new CustomObjectExportData(); + [JsonProperty("CompressedData")] + private byte[] compressedData = null; + + [JsonProperty("CustomModels")] + [JsonConverter(typeof(ComplexDictionarJsonConverter))] + private Dictionary ObsulateCustomModels { set => Data.CustomModels = value; } + [JsonProperty("Behaviors")] + [JsonConverter(typeof(ComplexDictionarJsonConverter))] + private Dictionary ObsulateBehaviors { set => Data.Behaviors = value; } + [JsonProperty("CustomObjects")] + private List ObsulateCustomObjects { set => Data.CustomObjects = value; } + + [JsonIgnore] + public bool IsCompressed { - public string Name { get; set; } = string.Empty; - public DateTime ExportDate { get; set; } - [JsonConverter(typeof(Newtonsoft.Json.Converters.VersionConverter))] - public Version Version { get; set; } = new Version("1.0.0.0"); - [JsonConverter(typeof(UniquieIDStringJsonConverter))] - public UniquieID ID { get; set; } = new(); + get => compressedData is object; + } - [JsonIgnore] - public CustomObjectExportData Data { get; private set; } = new CustomObjectExportData(); - [JsonProperty("CompressedData")] - private byte[] compressedData = null; - - [JsonProperty("CustomModels")] - [JsonConverter(typeof(ComplexDictionarJsonConverter))] - private Dictionary ObsulateCustomModels { set => Data.CustomModels = value; } - [JsonProperty("Behaviors")] - [JsonConverter(typeof(ComplexDictionarJsonConverter))] - private Dictionary ObsulateBehaviors { set => Data.Behaviors = value; } - [JsonProperty("CustomObjects")] - private List ObsulateCustomObjects { set => Data.CustomObjects = value; } - - [JsonIgnore] - public bool IsCompressed + public void Compress() + { + using (var outputRaw = new MemoryStream()) { - get => compressedData is object; - } - - public void Compress() - { - using (var outputRaw = new MemoryStream()) + using (var sw = new StreamWriter(outputRaw)) { - using (var sw = new StreamWriter(outputRaw)) + var ser = JsonSerializer.CreateDefault(); + ser.PreserveReferencesHandling = PreserveReferencesHandling.All; + sw.Write(JObject.FromObject(Data, ser).ToString()); + sw.Flush(); + compressedData = General.CompressData(outputRaw, CompressionLevel.Optimal); + } + } + } + + public void Decompress() + { + if (IsCompressed) + { + using (var raw = new MemoryStream()) + { + General.DecompressData(compressedData, raw); + raw.Position = 0; + using (var sr = new StreamReader(raw)) { var ser = JsonSerializer.CreateDefault(); ser.PreserveReferencesHandling = PreserveReferencesHandling.All; - sw.Write(JObject.FromObject(Data, ser).ToString()); - sw.Flush(); - compressedData = General.CompressData(outputRaw, CompressionLevel.Optimal); - } - } - } - - public void Decompress() - { - if (IsCompressed) - { - using (var raw = new MemoryStream()) - { - General.DecompressData(compressedData, raw); - raw.Position = 0; - using (var sr = new StreamReader(raw)) - { - var ser = JsonSerializer.CreateDefault(); - ser.PreserveReferencesHandling = PreserveReferencesHandling.All; - Data = JObject.Parse(sr.ReadToEnd()).ToObject(ser); - compressedData = null; - } + Data = JObject.Parse(sr.ReadToEnd()).ToObject(ser); + compressedData = null; } } } diff --git a/SM64Lib/Objects/ObjectBanks/CustomObjectExportData.cs b/SM64Lib/Objects/ObjectBanks/CustomObjectExportData.cs index 6158da9..10f6e83 100644 --- a/SM64Lib/Objects/ObjectBanks/CustomObjectExportData.cs +++ b/SM64Lib/Objects/ObjectBanks/CustomObjectExportData.cs @@ -6,24 +6,19 @@ using SM64Lib.Configuration; using SM64Lib.Json; using SM64Lib.Objects.ModelBanks; using SM64Lib.Patching; -using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace SM64Lib.Objects.ObjectBanks +namespace SM64Lib.Objects.ObjectBanks; + +public class CustomObjectExportData { - public class CustomObjectExportData - { - public List CustomObjects { get; set; } = new List(); - [JsonConverter(typeof(ComplexDictionarJsonConverter))] - public Dictionary CustomModels { get; set; } = new Dictionary(); - [JsonConverter(typeof(ComplexDictionarJsonConverter))] - public Dictionary Behaviors { get; set; } = new Dictionary(); - [JsonConverter(typeof(ComplexDictionarJsonConverter))] - public Dictionary CustomAsmAreas { get; set; } = new Dictionary(); - public EmbeddedFilesContainer EmbeddedFiles { get; set; } - public PatchScript Script { get; set; } - } + public List CustomObjects { get; set; } = new List(); + [JsonConverter(typeof(ComplexDictionarJsonConverter))] + public Dictionary CustomModels { get; set; } = new Dictionary(); + [JsonConverter(typeof(ComplexDictionarJsonConverter))] + public Dictionary Behaviors { get; set; } = new Dictionary(); + [JsonConverter(typeof(ComplexDictionarJsonConverter))] + public Dictionary CustomAsmAreas { get; set; } = new Dictionary(); + public EmbeddedFilesContainer EmbeddedFiles { get; set; } + public PatchScript Script { get; set; } } diff --git a/SM64Lib/Objects/ObjectBanks/CustomObjectExportOptions.cs b/SM64Lib/Objects/ObjectBanks/CustomObjectExportOptions.cs index b9bb90f..7f24dc0 100644 --- a/SM64Lib/Objects/ObjectBanks/CustomObjectExportOptions.cs +++ b/SM64Lib/Objects/ObjectBanks/CustomObjectExportOptions.cs @@ -1,16 +1,10 @@ using Pilz.IO; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace SM64Lib.Objects.ObjectBanks +namespace SM64Lib.Objects.ObjectBanks; + +public class CustomObjectExportOptions { - public class CustomObjectExportOptions - { - public string ExportName { get; set; } - public EmbeddedFilesContainer EmbeddedFiles { get; set; } - public Patching.PatchScript Script { get; set; } - } + public string ExportName { get; set; } + public EmbeddedFilesContainer EmbeddedFiles { get; set; } + public Patching.PatchScript Script { get; set; } } diff --git a/SM64Lib/Objects/ObjectBanks/CustomObjectImport.cs b/SM64Lib/Objects/ObjectBanks/CustomObjectImport.cs index ac0af1f..3b557e8 100644 --- a/SM64Lib/Objects/ObjectBanks/CustomObjectImport.cs +++ b/SM64Lib/Objects/ObjectBanks/CustomObjectImport.cs @@ -3,25 +3,20 @@ using SM64Lib.ASM; using SM64Lib.Behaviors; using SM64Lib.Configuration; using SM64Lib.Objects.ModelBanks; -using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace SM64Lib.Objects.ObjectBanks +namespace SM64Lib.Objects.ObjectBanks; + +public class CustomObjectImport : CustomObjectExport { - public class CustomObjectImport : CustomObjectExport - { - [JsonIgnore] - public Dictionary DestModelBanks { get; } = new Dictionary(); - [JsonIgnore] - public CustomAsmBank DestCustomAsmBank { get; set; } = null; - [JsonIgnore] - public BehaviorBank DestBehaviorBank { get; set; } = null; - [JsonIgnore] - public List IgnoreCustomObjects { get; } = new List(); - [JsonIgnore] - public bool OverwriteExistingObjecs { get; set; } = true; - } + [JsonIgnore] + public Dictionary DestModelBanks { get; } = new Dictionary(); + [JsonIgnore] + public CustomAsmBank DestCustomAsmBank { get; set; } = null; + [JsonIgnore] + public BehaviorBank DestBehaviorBank { get; set; } = null; + [JsonIgnore] + public List IgnoreCustomObjects { get; } = new List(); + [JsonIgnore] + public bool OverwriteExistingObjecs { get; set; } = true; } diff --git a/SM64Lib/Objects/ObjectBanks/CustomObjectModelProps.cs b/SM64Lib/Objects/ObjectBanks/CustomObjectModelProps.cs index 466ce47..7731da5 100644 --- a/SM64Lib/Objects/ObjectBanks/CustomObjectModelProps.cs +++ b/SM64Lib/Objects/ObjectBanks/CustomObjectModelProps.cs @@ -1,50 +1,43 @@ using Newtonsoft.Json; using SM64Lib.Configuration; -using SM64Lib.Objects.ModelBanks; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace SM64Lib.Objects.ObjectBanks +namespace SM64Lib.Objects.ObjectBanks; + +public class CustomObjectModelProps { - public class CustomObjectModelProps + public CustomModelConfig Model { get; set; } + public bool UseCustomModelID { get; set; } = true; + + [JsonProperty(nameof(ModelID))] + private byte _modelID; + + [JsonIgnore] + public byte ModelID { - public CustomModelConfig Model { get; set; } - public bool UseCustomModelID { get; set; } = true; - - [JsonProperty(nameof(ModelID))] - private byte _modelID; - - [JsonIgnore] - public byte ModelID + get { - get + if (UseCustomModelID || Model == null) + return _modelID; + else { - if (UseCustomModelID || Model == null) - return _modelID; - else - { - var mdl = Model.FindModel(); - return mdl is object ? mdl.ModelID : _modelID; - } - } - set - { - if (UseCustomModelID) - _modelID = value; - else - { - var mdl = Model.FindModel(); - if (mdl is not null) - mdl.ModelID = value; - else - _modelID = value; - } + var mdl = Model.FindModel(); + return mdl is object ? mdl.ModelID : _modelID; + } + } + set + { + if (UseCustomModelID) + _modelID = value; + else + { + var mdl = Model.FindModel(); + if (mdl is not null) + mdl.ModelID = value; + else + _modelID = value; } } - - } + + } diff --git a/SM64Lib/Objects/ObjectBanks/CustomObjectReferences.cs b/SM64Lib/Objects/ObjectBanks/CustomObjectReferences.cs index 69f5d23..5e2464b 100644 --- a/SM64Lib/Objects/ObjectBanks/CustomObjectReferences.cs +++ b/SM64Lib/Objects/ObjectBanks/CustomObjectReferences.cs @@ -1,129 +1,124 @@ using SM64Lib.ASM; using SM64Lib.Behaviors; using SM64Lib.Configuration; -using SM64Lib.Objects.ModelBanks; -using System; using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; using Z.Collections.Extensions; -namespace SM64Lib.Objects.ObjectBanks +namespace SM64Lib.Objects.ObjectBanks; + +public class CustomObjectReferences { - public class CustomObjectReferences + public IReadOnlyCollection ReferenceObjects { get; } + public IReadOnlyCollection ReferenceBehaviors { get; } + public IReadOnlyCollection ReferenceAsmAreas { get; } + public IReadOnlyCollection ReferenceModels { get; } + + public bool HasReferences { - public IReadOnlyCollection ReferenceObjects { get; } - public IReadOnlyCollection ReferenceBehaviors { get; } - public IReadOnlyCollection ReferenceAsmAreas { get; } - public IReadOnlyCollection ReferenceModels { get; } + get => ReferenceObjects.Any() || ReferenceBehaviors.Any() || ReferenceAsmAreas.Any() || ReferenceModels.Any(); + } - public bool HasReferences + private CustomObjectReferences(CustomObject[] refObject, BehaviorConfig[] refBehaviors, CustomAsmAreaConfig[] refAsmAreas, CustomModelConfig[] refModels) + { + ReferenceObjects = refObject; + ReferenceBehaviors = refBehaviors; + ReferenceAsmAreas = refAsmAreas; + ReferenceModels = refModels; + } + + public void DeleteReferences(RomManager rommgr) + { + var refObjs = ReferenceObjects.ToArray(); + var refBehavs = ReferenceBehaviors.Select(n => n.FindBehavior()).TakeWhile(n => n is not null).ToArray(); + var refAsmAreas = ReferenceAsmAreas.ToArray(); + var refMdls = ReferenceModels.Select(n => n.FindModel()).TakeWhile(n => n is not null).ToArray(); + + rommgr.CustomObjects.CustomObjects.RemoveRangeIfContains(refObjs); + rommgr.GlobalBehaviorBank.Behaviors.RemoveRangeIfContains(refBehavs); + rommgr.GlobalModelBank.Models.RemoveRangeIfContains(refMdls); + rommgr.GlobalCustomAsmBank.Areas.RemoveRangeIfContains(refAsmAreas.Select(n => n.FindCustomAsmArea()).Where(n => n is not null).ToArray()); + rommgr.GlobalCustomAsmBank.UpdateAreaConfigCollection(); + rommgr.GlobalCustomAsmBank.UpdateAddresses(); + + foreach (var lvl in rommgr.Levels) { - get => ReferenceObjects.Any() || ReferenceBehaviors.Any() || ReferenceAsmAreas.Any() || ReferenceModels.Any(); + if (lvl.LocalObjectBank is not null) + lvl.LocalObjectBank.Models.RemoveRangeIfContains(ReferenceModels.Select(n => n.FindModel()).ToArray()); } + } - private CustomObjectReferences(CustomObject[] refObject, BehaviorConfig[] refBehaviors, CustomAsmAreaConfig[] refAsmAreas, CustomModelConfig[] refModels) + public static CustomObjectReferences Find(CustomObject[] customObjects, RomManager rommgr) + { + var refObjects = new List(); + var refBehaviors = new List(); + var refAsmAreas = new List(); + var refModels = new List(); + + foreach (var customObject in customObjects) { - ReferenceObjects = refObject; - ReferenceBehaviors = refBehaviors; - ReferenceAsmAreas = refAsmAreas; - ReferenceModels = refModels; - } - - public void DeleteReferences(RomManager rommgr) - { - var refObjs = ReferenceObjects.ToArray(); - var refBehavs = ReferenceBehaviors.Select(n => n.FindBehavior()).TakeWhile(n => n is not null).ToArray(); - var refAsmAreas = ReferenceAsmAreas.ToArray(); - var refMdls = ReferenceModels.Select(n => n.FindModel()).TakeWhile(n => n is not null).ToArray(); - - rommgr.CustomObjects.CustomObjects.RemoveRangeIfContains(refObjs); - rommgr.GlobalBehaviorBank.Behaviors.RemoveRangeIfContains(refBehavs); - rommgr.GlobalModelBank.Models.RemoveRangeIfContains(refMdls); - rommgr.GlobalCustomAsmBank.Areas.RemoveRangeIfContains(refAsmAreas.Select(n => n.FindCustomAsmArea()).Where(n => n is not null).ToArray()); - rommgr.GlobalCustomAsmBank.UpdateAreaConfigCollection(); - rommgr.GlobalCustomAsmBank.UpdateAddresses(); - - foreach (var lvl in rommgr.Levels) + if (!customObject.BehaviorProps.UseCustomAddress && customObject.BehaviorProps.Behavior is not null) { - if (lvl.LocalObjectBank is not null) - lvl.LocalObjectBank.Models.RemoveRangeIfContains(ReferenceModels.Select(n => n.FindModel()).ToArray()); - } - } - - public static CustomObjectReferences Find(CustomObject[] customObjects, RomManager rommgr) - { - var refObjects = new List(); - var refBehaviors = new List(); - var refAsmAreas = new List(); - var refModels = new List(); - - foreach (var customObject in customObjects) - { - if (!customObject.BehaviorProps.UseCustomAddress && customObject.BehaviorProps.Behavior is not null) + var behavConfig = customObject.BehaviorProps.Behavior; + if (!refBehaviors.Contains(behavConfig)) { - var behavConfig = customObject.BehaviorProps.Behavior; - if (!refBehaviors.Contains(behavConfig)) - { - refBehaviors.Add(behavConfig); - FindReferenceCustomModels(rommgr.CustomObjects, behavConfig, refObjects); + refBehaviors.Add(behavConfig); + FindReferenceCustomModels(rommgr.CustomObjects, behavConfig, refObjects); - foreach (var asmArea in behavConfig.CustomAsmLinks) + foreach (var asmArea in behavConfig.CustomAsmLinks) + { + if (!refAsmAreas.Contains(asmArea.CustomAsmAreaConfig)) { - if (!refAsmAreas.Contains(asmArea.CustomAsmAreaConfig)) - { - refAsmAreas.Add(asmArea.CustomAsmAreaConfig); - FindReferenceBehaviors(rommgr.GlobalBehaviorBank, asmArea.CustomAsmAreaConfig, refBehaviors); - } + refAsmAreas.Add(asmArea.CustomAsmAreaConfig); + FindReferenceBehaviors(rommgr.GlobalBehaviorBank, asmArea.CustomAsmAreaConfig, refBehaviors); } } } - - if (!customObject.ModelProps.UseCustomModelID && customObject.ModelProps.Model is not null) - { - var modelConfig = customObject.ModelProps.Model; - if (!refModels.Contains(modelConfig)) - { - refModels.Add(modelConfig); - FindReferenceCustomModels(rommgr.CustomObjects, modelConfig, refObjects); - } - } - } - return new CustomObjectReferences(refObjects.ToArray(), refBehaviors.ToArray(), refAsmAreas.ToArray(), refModels.ToArray()); - } - - private static void FindReferenceCustomModels(CustomObjectCollection collection, BehaviorConfig behavior, List refObjects) - { - foreach (var customObject in collection.CustomObjects) + if (!customObject.ModelProps.UseCustomModelID && customObject.ModelProps.Model is not null) { - if (!customObject.BehaviorProps.UseCustomAddress && customObject.BehaviorProps.Behavior == behavior) - refObjects.AddIfNotContains(customObject); - } - } - - private static void FindReferenceBehaviors(BehaviorBank bank, CustomAsmAreaConfig asmArea, List refBehaviors) - { - foreach (var behav in bank.Behaviors) - { - foreach (var link in behav.Config.CustomAsmLinks) + var modelConfig = customObject.ModelProps.Model; + if (!refModels.Contains(modelConfig)) { - if (link.CustomAsmAreaConfig == asmArea) - refBehaviors.AddIfNotContains(behav.Config); + refModels.Add(modelConfig); + FindReferenceCustomModels(rommgr.CustomObjects, modelConfig, refObjects); } } + } - private static void FindReferenceCustomModels(CustomObjectCollection collection, CustomModelConfig model, List refObjects) - { - foreach (var customObject in collection.CustomObjects) - { - if (!customObject.ModelProps.UseCustomModelID && customObject.ModelProps.Model == model) - refObjects.AddIfNotContains(customObject); - } - } - + return new CustomObjectReferences(refObjects.ToArray(), refBehaviors.ToArray(), refAsmAreas.ToArray(), refModels.ToArray()); } + + private static void FindReferenceCustomModels(CustomObjectCollection collection, BehaviorConfig behavior, List refObjects) + { + foreach (var customObject in collection.CustomObjects) + { + if (!customObject.BehaviorProps.UseCustomAddress && customObject.BehaviorProps.Behavior == behavior) + refObjects.AddIfNotContains(customObject); + } + } + + private static void FindReferenceBehaviors(BehaviorBank bank, CustomAsmAreaConfig asmArea, List refBehaviors) + { + foreach (var behav in bank.Behaviors) + { + foreach (var link in behav.Config.CustomAsmLinks) + { + if (link.CustomAsmAreaConfig == asmArea) + refBehaviors.AddIfNotContains(behav.Config); + } + } + } + + private static void FindReferenceCustomModels(CustomObjectCollection collection, CustomModelConfig model, List refObjects) + { + foreach (var customObject in collection.CustomObjects) + { + if (!customObject.ModelProps.UseCustomModelID && customObject.ModelProps.Model == model) + refObjects.AddIfNotContains(customObject); + } + } + } diff --git a/SM64Lib/Objects/ObjectBanks/Data/ObjectBankData.cs b/SM64Lib/Objects/ObjectBanks/Data/ObjectBankData.cs index 0845147..dbe08a2 100644 --- a/SM64Lib/Objects/ObjectBanks/Data/ObjectBankData.cs +++ b/SM64Lib/Objects/ObjectBanks/Data/ObjectBankData.cs @@ -1,20 +1,19 @@ using System.Collections.Generic; -namespace SM64Lib.Objects.ObjectBanks.Data +namespace SM64Lib.Objects.ObjectBanks.Data; + +public class ObjectBankData { - public class ObjectBankData + public string Name { get; set; } + public List Objects { get; private set; } = new List(); + public List Commands { get; private set; } = new List(); + + public ObjectBankData() { - public string Name { get; set; } - public List Objects { get; private set; } = new List(); - public List Commands { get; private set; } = new List(); + } - public ObjectBankData() - { - } - - public ObjectBankData(string name) - { - Name = name; - } + public ObjectBankData(string name) + { + Name = name; } } \ No newline at end of file diff --git a/SM64Lib/Objects/ObjectBanks/Data/ObjectBankDataCommand.cs b/SM64Lib/Objects/ObjectBanks/Data/ObjectBankDataCommand.cs index 231025d..efab471 100644 --- a/SM64Lib/Objects/ObjectBanks/Data/ObjectBankDataCommand.cs +++ b/SM64Lib/Objects/ObjectBanks/Data/ObjectBankDataCommand.cs @@ -1,35 +1,34 @@ using global::Newtonsoft.Json; -namespace SM64Lib.Objects.ObjectBanks.Data -{ - public class ObjectBankDataCommand - { - public byte[] Command { get; set; } +namespace SM64Lib.Objects.ObjectBanks.Data; - [JsonIgnore] - public byte CommandType +public class ObjectBankDataCommand +{ + public byte[] Command { get; set; } + + [JsonIgnore] + public byte CommandType + { + get { - get + if (Command is not null && Command.Length >= 1) { - if (Command is not null && Command.Length >= 1) - { - return Command[0]; - } - else - { - return 0; - } + return Command[0]; + } + else + { + return 0; } } + } - public ObjectBankDataCommand() - { - Command = null; - } + public ObjectBankDataCommand() + { + Command = null; + } - public ObjectBankDataCommand(byte[] cmd) - { - Command = cmd; - } + public ObjectBankDataCommand(byte[] cmd) + { + Command = cmd; } } \ No newline at end of file diff --git a/SM64Lib/Objects/ObjectBanks/Data/ObjectBankDataList.cs b/SM64Lib/Objects/ObjectBanks/Data/ObjectBankDataList.cs index 88f0b5c..4941c6b 100644 --- a/SM64Lib/Objects/ObjectBanks/Data/ObjectBankDataList.cs +++ b/SM64Lib/Objects/ObjectBanks/Data/ObjectBankDataList.cs @@ -1,8 +1,7 @@ using System.Collections.Generic; -namespace SM64Lib.Objects.ObjectBanks.Data +namespace SM64Lib.Objects.ObjectBanks.Data; + +public class ObjectBankDataList : List { - public class ObjectBankDataList : List - { - } } \ No newline at end of file diff --git a/SM64Lib/Objects/ObjectBanks/Data/ObjectBankDataListCollection.cs b/SM64Lib/Objects/ObjectBanks/Data/ObjectBankDataListCollection.cs index e508ada..e90e50e 100644 --- a/SM64Lib/Objects/ObjectBanks/Data/ObjectBankDataListCollection.cs +++ b/SM64Lib/Objects/ObjectBanks/Data/ObjectBankDataListCollection.cs @@ -1,42 +1,41 @@ -using System.Collections.Generic; +using global::Newtonsoft.Json.Linq; using global::System.IO; +using System.Collections.Generic; using System.Linq; -using global::Newtonsoft.Json.Linq; -namespace SM64Lib.Objects.ObjectBanks.Data +namespace SM64Lib.Objects.ObjectBanks.Data; + +public class ObjectBankDataListCollection : Dictionary { - public class ObjectBankDataListCollection : Dictionary + public ObjectBankDataList this[int index] { - public ObjectBankDataList this[int index] + get { - get - { - return this.ElementAt(index).Value; - } - } - public new ObjectBankDataList this[byte bankID] - { - get - { - return base[bankID]; - } - } - - public void Load(string filePath) - { - if (File.Exists(filePath)) - { - string strContent = File.ReadAllText(filePath); - var tempDic = JToken.Parse(strContent).ToObject>(); - Clear(); - foreach (var kvp in tempDic) - Add(kvp.Key, kvp.Value); - } - } - - public void Save(string filePath) - { - File.WriteAllText(filePath, JObject.FromObject(this).ToString()); + return this.ElementAt(index).Value; } } + public new ObjectBankDataList this[byte bankID] + { + get + { + return base[bankID]; + } + } + + public void Load(string filePath) + { + if (File.Exists(filePath)) + { + string strContent = File.ReadAllText(filePath); + var tempDic = JToken.Parse(strContent).ToObject>(); + Clear(); + foreach (var kvp in tempDic) + Add(kvp.Key, kvp.Value); + } + } + + public void Save(string filePath) + { + File.WriteAllText(filePath, JObject.FromObject(this).ToString()); + } } \ No newline at end of file diff --git a/SM64Lib/Objects/StarManager.cs b/SM64Lib/Objects/StarManager.cs index 9e8272d..042254e 100644 --- a/SM64Lib/Objects/StarManager.cs +++ b/SM64Lib/Objects/StarManager.cs @@ -1,319 +1,317 @@ -using global::System.IO; -using System.Linq; +using global::SM64Lib.Data; +using global::System.IO; using global::System.Numerics; -using Microsoft.VisualBasic.CompilerServices; -using global::SM64Lib.Data; using System; +using System.Linq; -namespace SM64Lib.Objects +namespace SM64Lib.Objects; + +public class StarPosition { - public class StarPosition + public Vector3 Position { get; set; } + public StarNames Name { get; set; } + + public StarPosition() { - public Vector3 Position { get; set; } - public StarNames Name { get; set; } + Position = Vector3.Zero; + } - public StarPosition() + public StarPosition(StarNames name) : this() + { + Name = name; + } + + public StarPosition(StarNames name, Vector3 position) + { + Position = position; + Name = name; + } + + public void SavePosition(RomManager rommgr) + { + var rom = rommgr.GetBinaryRom(FileAccess.ReadWrite); + if (!new[] { StarNames.KoopaTheQuick1, StarNames.KoopaTheQuick2 }.Contains(Name)) { - Position = Vector3.Zero; + WriteStarWrapperFunction(rom); } - public StarPosition(StarNames name) : this() + var switchExpr = Name; + switch (switchExpr) { - Name = name; + case StarNames.KoopaTheQuick1: + { + WritePositionAsShort(rom, Position, StarPositionAddress.KoopaTheQuick1); + break; + } + + case StarNames.KoopaTheQuick2: + { + WritePositionAsShort(rom, Position, StarPositionAddress.KoopaTheQuick2); + break; + } + + case StarNames.KingBobOmbBoss: + { + WritePositionAsSingle(rom, Position, StarPositionAddress.KingBobOmbBoss); + rom.Position = 0x62AD4; + rom.Write(0x3C048040); // LUI A0, &H8040 + rom.Write(0xC1009C0); // JAL &H80402700 + rom.Write(0x34844F00); // ORI A0, A0, &H4F40 + rom.Write(0x0); + rom.Write(0x0); + rom.Write(0x0); + rom.Write(0x0); + rom.Write(0x0); + break; + } + + case StarNames.WhompBoss: + { + WritePositionAsSingle(rom, Position, StarPositionAddress.WhompBoss); + rom.Position = 0x82900; + rom.Write(0x3C018040); + rom.Write(0xC42C4F10); + rom.Write(0xC42E4F14); + rom.Write(0x8C264F18); + rom.Position = 0x82914; + rom.Write(0x0); + break; + } + + case StarNames.EyerockBoss: + { + WritePositionAsSingle(rom, Position, StarPositionAddress.EyerockBoss); + rom.Position = 0xC9A1C; // 0x8030EA1c + rom.Write(0x3C048040); // LUI A0, &H8040 + rom.Write(0xC1009C0); // JAL &H80402700 + rom.Write(0x34844F20); // ORI A0, A0, &H4F20 + rom.Write(0x0); // NOPs + rom.Write(0x0); + rom.Write(0x0); + break; + } + + case StarNames.BigBullyBoss: + { + WritePositionAsSingle(rom, Position, StarPositionAddress.BigBullyBoss); + rom.Position = 0xA6970; // 0x802EB970 + rom.Write(0x3C048040); // LUI A0, 0x8040 + rom.Write(0xC1009C0); // JAL 0x80402700 + rom.Write(0x34844F30); // ORI A0, A0, 0x4F30 + break; + } + + case StarNames.ChillBullyBoss: + { + WritePositionAsSingle(rom, Position, StarPositionAddress.ChillBullyBoss); + rom.Position = 0xA6950; // 0x802EB950 + rom.Write(0x3C048040); // LUI A0, 0x8040 + rom.Write(0xC1009C0); // JAL 0x80402700 + rom.Write(0x34844F40); // ORI A0, A0, 0x4F40 + break; + } + + case StarNames.GiantPiranhaPlants: + { + WritePositionAsSingle(rom, Position, StarPositionAddress.GiantPiranhaPlants); + rom.Position = 0xC802C; // 0x8030D02C + rom.Write(0x3C048040); // LUI A0, 0x8040 + rom.Write(0xC1009C0); // JAL 0x80402700 + rom.Write(0x34844F50); // ORI A0, A0, 0x4F50 + break; + } + + case StarNames.PenguinMother: + { + WritePositionAsSingle(rom, Position, StarPositionAddress.PenguinMother); + rom.Position = 0x7A128; // 0x802BF128 + rom.Write(0x3C048040); // LUI A0, 0x8040 + rom.Write(0xC1009C0); // JAL 0x80402700 + rom.Write(0x34844F60); + break; + } + + case StarNames.BigPenguinRace: + { + WritePositionAsSingle(rom, Position, StarPositionAddress.BigPenguinRace); + rom.Position = 0xCD040; // 0x80312040 + rom.Write(0x3C048040); // LUI A0, 0x8040 + rom.Write(0xC1009C0); // JAL 0x80402700 + rom.Write(0x34844F90); + break; + } + + case StarNames.WigglerBoss: + { + WritePositionAsSingle(rom, Position, StarPositionAddress.WigglerBoss); + rom.Position = 0xBCFE0; // 80301FE0 + rom.Write(0x3C048040); // LUI A0, 0x8040 + rom.Write(0xC1009C0); // JAL 0x80402700 + rom.Write(0x34844F70); + break; + } + + case StarNames.PeachSlideStar: + { + WritePositionAsSingle(rom, Position, StarPositionAddress.PeachSlideStar); + rom.Position = 0xB7D0; // 80301FE0 + rom.Write(0x3C048040); // LUI A0, 0x8040 + rom.Write(0xC1009C0); // JAL 0x80402700 + rom.Write(0x34844F80); + break; + } + + //case StarNames.BigPenguinRace: + // { + // WritePositionAsSingle(rom, Position, 0x1204F90); + // rom.Position = 0x605E4; // 80301FE0 + // rom.Write(0x3C048040); // LUI A0, 0x8040 + // rom.Write(0xC1009C0); // JAL 0x80402700 + // rom.Write(0x34844F90); + // break; + // } + + case StarNames.TreasureChests: + { + WritePositionAsSingle(rom, Position, StarPositionAddress.TreasureChests); + rom.Position = 0xB32B0; + rom.Write(0x3C048040); // LUI A0, 0x8040 + rom.Write(0xC1009C0); // JAL 0x80402700 + rom.Write(0x34844FA0); + break; + } + + case StarNames.BooInHauntedHouse: + { + WritePositionAsSingle(rom, Position, StarPositionAddress.BooInHauntedHouse); + rom.Position = 0x7FBB0; + rom.Write(0x3C048040); // LUI A0, 0x8040 + rom.Write(0xC1009C0); // JAL 0x80402700 + rom.Write(0x34844FAC); + break; + } + + case StarNames.Klepto: + { + WritePositionAsSingle(rom, Position, StarPositionAddress.Klepto); + rom.Position = 0xCC47C; + rom.Write(0x3C048040); // LUI A0, 0x8040 + rom.Write(0xC1009C0); // JAL 0x80402700 + rom.Write(0x34844FC4); + break; + } + + case StarNames.MerryGoRoundboss: + { + WritePositionAsSingle(rom, Position, StarPositionAddress.MerryGoRoundboss); + rom.Position = 0x7FC24; + rom.Write(0x3C048040); // LUI A0, 0x8040 + rom.Write(0xC1009C0); // JAL 0x80402700 + rom.Write(0x34844FB8); + break; + } + + case StarNames.MrIboss: + { + WritePositionAsSingle(rom, Position, StarPositionAddress.MrIboss); + rom.Position = 0x61450; + rom.Write(0x3C048040); // LUI A0, 0x8040 + rom.Write(0xC1009C0); // JAL 0x80402700 + rom.Write(0x34844FD0); + break; + } + + case StarNames.RooftopBoo: + { + WritePositionAsSingle(rom, Position, StarPositionAddress.RooftopBoo); + rom.Position = 0x7FBEC; + rom.Write(0x3C048040); // LUI A0, 0x8040 + rom.Write(0xC1009C0); // JAL 0x80402700 + rom.Write(0x34844FDC); + break; + } + + case StarNames.SecondactBigBully: + { + WritePositionAsSingle(rom, Position, StarPositionAddress.SecondactBigBully); + rom.Position = 0xA6CBC; + rom.Write(0x3C048040); // LUI A0, 0x8040 + rom.Write(0xC1009C0); // JAL 0x80402700 + rom.Write(0x34844FE4); + break; + } } - public StarPosition(StarNames name, Vector3 position) + rom.Close(); + } + + private void WritePositionAsShort(BinaryRom rom, Vector3 position, StarPositionAddress offset) + { + rom.Position = (int)offset; + rom.Write(Convert.ToInt16(position.X)); + rom.Write(Convert.ToInt16(position.Y)); + rom.Write(Convert.ToInt16(position.Z)); + } + + private void WritePositionAsSingle(BinaryRom rom, Vector3 position, StarPositionAddress offset) + { + rom.Position = (int)offset; + rom.Write(position.X); + rom.Write(position.Y); + rom.Write(position.Z); + } + + public static void WriteStarWrapperFunction(BinaryRom rom) + { + var StarWrapperFunction = new[] { 0x27, 0xBD, 0xFF, 0xE8, 0xAF, 0xBF, 0x0, 0x14, 0xC4, 0x8C, 0x0, 0x0, 0xC4, 0x8E, 0x0, 0x4, 0xC, 0xB, 0xCA, 0xE2, 0x8C, 0x86, 0x0, 0x8, 0x8F, 0xBF, 0x0, 0x14, 0x27, 0xBD, 0x0, 0x18, 0x3, 0xE0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x0 }; + rom.Position = 0x1202700; + foreach (var b in StarWrapperFunction) + rom.Write(b); + } + + public Vector3 LoadPosition(StarNames name, RomManager romManager) + { + using var rom = romManager.GetBinaryRom(FileAccess.Read); + return name switch { - Position = position; - Name = name; - } + StarNames.KoopaTheQuick1 => ReadPositionAsShort(rom, StarPositionAddress.KoopaTheQuick1), + StarNames.KoopaTheQuick2 => ReadPositionAsShort(rom, StarPositionAddress.KoopaTheQuick2), + StarNames.KingBobOmbBoss => ReadPositionAsSingle(rom, StarPositionAddress.KingBobOmbBoss), + StarNames.WhompBoss => ReadPositionAsSingle(rom, StarPositionAddress.WhompBoss), + StarNames.EyerockBoss => ReadPositionAsSingle(rom, StarPositionAddress.EyerockBoss), + StarNames.BigBullyBoss => ReadPositionAsSingle(rom, StarPositionAddress.BigBullyBoss), + StarNames.ChillBullyBoss => ReadPositionAsSingle(rom, StarPositionAddress.ChillBullyBoss), + StarNames.GiantPiranhaPlants => ReadPositionAsSingle(rom, StarPositionAddress.GiantPiranhaPlants), + StarNames.PenguinMother => ReadPositionAsSingle(rom, StarPositionAddress.PenguinMother), + StarNames.BigPenguinRace => ReadPositionAsSingle(rom, StarPositionAddress.BigPenguinRace), + StarNames.WigglerBoss => ReadPositionAsSingle(rom, StarPositionAddress.WigglerBoss), + StarNames.PeachSlideStar => ReadPositionAsSingle(rom, StarPositionAddress.PeachSlideStar), + StarNames.TreasureChests => ReadPositionAsSingle(rom, StarPositionAddress.TreasureChests), + StarNames.BooInHauntedHouse => ReadPositionAsSingle(rom, StarPositionAddress.BooInHauntedHouse), + StarNames.Klepto => ReadPositionAsSingle(rom, StarPositionAddress.Klepto), + StarNames.MerryGoRoundboss => ReadPositionAsSingle(rom, StarPositionAddress.MerryGoRoundboss), + StarNames.MrIboss => ReadPositionAsSingle(rom, StarPositionAddress.MrIboss), + StarNames.RooftopBoo => ReadPositionAsSingle(rom, StarPositionAddress.RooftopBoo), + StarNames.SecondactBigBully => ReadPositionAsSingle(rom, StarPositionAddress.SecondactBigBully), + _ => throw new System.ArgumentException(string.Format("{0} is not a valid StarNames value", name)), + }; + } - public void SavePosition(RomManager rommgr) - { - var rom = rommgr.GetBinaryRom(FileAccess.ReadWrite); - if (!new[] { StarNames.KoopaTheQuick1, StarNames.KoopaTheQuick2 }.Contains(Name)) - { - WriteStarWrapperFunction(rom); - } + private Vector3 ReadPositionAsShort(BinaryRom rom, StarPositionAddress offset) + { + rom.Position = (int)offset; + int x = rom.ReadInt16(); + int y = rom.ReadInt16(); + int z = rom.ReadInt16(); + return new Vector3(x, y, z); + } - var switchExpr = Name; - switch (switchExpr) - { - case StarNames.KoopaTheQuick1: - { - WritePositionAsShort(rom, Position, StarPositionAddress.KoopaTheQuick1); - break; - } - - case StarNames.KoopaTheQuick2: - { - WritePositionAsShort(rom, Position, StarPositionAddress.KoopaTheQuick2); - break; - } - - case StarNames.KingBobOmbBoss: - { - WritePositionAsSingle(rom, Position, StarPositionAddress.KingBobOmbBoss); - rom.Position = 0x62AD4; - rom.Write(0x3C048040); // LUI A0, &H8040 - rom.Write(0xC1009C0); // JAL &H80402700 - rom.Write(0x34844F00); // ORI A0, A0, &H4F40 - rom.Write(0x0); - rom.Write(0x0); - rom.Write(0x0); - rom.Write(0x0); - rom.Write(0x0); - break; - } - - case StarNames.WhompBoss: - { - WritePositionAsSingle(rom, Position, StarPositionAddress.WhompBoss); - rom.Position = 0x82900; - rom.Write(0x3C018040); - rom.Write(0xC42C4F10); - rom.Write(0xC42E4F14); - rom.Write(0x8C264F18); - rom.Position = 0x82914; - rom.Write(0x0); - break; - } - - case StarNames.EyerockBoss: - { - WritePositionAsSingle(rom, Position, StarPositionAddress.EyerockBoss); - rom.Position = 0xC9A1C; // 0x8030EA1c - rom.Write(0x3C048040); // LUI A0, &H8040 - rom.Write(0xC1009C0); // JAL &H80402700 - rom.Write(0x34844F20); // ORI A0, A0, &H4F20 - rom.Write(0x0); // NOPs - rom.Write(0x0); - rom.Write(0x0); - break; - } - - case StarNames.BigBullyBoss: - { - WritePositionAsSingle(rom, Position, StarPositionAddress.BigBullyBoss); - rom.Position = 0xA6970; // 0x802EB970 - rom.Write(0x3C048040); // LUI A0, 0x8040 - rom.Write(0xC1009C0); // JAL 0x80402700 - rom.Write(0x34844F30); // ORI A0, A0, 0x4F30 - break; - } - - case StarNames.ChillBullyBoss: - { - WritePositionAsSingle(rom, Position, StarPositionAddress.ChillBullyBoss); - rom.Position = 0xA6950; // 0x802EB950 - rom.Write(0x3C048040); // LUI A0, 0x8040 - rom.Write(0xC1009C0); // JAL 0x80402700 - rom.Write(0x34844F40); // ORI A0, A0, 0x4F40 - break; - } - - case StarNames.GiantPiranhaPlants: - { - WritePositionAsSingle(rom, Position, StarPositionAddress.GiantPiranhaPlants); - rom.Position = 0xC802C; // 0x8030D02C - rom.Write(0x3C048040); // LUI A0, 0x8040 - rom.Write(0xC1009C0); // JAL 0x80402700 - rom.Write(0x34844F50); // ORI A0, A0, 0x4F50 - break; - } - - case StarNames.PenguinMother: - { - WritePositionAsSingle(rom, Position, StarPositionAddress.PenguinMother); - rom.Position = 0x7A128; // 0x802BF128 - rom.Write(0x3C048040); // LUI A0, 0x8040 - rom.Write(0xC1009C0); // JAL 0x80402700 - rom.Write(0x34844F60); - break; - } - - case StarNames.BigPenguinRace: - { - WritePositionAsSingle(rom, Position, StarPositionAddress.BigPenguinRace); - rom.Position = 0xCD040; // 0x80312040 - rom.Write(0x3C048040); // LUI A0, 0x8040 - rom.Write(0xC1009C0); // JAL 0x80402700 - rom.Write(0x34844F90); - break; - } - - case StarNames.WigglerBoss: - { - WritePositionAsSingle(rom, Position, StarPositionAddress.WigglerBoss); - rom.Position = 0xBCFE0; // 80301FE0 - rom.Write(0x3C048040); // LUI A0, 0x8040 - rom.Write(0xC1009C0); // JAL 0x80402700 - rom.Write(0x34844F70); - break; - } - - case StarNames.PeachSlideStar: - { - WritePositionAsSingle(rom, Position, StarPositionAddress.PeachSlideStar); - rom.Position = 0xB7D0; // 80301FE0 - rom.Write(0x3C048040); // LUI A0, 0x8040 - rom.Write(0xC1009C0); // JAL 0x80402700 - rom.Write(0x34844F80); - break; - } - - //case StarNames.BigPenguinRace: - // { - // WritePositionAsSingle(rom, Position, 0x1204F90); - // rom.Position = 0x605E4; // 80301FE0 - // rom.Write(0x3C048040); // LUI A0, 0x8040 - // rom.Write(0xC1009C0); // JAL 0x80402700 - // rom.Write(0x34844F90); - // break; - // } - - case StarNames.TreasureChests: - { - WritePositionAsSingle(rom, Position, StarPositionAddress.TreasureChests); - rom.Position = 0xB32B0; - rom.Write(0x3C048040); // LUI A0, 0x8040 - rom.Write(0xC1009C0); // JAL 0x80402700 - rom.Write(0x34844FA0); - break; - } - - case StarNames.BooInHauntedHouse: - { - WritePositionAsSingle(rom, Position, StarPositionAddress.BooInHauntedHouse); - rom.Position = 0x7FBB0; - rom.Write(0x3C048040); // LUI A0, 0x8040 - rom.Write(0xC1009C0); // JAL 0x80402700 - rom.Write(0x34844FAC); - break; - } - - case StarNames.Klepto: - { - WritePositionAsSingle(rom, Position, StarPositionAddress.Klepto); - rom.Position = 0xCC47C; - rom.Write(0x3C048040); // LUI A0, 0x8040 - rom.Write(0xC1009C0); // JAL 0x80402700 - rom.Write(0x34844FC4); - break; - } - - case StarNames.MerryGoRoundboss: - { - WritePositionAsSingle(rom, Position, StarPositionAddress.MerryGoRoundboss); - rom.Position = 0x7FC24; - rom.Write(0x3C048040); // LUI A0, 0x8040 - rom.Write(0xC1009C0); // JAL 0x80402700 - rom.Write(0x34844FB8); - break; - } - - case StarNames.MrIboss: - { - WritePositionAsSingle(rom, Position, StarPositionAddress.MrIboss); - rom.Position = 0x61450; - rom.Write(0x3C048040); // LUI A0, 0x8040 - rom.Write(0xC1009C0); // JAL 0x80402700 - rom.Write(0x34844FD0); - break; - } - - case StarNames.RooftopBoo: - { - WritePositionAsSingle(rom, Position, StarPositionAddress.RooftopBoo); - rom.Position = 0x7FBEC; - rom.Write(0x3C048040); // LUI A0, 0x8040 - rom.Write(0xC1009C0); // JAL 0x80402700 - rom.Write(0x34844FDC); - break; - } - - case StarNames.SecondactBigBully: - { - WritePositionAsSingle(rom, Position, StarPositionAddress.SecondactBigBully); - rom.Position = 0xA6CBC; - rom.Write(0x3C048040); // LUI A0, 0x8040 - rom.Write(0xC1009C0); // JAL 0x80402700 - rom.Write(0x34844FE4); - break; - } - } - - rom.Close(); - } - - private void WritePositionAsShort(BinaryRom rom, Vector3 position, StarPositionAddress offset) - { - rom.Position = (int)offset; - rom.Write(Convert.ToInt16(position.X)); - rom.Write(Convert.ToInt16(position.Y)); - rom.Write(Convert.ToInt16(position.Z)); - } - - private void WritePositionAsSingle(BinaryRom rom, Vector3 position, StarPositionAddress offset) - { - rom.Position = (int)offset; - rom.Write(position.X); - rom.Write(position.Y); - rom.Write(position.Z); - } - - public static void WriteStarWrapperFunction(BinaryRom rom) - { - var StarWrapperFunction = new[] { 0x27, 0xBD, 0xFF, 0xE8, 0xAF, 0xBF, 0x0, 0x14, 0xC4, 0x8C, 0x0, 0x0, 0xC4, 0x8E, 0x0, 0x4, 0xC, 0xB, 0xCA, 0xE2, 0x8C, 0x86, 0x0, 0x8, 0x8F, 0xBF, 0x0, 0x14, 0x27, 0xBD, 0x0, 0x18, 0x3, 0xE0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x0 }; - rom.Position = 0x1202700; - foreach (var b in StarWrapperFunction) - rom.Write(b); - } - - public Vector3 LoadPosition(StarNames name, RomManager romManager) - { - using var rom = romManager.GetBinaryRom(FileAccess.Read); - return name switch - { - StarNames.KoopaTheQuick1 => ReadPositionAsShort(rom, StarPositionAddress.KoopaTheQuick1), - StarNames.KoopaTheQuick2 => ReadPositionAsShort(rom, StarPositionAddress.KoopaTheQuick2), - StarNames.KingBobOmbBoss => ReadPositionAsSingle(rom, StarPositionAddress.KingBobOmbBoss), - StarNames.WhompBoss => ReadPositionAsSingle(rom, StarPositionAddress.WhompBoss), - StarNames.EyerockBoss => ReadPositionAsSingle(rom, StarPositionAddress.EyerockBoss), - StarNames.BigBullyBoss => ReadPositionAsSingle(rom, StarPositionAddress.BigBullyBoss), - StarNames.ChillBullyBoss => ReadPositionAsSingle(rom, StarPositionAddress.ChillBullyBoss), - StarNames.GiantPiranhaPlants => ReadPositionAsSingle(rom, StarPositionAddress.GiantPiranhaPlants), - StarNames.PenguinMother => ReadPositionAsSingle(rom, StarPositionAddress.PenguinMother), - StarNames.BigPenguinRace => ReadPositionAsSingle(rom, StarPositionAddress.BigPenguinRace), - StarNames.WigglerBoss => ReadPositionAsSingle(rom, StarPositionAddress.WigglerBoss), - StarNames.PeachSlideStar => ReadPositionAsSingle(rom, StarPositionAddress.PeachSlideStar), - StarNames.TreasureChests => ReadPositionAsSingle(rom, StarPositionAddress.TreasureChests), - StarNames.BooInHauntedHouse => ReadPositionAsSingle(rom, StarPositionAddress.BooInHauntedHouse), - StarNames.Klepto => ReadPositionAsSingle(rom, StarPositionAddress.Klepto), - StarNames.MerryGoRoundboss => ReadPositionAsSingle(rom, StarPositionAddress.MerryGoRoundboss), - StarNames.MrIboss => ReadPositionAsSingle(rom, StarPositionAddress.MrIboss), - StarNames.RooftopBoo => ReadPositionAsSingle(rom, StarPositionAddress.RooftopBoo), - StarNames.SecondactBigBully => ReadPositionAsSingle(rom, StarPositionAddress.SecondactBigBully), - _ => throw new System.ArgumentException(string.Format("{0} is not a valid StarNames value", name)), - }; - } - - private Vector3 ReadPositionAsShort(BinaryRom rom, StarPositionAddress offset) - { - rom.Position = (int)offset; - int x = rom.ReadInt16(); - int y = rom.ReadInt16(); - int z = rom.ReadInt16(); - return new Vector3(x, y, z); - } - - private Vector3 ReadPositionAsSingle(BinaryRom rom, StarPositionAddress offset) - { - rom.Position = (int)offset; - float x = rom.ReadSingle(); - float y = rom.ReadSingle(); - float z = rom.ReadSingle(); - return new Vector3(x, y, z); - } + private Vector3 ReadPositionAsSingle(BinaryRom rom, StarPositionAddress offset) + { + rom.Position = (int)offset; + float x = rom.ReadSingle(); + float y = rom.ReadSingle(); + float z = rom.ReadSingle(); + return new Vector3(x, y, z); } } \ No newline at end of file diff --git a/SM64Lib/Objects/StarNames.cs b/SM64Lib/Objects/StarNames.cs index 22f8a7c..3920644 100644 --- a/SM64Lib/Objects/StarNames.cs +++ b/SM64Lib/Objects/StarNames.cs @@ -1,26 +1,25 @@  -namespace SM64Lib.Objects +namespace SM64Lib.Objects; + +public enum StarNames { - public enum StarNames - { - KoopaTheQuick1, - KoopaTheQuick2, - KingBobOmbBoss, - WhompBoss, - EyerockBoss, - BigBullyBoss, - ChillBullyBoss, - GiantPiranhaPlants, - PenguinMother, - BigPenguinRace, - WigglerBoss, - PeachSlideStar, - TreasureChests, - BooInHauntedHouse, - Klepto, - MerryGoRoundboss, - MrIboss, - RooftopBoo, - SecondactBigBully - } + KoopaTheQuick1, + KoopaTheQuick2, + KingBobOmbBoss, + WhompBoss, + EyerockBoss, + BigBullyBoss, + ChillBullyBoss, + GiantPiranhaPlants, + PenguinMother, + BigPenguinRace, + WigglerBoss, + PeachSlideStar, + TreasureChests, + BooInHauntedHouse, + Klepto, + MerryGoRoundboss, + MrIboss, + RooftopBoo, + SecondactBigBully } \ No newline at end of file diff --git a/SM64Lib/Objects/StarPositionAddress.cs b/SM64Lib/Objects/StarPositionAddress.cs index c74fcc4..4cce453 100644 --- a/SM64Lib/Objects/StarPositionAddress.cs +++ b/SM64Lib/Objects/StarPositionAddress.cs @@ -1,25 +1,24 @@ -namespace SM64Lib.Objects +namespace SM64Lib.Objects; + +public enum StarPositionAddress { - public enum StarPositionAddress - { - KoopaTheQuick1 = 0xED868, - KoopaTheQuick2 = 0xED878, - KingBobOmbBoss = 0x1204F00, - WhompBoss = 0x1204F10, - EyerockBoss = 0x1204F20, - BigBullyBoss = 0x1204F30, - ChillBullyBoss = 0x1204F40, - GiantPiranhaPlants = 0x1204F50, - PenguinMother = 0x1204F60, - BigPenguinRace = 0x1204F90, - WigglerBoss = 0x1204F70, - PeachSlideStar = 0x1204F80, - TreasureChests = 0x1204FA0, - BooInHauntedHouse = 0x1204FAC, - Klepto = 0x1204FC4, - MerryGoRoundboss = 0x1204FB8, - MrIboss = 0x1204FD0, - RooftopBoo = 0x1204FDC, - SecondactBigBully = 0x1204FE4 - } + KoopaTheQuick1 = 0xED868, + KoopaTheQuick2 = 0xED878, + KingBobOmbBoss = 0x1204F00, + WhompBoss = 0x1204F10, + EyerockBoss = 0x1204F20, + BigBullyBoss = 0x1204F30, + ChillBullyBoss = 0x1204F40, + GiantPiranhaPlants = 0x1204F50, + PenguinMother = 0x1204F60, + BigPenguinRace = 0x1204F90, + WigglerBoss = 0x1204F70, + PeachSlideStar = 0x1204F80, + TreasureChests = 0x1204FA0, + BooInHauntedHouse = 0x1204FAC, + Klepto = 0x1204FC4, + MerryGoRoundboss = 0x1204FB8, + MrIboss = 0x1204FD0, + RooftopBoo = 0x1204FDC, + SecondactBigBully = 0x1204FE4 } diff --git a/SM64Lib/Patching/DLLFunctionInformation.cs b/SM64Lib/Patching/DLLFunctionInformation.cs index ee9844d..c594296 100644 --- a/SM64Lib/Patching/DLLFunctionInformation.cs +++ b/SM64Lib/Patching/DLLFunctionInformation.cs @@ -1,25 +1,19 @@ using Newtonsoft.Json.Linq; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace SM64Lib.Patching +namespace SM64Lib.Patching; + +public class DLLFunctionInformation { - public class DLLFunctionInformation + public string EmbeddedFileName { get; set; } + public string Typename { get; set; } + + public void Set(PatchScript script) { - public string EmbeddedFileName { get; set; } - public string Typename { get; set; } + script.Script = JObject.FromObject(this).ToString(); + } - public void Set(PatchScript script) - { - script.Script = JObject.FromObject(this).ToString(); - } - - public static PatchFileInformations Get(PatchScript script) - { - return JObject.Parse(script.Script).ToObject(); - } + public static PatchFileInformations Get(PatchScript script) + { + return JObject.Parse(script.Script).ToObject(); } } diff --git a/SM64Lib/Patching/Flips.cs b/SM64Lib/Patching/Flips.cs index db176a2..32e56e7 100644 --- a/SM64Lib/Patching/Flips.cs +++ b/SM64Lib/Patching/Flips.cs @@ -1,100 +1,94 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Diagnostics; -namespace SM64Lib.Patching +namespace SM64Lib.Patching; + +public class Flips { - public class Flips + private readonly string flipsFilePath = null; + + public string FlipsFilePath { - private readonly string flipsFilePath = null; + get => flipsFilePath ?? General.MyFilePaths["Flips.exe"]; + } - public string FlipsFilePath + public bool Enabled + { get => !string.IsNullOrEmpty(FlipsFilePath); } + + public Flips() + { + } + + public Flips(string flipsFilePath) : this() + { + this.flipsFilePath = flipsFilePath; + } + + public bool CreatePatch(string originalRomPath, string patchedRomPath, string patchPath, FlipsPatchType patchType) + { + return ExecuteFlips($"--create {GetArgumentParameter(patchType)} \"{originalRomPath}\" \"{patchedRomPath}\" \"{patchPath}\""); + } + + public bool ApplyPatch(string romPath, string patchPath) + { + return ExecuteFlips($"--apply --ignore-checksum \"{patchPath}\" \"{romPath}\" \"{romPath}\""); + } + + public static string GetExtension(FlipsPatchType patchType) + { + string ext; + + switch (patchType) { - get => flipsFilePath ?? General.MyFilePaths["Flips.exe"]; + case FlipsPatchType.IPS: + ext = ".ips"; + break; + case FlipsPatchType.BPS: + ext = ".bps"; + break; + default: + ext = string.Empty; + break; } - public bool Enabled - { get => !string.IsNullOrEmpty(FlipsFilePath); } + return ext; + } - public Flips() + private static string GetArgumentParameter(FlipsPatchType patchType) + { + string ext; + + switch (patchType) { + case FlipsPatchType.IPS: + ext = "--ips"; + break; + case FlipsPatchType.BPS: + ext = "--bps"; + break; + default: + ext = string.Empty; + break; } - public Flips(string flipsFilePath) : this() - { - this.flipsFilePath = flipsFilePath; - } + return ext; + } - public bool CreatePatch(string originalRomPath, string patchedRomPath, string patchPath, FlipsPatchType patchType) - { - return ExecuteFlips($"--create {GetArgumentParameter(patchType)} \"{originalRomPath}\" \"{patchedRomPath}\" \"{patchPath}\""); - } + private bool ExecuteFlips(string arguments) + { + // Create process + var proc = new Process(); + proc.StartInfo.FileName = FlipsFilePath; + proc.StartInfo.UseShellExecute = false; + proc.StartInfo.Arguments = arguments; + proc.StartInfo.CreateNoWindow = true; - public bool ApplyPatch(string romPath, string patchPath) - { - return ExecuteFlips($"--apply --ignore-checksum \"{patchPath}\" \"{romPath}\" \"{romPath}\""); - } + // Execute + proc.Start(); + proc.WaitForExit(); - public static string GetExtension(FlipsPatchType patchType) - { - string ext; + // Check for errors + var success = proc.ExitCode == 0; - switch (patchType) - { - case FlipsPatchType.IPS: - ext = ".ips"; - break; - case FlipsPatchType.BPS: - ext = ".bps"; - break; - default: - ext = string.Empty; - break; - } - - return ext; - } - - private static string GetArgumentParameter(FlipsPatchType patchType) - { - string ext; - - switch (patchType) - { - case FlipsPatchType.IPS: - ext = "--ips"; - break; - case FlipsPatchType.BPS: - ext = "--bps"; - break; - default: - ext = string.Empty; - break; - } - - return ext; - } - - private bool ExecuteFlips(string arguments) - { - // Create process - var proc = new Process(); - proc.StartInfo.FileName = FlipsFilePath; - proc.StartInfo.UseShellExecute = false; - proc.StartInfo.Arguments = arguments; - proc.StartInfo.CreateNoWindow = true; - - // Execute - proc.Start(); - proc.WaitForExit(); - - // Check for errors - var success = proc.ExitCode == 0; - - return success; - } + return success; } } diff --git a/SM64Lib/Patching/FlipsPatchType.cs b/SM64Lib/Patching/FlipsPatchType.cs index 8c4ec17..1ad3ca2 100644 --- a/SM64Lib/Patching/FlipsPatchType.cs +++ b/SM64Lib/Patching/FlipsPatchType.cs @@ -1,14 +1,7 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +namespace SM64Lib.Patching; -namespace SM64Lib.Patching +public enum FlipsPatchType { - public enum FlipsPatchType - { - IPS, - BPS - } + IPS, + BPS } diff --git a/SM64Lib/Patching/InputValueType.cs b/SM64Lib/Patching/InputValueType.cs index 4f7e029..7e99cb4 100644 --- a/SM64Lib/Patching/InputValueType.cs +++ b/SM64Lib/Patching/InputValueType.cs @@ -1,19 +1,12 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +namespace SM64Lib.Patching; -namespace SM64Lib.Patching +public enum InputValueType { - public enum InputValueType - { - Byte, - UInt16, - UInt32, - Single, - String, - Sequence, - LevelID - } + Byte, + UInt16, + UInt32, + Single, + String, + Sequence, + LevelID } diff --git a/SM64Lib/Patching/PPF.cs b/SM64Lib/Patching/PPF.cs index 58f5b0d..6e97f3f 100644 --- a/SM64Lib/Patching/PPF.cs +++ b/SM64Lib/Patching/PPF.cs @@ -1,56 +1,50 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Diagnostics; -namespace SM64Lib.Patching +namespace SM64Lib.Patching; + +public class PPF { - public class PPF + private readonly string applyPPFFilePath = null; + + public string ApplyPPFFilePath { - private readonly string applyPPFFilePath = null; + get => applyPPFFilePath ?? General.MyFilePaths["ApplyPPF3.exe"]; + } - public string ApplyPPFFilePath - { - get => applyPPFFilePath ?? General.MyFilePaths["ApplyPPF3.exe"]; - } + public bool Enabled + { get => !string.IsNullOrEmpty(ApplyPPFFilePath); } - public bool Enabled - { get => !string.IsNullOrEmpty(ApplyPPFFilePath); } + public PPF() + { + } - public PPF() - { - } + public PPF(string applyPPFFilePath) + { + this.applyPPFFilePath = applyPPFFilePath; + } - public PPF(string applyPPFFilePath) - { - this.applyPPFFilePath = applyPPFFilePath; - } + public bool ApplyPatch(string romPath, string patchPath) + { + var args = string.Format("a \"{0}\" \"{1}\"", romPath, patchPath); + return ExecuteApplyPPF(args); + } - public bool ApplyPatch(string romPath, string patchPath) - { - var args = string.Format("a \"{0}\" \"{1}\"", romPath, patchPath); - return ExecuteApplyPPF(args); - } + private bool ExecuteApplyPPF(string arguments) + { + // Create process + var proc = new Process(); + proc.StartInfo.FileName = ApplyPPFFilePath; + proc.StartInfo.UseShellExecute = false; + proc.StartInfo.Arguments = arguments; + proc.StartInfo.CreateNoWindow = true; - private bool ExecuteApplyPPF(string arguments) - { - // Create process - var proc = new Process(); - proc.StartInfo.FileName = ApplyPPFFilePath; - proc.StartInfo.UseShellExecute = false; - proc.StartInfo.Arguments = arguments; - proc.StartInfo.CreateNoWindow = true; + // Execute + proc.Start(); + proc.WaitForExit(); - // Execute - proc.Start(); - proc.WaitForExit(); + // Check for errors + var success = proc.ExitCode == 0; - // Check for errors - var success = proc.ExitCode == 0; - - return success; - } + return success; } } diff --git a/SM64Lib/Patching/PatchClass.cs b/SM64Lib/Patching/PatchClass.cs index 5e73e0a..86cabb0 100644 --- a/SM64Lib/Patching/PatchClass.cs +++ b/SM64Lib/Patching/PatchClass.cs @@ -1,206 +1,204 @@ -using System; -using System.Diagnostics; +using global::SM64Lib.Data; using global::System.IO; using global::System.Windows.Forms; -using Microsoft.VisualBasic.CompilerServices; -using global::SM64Lib.Data; +using System; +using System.Diagnostics; -namespace SM64Lib.Patching +namespace SM64Lib.Patching; + +public class PatchClass { - public class PatchClass + public static event ExternalToolStartExitNotification StartingExternalTool; + public static event ExternalToolStartExitNotification ExitingExternalTool; + public delegate void ExternalToolStartExitNotification(PatchClass instance); + + private BinaryData data = null; + + /* TODO ERROR: Skipped RegionDirectiveTrivia */ + public void ApplyPPF(string Romfile, string PPFFile) { - public static event ExternalToolStartExitNotification StartingExternalTool; - public static event ExternalToolStartExitNotification ExitingExternalTool; - public delegate void ExternalToolStartExitNotification(PatchClass instance); - - private BinaryData data = null; - - /* TODO ERROR: Skipped RegionDirectiveTrivia */ - public void ApplyPPF(string Romfile, string PPFFile) - { - var ppf = new PPF(); - ppf.ApplyPatch(Romfile, PPFFile); - } - - private int RunProcess(string Filename, string Args = "") - { - var p = new Process(); - { - var withBlock = p.StartInfo; - withBlock.CreateNoWindow = true; - withBlock.FileName = Filename; - withBlock.Arguments = Args; - withBlock.UseShellExecute = false; - } - - StartingExternalTool?.Invoke(this); - - p.Start(); - while (!p.HasExited) - Application.DoEvents(); - - ExitingExternalTool?.Invoke(this); - return p.ExitCode; - } - /* TODO ERROR: Skipped EndRegionDirectiveTrivia */ - /* TODO ERROR: Skipped RegionDirectiveTrivia */ - public void UpdateChecksum(string Romfile) - { - RunProcess(General.MyFilePaths["rn64crc.exe"], $"\"{Romfile}\" -u"); - } - - public void RestoreChecksum() - { - data.Position = 0x66C; - data.Write(350748678U); - data.Position = 0x678; - data.Write(369623043U); - } - /* TODO ERROR: Skipped EndRegionDirectiveTrivia */ - /* TODO ERROR: Skipped RegionDirectiveTrivia */ - public void Open(string Romfile, bool OnlyRead) - { - Open(new BinaryFile(Romfile, FileMode.Open, OnlyRead ? FileAccess.Read : FileAccess.ReadWrite)); - } - - public void Open(BinaryData data) - { - this.data = data; - } - - public void Open(Stream s) - { - Open(new BinaryStreamData(s)); - } - - public void Close() - { - data.Close(); - } - - /* TODO ERROR: Skipped EndRegionDirectiveTrivia */ - /* TODO ERROR: Skipped RegionDirectiveTrivia */ - public void ActSelector_ApplyPatch() - { - // Write Original Data - data.Position = 0x1202EC0; - foreach (byte b in new[] { 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 17 }) // {0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17} - data.Write(b); - - // Update Pointers - data.Position = 0x6F38; - data.Write(0x2B010001U); - data.Position = 0x6F50; - data.Write(0x8100BC0U); - data.Write(0); - - // Write Function - data.Position = 0x1202F00; - foreach (byte b in new[] { 60, 1, 128, 51, 132, 33, 221, 248, 60, 8, 128, 64, 53, 8, 46, 192, 1, 1, 64, 33, 145, 8, 0, 0, 36, 1, 0, 1, 16, 40, 0, 3, 36, 0, 0, 0, 8, 9, 47, 228, 0, 0, 16, 37, 8, 9, 47, 214, 36, 0, 0, 0, 1, 1, 1, 1 }) - data.Write(b); - } - - public bool get_ActSelector_Enabled(int LevelID) - { - data.Position = 0x1202EC0 + LevelID; - return Convert.ToBoolean(data.ReadByte()); - } - - public void set_ActSelector_Enabled(int LevelID, bool value) - { - data.Position = 0x1202EC0 + LevelID; - data.Write(value ? Convert.ToByte(0x1) : Convert.ToByte(0x0)); - } - /* TODO ERROR: Skipped EndRegionDirectiveTrivia */ - /* TODO ERROR: Skipped RegionDirectiveTrivia */ - public void HardcodedCamera_ApplyPatch() - { - data.Position = 0x41AD8; - data.Write(202378196U); - data.Write(2409889856U); - data.Position = 0x1202F50; - data.Write(666763240U); - data.Write(2948530196U); - data.Write(1006731315U); - data.Write(2216812024U); - data.Write(1007190080U); - data.Write(889728592U); - data.Write(16859169U); - data.Write(2433220608U); - data.Write(604045313U); - data.Write(271056899U); - data.Write(603979776U); - data.Write(65011720U); - data.Write(666697752U); - data.Write(201997228U); - data.Write(0U); - data.Write(2411659284U); - data.Write(65011720U); - data.Write(666697752U); - data.Position = 0x1202E50; - for (int index = 0; index <= 43; index++) - data.Write(Convert.ToByte(0x1)); - } - - public void HardcodedCamera_DisableAll() - { - for (int i = 0; i <= 30; i++) - { - data.Position = 0x1202E50 + General.GetLevelIDFromIndex(Convert.ToByte(i)); - data.Write(Convert.ToByte(0x0)); - } - } - - public void HardcodedCamera_EnableAll() - { - for (int i = 0; i <= 30; i++) - { - data.Position = 0x1202E50 + General.GetLevelIDFromIndex(Convert.ToByte(i)); - data.Write(Convert.ToByte(0x1)); - } - } - - public bool get_HardcodedCamera_Enabled(int Levelindex) - { - data.Position = 0x1202E50 + General.GetLevelIDFromIndex(Convert.ToByte(Levelindex)); - if (data.ReadByte() == 0x1) - return true; - else - return false; - } - - public void set_HardcodedCamera_Enabled(int Levelindex, bool value) - { - if (!data.CanWrite) - return; - data.Position = 0x1202E50 + General.GetLevelIDFromIndex(Convert.ToByte(Levelindex)); - if (value) - { - data.Write(Convert.ToByte(0x1)); - } - else - { - data.Write(Convert.ToByte(0x0)); - } - } - - /* TODO ERROR: Skipped EndRegionDirectiveTrivia */ - /* TODO ERROR: Skipped RegionDirectiveTrivia */ - public void SetPauseMenuWarp(short levelID, short areaID, short warpID) - { - // Level ID - data.Position = 0x666A; - data.Write(levelID); - - // Area ID - data.Position = 0x666E; - data.Write(areaID); - - // Warp ID - data.Position = 0x6672; - data.Write(warpID); - } - - /* TODO ERROR: Skipped EndRegionDirectiveTrivia */ + var ppf = new PPF(); + ppf.ApplyPatch(Romfile, PPFFile); } + + private int RunProcess(string Filename, string Args = "") + { + var p = new Process(); + { + var withBlock = p.StartInfo; + withBlock.CreateNoWindow = true; + withBlock.FileName = Filename; + withBlock.Arguments = Args; + withBlock.UseShellExecute = false; + } + + StartingExternalTool?.Invoke(this); + + p.Start(); + while (!p.HasExited) + Application.DoEvents(); + + ExitingExternalTool?.Invoke(this); + return p.ExitCode; + } + /* TODO ERROR: Skipped EndRegionDirectiveTrivia */ + /* TODO ERROR: Skipped RegionDirectiveTrivia */ + public void UpdateChecksum(string Romfile) + { + RunProcess(General.MyFilePaths["rn64crc.exe"], $"\"{Romfile}\" -u"); + } + + public void RestoreChecksum() + { + data.Position = 0x66C; + data.Write(350748678U); + data.Position = 0x678; + data.Write(369623043U); + } + /* TODO ERROR: Skipped EndRegionDirectiveTrivia */ + /* TODO ERROR: Skipped RegionDirectiveTrivia */ + public void Open(string Romfile, bool OnlyRead) + { + Open(new BinaryFile(Romfile, FileMode.Open, OnlyRead ? FileAccess.Read : FileAccess.ReadWrite)); + } + + public void Open(BinaryData data) + { + this.data = data; + } + + public void Open(Stream s) + { + Open(new BinaryStreamData(s)); + } + + public void Close() + { + data.Close(); + } + + /* TODO ERROR: Skipped EndRegionDirectiveTrivia */ + /* TODO ERROR: Skipped RegionDirectiveTrivia */ + public void ActSelector_ApplyPatch() + { + // Write Original Data + data.Position = 0x1202EC0; + foreach (byte b in new[] { 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 17 }) // {0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17} + data.Write(b); + + // Update Pointers + data.Position = 0x6F38; + data.Write(0x2B010001U); + data.Position = 0x6F50; + data.Write(0x8100BC0U); + data.Write(0); + + // Write Function + data.Position = 0x1202F00; + foreach (byte b in new[] { 60, 1, 128, 51, 132, 33, 221, 248, 60, 8, 128, 64, 53, 8, 46, 192, 1, 1, 64, 33, 145, 8, 0, 0, 36, 1, 0, 1, 16, 40, 0, 3, 36, 0, 0, 0, 8, 9, 47, 228, 0, 0, 16, 37, 8, 9, 47, 214, 36, 0, 0, 0, 1, 1, 1, 1 }) + data.Write(b); + } + + public bool get_ActSelector_Enabled(int LevelID) + { + data.Position = 0x1202EC0 + LevelID; + return Convert.ToBoolean(data.ReadByte()); + } + + public void set_ActSelector_Enabled(int LevelID, bool value) + { + data.Position = 0x1202EC0 + LevelID; + data.Write(value ? Convert.ToByte(0x1) : Convert.ToByte(0x0)); + } + /* TODO ERROR: Skipped EndRegionDirectiveTrivia */ + /* TODO ERROR: Skipped RegionDirectiveTrivia */ + public void HardcodedCamera_ApplyPatch() + { + data.Position = 0x41AD8; + data.Write(202378196U); + data.Write(2409889856U); + data.Position = 0x1202F50; + data.Write(666763240U); + data.Write(2948530196U); + data.Write(1006731315U); + data.Write(2216812024U); + data.Write(1007190080U); + data.Write(889728592U); + data.Write(16859169U); + data.Write(2433220608U); + data.Write(604045313U); + data.Write(271056899U); + data.Write(603979776U); + data.Write(65011720U); + data.Write(666697752U); + data.Write(201997228U); + data.Write(0U); + data.Write(2411659284U); + data.Write(65011720U); + data.Write(666697752U); + data.Position = 0x1202E50; + for (int index = 0; index <= 43; index++) + data.Write(Convert.ToByte(0x1)); + } + + public void HardcodedCamera_DisableAll() + { + for (int i = 0; i <= 30; i++) + { + data.Position = 0x1202E50 + General.GetLevelIDFromIndex(Convert.ToByte(i)); + data.Write(Convert.ToByte(0x0)); + } + } + + public void HardcodedCamera_EnableAll() + { + for (int i = 0; i <= 30; i++) + { + data.Position = 0x1202E50 + General.GetLevelIDFromIndex(Convert.ToByte(i)); + data.Write(Convert.ToByte(0x1)); + } + } + + public bool get_HardcodedCamera_Enabled(int Levelindex) + { + data.Position = 0x1202E50 + General.GetLevelIDFromIndex(Convert.ToByte(Levelindex)); + if (data.ReadByte() == 0x1) + return true; + else + return false; + } + + public void set_HardcodedCamera_Enabled(int Levelindex, bool value) + { + if (!data.CanWrite) + return; + data.Position = 0x1202E50 + General.GetLevelIDFromIndex(Convert.ToByte(Levelindex)); + if (value) + { + data.Write(Convert.ToByte(0x1)); + } + else + { + data.Write(Convert.ToByte(0x0)); + } + } + + /* TODO ERROR: Skipped EndRegionDirectiveTrivia */ + /* TODO ERROR: Skipped RegionDirectiveTrivia */ + public void SetPauseMenuWarp(short levelID, short areaID, short warpID) + { + // Level ID + data.Position = 0x666A; + data.Write(levelID); + + // Area ID + data.Position = 0x666E; + data.Write(areaID); + + // Warp ID + data.Position = 0x6672; + data.Write(warpID); + } + + /* TODO ERROR: Skipped EndRegionDirectiveTrivia */ } \ No newline at end of file diff --git a/SM64Lib/Patching/PatchCompilingResult.cs b/SM64Lib/Patching/PatchCompilingResult.cs index 1e0d5e9..b35d838 100644 --- a/SM64Lib/Patching/PatchCompilingResult.cs +++ b/SM64Lib/Patching/PatchCompilingResult.cs @@ -1,22 +1,16 @@ using Microsoft.CodeAnalysis.Emit; -using System; -using System.Collections.Generic; -using System.Linq; using System.Reflection; -using System.Text; -using System.Threading.Tasks; -namespace SM64Lib.Patching +namespace SM64Lib.Patching; + +public class PatchCompilingResult { - public class PatchCompilingResult - { - public EmitResult EmitResult { get; init; } - public Assembly OutputAssembly { get; init; } + public EmitResult EmitResult { get; init; } + public Assembly OutputAssembly { get; init; } - internal PatchCompilingResult(EmitResult emitResult, Assembly outputAssembly) - { - EmitResult = emitResult; - OutputAssembly = outputAssembly; - } + internal PatchCompilingResult(EmitResult emitResult, Assembly outputAssembly) + { + EmitResult = emitResult; + OutputAssembly = outputAssembly; } } diff --git a/SM64Lib/Patching/PatchFileInformations.cs b/SM64Lib/Patching/PatchFileInformations.cs index 23b58bb..b8cea48 100644 --- a/SM64Lib/Patching/PatchFileInformations.cs +++ b/SM64Lib/Patching/PatchFileInformations.cs @@ -1,34 +1,28 @@ using Newtonsoft.Json.Linq; -using SM64Lib.Patching; using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace SM64Lib.Patching +namespace SM64Lib.Patching; + +public class PatchFileInformations { - public class PatchFileInformations + public string PatchFileName { get; set; } + public string ClassPath { get; set; } + public string MethodName { get; set; } + + public void Set(PatchScript script) { - public string PatchFileName { get; set; } - public string ClassPath { get; set; } - public string MethodName { get; set; } + script.Script = JObject.FromObject(this).ToString(); + } - public void Set(PatchScript script) + public static PatchFileInformations Get(PatchScript script) + { + try { - script.Script = JObject.FromObject(this).ToString(); + return JObject.Parse(script.Script).ToObject(); } - - public static PatchFileInformations Get(PatchScript script) + catch (Exception) { - try - { - return JObject.Parse(script.Script).ToObject(); - } - catch(Exception) - { - return new PatchFileInformations(); - } + return new PatchFileInformations(); } } } diff --git a/SM64Lib/Patching/PatchScript.cs b/SM64Lib/Patching/PatchScript.cs index 1381992..f38bfeb 100644 --- a/SM64Lib/Patching/PatchScript.cs +++ b/SM64Lib/Patching/PatchScript.cs @@ -1,179 +1,178 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Collections.Specialized; -using Newtonsoft.Json; +using Newtonsoft.Json; using Newtonsoft.Json.Converters; -using Pilz.IO; using Pilz.Cryptography; +using Pilz.IO; using Pilz.Json.Converters; +using System; +using System.Collections.Generic; +using System.Collections.Specialized; using System.ComponentModel; +using System.IO; using VersionConverter = Newtonsoft.Json.Converters.VersionConverter; -namespace SM64Lib.Patching +namespace SM64Lib.Patching; + +public class PatchProfile { - public class PatchProfile - { - /// - /// The Name of the Profile. - /// - /// - public string Name { get; set; } = ""; - /// - /// A list with scripts. - /// - /// - public List Scripts { get; set; } = new List(); - /// - /// The version of this profile. - /// - /// - [JsonConverter(typeof(VersionConverter))] - public Version Version { get; set; } = new Version("1.0.0.0"); - /// - /// The minimum ROM Manager version requied for this tweak. - /// - [JsonConverter(typeof(VersionConverter))] - public Version MinVersion { get; set; } = new Version("1.0.0.0"); - /// - /// The maximum ROM Manager version allowed for this tweak. - /// - [JsonConverter(typeof(VersionConverter))] - public Version MaxVersion { get; set; } = new Version("0.0.0.0"); - /// - /// The description of this profile - /// - /// - public string Description { get; set; } = ""; - /// - /// The Xml file for this profile. - /// - /// - [JsonIgnore] - public string FileName { get; set; } = ""; - /// - /// Indicates if this patch use the old XML format. - /// - [JsonIgnore] - public bool IsLegacy => Path.GetExtension(FileName).Equals(".xml", StringComparison.CurrentCultureIgnoreCase); - /// - /// Contains files embedded into this profile. - /// - public EmbeddedFilesContainer EmbeddedFiles { get; } = new EmbeddedFilesContainer(); - /// - /// Defines an uniquie ID to identify this tweak (e.g. for undo patch). - /// - [JsonConverter(typeof(UniquieIDStringJsonConverter))] - public UniquieID ID { get; set; } = new(); - /// - /// Defines if the tweak is official and secure. - /// - public bool Official { get; set; } = false; - /// - /// Defines if the tweak is recommended for every common SM64 ROM Hack. - /// - public bool Recommended { get; set; } = false; - } - /// - /// A Profile containing a script and some descriptions. + /// The Name of the Profile. /// - public class PatchScript - { - /// - /// The Name of this Script. - /// - /// - [DefaultValue("")] - public string Name { get; set; } = string.Empty; - /// - /// The Script. - /// - /// - [DefaultValue("")] - public string Script { get; set; } = string.Empty; - /// - /// Defines the syntax of the script. - /// - /// - [JsonConverter(typeof(StringEnumConverter))] - public ScriptType Type { get; set; } = ScriptType.TweakScript; - /// - /// The description of this Script. - /// - /// - [DefaultValue("")] - public string Description { get; set; } = string.Empty; - /// - /// A collection of Reference Assemblies to bind at compiling script. - /// - /// - [JsonProperty("ReferencesV2")] - public PatchScriptReferences References { get; set; } = []; - /// - /// Defines an uniquie ID to identify this script (e.g. for undo patch). - /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Include)] - [JsonConverter(typeof(UniquieIDStringJsonConverter))] - public UniquieID ID { get; set; } = new(); - /// - /// Defines if undo is allowed for this script. - /// - public bool AllowRevert { get; set; } = false; + /// + public string Name { get; set; } = ""; + /// + /// A list with scripts. + /// + /// + public List Scripts { get; set; } = new List(); + /// + /// The version of this profile. + /// + /// + [JsonConverter(typeof(VersionConverter))] + public Version Version { get; set; } = new Version("1.0.0.0"); + /// + /// The minimum ROM Manager version requied for this tweak. + /// + [JsonConverter(typeof(VersionConverter))] + public Version MinVersion { get; set; } = new Version("1.0.0.0"); + /// + /// The maximum ROM Manager version allowed for this tweak. + /// + [JsonConverter(typeof(VersionConverter))] + public Version MaxVersion { get; set; } = new Version("0.0.0.0"); + /// + /// The description of this profile + /// + /// + public string Description { get; set; } = ""; + /// + /// The Xml file for this profile. + /// + /// + [JsonIgnore] + public string FileName { get; set; } = ""; + /// + /// Indicates if this patch use the old XML format. + /// + [JsonIgnore] + public bool IsLegacy => Path.GetExtension(FileName).Equals(".xml", StringComparison.CurrentCultureIgnoreCase); + /// + /// Contains files embedded into this profile. + /// + public EmbeddedFilesContainer EmbeddedFiles { get; } = new EmbeddedFilesContainer(); + /// + /// Defines an uniquie ID to identify this tweak (e.g. for undo patch). + /// + [JsonConverter(typeof(UniquieIDStringJsonConverter))] + public UniquieID ID { get; set; } = new(); + /// + /// Defines if the tweak is official and secure. + /// + public bool Official { get; set; } = false; + /// + /// Defines if the tweak is recommended for every common SM64 ROM Hack. + /// + public bool Recommended { get; set; } = false; +} - [JsonProperty("References"), Obsolete] - private StringCollection ReferencesV1 +/// +/// A Profile containing a script and some descriptions. +/// +public class PatchScript +{ + /// + /// The Name of this Script. + /// + /// + [DefaultValue("")] + public string Name { get; set; } = string.Empty; + /// + /// The Script. + /// + /// + [DefaultValue("")] + public string Script { get; set; } = string.Empty; + /// + /// Defines the syntax of the script. + /// + /// + [JsonConverter(typeof(StringEnumConverter))] + public ScriptType Type { get; set; } = ScriptType.TweakScript; + /// + /// The description of this Script. + /// + /// + [DefaultValue("")] + public string Description { get; set; } = string.Empty; + /// + /// A collection of Reference Assemblies to bind at compiling script. + /// + /// + [JsonProperty("ReferencesV2")] + public PatchScriptReferences References { get; set; } = []; + /// + /// Defines an uniquie ID to identify this script (e.g. for undo patch). + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Include)] + [JsonConverter(typeof(UniquieIDStringJsonConverter))] + public UniquieID ID { get; set; } = new(); + /// + /// Defines if undo is allowed for this script. + /// + public bool AllowRevert { get; set; } = false; + + [JsonProperty("References"), Obsolete] + private StringCollection ReferencesV1 + { + set { - set + foreach (var reference in value) { - foreach (var reference in value) + References.Add(new PatchScriptReference { - References.Add(new PatchScriptReference - { - Name = reference, - ReferenceType = PatchScriptReferenceType.AssemblyName - }); - } + Name = reference, + ReferenceType = PatchScriptReferenceType.AssemblyName + }); } } } +} +/// +/// Defines the script type, so the behavior on write it. +/// +public enum ScriptType +{ /// - /// Defines the script type, so the behavior on write it. + /// A tweak syntax known from the SM64 Editor. /// - public enum ScriptType - { - /// - /// A tweak syntax known from the SM64 Editor. - /// - TweakScript, - /// - /// A Visual Basic code. - /// - VisualBasic, - /// - /// A C# Code. - /// - CSharp, - /// - /// A DLL file containing the Code. - /// - DynamicLinkLibrary, - /// - /// Code that can be applied using Armips. - /// - Armips, - /// - /// Patch a BSP patch using Flips. - /// - BPS, - /// - /// Patch an IPS patch using Flips. - /// - IPS, - /// - /// Patch a PPF patch using ApplyPPF3. - /// - PPF - } + TweakScript, + /// + /// A Visual Basic code. + /// + VisualBasic, + /// + /// A C# Code. + /// + CSharp, + /// + /// A DLL file containing the Code. + /// + DynamicLinkLibrary, + /// + /// Code that can be applied using Armips. + /// + Armips, + /// + /// Patch a BSP patch using Flips. + /// + BPS, + /// + /// Patch an IPS patch using Flips. + /// + IPS, + /// + /// Patch a PPF patch using ApplyPPF3. + /// + PPF } \ No newline at end of file diff --git a/SM64Lib/Patching/PatchScriptExecuteParams.cs b/SM64Lib/Patching/PatchScriptExecuteParams.cs index 997064b..375ffa6 100644 --- a/SM64Lib/Patching/PatchScriptExecuteParams.cs +++ b/SM64Lib/Patching/PatchScriptExecuteParams.cs @@ -1,20 +1,15 @@ using Pilz.IO; -using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using System.Windows.Forms; -namespace SM64Lib.Patching +namespace SM64Lib.Patching; + +public class PatchScriptExecuteParams { - public class PatchScriptExecuteParams - { - public string RomFilePath { get; set; } - public RomManager RomManager { get; set; } - public EmbeddedFilesContainer EmbeddedFiles { get; set; } - public string ProfilePath { get; set; } - public Dictionary OtherParameters { get; set; } = new(); - public IWin32Window WindowOwner { get; set; } - } + public string RomFilePath { get; set; } + public RomManager RomManager { get; set; } + public EmbeddedFilesContainer EmbeddedFiles { get; set; } + public string ProfilePath { get; set; } + public Dictionary OtherParameters { get; set; } = new(); + public IWin32Window WindowOwner { get; set; } } diff --git a/SM64Lib/Patching/PatchScriptManager.cs b/SM64Lib/Patching/PatchScriptManager.cs index 0e3b445..88fded3 100644 --- a/SM64Lib/Patching/PatchScriptManager.cs +++ b/SM64Lib/Patching/PatchScriptManager.cs @@ -1,642 +1,633 @@ -using System; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Emit; +using Microsoft.CodeAnalysis.VisualBasic; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Pilz.Cryptography; +using Pilz.IO; +using System; using System.Collections.Generic; using System.Data; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; +using System.Runtime.Loader; using System.Windows.Forms; using System.Xml.Linq; -using Microsoft.CSharp; -using Microsoft.VisualBasic; -using Microsoft.VisualBasic.CompilerServices; -using Pilz.S3DFileParser; -using SM64Lib; -using Newtonsoft.Json.Linq; -using Pilz.IO; -using Microsoft.CodeAnalysis.VisualBasic; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.Emit; -using System.Runtime.Loader; -using Pilz.Cryptography; -using Microsoft.CodeAnalysis; -using System.Security.Cryptography.Xml; -using Z.Collections.Extensions; -using Z.Core.Extensions; -using VBLanguageVersion = Microsoft.CodeAnalysis.VisualBasic.LanguageVersion; using CSLanguageVersion = Microsoft.CodeAnalysis.CSharp.LanguageVersion; -using Newtonsoft.Json; +using VBLanguageVersion = Microsoft.CodeAnalysis.VisualBasic.LanguageVersion; -namespace SM64Lib.Patching +namespace SM64Lib.Patching; + +public class PatchingManager { - public class PatchingManager + public delegate void PatchScriptManagerProcessingInputValueEventHandler(object sender, PatchScriptManagerProcessingInputValueEventArgs e); + public static event PatchScriptManagerProcessingInputValueEventHandler ProcessingInputValue; + + public void Save(PatchProfile patch, string dir) { - public delegate void PatchScriptManagerProcessingInputValueEventHandler(object sender, PatchScriptManagerProcessingInputValueEventArgs e); - public static event PatchScriptManagerProcessingInputValueEventHandler ProcessingInputValue; - - public void Save(PatchProfile patch, string dir) + // Check for old file extension and change it + if (string.IsNullOrEmpty(patch.FileName)) { - // Check for old file extension and change it - if (string.IsNullOrEmpty(patch.FileName)) - { - patch.FileName = Path.Combine(dir, patch.Name + ".json"); - } - else if (Path.GetExtension(patch.FileName) == ".xml") - { - var newFileName = Path.ChangeExtension(patch.FileName, ".json"); - File.Delete(patch.FileName); - patch.FileName = newFileName; - } - - // Generate profile ID if null - patch.ID.GenerateIfNull(); - - // Generate script IDs if null - foreach (var script in patch.Scripts) - script.ID.GenerateIfNull(); - - // Write file - Export(patch, patch.FileName); + patch.FileName = Path.Combine(dir, patch.Name + ".json"); + } + else if (Path.GetExtension(patch.FileName) == ".xml") + { + var newFileName = Path.ChangeExtension(patch.FileName, ".json"); + File.Delete(patch.FileName); + patch.FileName = newFileName; } - public void Export(PatchProfile patch, string fileName) - { - File.WriteAllText(fileName, JsonConvert.SerializeObject(patch, Formatting.Indented)); - } + // Generate profile ID if null + patch.ID.GenerateIfNull(); - public PatchProfile Read(string fileName) + // Generate script IDs if null + foreach (var script in patch.Scripts) + script.ID.GenerateIfNull(); + + // Write file + Export(patch, patch.FileName); + } + + public void Export(PatchProfile patch, string fileName) + { + File.WriteAllText(fileName, JsonConvert.SerializeObject(patch, Formatting.Indented)); + } + + public PatchProfile Read(string fileName) + { + switch (Path.GetExtension(fileName)) { - switch (Path.GetExtension(fileName)) + case ".json": + var profile = JObject.Parse(File.ReadAllText(fileName)).ToObject(); + profile.FileName = fileName; + return profile; + case ".xml": + return ReadPatchProfileFromXml(fileName); + default: + return null; + } + } + + private PatchProfile ReadPatchProfileFromXml(string fileName) + { + var patch = new PatchProfile(); + var xml = XDocument.Load(fileName); + patch.FileName = fileName; + var mainNode = xml.Elements().FirstOrDefault(n => n.Name == "m64tweak"); + foreach (XAttribute attr in mainNode.Attributes()) + { + var switchExpr = attr.Name; + switch (switchExpr) { - case ".json": - var profile = JObject.Parse(File.ReadAllText(fileName)).ToObject(); - profile.FileName = fileName; - return profile; - case ".xml": - return ReadPatchProfileFromXml(fileName); - default: - return null; + case var @case when @case == "name": + patch.Name = attr.Value; + break; + case var case1 when case1 == "description": + patch.Description = attr.Value; + break; + case var case2 when case2 == "version": + patch.Version = new Version(attr.Value); + break; } } - private PatchProfile ReadPatchProfileFromXml(string fileName) + foreach (XElement element in mainNode.Elements()) { - var patch = new PatchProfile(); - var xml = XDocument.Load(fileName); - patch.FileName = fileName; - var mainNode = xml.Elements().FirstOrDefault(n => n.Name == "m64tweak"); - foreach (XAttribute attr in mainNode.Attributes()) + var switchExpr1 = element.Name; + switch (switchExpr1) { - var switchExpr = attr.Name; - switch (switchExpr) - { - case var @case when @case == "name": - patch.Name = attr.Value; - break; - case var case1 when case1 == "description": - patch.Description = attr.Value; - break; - case var case2 when case2 == "version": - patch.Version = new Version(attr.Value); - break; - } + case var case3 when case3 == "name": + patch.Name = element.Value; + break; + case var case4 when case4 == "description": + patch.Description = element.Value; + break; + case var case5 when case5 == "patch": + patch.Scripts.Add(XElementToScript(element)); + break; } - - foreach (XElement element in mainNode.Elements()) - { - var switchExpr1 = element.Name; - switch (switchExpr1) - { - case var case3 when case3 == "name": - patch.Name = element.Value; - break; - case var case4 when case4 == "description": - patch.Description = element.Value; - break; - case var case5 when case5 == "patch": - patch.Scripts.Add(XElementToScript(element)); - break; - } - } - - if (string.IsNullOrEmpty(patch.Name)) - { - patch.Name = Path.GetFileNameWithoutExtension(fileName); - } - - return patch; } - public PatchScript XElementToScript(XElement element) + if (string.IsNullOrEmpty(patch.Name)) { - var script = new PatchScript(); - script.Script = element.Value; - foreach (XAttribute attr in element.Attributes()) + patch.Name = Path.GetFileNameWithoutExtension(fileName); + } + + return patch; + } + + public PatchScript XElementToScript(XElement element) + { + var script = new PatchScript(); + script.Script = element.Value; + foreach (XAttribute attr in element.Attributes()) + { + var switchExpr = attr.Name; + switch (switchExpr) { - var switchExpr = attr.Name; - switch (switchExpr) - { - case var @case when @case == "name": - script.Name = attr.Value; - break; - case var case1 when case1 == "description": - script.Description = attr.Value; - break; - case var case2 when case2 == "type": - script.Type = (ScriptType)Convert.ToInt32(attr.Value); - break; - case var case3 when case3 == "references": - if (!string.IsNullOrEmpty(attr.Value)) + case var @case when @case == "name": + script.Name = attr.Value; + break; + case var case1 when case1 == "description": + script.Description = attr.Value; + break; + case var case2 when case2 == "type": + script.Type = (ScriptType)Convert.ToInt32(attr.Value); + break; + case var case3 when case3 == "references": + if (!string.IsNullOrEmpty(attr.Value)) + { + foreach (var reference in attr.Value.Split(';')) { - foreach (var reference in attr.Value.Split(';')) + script.References.Add(new PatchScriptReference { - script.References.Add(new PatchScriptReference - { - Name = reference, - ReferenceType = PatchScriptReferenceType.AssemblyName - }); + Name = reference, + ReferenceType = PatchScriptReferenceType.AssemblyName + }); + } + } + + break; + } + } + + return script; + } + + public PatchScriptResult Patch(PatchScript script, PatchScriptExecuteParams @params, bool createUndoPatch = false) + { + if (script is null) + throw new ArgumentNullException(nameof(script)); + + string romfileBackup = null; + + var result = new PatchScriptResult(); + var flips = new Flips(); + + createUndoPatch &= script.AllowRevert && script.ID.HasID && flips.Enabled; + + if (createUndoPatch) + { + romfileBackup = Path.GetTempFileName(); + File.Copy(@params.RomFilePath, romfileBackup, true); + } + + switch (script.Type) + { + case ScriptType.TweakScript: + ExecuteTweakScript(script.Script, @params, @params.WindowOwner); + break; + case ScriptType.VisualBasic: + case ScriptType.CSharp: + { + var assembly = GetAssembly(script, @params.EmbeddedFiles); + if (assembly is not null) + ExecuteScript(assembly, @params); + } + break; + case ScriptType.DynamicLinkLibrary: + { + var infos = DLLFunctionInformation.Get(script); + var assemblyRaw = (MemoryStream)@params.EmbeddedFiles.GetStream(infos.PatchFileName); + var assembly = Assembly.Load(assemblyRaw.ToArray()); + assemblyRaw.Close(); + ExecuteDLLFunction(assembly, infos.ClassPath, infos.MethodName); + } + break; + case ScriptType.Armips: + RunArmips(script.Script, @params.RomFilePath, Path.GetDirectoryName(@params.ProfilePath)); + break; + case ScriptType.BPS: + case ScriptType.IPS: + { + var infos = PatchFileInformations.Get(script); + var fileToPatch = @params.EmbeddedFiles.GetLocalFilePath(infos.PatchFileName); + flips.ApplyPatch(@params.RomFilePath, fileToPatch); + } + break; + case ScriptType.PPF: + { + var infos = PatchFileInformations.Get(script); + var fileToPatch = @params.EmbeddedFiles.GetLocalFilePath(infos.PatchFileName); + var ppf = new PPF(); + ppf.ApplyPatch(@params.RomFilePath, fileToPatch); + } + break; + } + + if (createUndoPatch) + { + var ipsFile = Path.GetTempFileName(); + if (flips.CreatePatch(@params.RomFilePath, romfileBackup, ipsFile, FlipsPatchType.BPS)) + @params.RomManager?.RomConfig.PatchingConfig.TweakBackups.AddFile(GetUndoPatchFileNameOfScript(script), ipsFile); + if (File.Exists(ipsFile)) + File.Delete(ipsFile); + File.Delete(romfileBackup); + } + + General.PatchClass.UpdateChecksum(@params.RomFilePath); + + return result; + } + + public PatchCompilingResult CompileScript(PatchScript script, EmbeddedFilesContainer embeddedFiles, bool loadAssembly) + { + CompilationOptions compilationOptions; + Compilation compilation = null; + SyntaxTree syntaxTree = null; + Dictionary references = new(); + EmitResult resultEmit = null; + Assembly resultAssembly = null; + + string assemblyName = new UniquieID(UniquieIDGenerationMode.GenerateOnGet) + ".dll"; + compilationOptions = script.Type switch + { + ScriptType.VisualBasic => new VisualBasicCompilationOptions(OutputKind.DynamicallyLinkedLibrary), + ScriptType.CSharp => new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary), + _ => null + }; + + // References & SyntaxTree + if (compilationOptions != null) + { + // Collect already loaded references + foreach (var a in AssemblyLoadContext.Default.Assemblies) + { + try + { + if (File.Exists(a.Location) && !references.ContainsKey(a.Location)) + references.Add(a.Location, MetadataReference.CreateFromFile(a.Location)); + } + catch (Exception) { } + } + + // Collect additional references + foreach (var reference in script.References) + { + switch (reference.ReferenceType) + { + case PatchScriptReferenceType.AssemblyName: + { + Assembly a; + try + { + a = Assembly.Load(reference.Name); + } + catch (Exception) + { + a = null; + } + if (a != null && !string.IsNullOrEmpty(a.Location) && !references.ContainsKey(a.Location)) + references.Add(a.Location, MetadataReference.CreateFromFile(a.Location)); + } + break; + case PatchScriptReferenceType.AssemblyLocation: + { + Assembly a; + try + { + a = Assembly.LoadFrom(reference.Name); + } + catch (Exception) + { + a = null; + } + if (a != null && !string.IsNullOrEmpty(a.Location) && !references.ContainsKey(a.Location)) + references.Add(a.Location, MetadataReference.CreateFromFile(a.Location)); + } + break; + case PatchScriptReferenceType.EmbeddedFile: + { + if (!references.ContainsKey(reference.Name)) + { + using var file = embeddedFiles.GetStream(reference.Name); + if (file != null) + references.Add(reference.Name, MetadataReference.CreateFromStream(file)); } } - break; } } - return script; - } - - public PatchScriptResult Patch(PatchScript script, PatchScriptExecuteParams @params, bool createUndoPatch = false) - { - if (script is null) - throw new ArgumentNullException(nameof(script)); - - string romfileBackup = null; - - var result = new PatchScriptResult(); - var flips = new Flips(); - - createUndoPatch &= script.AllowRevert && script.ID.HasID && flips.Enabled; - - if (createUndoPatch) + // Load SyntaxTree + syntaxTree = script.Type switch { - romfileBackup = Path.GetTempFileName(); - File.Copy(@params.RomFilePath, romfileBackup, true); - } - - switch (script.Type) - { - case ScriptType.TweakScript: - ExecuteTweakScript(script.Script, @params, @params.WindowOwner); - break; - case ScriptType.VisualBasic: - case ScriptType.CSharp: - { - var assembly = GetAssembly(script, @params.EmbeddedFiles); - if (assembly is not null) - ExecuteScript(assembly, @params); - } - break; - case ScriptType.DynamicLinkLibrary: - { - var infos = DLLFunctionInformation.Get(script); - var assemblyRaw = (MemoryStream)@params.EmbeddedFiles.GetStream(infos.PatchFileName); - var assembly = Assembly.Load(assemblyRaw.ToArray()); - assemblyRaw.Close(); - ExecuteDLLFunction(assembly, infos.ClassPath, infos.MethodName); - } - break; - case ScriptType.Armips: - RunArmips(script.Script, @params.RomFilePath, Path.GetDirectoryName(@params.ProfilePath)); - break; - case ScriptType.BPS: - case ScriptType.IPS: - { - var infos = PatchFileInformations.Get(script); - var fileToPatch = @params.EmbeddedFiles.GetLocalFilePath(infos.PatchFileName); - flips.ApplyPatch(@params.RomFilePath, fileToPatch); - } - break; - case ScriptType.PPF: - { - var infos = PatchFileInformations.Get(script); - var fileToPatch = @params.EmbeddedFiles.GetLocalFilePath(infos.PatchFileName); - var ppf = new PPF(); - ppf.ApplyPatch(@params.RomFilePath, fileToPatch); - } - break; - } - - if (createUndoPatch) - { - var ipsFile = Path.GetTempFileName(); - if (flips.CreatePatch(@params.RomFilePath, romfileBackup, ipsFile, FlipsPatchType.BPS)) - @params.RomManager?.RomConfig.PatchingConfig.TweakBackups.AddFile(GetUndoPatchFileNameOfScript(script), ipsFile); - if (File.Exists(ipsFile)) - File.Delete(ipsFile); - File.Delete(romfileBackup); - } - - General.PatchClass.UpdateChecksum(@params.RomFilePath); - - return result; - } - - public PatchCompilingResult CompileScript(PatchScript script, EmbeddedFilesContainer embeddedFiles, bool loadAssembly) - { - CompilationOptions compilationOptions; - Compilation compilation = null; - SyntaxTree syntaxTree = null; - Dictionary references = new(); - EmitResult resultEmit = null; - Assembly resultAssembly = null; - - string assemblyName = new UniquieID(UniquieIDGenerationMode.GenerateOnGet) + ".dll"; - compilationOptions = script.Type switch - { - ScriptType.VisualBasic => new VisualBasicCompilationOptions(OutputKind.DynamicallyLinkedLibrary), - ScriptType.CSharp => new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary), + ScriptType.VisualBasic => VisualBasicSyntaxTree.ParseText(script.Script, new VisualBasicParseOptions(VBLanguageVersion.Latest)), + ScriptType.CSharp => CSharpSyntaxTree.ParseText(script.Script, new CSharpParseOptions(CSLanguageVersion.Latest)), _ => null }; - - // References & SyntaxTree - if (compilationOptions != null) - { - // Collect already loaded references - foreach (var a in AssemblyLoadContext.Default.Assemblies) - { - try - { - if (File.Exists(a.Location) && !references.ContainsKey(a.Location)) - references.Add(a.Location, MetadataReference.CreateFromFile(a.Location)); - } - catch(Exception) { } - } - - // Collect additional references - foreach (var reference in script.References) - { - switch (reference.ReferenceType) - { - case PatchScriptReferenceType.AssemblyName: - { - Assembly a; - try - { - a = Assembly.Load(reference.Name); - } - catch (Exception) - { - a = null; - } - if (a != null && !string.IsNullOrEmpty(a.Location) && !references.ContainsKey(a.Location)) - references.Add(a.Location, MetadataReference.CreateFromFile(a.Location)); - } - break; - case PatchScriptReferenceType.AssemblyLocation: - { - Assembly a; - try - { - a = Assembly.LoadFrom(reference.Name); - } - catch (Exception) - { - a = null; - } - if (a != null && !string.IsNullOrEmpty(a.Location) && !references.ContainsKey(a.Location)) - references.Add(a.Location, MetadataReference.CreateFromFile(a.Location)); - } - break; - case PatchScriptReferenceType.EmbeddedFile: - { - if (!references.ContainsKey(reference.Name)) - { - using var file = embeddedFiles.GetStream(reference.Name); - if (file != null) - references.Add(reference.Name, MetadataReference.CreateFromStream(file)); - } - } - break; - } - } - - // Load SyntaxTree - syntaxTree = script.Type switch - { - ScriptType.VisualBasic => VisualBasicSyntaxTree.ParseText(script.Script, new VisualBasicParseOptions(VBLanguageVersion.Latest)), - ScriptType.CSharp => CSharpSyntaxTree.ParseText(script.Script, new CSharpParseOptions(CSLanguageVersion.Latest)), - _ => null - }; - } - - if (compilationOptions != null && syntaxTree != null) - { - compilation = script.Type switch - { - ScriptType.VisualBasic => VisualBasicCompilation.Create(assemblyName, - options: (VisualBasicCompilationOptions)compilationOptions, - syntaxTrees: new[] { syntaxTree }, - references: references.Values - ), - ScriptType.CSharp => CSharpCompilation.Create(assemblyName, - options: (CSharpCompilationOptions)compilationOptions, - syntaxTrees: new[] { syntaxTree }, - references: references.Values - ), - _ => null - }; - } - - if (compilation != null) - { - using var ms = new MemoryStream(); - resultEmit = compilation.Emit(ms); - - if (resultEmit.Success && loadAssembly) - { - ms.Position = 0; - resultAssembly = AssemblyLoadContext.Default.LoadFromStream(ms); - } - } - - return new PatchCompilingResult(resultEmit, resultAssembly); } - public Assembly GetAssembly(PatchScript script, EmbeddedFilesContainer embeddedFiles) + if (compilationOptions != null && syntaxTree != null) { - var res = CompileScript(script, embeddedFiles, true); - if (res.EmitResult.Success) - return res.OutputAssembly; - else - throw new SyntaxErrorException("Error hat compiling Script. Either there are syntax errors or there are missing some references."); + compilation = script.Type switch + { + ScriptType.VisualBasic => VisualBasicCompilation.Create(assemblyName, + options: (VisualBasicCompilationOptions)compilationOptions, + syntaxTrees: new[] { syntaxTree }, + references: references.Values + ), + ScriptType.CSharp => CSharpCompilation.Create(assemblyName, + options: (CSharpCompilationOptions)compilationOptions, + syntaxTrees: new[] { syntaxTree }, + references: references.Values + ), + _ => null + }; } - public void ExecuteDLLFunction(Assembly assembly, string classPath, string methodName) + if (compilation != null) { - var t = assembly.GetType(classPath, false); - if (t is not null) + using var ms = new MemoryStream(); + resultEmit = compilation.Emit(ms); + + if (resultEmit.Success && loadAssembly) { - var m = t.GetMethod(methodName); - if (m is not null) - m.Invoke(null, null); + ms.Position = 0; + resultAssembly = AssemblyLoadContext.Default.LoadFromStream(ms); } } - public void ExecuteScript(Assembly assembly, PatchScriptExecuteParams @params) + return new PatchCompilingResult(resultEmit, resultAssembly); + } + + public Assembly GetAssembly(PatchScript script, EmbeddedFilesContainer embeddedFiles) + { + var res = CompileScript(script, embeddedFiles, true); + if (res.EmitResult.Success) + return res.OutputAssembly; + else + throw new SyntaxErrorException("Error hat compiling Script. Either there are syntax errors or there are missing some references."); + } + + public void ExecuteDLLFunction(Assembly assembly, string classPath, string methodName) + { + var t = assembly.GetType(classPath, false); + if (t is not null) { - var main = assembly.GetType("Script")?.GetMethod("Main", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); - FileStream fs = null; - var param = new object[] { null }; - var paraminfo = main.GetParameters(); - - if (paraminfo.Length == 1 && paraminfo[0].ParameterType == typeof(Stream) && !string.IsNullOrEmpty(@params.RomFilePath)) - { - fs = new FileStream(@params.RomFilePath, FileMode.Open, FileAccess.ReadWrite); - param = new object[] { fs }; - } - else if (paraminfo.Length == 1 && paraminfo[0].ParameterType == typeof(string)) - param = new object[] { @params.RomFilePath }; - else if (paraminfo.Length == 1 && paraminfo[0].ParameterType == typeof(IReadOnlyDictionary)) - param = new object[] { @params.OtherParameters }; - else if (paraminfo.Length == 1 && paraminfo[0].ParameterType == typeof(PatchScriptExecuteParams)) - param = new object[] { @params }; - - main?.Invoke(null, param); - - fs?.Close(); + var m = t.GetMethod(methodName); + if (m is not null) + m.Invoke(null, null); } + } - private void ExecuteTweakScript(string script, PatchScriptExecuteParams @params, IWin32Window owner) + public void ExecuteScript(Assembly assembly, PatchScriptExecuteParams @params) + { + var main = assembly.GetType("Script")?.GetMethod("Main", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); + FileStream fs = null; + var param = new object[] { null }; + var paraminfo = main.GetParameters(); + + if (paraminfo.Length == 1 && paraminfo[0].ParameterType == typeof(Stream) && !string.IsNullOrEmpty(@params.RomFilePath)) { - var stream = new FileStream(@params.RomFilePath, FileMode.Open, FileAccess.ReadWrite); - var bw = new BinaryWriter(stream); - var br = new BinaryReader(stream); - var reader = new StringReader(script); - while (reader.Peek() > -1) + fs = new FileStream(@params.RomFilePath, FileMode.Open, FileAccess.ReadWrite); + param = new object[] { fs }; + } + else if (paraminfo.Length == 1 && paraminfo[0].ParameterType == typeof(string)) + param = new object[] { @params.RomFilePath }; + else if (paraminfo.Length == 1 && paraminfo[0].ParameterType == typeof(IReadOnlyDictionary)) + param = new object[] { @params.OtherParameters }; + else if (paraminfo.Length == 1 && paraminfo[0].ParameterType == typeof(PatchScriptExecuteParams)) + param = new object[] { @params }; + + main?.Invoke(null, param); + + fs?.Close(); + } + + private void ExecuteTweakScript(string script, PatchScriptExecuteParams @params, IWin32Window owner) + { + var stream = new FileStream(@params.RomFilePath, FileMode.Open, FileAccess.ReadWrite); + var bw = new BinaryWriter(stream); + var br = new BinaryReader(stream); + var reader = new StringReader(script); + while (reader.Peek() > -1) + { + string line = reader.ReadLine().Trim().ToLower(); + int commentStart = line.IndexOf("//"); + if (commentStart > -1) { - string line = reader.ReadLine().Trim().ToLower(); - int commentStart = line.IndexOf("//"); - if (commentStart > -1) + line = line.Substring(0, commentStart); + } + + if (string.IsNullOrEmpty(line.Trim())) + { + continue; + } + + int nextDP = line.IndexOf(":"); + string body = line.Substring(nextDP + 1).Trim(); + if (nextDP > -1) + { + string addr; + addr = line.Substring(0, nextDP); + stream.Position = Convert.ToInt32(addr, 16); + } + + int nextKlammer = body.IndexOf('['); + while (nextKlammer > -1) + { + int endKl = body.IndexOf(']', nextKlammer + 1); + string str = body.Substring(nextKlammer, endKl - nextKlammer + 1); + string newVal = ""; + switch (true) { - line = line.Substring(0, commentStart); - } - - if (string.IsNullOrEmpty(line.Trim())) - { - continue; - } - - int nextDP = line.IndexOf(":"); - string body = line.Substring(nextDP + 1).Trim(); - if (nextDP > -1) - { - string addr; - addr = line.Substring(0, nextDP); - stream.Position = Convert.ToInt32(addr, 16); - } - - int nextKlammer = body.IndexOf('['); - while (nextKlammer > -1) - { - int endKl = body.IndexOf(']', nextKlammer + 1); - string str = body.Substring(nextKlammer, endKl - nextKlammer + 1); - string newVal = ""; - switch (true) - { - case object _ when str.StartsWith("["): - var parts = str.Substring(1, str.Length - 2).Split(','); // body.Substring(1, body.Length - 1).Split(",") - if (parts.Count() > 0) - { - var switchExpr1 = parts[0].Trim(); - switch (switchExpr1) - { - case "copy": - { - if (parts.Count() > 1) - { - int startAddr = Convert.ToInt32(parts[1].Trim(), 16); - int endAddr = parts.Length > 2 ? Convert.ToInt32(parts[2].Trim(), 16) : startAddr + 1; - int length = endAddr - startAddr; - int lastPos = Convert.ToInt32(stream.Position); - body = ""; - stream.Position = startAddr; - for (int i = 1, loopTo = length; i <= loopTo; i++) - body += " " + br.ReadByte().ToString("X2"); - stream.Position = lastPos; - } - - break; - } - - case "fill": - { - if (parts.Count() > 2) - { - byte value = Convert.ToByte(parts[1].Trim(), 16); - string valueString = value.ToString("X2"); - int length = Convert.ToInt32(parts[2].Trim(), 16); - body = ""; - for (int i = 1, loopTo1 = length; i <= loopTo1; i++) - body += " " + valueString; - } - - break; - } - - default: - { - var inputType = InputValueType.Byte; - var switchExpr2 = parts[0].Trim(); - switch (switchExpr2) - { - case "8": - inputType = InputValueType.Byte; - break; - case "16": - inputType = InputValueType.UInt16; - break; - case "32": - inputType = InputValueType.UInt32; - break; - case "half": - inputType = InputValueType.Single; - break; - case "string": - inputType = InputValueType.String; - break; - case "sequence": - inputType = InputValueType.Sequence; - break; - case "level": - inputType = InputValueType.LevelID; - break; - } - - var titel = parts.ElementAtOrDefault(1)?.Trim()?.Trim('"', '[', ']'); - var processingEventArgs = new PatchScriptManagerProcessingInputValueEventArgs(inputType, titel, @params.RomManager, owner); - ProcessingInputValue?.Invoke(this, processingEventArgs); - - if (processingEventArgs.SettedValue) - { - if (inputType == InputValueType.String) - { - byte[] barr = System.Text.Encoding.ASCII.GetBytes((string)processingEventArgs.ReturnValue); - foreach (byte b in barr) - newVal += b.ToString("X2"); - } - else - { - string barr = string.Empty; - switch (inputType) - { - case InputValueType.Byte: - case InputValueType.Sequence: - barr = Convert.ToByte(processingEventArgs.ReturnValue).ToString("X2"); - break; - case InputValueType.UInt16: - case InputValueType.LevelID: - barr = Convert.ToUInt16(processingEventArgs.ReturnValue).ToString("X4"); - break; - case InputValueType.Single: - barr = Data.System.SwapInts.SwapHalf(Convert.ToSingle(processingEventArgs.ReturnValue)).ToString("X4"); - break; - case InputValueType.UInt32: - barr = Convert.ToUInt32(processingEventArgs.ReturnValue).ToString("X8"); - break; - } - - for (int i = 0, loopTo2 = barr.Length - 1; i <= loopTo2; i += 2) - newVal += " " + barr.Substring(i, 2); - } - } - - body = body.Replace(str, newVal); - break; - } - } - break; - } - break; - default: - continue; - } - - nextKlammer = body.IndexOf('[', nextKlammer + 1); - } - - if (!string.IsNullOrEmpty(body)) - { - foreach (string str in body.Split(' ')) - { - if (!string.IsNullOrWhiteSpace(str)) + case object _ when str.StartsWith("["): + var parts = str.Substring(1, str.Length - 2).Split(','); // body.Substring(1, body.Length - 1).Split(",") + if (parts.Count() > 0) { - byte value = Convert.ToByte(str, 16); - bw.Write(value); + var switchExpr1 = parts[0].Trim(); + switch (switchExpr1) + { + case "copy": + { + if (parts.Count() > 1) + { + int startAddr = Convert.ToInt32(parts[1].Trim(), 16); + int endAddr = parts.Length > 2 ? Convert.ToInt32(parts[2].Trim(), 16) : startAddr + 1; + int length = endAddr - startAddr; + int lastPos = Convert.ToInt32(stream.Position); + body = ""; + stream.Position = startAddr; + for (int i = 1, loopTo = length; i <= loopTo; i++) + body += " " + br.ReadByte().ToString("X2"); + stream.Position = lastPos; + } + + break; + } + + case "fill": + { + if (parts.Count() > 2) + { + byte value = Convert.ToByte(parts[1].Trim(), 16); + string valueString = value.ToString("X2"); + int length = Convert.ToInt32(parts[2].Trim(), 16); + body = ""; + for (int i = 1, loopTo1 = length; i <= loopTo1; i++) + body += " " + valueString; + } + + break; + } + + default: + { + var inputType = InputValueType.Byte; + var switchExpr2 = parts[0].Trim(); + switch (switchExpr2) + { + case "8": + inputType = InputValueType.Byte; + break; + case "16": + inputType = InputValueType.UInt16; + break; + case "32": + inputType = InputValueType.UInt32; + break; + case "half": + inputType = InputValueType.Single; + break; + case "string": + inputType = InputValueType.String; + break; + case "sequence": + inputType = InputValueType.Sequence; + break; + case "level": + inputType = InputValueType.LevelID; + break; + } + + var titel = parts.ElementAtOrDefault(1)?.Trim()?.Trim('"', '[', ']'); + var processingEventArgs = new PatchScriptManagerProcessingInputValueEventArgs(inputType, titel, @params.RomManager, owner); + ProcessingInputValue?.Invoke(this, processingEventArgs); + + if (processingEventArgs.SettedValue) + { + if (inputType == InputValueType.String) + { + byte[] barr = System.Text.Encoding.ASCII.GetBytes((string)processingEventArgs.ReturnValue); + foreach (byte b in barr) + newVal += b.ToString("X2"); + } + else + { + string barr = string.Empty; + switch (inputType) + { + case InputValueType.Byte: + case InputValueType.Sequence: + barr = Convert.ToByte(processingEventArgs.ReturnValue).ToString("X2"); + break; + case InputValueType.UInt16: + case InputValueType.LevelID: + barr = Convert.ToUInt16(processingEventArgs.ReturnValue).ToString("X4"); + break; + case InputValueType.Single: + barr = Data.System.SwapInts.SwapHalf(Convert.ToSingle(processingEventArgs.ReturnValue)).ToString("X4"); + break; + case InputValueType.UInt32: + barr = Convert.ToUInt32(processingEventArgs.ReturnValue).ToString("X8"); + break; + } + + for (int i = 0, loopTo2 = barr.Length - 1; i <= loopTo2; i += 2) + newVal += " " + barr.Substring(i, 2); + } + } + + body = body.Replace(str, newVal); + break; + } + } + break; } + break; + default: + continue; + } + + nextKlammer = body.IndexOf('[', nextKlammer + 1); + } + + if (!string.IsNullOrEmpty(body)) + { + foreach (string str in body.Split(' ')) + { + if (!string.IsNullOrWhiteSpace(str)) + { + byte value = Convert.ToByte(str, 16); + bw.Write(value); } } } - - reader.Close(); - stream.Close(); } - private static void RunArmips(string script, string filePath, string rootPath) - { - string createText = + reader.Close(); + stream.Close(); + } + + private static void RunArmips(string script, string filePath, string rootPath) + { + string createText = $@".Open ""{filePath}"", 0 .n64 {script} .Close"; - string tmpAsmFile = Path.GetTempFileName(); - File.WriteAllText(tmpAsmFile, createText); - var p = new Process(); - p.StartInfo.FileName = Path.Combine(General.MyFilePaths["armips.exe"]); - p.StartInfo.Arguments = $"-root \"{rootPath}\" \"{tmpAsmFile}\""; - p.StartInfo.UseShellExecute = false; - p.StartInfo.CreateNoWindow = true; - p.Start(); - while (!p.HasExited) - { - } - - File.Delete(tmpAsmFile); - } - - public static byte[] ConvertAsmToBytes(string script) + string tmpAsmFile = Path.GetTempFileName(); + File.WriteAllText(tmpAsmFile, createText); + var p = new Process(); + p.StartInfo.FileName = Path.Combine(General.MyFilePaths["armips.exe"]); + p.StartInfo.Arguments = $"-root \"{rootPath}\" \"{tmpAsmFile}\""; + p.StartInfo.UseShellExecute = false; + p.StartInfo.CreateNoWindow = true; + p.Start(); + while (!p.HasExited) { - string tmpBinFile = Path.GetTempFileName(); - RunArmips(script, tmpBinFile, Path.GetDirectoryName(tmpBinFile)); - var bytes = File.ReadAllBytes(tmpBinFile); - File.Delete(tmpBinFile); - return bytes; } - public static string GetUndoPatchFileNameOfScript(PatchScript script) - { - return $"patch-undo.{script.ID}"; - } + File.Delete(tmpAsmFile); + } - public static bool HasUndoPatch(PatchScript script, RomManager rommgr) - { - var fileName = GetUndoPatchFileNameOfScript(script); - return rommgr.RomConfig.PatchingConfig.TweakBackups.HasFile(fileName); - } + public static byte[] ConvertAsmToBytes(string script) + { + string tmpBinFile = Path.GetTempFileName(); + RunArmips(script, tmpBinFile, Path.GetDirectoryName(tmpBinFile)); + var bytes = File.ReadAllBytes(tmpBinFile); + File.Delete(tmpBinFile); + return bytes; + } - public static void ApplyUndoPatch(PatchScript script, RomManager rommgr, bool removeFileAfterPatching = true) - { - var fileName = GetUndoPatchFileNameOfScript(script); - var filePath = rommgr.RomConfig.PatchingConfig.TweakBackups.GetLocalFilePath(fileName); + public static string GetUndoPatchFileNameOfScript(PatchScript script) + { + return $"patch-undo.{script.ID}"; + } - var flips = new Flips(); - flips.ApplyPatch(rommgr.RomFile, filePath); + public static bool HasUndoPatch(PatchScript script, RomManager rommgr) + { + var fileName = GetUndoPatchFileNameOfScript(script); + return rommgr.RomConfig.PatchingConfig.TweakBackups.HasFile(fileName); + } - if (removeFileAfterPatching) - rommgr.RomConfig.PatchingConfig.TweakBackups.RemoveFile(fileName); + public static void ApplyUndoPatch(PatchScript script, RomManager rommgr, bool removeFileAfterPatching = true) + { + var fileName = GetUndoPatchFileNameOfScript(script); + var filePath = rommgr.RomConfig.PatchingConfig.TweakBackups.GetLocalFilePath(fileName); - File.Delete(filePath); + var flips = new Flips(); + flips.ApplyPatch(rommgr.RomFile, filePath); - General.PatchClass.UpdateChecksum(rommgr.RomFile); - } + if (removeFileAfterPatching) + rommgr.RomConfig.PatchingConfig.TweakBackups.RemoveFile(fileName); + + File.Delete(filePath); + + General.PatchClass.UpdateChecksum(rommgr.RomFile); } } \ No newline at end of file diff --git a/SM64Lib/Patching/PatchScriptManagerProcessingInputValueEventArgs.cs b/SM64Lib/Patching/PatchScriptManagerProcessingInputValueEventArgs.cs index 65f975d..9dcf305 100644 --- a/SM64Lib/Patching/PatchScriptManagerProcessingInputValueEventArgs.cs +++ b/SM64Lib/Patching/PatchScriptManagerProcessingInputValueEventArgs.cs @@ -1,28 +1,22 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows.Forms; +using System.Windows.Forms; -namespace SM64Lib.Patching +namespace SM64Lib.Patching; + +public class PatchScriptManagerProcessingInputValueEventArgs { - public class PatchScriptManagerProcessingInputValueEventArgs - { - public InputValueType ValueType { get; private set; } - public string Titel { get; private set; } - public RomManager RomManager { get; private set; } - public IWin32Window Owner { get; private set; } - public object ReturnValue { get; set; } - public bool SettedValue { get; set; } + public InputValueType ValueType { get; private set; } + public string Titel { get; private set; } + public RomManager RomManager { get; private set; } + public IWin32Window Owner { get; private set; } + public object ReturnValue { get; set; } + public bool SettedValue { get; set; } - internal PatchScriptManagerProcessingInputValueEventArgs(InputValueType valueType, string titel, RomManager romManager, IWin32Window owner) - { - ValueType = valueType; - Titel = titel; - RomManager = romManager; - Owner = owner; - SettedValue = false; - } + internal PatchScriptManagerProcessingInputValueEventArgs(InputValueType valueType, string titel, RomManager romManager, IWin32Window owner) + { + ValueType = valueType; + Titel = titel; + RomManager = romManager; + Owner = owner; + SettedValue = false; } } diff --git a/SM64Lib/Patching/PatchScriptReference.cs b/SM64Lib/Patching/PatchScriptReference.cs index bb10a47..ecef3fc 100644 --- a/SM64Lib/Patching/PatchScriptReference.cs +++ b/SM64Lib/Patching/PatchScriptReference.cs @@ -1,15 +1,7 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Text; -using System.Threading.Tasks; +namespace SM64Lib.Patching; -namespace SM64Lib.Patching +public class PatchScriptReference { - public class PatchScriptReference - { - public string Name { get; set; } - public PatchScriptReferenceType ReferenceType { get; set; } - } + public string Name { get; set; } + public PatchScriptReferenceType ReferenceType { get; set; } } diff --git a/SM64Lib/Patching/PatchScriptReferenceType.cs b/SM64Lib/Patching/PatchScriptReferenceType.cs index d955c11..169fc55 100644 --- a/SM64Lib/Patching/PatchScriptReferenceType.cs +++ b/SM64Lib/Patching/PatchScriptReferenceType.cs @@ -1,15 +1,8 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +namespace SM64Lib.Patching; -namespace SM64Lib.Patching +public enum PatchScriptReferenceType { - public enum PatchScriptReferenceType - { - AssemblyName, - AssemblyLocation, - EmbeddedFile - } + AssemblyName, + AssemblyLocation, + EmbeddedFile } diff --git a/SM64Lib/Patching/PatchScriptReferences.cs b/SM64Lib/Patching/PatchScriptReferences.cs index 894cc90..ba3ca58 100644 --- a/SM64Lib/Patching/PatchScriptReferences.cs +++ b/SM64Lib/Patching/PatchScriptReferences.cs @@ -1,12 +1,7 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Collections.Generic; -namespace SM64Lib.Patching +namespace SM64Lib.Patching; + +public class PatchScriptReferences : List { - public class PatchScriptReferences : List - { - } } diff --git a/SM64Lib/Patching/PatchScriptResult.cs b/SM64Lib/Patching/PatchScriptResult.cs index 0bd3fdf..c240a27 100644 --- a/SM64Lib/Patching/PatchScriptResult.cs +++ b/SM64Lib/Patching/PatchScriptResult.cs @@ -1,12 +1,5 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +namespace SM64Lib.Patching; -namespace SM64Lib.Patching +public class PatchScriptResult { - public class PatchScriptResult - { - } } diff --git a/SM64Lib/Properties/AssemblyInfo.cs b/SM64Lib/Properties/AssemblyInfo.cs index 440f5b5..96acf41 100644 --- a/SM64Lib/Properties/AssemblyInfo.cs +++ b/SM64Lib/Properties/AssemblyInfo.cs @@ -1,5 +1,4 @@ using global::System; -using global::System.Reflection; using global::System.Runtime.InteropServices; [assembly: ComVisible(false)] diff --git a/SM64Lib/RecalcChecksumBehavior.cs b/SM64Lib/RecalcChecksumBehavior.cs index ee008d7..e506286 100644 --- a/SM64Lib/RecalcChecksumBehavior.cs +++ b/SM64Lib/RecalcChecksumBehavior.cs @@ -1,15 +1,8 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +namespace SM64Lib; -namespace SM64Lib +public enum RecalcChecksumBehavior { - public enum RecalcChecksumBehavior - { - Never, - Always, - Auto - } + Never, + Always, + Auto } diff --git a/SM64Lib/RomManager.cs b/SM64Lib/RomManager.cs index 790571b..40bf583 100644 --- a/SM64Lib/RomManager.cs +++ b/SM64Lib/RomManager.cs @@ -1,13 +1,4 @@ -using System; -using System.Collections.Generic; -using global::System.ComponentModel; -using System.Data; -using System.Diagnostics; -using global::System.IO; -using System.Linq; -using global::System.Text; -using Microsoft.VisualBasic.CompilerServices; -using global::Newtonsoft.Json.Linq; +using global::Newtonsoft.Json.Linq; using global::SM64Lib.Configuration; using global::SM64Lib.Data; using global::SM64Lib.Data.System; @@ -16,1227 +7,1234 @@ using global::SM64Lib.Levels; using global::SM64Lib.Music; using global::SM64Lib.Objects.ModelBanks; using global::SM64Lib.SegmentedBanking; -using SM64Lib.Behaviors; -using SM64Lib.Objects.ObjectBanks; +using global::System.ComponentModel; +using global::System.IO; +using global::System.Text; using SM64Lib.ASM; +using SM64Lib.Behaviors; using SM64Lib.Exceptions; +using SM64Lib.Objects.ObjectBanks; using SM64Lib.Patching; +using System; +using System.Collections.Generic; +using System.Data; +using System.Diagnostics; +using System.Linq; -namespace SM64Lib +namespace SM64Lib; + +public class RomManager { - public class RomManager + + // E v e n t s + + public event BeginLoadingRomEventHandler BeginLoadingRom; + public delegate void BeginLoadingRomEventHandler(RomManager sender, EventArgs e); + + public event PrepairingRomEventHandler PrepairingRom; + public delegate void PrepairingRomEventHandler(RomManager sender, EventArgs e); + + public event AfterRomLoadedEventHandler AfterRomLoaded; + public delegate void AfterRomLoadedEventHandler(RomManager sender, EventArgs e); + + public event AfterLevelsLoadedEventHandler AfterLevelsLoaded; + public delegate void AfterLevelsLoadedEventHandler(RomManager sender, EventArgs e); + + public event BeginLoadingMusicEventHandler BeginLoadingMusic; + public delegate void BeginLoadingMusicEventHandler(RomManager sender, EventArgs e); + + public event AfterMusicLoadedEventHandler AfterMusicLoaded; + public delegate void AfterMusicLoadedEventHandler(RomManager sender, EventArgs e); + + public event BeforeRomSaveEventHandler BeforeRomSave; + public delegate void BeforeRomSaveEventHandler(RomManager sender, CancelEventArgs e); + + public event AfterRomSaveEventHandler AfterRomSave; + public delegate void AfterRomSaveEventHandler(RomManager sender, EventArgs e); + + public event WritingNewProgramVersionEventHandler WritingNewProgramVersion; + public delegate void WritingNewProgramVersionEventHandler(RomManager sender, RomVersionEventArgs e); + + public event GetTextProfileInfoEventHandler GettingDefaultTextProfileInfo; + public delegate void GetTextProfileInfoEventHandler(RomManager rommgr, GetTextProfileInfoEventArgs e); + + // C o n s t a n t s + + public const string SUPER_MARIO_64_U_MD5HASH = "20b854b239203baf6c961b850a4a51a2"; + + // F i e l d s + + private readonly Dictionary segBankList = new Dictionary(); + private readonly Dictionary> areaSegBankList = new Dictionary>(); + private Dictionary dicUpdatePatches = new Dictionary(); + private RomVersion myProgramVersion = new RomVersion(); + private readonly List levelIDsToReset = new List(); + private readonly List myTextGroups = new List(); + private string myGameName = null; + private bool programVersion_loadedVersion = false; + + // P r o p e r t i e s + + public LevelInfoDataTabelList LevelInfoData { get; private set; } = new LevelInfoDataTabelList(); + public LevelList Levels { get; private set; } = new LevelList(); + public string RomFile { get; set; } = string.Empty; + public bool IsSM64EditorMode { get; private set; } = false; + public MusicList MusicList { get; private set; } = new MusicList(); + public CustomModelBank GlobalModelBank { get; private set; } = new CustomModelBank(); + public CustomAsmBank GlobalCustomAsmBank { get; private set; } = null; + public BehaviorBank GlobalBehaviorBank { get; private set; } = null; + public ILevelManager LevelManager { get; private set; } + public RomConfig RomConfig { get; private set; } + public bool IsNewROM { get; private set; } = false; + public CustomObjectCollection CustomObjects { get => RomConfig.GlobalObjectBank; } + public Text.TextGroup[] TextGroups { get => myTextGroups.ToArray(); } + + /// + /// Gets or sets the lastly used program version for this ROM. + /// + /// + public RomVersion ProgramVersion { - - // E v e n t s - - public event BeginLoadingRomEventHandler BeginLoadingRom; - public delegate void BeginLoadingRomEventHandler(RomManager sender, EventArgs e); - - public event PrepairingRomEventHandler PrepairingRom; - public delegate void PrepairingRomEventHandler(RomManager sender, EventArgs e); - - public event AfterRomLoadedEventHandler AfterRomLoaded; - public delegate void AfterRomLoadedEventHandler(RomManager sender, EventArgs e); - - public event AfterLevelsLoadedEventHandler AfterLevelsLoaded; - public delegate void AfterLevelsLoadedEventHandler(RomManager sender, EventArgs e); - - public event BeginLoadingMusicEventHandler BeginLoadingMusic; - public delegate void BeginLoadingMusicEventHandler(RomManager sender, EventArgs e); - - public event AfterMusicLoadedEventHandler AfterMusicLoaded; - public delegate void AfterMusicLoadedEventHandler(RomManager sender, EventArgs e); - - public event BeforeRomSaveEventHandler BeforeRomSave; - public delegate void BeforeRomSaveEventHandler(RomManager sender, CancelEventArgs e); - - public event AfterRomSaveEventHandler AfterRomSave; - public delegate void AfterRomSaveEventHandler(RomManager sender, EventArgs e); - - public event WritingNewProgramVersionEventHandler WritingNewProgramVersion; - public delegate void WritingNewProgramVersionEventHandler(RomManager sender, RomVersionEventArgs e); - - public event GetTextProfileInfoEventHandler GettingDefaultTextProfileInfo; - public delegate void GetTextProfileInfoEventHandler(RomManager rommgr, GetTextProfileInfoEventArgs e); - - // C o n s t a n t s - - public const string SUPER_MARIO_64_U_MD5HASH = "20b854b239203baf6c961b850a4a51a2"; - - // F i e l d s - - private readonly Dictionary segBankList = new Dictionary(); - private readonly Dictionary> areaSegBankList = new Dictionary>(); - private Dictionary dicUpdatePatches = new Dictionary(); - private RomVersion myProgramVersion = new RomVersion(); - private readonly List levelIDsToReset = new List(); - private readonly List myTextGroups = new List(); - private string myGameName = null; - private bool programVersion_loadedVersion = false; - - // P r o p e r t i e s - - public LevelInfoDataTabelList LevelInfoData { get; private set; } = new LevelInfoDataTabelList(); - public LevelList Levels { get; private set; } = new LevelList(); - public string RomFile { get; set; } = string.Empty; - public bool IsSM64EditorMode { get; private set; } = false; - public MusicList MusicList { get; private set; } = new MusicList(); - public CustomModelBank GlobalModelBank { get; private set; } = new CustomModelBank(); - public CustomAsmBank GlobalCustomAsmBank { get; private set; } = null; - public BehaviorBank GlobalBehaviorBank { get; private set; } = null; - public ILevelManager LevelManager { get; private set; } - public RomConfig RomConfig { get; private set; } - public bool IsNewROM { get; private set; } = false; - public CustomObjectCollection CustomObjects { get => RomConfig.GlobalObjectBank; } - public Text.TextGroup[] TextGroups { get => myTextGroups.ToArray(); } - - /// - /// Gets or sets the lastly used program version for this ROM. - /// - /// - public RomVersion ProgramVersion + get { - get + RomVersion ver; + if (!programVersion_loadedVersion) { - RomVersion ver; - if (!programVersion_loadedVersion) + if (IsNewROM) { - if (IsNewROM) - { - var romVerEventArgs = new RomVersionEventArgs(myProgramVersion); - WritingNewProgramVersion?.Invoke(this, romVerEventArgs); - myProgramVersion = romVerEventArgs.RomVersion; - ver = myProgramVersion; - } - else - { - ver = LoadVersion(); - } - programVersion_loadedVersion = true; + var romVerEventArgs = new RomVersionEventArgs(myProgramVersion); + WritingNewProgramVersion?.Invoke(this, romVerEventArgs); + myProgramVersion = romVerEventArgs.RomVersion; + ver = myProgramVersion; } else { - ver = myProgramVersion; + ver = LoadVersion(); } - - return ver; + programVersion_loadedVersion = true; } - - set + else { - myProgramVersion = value; + ver = myProgramVersion; } + + return ver; } - /// - /// Gets if the ROM has unsaved chnages and need to be saved. - /// - /// - public bool NeedToSave + set { - get + myProgramVersion = value; + } + } + + /// + /// Gets if the ROM has unsaved chnages and need to be saved. + /// + /// + public bool NeedToSave + { + get + { + return MusicList.NeedToSave || myTextGroups.Where(n => n is not null && n.NeedToSave).Count() > 0 || levelIDsToReset.Any() || Levels.NeedToSave; + } + } + + /// + /// Gets if the current ROM has an user created global object bank. + /// + /// + public bool HasGlobalObjectBank { get => GlobalModelBank is object; } + + // C o n s t r u c t o r s + + /// + /// Creates a new instance with input ROM. + /// + /// The ROM that will be opened. + public RomManager(string FileName) : this(FileName, new LevelManager()) + { + } + + /// + /// Creates a new instance with input ROM. + /// + /// The ROM that will be opened. + /// The ROM that will be opened. + public RomManager(string FileName, ILevelManager levelManager) + { + RomManagerInstances.RegisterRomManager(this); + + CustomModelConfig.RequestModel += CustomModelConfig_RequestModel; + BehaviorConfig.RequestBehavior += BehaviorConfig_RequestBehavior; + CustomAsmAreaConfig.RequestCustomAsmArea += CustomAsmAreaConfig_RequestCustomAsmArea; + + RomFile = FileName; + LevelManager = levelManager; + string levelTableFile = General.MyFilePaths["Level Tabel.json"]; + if (File.Exists(levelTableFile)) + { + LevelInfoData.ReadFromFile(levelTableFile); + } + + SetSegBank(0x0, 0, Convert.ToInt32(new FileInfo(FileName).Length)); // Bank 0 means the whole ROM. + SetSegBank(0x15, 0x2ABCA0, 0x2AC6B0); + // SetSegBank(&H2, &H108A40, &H114750) + SetSegBank(0x2, 0x803156, 0); // Text Table?? + LoadRomConfig(); + LoadDictionaryUpdatePatches(); + } + + ~RomManager() + { + RomManagerInstances.UnregisterRomManager(this); + } + + // O t h e r E v e n t s + + private void CustomAsmAreaConfig_RequestCustomAsmArea(CustomAsmAreaConfig config, CustomAsmAreaConfig.RequestCustomAsmAreaEventArgs request) + { + if (request.CustomAsmArea == null) + { + foreach (var area in GlobalCustomAsmBank.Areas) { - return MusicList.NeedToSave || myTextGroups.Where(n => n is not null && n.NeedToSave).Count() > 0 || levelIDsToReset.Any() || Levels.NeedToSave; + if (request.CustomAsmArea == null && area.Config == config) + request.CustomAsmArea = area; } } + } - /// - /// Gets if the current ROM has an user created global object bank. - /// - /// - public bool HasGlobalObjectBank { get => GlobalModelBank is object; } - - // C o n s t r u c t o r s - - /// - /// Creates a new instance with input ROM. - /// - /// The ROM that will be opened. - public RomManager(string FileName) : this(FileName, new LevelManager()) + private void BehaviorConfig_RequestBehavior(BehaviorConfig config, BehaviorConfig.RequestBehaviorEventArgs request) + { + if (request.Behavior == null) { - } - - /// - /// Creates a new instance with input ROM. - /// - /// The ROM that will be opened. - /// The ROM that will be opened. - public RomManager(string FileName, ILevelManager levelManager) - { - RomManagerInstances.RegisterRomManager(this); - - CustomModelConfig.RequestModel += CustomModelConfig_RequestModel; - BehaviorConfig.RequestBehavior += BehaviorConfig_RequestBehavior; - CustomAsmAreaConfig.RequestCustomAsmArea += CustomAsmAreaConfig_RequestCustomAsmArea; - - RomFile = FileName; - LevelManager = levelManager; - string levelTableFile = General.MyFilePaths["Level Tabel.json"]; - if (File.Exists(levelTableFile)) + foreach (var behav in GlobalBehaviorBank.Behaviors) { - LevelInfoData.ReadFromFile(levelTableFile); + if (request.Behavior == null && behav.Config == config) + request.Behavior = behav; } - - SetSegBank(0x0, 0, Convert.ToInt32(new FileInfo(FileName).Length)); // Bank 0 means the whole ROM. - SetSegBank(0x15, 0x2ABCA0, 0x2AC6B0); - // SetSegBank(&H2, &H108A40, &H114750) - SetSegBank(0x2, 0x803156, 0); // Text Table?? - LoadRomConfig(); - LoadDictionaryUpdatePatches(); } + } - ~RomManager() + private void CustomModelConfig_RequestModel(CustomModelConfig config, CustomModelConfig.RequestModelEventArgs request) + { + if (HasGlobalObjectBank) + checkModelBank(GlobalModelBank); + + if (request.Model == null) { - RomManagerInstances.UnregisterRomManager(this); - } - - // O t h e r E v e n t s - - private void CustomAsmAreaConfig_RequestCustomAsmArea(CustomAsmAreaConfig config, CustomAsmAreaConfig.RequestCustomAsmAreaEventArgs request) - { - if (request.CustomAsmArea == null) + foreach (var lvl in Levels) { - foreach (var area in GlobalCustomAsmBank.Areas) - { - if (request.CustomAsmArea == null && area.Config == config) - request.CustomAsmArea = area; - } + if (lvl.LocalObjectBank is not null) + checkModelBank(lvl.LocalObjectBank); } } - private void BehaviorConfig_RequestBehavior(BehaviorConfig config, BehaviorConfig.RequestBehaviorEventArgs request) + void checkModelBank(CustomModelBank bank) { - if (request.Behavior == null) - { - foreach (var behav in GlobalBehaviorBank.Behaviors) - { - if (request.Behavior == null && behav.Config == config) - request.Behavior = behav; - } - } - } - - private void CustomModelConfig_RequestModel(CustomModelConfig config, CustomModelConfig.RequestModelEventArgs request) - { - if (HasGlobalObjectBank) - checkModelBank(GlobalModelBank); - if (request.Model == null) { - foreach (var lvl in Levels) + foreach (var mdl in bank.Models) { - if (lvl.LocalObjectBank is not null) - checkModelBank(lvl.LocalObjectBank); - } - } - - void checkModelBank(CustomModelBank bank) - { - if (request.Model == null) - { - foreach (var mdl in bank.Models) - { - if (request.Model == null && mdl.Config == config) - request.Model = mdl; - } + if (request.Model == null && mdl.Config == config) + request.Model = mdl; } } } + } - // R a i s e E v e n t s + // R a i s e E v e n t s - private Text.Profiles.TextProfileInfo GetDefaultTextProfileInfo() + private Text.Profiles.TextProfileInfo GetDefaultTextProfileInfo() + { + var args = new GetTextProfileInfoEventArgs(); + GettingDefaultTextProfileInfo?.Invoke(this, args); + return args.ProfileInfo; + } + + public Text.Profiles.TextProfileInfo GetTextProfileInfo() + { + if (RomConfig?.TextProfileInfo is not null) + return RomConfig.TextProfileInfo; + else + return GetDefaultTextProfileInfo(); + } + + public void CreateNewTextProfileInfo() + => SetTextProfileInfo(GetTextProfileInfo().Clone()); + + public void ResetTextProfileInfo() + => SetTextProfileInfo(null); + + public void SetTextProfileInfo(Text.Profiles.TextProfileInfo profile) + { + RomConfig.TextProfileInfo = profile; + ClearTextGroups(); + } + + private bool RaiseBeforeRomSave() + { + var e = new CancelEventArgs(); + BeforeRomSave?.Invoke(this, e); + return e.Cancel; + } + + private void RaiseAfterRomSave() + { + AfterRomSave?.Invoke(this, new EventArgs()); + } + + // F e a t u r e s + + public string GetRomConfigFilePath() + { + var p = Path.ChangeExtension(RomFile, ".config"); + if (!File.Exists(p)) { - var args = new GetTextProfileInfoEventArgs(); - GettingDefaultTextProfileInfo?.Invoke(this, args); - return args.ProfileInfo; + var pOld = RomFile + ".config"; + if (File.Exists(pOld)) + File.Move(pOld, p); } + return p; + } - public Text.Profiles.TextProfileInfo GetTextProfileInfo() + private void LoadRomConfig() + { + string confFile = GetRomConfigFilePath(); + if (File.Exists(confFile)) { - if (RomConfig?.TextProfileInfo is not null) - return RomConfig.TextProfileInfo; - else - return GetDefaultTextProfileInfo(); + RomConfig = RomConfig.Load(confFile); } - - public void CreateNewTextProfileInfo() - => SetTextProfileInfo(GetTextProfileInfo().Clone()); - - public void ResetTextProfileInfo() - => SetTextProfileInfo(null); - - public void SetTextProfileInfo(Text.Profiles.TextProfileInfo profile) + else { - RomConfig.TextProfileInfo = profile; - ClearTextGroups(); + RomConfig = new RomConfig(); } + } - private bool RaiseBeforeRomSave() + private void SaveRomConfig() + { + RomConfig.Save(GetRomConfigFilePath()); + } + + /// + /// Gets if Update Patches are avaiable for this ROM. + /// + /// + public bool AreRomUpdatesAvaiable() + { + return dicUpdatePatches.Where(n => n.Value > ProgramVersion).Count() > 0; + } + + private void LoadDictionaryUpdatePatches() + { + string udatePatchsFile = General.MyFilePaths["Update-Patches.json"]; + string jsFile; + JObject obj; + if (File.Exists(udatePatchsFile)) { - var e = new CancelEventArgs(); - BeforeRomSave?.Invoke(this, e); - return e.Cancel; + jsFile = File.ReadAllText(udatePatchsFile); + obj = JObject.Parse(jsFile); + dicUpdatePatches = (Dictionary)obj.ToObject(typeof(Dictionary)); } + } - private void RaiseAfterRomSave() + /// + /// Gets or sets the Game Name which is used for the EEP-ROM (Save file). + /// + /// + public string GameName + { + get { - AfterRomSave?.Invoke(this, new EventArgs()); - } - - // F e a t u r e s - - public string GetRomConfigFilePath() - { - var p = Path.ChangeExtension(RomFile, ".config"); - if (!File.Exists(p)) + if (myGameName is null) { - var pOld = RomFile + ".config"; - if (File.Exists(pOld)) - File.Move(pOld, p); - } - return p; - } - - private void LoadRomConfig() - { - string confFile = GetRomConfigFilePath(); - if (File.Exists(confFile)) - { - RomConfig = RomConfig.Load(confFile); - } - else - { - RomConfig = new RomConfig(); - } - } - - private void SaveRomConfig() - { - RomConfig.Save(GetRomConfigFilePath()); - } - - /// - /// Gets if Update Patches are avaiable for this ROM. - /// - /// - public bool AreRomUpdatesAvaiable() - { - return dicUpdatePatches.Where(n => n.Value > ProgramVersion).Count() > 0; - } - - private void LoadDictionaryUpdatePatches() - { - string udatePatchsFile = General.MyFilePaths["Update-Patches.json"]; - string jsFile; - JObject obj; - if (File.Exists(udatePatchsFile)) - { - jsFile = File.ReadAllText(udatePatchsFile); - obj = JObject.Parse(jsFile); - dicUpdatePatches = (Dictionary)obj.ToObject(typeof(Dictionary)); - } - } - - /// - /// Gets or sets the Game Name which is used for the EEP-ROM (Save file). - /// - /// - public string GameName - { - get - { - if (myGameName is null) - { - var fs = new BinaryRom(this, FileAccess.Read); - fs.Position = 0x20; - myGameName = Encoding.ASCII.GetString(fs.Read(0x14)).Trim(); - fs.Close(); - } - - return myGameName; - } - - set - { - var fs = new BinaryRom(this, FileAccess.Write); + var fs = new BinaryRom(this, FileAccess.Read); fs.Position = 0x20; - foreach (byte b in Encoding.ASCII.GetBytes(value)) - fs.Write(b); - while (fs.Position < 0x34) - fs.WriteByte(0x20); + myGameName = Encoding.ASCII.GetString(fs.Read(0x14)).Trim(); fs.Close(); - myGameName = value; } + + return myGameName; } - /// - /// Gets a new instance of BinaryRom, a BinaryData object. - /// - /// - /// - public BinaryRom GetBinaryRom(FileAccess access) + set { - return new BinaryRom(this, access); + var fs = new BinaryRom(this, FileAccess.Write); + fs.Position = 0x20; + foreach (byte b in Encoding.ASCII.GetBytes(value)) + fs.Write(b); + while (fs.Position < 0x34) + fs.WriteByte(0x20); + fs.Close(); + myGameName = value; } + } - public RomSpaceInfo GetRomSpaceInfo() + /// + /// Gets a new instance of BinaryRom, a BinaryData object. + /// + /// + /// + public BinaryRom GetBinaryRom(FileAccess access) + { + return new BinaryRom(this, access); + } + + public RomSpaceInfo GetRomSpaceInfo() + { + var info = new RomSpaceInfo(); + info.MaxAvailableSpace = 0x4000000 - 0x1210000; + info.UsedLevelsSpace = Levels.Length; + info.UsedMusicSpace = MusicList.Length; + info.UsedGlobalBehaviorSpace = GlobalBehaviorBank.Length; + info.UsedGlobalModelsSpace = GlobalModelBank is object ? GlobalModelBank.Length : 0; + return info; + } + + public void LoadRom() + { + BeginLoadingRom?.Invoke(this, new EventArgs()); + + // Load Global Custom Asm Bank + LoadGlobalCustomAsmBank(); + + // Load Global Behavior Bank + LoadGlobalBehaviorBank(); + + // Global Object Banks + LoadGlobalModelBank(); + + // Levels + LoadLevels(); + + // Music + LoadMusic(); + + AfterRomLoaded?.Invoke(this, new EventArgs()); + } + + /// + /// Saves the ROM. + /// + /// If True, everything will be saved even if there are no changes. + /// If True, Update Patches will be ignored. + /// + public void SaveRom(bool IgnoreNeedToSave = false, bool DontPatchUpdates = false, RecalcChecksumBehavior recalcChecksumBehavior = RecalcChecksumBehavior.Auto) + { + if (!RaiseBeforeRomSave()) { - var info = new RomSpaceInfo(); - info.MaxAvailableSpace = 0x4000000 - 0x1210000; - info.UsedLevelsSpace = Levels.Length; - info.UsedMusicSpace = MusicList.Length; - info.UsedGlobalBehaviorSpace = GlobalBehaviorBank.Length; - info.UsedGlobalModelsSpace = GlobalModelBank is object ? GlobalModelBank.Length : 0; - return info; - } - - public void LoadRom() - { - BeginLoadingRom?.Invoke(this, new EventArgs()); - - // Load Global Custom Asm Bank - LoadGlobalCustomAsmBank(); - - // Load Global Behavior Bank - LoadGlobalBehaviorBank(); - - // Global Object Banks - LoadGlobalModelBank(); - - // Levels - LoadLevels(); - - // Music - LoadMusic(); - - AfterRomLoaded?.Invoke(this, new EventArgs()); - } - - /// - /// Saves the ROM. - /// - /// If True, everything will be saved even if there are no changes. - /// If True, Update Patches will be ignored. - /// - public void SaveRom(bool IgnoreNeedToSave = false, bool DontPatchUpdates = false, RecalcChecksumBehavior recalcChecksumBehavior = RecalcChecksumBehavior.Auto) - { - if (!RaiseBeforeRomSave()) + bool needUpdateChecksum = MusicList.NeedToSaveMusicHackSettings; + if (!DontPatchUpdates) { - bool needUpdateChecksum = MusicList.NeedToSaveMusicHackSettings; - if (!DontPatchUpdates) + // Patch update-patches + foreach (KeyValuePair kvp in dicUpdatePatches.Where(n => n.Value > ProgramVersion).OrderBy(n => n.Key)) { - // Patch update-patches - foreach (KeyValuePair kvp in dicUpdatePatches.Where(n => n.Value > ProgramVersion).OrderBy(n => n.Key)) + if (kvp.Value.Filename.StartsWith("#")) { - if (kvp.Value.Filename.StartsWith("#")) + var paths = kvp.Value.Filename.Substring(1).Split('#'); + var mgr = new Patching.PatchingManager(); + var patch = mgr.Read(Path.Combine(General.MyFilePaths["Update Patches Folder"], paths[0])); + if (patch.ID == paths[1]) { - var paths = kvp.Value.Filename.Substring(1).Split('#'); - var mgr = new Patching.PatchingManager(); - var patch = mgr.Read(Path.Combine(General.MyFilePaths["Update Patches Folder"], paths[0])); - if (patch.ID == paths[1]) + var script = patch.Scripts.FirstOrDefault(n => n.ID == paths[2]); + if (script is not null) { - var script = patch.Scripts.FirstOrDefault(n => n.ID == paths[2]); - if (script is not null) + var dicParams = new Dictionary() { - var dicParams = new Dictionary() - { - { "files", patch.EmbeddedFiles }, - { "rommgr", this }, - { "romfile", RomFile }, - { "profilepath", patch.FileName } - }; - var @params = new PatchScriptExecuteParams - { - OtherParameters = dicParams, - RomManager = this, - RomFilePath = RomFile, - EmbeddedFiles = patch.EmbeddedFiles - }; - mgr.Patch(script, @params); - } + { "files", patch.EmbeddedFiles }, + { "rommgr", this }, + { "romfile", RomFile }, + { "profilepath", patch.FileName } + }; + var @params = new PatchScriptExecuteParams + { + OtherParameters = dicParams, + RomManager = this, + RomFilePath = RomFile, + EmbeddedFiles = patch.EmbeddedFiles + }; + mgr.Patch(script, @params); } } - else - General.PatchClass.ApplyPPF(RomFile, Path.Combine(General.MyFilePaths["Update Patches Folder"], kvp.Value.Filename)); - needUpdateChecksum = true; } + else + General.PatchClass.ApplyPPF(RomFile, Path.Combine(General.MyFilePaths["Update Patches Folder"], kvp.Value.Filename)); + needUpdateChecksum = true; } + } - // Write Version - WriteNewVersion(); + // Write Version + WriteNewVersion(); - // Texts - SaveAllTextGroups(ref needUpdateChecksum); + // Texts + SaveAllTextGroups(ref needUpdateChecksum); - // Music - var lastpos = default(int); - MusicList.Write(this, ref lastpos); + // Music + var lastpos = default(int); + MusicList.Write(this, ref lastpos); + General.HexRoundUp2(ref lastpos); + + // Global Model Bank + SaveGlobalModelBank(ref lastpos, ref needUpdateChecksum); + General.HexRoundUp2(ref lastpos); + + // Calc behavior bank addresses + CalculateGlobalBehaviorBankAddresses(); + + // Levels + SaveLevels(ref lastpos); // If IgnoreNeedToSave OrElse Levels.NeedToSave Then + + // Custom Object Combos + CustomObjects.TakeoverProperties(this); + + // Global Asm Bank + GlobalCustomAsmBank.Save(this); + + // Global Behavior Bank + if (RomConfig.GlobalBehaviorBank.Enabled) + { + SaveGlobalBehaviorBank(ref lastpos); General.HexRoundUp2(ref lastpos); - - // Global Model Bank - SaveGlobalModelBank(ref lastpos, ref needUpdateChecksum); - General.HexRoundUp2(ref lastpos); - - // Calc behavior bank addresses - CalculateGlobalBehaviorBankAddresses(); - - // Levels - SaveLevels(ref lastpos); // If IgnoreNeedToSave OrElse Levels.NeedToSave Then - - // Custom Object Combos - CustomObjects.TakeoverProperties(this); - - // Global Asm Bank - GlobalCustomAsmBank.Save(this); - - // Global Behavior Bank - if (RomConfig.GlobalBehaviorBank.Enabled) - { - SaveGlobalBehaviorBank(ref lastpos); - General.HexRoundUp2(ref lastpos); - } - - // Update checksum - if (recalcChecksumBehavior == RecalcChecksumBehavior.Always || (recalcChecksumBehavior == RecalcChecksumBehavior.Auto && needUpdateChecksum)) - General.PatchClass.UpdateChecksum(RomFile); - - // Write Rom.config - SaveRomConfig(); - - IsNewROM = false; - RaiseAfterRomSave(); } + + // Update checksum + if (recalcChecksumBehavior == RecalcChecksumBehavior.Always || (recalcChecksumBehavior == RecalcChecksumBehavior.Auto && needUpdateChecksum)) + General.PatchClass.UpdateChecksum(RomFile); + + // Write Rom.config + SaveRomConfig(); + + IsNewROM = false; + RaiseAfterRomSave(); + } + } + + public void CalculateGlobalBehaviorBankAddresses() + { + GlobalBehaviorBank.CalculateBehaviorBankAddresses(0x13000000, this); + } + + public void DisableGlobalBehaviorBank() + { + if (GlobalBehaviorBank.Config.Enabled) + { + // Reset Pointers + var rom = GetBinaryRom(FileAccess.ReadWrite); + rom.Position = 0x2ABCD4; + rom.Write(0x219E00); + rom.Write(0x21F4C0); + rom.Close(); + + // Set enabled false + GlobalBehaviorBank.Config.Disable(); + } + } + + private void WriteNewVersion() + { + var romVerEventArgs = new RomVersionEventArgs(ProgramVersion); + WritingNewProgramVersion?.Invoke(this, romVerEventArgs); + WriteVersion(romVerEventArgs.RomVersion); + } + + private void WriteVersion(RomVersion newVersion) + { + myProgramVersion = newVersion; + var fs = new BinaryRom(this, FileAccess.ReadWrite); + fs.Position = 0x1201FF8; + fs.Write(newVersion.DevelopmentStage << 24 | newVersion.DevelopmentBuild); + fs.WriteByte(Convert.ToByte(newVersion.Version.Major)); + fs.WriteByte(Convert.ToByte(newVersion.Version.Minor)); + fs.WriteByte(Convert.ToByte(newVersion.Version.Build)); + fs.WriteByte(Convert.ToByte(newVersion.Version.Revision)); + fs.Close(); + } + + private RomVersion LoadVersion() + { + var fs = new BinaryRom(this, FileAccess.Read); + fs.Position = 0x1201FF8; + int devInfo = fs.ReadInt32(); + byte major = fs.ReadByte(); + byte minor = fs.ReadByte(); + byte build = fs.ReadByte(); + byte revision = fs.ReadByte(); + fs.Close(); + myProgramVersion.Version = new Version(major, minor, build, revision); + if (devInfo != 0x1010101) + { + myProgramVersion.DevelopmentStage = devInfo >> 24; + myProgramVersion.DevelopmentBuild = devInfo & 0xFFFFFF; + } + else + { + myProgramVersion.DevelopmentStage = 3; + myProgramVersion.DevelopmentBuild = 0; } - public void CalculateGlobalBehaviorBankAddresses() - { - GlobalBehaviorBank.CalculateBehaviorBankAddresses(0x13000000, this); - } + return myProgramVersion; + } - public void DisableGlobalBehaviorBank() + private Text.Profiles.TextGroupInfo GetTextProfile(string name) + { + return GetTextProfileInfo().GetGroup(name); + } + + /// + /// Removes all loaded text groups, so they can be re-loaded. + /// + public void ClearTextGroups() + { + myTextGroups.Clear(); + } + + /// + /// Loads the Text Tables. + /// + public Text.TextGroup LoadTextGroup(string name, bool CheckIfAlreadyLoaded = true) + { + return LoadTextGroup(myTextGroups.FirstOrDefault(n => (n.TextGroupInfo.Name ?? "") == (name ?? "")), name, CheckIfAlreadyLoaded); + } + + private Text.TextGroup LoadTextGroup(Text.TextGroup table, string name, bool CheckIfAlreadyLoaded = true) + { + if (table is null || !CheckIfAlreadyLoaded) { - if (GlobalBehaviorBank.Config.Enabled) + var data = new BinaryRom(this, FileAccess.Read); + var prof = GetTextProfile(name); + if (table is not null) { - // Reset Pointers - var rom = GetBinaryRom(FileAccess.ReadWrite); - rom.Position = 0x2ABCD4; - rom.Write(0x219E00); - rom.Write(0x21F4C0); - rom.Close(); - - // Set enabled false - GlobalBehaviorBank.Config.Disable(); - } - } - - private void WriteNewVersion() - { - var romVerEventArgs = new RomVersionEventArgs(ProgramVersion); - WritingNewProgramVersion?.Invoke(this, romVerEventArgs); - WriteVersion(romVerEventArgs.RomVersion); - } - - private void WriteVersion(RomVersion newVersion) - { - myProgramVersion = newVersion; - var fs = new BinaryRom(this, FileAccess.ReadWrite); - fs.Position = 0x1201FF8; - fs.Write(newVersion.DevelopmentStage << 24 | newVersion.DevelopmentBuild); - fs.WriteByte(Convert.ToByte(newVersion.Version.Major)); - fs.WriteByte(Convert.ToByte(newVersion.Version.Minor)); - fs.WriteByte(Convert.ToByte(newVersion.Version.Build)); - fs.WriteByte(Convert.ToByte(newVersion.Version.Revision)); - fs.Close(); - } - - private RomVersion LoadVersion() - { - var fs = new BinaryRom(this, FileAccess.Read); - fs.Position = 0x1201FF8; - int devInfo = fs.ReadInt32(); - byte major = fs.ReadByte(); - byte minor = fs.ReadByte(); - byte build = fs.ReadByte(); - byte revision = fs.ReadByte(); - fs.Close(); - myProgramVersion.Version = new Version(major, minor, build, revision); - if (devInfo != 0x1010101) - { - myProgramVersion.DevelopmentStage = devInfo >> 24; - myProgramVersion.DevelopmentBuild = devInfo & 0xFFFFFF; - } - else - { - myProgramVersion.DevelopmentStage = 3; - myProgramVersion.DevelopmentBuild = 0; + myTextGroups.Remove(table); } - return myProgramVersion; - } - - private Text.Profiles.TextGroupInfo GetTextProfile(string name) - { - return GetTextProfileInfo().GetGroup(name); - } - - /// - /// Removes all loaded text groups, so they can be re-loaded. - /// - public void ClearTextGroups() - { - myTextGroups.Clear(); - } - - /// - /// Loads the Text Tables. - /// - public Text.TextGroup LoadTextGroup(string name, bool CheckIfAlreadyLoaded = true) - { - return LoadTextGroup(myTextGroups.FirstOrDefault(n => (n.TextGroupInfo.Name ?? "") == (name ?? "")), name, CheckIfAlreadyLoaded); - } - - private Text.TextGroup LoadTextGroup(Text.TextGroup table, string name, bool CheckIfAlreadyLoaded = true) - { - if (table is null || !CheckIfAlreadyLoaded) - { - var data = new BinaryRom(this, FileAccess.Read); - var prof = GetTextProfile(name); - if (table is not null) - { - myTextGroups.Remove(table); - } - - if (prof is Text.Profiles.TextTableGroupInfo) - { - table = new Text.TextTableGroup((Text.Profiles.TextTableGroupInfo)prof); - } - else if (prof is Text.Profiles.TextArrayGroupInfo) - { - table = new Text.TextArrayGroup((Text.Profiles.TextArrayGroupInfo)prof); - } - - myTextGroups.Add(table); - table.Read(data); - data.Close(); - } - - return table; - } - - /// - /// Gets the all known text sections - /// - /// - public Text.Profiles.TextGroupInfo[] GetTextGroupInfos() - { - return GetTextProfileInfo().AllGroups.ToArray(); - } - - /// - /// Saves the Text Tables. - /// - /// The text table to save. - public void SaveTextGroup(Text.TextGroup table) - { - bool argneedUpdateChecksum = default; - SaveTextGroup(ref argneedUpdateChecksum, table); - } - - /// - /// Saves the Text Tables. - /// - /// Outputs if the checksumarea was changed and need to be updated. - /// The text table to save. - public void SaveTextGroup(ref bool needUpdateChecksum, Text.TextGroup table) - { - var data = new BinaryRom(this, FileAccess.ReadWrite); - var prof = table.TextGroupInfo; - table.Save(data); - table.NeedToSave = false; if (prof is Text.Profiles.TextTableGroupInfo) { - needUpdateChecksum = needUpdateChecksum | ((Text.Profiles.TextTableGroupInfo)prof).Segmented.BankAddress == 0x80245000U; + table = new Text.TextTableGroup((Text.Profiles.TextTableGroupInfo)prof); } else if (prof is Text.Profiles.TextArrayGroupInfo) { - foreach (Text.Profiles.TextArrayItemInfo t in ((Text.Profiles.TextArrayGroupInfo)prof).Texts) - { - // If t.RomAddress > &H20 AndAlso t.RomAddress < &H55555 Then - // needUpdateChecksum = True - // End If - } + table = new Text.TextArrayGroup((Text.Profiles.TextArrayGroupInfo)prof); } + myTextGroups.Add(table); + table.Read(data); data.Close(); } - /// - /// Saves all Text Tables. - /// - /// If True, everything will be saved even if there are no changes. - public void SaveAllTextGroups(bool IgnoreNeedToSave = false) - { - bool argneedUpdateChecksum = default; - SaveAllTextGroups(ref argneedUpdateChecksum); - } + return table; + } - /// - /// Saves all Text Tables. - /// - /// Outputs if the checksumarea was changed and need to be updated. - /// If True, everything will be saved even if there are no changes. - public void SaveAllTextGroups(ref bool needUpdateChecksum, bool IgnoreNeedToSave = false) + /// + /// Gets the all known text sections + /// + /// + public Text.Profiles.TextGroupInfo[] GetTextGroupInfos() + { + return GetTextProfileInfo().AllGroups.ToArray(); + } + + /// + /// Saves the Text Tables. + /// + /// The text table to save. + public void SaveTextGroup(Text.TextGroup table) + { + bool argneedUpdateChecksum = default; + SaveTextGroup(ref argneedUpdateChecksum, table); + } + + /// + /// Saves the Text Tables. + /// + /// Outputs if the checksumarea was changed and need to be updated. + /// The text table to save. + public void SaveTextGroup(ref bool needUpdateChecksum, Text.TextGroup table) + { + var data = new BinaryRom(this, FileAccess.ReadWrite); + var prof = table.TextGroupInfo; + table.Save(data); + table.NeedToSave = false; + if (prof is Text.Profiles.TextTableGroupInfo) { - foreach (Text.TextGroup table in myTextGroups) + needUpdateChecksum = needUpdateChecksum | ((Text.Profiles.TextTableGroupInfo)prof).Segmented.BankAddress == 0x80245000U; + } + else if (prof is Text.Profiles.TextArrayGroupInfo) + { + foreach (Text.Profiles.TextArrayItemInfo t in ((Text.Profiles.TextArrayGroupInfo)prof).Texts) { - if (IgnoreNeedToSave || table.NeedToSave) - { - SaveTextGroup(ref needUpdateChecksum, table); - } + // If t.RomAddress > &H20 AndAlso t.RomAddress < &H55555 Then + // needUpdateChecksum = True + // End If } } - /// - /// Loads all Levels that are in the ROM. - /// - public void LoadLevels() + data.Close(); + } + + /// + /// Saves all Text Tables. + /// + /// If True, everything will be saved even if there are no changes. + public void SaveAllTextGroups(bool IgnoreNeedToSave = false) + { + bool argneedUpdateChecksum = default; + SaveAllTextGroups(ref argneedUpdateChecksum); + } + + /// + /// Saves all Text Tables. + /// + /// Outputs if the checksumarea was changed and need to be updated. + /// If True, everything will be saved even if there are no changes. + public void SaveAllTextGroups(ref bool needUpdateChecksum, bool IgnoreNeedToSave = false) + { + foreach (Text.TextGroup table in myTextGroups) { - Levels.Clear(); - var seg0x15 = GetSegBank(0x15); - seg0x15.ReadDataIfNull(RomFile); - var br = new BinaryReader(seg0x15.Data); - foreach (var ldi in LevelInfoData) + if (IgnoreNeedToSave || table.NeedToSave) { - Level lvl; - seg0x15.Data.Position = seg0x15.BankOffsetFromRomAddr((int)(ldi.Pointer + (long)3)); - byte segID = br.ReadByte(); - var curLvlSeg = SetSegBank(segID, Convert.ToInt32(SwapInts.SwapUInt32(br.ReadUInt32())), Convert.ToInt32(SwapInts.SwapUInt32(br.ReadUInt32()))); - uint offset = SwapInts.SwapUInt32(br.ReadUInt32()); + SaveTextGroup(ref needUpdateChecksum, table); + } + } + } + + /// + /// Loads all Levels that are in the ROM. + /// + public void LoadLevels() + { + Levels.Clear(); + var seg0x15 = GetSegBank(0x15); + seg0x15.ReadDataIfNull(RomFile); + var br = new BinaryReader(seg0x15.Data); + foreach (var ldi in LevelInfoData) + { + Level lvl; + seg0x15.Data.Position = seg0x15.BankOffsetFromRomAddr((int)(ldi.Pointer + (long)3)); + byte segID = br.ReadByte(); + var curLvlSeg = SetSegBank(segID, Convert.ToInt32(SwapInts.SwapUInt32(br.ReadUInt32())), Convert.ToInt32(SwapInts.SwapUInt32(br.ReadUInt32()))); + uint offset = SwapInts.SwapUInt32(br.ReadUInt32()); #if !DEBUG - try - { + try + { #endif - switch (segID) - { - case 0x19: - if (IsSM64EditorMode) - lvl = new SM64ELevel(ldi.ID, ldi.Index, this); - else - lvl = new RMLevel(RomConfig.GetLevelConfig(ldi.ID), this); - LevelManager.LoadLevel(lvl, this, ldi.ID, offset); - lvl.LastRomOffset = curLvlSeg.RomStart; // Original Level - break; - default: - lvl = null; - // Dim mgr As New OriginalLevelManager - // lvl = New OriginalLevel - // mgr.LoadLevel(lvl, Me, ldi.ID, offset) - break; - } -#if !DEBUG - } - catch (Exception) - { + switch (segID) + { + case 0x19: + if (IsSM64EditorMode) + lvl = new SM64ELevel(ldi.ID, ldi.Index, this); + else + lvl = new RMLevel(RomConfig.GetLevelConfig(ldi.ID), this); + LevelManager.LoadLevel(lvl, this, ldi.ID, offset); + lvl.LastRomOffset = curLvlSeg.RomStart; // Original Level + break; + default: lvl = null; - } + // Dim mgr As New OriginalLevelManager + // lvl = New OriginalLevel + // mgr.LoadLevel(lvl, Me, ldi.ID, offset) + break; + } +#if !DEBUG + } + catch (Exception) + { + lvl = null; + } #endif - if (lvl is not null) - Levels.Add(lvl); - } - - AfterLevelsLoaded?.Invoke(this, new EventArgs()); + if (lvl is not null) + Levels.Add(lvl); } - /// - /// Saves all Levels to the ROM. - /// - /// At this position the Levels will be written in ROM. - public void SaveLevels(ref int lastpos) - { - uint curOff = Convert.ToUInt32(lastpos); - var binRom = new BinaryRom(this, FileAccess.ReadWrite) { Position = curOff }; - foreach (Level lvl in Levels) - { - var res = LevelManager.SaveLevel(lvl, this, binRom, ref curOff); - lvl.LastRomOffset = res.Bank0x19.RomStart; - lvl.NeedToSaveBanks0E = false; - lvl.NeedToSaveLevelscript = false; - General.HexRoundUp2(ref curOff); - lastpos = (int)curOff; - } + AfterLevelsLoaded?.Invoke(this, new EventArgs()); + } - binRom.Close(); - ResetListedLevelPointers(); + /// + /// Saves all Levels to the ROM. + /// + /// At this position the Levels will be written in ROM. + public void SaveLevels(ref int lastpos) + { + uint curOff = Convert.ToUInt32(lastpos); + var binRom = new BinaryRom(this, FileAccess.ReadWrite) { Position = curOff }; + foreach (Level lvl in Levels) + { + var res = LevelManager.SaveLevel(lvl, this, binRom, ref curOff); + lvl.LastRomOffset = res.Bank0x19.RomStart; + lvl.NeedToSaveBanks0E = false; + lvl.NeedToSaveLevelscript = false; + General.HexRoundUp2(ref curOff); + lastpos = (int)curOff; } - private void ResetListedLevelPointers() - { - foreach (ushort id in levelIDsToReset.ToArray()) - { - if (!Levels.Where(n => n.LevelID == id).Any()) - { - ResetLevelPointer(Convert.ToByte(id)); - } + binRom.Close(); + ResetListedLevelPointers(); + } - levelIDsToReset.Remove(id); + private void ResetListedLevelPointers() + { + foreach (ushort id in levelIDsToReset.ToArray()) + { + if (!Levels.Where(n => n.LevelID == id).Any()) + { + ResetLevelPointer(Convert.ToByte(id)); } + + levelIDsToReset.Remove(id); } + } - /// - /// Loads the global object bank, if avaiable (WIP) - /// - public void LoadGlobalModelBank() + /// + /// Loads the global object bank, if avaiable (WIP) + /// + public void LoadGlobalModelBank() + { + var fs = new BinaryRom(this, FileAccess.Read); + + // Read Bank Addres & Length from Rom + fs.Position = 0x120FFF0; + var seg = new SegmentedBank(0x7); + seg.RomStart = fs.ReadInt32(); + seg.RomEnd = fs.ReadInt32(); + if (seg.RomStart != 0x1010101 && seg.RomStart > -1) { - var fs = new BinaryRom(this, FileAccess.Read); + // Set Segmented Bank + SetSegBank(seg); - // Read Bank Addres & Length from Rom - fs.Position = 0x120FFF0; - var seg = new SegmentedBank(0x7); - seg.RomStart = fs.ReadInt32(); - seg.RomEnd = fs.ReadInt32(); - if (seg.RomStart != 0x1010101 && seg.RomStart > -1) - { - // Set Segmented Bank - SetSegBank(seg); - - // Load Object Bank - GlobalModelBank = new CustomModelBank(); - GlobalModelBank.ReadFromSeg(this, seg, RomConfig.GlobalModelBank); - } - else - { - // Set Object Bank to Null - GlobalModelBank = null; - } - - fs.Close(); - } - - public void CreateNewGlobalModelBank() - { + // Load Object Bank GlobalModelBank = new CustomModelBank(); + GlobalModelBank.ReadFromSeg(this, seg, RomConfig.GlobalModelBank); + } + else + { + // Set Object Bank to Null + GlobalModelBank = null; } - public void GenerateGlobalObjectBank() + fs.Close(); + } + + public void CreateNewGlobalModelBank() + { + GlobalModelBank = new CustomModelBank(); + } + + public void GenerateGlobalObjectBank() + { + GenerateAndGetGlobalObjectBank(); + } + + private SegmentedBank GenerateAndGetGlobalObjectBank() + { + if (GlobalModelBank is null) { - GenerateAndGetGlobalObjectBank(); + CreateNewGlobalModelBank(); } - private SegmentedBank GenerateAndGetGlobalObjectBank() + var seg = GlobalModelBank.WriteToSeg(0x7, RomConfig.CollisionBaseConfig); + SetSegBank(seg); + return seg; + } + + private void SaveGlobalModelBank(ref int offset, ref bool needToRecalcChecksum) + { + var seg = GenerateAndGetGlobalObjectBank(); + + // Write collision pointers + GlobalModelBank.WriteCollisionPointers(this); + + // Set Segmented Bank + seg.RomStart = offset; + + // Write Segmented Bank + var rom = new BinaryRom(this, FileAccess.ReadWrite); + seg.WriteData(rom.BaseStream); + offset = Convert.ToInt32(rom.Position); + + // Write Bank Address & Length to Rom + rom.Position = 0x120FFF0; + void checkAndSet(int value, ref bool needToRecalcChecksum2) { - if (GlobalModelBank is null) + if (rom.ReadInt32() != value) { - CreateNewGlobalModelBank(); - } - - var seg = GlobalModelBank.WriteToSeg(0x7, RomConfig.CollisionBaseConfig); - SetSegBank(seg); - return seg; - } - - private void SaveGlobalModelBank(ref int offset, ref bool needToRecalcChecksum) - { - var seg = GenerateAndGetGlobalObjectBank(); - - // Write collision pointers - GlobalModelBank.WriteCollisionPointers(this); - - // Set Segmented Bank - seg.RomStart = offset; - - // Write Segmented Bank - var rom = new BinaryRom(this, FileAccess.ReadWrite); - seg.WriteData(rom.BaseStream); - offset = Convert.ToInt32(rom.Position); - - // Write Bank Address & Length to Rom - rom.Position = 0x120FFF0; - void checkAndSet(int value, ref bool needToRecalcChecksum2) - { - if (rom.ReadInt32() != value) - { - rom.Position -= 4; - rom.Write(value); - needToRecalcChecksum2 = true; - } - } - checkAndSet(seg.RomStart, ref needToRecalcChecksum); - checkAndSet(seg.RomEnd, ref needToRecalcChecksum); - rom.Close(); - } - - public void LoadGlobalBehaviorBank(bool enableAndLoadIfDisabled = false) - { - GlobalBehaviorBank = new BehaviorBank(RomConfig.GlobalBehaviorBank); - - if (!GlobalBehaviorBank.Config.Enabled && enableAndLoadIfDisabled) - RomConfig.GlobalBehaviorBank.Enable(); - - if (GlobalBehaviorBank.Config.Enabled) - { - var rom = GetBinaryRom(FileAccess.Read); - - // Get Bank Address & Length from ROM - rom.Position = 0x2ABCD4; - var seg = new SegmentedBank(0x13) - { - RomStart = rom.ReadInt32(), - RomEnd = rom.ReadInt32() - }; - seg.ReadData(rom.BaseStream); - rom.Close(); - - // Read Behavior Bank - if (RomConfig.GlobalBehaviorBank.IsVanilla) - GlobalBehaviorBank.ReadVanillaBank(seg); - else - GlobalBehaviorBank.ReadBank(seg, 0); + rom.Position -= 4; + rom.Write(value); + needToRecalcChecksum2 = true; } } + checkAndSet(seg.RomStart, ref needToRecalcChecksum); + checkAndSet(seg.RomEnd, ref needToRecalcChecksum); + rom.Close(); + } - private void SaveGlobalBehaviorBank(ref int offset) + public void LoadGlobalBehaviorBank(bool enableAndLoadIfDisabled = false) + { + GlobalBehaviorBank = new BehaviorBank(RomConfig.GlobalBehaviorBank); + + if (!GlobalBehaviorBank.Config.Enabled && enableAndLoadIfDisabled) + RomConfig.GlobalBehaviorBank.Enable(); + + if (GlobalBehaviorBank.Config.Enabled) { - // Write Segmented Bank - var seg = GlobalBehaviorBank.WriteToSeg(0x13, 0, this); - SetSegBank(seg); + var rom = GetBinaryRom(FileAccess.Read); - // Set Segmented Bank - seg.RomStart = offset; - - // Write Segmented Bank - var rom = new BinaryRom(this, FileAccess.ReadWrite); - seg.WriteData(rom.BaseStream); - offset = Convert.ToInt32(rom.Position); - - // Write Bank Address & Length to ROM + // Get Bank Address & Length from ROM rom.Position = 0x2ABCD4; - rom.Write(seg.RomStart); - rom.Write(seg.RomEnd); - - // Write addresses - GlobalBehaviorBank.WriteBehaviorAddresss(rom); - + var seg = new SegmentedBank(0x13) + { + RomStart = rom.ReadInt32(), + RomEnd = rom.ReadInt32() + }; + seg.ReadData(rom.BaseStream); rom.Close(); - RomConfig.GlobalBehaviorBank.IsVanilla = false; - } - public void LoadGlobalCustomAsmBank() - { - GlobalCustomAsmBank = new CustomAsmBank(RomConfig.GlobalCustomAsmBank); - GlobalCustomAsmBank.Load(this); - } - - /// - /// Creates and adds a new Level with ID. - /// - /// The ID of the Level. - public Level AddLevel(byte LevelID) - { - var newLevel = new RMLevel(LevelID, LevelInfoData.GetByLevelID(LevelID).Index, this); // GetLevelIndexFromID(LevelID) - Levels.Add(newLevel); - if (levelIDsToReset.Contains(LevelID)) - { - levelIDsToReset.Remove(LevelID); - } - - return newLevel; - } - - /// - /// Removes a Level from the list and ROM. - /// - /// The level to remove. - public void RemoveLevel(Level level) - { - Levels.Remove(level); - levelIDsToReset.Add(level.LevelID); - } - - /// - /// Changes the Level ID from a existing Level. - /// - /// The Level where to change the Level ID. - /// The new Level ID. - /// Activate/Deactivate the Act Selector fot the Level. - public bool ChangeLevelID(Level level, ushort newLevelID, bool? EnableActSelector = default) - { - if (level.LevelID != newLevelID) - { - levelIDsToReset.Add(level.LevelID); - level.LevelID = newLevelID; - if (EnableActSelector is not null) - level.ActSelector = EnableActSelector == true; - return true; - } + // Read Behavior Bank + if (RomConfig.GlobalBehaviorBank.IsVanilla) + GlobalBehaviorBank.ReadVanillaBank(seg); else - { - return false; - } + GlobalBehaviorBank.ReadBank(seg, 0); + } + } + + private void SaveGlobalBehaviorBank(ref int offset) + { + // Write Segmented Bank + var seg = GlobalBehaviorBank.WriteToSeg(0x13, 0, this); + SetSegBank(seg); + + // Set Segmented Bank + seg.RomStart = offset; + + // Write Segmented Bank + var rom = new BinaryRom(this, FileAccess.ReadWrite); + seg.WriteData(rom.BaseStream); + offset = Convert.ToInt32(rom.Position); + + // Write Bank Address & Length to ROM + rom.Position = 0x2ABCD4; + rom.Write(seg.RomStart); + rom.Write(seg.RomEnd); + + // Write addresses + GlobalBehaviorBank.WriteBehaviorAddresss(rom); + + rom.Close(); + RomConfig.GlobalBehaviorBank.IsVanilla = false; + } + + public void LoadGlobalCustomAsmBank() + { + GlobalCustomAsmBank = new CustomAsmBank(RomConfig.GlobalCustomAsmBank); + GlobalCustomAsmBank.Load(this); + } + + /// + /// Creates and adds a new Level with ID. + /// + /// The ID of the Level. + public Level AddLevel(byte LevelID) + { + var newLevel = new RMLevel(LevelID, LevelInfoData.GetByLevelID(LevelID).Index, this); // GetLevelIndexFromID(LevelID) + Levels.Add(newLevel); + if (levelIDsToReset.Contains(LevelID)) + { + levelIDsToReset.Remove(LevelID); } - /// - /// Loads the Music from the ROM. - /// - private void LoadMusic() + return newLevel; + } + + /// + /// Removes a Level from the list and ROM. + /// + /// The level to remove. + public void RemoveLevel(Level level) + { + Levels.Remove(level); + levelIDsToReset.Add(level.LevelID); + } + + /// + /// Changes the Level ID from a existing Level. + /// + /// The Level where to change the Level ID. + /// The new Level ID. + /// Activate/Deactivate the Act Selector fot the Level. + public bool ChangeLevelID(Level level, ushort newLevelID, bool? EnableActSelector = default) + { + if (level.LevelID != newLevelID) { - BeginLoadingMusic?.Invoke(this, new EventArgs()); - MusicList.Read(this); - AfterMusicLoaded?.Invoke(this, new EventArgs()); - } - - /// - /// Check, if the ROM is a valid SM64 ROM. - /// - /// - public bool CheckROM(bool doNotHandleVanillaRom = false, bool enableMD5Check = true) - { - var fi = new FileInfo(RomFile); - long filelength = fi.Length; - if (fi.IsReadOnly) - { - throw new ReadOnlyException("This ROM file is Read-Only. Remove the write protection and try again."); - } - - if (filelength == 8 * 1024 * 1024) - { - if (doNotHandleVanillaRom) - return false; - else - { - CreateROM(enableMD5Check: enableMD5Check); - PrepairROM(); - IsNewROM = true; - } - } - - var br = new BinaryRom(this, FileAccess.Read); - br.Position = 0x1200000; - long tCheckData = br.ReadInt64(); - br.Close(); - IsSM64EditorMode = new[] { 0x800800001900001C, 0x800800000E0000C4 }.Contains((ulong)tCheckData); - if (IsSM64EditorMode && LevelManager is LevelManager) - { - LevelManager = new SM64EditorLevelManager(); - } - + levelIDsToReset.Add(level.LevelID); + level.LevelID = newLevelID; + if (EnableActSelector is not null) + level.ActSelector = EnableActSelector == true; return true; } - - private void PrepairROM() + else { - var baseTweakFile = General.MyFilePaths["BaseTweak"]; - var patchingManager = new Patching.PatchingManager(); - var baseTweak = patchingManager.Read(baseTweakFile); - IEnumerable allScripts = baseTweak.Scripts - .Select(n => new BaseTweakScriptInfo(n)) - .OrderBy(n => n.Priority); - - // Raise Event to let the user choose what to enable - var eargs = new PrepairingRomEventArgs - { - ScriptInfos = allScripts - }; - PrepairingRom?.Invoke(this, eargs); - - // Get only enabled script and sort by priority - allScripts = allScripts.Where(n => n.Enabled); - - // Patch all scripts - if (allScripts.Any()) - { - var dicParams = new Dictionary() - { - {"files", baseTweak.EmbeddedFiles }, - {"rommgr", this }, - {"romfile", RomFile }, - {"profilepath", baseTweak.FileName } - }; - var @params = new PatchScriptExecuteParams - { - OtherParameters = dicParams, - RomManager = this, - RomFilePath = RomFile, - EmbeddedFiles = baseTweak.EmbeddedFiles - }; - foreach (var info in allScripts) - patchingManager.Patch(info.Script, @params); - } - - // Repaire patched music - MusicList.Read(this); - MusicList.NeedToSaveSequences = true; - MusicList.NeedToSaveSequenceNames = true; - MusicList.NeedToSaveNInsts = true; - MusicList.NeedToSaveMusicHackSettings = true; - int arglastPosition = 0; - MusicList.Write(this, ref arglastPosition); - - // Update Checksum - General.PatchClass.UpdateChecksum(RomFile); - - WriteNewVersion(); - SaveRomConfig(); + return false; } - - /// - /// Extens the ROM. - /// - /// If True, no new try will be executed, if failed. - /// - public void CreateROM(bool IsSecondTry = false, bool enableMD5Check = true) - { - // Check md5 hash of ROM - if (!IsSecondTry && enableMD5Check) - { - var md5 = General.ComputeMD5Hash(RomFile); - if (md5 != SUPER_MARIO_64_U_MD5HASH) - throw new InvalidMD5HashException(); - } - - // Extend to 64MB - var proc = new Process(); - { - var withBlock = proc.StartInfo; - withBlock.FileName = General.MyFilePaths["sm64extend.exe"]; - withBlock.UseShellExecute = false; - withBlock.Arguments = string.Format("-a 16 -f \"{0}\" \"{0}\"", RomFile); - withBlock.CreateNoWindow = true; - } - - proc.Start(); - proc.WaitForExit(); - - //if (new FileInfo(RomFile).Length == 8 * 1024 * 1024) - //{ - // if (IsSecondTry) - // { - // throw new Exception("Your ROM is invalid, it isn't possible to extend it."); - // } - // else - // { - // var fs = new BinaryRom(this, FileAccess.Write); - // fs.Position = 0x10; - // foreach (string b in "63 5A 2B FF 8B 02 23 26".Split(' ')) - // fs.WriteByte(Convert.ToByte("&H" + b)); - // fs.Close(); - // CreateROM(true); - // } - //} - } - - /// - /// Resets the Level Pointer of the Level with the given ID. - /// - /// The ID where to reset the pointer. - public void ResetLevelPointer(byte ID) - { - ResetLevelPointer(LevelInfoData.GetByLevelID(ID)); - } - - /// - /// Resets the Level Pointer of the Level with the given Levelinfo. - /// - /// The Levelinfo where to reset the pointer. - public void ResetLevelPointer(LevelInfoDataTabelList.Level info) - { - var fsPointer = new BinaryFile(Path.Combine(General.MyFilePaths["Original Level Pointers.bin"]), FileMode.Open, FileAccess.Read); - var fsRom = new BinaryRom(this, FileAccess.ReadWrite); - var data = new byte[20]; - fsPointer.Position = info.Pointer - (long)0x2AC094; - fsPointer.Read(data, 0, data.Count()); - fsRom.Position = info.Pointer; - fsRom.Write(data); - fsPointer.Close(); - fsRom.Close(); - } - - public SegmentedBank SetSegBank(byte BankID, int RomStart, int RomEnd) - { - return SetSegBank(BankID, RomStart, RomEnd, default); - } - - public SegmentedBank SetSegBank(byte BankID, int RomStart, int RomEnd, byte? AreaID) - { - var newBank = new SegmentedBank() { BankID = BankID, RomStart = RomStart, RomEnd = RomEnd }; - SetSegBank(newBank, AreaID); - return newBank; - } - - public void SetSegBank(SegmentedBank SegBank) - { - SetSegBank(SegBank, default); - } - - public void SetSegBank(SegmentedBank SegBank, byte? AreaID) - { - Dictionary sbl; - if (AreaID is not null) - { - if (areaSegBankList.ContainsKey((byte)AreaID)) - { - sbl = areaSegBankList[(byte)AreaID]; - } - else - { - sbl = new Dictionary(); - areaSegBankList.Add((byte)AreaID, sbl); - } - } - else - { - sbl = segBankList; - } - - if (sbl.ContainsKey(SegBank.BankID)) - { - sbl.Remove(SegBank.BankID); - } - - sbl.Add(SegBank.BankID, SegBank); - } - - public SegmentedBank GetSegBank(byte BankID) - { - return GetSegBank(BankID, default); - } - - public SegmentedBank GetSegBank(byte BankID, byte? AreaID) - { - if (AreaID is not null && areaSegBankList.ContainsKey((byte)AreaID) && areaSegBankList[(byte)AreaID].ContainsKey(BankID)) - { - return areaSegBankList[(byte)AreaID][BankID]; - } - else if (segBankList.ContainsKey(BankID)) - { - return segBankList[BankID]; - } - else - { - return null; - } - } - - public SegmentedBank[] GetAllSegBanks() - { - var sb = new List(); - foreach (var kvp in segBankList) - sb.Add(kvp.Value); - return sb.ToArray(); - } - - public BinaryData GetSegBankData(byte bankID) - { - BinaryData data; - - // Get correct bank - var seg = GetSegBank(bankID); - seg.ReadDataIfNull(this); - data = new BinaryStreamData(seg.Data); - - return data; - } - } + + /// + /// Loads the Music from the ROM. + /// + private void LoadMusic() + { + BeginLoadingMusic?.Invoke(this, new EventArgs()); + MusicList.Read(this); + AfterMusicLoaded?.Invoke(this, new EventArgs()); + } + + /// + /// Check, if the ROM is a valid SM64 ROM. + /// + /// + public bool CheckROM(bool doNotHandleVanillaRom = false, bool enableMD5Check = true) + { + var fi = new FileInfo(RomFile); + long filelength = fi.Length; + if (fi.IsReadOnly) + { + throw new ReadOnlyException("This ROM file is Read-Only. Remove the write protection and try again."); + } + + if (filelength == 8 * 1024 * 1024) + { + if (doNotHandleVanillaRom) + return false; + else + { + CreateROM(enableMD5Check: enableMD5Check); + PrepairROM(); + IsNewROM = true; + } + } + + var br = new BinaryRom(this, FileAccess.Read); + br.Position = 0x1200000; + long tCheckData = br.ReadInt64(); + br.Close(); + IsSM64EditorMode = new[] { 0x800800001900001C, 0x800800000E0000C4 }.Contains((ulong)tCheckData); + if (IsSM64EditorMode && LevelManager is LevelManager) + { + LevelManager = new SM64EditorLevelManager(); + } + + return true; + } + + private void PrepairROM() + { + var baseTweakFile = General.MyFilePaths["BaseTweak"]; + var patchingManager = new Patching.PatchingManager(); + var baseTweak = patchingManager.Read(baseTweakFile); + IEnumerable allScripts = baseTweak.Scripts + .Select(n => new BaseTweakScriptInfo(n)) + .OrderBy(n => n.Priority); + + // Raise Event to let the user choose what to enable + var eargs = new PrepairingRomEventArgs + { + ScriptInfos = allScripts + }; + PrepairingRom?.Invoke(this, eargs); + + // Get only enabled script and sort by priority + allScripts = allScripts.Where(n => n.Enabled); + + // Patch all scripts + if (allScripts.Any()) + { + var dicParams = new Dictionary() + { + {"files", baseTweak.EmbeddedFiles }, + {"rommgr", this }, + {"romfile", RomFile }, + {"profilepath", baseTweak.FileName } + }; + var @params = new PatchScriptExecuteParams + { + OtherParameters = dicParams, + RomManager = this, + RomFilePath = RomFile, + EmbeddedFiles = baseTweak.EmbeddedFiles + }; + foreach (var info in allScripts) + patchingManager.Patch(info.Script, @params); + } + + // Repaire patched music + MusicList.Read(this); + MusicList.NeedToSaveSequences = true; + MusicList.NeedToSaveSequenceNames = true; + MusicList.NeedToSaveNInsts = true; + MusicList.NeedToSaveMusicHackSettings = true; + int arglastPosition = 0; + MusicList.Write(this, ref arglastPosition); + + // Update Checksum + General.PatchClass.UpdateChecksum(RomFile); + + WriteNewVersion(); + SaveRomConfig(); + } + + /// + /// Extens the ROM. + /// + /// If True, no new try will be executed, if failed. + /// + public void CreateROM(bool IsSecondTry = false, bool enableMD5Check = true) + { + // Check md5 hash of ROM + if (!IsSecondTry && enableMD5Check) + { + var md5 = General.ComputeMD5Hash(RomFile); + if (md5 != SUPER_MARIO_64_U_MD5HASH) + throw new InvalidMD5HashException(); + } + + // Extend to 64MB + var proc = new Process(); + { + var withBlock = proc.StartInfo; + withBlock.FileName = General.MyFilePaths["sm64extend.exe"]; + withBlock.UseShellExecute = false; + withBlock.Arguments = string.Format("-a 16 -f \"{0}\" \"{0}\"", RomFile); + withBlock.CreateNoWindow = true; + } + + proc.Start(); + proc.WaitForExit(); + + //if (new FileInfo(RomFile).Length == 8 * 1024 * 1024) + //{ + // if (IsSecondTry) + // { + // throw new Exception("Your ROM is invalid, it isn't possible to extend it."); + // } + // else + // { + // var fs = new BinaryRom(this, FileAccess.Write); + // fs.Position = 0x10; + // foreach (string b in "63 5A 2B FF 8B 02 23 26".Split(' ')) + // fs.WriteByte(Convert.ToByte("&H" + b)); + // fs.Close(); + // CreateROM(true); + // } + //} + } + + /// + /// Resets the Level Pointer of the Level with the given ID. + /// + /// The ID where to reset the pointer. + public void ResetLevelPointer(byte ID) + { + ResetLevelPointer(LevelInfoData.GetByLevelID(ID)); + } + + /// + /// Resets the Level Pointer of the Level with the given Levelinfo. + /// + /// The Levelinfo where to reset the pointer. + public void ResetLevelPointer(LevelInfoDataTabelList.Level info) + { + var fsPointer = new BinaryFile(Path.Combine(General.MyFilePaths["Original Level Pointers.bin"]), FileMode.Open, FileAccess.Read); + var fsRom = new BinaryRom(this, FileAccess.ReadWrite); + var data = new byte[20]; + fsPointer.Position = info.Pointer - (long)0x2AC094; + fsPointer.Read(data, 0, data.Count()); + fsRom.Position = info.Pointer; + fsRom.Write(data); + fsPointer.Close(); + fsRom.Close(); + } + + public SegmentedBank SetSegBank(byte BankID, int RomStart, int RomEnd) + { + return SetSegBank(BankID, RomStart, RomEnd, default); + } + + public SegmentedBank SetSegBank(byte BankID, int RomStart, int RomEnd, byte? AreaID) + { + var newBank = new SegmentedBank() { BankID = BankID, RomStart = RomStart, RomEnd = RomEnd }; + SetSegBank(newBank, AreaID); + return newBank; + } + + public void SetSegBank(SegmentedBank SegBank) + { + SetSegBank(SegBank, default); + } + + public void SetSegBank(SegmentedBank SegBank, byte? AreaID) + { + Dictionary sbl; + if (AreaID is not null) + { + if (areaSegBankList.ContainsKey((byte)AreaID)) + { + sbl = areaSegBankList[(byte)AreaID]; + } + else + { + sbl = new Dictionary(); + areaSegBankList.Add((byte)AreaID, sbl); + } + } + else + { + sbl = segBankList; + } + + if (sbl.ContainsKey(SegBank.BankID)) + { + sbl.Remove(SegBank.BankID); + } + + sbl.Add(SegBank.BankID, SegBank); + } + + public SegmentedBank GetSegBank(byte BankID) + { + return GetSegBank(BankID, default); + } + + public SegmentedBank GetSegBank(byte BankID, byte? AreaID) + { + if (AreaID is not null && areaSegBankList.ContainsKey((byte)AreaID) && areaSegBankList[(byte)AreaID].ContainsKey(BankID)) + { + return areaSegBankList[(byte)AreaID][BankID]; + } + else if (segBankList.ContainsKey(BankID)) + { + return segBankList[BankID]; + } + else + { + return null; + } + } + + public SegmentedBank[] GetAllSegBanks() + { + var sb = new List(); + foreach (var kvp in segBankList) + sb.Add(kvp.Value); + return sb.ToArray(); + } + + public BinaryData GetSegBankData(byte bankID) + { + BinaryData data; + + // Get correct bank + var seg = GetSegBank(bankID); + seg.ReadDataIfNull(this); + data = new BinaryStreamData(seg.Data); + + return data; + } + } \ No newline at end of file diff --git a/SM64Lib/RomManagerInstances.cs b/SM64Lib/RomManagerInstances.cs index 40e2022..b258a07 100644 --- a/SM64Lib/RomManagerInstances.cs +++ b/SM64Lib/RomManagerInstances.cs @@ -1,30 +1,25 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Collections.Generic; -namespace SM64Lib +namespace SM64Lib; + +public static class RomManagerInstances { - public static class RomManagerInstances + private static readonly List romManagers = new List(); + + public static IEnumerable CurrentInstances { - private static readonly List romManagers = new List(); + get => romManagers; + } - public static IEnumerable CurrentInstances - { - get => romManagers; - } + internal static void RegisterRomManager(RomManager romManager) + { + if (!romManagers.Contains(romManager)) + romManagers.Add(romManager); + } - internal static void RegisterRomManager(RomManager romManager) - { - if(!romManagers.Contains(romManager)) - romManagers.Add(romManager); - } - - internal static void UnregisterRomManager(RomManager romManager) - { - if (romManagers.Contains(romManager)) - romManagers.Remove(romManager); - } + internal static void UnregisterRomManager(RomManager romManager) + { + if (romManagers.Contains(romManager)) + romManagers.Remove(romManager); } } diff --git a/SM64Lib/RomManagerSettings.cs b/SM64Lib/RomManagerSettings.cs index 8637ead..fc2e8ea 100644 --- a/SM64Lib/RomManagerSettings.cs +++ b/SM64Lib/RomManagerSettings.cs @@ -1,10 +1,9 @@  -namespace SM64Lib +namespace SM64Lib; + +public class RomManagerSettings { - public class RomManagerSettings - { - public const uint DefaultRangeForLevelsStart = 0x1410000; - public const uint DefaultRangeForLevelsEnd = 0x3FFFFFF; - public const uint DefaultLevelscriptSize = 0xA000; - } + public const uint DefaultRangeForLevelsStart = 0x1410000; + public const uint DefaultRangeForLevelsEnd = 0x3FFFFFF; + public const uint DefaultLevelscriptSize = 0xA000; } \ No newline at end of file diff --git a/SM64Lib/RomSpaceInfo.cs b/SM64Lib/RomSpaceInfo.cs index ed420fe..3beaa1e 100644 --- a/SM64Lib/RomSpaceInfo.cs +++ b/SM64Lib/RomSpaceInfo.cs @@ -1,31 +1,24 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +namespace SM64Lib; -namespace SM64Lib +public class RomSpaceInfo { - public class RomSpaceInfo + public long MaxAvailableSpace { get; set; } + public long UsedLevelsSpace { get; set; } + public long UsedMusicSpace { get; set; } + public long UsedGlobalBehaviorSpace { get; set; } + public long UsedGlobalModelsSpace { get; set; } + + public long TotalUsedSpace { - public long MaxAvailableSpace { get; set; } - public long UsedLevelsSpace { get; set; } - public long UsedMusicSpace { get; set; } - public long UsedGlobalBehaviorSpace { get; set; } - public long UsedGlobalModelsSpace { get; set; } + get => + UsedLevelsSpace + + UsedMusicSpace + + UsedGlobalBehaviorSpace + + UsedGlobalModelsSpace; + } - public long TotalUsedSpace - { - get => - UsedLevelsSpace + - UsedMusicSpace + - UsedGlobalBehaviorSpace + - UsedGlobalModelsSpace; - } - - public long FreeSpace - { - get => MaxAvailableSpace - TotalUsedSpace; - } + public long FreeSpace + { + get => MaxAvailableSpace - TotalUsedSpace; } } diff --git a/SM64Lib/RomVersion.cs b/SM64Lib/RomVersion.cs index 8f2020f..7867378 100644 --- a/SM64Lib/RomVersion.cs +++ b/SM64Lib/RomVersion.cs @@ -1,45 +1,44 @@ using Newtonsoft.Json; using System; -namespace SM64Lib +namespace SM64Lib; + +public struct RomVersion { - public struct RomVersion + public Version Version { get; set; } + public int DevelopmentStage { get; set; } + public int DevelopmentBuild { get; set; } + [JsonProperty()] + internal string Filename { get; private set; } + + public static bool operator !=(RomVersion left, RomVersion right) { - public Version Version { get; set; } - public int DevelopmentStage { get; set; } - public int DevelopmentBuild { get; set; } - [JsonProperty()] - internal string Filename { get; private set; } + return left.Version != right.Version && left.DevelopmentBuild != right.DevelopmentBuild && left.DevelopmentStage != right.DevelopmentStage; + } - public static bool operator !=(RomVersion left, RomVersion right) - { - return left.Version != right.Version && left.DevelopmentBuild != right.DevelopmentBuild && left.DevelopmentStage != right.DevelopmentStage; - } + public static bool operator ==(RomVersion left, RomVersion right) + { + return left.Version == right.Version && left.DevelopmentBuild == right.DevelopmentBuild && left.DevelopmentStage == right.DevelopmentStage; + } - public static bool operator ==(RomVersion left, RomVersion right) - { - return left.Version == right.Version && left.DevelopmentBuild == right.DevelopmentBuild && left.DevelopmentStage == right.DevelopmentStage; - } + public static bool operator >(RomVersion left, RomVersion right) + { + bool flag = left.Version > right.Version || left.Version == right.Version && left.DevelopmentStage < right.DevelopmentStage || left.Version == right.Version && left.DevelopmentStage == right.DevelopmentStage && left.DevelopmentBuild > right.DevelopmentBuild; + return flag; + } - public static bool operator >(RomVersion left, RomVersion right) - { - bool flag = left.Version > right.Version || left.Version == right.Version && left.DevelopmentStage < right.DevelopmentStage || left.Version == right.Version && left.DevelopmentStage == right.DevelopmentStage && left.DevelopmentBuild > right.DevelopmentBuild; - return flag; - } + public static bool operator <(RomVersion left, RomVersion right) + { + return !(left >= right); + } - public static bool operator <(RomVersion left, RomVersion right) - { - return !(left >= right); - } + public static bool operator >=(RomVersion left, RomVersion right) + { + return left == right || left > right; + } - public static bool operator >=(RomVersion left, RomVersion right) - { - return left == right || left > right; - } - - public static bool operator <=(RomVersion left, RomVersion right) - { - return left == right || left < right; - } + public static bool operator <=(RomVersion left, RomVersion right) + { + return left == right || left < right; } } \ No newline at end of file diff --git a/SM64Lib/Script/BaseCommand.cs b/SM64Lib/Script/BaseCommand.cs index c2f3c6f..0ba937b 100644 --- a/SM64Lib/Script/BaseCommand.cs +++ b/SM64Lib/Script/BaseCommand.cs @@ -1,93 +1,91 @@ -using System; +using global::System.IO; +using System; using System.Collections.Generic; -using global::System.IO; using System.Linq; -using Microsoft.VisualBasic.CompilerServices; -namespace SM64Lib.Script +namespace SM64Lib.Script; + +[Serializable] +public abstract class BaseCommand : Data.BinaryStreamData, ICommand { - [Serializable] - public abstract class BaseCommand : Data.BinaryStreamData, ICommand + private int dirtyHash = 0; + + public int RomAddress { get; set; } = 0; + public int BankAddress { get; set; } = 0; + public abstract eTypes CommandType { get; set; } + + public BaseCommand(string bytes, bool enabledHex = true) : this() { - private int dirtyHash = 0; - - public int RomAddress { get; set; } = 0; - public int BankAddress { get; set; } = 0; - public abstract eTypes CommandType { get; set; } - - public BaseCommand(string bytes, bool enabledHex = true) : this() + var bts = new List(); + foreach (string b in bytes.Split(' ')) { - var bts = new List(); - foreach (string b in bytes.Split(' ')) - { - string bb = b; - if (enabledHex) - bb = Convert.ToString(Convert.ToInt32(bb, 16)); - bts.Add(Convert.ToByte(bb)); - } - - NewBytes(bts.ToArray()); + string bb = b; + if (enabledHex) + bb = Convert.ToString(Convert.ToInt32(bb, 16)); + bts.Add(Convert.ToByte(bb)); } - public BaseCommand() : base(new MemoryStream()) - { - } + NewBytes(bts.ToArray()); + } - public BaseCommand(byte[] bytes) : this() - { - NewBytes(bytes); - } + public BaseCommand() : base(new MemoryStream()) + { + } - private void NewBytes(byte[] bytes) - { - SetLength(bytes.Count()); - foreach (byte b in bytes) - WriteByte(b); - Position = 0; - } + public BaseCommand(byte[] bytes) : this() + { + NewBytes(bytes); + } - public byte[] ToArray() - { - return ((MemoryStream)BaseStream).ToArray(); - } + private void NewBytes(byte[] bytes) + { + SetLength(bytes.Count()); + foreach (byte b in bytes) + WriteByte(b); + Position = 0; + } - public override string ToString() - { - return $"{RomAddress.ToString("X")} ({BankAddress.ToString("X")}): {General.CommandByteArrayToString(ToArray())}"; - } + public byte[] ToArray() + { + return ((MemoryStream)BaseStream).ToArray(); + } - public static bool operator ==(BaseCommand cmd1, BaseCommand cmd2) + public override string ToString() + { + return $"{RomAddress.ToString("X")} ({BankAddress.ToString("X")}): {General.CommandByteArrayToString(ToArray())}"; + } + + public static bool operator ==(BaseCommand cmd1, BaseCommand cmd2) + { + if (!(cmd1 is not null) || !(cmd2 is not null)) + return false; + + if (cmd1.Length != cmd2.Length) + return false; + + var buf1 = ((MemoryStream)cmd1.BaseStream).GetBuffer(); + var buf2 = ((MemoryStream)cmd2.BaseStream).GetBuffer(); + for (int i = 0, loopTo = (int)(cmd1.Length - 1); i <= loopTo; i++) { - if (!(cmd1 is not null) || !(cmd2 is not null)) + if (buf1[i] != buf2[i]) return false; - - if (cmd1.Length != cmd2.Length) - return false; - - var buf1 = ((MemoryStream)cmd1.BaseStream).GetBuffer(); - var buf2 = ((MemoryStream)cmd2.BaseStream).GetBuffer(); - for (int i = 0, loopTo = (int)(cmd1.Length - 1); i <= loopTo; i++) - { - if (buf1[i] != buf2[i]) - return false; - } - - return true; } - public static bool operator !=(BaseCommand cmd1, BaseCommand cmd2) - { - return !(cmd1 == cmd2); - } + return true; + } - public void RefreshDirty() - { - dirtyHash = ((MemoryStream)BaseStream).GetHashCode(); - } + public static bool operator !=(BaseCommand cmd1, BaseCommand cmd2) + { + return !(cmd1 == cmd2); + } - public bool IsDirty - { - get => ((MemoryStream)BaseStream).GetHashCode() != dirtyHash; - } + public void RefreshDirty() + { + dirtyHash = ((MemoryStream)BaseStream).GetHashCode(); + } + + public bool IsDirty + { + get => ((MemoryStream)BaseStream).GetHashCode() != dirtyHash; } } \ No newline at end of file diff --git a/SM64Lib/Script/BaseCommandCollection.cs b/SM64Lib/Script/BaseCommandCollection.cs index 25ee590..ff7936b 100644 --- a/SM64Lib/Script/BaseCommandCollection.cs +++ b/SM64Lib/Script/BaseCommandCollection.cs @@ -1,41 +1,39 @@ using System; using System.Collections.Generic; using System.Linq; -using Microsoft.VisualBasic; -namespace SM64Lib.Script +namespace SM64Lib.Script; + +public class BaseCommandCollection : List where TCmd : BaseCommand { - public class BaseCommandCollection : List where TCmd : BaseCommand + public long Length { - public long Length + get { - get - { - return this.Sum(n => n.Length); - } - } - - public bool IsDirty - { - get - { - return this.FirstOrDefault(n => n.IsDirty) is object; - } - } - - public override string ToString() - { - var Lines = new List(); - foreach (TCmd cmd in this) - Lines.Add(cmd.ToString()); - return string.Join(Environment.NewLine, Lines.ToArray()); - } - - public void Close() - { - foreach (TCmd cmd in this) - cmd.Close(); - Clear(); + return this.Sum(n => n.Length); } } + + public bool IsDirty + { + get + { + return this.FirstOrDefault(n => n.IsDirty) is object; + } + } + + public override string ToString() + { + var Lines = new List(); + foreach (TCmd cmd in this) + Lines.Add(cmd.ToString()); + return string.Join(Environment.NewLine, Lines.ToArray()); + } + + public void Close() + { + foreach (TCmd cmd in this) + cmd.Close(); + Clear(); + } } \ No newline at end of file diff --git a/SM64Lib/Script/ICommand.cs b/SM64Lib/Script/ICommand.cs index e89ab23..1ffd63c 100644 --- a/SM64Lib/Script/ICommand.cs +++ b/SM64Lib/Script/ICommand.cs @@ -1,11 +1,10 @@  -namespace SM64Lib.Script +namespace SM64Lib.Script; + +public interface ICommand { - public interface ICommand - { - int RomAddress { get; set; } - int BankAddress { get; set; } - bool IsDirty { get; } - byte[] ToArray(); - } + int RomAddress { get; set; } + int BankAddress { get; set; } + bool IsDirty { get; } + byte[] ToArray(); } \ No newline at end of file diff --git a/SM64Lib/SegmentedBanking/SegmentedBank.cs b/SM64Lib/SegmentedBanking/SegmentedBank.cs index 9bf6e49..964013e 100644 --- a/SM64Lib/SegmentedBanking/SegmentedBank.cs +++ b/SM64Lib/SegmentedBanking/SegmentedBank.cs @@ -1,258 +1,256 @@ -using global::System.IO; -using Microsoft.VisualBasic.CompilerServices; -using global::SM64Lib.Data; +using global::SM64Lib.Data; +using global::System.IO; using System; -namespace SM64Lib.SegmentedBanking +namespace SM64Lib.SegmentedBanking; + +public class SegmentedBank : IDisposable { - public class SegmentedBank : IDisposable + + // F i e l d s + + private int _RomEnd = 0; + + // A u t o P r o p e r t i e s + + public int RomStart { get; set; } = 0; + public byte BankID { get; set; } = 0; + public bool IsMIO0 { get; private set; } = false; + public MemoryStream Data { get; set; } = null; + + // O t h e r P r o p e r t i e s + + public int RomEnd { - - // F i e l d s - - private int _RomEnd = 0; - - // A u t o P r o p e r t i e s - - public int RomStart { get; set; } = 0; - public byte BankID { get; set; } = 0; - public bool IsMIO0 { get; private set; } = false; - public MemoryStream Data { get; set; } = null; - - // O t h e r P r o p e r t i e s - - public int RomEnd - { - get - { - if (Data is null) - { - return _RomEnd; - } - else - { - return (int)(RomStart + Data.Length); - } - } - - set - { - if (Data is null) - { - _RomEnd = value; - } - else - { - long newLength = value - RomStart; - if (Data.Length != newLength) - { - Data.SetLength(newLength); - } - } - } - } - - public int BankAddress - { - get - { - return Convert.ToInt32(Convert.ToUInt32(BankID) << 24); - } - - set - { - BankID = Convert.ToByte(value >> 24 & 0xFF); - } - } - - public int Length - { - get - { - if (Data is null) - { - return RomEnd - RomStart; - } - else - { - return Convert.ToInt32(Data.Length); - } - } - - set - { - if (Data is null) - { - RomEnd = RomStart + value; - } - else - { - Data.SetLength(value); - } - } - } - - // C o n s t r u c t o r s - - public SegmentedBank() - { - } - - public SegmentedBank(byte bankID) - { - BankID = bankID; - } - - public SegmentedBank(byte bankID, uint length) - { - BankID = bankID; - Length = Convert.ToInt32(length); - } - - public SegmentedBank(byte bankID, MemoryStream data) - { - BankID = bankID; - Data = data; - } - - public SegmentedBank(MemoryStream data) - { - Data = data; - } - - // D e c o n s t r u c t o r s - - ~SegmentedBank() - { - //Dispose(); - } - - public void Dispose() - { - CloseData(); - } - - private void CloseData() - { - Data?.Dispose(); - Data = null; - } - - // M e t h o d s - - public int SegToRomAddr(int SegmentedAddress) - { - return SegmentedAddress - BankAddress + RomStart; - } - - public int RomToSegAddr(int RomAddress) - { - return RomAddress - RomStart + BankAddress; - } - - public int BankOffsetFromSegAddr(int segPointer) - { - return segPointer - BankAddress; - } - - public int BankOffsetFromRomAddr(int RomAddr) - { - return RomAddr - RomStart; - } - - public MemoryStream ReadData(RomManager rommgr) - { - var fs = new FileStream(rommgr.RomFile, FileMode.Open, FileAccess.Read); - MemoryStream ms; - ms = ReadDataIfNull(fs); - fs.Close(); - return ms; - } - - public MemoryStream ReadDataIfNull(Stream s) + get { if (Data is null) { - ReadData(s); + return _RomEnd; + } + else + { + return (int)(RomStart + Data.Length); } - - return Data; } - public MemoryStream ReadDataIfNull(string fileName) + set { if (Data is null) { - var fs = new FileStream(fileName, FileMode.Open, FileAccess.Read); - ReadData(fs); - fs.Close(); + _RomEnd = value; } - - return Data; - } - - public MemoryStream ReadDataIfNull(RomManager rommgr) - { - return ReadDataIfNull(rommgr.RomFile); - } - - public MemoryStream ReadData(Stream s) - { - var ms = new MemoryStream(); - if (RomStart > 0 && Length > 0 && s.Length >= RomEnd) + else { - var data = new byte[Length]; - s.Position = RomStart; - s.Read(data, 0, data.Length); - if (IsDataMIO0(data)) + long newLength = value - RomStart; + if (Data.Length != newLength) { - data = LIBMIO0.MIO0.mio0_decode(data); + Data.SetLength(newLength); } - - ms.Write(data, 0, data.Length); - ms.Position = 0; } - - CloseData(); - Data = ms; - return ms; - } - - private bool IsDataMIO0(byte[] arr) - { - int check = Convert.ToInt32(arr[0]) << 24 | Convert.ToInt32(arr[1]) << 16 | Convert.ToInt32(arr[2]) << 8 | arr[3]; - return check == 0x4D494F30; - } - - public void WriteData(RomManager rommgr) - { - if (Data is not null) - { - var fs = new FileStream(rommgr.RomFile, FileMode.Open, FileAccess.ReadWrite); - WriteData(fs); - fs.Close(); - } - } - - public void WriteData(BinaryData data) - { - WriteData(data.BaseStream); - } - - public void WriteData(Stream s) - { - if (Data is not null) - { - Data.Position = 0; - s.Position = RomStart; - for (int i = 1, loopTo = (int)Data.Length; i <= loopTo; i++) - s.WriteByte(Convert.ToByte(Data.ReadByte())); - } - } - - public void MakeAsMIO0() - { - IsMIO0 = true; } } + + public int BankAddress + { + get + { + return Convert.ToInt32(Convert.ToUInt32(BankID) << 24); + } + + set + { + BankID = Convert.ToByte(value >> 24 & 0xFF); + } + } + + public int Length + { + get + { + if (Data is null) + { + return RomEnd - RomStart; + } + else + { + return Convert.ToInt32(Data.Length); + } + } + + set + { + if (Data is null) + { + RomEnd = RomStart + value; + } + else + { + Data.SetLength(value); + } + } + } + + // C o n s t r u c t o r s + + public SegmentedBank() + { + } + + public SegmentedBank(byte bankID) + { + BankID = bankID; + } + + public SegmentedBank(byte bankID, uint length) + { + BankID = bankID; + Length = Convert.ToInt32(length); + } + + public SegmentedBank(byte bankID, MemoryStream data) + { + BankID = bankID; + Data = data; + } + + public SegmentedBank(MemoryStream data) + { + Data = data; + } + + // D e c o n s t r u c t o r s + + ~SegmentedBank() + { + //Dispose(); + } + + public void Dispose() + { + CloseData(); + } + + private void CloseData() + { + Data?.Dispose(); + Data = null; + } + + // M e t h o d s + + public int SegToRomAddr(int SegmentedAddress) + { + return SegmentedAddress - BankAddress + RomStart; + } + + public int RomToSegAddr(int RomAddress) + { + return RomAddress - RomStart + BankAddress; + } + + public int BankOffsetFromSegAddr(int segPointer) + { + return segPointer - BankAddress; + } + + public int BankOffsetFromRomAddr(int RomAddr) + { + return RomAddr - RomStart; + } + + public MemoryStream ReadData(RomManager rommgr) + { + var fs = new FileStream(rommgr.RomFile, FileMode.Open, FileAccess.Read); + MemoryStream ms; + ms = ReadDataIfNull(fs); + fs.Close(); + return ms; + } + + public MemoryStream ReadDataIfNull(Stream s) + { + if (Data is null) + { + ReadData(s); + } + + return Data; + } + + public MemoryStream ReadDataIfNull(string fileName) + { + if (Data is null) + { + var fs = new FileStream(fileName, FileMode.Open, FileAccess.Read); + ReadData(fs); + fs.Close(); + } + + return Data; + } + + public MemoryStream ReadDataIfNull(RomManager rommgr) + { + return ReadDataIfNull(rommgr.RomFile); + } + + public MemoryStream ReadData(Stream s) + { + var ms = new MemoryStream(); + if (RomStart > 0 && Length > 0 && s.Length >= RomEnd) + { + var data = new byte[Length]; + s.Position = RomStart; + s.Read(data, 0, data.Length); + if (IsDataMIO0(data)) + { + data = LIBMIO0.MIO0.mio0_decode(data); + } + + ms.Write(data, 0, data.Length); + ms.Position = 0; + } + + CloseData(); + Data = ms; + return ms; + } + + private bool IsDataMIO0(byte[] arr) + { + int check = Convert.ToInt32(arr[0]) << 24 | Convert.ToInt32(arr[1]) << 16 | Convert.ToInt32(arr[2]) << 8 | arr[3]; + return check == 0x4D494F30; + } + + public void WriteData(RomManager rommgr) + { + if (Data is not null) + { + var fs = new FileStream(rommgr.RomFile, FileMode.Open, FileAccess.ReadWrite); + WriteData(fs); + fs.Close(); + } + } + + public void WriteData(BinaryData data) + { + WriteData(data.BaseStream); + } + + public void WriteData(Stream s) + { + if (Data is not null) + { + Data.Position = 0; + s.Position = RomStart; + for (int i = 1, loopTo = (int)Data.Length; i <= loopTo; i++) + s.WriteByte(Convert.ToByte(Data.ReadByte())); + } + } + + public void MakeAsMIO0() + { + IsMIO0 = true; + } } \ No newline at end of file diff --git a/SM64Lib/SegmentedBanking/SegmentedBanks.cs b/SM64Lib/SegmentedBanking/SegmentedBanks.cs index 57f5128..acc912a 100644 --- a/SM64Lib/SegmentedBanking/SegmentedBanks.cs +++ b/SM64Lib/SegmentedBanking/SegmentedBanks.cs @@ -1,9 +1,8 @@  -namespace SM64Lib.SegmentedBanking +namespace SM64Lib.SegmentedBanking; + +public class SegmentedBanks { - public class SegmentedBanks - { - public const uint Bank0x2RomStart = 0x803156; - public const uint Bank0x3RomStart = 0xAB2450; - } + public const uint Bank0x2RomStart = 0x803156; + public const uint Bank0x3RomStart = 0xAB2450; } \ No newline at end of file diff --git a/SM64Lib/Text/DialogHorizontalPosition.cs b/SM64Lib/Text/DialogHorizontalPosition.cs index 3a08d51..be959d0 100644 --- a/SM64Lib/Text/DialogHorizontalPosition.cs +++ b/SM64Lib/Text/DialogHorizontalPosition.cs @@ -1,9 +1,8 @@  -namespace SM64Lib.Text +namespace SM64Lib.Text; + +public enum DialogHorizontalPosition : short { - public enum DialogHorizontalPosition : short - { - Middle = 0x96, - Top = 0xC8 - } + Middle = 0x96, + Top = 0xC8 } \ No newline at end of file diff --git a/SM64Lib/Text/DialogSoundEffects.cs b/SM64Lib/Text/DialogSoundEffects.cs index b683980..ad14565 100644 --- a/SM64Lib/Text/DialogSoundEffects.cs +++ b/SM64Lib/Text/DialogSoundEffects.cs @@ -1,24 +1,17 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +namespace SM64Lib.Text; -namespace SM64Lib.Text +public enum DialogSoundEffect : byte { - public enum DialogSoundEffect : byte - { - Monkey = 0x00, - Penguin = 0x01, - BowserIntroDoors = 0x02, - KoopaTheQuick = 0x03, - KingBobOmb = 0x04, - Boo = 0x05, - BobOmb = 0x06, - BowserFight = 0x07, - WhompKing = 0x08, - Wiggler = 0x09, - Yoshi = 0x0A, - Sign = 0xFF - } + Monkey = 0x00, + Penguin = 0x01, + BowserIntroDoors = 0x02, + KoopaTheQuick = 0x03, + KingBobOmb = 0x04, + Boo = 0x05, + BobOmb = 0x06, + BowserFight = 0x07, + WhompKing = 0x08, + Wiggler = 0x09, + Yoshi = 0x0A, + Sign = 0xFF } diff --git a/SM64Lib/Text/DialogVerticalPosition.cs b/SM64Lib/Text/DialogVerticalPosition.cs index 2cf9f14..6e40f8f 100644 --- a/SM64Lib/Text/DialogVerticalPosition.cs +++ b/SM64Lib/Text/DialogVerticalPosition.cs @@ -1,10 +1,9 @@  -namespace SM64Lib.Text +namespace SM64Lib.Text; + +public enum DialogVerticalPosition : short { - public enum DialogVerticalPosition : short - { - Left = 0x1E, - Centred = 0x5F, - Right = 0x96 - } + Left = 0x1E, + Centred = 0x5F, + Right = 0x96 } \ No newline at end of file diff --git a/SM64Lib/Text/M64TextEncoding.cs b/SM64Lib/Text/M64TextEncoding.cs index 4e37384..8f32f44 100644 --- a/SM64Lib/Text/M64TextEncoding.cs +++ b/SM64Lib/Text/M64TextEncoding.cs @@ -2,328 +2,327 @@ using System.Collections.Generic; using System.Linq; -namespace SM64Lib.Text +namespace SM64Lib.Text; + +public class M64TextEncoding : System.Text.Encoding { - public class M64TextEncoding : System.Text.Encoding + public static System.Text.Encoding M64Text { get; } = new M64TextEncoding(); + public static bool AutoDetectStartEndQuotationMarks { get; set; } = true; + + /// + /// Defines additional charaters that are not catched by default by and . + /// + public Dictionary CharDictionary { get; } = []; + + public override string GetString(byte[] bytes) { - public static System.Text.Encoding M64Text { get; } = new M64TextEncoding(); - public static bool AutoDetectStartEndQuotationMarks { get; set; } = true; + string txt = string.Empty; - /// - /// Defines additional charaters that are not catched by default by and . - /// - public Dictionary CharDictionary { get; } = []; - - public override string GetString(byte[] bytes) + foreach (var b in bytes) { - string txt = string.Empty; - - foreach (var b in bytes) + string t = b switch { - string t = b switch - { - 0x0 => "0", - 0x1 => "1", - 0x2 => "2", - 0x3 => "3", - 0x4 => "4", - 0x5 => "5", - 0x6 => "6", - 0x7 => "7", - 0x8 => "8", - 0x9 => "9", - 0xA => "A", - 0xB => "B", - 0xC => "C", - 0xD => "D", - 0xE => "E", - 0xF => "F", - 0x10 => "G", - 0x11 => "H", - 0x12 => "I", - 0x13 => "J", - 0x14 => "K", - 0x15 => "L", - 0x16 => "M", - 0x17 => "N", - 0x18 => "O", - 0x19 => "P", - 0x1A => "Q", - 0x1B => "R", - 0x1C => "S", - 0x1D => "T", - 0x1E => "U", - 0x1F => "V", - 0x20 => "W", - 0x21 => "X", - 0x22 => "Y", - 0x23 => "Z", - 0x24 => "a", - 0x25 => "b", - 0x26 => "c", - 0x27 => "d", - 0x28 => "e", - 0x29 => "f", - 0x2A => "g", - 0x2B => "h", - 0x2C => "i", - 0x2D => "j", - 0x2E => "k", - 0x2F => "l", - 0x30 => "m", - 0x31 => "n", - 0x32 => "o", - 0x33 => "p", - 0x34 => "q", - 0x35 => "r", - 0x36 => "s", - 0x37 => "t", - 0x38 => "u", - 0x39 => "v", - 0x3A => "w", - 0x3B => "x", - 0x3C => "y", - 0x3D => "z", - 0x3E => "'", - 0x3F => ".", - 0x50 => "↑", - 0x51 => "↓", - 0x52 => "←", - 0x53 => "→", - 0x54 => "[A]", - 0x55 => "[B]", - 0x56 => "[C]", - 0x57 => "[Z]", - 0x58 => "[R]", - 0x6F => ",", - 0xD0 => "/", - 0xD1 => "the", - 0xD2 => "you", - 0x9E => " ", - 0x9F => "-", - 0xE0 => "{starsleft}", - 0xE1 => "(", - 0xE2 => ")(", - 0xE3 => ")", - 0xE4 => "+", - 0xE5 => "&", - 0xE6 => ":", - 0xF2 => "!", - 0xF4 => "?", - 0xF5 => AutoDetectStartEndQuotationMarks ? "\"" : "{sqm}", - 0xF6 => AutoDetectStartEndQuotationMarks ? "\"" : "{eqm}", - 0xF7 => "~", - 0xF9 => "$", - 0xFA => "★", - 0xFB => "[x]", - 0xFC => "•", - 0xFD => "☆", - 0xFE => Environment.NewLine, - 0xFF => null, - _ => null, - }; + 0x0 => "0", + 0x1 => "1", + 0x2 => "2", + 0x3 => "3", + 0x4 => "4", + 0x5 => "5", + 0x6 => "6", + 0x7 => "7", + 0x8 => "8", + 0x9 => "9", + 0xA => "A", + 0xB => "B", + 0xC => "C", + 0xD => "D", + 0xE => "E", + 0xF => "F", + 0x10 => "G", + 0x11 => "H", + 0x12 => "I", + 0x13 => "J", + 0x14 => "K", + 0x15 => "L", + 0x16 => "M", + 0x17 => "N", + 0x18 => "O", + 0x19 => "P", + 0x1A => "Q", + 0x1B => "R", + 0x1C => "S", + 0x1D => "T", + 0x1E => "U", + 0x1F => "V", + 0x20 => "W", + 0x21 => "X", + 0x22 => "Y", + 0x23 => "Z", + 0x24 => "a", + 0x25 => "b", + 0x26 => "c", + 0x27 => "d", + 0x28 => "e", + 0x29 => "f", + 0x2A => "g", + 0x2B => "h", + 0x2C => "i", + 0x2D => "j", + 0x2E => "k", + 0x2F => "l", + 0x30 => "m", + 0x31 => "n", + 0x32 => "o", + 0x33 => "p", + 0x34 => "q", + 0x35 => "r", + 0x36 => "s", + 0x37 => "t", + 0x38 => "u", + 0x39 => "v", + 0x3A => "w", + 0x3B => "x", + 0x3C => "y", + 0x3D => "z", + 0x3E => "'", + 0x3F => ".", + 0x50 => "↑", + 0x51 => "↓", + 0x52 => "←", + 0x53 => "→", + 0x54 => "[A]", + 0x55 => "[B]", + 0x56 => "[C]", + 0x57 => "[Z]", + 0x58 => "[R]", + 0x6F => ",", + 0xD0 => "/", + 0xD1 => "the", + 0xD2 => "you", + 0x9E => " ", + 0x9F => "-", + 0xE0 => "{starsleft}", + 0xE1 => "(", + 0xE2 => ")(", + 0xE3 => ")", + 0xE4 => "+", + 0xE5 => "&", + 0xE6 => ":", + 0xF2 => "!", + 0xF4 => "?", + 0xF5 => AutoDetectStartEndQuotationMarks ? "\"" : "{sqm}", + 0xF6 => AutoDetectStartEndQuotationMarks ? "\"" : "{eqm}", + 0xF7 => "~", + 0xF9 => "$", + 0xFA => "★", + 0xFB => "[x]", + 0xFC => "•", + 0xFD => "☆", + 0xFE => Environment.NewLine, + 0xFF => null, + _ => null, + }; - if (t == null && CharDictionary.TryGetValue(b, out char value)) - t = value.ToString(); + if (t == null && CharDictionary.TryGetValue(b, out char value)) + t = value.ToString(); - if (t != null) - txt += t; - } - - return txt; + if (t != null) + txt += t; } - public override byte[] GetBytes(string s) + return txt; + } + + public override byte[] GetBytes(string s) + { + bool isFirst = true; + var bytes = new List(); + + s = s.Replace("{starsleft}", "€"); + s = s.Replace("you", "²"); + s = s.Replace("the", "³"); + s = s.Replace("[A]", @"\"); + s = s.Replace("[B]", "°"); + s = s.Replace("[C]", "#"); + s = s.Replace("[Z]", "*"); + s = s.Replace("[R]", ";"); + s = s.Replace(")(", "}"); + s = s.Replace("[x]", "{"); + s = s.Replace("{sqm}", "["); + s = s.Replace("{eqm}", "]"); + s = s.Replace(Environment.NewLine, "§"); + + foreach (var ccb in s) { - bool isFirst = true; - var bytes = new List(); - - s = s.Replace("{starsleft}", "€"); - s = s.Replace("you", "²"); - s = s.Replace("the", "³"); - s = s.Replace("[A]", @"\"); - s = s.Replace("[B]", "°"); - s = s.Replace("[C]", "#"); - s = s.Replace("[Z]", "*"); - s = s.Replace("[R]", ";"); - s = s.Replace(")(", "}"); - s = s.Replace("[x]", "{"); - s = s.Replace("{sqm}", "["); - s = s.Replace("{eqm}", "]"); - s = s.Replace(Environment.NewLine, "§"); - - foreach (var ccb in s) + byte? b = ccb switch { - byte? b = ccb switch - { - '0' => 0x0, - '1' => 0x1, - '2' => 0x2, - '3' => 0x3, - '4' => 0x4, - '5' => 0x5, - '6' => 0x6, - '7' => 0x7, - '8' => 0x8, - '9' => 0x9, - 'A' => 0xA, - 'B' => 0xB, - 'C' => 0xC, - 'D' => 0xD, - 'E' => 0xE, - 'F' => 0xF, - 'G' => 0x10, - 'H' => 0x11, - 'I' => 0x12, - 'J' => 0x13, - 'K' => 0x14, - 'L' => 0x15, - 'M' => 0x16, - 'N' => 0x17, - 'O' => 0x18, - 'P' => 0x19, - 'Q' => 0x1A, - 'R' => 0x1B, - 'S' => 0x1C, - 'T' => 0x1D, - 'U' => 0x1E, - 'V' => 0x1F, - 'W' => 0x20, - 'X' => 0x21, - 'Y' => 0x22, - 'Z' => 0x23, - 'a' => 0x24, - 'b' => 0x25, - 'c' => 0x26, - 'd' => 0x27, - 'e' => 0x28, - 'f' => 0x29, - 'g' => 0x2A, - 'h' => 0x2B, - 'i' => 0x2C, - 'j' => 0x2D, - 'k' => 0x2E, - 'l' => 0x2F, - 'm' => 0x30, - 'n' => 0x31, - 'o' => 0x32, - 'p' => 0x33, - 'q' => 0x34, - 'r' => 0x35, - 's' => 0x36, - 't' => 0x37, - 'u' => 0x38, - 'v' => 0x39, - 'w' => 0x3A, - 'x' => 0x3B, - 'y' => 0x3C, - 'z' => 0x3D, - '\'' => 0x3E, - '.' => 0x3F, - '↑' => 0x50, - '↓' => 0x51, - '←' => 0x52, - '→' => 0x53, - '\\' => 0x54, - '°' => 0x55, - '#' => 0x56, - '*' => 0x57, - ';' => 0x58, - ',' => 0x6F, - '/' => 0xD0, - '³' => 0xD1, - '²' => 0xD2, - ' ' => 0x9E, - '-' => 0x9F, - '€' => 0xE0, - '(' => 0xE1, - '}' => 0xE2, - ')' => 0xE3, - '+' => 0xE4, - '&' => 0xE5, - ':' => 0xE6, - '!' => 0xF2, - '?' => 0xF4, - '[' => 0xF5, - ']' => 0xF6, - '~' => 0xF7, - '$' => 0xF9, - '★' => 0xFA, - '{' => 0xFB, - '•' => 0xFC, - '☆' => 0xFD, - '§' => 0xFE, - _ => null, - }; + '0' => 0x0, + '1' => 0x1, + '2' => 0x2, + '3' => 0x3, + '4' => 0x4, + '5' => 0x5, + '6' => 0x6, + '7' => 0x7, + '8' => 0x8, + '9' => 0x9, + 'A' => 0xA, + 'B' => 0xB, + 'C' => 0xC, + 'D' => 0xD, + 'E' => 0xE, + 'F' => 0xF, + 'G' => 0x10, + 'H' => 0x11, + 'I' => 0x12, + 'J' => 0x13, + 'K' => 0x14, + 'L' => 0x15, + 'M' => 0x16, + 'N' => 0x17, + 'O' => 0x18, + 'P' => 0x19, + 'Q' => 0x1A, + 'R' => 0x1B, + 'S' => 0x1C, + 'T' => 0x1D, + 'U' => 0x1E, + 'V' => 0x1F, + 'W' => 0x20, + 'X' => 0x21, + 'Y' => 0x22, + 'Z' => 0x23, + 'a' => 0x24, + 'b' => 0x25, + 'c' => 0x26, + 'd' => 0x27, + 'e' => 0x28, + 'f' => 0x29, + 'g' => 0x2A, + 'h' => 0x2B, + 'i' => 0x2C, + 'j' => 0x2D, + 'k' => 0x2E, + 'l' => 0x2F, + 'm' => 0x30, + 'n' => 0x31, + 'o' => 0x32, + 'p' => 0x33, + 'q' => 0x34, + 'r' => 0x35, + 's' => 0x36, + 't' => 0x37, + 'u' => 0x38, + 'v' => 0x39, + 'w' => 0x3A, + 'x' => 0x3B, + 'y' => 0x3C, + 'z' => 0x3D, + '\'' => 0x3E, + '.' => 0x3F, + '↑' => 0x50, + '↓' => 0x51, + '←' => 0x52, + '→' => 0x53, + '\\' => 0x54, + '°' => 0x55, + '#' => 0x56, + '*' => 0x57, + ';' => 0x58, + ',' => 0x6F, + '/' => 0xD0, + '³' => 0xD1, + '²' => 0xD2, + ' ' => 0x9E, + '-' => 0x9F, + '€' => 0xE0, + '(' => 0xE1, + '}' => 0xE2, + ')' => 0xE3, + '+' => 0xE4, + '&' => 0xE5, + ':' => 0xE6, + '!' => 0xF2, + '?' => 0xF4, + '[' => 0xF5, + ']' => 0xF6, + '~' => 0xF7, + '$' => 0xF9, + '★' => 0xFA, + '{' => 0xFB, + '•' => 0xFC, + '☆' => 0xFD, + '§' => 0xFE, + _ => null, + }; - if (b == null && ccb == '\"') + if (b == null && ccb == '\"') + { + if (isFirst) { - if (isFirst) - { - b = 0xF5; - isFirst = false; - } - else - { - b = 0xF6; - isFirst = true; - } + b = 0xF5; + isFirst = false; + } + else + { + b = 0xF6; + isFirst = true; } - - if (b == null && CharDictionary.FirstOrDefault(n => n.Value == ccb) is KeyValuePair kvp) - b = kvp.Key; - - if (b != null) - bytes.Add(b.Value); } - bytes.Add(0xFF); + if (b == null && CharDictionary.FirstOrDefault(n => n.Value == ccb) is KeyValuePair kvp) + b = kvp.Key; - return [.. bytes]; + if (b != null) + bytes.Add(b.Value); } - public override int GetByteCount(char[] chars, int index, int count) - { - char[] myChars = (char[])chars.Skip(index).Take(count); - var nbytes = GetBytes(new string(myChars)); - return nbytes.Length; - } + bytes.Add(0xFF); - public override int GetBytes(char[] chars, int charIndex, int charCount, byte[] bytes, int byteIndex) - { - char[] myChars = (char[])chars.Skip(charIndex).Take(charCount); - var nbytes = GetBytes(new string(myChars)); - int bytesToCopy = Math.Min(nbytes.Length, bytes.Length - byteIndex); - for (int i = 0, loopTo = bytesToCopy - 1; i <= loopTo; i++) - bytes[i + byteIndex] = nbytes[i]; - return bytesToCopy; - } + return [.. bytes]; + } - public override int GetCharCount(byte[] bytes, int index, int count) - { - byte[] myBytes = (byte[])bytes.Skip(index).Take(count); - string nstring = GetString(myBytes); - return nstring.Length; - } + public override int GetByteCount(char[] chars, int index, int count) + { + char[] myChars = (char[])chars.Skip(index).Take(count); + var nbytes = GetBytes(new string(myChars)); + return nbytes.Length; + } - public override int GetChars(byte[] bytes, int byteIndex, int byteCount, char[] chars, int charIndex) - { - byte[] myBytes = (byte[])bytes.Skip(byteIndex).Take(byteCount); - string nstring = GetString(myBytes); - int charsToCopy = Math.Min(nstring.Length, chars.Length - charIndex); - for (int i = 0, loopTo = charsToCopy; i <= loopTo; i++) - chars[i + charIndex] = nstring[i]; - return charsToCopy; - } + public override int GetBytes(char[] chars, int charIndex, int charCount, byte[] bytes, int byteIndex) + { + char[] myChars = (char[])chars.Skip(charIndex).Take(charCount); + var nbytes = GetBytes(new string(myChars)); + int bytesToCopy = Math.Min(nbytes.Length, bytes.Length - byteIndex); + for (int i = 0, loopTo = bytesToCopy - 1; i <= loopTo; i++) + bytes[i + byteIndex] = nbytes[i]; + return bytesToCopy; + } - public override int GetMaxByteCount(int charCount) - { - throw new NotSupportedException(); - } + public override int GetCharCount(byte[] bytes, int index, int count) + { + byte[] myBytes = (byte[])bytes.Skip(index).Take(count); + string nstring = GetString(myBytes); + return nstring.Length; + } - public override int GetMaxCharCount(int byteCount) - { - throw new NotSupportedException(); - } + public override int GetChars(byte[] bytes, int byteIndex, int byteCount, char[] chars, int charIndex) + { + byte[] myBytes = (byte[])bytes.Skip(byteIndex).Take(byteCount); + string nstring = GetString(myBytes); + int charsToCopy = Math.Min(nstring.Length, chars.Length - charIndex); + for (int i = 0, loopTo = charsToCopy; i <= loopTo; i++) + chars[i + charIndex] = nstring[i]; + return charsToCopy; + } + + public override int GetMaxByteCount(int charCount) + { + throw new NotSupportedException(); + } + + public override int GetMaxCharCount(int byteCount) + { + throw new NotSupportedException(); } } \ No newline at end of file diff --git a/SM64Lib/Text/Profiles/TextArrayGroupInfo.cs b/SM64Lib/Text/Profiles/TextArrayGroupInfo.cs index 1749b1b..59a4407 100644 --- a/SM64Lib/Text/Profiles/TextArrayGroupInfo.cs +++ b/SM64Lib/Text/Profiles/TextArrayGroupInfo.cs @@ -1,9 +1,8 @@ using System.Collections.Generic; -namespace SM64Lib.Text.Profiles +namespace SM64Lib.Text.Profiles; + +public class TextArrayGroupInfo : TextGroupInfo { - public class TextArrayGroupInfo : TextGroupInfo - { - public List Texts { get; set; } = new List(); - } + public List Texts { get; set; } = new List(); } \ No newline at end of file diff --git a/SM64Lib/Text/Profiles/TextArrayItemInfo.cs b/SM64Lib/Text/Profiles/TextArrayItemInfo.cs index 0236c2e..c26c52c 100644 --- a/SM64Lib/Text/Profiles/TextArrayItemInfo.cs +++ b/SM64Lib/Text/Profiles/TextArrayItemInfo.cs @@ -1,9 +1,8 @@  -namespace SM64Lib.Text.Profiles +namespace SM64Lib.Text.Profiles; + +public class TextArrayItemInfo { - public class TextArrayItemInfo - { - public int RomAddress { get; set; } - public int MaxLength { get; set; } - } + public int RomAddress { get; set; } + public int MaxLength { get; set; } } \ No newline at end of file diff --git a/SM64Lib/Text/Profiles/TextGroupInfo.cs b/SM64Lib/Text/Profiles/TextGroupInfo.cs index 5a93d0c..4f0fb8e 100644 --- a/SM64Lib/Text/Profiles/TextGroupInfo.cs +++ b/SM64Lib/Text/Profiles/TextGroupInfo.cs @@ -1,57 +1,56 @@ -using System.Linq; -using global::Newtonsoft.Json; +using global::Newtonsoft.Json; +using System.Linq; -namespace SM64Lib.Text.Profiles +namespace SM64Lib.Text.Profiles; + +public abstract class TextGroupInfo { - public abstract class TextGroupInfo + public const string ENCODING_STRING_M64 = "m64"; + public const string ENCODING_STRING_ASCII = "ascii"; + [JsonProperty("Encoding")] + private string myTextEncoding; + + public string Name { get; set; } + + [JsonIgnore] + public System.Text.Encoding Encoding { - public const string ENCODING_STRING_M64 = "m64"; - public const string ENCODING_STRING_ASCII = "ascii"; - [JsonProperty("Encoding")] - private string myTextEncoding; - - public string Name { get; set; } - - [JsonIgnore] - public System.Text.Encoding Encoding + get { - get + var switchExpr = myTextEncoding; + switch (switchExpr) { - var switchExpr = myTextEncoding; - switch (switchExpr) - { - case ENCODING_STRING_ASCII: - { - return System.Text.Encoding.ASCII; - } + case ENCODING_STRING_ASCII: + { + return System.Text.Encoding.ASCII; + } - case ENCODING_STRING_M64: - { - return M64TextEncoding.M64Text; - } + case ENCODING_STRING_M64: + { + return M64TextEncoding.M64Text; + } - default: - { - return null; - } - } + default: + { + return null; + } } } + } - [JsonIgnore] - public string EncodingString + [JsonIgnore] + public string EncodingString + { + get { - get - { - return myTextEncoding; - } + return myTextEncoding; + } - set + set + { + if (new[] { ENCODING_STRING_M64, ENCODING_STRING_ASCII }.Contains(value)) { - if (new[] { ENCODING_STRING_M64, ENCODING_STRING_ASCII }.Contains(value)) - { - myTextEncoding = value; - } + myTextEncoding = value; } } } diff --git a/SM64Lib/Text/Profiles/TextProfileInfo.cs b/SM64Lib/Text/Profiles/TextProfileInfo.cs index 000dca0..e5badbc 100644 --- a/SM64Lib/Text/Profiles/TextProfileInfo.cs +++ b/SM64Lib/Text/Profiles/TextProfileInfo.cs @@ -1,58 +1,56 @@ -using System; +using global::Newtonsoft.Json; +using Newtonsoft.Json.Linq; using System.Collections.Generic; using System.IO; using System.Linq; -using global::Newtonsoft.Json; -using Newtonsoft.Json.Linq; -namespace SM64Lib.Text.Profiles +namespace SM64Lib.Text.Profiles; + +public class TextProfileInfo { - public class TextProfileInfo + public string Name { get; set; } + public List TextTableGroups { get; set; } = new List(); + public List TextArrayGroups { get; set; } = new List(); + + public TextGroupInfo GetGroup(string name) { - public string Name { get; set; } - public List TextTableGroups { get; set; } = new List(); - public List TextArrayGroups { get; set; } = new List(); + return AllGroups.FirstOrDefault(n => (n.Name ?? "") == (name ?? "")); + } - public TextGroupInfo GetGroup(string name) + [JsonIgnore] + public IEnumerable AllGroups + { + get { - return AllGroups.FirstOrDefault(n => (n.Name ?? "") == (name ?? "")); - } - - [JsonIgnore] - public IEnumerable AllGroups - { - get - { - var list = new List(); - list.AddRange(TextTableGroups.ToArray()); - list.AddRange(TextArrayGroups.ToArray()); - return list; - } - } - - public TextProfileInfo Clone() - { - return JObject.FromObject(this).ToObject(); - } - - public string WriteToString() - { - return JObject.FromObject(this).ToString(); - } - - public void WriteToFile(string filePath) - { - File.WriteAllText(filePath, WriteToString()); - } - - public static TextProfileInfo ReadFromString(string content) - { - return JObject.Parse(content).ToObject(); - } - - public static TextProfileInfo ReadFromFile(string filePath) - { - return ReadFromString(File.ReadAllText(filePath)); + var list = new List(); + list.AddRange(TextTableGroups.ToArray()); + list.AddRange(TextArrayGroups.ToArray()); + return list; } } + + public TextProfileInfo Clone() + { + return JObject.FromObject(this).ToObject(); + } + + public string WriteToString() + { + return JObject.FromObject(this).ToString(); + } + + public void WriteToFile(string filePath) + { + File.WriteAllText(filePath, WriteToString()); + } + + public static TextProfileInfo ReadFromString(string content) + { + return JObject.Parse(content).ToObject(); + } + + public static TextProfileInfo ReadFromFile(string filePath) + { + return ReadFromString(File.ReadAllText(filePath)); + } } \ No newline at end of file diff --git a/SM64Lib/Text/Profiles/TextTableDataInfo.cs b/SM64Lib/Text/Profiles/TextTableDataInfo.cs index af35234..7f79901 100644 --- a/SM64Lib/Text/Profiles/TextTableDataInfo.cs +++ b/SM64Lib/Text/Profiles/TextTableDataInfo.cs @@ -1,11 +1,10 @@  -namespace SM64Lib.Text.Profiles +namespace SM64Lib.Text.Profiles; + +public class TextTableDataInfo { - public class TextTableDataInfo - { - public int TableRomOffset { get; set; } - public int TableMaxItems { get; set; } - public int DataRomOffset { get; set; } - public int DataMaxSize { get; set; } - } + public int TableRomOffset { get; set; } + public int TableMaxItems { get; set; } + public int DataRomOffset { get; set; } + public int DataMaxSize { get; set; } } \ No newline at end of file diff --git a/SM64Lib/Text/Profiles/TextTableDialogDataInfo.cs b/SM64Lib/Text/Profiles/TextTableDialogDataInfo.cs index ae7cf79..a777cad 100644 --- a/SM64Lib/Text/Profiles/TextTableDialogDataInfo.cs +++ b/SM64Lib/Text/Profiles/TextTableDialogDataInfo.cs @@ -1,10 +1,9 @@  -namespace SM64Lib.Text.Profiles +namespace SM64Lib.Text.Profiles; + +public class TextTableDialogDataInfo { - public class TextTableDialogDataInfo - { - public int TableRomOffset { get; set; } - public int SoundEffectTable { get; set; } = -1; - public bool HasSoundEffects { get; set; } = false; - } + public int TableRomOffset { get; set; } + public int SoundEffectTable { get; set; } = -1; + public bool HasSoundEffects { get; set; } = false; } \ No newline at end of file diff --git a/SM64Lib/Text/Profiles/TextTableGroupInfo.cs b/SM64Lib/Text/Profiles/TextTableGroupInfo.cs index 798e2d5..15af3ef 100644 --- a/SM64Lib/Text/Profiles/TextTableGroupInfo.cs +++ b/SM64Lib/Text/Profiles/TextTableGroupInfo.cs @@ -6,53 +6,53 @@ using System.Collections.Generic; using System.IO; using System.Linq; -namespace SM64Lib.Text.Profiles -{ - public class TextTableGroupInfo : TextGroupInfo - { - public TextTableSegmentedInfo Segmented { get; set; } = new TextTableSegmentedInfo(); - public TextTableDataInfo Data { get; set; } = new TextTableDataInfo(); - public TextTableDialogDataInfo DialogData { get; set; } = new TextTableDialogDataInfo(); - [JsonIgnore] [Browsable(false)] - public List ItemDescriptionsList { get; set; } = new List(); +namespace SM64Lib.Text.Profiles; - [Editor(typeof(MultilineStringEditor), typeof(UITypeEditor))] - public string ItemDescriptions +public class TextTableGroupInfo : TextGroupInfo +{ + public TextTableSegmentedInfo Segmented { get; set; } = new TextTableSegmentedInfo(); + public TextTableDataInfo Data { get; set; } = new TextTableDataInfo(); + public TextTableDialogDataInfo DialogData { get; set; } = new TextTableDialogDataInfo(); + [JsonIgnore] + [Browsable(false)] + public List ItemDescriptionsList { get; set; } = new List(); + + [Editor(typeof(MultilineStringEditor), typeof(UITypeEditor))] + public string ItemDescriptions + { + get { - get + if (!ItemDescriptionsList.Any()) + return string.Empty; + else { - if (!ItemDescriptionsList.Any()) - return string.Empty; - else - { - var sw = new StringWriter(); - foreach (var str in ItemDescriptionsList) - sw.WriteLine(str); - return sw.ToString().Trim(); - } - } - set - { - ItemDescriptionsList.Clear(); - if (!string.IsNullOrEmpty(value)) - { - var sr = new StringReader(value); - while (sr.Peek() != -1) - { - string line = sr.ReadLine(); - if (!string.IsNullOrEmpty(line)) - ItemDescriptionsList.Add(line); - } - } + var sw = new StringWriter(); + foreach (var str in ItemDescriptionsList) + sw.WriteLine(str); + return sw.ToString().Trim(); } } - - public TextTableType TableType + set { - get + ItemDescriptionsList.Clear(); + if (!string.IsNullOrEmpty(value)) { - return DialogData.TableRomOffset == 0 ? TextTableType.Default : TextTableType.Dialogs; + var sr = new StringReader(value); + while (sr.Peek() != -1) + { + string line = sr.ReadLine(); + if (!string.IsNullOrEmpty(line)) + ItemDescriptionsList.Add(line); + } } } } + + public TextTableType TableType + { + get + { + return DialogData.TableRomOffset == 0 ? TextTableType.Default : TextTableType.Dialogs; + } + } } \ No newline at end of file diff --git a/SM64Lib/Text/Profiles/TextTableSegmentedInfo.cs b/SM64Lib/Text/Profiles/TextTableSegmentedInfo.cs index 495b5b6..1bf43c6 100644 --- a/SM64Lib/Text/Profiles/TextTableSegmentedInfo.cs +++ b/SM64Lib/Text/Profiles/TextTableSegmentedInfo.cs @@ -1,9 +1,8 @@  -namespace SM64Lib.Text.Profiles +namespace SM64Lib.Text.Profiles; + +public class TextTableSegmentedInfo { - public class TextTableSegmentedInfo - { - public uint BankAddress { get; set; } - public int BankStartRom { get; set; } - } + public uint BankAddress { get; set; } + public int BankStartRom { get; set; } } \ No newline at end of file diff --git a/SM64Lib/Text/Profiles/TextTableType.cs b/SM64Lib/Text/Profiles/TextTableType.cs index 99a4725..d0a8fe7 100644 --- a/SM64Lib/Text/Profiles/TextTableType.cs +++ b/SM64Lib/Text/Profiles/TextTableType.cs @@ -1,9 +1,8 @@  -namespace SM64Lib.Text.Profiles +namespace SM64Lib.Text.Profiles; + +public enum TextTableType { - public enum TextTableType - { - Default, - Dialogs - } + Default, + Dialogs } \ No newline at end of file diff --git a/SM64Lib/Text/TextArrayGroup.cs b/SM64Lib/Text/TextArrayGroup.cs index 2d0cf7e..1845058 100644 --- a/SM64Lib/Text/TextArrayGroup.cs +++ b/SM64Lib/Text/TextArrayGroup.cs @@ -1,83 +1,82 @@ -using System; -using System.Collections.Generic; -using global::SM64Lib.Data; +using global::SM64Lib.Data; using global::SM64Lib.Text.Profiles; +using System; +using System.Collections.Generic; -namespace SM64Lib.Text +namespace SM64Lib.Text; + +public class TextArrayGroup : TextGroup { - public class TextArrayGroup : TextGroup + public new TextArrayItem this[int index] { - public new TextArrayItem this[int index] + get { - get + return (TextArrayItem)base[index]; + } + } + + public new TextArrayGroupInfo TextGroupInfo + { + get + { + return (TextArrayGroupInfo)base.TextGroupInfo; + } + } + + public TextArrayGroup(TextArrayGroupInfo groupInfo) : base(groupInfo) + { + } + + public override void Read(BinaryData data) + { + foreach (TextArrayItemInfo info in TextGroupInfo.Texts) + Add(GetTextItem(data, info)); + } + + private TextArrayItem GetTextItem(BinaryData data, TextArrayItemInfo info) + { + byte tempByte = 0; + var byteBuffer = new List(); + bool ende = false; + data.Position = info.RomAddress; + while (!ende) + { + tempByte = data.ReadByte(); + byteBuffer.Add(tempByte); + if (byteBuffer.Count >= info.MaxLength || TextGroupInfo.Encoding == M64TextEncoding.M64Text && tempByte == 0xFF) { - return (TextArrayItem)base[index]; + ende = true; } } - public new TextArrayGroupInfo TextGroupInfo - { - get - { - return (TextArrayGroupInfo)base.TextGroupInfo; - } - } + var newItem = new TextArrayItem(byteBuffer.ToArray(), TextGroupInfo, info); + byteBuffer.Clear(); + return newItem; + } - public TextArrayGroup(TextArrayGroupInfo groupInfo) : base(groupInfo) + public override void Save(BinaryData data) + { + foreach (TextArrayItem item in this) { - } - - public override void Read(BinaryData data) - { - foreach (TextArrayItemInfo info in TextGroupInfo.Texts) - Add(GetTextItem(data, info)); - } - - private TextArrayItem GetTextItem(BinaryData data, TextArrayItemInfo info) - { - byte tempByte = 0; - var byteBuffer = new List(); - bool ende = false; - data.Position = info.RomAddress; - while (!ende) - { - tempByte = data.ReadByte(); - byteBuffer.Add(tempByte); - if (byteBuffer.Count >= info.MaxLength || TextGroupInfo.Encoding == M64TextEncoding.M64Text && tempByte == 0xFF) - { - ende = true; - } - } - - var newItem = new TextArrayItem(byteBuffer.ToArray(), TextGroupInfo, info); - byteBuffer.Clear(); - return newItem; - } - - public override void Save(BinaryData data) - { - foreach (TextArrayItem item in this) - { - data.Position = item.ItemInfo.RomAddress; - WriteTextItem(data, item); - } - } - - private void WriteTextItem(BinaryData data, TextArrayItem item) - { - int i = 0; - int loopTo = Math.Min(item.Data.Length, item.ItemInfo.MaxLength) - 1; - int loopToMax = item.ItemInfo.MaxLength - 1; data.Position = item.ItemInfo.RomAddress; - - for (; i <= loopTo; i++) - data.WriteByte(item.Data[i]); + WriteTextItem(data, item); + } + } - if (item.TextGroupInfo.Encoding == System.Text.Encoding.ASCII) - { - for (; i <= loopToMax; i++) - data.WriteByte(0x20); - } + private void WriteTextItem(BinaryData data, TextArrayItem item) + { + int i = 0; + int loopTo = Math.Min(item.Data.Length, item.ItemInfo.MaxLength) - 1; + int loopToMax = item.ItemInfo.MaxLength - 1; + data.Position = item.ItemInfo.RomAddress; + + for (; i <= loopTo; i++) + data.WriteByte(item.Data[i]); + + if (item.TextGroupInfo.Encoding == System.Text.Encoding.ASCII) + { + for (; i <= loopToMax; i++) + data.WriteByte(0x20); } } } diff --git a/SM64Lib/Text/TextArrayItem.cs b/SM64Lib/Text/TextArrayItem.cs index 02f4331..fa498c8 100644 --- a/SM64Lib/Text/TextArrayItem.cs +++ b/SM64Lib/Text/TextArrayItem.cs @@ -1,28 +1,27 @@ using global::SM64Lib.Text.Profiles; -namespace SM64Lib.Text +namespace SM64Lib.Text; + +public class TextArrayItem : TextItem { - public class TextArrayItem : TextItem + public TextArrayItemInfo ItemInfo { get; private set; } + + public new TextArrayGroupInfo TextGroupInfo { - public TextArrayItemInfo ItemInfo { get; private set; } - - public new TextArrayGroupInfo TextGroupInfo + get { - get - { - return (TextArrayGroupInfo)base.TextGroupInfo; - } + return (TextArrayGroupInfo)base.TextGroupInfo; } + } - public TextArrayItem(byte[] bytes, TextArrayGroupInfo groupInfo, TextArrayItemInfo info) : base(bytes, groupInfo) + public TextArrayItem(byte[] bytes, TextArrayGroupInfo groupInfo, TextArrayItemInfo info) : base(bytes, groupInfo) + { + ItemInfo = info; + + // Remove empty chars at the end of ascii text + if (groupInfo.Encoding == System.Text.Encoding.ASCII) { - ItemInfo = info; - - // Remove empty chars at the end of ascii text - if (groupInfo.Encoding == System.Text.Encoding.ASCII) - { - Text = Text.TrimEnd(); - } + Text = Text.TrimEnd(); } } } \ No newline at end of file diff --git a/SM64Lib/Text/TextGroup.cs b/SM64Lib/Text/TextGroup.cs index 5777adc..9491d8e 100644 --- a/SM64Lib/Text/TextGroup.cs +++ b/SM64Lib/Text/TextGroup.cs @@ -1,31 +1,30 @@ -using System.Collections.Generic; -using global::SM64Lib.Data; +using global::SM64Lib.Data; using global::SM64Lib.Text.Profiles; +using System.Collections.Generic; -namespace SM64Lib.Text +namespace SM64Lib.Text; + +public abstract class TextGroup : List { - public abstract class TextGroup : List + public bool NeedToSave { get; set; } = false; + public TextGroupInfo TextGroupInfo { get; private set; } + + public int DataLength { - public bool NeedToSave { get; set; } = false; - public TextGroupInfo TextGroupInfo { get; private set; } - - public int DataLength + get { - get - { - int count = 0; - foreach (TextItem item in this) - count += item.Data.Length; - return count; - } + int count = 0; + foreach (TextItem item in this) + count += item.Data.Length; + return count; } - - public TextGroup(TextGroupInfo groupInfo) - { - TextGroupInfo = groupInfo; - } - - public abstract void Read(BinaryData data); - public abstract void Save(BinaryData data); } + + public TextGroup(TextGroupInfo groupInfo) + { + TextGroupInfo = groupInfo; + } + + public abstract void Read(BinaryData data); + public abstract void Save(BinaryData data); } \ No newline at end of file diff --git a/SM64Lib/Text/TextItem.cs b/SM64Lib/Text/TextItem.cs index 7410dea..b2170cb 100644 --- a/SM64Lib/Text/TextItem.cs +++ b/SM64Lib/Text/TextItem.cs @@ -1,29 +1,28 @@ using global::SM64Lib.Text.Profiles; -namespace SM64Lib.Text +namespace SM64Lib.Text; + +public abstract class TextItem { - public abstract class TextItem + public byte[] Data { get; private set; } + public TextGroupInfo TextGroupInfo { get; private set; } + + public string Text { - public byte[] Data { get; private set; } - public TextGroupInfo TextGroupInfo { get; private set; } - - public string Text + get { - get - { - return TextGroupInfo.Encoding.GetString(Data); - } - - set - { - Data = TextGroupInfo.Encoding.GetBytes(value); - } + return TextGroupInfo.Encoding.GetString(Data); } - public TextItem(byte[] bytes, TextGroupInfo groupInfo) + set { - TextGroupInfo = groupInfo; - Data = bytes; + Data = TextGroupInfo.Encoding.GetBytes(value); } } + + public TextItem(byte[] bytes, TextGroupInfo groupInfo) + { + TextGroupInfo = groupInfo; + Data = bytes; + } } \ No newline at end of file diff --git a/SM64Lib/Text/TextTableDialogItem.cs b/SM64Lib/Text/TextTableDialogItem.cs index 0322a6b..71df3e1 100644 --- a/SM64Lib/Text/TextTableDialogItem.cs +++ b/SM64Lib/Text/TextTableDialogItem.cs @@ -1,17 +1,16 @@ using global::SM64Lib.Text.Profiles; -namespace SM64Lib.Text -{ - public class TextTableDialogItem : TextTableItem - { - public int LinesPerSite { get; set; } = 4; - public DialogVerticalPosition VerticalPosition { get; set; } = DialogVerticalPosition.Centred; - public DialogHorizontalPosition HorizontalPosition { get; set; } = DialogHorizontalPosition.Middle; - public DialogSoundEffect SoundEffect { get; set; } = DialogSoundEffect.Sign; - public byte UnknownValue { get; set; } = 0; +namespace SM64Lib.Text; - public TextTableDialogItem(byte[] bytes, TextTableGroupInfo info) : base(bytes, info) - { - } +public class TextTableDialogItem : TextTableItem +{ + public int LinesPerSite { get; set; } = 4; + public DialogVerticalPosition VerticalPosition { get; set; } = DialogVerticalPosition.Centred; + public DialogHorizontalPosition HorizontalPosition { get; set; } = DialogHorizontalPosition.Middle; + public DialogSoundEffect SoundEffect { get; set; } = DialogSoundEffect.Sign; + public byte UnknownValue { get; set; } = 0; + + public TextTableDialogItem(byte[] bytes, TextTableGroupInfo info) : base(bytes, info) + { } } \ No newline at end of file diff --git a/SM64Lib/Text/TextTableGroup.cs b/SM64Lib/Text/TextTableGroup.cs index ba1f484..ab1e8f4 100644 --- a/SM64Lib/Text/TextTableGroup.cs +++ b/SM64Lib/Text/TextTableGroup.cs @@ -1,209 +1,207 @@ -using System.Collections.Generic; -using System.Linq; -using Microsoft.VisualBasic.CompilerServices; -using global::SM64Lib.Data; +using global::SM64Lib.Data; using global::SM64Lib.Text.Profiles; using System; +using System.Collections.Generic; +using System.Linq; -namespace SM64Lib.Text +namespace SM64Lib.Text; + +public class TextTableGroup : TextGroup { - public class TextTableGroup : TextGroup + public new TextTableItem this[int index] { - public new TextTableItem this[int index] + get { - get - { - return (TextTableItem)base[index]; - } + return (TextTableItem)base[index]; } + } - public new TextTableGroupInfo TextGroupInfo + public new TextTableGroupInfo TextGroupInfo + { + get { - get - { - return (TextTableGroupInfo)base.TextGroupInfo; - } + return (TextTableGroupInfo)base.TextGroupInfo; } + } - public TextTableGroup(TextTableGroupInfo groupInfo) : base(groupInfo) - { - } + public TextTableGroup(TextTableGroupInfo groupInfo) : base(groupInfo) + { + } - public override void Read(BinaryData data) + public override void Read(BinaryData data) + { + uint BankRamStart, BankRomStart; + BankRamStart = TextGroupInfo.Segmented.BankAddress; + BankRomStart = Convert.ToUInt32(TextGroupInfo.Segmented.BankStartRom); + if (TextGroupInfo.TableType == TextTableType.Dialogs) { - uint BankRamStart, BankRomStart; - BankRamStart = TextGroupInfo.Segmented.BankAddress; - BankRomStart = Convert.ToUInt32(TextGroupInfo.Segmented.BankStartRom); - if (TextGroupInfo.TableType == TextTableType.Dialogs) + data.Position = TextGroupInfo.Data.TableRomOffset; + for (int i = 0; i < TextGroupInfo.Data.TableMaxItems; i++) { - data.Position = TextGroupInfo.Data.TableRomOffset; - for (int i = 0; i < TextGroupInfo.Data.TableMaxItems; i++) + int entryPointer = (int)(data.ReadInt32() - BankRamStart + BankRomStart); + int lastPos = Convert.ToInt32(data.Position); + + data.Position = entryPointer; + data.Position = entryPointer + 12; + + int addr = data.ReadInt32(); + if (addr != 0) { - int entryPointer = (int)(data.ReadInt32() - BankRamStart + BankRomStart); - int lastPos = Convert.ToInt32(data.Position); + var bytes = GetTextData(data, (int)(addr - BankRamStart + BankRomStart), true); + var newItem = new TextTableDialogItem(bytes, TextGroupInfo); + data.Position = entryPointer + 0x3; - data.Position = entryPointer; - data.Position = entryPointer + 12; + // The unknown value + newItem.UnknownValue = data.ReadByte(); - int addr = data.ReadInt32(); - if (addr != 0) - { - var bytes = GetTextData(data, (int)(addr - BankRamStart + BankRomStart), true); - var newItem = new TextTableDialogItem(bytes, TextGroupInfo); - data.Position = entryPointer + 0x3; + // Lines per Site + newItem.LinesPerSite = data.ReadByte(); - // The unknown value - newItem.UnknownValue = data.ReadByte(); + data.Position += 1; - // Lines per Site - newItem.LinesPerSite = data.ReadByte(); + // Position + newItem.VerticalPosition = (DialogVerticalPosition)data.ReadInt16(); + newItem.HorizontalPosition = (DialogHorizontalPosition)data.ReadInt16(); - data.Position += 1; + data.Position += 6; - // Position - newItem.VerticalPosition = (DialogVerticalPosition)data.ReadInt16(); - newItem.HorizontalPosition = (DialogHorizontalPosition)data.ReadInt16(); - - data.Position += 6; - - // Sound effect - if (TextGroupInfo.DialogData.HasSoundEffects && TextGroupInfo.DialogData.SoundEffectTable != -1) - { - data.Position = TextGroupInfo.DialogData.SoundEffectTable + i; - newItem.SoundEffect = (DialogSoundEffect)data.ReadByte(); - } - - // Add item - Add(newItem); - - data.Position = lastPos; - } - } - } - else - { - data.Position = TextGroupInfo.Data.TableRomOffset; - for (int i = 1, loopTo1 = TextGroupInfo.Data.TableMaxItems; i <= loopTo1; i++) - { - uint addrInROM = data.ReadUInt32(); - if (addrInROM != (long)0) - { - var bytes = GetTextData(data, (int)(addrInROM - BankRamStart + BankRomStart)); - Add(new TextTableItem(bytes, TextGroupInfo)); - } - } - } - } - - private byte[] GetTextData(BinaryData data, int RomAddress, bool EnableDialogParameters = false) - { - int lastPos = 0; - byte tempByte = 0; - var byteBuffer = new List(); - lastPos = Convert.ToInt32(data.Position); - data.Position = RomAddress; - do - { - tempByte = data.ReadByte(); - byteBuffer.Add(tempByte); - if (tempByte == 0xFF) - break; - } - while (true); - data.Position = lastPos; - return byteBuffer.ToArray(); - } - - public override void Save(BinaryData data) - { - int DataRomOffset, lastTableOffset, lastTable2Offset; - uint BankRomStart, BankRamStart; - - lastTableOffset = TextGroupInfo.Data.TableRomOffset; - DataRomOffset = TextGroupInfo.Data.DataRomOffset; - BankRamStart = TextGroupInfo.Segmented.BankAddress; - BankRomStart = Convert.ToUInt32(TextGroupInfo.Segmented.BankStartRom); - - if (TextGroupInfo.TableType == TextTableType.Dialogs) - { - lastTable2Offset = (int)TextGroupInfo.DialogData?.TableRomOffset; - for (int i = 0; i < Count; i++) - { - TextTableDialogItem textitem = (TextTableDialogItem)this.ElementAtOrDefault(i); - - // Table 1 - data.Position = lastTableOffset; - data.Write(textitem is null ? 0 : Convert.ToInt32(lastTable2Offset - BankRomStart + BankRamStart)); - lastTableOffset += 4; - - // Table 2 (including Dialog Params) - data.Position = lastTable2Offset; - if (textitem is not null) - { - data.Write(Convert.ToInt16(0)); - data.WriteByte(0); - data.WriteByte(textitem.UnknownValue); - data.WriteByte(Convert.ToByte(textitem.LinesPerSite)); - data.WriteByte(0); - data.Write(Convert.ToInt16(textitem.VerticalPosition)); - data.Write(Convert.ToInt16(textitem.HorizontalPosition)); - data.Write(Convert.ToInt16(0)); - data.Write(Convert.ToUInt32(DataRomOffset - BankRomStart + BankRamStart)); - } - else - { - data.Write(Convert.ToInt16(0)); - data.WriteByte(0); - data.WriteByte(0); - data.WriteByte(0); - data.WriteByte(0); - data.Write(Convert.ToInt16(0)); - data.Write(Convert.ToInt16(0)); - data.Write(Convert.ToInt16(0)); - data.Write(Convert.ToUInt32(0)); - } - - lastTable2Offset += 0x10; - - // Text Data - data.Position = DataRomOffset; - if (textitem is not null) - WriteTextItem(data, DataRomOffset, textitem); - DataRomOffset += textitem.Data.Length; - - // Sound Effect + // Sound effect if (TextGroupInfo.DialogData.HasSoundEffects && TextGroupInfo.DialogData.SoundEffectTable != -1) { data.Position = TextGroupInfo.DialogData.SoundEffectTable + i; - data.Write((byte)textitem.SoundEffect); + newItem.SoundEffect = (DialogSoundEffect)data.ReadByte(); } - } - } - else - { - for (int i = 0, loopTo1 = Count - 1; i <= loopTo1; i++) - { - TextTableItem textitem = (TextTableItem)this.ElementAtOrDefault(i); - // Table - data.Position = lastTableOffset; - data.Write(textitem is null ? Convert.ToUInt32(0) : Convert.ToUInt32(DataRomOffset - BankRomStart + BankRamStart)); - lastTableOffset += 4; + // Add item + Add(newItem); - // Text Data - data.Position = DataRomOffset; - if (textitem is not null) - WriteTextItem(data, DataRomOffset, textitem); - DataRomOffset += textitem.Data.Length; + data.Position = lastPos; } } } - - private void WriteTextItem(BinaryData data, int RomAddress, TextTableItem item) + else { - data.Position = RomAddress; - foreach (var b in item.Data) - data.WriteByte(b); + data.Position = TextGroupInfo.Data.TableRomOffset; + for (int i = 1, loopTo1 = TextGroupInfo.Data.TableMaxItems; i <= loopTo1; i++) + { + uint addrInROM = data.ReadUInt32(); + if (addrInROM != (long)0) + { + var bytes = GetTextData(data, (int)(addrInROM - BankRamStart + BankRomStart)); + Add(new TextTableItem(bytes, TextGroupInfo)); + } + } } } + + private byte[] GetTextData(BinaryData data, int RomAddress, bool EnableDialogParameters = false) + { + int lastPos = 0; + byte tempByte = 0; + var byteBuffer = new List(); + lastPos = Convert.ToInt32(data.Position); + data.Position = RomAddress; + do + { + tempByte = data.ReadByte(); + byteBuffer.Add(tempByte); + if (tempByte == 0xFF) + break; + } + while (true); + data.Position = lastPos; + return byteBuffer.ToArray(); + } + + public override void Save(BinaryData data) + { + int DataRomOffset, lastTableOffset, lastTable2Offset; + uint BankRomStart, BankRamStart; + + lastTableOffset = TextGroupInfo.Data.TableRomOffset; + DataRomOffset = TextGroupInfo.Data.DataRomOffset; + BankRamStart = TextGroupInfo.Segmented.BankAddress; + BankRomStart = Convert.ToUInt32(TextGroupInfo.Segmented.BankStartRom); + + if (TextGroupInfo.TableType == TextTableType.Dialogs) + { + lastTable2Offset = (int)TextGroupInfo.DialogData?.TableRomOffset; + for (int i = 0; i < Count; i++) + { + TextTableDialogItem textitem = (TextTableDialogItem)this.ElementAtOrDefault(i); + + // Table 1 + data.Position = lastTableOffset; + data.Write(textitem is null ? 0 : Convert.ToInt32(lastTable2Offset - BankRomStart + BankRamStart)); + lastTableOffset += 4; + + // Table 2 (including Dialog Params) + data.Position = lastTable2Offset; + if (textitem is not null) + { + data.Write(Convert.ToInt16(0)); + data.WriteByte(0); + data.WriteByte(textitem.UnknownValue); + data.WriteByte(Convert.ToByte(textitem.LinesPerSite)); + data.WriteByte(0); + data.Write(Convert.ToInt16(textitem.VerticalPosition)); + data.Write(Convert.ToInt16(textitem.HorizontalPosition)); + data.Write(Convert.ToInt16(0)); + data.Write(Convert.ToUInt32(DataRomOffset - BankRomStart + BankRamStart)); + } + else + { + data.Write(Convert.ToInt16(0)); + data.WriteByte(0); + data.WriteByte(0); + data.WriteByte(0); + data.WriteByte(0); + data.Write(Convert.ToInt16(0)); + data.Write(Convert.ToInt16(0)); + data.Write(Convert.ToInt16(0)); + data.Write(Convert.ToUInt32(0)); + } + + lastTable2Offset += 0x10; + + // Text Data + data.Position = DataRomOffset; + if (textitem is not null) + WriteTextItem(data, DataRomOffset, textitem); + DataRomOffset += textitem.Data.Length; + + // Sound Effect + if (TextGroupInfo.DialogData.HasSoundEffects && TextGroupInfo.DialogData.SoundEffectTable != -1) + { + data.Position = TextGroupInfo.DialogData.SoundEffectTable + i; + data.Write((byte)textitem.SoundEffect); + } + } + } + else + { + for (int i = 0, loopTo1 = Count - 1; i <= loopTo1; i++) + { + TextTableItem textitem = (TextTableItem)this.ElementAtOrDefault(i); + + // Table + data.Position = lastTableOffset; + data.Write(textitem is null ? Convert.ToUInt32(0) : Convert.ToUInt32(DataRomOffset - BankRomStart + BankRamStart)); + lastTableOffset += 4; + + // Text Data + data.Position = DataRomOffset; + if (textitem is not null) + WriteTextItem(data, DataRomOffset, textitem); + DataRomOffset += textitem.Data.Length; + } + } + } + + private void WriteTextItem(BinaryData data, int RomAddress, TextTableItem item) + { + data.Position = RomAddress; + foreach (var b in item.Data) + data.WriteByte(b); + } } \ No newline at end of file diff --git a/SM64Lib/Text/TextTableItem.cs b/SM64Lib/Text/TextTableItem.cs index e5b6c6a..e015e7d 100644 --- a/SM64Lib/Text/TextTableItem.cs +++ b/SM64Lib/Text/TextTableItem.cs @@ -1,19 +1,18 @@ using global::SM64Lib.Text.Profiles; -namespace SM64Lib.Text -{ - public class TextTableItem : TextItem - { - public new TextTableGroupInfo TextGroupInfo - { - get - { - return (TextTableGroupInfo)base.TextGroupInfo; - } - } +namespace SM64Lib.Text; - public TextTableItem(byte[] bytes, TextTableGroupInfo info) : base(bytes, info) +public class TextTableItem : TextItem +{ + public new TextTableGroupInfo TextGroupInfo + { + get { + return (TextTableGroupInfo)base.TextGroupInfo; } } + + public TextTableItem(byte[] bytes, TextTableGroupInfo info) : base(bytes, info) + { + } } \ No newline at end of file diff --git a/SM64Lib/Trajectories/Trajectories.cs b/SM64Lib/Trajectories/Trajectories.cs index c1c5e91..1ab7f9c 100644 --- a/SM64Lib/Trajectories/Trajectories.cs +++ b/SM64Lib/Trajectories/Trajectories.cs @@ -1,282 +1,278 @@ -using System.Collections.Generic; -using global::System.IO; +using SM64Lib.Data; +using System.Collections.Generic; using System.Linq; -using Microsoft.VisualBasic.CompilerServices; -using SM64Lib.Data.System; -using SM64Lib.Data; -namespace SM64Lib.Trajectorys +namespace SM64Lib.Trajectorys; + +public class Trajectories : List { - public class Trajectories : List + public bool NeedToSave { - public bool NeedToSave + get { - get - { - return this.FirstOrDefault(n => n.NeedToSave) is object; - } - } - - public void WriteTrajectories(BinaryData data) - { - int curPos = 0x1205000; - int romstartAddr = 0x1200000; - int ramStartOffset = 0x00400000; - - foreach (Trajectory traj in this) - { - int ramStartAddr = GetRamAddressBase(traj.Name); - int ramAddr = curPos - romstartAddr + ramStartAddr + ramStartOffset; - var switchExpr = traj.Name; - - switch (switchExpr) - { - case TrajectoryName.KoopaTheQuick1: - data.Position = 0xED864; - data.Write(ramAddr); - break; - case TrajectoryName.KoopaTheQuick2: - data.Position = 0xED874; - data.Write(ramAddr); - break; - case TrajectoryName.RacingPenguin: - data.Position = 0xCCA6E; - data.Write((ushort)(ramAddr >> 16)); - data.Position = 0xCCA76; - data.Write((ushort)(ramAddr & 0xFFFF)); - break; - case TrajectoryName.SnowmansBottom: - data.Position = 0xABC9E; - data.Write((ushort)(ramAddr >> 16)); - data.Position = 0xABCA6; - data.Write((ushort)(ramAddr & 0xFFFF)); - break; - case TrajectoryName.PlatformOnTracksBehavior_BParam2_00: - data.Position = 0xED9DC + 0 * 4; - data.Write(ramAddr); - break; - case TrajectoryName.PlatformOnTracksBehavior_BParam2_01: - data.Position = 0xED9DC + 1 * 4; - data.Write(ramAddr); - break; - case TrajectoryName.PlatformOnTracksBehavior_BParam2_02: - data.Position = 0xED9DC + 2 * 4; - data.Write(ramAddr); - break; - case TrajectoryName.PlatformOnTracksBehavior_BParam2_03: - data.Position = 0xED9DC + 3 * 4; - data.Write(ramAddr); - break; - case TrajectoryName.PlatformOnTracksBehavior_BParam2_04: - data.Position = 0xED9DC + 4 * 4; - data.Write(ramAddr); - break; - case TrajectoryName.PlatformOnTracksBehavior_BParam2_05: - data.Position = 0xED9DC + 5 * 4; - data.Write(ramAddr); - break; - case TrajectoryName.PlatformOnTracksBehavior_BParam2_06: - data.Position = 0xED9DC + 6 * 4; - data.Write(ramAddr); - break; - case TrajectoryName.PlatformOnTracksBehavior_BParam2_07: - data.Position = 0xED9DC + 7 * 4; - data.Write(ramAddr); - break; - case TrajectoryName.MetalBallsGenerators_BParam2_00: - data.Position = 0xA9AB4; - data.Write((short)0x3C04); // LU3 T3, 0x8040 - data.Write((ushort)(ramAddr >> 16)); - data.Position = 0xA9ABC; - data.Write((short)0x3484); // ORI A0, A0, 0x8040xxxx - data.Write((short)(ramAddr & 0xFFFF)); - break; - case TrajectoryName.MetalBallsGenerators_BParam2_01: - data.Position = 0xA9AD4; - data.Write((short)0x3C04); // LU3 T3, 0x8040 - data.Write((ushort)(ramAddr >> 16)); - data.Position = 0xA9ADC; - data.Write((short)0x3484); // ORI A0, A0, 0x8040xxxx - data.Write((short)(ramAddr & 0xFFFF)); - break; - case TrajectoryName.MetalBallsGenerators_BParam2_02: - data.Position = 0xA9AF4; - data.Write((short)0x3C04); // LU3 T3, 0x8040 - data.Write((ushort)(ramAddr >> 16)); - data.Position = 0xA9AFC; - data.Write((short)0x3484); // ORI A0, A0, 0x8040xxxx - data.Write((short)(ramAddr & 0xFFFF)); - break; - case TrajectoryName.MiniMetalBallGenerator_BParam2_03: - data.Position = 0xA9B1C; - data.Write((short)0x3C09); // LU3 T3, 0x8040 - data.Write((ushort)(ramAddr >> 16)); - data.Write((short)0x356B); // ORI T3, T3, 0x8040xxxx - data.Write((short)(ramAddr & 0xFFFF)); - break; - case TrajectoryName.MiniMetalBallGenerator_BParam2_04: - data.Position = 0xA9B38; - data.Write((short)0x3C09); // LU3 T3, 0x8040 - data.Write((ushort)(ramAddr >> 16)); - data.Write((short)0x356B); // ORI T3, T3, 0x8040xxxx - data.Write((short)(ramAddr & 0xFFFF)); - break; - case TrajectoryName.MipsTheRabbit: - continue; - } - - traj.Write(data, (uint)(curPos)); - curPos = (int)(data.Position); - } - - // Mips the Rabbit - var mipsTrajects = this.Where(n => n.Name == TrajectoryName.MipsTheRabbit).ToArray(); - if (mipsTrajects.Any()) - { - int ramStartAddr = GetRamAddressBase(TrajectoryName.MipsTheRabbit); - int ramAddr = curPos - romstartAddr + ramStartAddr + ramStartOffset; - - data.Position = 0xB3816; - data.Write((ushort)ramStartAddr >> 16); - data.Position += 6; - data.Write((ushort)(ramAddr & 0xFFFF)); - - foreach (Trajectory traj in mipsTrajects) - { - traj.Write(data, (uint)curPos); - curPos = (int)data.Position; - } - - data.Position = 0xB371E; - data.Write((ushort)mipsTrajects.Length); - } - } - - private static int GetRamAddressBase(TrajectoryName trajectoryName) - { - int addr; - - switch (trajectoryName) - { - default: - addr = 0; - break; - } - - return addr; - } - - private void AddTrajectory(BinaryData data, int addr, TrajectoryName name) - { - AddTrajectory(data, addr, name, 1); - } - - private void AddTrajectory(BinaryData data, int addr, TrajectoryName name, ushort count, bool checkAddress = true) - { - int? addrToSubstract = null; - - if (!checkAddress || (addr > 0x00400000 && addr < 0x00410000)) - addrToSubstract = 0x00400000; - else if (!checkAddress || ((uint)addr > 0x80400000 && (uint)addr < 0x80410000)) - // Support for old 0x80 addresses - addrToSubstract = unchecked((int)0x80400000); - - if (addrToSubstract != null) - { - data.Position = addr - (int)addrToSubstract + 0x1200000; - for (int i = 1, loopTo = count; i <= loopTo; i++) - { - var trajectory = new Trajectory(); - trajectory.Name = name; - trajectory.Read(data, (uint)(data.Position)); - Add(trajectory); - } - } - } - - public void ReadTrajectories(BinaryData data) - { - int addr; - - // Clear list - Clear(); - - // Koopa-The-Quick #1 - data.Position = 0xED864; - addr = data.ReadInt32(); - AddTrajectory(data, addr, TrajectoryName.KoopaTheQuick1); - - // Koopa-The-Quick #2 - data.Position = 0xED874; - addr = data.ReadInt32(); - AddTrajectory(data, addr, TrajectoryName.KoopaTheQuick2); - - // Racing Penguin - data.Position = 0xCCA6E; - addr = data.ReadUInt16() << 16; - data.Position = 0xCCA76; - addr = addr | data.ReadUInt16(); - AddTrajectory(data, addr, TrajectoryName.RacingPenguin); - - // Snowman's Bottom - data.Position = 0xABC9E; - addr = data.ReadUInt16() << 16; - data.Position = 0xABCA6; - addr = addr | data.ReadUInt16(); - AddTrajectory(data, addr, TrajectoryName.SnowmansBottom); - - // Platform on Tracks Behavior (B.Param 2 = 0 - 8) - for (byte bparam = 0; bparam <= 8; bparam++) - { - data.Position = 0xED9DC + bparam * 4; - addr = data.ReadInt32(); - AddTrajectory(data, addr, (TrajectoryName)((int)TrajectoryName.PlatformOnTracksBehavior_BParam2_00 + bparam)); - } - - // Metal Balls Generators - B.Param 2 = 00 - data.Position = 0xA9AB4 + 2; - addr = data.ReadUInt16() << 16; - data.Position = 0xA9ABC + 2; - var val3 = data.ReadUInt16(); - addr = addr | val3; - AddTrajectory(data, addr, TrajectoryName.MetalBallsGenerators_BParam2_00); - - // Metal Balls Generators - B.Param 2 = 01 - data.Position = 0xA9AD4 + 2; - addr = data.ReadUInt16() << 16; - data.Position = 0xA9ADC + 2; - addr = addr | data.ReadUInt16(); - AddTrajectory(data, addr, TrajectoryName.MetalBallsGenerators_BParam2_01); - - // Metal Balls Generators - B.Param 2 = 02 - data.Position = 0xA9AF4 + 2; - addr = data.ReadUInt16() << 16; - data.Position = 0xA9AFC + 2; - addr = addr | data.ReadUInt16(); - AddTrajectory(data, addr, TrajectoryName.MetalBallsGenerators_BParam2_02); - - // Mini-Metal Ball Generator - B.Param 2 = 03 - data.Position = 0xA9B1C + 2; - addr = data.ReadUInt16() << 16; - data.Position += 2; - addr = addr | data.ReadUInt16(); - AddTrajectory(data, addr, TrajectoryName.MiniMetalBallGenerator_BParam2_03); - - // Mini-Metal Ball Generator - B.Param 2 = 04 - data.Position = 0xA9B1C + 2; - addr = data.ReadUInt16() << 16; - data.Position += 2; - addr = addr | data.ReadUInt16(); - AddTrajectory(data, addr, TrajectoryName.MiniMetalBallGenerator_BParam2_04); - - // Mips the Rabbit - data.Position = 0xB3816; - addr = data.ReadUInt16() << 16; - data.Position += 6; - addr = addr | data.ReadUInt16(); - data.Position = 0xB371E; - ushort numOfPaths = data.ReadUInt16(); - AddTrajectory(data, addr, TrajectoryName.MipsTheRabbit, numOfPaths); + return this.FirstOrDefault(n => n.NeedToSave) is object; } } + + public void WriteTrajectories(BinaryData data) + { + int curPos = 0x1205000; + int romstartAddr = 0x1200000; + int ramStartOffset = 0x00400000; + + foreach (Trajectory traj in this) + { + int ramStartAddr = GetRamAddressBase(traj.Name); + int ramAddr = curPos - romstartAddr + ramStartAddr + ramStartOffset; + var switchExpr = traj.Name; + + switch (switchExpr) + { + case TrajectoryName.KoopaTheQuick1: + data.Position = 0xED864; + data.Write(ramAddr); + break; + case TrajectoryName.KoopaTheQuick2: + data.Position = 0xED874; + data.Write(ramAddr); + break; + case TrajectoryName.RacingPenguin: + data.Position = 0xCCA6E; + data.Write((ushort)(ramAddr >> 16)); + data.Position = 0xCCA76; + data.Write((ushort)(ramAddr & 0xFFFF)); + break; + case TrajectoryName.SnowmansBottom: + data.Position = 0xABC9E; + data.Write((ushort)(ramAddr >> 16)); + data.Position = 0xABCA6; + data.Write((ushort)(ramAddr & 0xFFFF)); + break; + case TrajectoryName.PlatformOnTracksBehavior_BParam2_00: + data.Position = 0xED9DC + 0 * 4; + data.Write(ramAddr); + break; + case TrajectoryName.PlatformOnTracksBehavior_BParam2_01: + data.Position = 0xED9DC + 1 * 4; + data.Write(ramAddr); + break; + case TrajectoryName.PlatformOnTracksBehavior_BParam2_02: + data.Position = 0xED9DC + 2 * 4; + data.Write(ramAddr); + break; + case TrajectoryName.PlatformOnTracksBehavior_BParam2_03: + data.Position = 0xED9DC + 3 * 4; + data.Write(ramAddr); + break; + case TrajectoryName.PlatformOnTracksBehavior_BParam2_04: + data.Position = 0xED9DC + 4 * 4; + data.Write(ramAddr); + break; + case TrajectoryName.PlatformOnTracksBehavior_BParam2_05: + data.Position = 0xED9DC + 5 * 4; + data.Write(ramAddr); + break; + case TrajectoryName.PlatformOnTracksBehavior_BParam2_06: + data.Position = 0xED9DC + 6 * 4; + data.Write(ramAddr); + break; + case TrajectoryName.PlatformOnTracksBehavior_BParam2_07: + data.Position = 0xED9DC + 7 * 4; + data.Write(ramAddr); + break; + case TrajectoryName.MetalBallsGenerators_BParam2_00: + data.Position = 0xA9AB4; + data.Write((short)0x3C04); // LU3 T3, 0x8040 + data.Write((ushort)(ramAddr >> 16)); + data.Position = 0xA9ABC; + data.Write((short)0x3484); // ORI A0, A0, 0x8040xxxx + data.Write((short)(ramAddr & 0xFFFF)); + break; + case TrajectoryName.MetalBallsGenerators_BParam2_01: + data.Position = 0xA9AD4; + data.Write((short)0x3C04); // LU3 T3, 0x8040 + data.Write((ushort)(ramAddr >> 16)); + data.Position = 0xA9ADC; + data.Write((short)0x3484); // ORI A0, A0, 0x8040xxxx + data.Write((short)(ramAddr & 0xFFFF)); + break; + case TrajectoryName.MetalBallsGenerators_BParam2_02: + data.Position = 0xA9AF4; + data.Write((short)0x3C04); // LU3 T3, 0x8040 + data.Write((ushort)(ramAddr >> 16)); + data.Position = 0xA9AFC; + data.Write((short)0x3484); // ORI A0, A0, 0x8040xxxx + data.Write((short)(ramAddr & 0xFFFF)); + break; + case TrajectoryName.MiniMetalBallGenerator_BParam2_03: + data.Position = 0xA9B1C; + data.Write((short)0x3C09); // LU3 T3, 0x8040 + data.Write((ushort)(ramAddr >> 16)); + data.Write((short)0x356B); // ORI T3, T3, 0x8040xxxx + data.Write((short)(ramAddr & 0xFFFF)); + break; + case TrajectoryName.MiniMetalBallGenerator_BParam2_04: + data.Position = 0xA9B38; + data.Write((short)0x3C09); // LU3 T3, 0x8040 + data.Write((ushort)(ramAddr >> 16)); + data.Write((short)0x356B); // ORI T3, T3, 0x8040xxxx + data.Write((short)(ramAddr & 0xFFFF)); + break; + case TrajectoryName.MipsTheRabbit: + continue; + } + + traj.Write(data, (uint)(curPos)); + curPos = (int)(data.Position); + } + + // Mips the Rabbit + var mipsTrajects = this.Where(n => n.Name == TrajectoryName.MipsTheRabbit).ToArray(); + if (mipsTrajects.Any()) + { + int ramStartAddr = GetRamAddressBase(TrajectoryName.MipsTheRabbit); + int ramAddr = curPos - romstartAddr + ramStartAddr + ramStartOffset; + + data.Position = 0xB3816; + data.Write((ushort)ramStartAddr >> 16); + data.Position += 6; + data.Write((ushort)(ramAddr & 0xFFFF)); + + foreach (Trajectory traj in mipsTrajects) + { + traj.Write(data, (uint)curPos); + curPos = (int)data.Position; + } + + data.Position = 0xB371E; + data.Write((ushort)mipsTrajects.Length); + } + } + + private static int GetRamAddressBase(TrajectoryName trajectoryName) + { + int addr; + + switch (trajectoryName) + { + default: + addr = 0; + break; + } + + return addr; + } + + private void AddTrajectory(BinaryData data, int addr, TrajectoryName name) + { + AddTrajectory(data, addr, name, 1); + } + + private void AddTrajectory(BinaryData data, int addr, TrajectoryName name, ushort count, bool checkAddress = true) + { + int? addrToSubstract = null; + + if (!checkAddress || (addr > 0x00400000 && addr < 0x00410000)) + addrToSubstract = 0x00400000; + else if (!checkAddress || ((uint)addr > 0x80400000 && (uint)addr < 0x80410000)) + // Support for old 0x80 addresses + addrToSubstract = unchecked((int)0x80400000); + + if (addrToSubstract != null) + { + data.Position = addr - (int)addrToSubstract + 0x1200000; + for (int i = 1, loopTo = count; i <= loopTo; i++) + { + var trajectory = new Trajectory(); + trajectory.Name = name; + trajectory.Read(data, (uint)(data.Position)); + Add(trajectory); + } + } + } + + public void ReadTrajectories(BinaryData data) + { + int addr; + + // Clear list + Clear(); + + // Koopa-The-Quick #1 + data.Position = 0xED864; + addr = data.ReadInt32(); + AddTrajectory(data, addr, TrajectoryName.KoopaTheQuick1); + + // Koopa-The-Quick #2 + data.Position = 0xED874; + addr = data.ReadInt32(); + AddTrajectory(data, addr, TrajectoryName.KoopaTheQuick2); + + // Racing Penguin + data.Position = 0xCCA6E; + addr = data.ReadUInt16() << 16; + data.Position = 0xCCA76; + addr = addr | data.ReadUInt16(); + AddTrajectory(data, addr, TrajectoryName.RacingPenguin); + + // Snowman's Bottom + data.Position = 0xABC9E; + addr = data.ReadUInt16() << 16; + data.Position = 0xABCA6; + addr = addr | data.ReadUInt16(); + AddTrajectory(data, addr, TrajectoryName.SnowmansBottom); + + // Platform on Tracks Behavior (B.Param 2 = 0 - 8) + for (byte bparam = 0; bparam <= 8; bparam++) + { + data.Position = 0xED9DC + bparam * 4; + addr = data.ReadInt32(); + AddTrajectory(data, addr, (TrajectoryName)((int)TrajectoryName.PlatformOnTracksBehavior_BParam2_00 + bparam)); + } + + // Metal Balls Generators - B.Param 2 = 00 + data.Position = 0xA9AB4 + 2; + addr = data.ReadUInt16() << 16; + data.Position = 0xA9ABC + 2; + var val3 = data.ReadUInt16(); + addr = addr | val3; + AddTrajectory(data, addr, TrajectoryName.MetalBallsGenerators_BParam2_00); + + // Metal Balls Generators - B.Param 2 = 01 + data.Position = 0xA9AD4 + 2; + addr = data.ReadUInt16() << 16; + data.Position = 0xA9ADC + 2; + addr = addr | data.ReadUInt16(); + AddTrajectory(data, addr, TrajectoryName.MetalBallsGenerators_BParam2_01); + + // Metal Balls Generators - B.Param 2 = 02 + data.Position = 0xA9AF4 + 2; + addr = data.ReadUInt16() << 16; + data.Position = 0xA9AFC + 2; + addr = addr | data.ReadUInt16(); + AddTrajectory(data, addr, TrajectoryName.MetalBallsGenerators_BParam2_02); + + // Mini-Metal Ball Generator - B.Param 2 = 03 + data.Position = 0xA9B1C + 2; + addr = data.ReadUInt16() << 16; + data.Position += 2; + addr = addr | data.ReadUInt16(); + AddTrajectory(data, addr, TrajectoryName.MiniMetalBallGenerator_BParam2_03); + + // Mini-Metal Ball Generator - B.Param 2 = 04 + data.Position = 0xA9B1C + 2; + addr = data.ReadUInt16() << 16; + data.Position += 2; + addr = addr | data.ReadUInt16(); + AddTrajectory(data, addr, TrajectoryName.MiniMetalBallGenerator_BParam2_04); + + // Mips the Rabbit + data.Position = 0xB3816; + addr = data.ReadUInt16() << 16; + data.Position += 6; + addr = addr | data.ReadUInt16(); + data.Position = 0xB371E; + ushort numOfPaths = data.ReadUInt16(); + AddTrajectory(data, addr, TrajectoryName.MipsTheRabbit, numOfPaths); + } } \ No newline at end of file diff --git a/SM64Lib/Trajectories/Trajectory.cs b/SM64Lib/Trajectories/Trajectory.cs index 85c5b36..9126f7e 100644 --- a/SM64Lib/Trajectories/Trajectory.cs +++ b/SM64Lib/Trajectories/Trajectory.cs @@ -1,64 +1,60 @@ -using System; -using System.Collections.Generic; -using global::System.IO; -using global::System.Numerics; -using Microsoft.VisualBasic.CompilerServices; +using global::System.Numerics; using SM64Lib.Data; -using SM64Lib.Data.System; +using System; +using System.Collections.Generic; -namespace SM64Lib.Trajectorys +namespace SM64Lib.Trajectorys; + +public class Trajectory { - public class Trajectory + public List Points { get; private set; } = new List(); + public bool NeedToSave { get; set; } = false; + public TrajectoryName Name { get; set; } = TrajectoryName.None; + + public void Write(BinaryData data, uint startPos) { - public List Points { get; private set; } = new List(); - public bool NeedToSave { get; set; } = false; - public TrajectoryName Name { get; set; } = TrajectoryName.None; + // Set position + data.Position = startPos; - public void Write(BinaryData data, uint startPos) + // Write xyz + for (short i = 0, loopTo = Convert.ToInt16(Points.Count - 1); i <= loopTo; i++) { - // Set position - data.Position = startPos; - - // Write xyz - for (short i = 0, loopTo = Convert.ToInt16(Points.Count - 1); i <= loopTo; i++) - { - var point = Points[i]; - data.Write(i); - data.Write((short)(point.X)); - data.Write((short)(point.Y)); - data.Write((short)(point.Z)); - } - - data.Write(0xFFFFFFFF); - data.Write(0xFFFFFFFF); + var point = Points[i]; + data.Write(i); + data.Write((short)(point.X)); + data.Write((short)(point.Y)); + data.Write((short)(point.Z)); } - public void Read(BinaryData data, uint startPos) + data.Write(0xFFFFFFFF); + data.Write(0xFFFFFFFF); + } + + public void Read(BinaryData data, uint startPos) + { + bool ende = false; + + // Set position + data.Position = startPos; + + // Clear list + Points.Clear(); + + // Read xyz + while (!ende) { - bool ende = false; - - // Set position - data.Position = startPos; - - // Clear list - Points.Clear(); - - // Read xyz - while (!ende) + if ((ulong)data.ReadInt64() != 0xFFFFFFFFFFFFFFFF) { - if ((ulong)data.ReadInt64() != 0xFFFFFFFFFFFFFFFF) - { - data.Position -= 6; - var point = new Vector3(); - point.X = data.ReadInt16(); - point.Y = data.ReadInt16(); - point.Z = data.ReadInt16(); - Points.Add(point); - } - else - { - ende = true; - } + data.Position -= 6; + var point = new Vector3(); + point.X = data.ReadInt16(); + point.Y = data.ReadInt16(); + point.Z = data.ReadInt16(); + Points.Add(point); + } + else + { + ende = true; } } } diff --git a/SM64Lib/Trajectories/TrajectoryName.cs b/SM64Lib/Trajectories/TrajectoryName.cs index 1655d26..97f7f10 100644 --- a/SM64Lib/Trajectories/TrajectoryName.cs +++ b/SM64Lib/Trajectories/TrajectoryName.cs @@ -1,26 +1,25 @@  -namespace SM64Lib.Trajectorys +namespace SM64Lib.Trajectorys; + +public enum TrajectoryName { - public enum TrajectoryName - { - None, - KoopaTheQuick1, - KoopaTheQuick2, - RacingPenguin, - SnowmansBottom, - PlatformOnTracksBehavior_BParam2_00, - PlatformOnTracksBehavior_BParam2_01, - PlatformOnTracksBehavior_BParam2_02, - PlatformOnTracksBehavior_BParam2_03, - PlatformOnTracksBehavior_BParam2_04, - PlatformOnTracksBehavior_BParam2_05, - PlatformOnTracksBehavior_BParam2_06, - PlatformOnTracksBehavior_BParam2_07, - MetalBallsGenerators_BParam2_00, - MetalBallsGenerators_BParam2_01, - MetalBallsGenerators_BParam2_02, - MiniMetalBallGenerator_BParam2_03, - MiniMetalBallGenerator_BParam2_04, - MipsTheRabbit - } + None, + KoopaTheQuick1, + KoopaTheQuick2, + RacingPenguin, + SnowmansBottom, + PlatformOnTracksBehavior_BParam2_00, + PlatformOnTracksBehavior_BParam2_01, + PlatformOnTracksBehavior_BParam2_02, + PlatformOnTracksBehavior_BParam2_03, + PlatformOnTracksBehavior_BParam2_04, + PlatformOnTracksBehavior_BParam2_05, + PlatformOnTracksBehavior_BParam2_06, + PlatformOnTracksBehavior_BParam2_07, + MetalBallsGenerators_BParam2_00, + MetalBallsGenerators_BParam2_01, + MetalBallsGenerators_BParam2_02, + MiniMetalBallGenerator_BParam2_03, + MiniMetalBallGenerator_BParam2_04, + MipsTheRabbit } \ No newline at end of file