diff --git a/Marathon.Tests/Formats/Acroarts/AckResourceTests.cs b/Marathon.Tests/Formats/Acroarts/AckResourceTests.cs new file mode 100644 index 00000000..466677de --- /dev/null +++ b/Marathon.Tests/Formats/Acroarts/AckResourceTests.cs @@ -0,0 +1,20 @@ +using Marathon.Formats.Acroarts; +using Marathon.Tests.Helpers; + +namespace Marathon.Tests.Formats.Acroarts +{ + internal class AckResourceTests : ITest + { + private Func[] _tests = [BinaryIdenticalTest]; + + private static bool BinaryIdenticalTest() + { + return TestHelper.CheckAllBinaries("*.mab"); + } + + public bool Run() + { + return TestHelper.RunSubTests(_tests); + } + } +} diff --git a/Marathon/Formats/Acroarts/AckResource.cs b/Marathon/Formats/Acroarts/AckResource.cs new file mode 100644 index 00000000..f348665f --- /dev/null +++ b/Marathon/Formats/Acroarts/AckResource.cs @@ -0,0 +1,126 @@ +using Amicitia.IO.Streams; +using Marathon.Formats.Acroarts.Chunks; +using Marathon.IO; +using Marathon.IO.Extensions; +using Marathon.IO.Types.BINA; +using Marathon.IO.Types.FileSystem; +using System.IO; + +// Format names: Acroarts Resource +// Format references: Sonicteam::Spanverse::AckResource +// Format designers: Sonic Team +// Format researchers: Hyper, Rei-san + +namespace Marathon.Formats.Acroarts +{ + /// + /// Support for *.mab files; used for Acroarts data. + /// + public class AckResource : FileBase + { + private const string _extension = ".mab"; // "Merged Acroarts Binary" (speculatory) + private const string _signature = "MRAB"; // "MeRged Acroarts Binary" (speculatory) + + private bool _binaHeaderHasSignature = true; + + public const uint Version = 2006020901; // 2006 February 9th, Revision 1 + + public DataChunk Data { get; set; } + + public ResourceChunk Resources { get; set; } + + public override string Extension => _extension; + + public AckResource() { } + + public AckResource(string in_path) : base(in_path) { } + + public AckResource(Stream in_stream) : base(in_stream) { } + + public AckResource(IFile in_file) : base(in_file) { } + + public override void Read(Stream in_stream) + { + var mrabReader = new BinaryObjectReaderEx(in_stream, StreamOwnership.Retain, Endianness); + + mrabReader.CheckSignature(_signature); + + var binaOffset = mrabReader.Read(); + var binaLength = mrabReader.Read(); + + mrabReader.JumpAhead(4); // Reserved. + + var binaReader = new BINAReader(in_stream, binaOffset); + + Endianness = binaReader.Endianness; + + _binaHeaderHasSignature = binaReader.Header.HasSignature; + + var abdaOffset = binaReader.Read(); + var abrsOffset = binaReader.Read(); + + if (abdaOffset != 0) + { + binaReader.JumpTo(binaReader.CalculateOffset(abdaOffset)); + Data = new DataChunk(binaReader); + } + + if (abrsOffset != 0) + { + binaReader.JumpTo(binaReader.CalculateOffset(abrsOffset)); + Resources = new ResourceChunk(binaReader); + } + } + + public override void Write(Stream in_stream) + { + var mrabWriter = new BinaryObjectWriterEx(in_stream, StreamOwnership.Retain, Endianness); + + mrabWriter.WriteSignature(_signature); + + var binaOffset = mrabWriter.Reserve(true); + var binaLength = mrabWriter.Reserve(true); + + mrabWriter.WriteZero(); // Reserved. + mrabWriter.WriteReserved(binaOffset, (uint)mrabWriter.Position); + + var binaWriter = new BINAWriter(in_stream, mrabWriter.Position, mrabWriter.Endianness); + { + binaWriter.Header.HasSignature = _binaHeaderHasSignature; + } + + var abdaOffset = binaWriter.Reserve(true); + var abrsOffset = binaWriter.Reserve(true); + + binaWriter.WriteZero(0x18); // Reserved. + + var abdaWriter = new BinaryObjectWriterEx(in_stream, StreamOwnership.Retain, binaWriter.Endianness); + + abdaWriter.JumpTo(binaWriter.Position); + + if (Data != null) + { + binaWriter.WriteReserved(abdaOffset, (uint)(binaWriter.Position - abdaOffset)); + Data.Write(abdaWriter); + } + + var abrsWriter = new BinaryObjectWriterEx(in_stream, StreamOwnership.Retain, binaWriter.Endianness); + + abrsWriter.JumpTo(binaWriter.Position); + + if (Resources != null) + { + binaWriter.WriteReserved(abrsOffset, (uint)(binaWriter.Position - abrsOffset) + sizeof(uint)); + Resources.Write(abrsWriter); + } + + // BINA is exclusively used for these. + binaWriter.AddOffset(abdaOffset); + binaWriter.AddOffset(abrsOffset); + + binaWriter.FinishWrite(); + + mrabWriter.WriteReserved(binaLength, binaWriter.Header.Length); + } + } +} diff --git a/Marathon/Formats/Acroarts/Chunks/ChunkHeader.cs b/Marathon/Formats/Acroarts/Chunks/ChunkHeader.cs new file mode 100644 index 00000000..478b990c --- /dev/null +++ b/Marathon/Formats/Acroarts/Chunks/ChunkHeader.cs @@ -0,0 +1,111 @@ +using Amicitia.IO; +using Amicitia.IO.Binary; +using Marathon.IO; +using Marathon.IO.Types; + +namespace Marathon.Formats.Acroarts.Chunks +{ + public class ChunkHeader : IBinarySerializable + { + public const uint DefaultHeaderSize = 16; + + private long _lengthOffset; + private long _chunkStart; + private long _headerSizeOffset; + private long _systemFlagsOffset; + private long _userFlagsOffset; + + public FourCC ID { get; set; } + + public uint Length { get; set; } + + public uint HeaderSize { get; set; } = DefaultHeaderSize; + + public ushort SystemFlags { get; set; } + + public ushort UserFlags { get; set; } + + public ChunkHeader() { } + + public ChunkHeader(FourCC in_id, uint in_length, uint in_headerSize, ushort in_systemFlags, ushort in_userFlags) + { + ID = in_id; + Length = in_length; + HeaderSize = in_headerSize; + SystemFlags = in_systemFlags; + UserFlags = in_userFlags; + } + + public ChunkHeader(string in_id, uint in_length, uint in_headerSize, ushort in_systemFlags, ushort in_userFlags) + : this(new FourCC(in_id), in_length, in_headerSize, in_systemFlags, in_userFlags) { } + + public ChunkHeader(BinaryObjectWriterEx in_writer, FourCC in_id) + { + ID = in_id; + + Reserve(in_writer); + } + + public ChunkHeader(BinaryObjectWriterEx in_writer, string in_id) + : this(in_writer, new FourCC(in_id)) { } + + public void Read(BinaryObjectReader in_reader) + { + ID = in_reader.ReadObject(); + Length = in_reader.Read(); + HeaderSize = in_reader.Read(); + SystemFlags = in_reader.Read(); + UserFlags = in_reader.Read(); + } + + public void Write(BinaryObjectWriter in_writer) + { + in_writer.WriteObject(ID); + in_writer.Write(Length); + in_writer.Write(HeaderSize); + in_writer.Write(SystemFlags); + in_writer.Write(UserFlags); + } + + public void Reserve(BinaryObjectWriterEx in_writer) + { + in_writer.WriteObject(ID); + _lengthOffset = in_writer.Reserve(true); + _headerSizeOffset = in_writer.Reserve(true); + _systemFlagsOffset = in_writer.Reserve(true); + _userFlagsOffset = in_writer.Reserve(true); + _chunkStart = (uint)in_writer.Position; + } + + public void FinishWrite(BinaryObjectWriterEx in_writer) + { + in_writer.WriteReserved(_lengthOffset, (uint)AlignmentHelper.Align(in_writer.Position - _chunkStart, 16)); + in_writer.WriteReserved(_headerSizeOffset, HeaderSize); + in_writer.WriteReserved(_systemFlagsOffset, SystemFlags); + in_writer.WriteReserved(_userFlagsOffset, UserFlags); + } + + public void FinishWrite(BinaryObjectWriterEx in_writer, uint in_length, uint in_headerSize, ushort in_systemFlags, ushort in_userFlags) + { + in_writer.WriteReserved(_lengthOffset, in_length); + in_writer.WriteReserved(_headerSizeOffset, in_headerSize); + in_writer.WriteReserved(_systemFlagsOffset, in_systemFlags); + in_writer.WriteReserved(_userFlagsOffset, in_userFlags); + } + + public void FinishWrite(BinaryObjectWriterEx in_writer, uint in_length, uint in_headerSize) + { + FinishWrite(in_writer, in_length, in_headerSize, SystemFlags, UserFlags); + } + + public void FinishWrite(BinaryObjectWriterEx in_writer, uint in_length) + { + FinishWrite(in_writer, in_length, HeaderSize, SystemFlags, UserFlags); + } + + public long GetChunkStart() + { + return _chunkStart; + } + } +} diff --git a/Marathon/Formats/Acroarts/Chunks/DataChunk.cs b/Marathon/Formats/Acroarts/Chunks/DataChunk.cs new file mode 100644 index 00000000..158abbaf --- /dev/null +++ b/Marathon/Formats/Acroarts/Chunks/DataChunk.cs @@ -0,0 +1,131 @@ +using Amicitia.IO.Binary; +using Marathon.Exceptions; +using Marathon.IO; +using Marathon.IO.Extensions; +using Newtonsoft.Json; +using System.Collections.Generic; +using System.Linq; + +namespace Marathon.Formats.Acroarts.Chunks +{ + public class DataChunk : List, IBinarySerializableEx + { + private bool _isChunkAligned = false; + + public const string ID = "ABDA"; // "Acroarts Binary DAta" + + [JsonIgnore] + public RelocationTableChunk RelocationTableChunk { get; set; } + + public DataChunk() { } + + public DataChunk(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + in_reader.PushOffsetOrigin(in_reader.Position); + + var chunkHeader = in_reader.ReadObject(); + + if (!chunkHeader.ID.Equals(ID)) + throw new InvalidSignatureException(ID, chunkHeader.ID); + + var version = in_reader.Read(); + + if (version != AckResource.Version) + throw new InvalidSignatureException(AckResource.Version, version); + + var trunkCount = in_reader.Read(); + var relocTableOffset = in_reader.Read(); + + in_reader.JumpAhead(4); // Reserved. + + for (uint i = 0; i < trunkCount; i++) + { + var chunkOffset = in_reader.Read(); + var param = in_reader.Read(); + + in_reader.ReadAtOffset(in_reader.CalculateOffset(chunkOffset), () => + { + Add(new(new TrunkChunk(in_reader), param)); + }); + } + + in_reader.JumpTo(in_reader.CalculateOffset(relocTableOffset)); + + RelocationTableChunk = new RelocationTableChunk(in_reader); + new EndOfChunk().Read(in_reader); + + _isChunkAligned = in_reader.ReadArray(0x10).Sum(x => x) == 0; + + in_reader.PopOffsetOrigin(); + } + + public void Write(BinaryObjectWriterEx in_writer) + { + in_writer.PushOffsetOrigin(in_writer.Position); + + var chunkHeader = new ChunkHeader(in_writer, ID) + { + HeaderSize = 0x30 + }; + + in_writer.Write(AckResource.Version); + in_writer.Write(Count); + + var relocTableOffset = in_writer.Reserve(true); + + in_writer.WriteZero(); // Reserved. + + if (Count <= 0) + { + // Empty chunk array. + in_writer.WriteZero(); + in_writer.Align(16); + } + else + { + var trunkOffsets = new List(); + + foreach (var trunk in this) + { + trunkOffsets.Add(in_writer.Reserve()); + in_writer.Write(trunk.Parameter); + } + + in_writer.Align(16); + + chunkHeader.HeaderSize = (uint)(in_writer.Position - in_writer.OffsetOrigin); + + for (int i = 0; i < Count; i++) + { + in_writer.WriteReserved(trunkOffsets[i], (uint)in_writer.CalculateOffset(in_writer.Position, OffsetType.Relative), false); + this[i].Trunk.Write(in_writer); + } + } + + in_writer.Align(16); + in_writer.WriteReserved(relocTableOffset, (uint)in_writer.CalculateOffset(in_writer.Position, OffsetType.Relative)); + + new RelocationTableChunk().Write(in_writer); + + chunkHeader.FinishWrite(in_writer, (uint)(in_writer.Position - in_writer.OffsetOrigin - chunkHeader.HeaderSize)); + + new EndOfChunk().Write(in_writer); + + if (_isChunkAligned) + in_writer.WriteZero(0x10); + + in_writer.PopOffsetOrigin(); + } + } + + public struct TrunkChunkParam(TrunkChunk in_trunk, uint in_parameter) + { + public TrunkChunk Trunk = in_trunk; + public uint Parameter = in_parameter; + } +} diff --git a/Marathon/Formats/Acroarts/Chunks/EndOfChunk.cs b/Marathon/Formats/Acroarts/Chunks/EndOfChunk.cs new file mode 100644 index 00000000..78f5fa24 --- /dev/null +++ b/Marathon/Formats/Acroarts/Chunks/EndOfChunk.cs @@ -0,0 +1,32 @@ +using Marathon.Exceptions; +using Marathon.IO; + +namespace Marathon.Formats.Acroarts.Chunks +{ + public class EndOfChunk : IBinarySerializableEx + { + public const string ID = "EOFC"; // "End OF Chunk" + + public EndOfChunk() { } + + public EndOfChunk(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + var header = in_reader.ReadObject(); + + if (header.ID.Equals(ID)) + return; + + throw new InvalidSignatureException(ID, header.ID); + } + + public void Write(BinaryObjectWriterEx in_writer) + { + new ChunkHeader(in_writer, ID).FinishWrite(in_writer, 0, ChunkHeader.DefaultHeaderSize); + } + } +} diff --git a/Marathon/Formats/Acroarts/Chunks/RelocationTableChunk.cs b/Marathon/Formats/Acroarts/Chunks/RelocationTableChunk.cs new file mode 100644 index 00000000..f0e30574 --- /dev/null +++ b/Marathon/Formats/Acroarts/Chunks/RelocationTableChunk.cs @@ -0,0 +1,51 @@ +using Amicitia.IO.Binary; +using Marathon.Exceptions; +using Marathon.IO; +using Marathon.IO.Types.BINA; + +namespace Marathon.Formats.Acroarts.Chunks +{ + public class RelocationTableChunk : IBinarySerializableEx + { + public const string ID = "POF0"; + + public BINARelocationTable RelocationTable { get; set; } + + public RelocationTableChunk() { } + + public RelocationTableChunk(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + var chunkHeader = in_reader.ReadObject(); + + if (!chunkHeader.ID.Equals(ID)) + throw new InvalidSignatureException(ID, chunkHeader.ID); + + var length = in_reader.Read(); + + RelocationTable = new BINARelocationTable(in_reader.OffsetOrigin - BINAHeader.Size); + RelocationTable.Read(in_reader, length - sizeof(uint)); + + in_reader.Align(16); + } + + public void Write(BinaryObjectWriterEx in_writer) + { + var chunkHeader = new ChunkHeader(in_writer, ID); + var length = in_writer.Reserve(true); + + RelocationTable = new BINARelocationTable(in_writer.OffsetOrigin - BINAHeader.Size); + RelocationTable.AddOffsets(in_writer.Offsets.Values); + RelocationTable.Write(in_writer); + + in_writer.WriteReserved(length, RelocationTable.Length <= 0 ? 0U : (uint)RelocationTable.Length + sizeof(uint)); + in_writer.Align(16); + + chunkHeader.FinishWrite(in_writer); + } + } +} diff --git a/Marathon/Formats/Acroarts/Chunks/ResourceChunk.cs b/Marathon/Formats/Acroarts/Chunks/ResourceChunk.cs new file mode 100644 index 00000000..adc2a1ba --- /dev/null +++ b/Marathon/Formats/Acroarts/Chunks/ResourceChunk.cs @@ -0,0 +1,117 @@ +using Amicitia.IO.Binary; +using Marathon.Exceptions; +using Marathon.IO; +using Newtonsoft.Json; +using System.Collections.Generic; + +namespace Marathon.Formats.Acroarts.Chunks +{ + public class ResourceChunk : List, IBinarySerializableEx + { + public const string ID = "ABRS"; // "Acroarts Binary ReSource" + + [JsonIgnore] + public RelocationTableChunk RelocationTableChunk { get; set; } + + public ResourceChunk() { } + + public ResourceChunk(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + in_reader.PushOffsetOrigin(in_reader.Position); + + var chunkHeader = in_reader.ReadObject(); + + if (!chunkHeader.ID.Equals(ID)) + throw new InvalidSignatureException(ID, chunkHeader.ID); + + var version = in_reader.Read(); + + if (version != AckResource.Version) + throw new InvalidSignatureException(AckResource.Version, version); + + var resourceCount = in_reader.Read(); + var relocTableOffset = in_reader.Read(); + + for (uint i = 0; i < resourceCount; i++) + { + var chunkOffset = in_reader.Read(); + var virtualResId = in_reader.Read(); + + in_reader.ReadAtOffset(in_reader.CalculateOffset(chunkOffset), () => + { + Add(new(new ResourcePathChunk(in_reader), virtualResId)); + }); + } + + in_reader.JumpTo(in_reader.CalculateOffset(relocTableOffset)); + + RelocationTableChunk = new RelocationTableChunk(in_reader); + + in_reader.PopOffsetOrigin(); + } + + public void Write(BinaryObjectWriterEx in_writer) + { + in_writer.PushOffsetOrigin(in_writer.Position); + + var chunkHeader = new ChunkHeader(in_writer, ID) + { + HeaderSize = 0x30 + }; + + in_writer.Write(AckResource.Version); + in_writer.Write(Count); + + var relocTableOffset = in_writer.Reserve(true); + + if (Count <= 0) + { + // Empty chunk array. + in_writer.WriteArray([0, -1]); + in_writer.Align(16); + } + else + { + var resourceOffsets = new List(); + + foreach (var trunk in this) + { + resourceOffsets.Add(in_writer.Reserve()); + in_writer.Write(trunk.ID); + } + + in_writer.Align(16); + + chunkHeader.HeaderSize = (uint)(in_writer.Position - in_writer.OffsetOrigin); + + for (int i = 0; i < Count; i++) + { + in_writer.WriteReserved(resourceOffsets[i], (uint)in_writer.CalculateOffset(in_writer.Position, OffsetType.Relative), false); + this[i].Resource.Write(in_writer); + } + } + + in_writer.Align(16); + in_writer.WriteReserved(relocTableOffset, (uint)in_writer.CalculateOffset(in_writer.Position, OffsetType.Relative)); + + new RelocationTableChunk().Write(in_writer); + + chunkHeader.FinishWrite(in_writer, (uint)(in_writer.Position - in_writer.OffsetOrigin - chunkHeader.HeaderSize)); + + new EndOfChunk().Write(in_writer); + + in_writer.PopOffsetOrigin(); + } + } + + public struct ResourceChunkParam(ResourcePathChunk in_resource, int in_id) + { + public ResourcePathChunk Resource = in_resource; + public int ID = in_id; + } +} diff --git a/Marathon/Formats/Acroarts/Chunks/ResourcePathChunk.cs b/Marathon/Formats/Acroarts/Chunks/ResourcePathChunk.cs new file mode 100644 index 00000000..374c7a88 --- /dev/null +++ b/Marathon/Formats/Acroarts/Chunks/ResourcePathChunk.cs @@ -0,0 +1,70 @@ +using Marathon.Helpers; +using Marathon.IO; +using Marathon.IO.Extensions; +using Marathon.IO.Types; +using System.IO.Enumeration; + +namespace Marathon.Formats.Acroarts.Chunks +{ + public class ResourcePathChunk : IBinarySerializableEx + { + public string Path { get; set; } + + public ResourcePathChunk() { } + + public ResourcePathChunk(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public ResourcePathChunk(string in_path) + { + Path = in_path; + } + + public void Read(BinaryObjectReaderEx in_reader) + { + var chunkHeader = in_reader.ReadObject(); + + Path = in_reader.ReadStringFixedLength((int)chunkHeader.Length); + } + + public void Write(BinaryObjectWriterEx in_writer) + { + var chunkHeader = new ChunkHeader(in_writer, GetResourceIDFromPath(Path)); + var position = in_writer.Position; + + in_writer.WriteStringNullTerminated(Path); + in_writer.Align(16); + + chunkHeader.FinishWrite(in_writer, (uint)(in_writer.Position - position), ChunkHeader.DefaultHeaderSize, 0x40, 0); + } + + public static FourCC GetResourceIDFromPath(string in_path) + { + var id = " "; + var extension = System.IO.Path.GetExtension(in_path).ToLower(); + + switch (extension) + { + case ".dds": + id = "DDS "; + break; + + case ".xncp": + id = "FAPC"; + break; + + case var _ when FileSystemName.MatchesSimpleExpression(".xn*", extension): + id = "NXIF"; + break; + + default: + Logger.Warning($"[ResourcePathChunk] Couldn't determine resource ID from extension: {extension}"); + break; + }; + + return new FourCC(id); + } + } +} diff --git a/Marathon/Formats/Acroarts/Chunks/TrunkChunk.cs b/Marathon/Formats/Acroarts/Chunks/TrunkChunk.cs new file mode 100644 index 00000000..0275ac81 --- /dev/null +++ b/Marathon/Formats/Acroarts/Chunks/TrunkChunk.cs @@ -0,0 +1,113 @@ +using Marathon.Exceptions; +using Marathon.Formats.Acroarts.Types; +using Marathon.IO; +using Marathon.IO.Extensions; +using System.Collections.Generic; + +namespace Marathon.Formats.Acroarts.Chunks +{ + public class TrunkChunk : IBinarySerializableEx + { + public const string ID = "ABDT"; // "Acroarts Binary Data Trunk" + + public uint Flags { get; set; } + + public int TrunkID { get; set; } = -1; + + public float ClipRange { get; set; } = -1.0f; + + public float ClipZRange { get; set; } = -1.0f; + + public float StartTime { get; set; } + + public float EndTime { get; set; } = -1.0f; + + public List Branches { get; set; } = []; + + public TrunkChunk() { } + + public TrunkChunk(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + var chunkHeader = in_reader.ReadObject(); + + if (!chunkHeader.ID.Equals(ID)) + throw new InvalidSignatureException(ID, chunkHeader.ID); + + var version = in_reader.Read(); + + if (version != AckResource.Version) + throw new InvalidSignatureException(AckResource.Version, version); + + Flags = in_reader.Read(); + TrunkID = in_reader.Read(); + ClipRange = in_reader.Read(); + ClipZRange = in_reader.Read(); + StartTime = in_reader.Read(); + EndTime = in_reader.Read(); + + var simpleNoticeCount = in_reader.Read(); + var simpleNoticeTableOffset = in_reader.Read(); + + // TODO: handle simple notice table. + + var branchCount = in_reader.Read(); + var branchTableOffset = in_reader.Read(); + + in_reader.JumpTo(in_reader.CalculateOffset(branchTableOffset)); + + for (uint i = 0; i < branchCount; i++) + { + var branchOffset = in_reader.Read(); + + in_reader.ReadAtOffset(in_reader.CalculateOffset(branchOffset), () => + { + Branches.Add(new Branch(in_reader)); + }); + } + } + + public void Write(BinaryObjectWriterEx in_writer) + { + var chunkHeader = new ChunkHeader(in_writer, ID); + + in_writer.Write(AckResource.Version); + in_writer.Write(Flags); + in_writer.Write(TrunkID); + in_writer.Write(ClipRange); + in_writer.Write(ClipZRange); + in_writer.Write(StartTime); + in_writer.Write(EndTime); + + // TODO: simple notice tables. + in_writer.WriteZero(); + + if (Branches.Count <= 0) + { + in_writer.WriteZero(); + } + else + { + in_writer.Write(Branches.Count); + in_writer.WriteOffset((uint)in_writer.CalculateOffset(in_writer.Position + sizeof(uint), OffsetType.Relative)); // Branch table offset. + + var branchOffsets = new List(); + + for (int i = 0; i < Branches.Count; i++) + branchOffsets.Add(in_writer.Reserve()); + + for (int i = 0; i < Branches.Count; i++) + { + in_writer.WriteReserved(branchOffsets[i], (uint)in_writer.CalculateOffset(in_writer.Position, OffsetType.Relative), false); + Branches[i].Write(in_writer); + } + } + + chunkHeader.FinishWrite(in_writer); + } + } +} diff --git a/Marathon/Formats/Acroarts/Chunks/UndefinedChunk.cs b/Marathon/Formats/Acroarts/Chunks/UndefinedChunk.cs new file mode 100644 index 00000000..a40e95d9 --- /dev/null +++ b/Marathon/Formats/Acroarts/Chunks/UndefinedChunk.cs @@ -0,0 +1,49 @@ +using Marathon.Helpers; +using Marathon.Helpers.Converters; +using Marathon.IO; +using Marathon.IO.Extensions; +using Marathon.IO.Types; +using Newtonsoft.Json; + +namespace Marathon.Formats.Acroarts.Chunks +{ + public class UndefinedChunk : IBinarySerializableEx + { + public string ChunkID { get; set; } + + public FourCC Signature { get; set; } + + [JsonConverter(typeof(ByteArrayToHexStringConverter))] + public byte[] Data { get; set; } + + public UndefinedChunk() { } + + public UndefinedChunk(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + + ChunkID = Signature.ToString(); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + Signature = in_reader.ReadObject(); + + var chunkLength = in_reader.Read(); + + Data = in_reader.ReadBytes((int)chunkLength); + + Logger.Warning($"Encountered undefined chunk at 0x{in_reader.OffsetOrigin:X8}: {Signature}"); + } + + public void Write(BinaryObjectWriterEx in_writer) + { + in_writer.WriteObject(Signature); + + var length = in_writer.Reserve(); + + in_writer.WriteBytes(Data); + in_writer.WriteReserved(length, (int)(in_writer.Position - (length + 4))); + } + } +} diff --git a/Marathon/Formats/Acroarts/Collections/IndirectList.cs b/Marathon/Formats/Acroarts/Collections/IndirectList.cs new file mode 100644 index 00000000..76f5d166 --- /dev/null +++ b/Marathon/Formats/Acroarts/Collections/IndirectList.cs @@ -0,0 +1,108 @@ +using Marathon.IO; +using Marathon.IO.Extensions; +using System; +using System.Collections.Generic; + +namespace Marathon.Formats.Acroarts.Collections +{ + public class IndirectList + { + public static (uint Count, uint Offset) ReadInfo(BinaryObjectReaderEx in_reader) + { + var count = in_reader.Read(); + var offset = in_reader.Read(); + + return (count, offset); + } + + public static (uint Count, uint Offset) PeekInfo(BinaryObjectReaderEx in_reader) + { + var pos = in_reader.Position; + var result = ReadInfo(in_reader); + + in_reader.JumpTo(pos); + + return result; + } + } + + public class IndirectList : List + { + private long _infoPtrOffset = 0; + private readonly List _arrayPtrOffsets = []; + + public IndirectList() { } + + public IndirectList(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + var (count, offset) = IndirectList.ReadInfo(in_reader); + + in_reader.ReadAtOffset(in_reader.CalculateOffset(offset), () => + { + for (uint i = 0; i < count; i++) + { + var dataOffset = in_reader.Read(); + + in_reader.ReadAtOffset(in_reader.CalculateOffset(dataOffset), () => + { + Add(ReadImpl(in_reader)); + }); + } + }); + } + + public virtual T ReadImpl(BinaryObjectReaderEx in_reader) + { + throw new NotImplementedException(); + } + + public void WriteInfo(BinaryObjectWriterEx in_writer) + { + if (Count <= 0) + { + in_writer.WriteZero(); + return; + } + + in_writer.Write(Count); + _infoPtrOffset = in_writer.Reserve(); + } + + public void WriteArray(BinaryObjectWriterEx in_writer) + { + if (Count <= 0) + return; + + in_writer.WriteReserved(_infoPtrOffset, (uint)in_writer.CalculateOffset(in_writer.Position, OffsetType.Relative)); + + for (int i = 0; i < Count; i++) + _arrayPtrOffsets.Add(in_writer.Reserve()); + } + + public void WriteData(BinaryObjectWriterEx in_writer) + { + for (int i = 0; i < Count; i++) + { + in_writer.WriteReserved(_arrayPtrOffsets[i], (uint)in_writer.CalculateOffset(in_writer.Position, OffsetType.Relative), false); + WriteDataImpl(in_writer, this[i]); + } + } + + public virtual void WriteDataImpl(BinaryObjectWriterEx in_writer, T in_object) + { + throw new NotImplementedException(); + } + + public void Write(BinaryObjectWriterEx in_writer) + { + WriteInfo(in_writer); + WriteArray(in_writer); + WriteData(in_writer); + } + } +} diff --git a/Marathon/Formats/Acroarts/Collections/IndirectMomentumParamList.cs b/Marathon/Formats/Acroarts/Collections/IndirectMomentumParamList.cs new file mode 100644 index 00000000..c4c89c68 --- /dev/null +++ b/Marathon/Formats/Acroarts/Collections/IndirectMomentumParamList.cs @@ -0,0 +1,32 @@ +using Marathon.Formats.Acroarts.Types.Momentums; +using Marathon.IO; + +namespace Marathon.Formats.Acroarts.Collections +{ + public class IndirectMomentumParamList : IndirectList where T : IMomentumParamSet, new() + { + public IndirectMomentumParamList() { } + + public IndirectMomentumParamList(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public override T ReadImpl(BinaryObjectReaderEx in_reader) + { + var paramCount = in_reader.Read(); + var paramOffset = in_reader.Read(); + + in_reader.JumpTo(in_reader.CalculateOffset(paramOffset)); + + return in_reader.ReadObjectEx(); + } + + public override void WriteDataImpl(BinaryObjectWriterEx in_writer, T in_object) + { + in_writer.Write(in_object.GetParamCount()); + in_writer.WriteOffset((uint)in_writer.CalculateOffset(in_writer.Position + sizeof(uint), OffsetType.Relative)); + in_writer.WriteObjectEx(in_object); + } + } +} diff --git a/Marathon/Formats/Acroarts/Collections/IndirectObjectList.cs b/Marathon/Formats/Acroarts/Collections/IndirectObjectList.cs new file mode 100644 index 00000000..dba2b101 --- /dev/null +++ b/Marathon/Formats/Acroarts/Collections/IndirectObjectList.cs @@ -0,0 +1,24 @@ +using Marathon.IO; + +namespace Marathon.Formats.Acroarts.Collections +{ + public class IndirectObjectList : IndirectList where T : IBinarySerializableEx, new() + { + public IndirectObjectList() { } + + public IndirectObjectList(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public override T ReadImpl(BinaryObjectReaderEx in_reader) + { + return in_reader.ReadObjectEx(); + } + + public override void WriteDataImpl(BinaryObjectWriterEx in_writer, T in_object) + { + in_writer.WriteObjectEx(in_object); + } + } +} diff --git a/Marathon/Formats/Acroarts/Collections/IndirectUnmanagedList.cs b/Marathon/Formats/Acroarts/Collections/IndirectUnmanagedList.cs new file mode 100644 index 00000000..f7d2afa9 --- /dev/null +++ b/Marathon/Formats/Acroarts/Collections/IndirectUnmanagedList.cs @@ -0,0 +1,24 @@ +using Marathon.IO; + +namespace Marathon.Formats.Acroarts.Collections +{ + public class IndirectUnmanagedList : IndirectList where T : unmanaged + { + public IndirectUnmanagedList() { } + + public IndirectUnmanagedList(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public override T ReadImpl(BinaryObjectReaderEx in_reader) + { + return in_reader.Read(); + } + + public override void WriteDataImpl(BinaryObjectWriterEx in_writer, T in_object) + { + in_writer.Write(in_object); + } + } +} diff --git a/Marathon/Formats/Acroarts/Types/Branch.cs b/Marathon/Formats/Acroarts/Types/Branch.cs new file mode 100644 index 00000000..56d89c03 --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Branch.cs @@ -0,0 +1,157 @@ +using Marathon.Helpers; +using Marathon.IO; +using Marathon.IO.Extensions; +using System.Collections.Generic; + +namespace Marathon.Formats.Acroarts.Types +{ + public class Branch : IBinarySerializableEx + { + public uint Flags { get; set; } + + public int ID { get; set; } + + public float ClipRange { get; set; } + + public float ClipZRange { get; set; } + + public float StartTime { get; set; } + + public float EndTime { get; set; } + + public uint CoordTarget { get; set; } + + public uint CoordBranchIndex { get; set; } + + public int CoordNode { get; set; } + + public string CoordNodeName { get; set; } + + public uint CoordType { get; set; } + + public int MessageParam0 { get; set; } = -1; + + public int MessageParam1 { get; set; } = -1; + + public int SortGroup { get; set; } + + public int LoopCount { get; set; } + + public List Leaves { get; set; } = []; + + public Branch() { } + + public Branch(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + Flags = in_reader.Read(); + ID = in_reader.Read(); + ClipRange = in_reader.Read(); + ClipZRange = in_reader.Read(); + StartTime = in_reader.Read(); + EndTime = in_reader.Read(); + CoordTarget = in_reader.Read(); + CoordBranchIndex = in_reader.Read(); + CoordNode = in_reader.Read(); + + var coordNodeNameOffset = in_reader.Read(); + + if (coordNodeNameOffset != 0) + { + in_reader.ReadAtOffset(in_reader.CalculateOffset(coordNodeNameOffset), + () => CoordNodeName = in_reader.ReadStringNullTerminated()); + } + + CoordType = in_reader.Read(); + MessageParam0 = in_reader.Read(); + MessageParam1 = in_reader.Read(); + + // TODO: no files in '06 use these. + var chainCount = in_reader.Read(); + var chainTableOffset = in_reader.Read(); + + if (chainCount > 0) + Logger.Warning($"[Branch] {chainCount} chains at 0x{chainTableOffset:X08}."); + + SortGroup = in_reader.Read(); + LoopCount = in_reader.Read(); + + var leafCount = in_reader.Read(); + var leafTableOffset = in_reader.Read(); + + in_reader.JumpTo(in_reader.CalculateOffset(leafTableOffset)); + + for (uint i = 0; i < leafCount; i++) + { + var leafOffset = in_reader.Read(); + + in_reader.ReadAtOffset(in_reader.CalculateOffset(leafOffset), () => + { + Leaves.Add(new Leaf(in_reader)); + }); + } + } + + public void Write(BinaryObjectWriterEx in_writer) + { + in_writer.Write(Flags); + in_writer.Write(ID); + in_writer.Write(ClipRange); + in_writer.Write(ClipZRange); + in_writer.Write(StartTime); + in_writer.Write(EndTime); + in_writer.Write(CoordTarget); + in_writer.Write(CoordBranchIndex); + in_writer.Write(CoordNode); + + var coordNodeNameOffset = 0L; + + if (string.IsNullOrEmpty(CoordNodeName)) + { + in_writer.WriteZero(); + } + else + { + coordNodeNameOffset = in_writer.Reserve(); + } + + in_writer.Write(CoordType); + in_writer.Write(MessageParam0); + in_writer.Write(MessageParam1); + in_writer.WriteZero(); // TODO: chainCount/chainTableOffset + in_writer.Write(SortGroup); + in_writer.Write(LoopCount); + + if (Leaves.Count <= 0) + { + in_writer.WriteZero(); + } + else + { + in_writer.Write(Leaves.Count); + in_writer.WriteOffset((uint)in_writer.CalculateOffset(in_writer.Position + sizeof(uint), OffsetType.Relative)); // Leaf table offset. + + var leafOffsets = new List(); + + for (int i = 0; i < Leaves.Count; i++) + leafOffsets.Add(in_writer.Reserve()); + + if (!string.IsNullOrEmpty(CoordNodeName)) + { + in_writer.WriteReserved(coordNodeNameOffset, (uint)in_writer.CalculateOffset(in_writer.Position, OffsetType.Relative), false); + in_writer.WriteStringFixedLength(CoordNodeName, ((CoordNodeName.Length + 15) / 16) * 16); + } + + for (int i = 0; i < Leaves.Count; i++) + { + in_writer.WriteReserved(leafOffsets[i], (uint)in_writer.CalculateOffset(in_writer.Position, OffsetType.Relative), false); + Leaves[i].Write(in_writer); + } + } + } + } +} diff --git a/Marathon/Formats/Acroarts/Types/Leaf.cs b/Marathon/Formats/Acroarts/Types/Leaf.cs new file mode 100644 index 00000000..196030a5 --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Leaf.cs @@ -0,0 +1,248 @@ +using Marathon.Formats.Acroarts.Types.Resources; +using Marathon.Helpers; +using Marathon.IO; +using Marathon.IO.Extensions; +using Marathon.IO.Types; +using System.Collections.Generic; +using System.Numerics; + +namespace Marathon.Formats.Acroarts.Types +{ + public class Leaf : IBinarySerializableEx + { + public uint Flags { get; set; } + + public int ID { get; set; } = -1; + + public uint CoordType { get; set; } = 1; + + public float LifeTimeMin { get; set; } + + public float LifeTimeMax { get; set; } + + public float SleepTime { get; set; } + + public float DelayTimeMax { get; set; } + + public float GenInterval { get; set; } + + public float GenLifeTime { get; set; } + + public float GenRate { get; set; } + + public float GenCountMin { get; set; } + + public float GenCountMax { get; set; } + + public float LODDistStart { get; set; } + + public float LODDistEnd { get; set; } + + public float LODRate { get; set; } + + public float LODCountMin { get; set; } + + public float LODCountMax { get; set; } + + public int MessageParam0 { get; set; } + + public int MessageParam1 { get; set; } + + public float ClipRange { get; set; } + + public float ClipZNearRange { get; set; } + + public float ClipZFarRange { get; set; } = -1.0f; + + public int BlendMode { get; set; } + + public uint ToLeafCoordTarget { get; set; } + + public uint ToLeafCoordType { get; set; } + + public uint ToLeafCoordNode { get; set; } + + public string ModelAttachNodeName { get; set; } + + public int ModelType { get; set; } + + public uint UnknownField { get; set; } + + public Rectangle Primitive { get; set; } + + public ResourceType ResourceType { get; set; } + + public IResourceTable Resources { get; set; } + + public uint TrOpCtrlFlag { get; set; } + + public uint ModelCount { get; set; } + + public uint MotionCount { get; set; } + + public uint TextureCount { get; set; } + + public List MomentumLists { get; set; } = []; + + public Leaf() { } + + public Leaf(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + Flags = in_reader.Read(); + ID = in_reader.Read(); + CoordType = in_reader.Read(); + LifeTimeMin = in_reader.Read(); + LifeTimeMax = in_reader.Read(); + SleepTime = in_reader.Read(); + DelayTimeMax = in_reader.Read(); + GenInterval = in_reader.Read(); + GenLifeTime = in_reader.Read(); + GenRate = in_reader.Read(); + GenCountMin = in_reader.Read(); + GenCountMax = in_reader.Read(); + LODDistStart = in_reader.Read(); + LODDistEnd = in_reader.Read(); + LODRate = in_reader.Read(); + LODCountMin = in_reader.Read(); + LODCountMax = in_reader.Read(); + MessageParam0 = in_reader.Read(); + MessageParam1 = in_reader.Read(); + ClipRange = in_reader.Read(); + ClipZNearRange = in_reader.Read(); + ClipZFarRange = in_reader.Read(); + BlendMode = in_reader.Read(); + ToLeafCoordTarget = in_reader.Read(); + ToLeafCoordType = in_reader.Read(); + ToLeafCoordNode = in_reader.Read(); + + var modelAttachNodeNameOffset = in_reader.Read(); + + if (modelAttachNodeNameOffset != 0) + { + in_reader.ReadAtOffset(in_reader.CalculateOffset(modelAttachNodeNameOffset), + () => ModelAttachNodeName = in_reader.ReadStringNullTerminated()); + } + + ModelType = in_reader.Read(); + UnknownField = in_reader.Read(); + Primitive = in_reader.Read(); + ResourceType = in_reader.Read(); + Resources = ResourceTableFactory.ReadResourceTableByType(in_reader, ResourceType); + TrOpCtrlFlag = in_reader.Read(); + ModelCount = in_reader.Read(); + MotionCount = in_reader.Read(); + TextureCount = in_reader.Read(); + + if (ModelCount > 0 || MotionCount > 0 || TextureCount > 0) + Logger.Warning($"[Leaf] Model Count: {ModelCount}; Motion Count: {MotionCount}; Texture Count: {TextureCount}"); + + var momentumListCount = in_reader.Read(); + var momentumListTableOffset = in_reader.Read(); + + in_reader.JumpTo(in_reader.CalculateOffset(momentumListTableOffset)); + + for (uint i = 0; i < momentumListCount; i++) + { + var momentumListOffset = in_reader.Read(); + + in_reader.ReadAtOffset(in_reader.CalculateOffset(momentumListOffset), () => + { + MomentumLists.Add(new MomentumList(in_reader)); + }); + } + } + + public void Write(BinaryObjectWriterEx in_writer) + { + in_writer.Write(Flags); + in_writer.Write(ID); + in_writer.Write(CoordType); + in_writer.Write(LifeTimeMin); + in_writer.Write(LifeTimeMax); + in_writer.Write(SleepTime); + in_writer.Write(DelayTimeMax); + in_writer.Write(GenInterval); + in_writer.Write(GenLifeTime); + in_writer.Write(GenRate); + in_writer.Write(GenCountMin); + in_writer.Write(GenCountMax); + in_writer.Write(LODDistStart); + in_writer.Write(LODDistEnd); + in_writer.Write(LODRate); + in_writer.Write(LODCountMin); + in_writer.Write(LODCountMax); + in_writer.Write(MessageParam0); + in_writer.Write(MessageParam1); + in_writer.Write(ClipRange); + in_writer.Write(ClipZNearRange); + in_writer.Write(ClipZFarRange); + in_writer.Write(BlendMode); + in_writer.Write(ToLeafCoordTarget); + in_writer.Write(ToLeafCoordType); + in_writer.Write(ToLeafCoordNode); + + var modelAttachNodeNameOffset = 0L; + + if (string.IsNullOrEmpty(ModelAttachNodeName)) + { + in_writer.WriteZero(); + } + else + { + modelAttachNodeNameOffset = in_writer.Reserve(); + } + + in_writer.Write(ModelType); + in_writer.Write(UnknownField); + in_writer.Write(Primitive); + in_writer.Write(ResourceType); + + Resources.WriteInfo(in_writer); + + in_writer.Write(TrOpCtrlFlag); + in_writer.Write(ModelCount); + in_writer.Write(MotionCount); + in_writer.Write(TextureCount); + + if (MomentumLists.Count <= 0) + { + in_writer.WriteZero(); + + Resources.WriteArray(in_writer); + } + else + { + in_writer.Write(MomentumLists.Count); + var momentumListTableOffset = in_writer.Reserve(); + + if (!string.IsNullOrEmpty(ModelAttachNodeName)) + { + in_writer.WriteReserved(modelAttachNodeNameOffset, (uint)in_writer.CalculateOffset(in_writer.Position, OffsetType.Relative), false); + in_writer.WriteStringFixedLength(ModelAttachNodeName, ((ModelAttachNodeName.Length + 15) / 16) * 16); + } + + in_writer.WriteReserved(momentumListTableOffset, (uint)in_writer.CalculateOffset(in_writer.Position, OffsetType.Relative), false); + + var momentumListOffsets = new List(); + + for (int i = 0; i < MomentumLists.Count; i++) + momentumListOffsets.Add(in_writer.Reserve()); + + Resources.WriteArray(in_writer); + + for (int i = 0; i < MomentumLists.Count; i++) + { + in_writer.WriteReserved(momentumListOffsets[i], (uint)in_writer.CalculateOffset(in_writer.Position, OffsetType.Relative), false); + MomentumLists[i].Write(in_writer); + } + } + + Resources.WriteData(in_writer); + } + } +} diff --git a/Marathon/Formats/Acroarts/Types/Momentum.cs b/Marathon/Formats/Acroarts/Types/Momentum.cs new file mode 100644 index 00000000..d379718e --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Momentum.cs @@ -0,0 +1,80 @@ +using Marathon.Formats.Acroarts.Types.Momentums; +using Marathon.Helpers; +using Marathon.IO; +using Marathon.IO.Extensions; + +namespace Marathon.Formats.Acroarts.Types +{ + public class Momentum : IBinarySerializableEx + { + public uint Flags { get; set; } + + public MomentumType Type { get; set; } + + public int SwitchID { get; set; } = -1; + + public float StartTime { get; set; } + + public float EndTime { get; set; } + + public IMomentumParamSet Params { get; set; } + + public Momentum() { } + + public Momentum(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + var position = in_reader.Position; + + Flags = in_reader.Read(); + Type = in_reader.Read(); + SwitchID = in_reader.Read(); + StartTime = in_reader.Read(); + EndTime = in_reader.Read(); + + var paramPosition = in_reader.Position; + var paramCount = in_reader.Read(); + var paramOffset = in_reader.Read(); + + in_reader.JumpTo(in_reader.CalculateOffset(paramOffset)); + + Params = MomentumFactory.ReadMomentumByType(in_reader, Type); + + if (Params == null) + { + in_reader.JumpTo(paramPosition); + + Params = new AnonymousMomentumParamSet(in_reader); + + Logger.Warning($"[Momentum] Unimplemented type at 0x{position:X08} of length {paramCount * 4}: {Type}"); + } + } + + public void Write(BinaryObjectWriterEx in_writer) + { + in_writer.Write(Flags); + in_writer.Write(Type); + in_writer.Write(SwitchID); + in_writer.Write(StartTime); + in_writer.Write(EndTime); + + var paramCount = Params.GetParamCount(); + + if (paramCount <= 0) + { + in_writer.WriteZero(); + } + else + { + in_writer.Write(Params.GetParamCount()); + in_writer.WriteOffset((uint)in_writer.CalculateOffset(in_writer.Position + sizeof(uint), OffsetType.Relative)); // Params offset. + + Params.Write(in_writer); + } + } + } +} diff --git a/Marathon/Formats/Acroarts/Types/MomentumList.cs b/Marathon/Formats/Acroarts/Types/MomentumList.cs new file mode 100644 index 00000000..ba99f224 --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/MomentumList.cs @@ -0,0 +1,90 @@ +using Marathon.Helpers; +using Marathon.IO; +using Marathon.IO.Extensions; +using System.Collections.Generic; + +namespace Marathon.Formats.Acroarts.Types +{ + public class MomentumList : IBinarySerializableEx + { + public uint Flags { get; set; } + + public int ID { get; set; } + + public uint CoordTarget { get; set; } + + public uint CoordType { get; set; } = 1; + + public uint CoordNode { get; set; } + + public List Momentums { get; set; } = []; + + public MomentumList() { } + + public MomentumList(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + Flags = in_reader.Read(); + ID = in_reader.Read(); + CoordTarget = in_reader.Read(); + CoordType = in_reader.Read(); + CoordNode = in_reader.Read(); + + // TODO: test this. + var unkField = in_reader.Read(); + + if (unkField > 0) + Logger.Warning($"[MomentumList] Unknown field is non-zero: {unkField}"); + + var momentumCount = in_reader.Read(); + var momentumTableOffset = in_reader.Read(); + + in_reader.JumpTo(in_reader.CalculateOffset(momentumTableOffset)); + + for (uint i = 0; i < momentumCount; i++) + { + var momentumOffset = in_reader.Read(); + + in_reader.ReadAtOffset(in_reader.CalculateOffset(momentumOffset), () => + { + Momentums.Add(new Momentum(in_reader)); + }); + } + } + + public void Write(BinaryObjectWriterEx in_writer) + { + in_writer.Write(Flags); + in_writer.Write(ID); + in_writer.Write(CoordTarget); + in_writer.Write(CoordType); + in_writer.Write(CoordNode); + in_writer.WriteZero(); // TODO: unkField + + if (Momentums.Count <= 0) + { + in_writer.WriteZero(); + } + else + { + in_writer.Write(Momentums.Count); + in_writer.WriteOffset((uint)in_writer.CalculateOffset(in_writer.Position + sizeof(uint), OffsetType.Relative)); // Momentum table offset. + + var momentumOffsets = new List(); + + for (int i = 0; i < Momentums.Count; i++) + momentumOffsets.Add(in_writer.Reserve()); + + for (int i = 0; i < Momentums.Count; i++) + { + in_writer.WriteReserved(momentumOffsets[i], (uint)in_writer.CalculateOffset(in_writer.Position, OffsetType.Relative), false); + Momentums[i].Write(in_writer); + } + } + } + } +} diff --git a/Marathon/Formats/Acroarts/Types/Momentums/AmbientLight.cs b/Marathon/Formats/Acroarts/Types/Momentums/AmbientLight.cs new file mode 100644 index 00000000..d8a7347c --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Momentums/AmbientLight.cs @@ -0,0 +1,32 @@ +using Marathon.IO; +using Marathon.IO.Types; + +namespace Marathon.Formats.Acroarts.Types.Momentums +{ + public class AmbientLight : IMomentumParamSet + { + public Color Color { get; set; } + + public AmbientLight() { } + + public AmbientLight(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + Color = in_reader.ReadObject>(); + } + + public void Write(BinaryObjectWriterEx in_writer) + { + in_writer.WriteObject(Color); + } + + public uint GetParamCount() + { + return 4; + } + } +} diff --git a/Marathon/Formats/Acroarts/Types/Momentums/AnonymousMomentumParam.cs b/Marathon/Formats/Acroarts/Types/Momentums/AnonymousMomentumParam.cs new file mode 100644 index 00000000..2a99491e --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Momentums/AnonymousMomentumParam.cs @@ -0,0 +1,111 @@ +using Marathon.IO; +using Newtonsoft.Json; +using System; +using System.Runtime.InteropServices; + +namespace Marathon.Formats.Acroarts.Types.Momentums +{ + public class AnonymousMomentumParam : IBinarySerializableEx + { + public uint Data { get; set; } + + [JsonIgnore] + public uint UInt32 => Data; + + [JsonIgnore] + public int Int32 + { + get => GetValue(); + set => SetValue(value); + } + + [JsonIgnore] + public int Angle => Int32; + + [JsonIgnore] + public float Float + { + get => GetValue(); + set => SetValue(value); + } + + public AnonymousMomentumParam() { } + + public AnonymousMomentumParam(uint in_data) + { + Data = in_data; + } + + public AnonymousMomentumParam(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + Data = in_reader.Read(); + } + + public void Write(BinaryObjectWriterEx in_writer) + { + in_writer.Write(Data); + } + + public T GetValue() where T : unmanaged + { + if (typeof(T) == typeof(uint)) + { + return (T)(object)Data; + } + else if (typeof(T) == typeof(float)) + { + var buffer = BitConverter.GetBytes(Data); + return (T)(object)BitConverter.ToSingle(buffer, 0); + } + + if (Marshal.SizeOf() > 4) + throw new NotSupportedException(); + + try + { + return (T)Convert.ChangeType(Data, typeof(T)); + } + catch + { + return default; + } + } + + public void SetValue(T in_value) where T : unmanaged + { + if (typeof(T) == typeof(uint)) + { + Data = (uint)(object)in_value; + return; + } + else if (typeof(T) == typeof(float)) + { + var buffer = BitConverter.GetBytes((float)(object)in_value); + Data = BitConverter.ToUInt32(buffer); + return; + } + + if (Marshal.SizeOf() > 4) + throw new NotSupportedException(); + + try + { + Data = (uint)Convert.ChangeType(in_value, typeof(uint)); + } + catch + { + Data = default; + } + } + + public override string ToString() + { + return Data.ToString(); + } + } +} diff --git a/Marathon/Formats/Acroarts/Types/Momentums/AnonymousMomentumParamSet.cs b/Marathon/Formats/Acroarts/Types/Momentums/AnonymousMomentumParamSet.cs new file mode 100644 index 00000000..13bc8faf --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Momentums/AnonymousMomentumParamSet.cs @@ -0,0 +1,41 @@ +using Marathon.IO; +using System.Collections.Generic; + +namespace Marathon.Formats.Acroarts.Types.Momentums +{ + public class AnonymousMomentumParamSet : List, IMomentumParamSet + { + public AnonymousMomentumParamSet() { } + + public AnonymousMomentumParamSet(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + var paramCount = in_reader.Read(); + var paramOffset = in_reader.Read(); + + in_reader.ReadAtOffset(in_reader.CalculateOffset(paramOffset), () => + { + for (uint i = 0; i < paramCount; i++) + Add(new AnonymousMomentumParam(in_reader)); + }); + } + + public void Write(BinaryObjectWriterEx in_writer) + { + in_writer.Write(Count); + in_writer.WriteOffset((uint)in_writer.CalculateOffset(in_writer.Position + sizeof(uint), OffsetType.Relative)); + + for (int i = 0; i < Count; i++) + this[i].Write(in_writer); + } + + public uint GetParamCount() + { + return (uint)Count; + } + } +} diff --git a/Marathon/Formats/Acroarts/Types/Momentums/AxisType.cs b/Marathon/Formats/Acroarts/Types/Momentums/AxisType.cs new file mode 100644 index 00000000..e096705a --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Momentums/AxisType.cs @@ -0,0 +1,13 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + +namespace Marathon.Formats.Acroarts.Types.Momentums +{ + [JsonConverter(typeof(StringEnumConverter))] + public enum AxisType : int + { + X, + Y, + Z + } +} diff --git a/Marathon/Formats/Acroarts/Types/Momentums/BillboardTail.cs b/Marathon/Formats/Acroarts/Types/Momentums/BillboardTail.cs new file mode 100644 index 00000000..cd7df691 --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Momentums/BillboardTail.cs @@ -0,0 +1,121 @@ +using Marathon.IO; +using Marathon.IO.Types; +using System.Numerics; + +namespace Marathon.Formats.Acroarts.Types.Momentums +{ + public class BillboardTail : IMomentumParamSet + { + public uint UnknownField1 { get; set; } + + public float UnknownField2 { get; set; } + + public float UnknownField3 { get; set; } + + public float UnknownField4 { get; set; } + + public uint UnknownField5 { get; set; } + + public uint UnknownField6 { get; set; } + + public uint UnknownField7 { get; set; } + + public uint UnknownField8 { get; set; } + + public uint BlendMode { get; set; } + + public int NodeCount { get; set; } + + public float UnknownField9 { get; set; } + + public float UnknownField10 { get; set; } + + public float UnknownField11 { get; set; } + + public float UnknownField12 { get; set; } + + public Vector3 Position { get; set; } + + public Color Color { get; set; } + + public ColorApplyMode ColorApplyMode { get; set; } + + public float UnknownField13 { get; set; } + + public uint UnknownField14 { get; set; } + + public float UnknownField15 { get; set; } + + public uint UnknownField16 { get; set; } + + public float UnknownField17 { get; set; } + + public uint UnknownField18 { get; set; } + + public BillboardTail() { } + + public BillboardTail(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + UnknownField1 = in_reader.Read(); + UnknownField2 = in_reader.Read(); + UnknownField3 = in_reader.Read(); + UnknownField4 = in_reader.Read(); + UnknownField5 = in_reader.Read(); + UnknownField6 = in_reader.Read(); + UnknownField7 = in_reader.Read(); + UnknownField8 = in_reader.Read(); + BlendMode = in_reader.Read(); + NodeCount = in_reader.Read(); + UnknownField9 = in_reader.Read(); + UnknownField10 = in_reader.Read(); + UnknownField11 = in_reader.Read(); + UnknownField12 = in_reader.Read(); + Position = in_reader.Read(); + Color = in_reader.ReadObject>(); + ColorApplyMode = in_reader.Read(); + UnknownField13 = in_reader.Read(); + UnknownField14 = in_reader.Read(); + UnknownField15 = in_reader.Read(); + UnknownField16 = in_reader.Read(); + UnknownField17 = in_reader.Read(); + UnknownField18 = in_reader.Read(); + } + + public void Write(BinaryObjectWriterEx in_writer) + { + in_writer.Write(UnknownField1); + in_writer.Write(UnknownField2); + in_writer.Write(UnknownField3); + in_writer.Write(UnknownField4); + in_writer.Write(UnknownField5); + in_writer.Write(UnknownField6); + in_writer.Write(UnknownField7); + in_writer.Write(UnknownField8); + in_writer.Write(BlendMode); + in_writer.Write(NodeCount); + in_writer.Write(UnknownField9); + in_writer.Write(UnknownField10); + in_writer.Write(UnknownField11); + in_writer.Write(UnknownField12); + in_writer.Write(Position); + in_writer.WriteObject(Color); + in_writer.Write(ColorApplyMode); + in_writer.Write(UnknownField13); + in_writer.Write(UnknownField14); + in_writer.Write(UnknownField15); + in_writer.Write(UnknownField16); + in_writer.Write(UnknownField17); + in_writer.Write(UnknownField18); + } + + public uint GetParamCount() + { + return 28; + } + } +} diff --git a/Marathon/Formats/Acroarts/Types/Momentums/BlurBelt.cs b/Marathon/Formats/Acroarts/Types/Momentums/BlurBelt.cs new file mode 100644 index 00000000..8bcd526f --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Momentums/BlurBelt.cs @@ -0,0 +1,175 @@ +using Marathon.IO; + +namespace Marathon.Formats.Acroarts.Types.Momentums +{ + public class BlurBelt : IMomentumParamSet + { + public uint UnknownField1 { get; set; } + + public float UnknownField2 { get; set; } + + public float UnknownField3 { get; set; } + + public float UnknownField4 { get; set; } + + public uint UnknownField5 { get; set; } + + public uint UnknownField6 { get; set; } + + public uint UnknownField7 { get; set; } + + public uint UnknownField8 { get; set; } + + public uint UnknownField9 { get; set; } + + public uint UnknownField10 { get; set; } + + public uint UnknownField11 { get; set; } + + public float UnknownField12 { get; set; } + + public float UnknownField13 { get; set; } + + public float UnknownField14 { get; set; } + + public uint UnknownField15 { get; set; } + + public uint UnknownField16 { get; set; } + + public float UnknownField17 { get; set; } + + public uint UnknownField18 { get; set; } + + public uint UnknownField19 { get; set; } + + public uint UnknownField20 { get; set; } + + public int UnknownField21 { get; set; } + + public uint UnknownField22 { get; set; } + + public float UnknownField23 { get; set; } + + public float UnknownField24 { get; set; } + + public float UnknownField25 { get; set; } + + public float UnknownField26 { get; set; } + + public uint UnknownField27 { get; set; } + + public float UnknownField28 { get; set; } + + public uint UnknownField29 { get; set; } + + public uint UnknownField30 { get; set; } + + public uint UnknownField31 { get; set; } + + public uint UnknownField32 { get; set; } + + public float UnknownField33 { get; set; } + + public uint UnknownField34 { get; set; } + + public float UnknownField35 { get; set; } + + public uint UnknownField36 { get; set; } + + public float UnknownField37 { get; set; } + + public BlurBelt() { } + + public BlurBelt(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + UnknownField1 = in_reader.Read(); + UnknownField2 = in_reader.Read(); + UnknownField3 = in_reader.Read(); + UnknownField4 = in_reader.Read(); + UnknownField5 = in_reader.Read(); + UnknownField6 = in_reader.Read(); + UnknownField7 = in_reader.Read(); + UnknownField8 = in_reader.Read(); + UnknownField9 = in_reader.Read(); + UnknownField10 = in_reader.Read(); + UnknownField11 = in_reader.Read(); + UnknownField12 = in_reader.Read(); + UnknownField13 = in_reader.Read(); + UnknownField14 = in_reader.Read(); + UnknownField15 = in_reader.Read(); + UnknownField16 = in_reader.Read(); + UnknownField17 = in_reader.Read(); + UnknownField18 = in_reader.Read(); + UnknownField19 = in_reader.Read(); + UnknownField20 = in_reader.Read(); + UnknownField21 = in_reader.Read(); + UnknownField22 = in_reader.Read(); + UnknownField23 = in_reader.Read(); + UnknownField24 = in_reader.Read(); + UnknownField25 = in_reader.Read(); + UnknownField26 = in_reader.Read(); + UnknownField27 = in_reader.Read(); + UnknownField28 = in_reader.Read(); + UnknownField29 = in_reader.Read(); + UnknownField30 = in_reader.Read(); + UnknownField31 = in_reader.Read(); + UnknownField32 = in_reader.Read(); + UnknownField33 = in_reader.Read(); + UnknownField34 = in_reader.Read(); + UnknownField35 = in_reader.Read(); + UnknownField36 = in_reader.Read(); + UnknownField37 = in_reader.Read(); + } + + public void Write(BinaryObjectWriterEx in_writer) + { + in_writer.Write(UnknownField1); + in_writer.Write(UnknownField2); + in_writer.Write(UnknownField3); + in_writer.Write(UnknownField4); + in_writer.Write(UnknownField5); + in_writer.Write(UnknownField6); + in_writer.Write(UnknownField7); + in_writer.Write(UnknownField8); + in_writer.Write(UnknownField9); + in_writer.Write(UnknownField10); + in_writer.Write(UnknownField11); + in_writer.Write(UnknownField12); + in_writer.Write(UnknownField13); + in_writer.Write(UnknownField14); + in_writer.Write(UnknownField15); + in_writer.Write(UnknownField16); + in_writer.Write(UnknownField17); + in_writer.Write(UnknownField18); + in_writer.Write(UnknownField19); + in_writer.Write(UnknownField20); + in_writer.Write(UnknownField21); + in_writer.Write(UnknownField22); + in_writer.Write(UnknownField23); + in_writer.Write(UnknownField24); + in_writer.Write(UnknownField25); + in_writer.Write(UnknownField26); + in_writer.Write(UnknownField27); + in_writer.Write(UnknownField28); + in_writer.Write(UnknownField29); + in_writer.Write(UnknownField30); + in_writer.Write(UnknownField31); + in_writer.Write(UnknownField32); + in_writer.Write(UnknownField33); + in_writer.Write(UnknownField34); + in_writer.Write(UnknownField35); + in_writer.Write(UnknownField36); + in_writer.Write(UnknownField37); + } + + public uint GetParamCount() + { + return 37; + } + } +} diff --git a/Marathon/Formats/Acroarts/Types/Momentums/CellSpriteSceneSet.cs b/Marathon/Formats/Acroarts/Types/Momentums/CellSpriteSceneSet.cs new file mode 100644 index 00000000..cda0473c --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Momentums/CellSpriteSceneSet.cs @@ -0,0 +1,62 @@ +using Marathon.IO; + +namespace Marathon.Formats.Acroarts.Types.Momentums +{ + public class CellSpriteSceneSet : IMomentumParamSet + { + public string SceneName { get; set; } + + public string SceneMotionName { get; set; } + + public int UnknownField1 { get; set; } + + public float UnknownField2 { get; set; } + + public uint UnknownField3 { get; set; } + + public CellSpriteSceneSet() { } + + public CellSpriteSceneSet(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + var sceneNameOffset = in_reader.Read(); + var sceneMotionNameOffset = in_reader.Read(); + UnknownField1 = in_reader.Read(); + UnknownField2 = in_reader.Read(); + UnknownField3 = in_reader.Read(); + + if (sceneNameOffset != 0) + { + in_reader.ReadAtOffset(in_reader.CalculateOffset(sceneNameOffset), + () => SceneName = MomentumString.Read(in_reader)); + } + + if (sceneMotionNameOffset != 0) + { + in_reader.ReadAtOffset(in_reader.CalculateOffset(sceneMotionNameOffset), + () => SceneMotionName = MomentumString.Read(in_reader)); + } + } + + public void Write(BinaryObjectWriterEx in_writer) + { + var sceneNameOffset = in_writer.Reserve(); + var sceneMotionNameOffset = in_writer.Reserve(); + in_writer.Write(UnknownField1); + in_writer.Write(UnknownField2); + in_writer.Write(UnknownField3); + + MomentumString.Write(in_writer, SceneName, sceneNameOffset); + MomentumString.Write(in_writer, SceneMotionName, sceneMotionNameOffset); + } + + public uint GetParamCount() + { + return 5; + } + } +} diff --git a/Marathon/Formats/Acroarts/Types/Momentums/ClipPlane.cs b/Marathon/Formats/Acroarts/Types/Momentums/ClipPlane.cs new file mode 100644 index 00000000..25d171d7 --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Momentums/ClipPlane.cs @@ -0,0 +1,35 @@ +using Marathon.IO; + +namespace Marathon.Formats.Acroarts.Types.Momentums +{ + public class ClipPlane : IMomentumParamSet + { + public float Near { get; set; } + + public float Far { get; set; } + + public ClipPlane() { } + + public ClipPlane(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + Near = in_reader.Read(); + Far = in_reader.Read(); + } + + public void Write(BinaryObjectWriterEx in_writer) + { + in_writer.Write(Near); + in_writer.Write(Far); + } + + public uint GetParamCount() + { + return 2; + } + } +} diff --git a/Marathon/Formats/Acroarts/Types/Momentums/ColorApplyMode.cs b/Marathon/Formats/Acroarts/Types/Momentums/ColorApplyMode.cs new file mode 100644 index 00000000..fc7ba774 --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Momentums/ColorApplyMode.cs @@ -0,0 +1,14 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + +namespace Marathon.Formats.Acroarts.Types.Momentums +{ + [JsonConverter(typeof(StringEnumConverter))] + public enum ColorApplyMode : int + { + None, + Replace, + Addition, + Multiplication + } +} diff --git a/Marathon/Formats/Acroarts/Types/Momentums/ColorBlendMode.cs b/Marathon/Formats/Acroarts/Types/Momentums/ColorBlendMode.cs new file mode 100644 index 00000000..7a19e01f --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Momentums/ColorBlendMode.cs @@ -0,0 +1,14 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + +namespace Marathon.Formats.Acroarts.Types.Momentums +{ + [JsonConverter(typeof(StringEnumConverter))] + public enum ColorBlendMode : int + { + Modulation, + Addition, + Subtraction, + Replace + } +} diff --git a/Marathon/Formats/Acroarts/Types/Momentums/ColorKeyFrame.cs b/Marathon/Formats/Acroarts/Types/Momentums/ColorKeyFrame.cs new file mode 100644 index 00000000..3ef3ea33 --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Momentums/ColorKeyFrame.cs @@ -0,0 +1,36 @@ +using Marathon.IO; +using Marathon.IO.Types; + +namespace Marathon.Formats.Acroarts.Types.Momentums +{ + public class ColorKeyFrame : IMomentumParamSet + { + public float Frame { get; set; } + + public Color Color { get; set; } + + public ColorKeyFrame() { } + + public ColorKeyFrame(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + Frame = in_reader.Read(); + Color = in_reader.ReadObject>(); + } + + public void Write(BinaryObjectWriterEx in_writer) + { + in_writer.Write(Frame); + in_writer.WriteObject(Color); + } + + public uint GetParamCount() + { + return 5; + } + } +} diff --git a/Marathon/Formats/Acroarts/Types/Momentums/DetachCoordinate.cs b/Marathon/Formats/Acroarts/Types/Momentums/DetachCoordinate.cs new file mode 100644 index 00000000..b54760e9 --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Momentums/DetachCoordinate.cs @@ -0,0 +1,35 @@ +using Marathon.IO; + +namespace Marathon.Formats.Acroarts.Types.Momentums +{ + public class DetachCoordinate : IMomentumParamSet + { + public float UnknownField1 { get; set; } + + public GTCounter GTCounter { get; set; } + + public DetachCoordinate() { } + + public DetachCoordinate(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + UnknownField1 = in_reader.Read(); + GTCounter = in_reader.Read(); + } + + public void Write(BinaryObjectWriterEx in_writer) + { + in_writer.Write(UnknownField1); + in_writer.Write(GTCounter); + } + + public uint GetParamCount() + { + return 2; + } + } +} diff --git a/Marathon/Formats/Acroarts/Types/Momentums/DirectionalLight.cs b/Marathon/Formats/Acroarts/Types/Momentums/DirectionalLight.cs new file mode 100644 index 00000000..aac73c54 --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Momentums/DirectionalLight.cs @@ -0,0 +1,31 @@ +using Marathon.IO; + +namespace Marathon.Formats.Acroarts.Types.Momentums +{ + public class DirectionalLight : IMomentumParamSet + { + public uint UnknownField { get; set; } + + public DirectionalLight() { } + + public DirectionalLight(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + UnknownField = in_reader.Read(); + } + + public void Write(BinaryObjectWriterEx in_writer) + { + in_writer.Write(UnknownField); + } + + public uint GetParamCount() + { + return 1; + } + } +} diff --git a/Marathon/Formats/Acroarts/Types/Momentums/FaceType.cs b/Marathon/Formats/Acroarts/Types/Momentums/FaceType.cs new file mode 100644 index 00000000..d9882b62 --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Momentums/FaceType.cs @@ -0,0 +1,13 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + +namespace Marathon.Formats.Acroarts.Types.Momentums +{ + [JsonConverter(typeof(StringEnumConverter))] + public enum FaceType : int + { + RotateOnly, + FixAxis, + SameUpVector + } +} diff --git a/Marathon/Formats/Acroarts/Types/Momentums/FilterColorCorrection.cs b/Marathon/Formats/Acroarts/Types/Momentums/FilterColorCorrection.cs new file mode 100644 index 00000000..0d9dc413 --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Momentums/FilterColorCorrection.cs @@ -0,0 +1,44 @@ +using Marathon.Formats.Acroarts.Chunks; +using Marathon.IO; + +namespace Marathon.Formats.Acroarts.Types.Momentums +{ + public class FilterColorCorrection : IMomentumParamSet + { + public float UnknownField1 { get; set; } + + public float UnknownField2 { get; set; } + + public float UnknownField3 { get; set; } + + public float UnknownField4 { get; set; } + + public FilterColorCorrection() { } + + public FilterColorCorrection(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + UnknownField1 = in_reader.Read(); + UnknownField2 = in_reader.Read(); + UnknownField3 = in_reader.Read(); + UnknownField4 = in_reader.Read(); + } + + public void Write(BinaryObjectWriterEx in_writer) + { + in_writer.Write(UnknownField1); + in_writer.Write(UnknownField2); + in_writer.Write(UnknownField3); + in_writer.Write(UnknownField4); + } + + public uint GetParamCount() + { + return 4; + } + } +} diff --git a/Marathon/Formats/Acroarts/Types/Momentums/GTCounter.cs b/Marathon/Formats/Acroarts/Types/Momentums/GTCounter.cs new file mode 100644 index 00000000..7a682543 --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Momentums/GTCounter.cs @@ -0,0 +1,14 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + +namespace Marathon.Formats.Acroarts.Types.Momentums +{ + [JsonConverter(typeof(StringEnumConverter))] + public enum GTCounter : int + { + None, + Branch, + Leaf, + Momentum + } +} diff --git a/Marathon/Formats/Acroarts/Types/Momentums/GoalInterpolation.cs b/Marathon/Formats/Acroarts/Types/Momentums/GoalInterpolation.cs new file mode 100644 index 00000000..5ccdfe36 --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Momentums/GoalInterpolation.cs @@ -0,0 +1,13 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + +namespace Marathon.Formats.Acroarts.Types.Momentums +{ + [JsonConverter(typeof(StringEnumConverter))] + public enum GoalInterpolation : int + { + Linear, + Sin, + Multi + } +} diff --git a/Marathon/Formats/Acroarts/Types/Momentums/IMomentumParamSet.cs b/Marathon/Formats/Acroarts/Types/Momentums/IMomentumParamSet.cs new file mode 100644 index 00000000..ada667a6 --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Momentums/IMomentumParamSet.cs @@ -0,0 +1,9 @@ +using Marathon.IO; + +namespace Marathon.Formats.Acroarts.Types.Momentums +{ + public interface IMomentumParamSet : IBinarySerializableEx + { + uint GetParamCount(); + } +} diff --git a/Marathon/Formats/Acroarts/Types/Momentums/MaterialColorGoal.cs b/Marathon/Formats/Acroarts/Types/Momentums/MaterialColorGoal.cs new file mode 100644 index 00000000..2500d946 --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Momentums/MaterialColorGoal.cs @@ -0,0 +1,156 @@ +using Marathon.IO; +using Marathon.IO.Types; +using System.Collections.Generic; + +namespace Marathon.Formats.Acroarts.Types.Momentums +{ + public class MaterialColorGoal : IMomentumParamSet + { + public ColorInfoSet[] Steps { get; set; } = new ColorInfoSet[4]; + + public uint UnknownField1 { get; set; } + + public uint UnknownField2 { get; set; } + + public ColorBlendMode ColorBlendMode { get; set; } + + public MaterialColorGoal() { } + + public MaterialColorGoal(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + for (int i = 0; i < Steps.Length; i++) + { + var offset = in_reader.Read(); + + in_reader.ReadAtOffset(in_reader.CalculateOffset(offset), () => + { + Steps[i] = new ColorInfoSet(in_reader); + }); + } + + UnknownField1 = in_reader.Read(); + UnknownField2 = in_reader.Read(); + ColorBlendMode = in_reader.Read(); + } + + public void Write(BinaryObjectWriterEx in_writer) + { + var offsets = new long[Steps.Length]; + + for (int i = 0; i < offsets.Length; i++) + offsets[i] = in_writer.Reserve(); + + in_writer.Write(UnknownField1); + in_writer.Write(UnknownField2); + in_writer.Write(ColorBlendMode); + + for (int i = 0; i < Steps.Length; i++) + { + in_writer.WriteReserved(offsets[i], (uint)in_writer.CalculateOffset(in_writer.Position, OffsetType.Relative), false); + Steps[i].Write(in_writer); + } + } + + public uint GetParamCount() + { + return 7; + } + + public class ColorInfoSet : List, IMomentumParamSet + { + private List _arrayPtrOffsets = []; + + public ColorInfoSet() { } + + public ColorInfoSet(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + var offsets = new AnonymousMomentumParamSet(in_reader); + + foreach (var offset in offsets) + { + in_reader.ReadAtOffset(in_reader.CalculateOffset(offset.UInt32), () => + { + var paramCount = in_reader.Read(); + var paramOffset = in_reader.Read(); + + in_reader.ReadAtOffset(in_reader.CalculateOffset(paramOffset), () => + { + Add(new ColorInfo(in_reader)); + }); + }); + } + } + + public void Write(BinaryObjectWriterEx in_writer) + { + in_writer.Write(Count); + in_writer.WriteOffset((uint)in_writer.CalculateOffset(in_writer.Position + sizeof(uint), OffsetType.Relative)); + + for (int i = 0; i < Count; i++) + _arrayPtrOffsets.Add(in_writer.Reserve()); + + for (int i = 0; i < Count; i++) + { + in_writer.WriteReserved(_arrayPtrOffsets[i], (uint)in_writer.CalculateOffset(in_writer.Position, OffsetType.Relative), false); + in_writer.Write(this[i].GetParamCount()); + in_writer.WriteOffset((uint)in_writer.CalculateOffset(in_writer.Position + sizeof(uint), OffsetType.Relative)); + this[i].Write(in_writer); + } + } + + public uint GetParamCount() + { + return (uint)Count; + } + } + + public class ColorInfo : IMomentumParamSet + { + public Color Color { get; set; } + + public uint UnknownField1 { get; set; } + + public uint UnknownField2 { get; set; } + + public int UnknownField3 { get; set; } + + public ColorInfo() { } + + public ColorInfo(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + Color = in_reader.ReadObject>(); + UnknownField1 = in_reader.Read(); + UnknownField2 = in_reader.Read(); + UnknownField3 = in_reader.Read(); + } + + public void Write(BinaryObjectWriterEx in_writer) + { + in_writer.WriteObject(Color); + in_writer.Write(UnknownField1); + in_writer.Write(UnknownField2); + in_writer.Write(UnknownField3); + } + + public uint GetParamCount() + { + return 7; + } + } + } +} diff --git a/Marathon/Formats/Acroarts/Types/Momentums/MaterialColorNormal.cs b/Marathon/Formats/Acroarts/Types/Momentums/MaterialColorNormal.cs new file mode 100644 index 00000000..95be28c0 --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Momentums/MaterialColorNormal.cs @@ -0,0 +1,40 @@ +using Marathon.IO; +using Marathon.IO.Types; + +namespace Marathon.Formats.Acroarts.Types.Momentums +{ + public class MaterialColorNormal : IMomentumParamSet + { + public Color Color { get; set; } + + public bool SetGeneralColor { get; set; } + + public ColorBlendMode ColorBlendMode { get; set; } + + public MaterialColorNormal() { } + + public MaterialColorNormal(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + Color = in_reader.ReadObject>(); + SetGeneralColor = in_reader.Read() != 0; + ColorBlendMode = in_reader.Read(); + } + + public void Write(BinaryObjectWriterEx in_writer) + { + in_writer.WriteObject(Color); + in_writer.Write(SetGeneralColor ? 1 : 0); + in_writer.Write(ColorBlendMode); + } + + public uint GetParamCount() + { + return 6; + } + } +} diff --git a/Marathon/Formats/Acroarts/Types/Momentums/MaterialColorRandomGoal.cs b/Marathon/Formats/Acroarts/Types/Momentums/MaterialColorRandomGoal.cs new file mode 100644 index 00000000..778303f5 --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Momentums/MaterialColorRandomGoal.cs @@ -0,0 +1,183 @@ +using Marathon.IO; +using System.Collections.Generic; + +namespace Marathon.Formats.Acroarts.Types.Momentums +{ + public class MaterialColorRandomGoal : IMomentumParamSet + { + public ColorInfoSet[] Steps { get; set; } = new ColorInfoSet[4]; + + public uint UnknownField1 { get; set; } + + public uint UnknownField2 { get; set; } + + public uint UnknownField3 { get; set; } + + public uint UnknownField4 { get; set; } + + public MaterialColorRandomGoal() { } + + public MaterialColorRandomGoal(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + for (int i = 0; i < Steps.Length; i++) + { + var offset = in_reader.Read(); + + in_reader.ReadAtOffset(in_reader.CalculateOffset(offset), () => + { + Steps[i] = new ColorInfoSet(in_reader); + }); + } + + UnknownField1 = in_reader.Read(); + UnknownField2 = in_reader.Read(); + UnknownField3 = in_reader.Read(); + UnknownField4 = in_reader.Read(); + } + + public void Write(BinaryObjectWriterEx in_writer) + { + var offsets = new long[Steps.Length]; + + for (int i = 0; i < offsets.Length; i++) + offsets[i] = in_writer.Reserve(); + + in_writer.Write(UnknownField1); + in_writer.Write(UnknownField2); + in_writer.Write(UnknownField3); + in_writer.Write(UnknownField4); + + for (int i = 0; i < Steps.Length; i++) + { + in_writer.WriteReserved(offsets[i], (uint)in_writer.CalculateOffset(in_writer.Position, OffsetType.Relative), false); + Steps[i].Write(in_writer); + } + } + + public uint GetParamCount() + { + return 8; + } + + public class ColorInfoSet : List, IMomentumParamSet + { + private List _arrayPtrOffsets = []; + + public ColorInfoSet() { } + + public ColorInfoSet(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + var offsets = new AnonymousMomentumParamSet(in_reader); + + foreach (var offset in offsets) + { + in_reader.ReadAtOffset(in_reader.CalculateOffset(offset.UInt32), () => + { + var paramCount = in_reader.Read(); + var paramOffset = in_reader.Read(); + + in_reader.ReadAtOffset(in_reader.CalculateOffset(paramOffset), () => + { + Add(new ColorInfo(in_reader)); + }); + }); + } + } + + public void Write(BinaryObjectWriterEx in_writer) + { + in_writer.Write(Count); + in_writer.WriteOffset((uint)in_writer.CalculateOffset(in_writer.Position + sizeof(uint), OffsetType.Relative)); + + for (int i = 0; i < Count; i++) + _arrayPtrOffsets.Add(in_writer.Reserve()); + + for (int i = 0; i < Count; i++) + { + in_writer.WriteReserved(_arrayPtrOffsets[i], (uint)in_writer.CalculateOffset(in_writer.Position, OffsetType.Relative), false); + in_writer.Write(this[i].GetParamCount()); + in_writer.WriteOffset((uint)in_writer.CalculateOffset(in_writer.Position + sizeof(uint), OffsetType.Relative)); + this[i].Write(in_writer); + } + } + + public uint GetParamCount() + { + return (uint)Count; + } + } + + public class ColorInfo : IMomentumParamSet + { + public float UnknownField1 { get; set; } + + public float UnknownField2 { get; set; } + + public float UnknownField3 { get; set; } + + public float UnknownField4 { get; set; } + + public float UnknownField5 { get; set; } + + public float UnknownField6 { get; set; } + + public float UnknownField7 { get; set; } + + public float UnknownField8 { get; set; } + + public uint UnknownField9 { get; set; } + + public int UnknownField10 { get; set; } + + public ColorInfo() { } + + public ColorInfo(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + UnknownField1 = in_reader.Read(); + UnknownField2 = in_reader.Read(); + UnknownField3 = in_reader.Read(); + UnknownField4 = in_reader.Read(); + UnknownField5 = in_reader.Read(); + UnknownField6 = in_reader.Read(); + UnknownField7 = in_reader.Read(); + UnknownField8 = in_reader.Read(); + UnknownField9 = in_reader.Read(); + UnknownField10 = in_reader.Read(); + } + + public void Write(BinaryObjectWriterEx in_writer) + { + in_writer.Write(UnknownField1); + in_writer.Write(UnknownField2); + in_writer.Write(UnknownField3); + in_writer.Write(UnknownField4); + in_writer.Write(UnknownField5); + in_writer.Write(UnknownField6); + in_writer.Write(UnknownField7); + in_writer.Write(UnknownField8); + in_writer.Write(UnknownField9); + in_writer.Write(UnknownField10); + } + + public uint GetParamCount() + { + return 10; + } + } + } +} diff --git a/Marathon/Formats/Acroarts/Types/Momentums/MaterialColorRandomNormal.cs b/Marathon/Formats/Acroarts/Types/Momentums/MaterialColorRandomNormal.cs new file mode 100644 index 00000000..8214f2c5 --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Momentums/MaterialColorRandomNormal.cs @@ -0,0 +1,48 @@ +using Marathon.IO; +using Marathon.IO.Types; + +namespace Marathon.Formats.Acroarts.Types.Momentums +{ + public class MaterialColorRandomNormal : IMomentumParamSet + { + public Color Color { get; set; } + + public Color Random { get; set; } + + public uint UnknownField { get; set; } + + public bool SetGeneralColor { get; set; } + + public ColorBlendMode ColorBlendMode { get; set; } + + public MaterialColorRandomNormal() { } + + public MaterialColorRandomNormal(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + Color = in_reader.ReadObject>(); + Random = in_reader.ReadObject>(); + UnknownField = in_reader.Read(); + SetGeneralColor = in_reader.Read() != 0; + ColorBlendMode = in_reader.Read(); + } + + public void Write(BinaryObjectWriterEx in_writer) + { + in_writer.WriteObject(Color); + in_writer.WriteObject(Random); + in_writer.Write(UnknownField); + in_writer.Write(SetGeneralColor ? 1 : 0); + in_writer.Write(ColorBlendMode); + } + + public uint GetParamCount() + { + return 11; + } + } +} diff --git a/Marathon/Formats/Acroarts/Types/Momentums/MaterialColorSin.cs b/Marathon/Formats/Acroarts/Types/Momentums/MaterialColorSin.cs new file mode 100644 index 00000000..9b2fb0af --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Momentums/MaterialColorSin.cs @@ -0,0 +1,68 @@ +using Marathon.IO; +using Marathon.IO.Types; + +namespace Marathon.Formats.Acroarts.Types.Momentums +{ + public class MaterialColorSin : IMomentumParamSet + { + public Color Color { get; set; } + + public uint UnknownField1 { get; set; } + + public uint UnknownField2 { get; set; } + + public uint UnknownField3 { get; set; } + + public uint UnknownField4 { get; set; } + + public uint UnknownField5 { get; set; } + + public uint UnknownField6 { get; set; } + + public GTCounter GTCounter { get; set; } + + public bool SetGeneralColor { get; set; } + + public ColorBlendMode ColorBlendMode { get; set; } + + public MaterialColorSin() { } + + public MaterialColorSin(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + Color = in_reader.ReadObject>(); + UnknownField1 = in_reader.Read(); + UnknownField2 = in_reader.Read(); + UnknownField3 = in_reader.Read(); + UnknownField4 = in_reader.Read(); + UnknownField5 = in_reader.Read(); + UnknownField6 = in_reader.Read(); + GTCounter = in_reader.Read(); + SetGeneralColor = in_reader.Read() != 0; + ColorBlendMode = in_reader.Read(); + } + + public void Write(BinaryObjectWriterEx in_writer) + { + in_writer.WriteObject(Color); + in_writer.Write(UnknownField1); + in_writer.Write(UnknownField2); + in_writer.Write(UnknownField3); + in_writer.Write(UnknownField4); + in_writer.Write(UnknownField5); + in_writer.Write(UnknownField6); + in_writer.Write(GTCounter); + in_writer.Write(SetGeneralColor ? 1 : 0); + in_writer.Write(ColorBlendMode); + } + + public uint GetParamCount() + { + return 13; + } + } +} diff --git a/Marathon/Formats/Acroarts/Types/Momentums/ModelJoin.cs b/Marathon/Formats/Acroarts/Types/Momentums/ModelJoin.cs new file mode 100644 index 00000000..13386a7d --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Momentums/ModelJoin.cs @@ -0,0 +1,47 @@ +using Marathon.IO; + +namespace Marathon.Formats.Acroarts.Types.Momentums +{ + public class ModelJoin : IMomentumParamSet + { + public uint UnknownField1 { get; set; } + + public uint UnknownField2 { get; set; } + + public string NodeName { get; set; } + + public ModelJoin() { } + + public ModelJoin(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + UnknownField1 = in_reader.Read(); + UnknownField2 = in_reader.Read(); + var nodeNameOffset = in_reader.Read(); + + if (nodeNameOffset != 0) + { + in_reader.ReadAtOffset(in_reader.CalculateOffset(nodeNameOffset), + () => NodeName = MomentumString.Read(in_reader)); + } + } + + public void Write(BinaryObjectWriterEx in_writer) + { + in_writer.Write(UnknownField1); + in_writer.Write(UnknownField2); + var nodeNameOffset = in_writer.Reserve(); + + MomentumString.Write(in_writer, NodeName, nodeNameOffset); + } + + public uint GetParamCount() + { + return 3; + } + } +} diff --git a/Marathon/Formats/Acroarts/Types/Momentums/MomentumFactory.cs b/Marathon/Formats/Acroarts/Types/Momentums/MomentumFactory.cs new file mode 100644 index 00000000..211b234f --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Momentums/MomentumFactory.cs @@ -0,0 +1,62 @@ +using Marathon.IO; + +namespace Marathon.Formats.Acroarts.Types.Momentums +{ + public class MomentumFactory + { + public static IMomentumParamSet ReadMomentumByType(BinaryObjectReaderEx in_reader, MomentumType in_type) + { + return in_type switch + { + MomentumType.TranslateNormal => new TranslateNormal(in_reader), + MomentumType.TranslateAdd => new TranslateAdd(in_reader), + MomentumType.TranslateAccel => new TranslateAccel(in_reader), + MomentumType.TranslateRandomNormal => new TranslateRandomNormal(in_reader), + MomentumType.TranslateRandomAdd => new TranslateRandomAdd(in_reader), + MomentumType.TranslateRandomSin => new TranslateRandomSin(in_reader), + MomentumType.TranslateGoal => new TranslateGoal(in_reader), + MomentumType.RotateNormal => new RotateNormal(in_reader), + MomentumType.RotateAdd => new RotateAdd(in_reader), + MomentumType.RotateRandomNormal => new RotateRandomNormal(in_reader), + MomentumType.RotateRandomAdd => new RotateRandomAdd(in_reader), + MomentumType.RotateGoal => new RotateGoal(in_reader), + MomentumType.ScaleNormal => new ScaleNormal(in_reader), + MomentumType.ScaleAdd => new ScaleAdd(in_reader), + MomentumType.ScaleAccel => new ScaleAccel(in_reader), + MomentumType.ScaleRandomNormal => new ScaleRandomNormal(in_reader), + MomentumType.ScaleRandomAdd => new ScaleRandomAdd(in_reader), + MomentumType.ScaleGoal => new ScaleGoal(in_reader), + MomentumType.ScaleRandomGoal => new ScaleRandomGoal(in_reader), + MomentumType.ScaleAddGoal => new ScaleAddGoal(in_reader), + MomentumType.PlaceFanShaped => new PlaceFanShaped(in_reader), + MomentumType.PlaceLineShaped => new PlaceLineShaped(in_reader), + MomentumType.ParticleBillboardPV => new ParticleBillboardPV(in_reader), + MomentumType.SparklingTail => new SparklingTail(in_reader), + MomentumType.BlurBelt => new BlurBelt(in_reader), + MomentumType.BillboardTail => new BillboardTail(in_reader), + MomentumType.TurnCamera => new TurnCamera(in_reader), + MomentumType.MaterialColorNormal => new MaterialColorNormal(in_reader), + MomentumType.MaterialColorSin => new MaterialColorSin(in_reader), + MomentumType.MaterialColorRandomNormal => new MaterialColorRandomNormal(in_reader), + MomentumType.MaterialColorGoal => new MaterialColorGoal(in_reader), + MomentumType.MaterialColorRandomGoal => new MaterialColorRandomGoal(in_reader), + MomentumType.ModelJoin => new ModelJoin(in_reader), + MomentumType.ShadowOn => new ShadowOn(in_reader), + MomentumType.PointLight => new PointLight(in_reader), + MomentumType.DirectionalLight => new DirectionalLight(in_reader), + MomentumType.AmbientLight => new AmbientLight(in_reader), + MomentumType.MotionSet => new MotionSet(in_reader), + MomentumType.DetachCoordinate => new DetachCoordinate(in_reader), + MomentumType.SendParamGoal => new SendParamGoal(in_reader), + MomentumType.SoundPlay => new SoundPlay(in_reader), + MomentumType.Sound3DPlay => new Sound3DPlay(in_reader), + MomentumType.ParticlePlay => new ParticlePlay(in_reader), + MomentumType.CellSpriteSceneSet => new CellSpriteSceneSet(in_reader), + MomentumType.Subtitle => new Subtitle(in_reader), + MomentumType.ClipPlane => new ClipPlane(in_reader), + MomentumType.FilterColorCorrection => new FilterColorCorrection(in_reader), + _ => null + }; + } + } +} diff --git a/Marathon/Formats/Acroarts/Types/Momentums/MomentumString.cs b/Marathon/Formats/Acroarts/Types/Momentums/MomentumString.cs new file mode 100644 index 00000000..8981274a --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Momentums/MomentumString.cs @@ -0,0 +1,55 @@ +using Marathon.IO; +using Marathon.IO.Extensions; +using System; +using System.IO; + +namespace Marathon.Formats.Acroarts.Types.Momentums +{ + public class MomentumString + { + public static string Read(BinaryObjectReaderEx in_reader) + { + var pos = in_reader.Position; + var result = in_reader.ReadStringFixedLength(0x80); + + if (result.Length > 0x0F) + { + in_reader.Seek(pos, SeekOrigin.Begin); + result = in_reader.ReadStringFixedLength(0x100); + } + + return result; + } + + public static void Write(BinaryObjectWriterEx in_writer, string in_value, Action in_preWriteStringAction = null) + { + if (string.IsNullOrEmpty(in_value)) + { + in_preWriteStringAction?.Invoke(); + return; + } + + in_writer.WriteZero(); + in_preWriteStringAction?.Invoke(); + in_writer.WriteStringFixedLength(in_value, GetFixedLength(in_value)); + } + + public static void Write(BinaryObjectWriterEx in_writer, string in_value, long in_reservedOffset) + { + Write(in_writer, in_value, () => + { + var offset = 0U; + + if (!string.IsNullOrEmpty(in_value)) + offset = (uint)in_writer.CalculateOffset(in_writer.Position, OffsetType.Relative); + + in_writer.WriteReserved(in_reservedOffset, offset, offset == 0); + }); + } + + public static int GetFixedLength(string in_value) + { + return in_value.Length > 0x0F ? 0x100 : 0x80; + } + } +} diff --git a/Marathon/Formats/Acroarts/Types/Momentums/MomentumType.cs b/Marathon/Formats/Acroarts/Types/Momentums/MomentumType.cs new file mode 100644 index 00000000..c5b51151 --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Momentums/MomentumType.cs @@ -0,0 +1,119 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + +namespace Marathon.Formats.Acroarts.Types.Momentums +{ + [JsonConverter(typeof(StringEnumConverter))] + public enum MomentumType : int + { + TranslateNormal = 0x00, + TranslateAdd = 0x01, + TranslateAccel = 0x02, + TranslateRandomNormal = 0x03, + TranslateRandomAdd = 0x04, + TranslateRandomAccel = 0x05, + TranslateSin = 0x06, + TranslateRandomSin = 0x07, + TranslateGoal = 0x08, + TranslateSpline = 0x09, + TranslateAddGoal = 0x0A, + TranslateRandomGoal = 0x0B, + TranslateWrap = 0x5C11, + RotateNormal = 0x14, + RotateAdd = 0x15, + RotateAccel = 0x16, + RotateRandomNormal = 0x17, + RotateRandomAdd = 0x18, + RotateRandomAccel = 0x19, + RotateSin = 0x1A, + RotateRandomSin = 0x1B, + RotateGoal = 0x1C, + RotateRandomGoal = 0x1D, + RotateAddGoal = 0x1E, + RotateErase = 0x1F, + ScaleNormal = 0x28, + ScaleAdd = 0x29, + ScaleAccel = 0x2A, + ScaleRandomNormal = 0x2B, + ScaleRandomAdd = 0x2C, + ScaleRandomAccel = 0x2D, + ScaleSin = 0x2E, + ScaleRandomSin = 0x2F, + ScaleGoal = 0x30, + ScaleRandomGoal = 0x31, + ScaleAddGoal = 0x32, + PlaceFanShaped = 0x3C, + PlaceLineShaped = 0x3D, + PlaceSelectLocation = 0x3E, + PlacePolygonShaped = 0x3F, + ParticleBillboardEx = 0x65, + LineEx = 0x66, + ParticleBillboardPV = 0x67, + SparklingTail = 0x69, + ParticleBillboardND = 0x6A, + BlurBelt = 0x78, + BillboardTail = 0x7A, + TurnCamera = 0x96, + MaterialColorNormal = 0xC8, + MaterialColorSin = 0xC9, + MaterialColorRandomNormal = 0xCA, + MaterialColorRandomSin = 0xCB, + MaterialColorGoal = 0xCC, + MaterialColorRandomGoal = 0xCD, + MaterialColorSetByCamDist = 0xCE, + MaterialColorSetByCamDire = 0xCF, + ModelJoin = 0xE7, + ShadowOn = 0xE8, + TextureSurfaceAnimation = 0xFA, + TexturePatternAnimation = 0xFB, + TextureSurfaceAnimationEasy = 0xFD, + TexturePatternAnimationEasy = 0xFE, + TextureListAnimation = 0xFF, + TextureSet = 0x100, + UvScrollByCameraDirection = 0x12C, + UvScrollNormal = 0x12D, + UvScrollSin = 0x12E, + UvSet = 0x12F, + PointLight = 0x17C, + DirectionalLight = 0x17D, + AmbientLight = 0x17E, + CameraPosition = 0x1C2, + CameraTarget = 0x1C3, + CameraRoll = 0x1C4, + MotionSet = 0x1F4, + ModelMotionSet = 0x1F5, + MotionFrameSet = 0x1F6, + ScreenPerspective = 0x226, + Thunder = 0x258, + DetachCoordinate = 0x25A, + TexScreen = 0x263, + CameraContactLens = 0x264, + LensFlare = 0x265, + ModelDrawMultitude = 0x269, + TimeRate = 0x28A, + SendParamNormal = 0x2BC, + SendParamAdd = 0x2BD, + SendParamAccel = 0x2BE, + SendParamSin = 0x2BF, + SendParamRandomNormal = 0x2C0, + SendParamRandomAdd = 0x2C1, + SendParamRandomAccel = 0x2C2, + SendParamRandomSin = 0x2C3, + SendParamGoal = 0x2C4, + SendParamAddGoal = 0x2C5, + SendParamSpline = 0x2C6, + SendParamRandomGoal = 0x2C7, + SendParamEqualSpace = 0x2C8, + SoundPlay = 0x320, + Sound3DPlay = 0x321, + ParticlePlay = 0x32A, + ParticleSet = 0x32B, + CellSpriteSceneSet = 0x334, + Subtitle = 0x33E, + ClipPlane = 0x348, + FilterClassicBlur = 0x352, + FilterColorCorrection = 0x353, + FilterDepthOfField = 0x354, + SceneBloom = 0x366 + }; +} diff --git a/Marathon/Formats/Acroarts/Types/Momentums/MotionSet.cs b/Marathon/Formats/Acroarts/Types/Momentums/MotionSet.cs new file mode 100644 index 00000000..d564b624 --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Momentums/MotionSet.cs @@ -0,0 +1,98 @@ +using Marathon.Formats.Acroarts.Chunks; +using Marathon.IO; +using System.Collections.Generic; + +namespace Marathon.Formats.Acroarts.Types.Momentums +{ + public class MotionSet : IMomentumParamSet + { + public uint UnknownField1 { get; set; } + + public uint UnknownField2 { get; set; } + + public uint UnknownField3 { get; set; } + + public uint UnknownField4 { get; set; } + + public float UnknownField5 { get; set; } + + public List Params { get; set; } = []; + + public uint UnknownField6 { get; set; } + + public uint UnknownField7 { get; set; } + + public uint UnknownField8 { get; set; } + + public MotionSet() { } + + public MotionSet(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + UnknownField1 = in_reader.Read(); + UnknownField2 = in_reader.Read(); + UnknownField3 = in_reader.Read(); + UnknownField4 = in_reader.Read(); + UnknownField5 = in_reader.Read(); + + var paramsOffset = in_reader.Read(); + + UnknownField6 = in_reader.Read(); + UnknownField7 = in_reader.Read(); + UnknownField8 = in_reader.Read(); + + in_reader.ReadAtOffset(in_reader.CalculateOffset(paramsOffset), () => + { + var offsets = new AnonymousMomentumParamSet(in_reader); + + foreach (var offset in offsets) + { + in_reader.ReadAtOffset(in_reader.CalculateOffset(offset.UInt32), () => + { + Params.Add(new AnonymousMomentumParamSet(in_reader)); + }); + } + }); + } + + public void Write(BinaryObjectWriterEx in_writer) + { + in_writer.Write(UnknownField1); + in_writer.Write(UnknownField2); + in_writer.Write(UnknownField3); + in_writer.Write(UnknownField4); + in_writer.Write(UnknownField5); + + var paramsOffset = in_writer.Reserve(); + + in_writer.Write(UnknownField6); + in_writer.Write(UnknownField7); + in_writer.Write(UnknownField8); + + in_writer.WriteReserved(paramsOffset, (uint)in_writer.CalculateOffset(in_writer.Position, OffsetType.Relative), false); + + in_writer.Write(Params.Count); + in_writer.WriteOffset((uint)in_writer.CalculateOffset(in_writer.Position + sizeof(uint), OffsetType.Relative)); + + var paramsOffsets = new List(); + + for (int i = 0; i < Params.Count; i++) + paramsOffsets.Add(in_writer.Reserve()); + + for (int i = 0; i < Params.Count; i++) + { + in_writer.WriteReserved(paramsOffsets[i], (uint)in_writer.CalculateOffset(in_writer.Position, OffsetType.Relative), false); + Params[i].Write(in_writer); + } + } + + public uint GetParamCount() + { + return 9; + } + } +} diff --git a/Marathon/Formats/Acroarts/Types/Momentums/ParticleBillboardPV.cs b/Marathon/Formats/Acroarts/Types/Momentums/ParticleBillboardPV.cs new file mode 100644 index 00000000..2ca0a1ca --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Momentums/ParticleBillboardPV.cs @@ -0,0 +1,239 @@ +using Marathon.Formats.Acroarts.Collections; +using Marathon.IO; +using Marathon.IO.Types; +using System.Numerics; + +namespace Marathon.Formats.Acroarts.Types.Momentums +{ + public class ParticleBillboardPV : IMomentumParamSet + { + public ParticleEmitterType EmitterType { get; set; } + + public uint UnknownField1 { get; set; } + + public Vector3 Position { get; set; } + + public bool IsCameraLocal { get; set; } + + public float Radius { get; set; } + + public Vector3 Offset { get; set; } + + public Distance DistanceWidth { get; set; } + + public Distance DistanceHeight { get; set; } + + public uint UnknownField2 { get; set; } + + public bool UseSplineMotion { get; set; } + + public IndirectMomentumParamList> SplineKeyFrames { get; set; } = []; + + public bool Loop { get; set; } + + public bool UseMaterialColor { get; set; } + + public int BlendMode { get; set; } + + public uint ParticleCount { get; set; } + + public float Rate { get; set; } + + public uint UnknownField3 { get; set; } + + public uint UnknownField4 { get; set; } + + public float Angle { get; set; } + + public Distance DistanceAngle { get; set; } + + public bool Billboard { get; set; } + + public uint UnknownField5 { get; set; } + + public Distance DistanceVelocityX { get; set; } + + public Distance DistanceVelocityY { get; set; } + + public Distance DistanceVelocityZ { get; set; } + + public float UnknownField12 { get; set; } + + public float UnknownField13 { get; set; } + + public Distance DistanceAccelX { get; set; } + + public Distance DistanceAccelY { get; set; } + + public Distance DistanceAccelZ { get; set; } + + public uint UnknownField14 { get; set; } + + public float Parameter { get; set; } + + public uint UnknownField15 { get; set; } + + public IndirectMomentumParamList ColorKeyFrames { get; set; } = []; + + public bool UseColorMotion { get; set; } + + public bool UsePattern { get; set; } + + public int TextureCount { get; set; } + + public int Surface { get; set; } + + public AnonymousMomentumParam Anime { get; set; } + + public bool UsePatternMotion { get; set; } + + public int PatternColumns { get; set; } + + public int PatternRows { get; set; } + + public uint PatternIndex { get; set; } + + public uint PatternCount { get; set; } + + public bool UnknownField16 { get; set; } + + public bool UseRandomPattern { get; set; } + + public ParticleBillboardPV() { } + + public ParticleBillboardPV(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + EmitterType = in_reader.Read(); + UnknownField1 = in_reader.Read(); + Position = in_reader.Read(); + IsCameraLocal = in_reader.ReadBoolean(); + Radius = in_reader.Read(); + Offset = in_reader.Read(); + DistanceWidth = in_reader.Read>(); + DistanceHeight = in_reader.Read>(); + UnknownField2 = in_reader.Read(); + UseSplineMotion = in_reader.ReadBoolean(); + + var splineKeyFramesOffset = in_reader.Read(); + + in_reader.ReadAtOffset(in_reader.CalculateOffset(splineKeyFramesOffset), () => + { + SplineKeyFrames.Read(in_reader); + }); + + Loop = in_reader.ReadBoolean(); + UseMaterialColor = in_reader.ReadBoolean(); + BlendMode = in_reader.Read(); + ParticleCount = in_reader.Read(); + Rate = in_reader.Read(); + UnknownField3 = in_reader.Read(); + UnknownField4 = in_reader.Read(); + Angle = in_reader.Read(); + DistanceAngle = in_reader.Read>(); + Billboard = in_reader.ReadBoolean(); + UnknownField5 = in_reader.Read(); + DistanceVelocityX = in_reader.Read>(); + DistanceVelocityY = in_reader.Read>(); + DistanceVelocityZ = in_reader.Read>(); + UnknownField12 = in_reader.Read(); + UnknownField13 = in_reader.Read(); + DistanceAccelX = in_reader.Read>(); + DistanceAccelY = in_reader.Read>(); + DistanceAccelZ = in_reader.Read>(); + UnknownField14 = in_reader.Read(); + Parameter = in_reader.Read(); + UnknownField15 = in_reader.Read(); + + var colorKeyFramesOffset = in_reader.Read(); + + in_reader.ReadAtOffset(in_reader.CalculateOffset(colorKeyFramesOffset), () => + { + ColorKeyFrames.Read(in_reader); + }); + + UseColorMotion = in_reader.ReadBoolean(); + UsePattern = in_reader.ReadBoolean(); + TextureCount = in_reader.Read(); + Surface = in_reader.Read(); + Anime = in_reader.ReadObjectEx(); + UsePatternMotion = in_reader.ReadBoolean(); + PatternColumns = in_reader.Read(); + PatternRows = in_reader.Read(); + PatternIndex = in_reader.Read(); + PatternCount = in_reader.Read(); + UnknownField16 = in_reader.ReadBoolean(); + UseRandomPattern = in_reader.ReadBoolean(); + } + + public void Write(BinaryObjectWriterEx in_writer) + { + in_writer.Write(EmitterType); + in_writer.Write(UnknownField1); + in_writer.Write(Position); + in_writer.WriteBoolean(IsCameraLocal); + in_writer.Write(Radius); + in_writer.Write(Offset); + in_writer.Write(DistanceWidth); + in_writer.Write(DistanceHeight); + in_writer.Write(UnknownField2); + in_writer.WriteBoolean(UseSplineMotion); + var splineKeyFramesOffset = in_writer.Reserve(); + in_writer.WriteBoolean(Loop); + in_writer.WriteBoolean(UseMaterialColor); + in_writer.Write(BlendMode); + in_writer.Write(ParticleCount); + in_writer.Write(Rate); + in_writer.Write(UnknownField3); + in_writer.Write(UnknownField4); + in_writer.Write(Angle); + in_writer.Write(DistanceAngle); + in_writer.WriteBoolean(Billboard); + in_writer.Write(UnknownField5); + in_writer.Write(DistanceVelocityX); + in_writer.Write(DistanceVelocityY); + in_writer.Write(DistanceVelocityZ); + in_writer.Write(UnknownField12); + in_writer.Write(UnknownField13); + in_writer.Write(DistanceAccelX); + in_writer.Write(DistanceAccelY); + in_writer.Write(DistanceAccelZ); + in_writer.Write(UnknownField14); + in_writer.Write(Parameter); + in_writer.Write(UnknownField15); + var colorKeyFramesOffset = in_writer.Reserve(); + in_writer.WriteBoolean(UseColorMotion); + in_writer.WriteBoolean(UsePattern); + in_writer.Write(TextureCount); + in_writer.Write(Surface); + in_writer.WriteObjectEx(Anime); + in_writer.WriteBoolean(UsePatternMotion); + in_writer.Write(PatternColumns); + in_writer.Write(PatternRows); + in_writer.Write(PatternIndex); + in_writer.Write(PatternCount); + in_writer.WriteBoolean(UnknownField16); + in_writer.WriteBoolean(UseRandomPattern); + + in_writer.WriteReserved(splineKeyFramesOffset, (uint)in_writer.CalculateOffset(in_writer.Position, OffsetType.Relative), false); + SplineKeyFrames.Write(in_writer); + + in_writer.WriteReserved(colorKeyFramesOffset, (uint)in_writer.CalculateOffset(in_writer.Position, OffsetType.Relative), false); + ColorKeyFrames.Write(in_writer); + } + + public float GetBetweenValue(Distance in_distance) + { + return Random.GetRandomF(in_distance.Max - in_distance.Min) + in_distance.Min; + } + + public uint GetParamCount() + { + return 59; + } + } +} diff --git a/Marathon/Formats/Acroarts/Types/Momentums/ParticleEmitterType.cs b/Marathon/Formats/Acroarts/Types/Momentums/ParticleEmitterType.cs new file mode 100644 index 00000000..5ca6fb37 --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Momentums/ParticleEmitterType.cs @@ -0,0 +1,13 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + +namespace Marathon.Formats.Acroarts.Types.Momentums +{ + [JsonConverter(typeof(StringEnumConverter))] + public enum ParticleEmitterType : int + { + Sphere, + Volume, + Box + } +} diff --git a/Marathon/Formats/Acroarts/Types/Momentums/ParticlePlay.cs b/Marathon/Formats/Acroarts/Types/Momentums/ParticlePlay.cs new file mode 100644 index 00000000..de278f4f --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Momentums/ParticlePlay.cs @@ -0,0 +1,60 @@ +using Marathon.IO; + +namespace Marathon.Formats.Acroarts.Types.Momentums +{ + public class ParticlePlay : IMomentumParamSet + { + public string ParticleContainer { get; set; } + + public string ParticleName { get; set; } + + public float Speed { get; set; } + + public uint Mode { get; set; } + + public ParticlePlay() { } + + public ParticlePlay(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + var particleContainerOffset = in_reader.Read(); + var particleNameOffset = in_reader.Read(); + + Speed = in_reader.Read(); + Mode = in_reader.Read(); + + if (particleContainerOffset != 0) + { + in_reader.ReadAtOffset(in_reader.CalculateOffset(particleContainerOffset), + () => ParticleContainer = MomentumString.Read(in_reader)); + } + + if (particleNameOffset != 0) + { + in_reader.ReadAtOffset(in_reader.CalculateOffset(particleNameOffset), + () => ParticleName = MomentumString.Read(in_reader)); + } + } + + public void Write(BinaryObjectWriterEx in_writer) + { + var particleContainerOffset = in_writer.Reserve(); + var particleNameOffset = in_writer.Reserve(); + + in_writer.Write(Speed); + in_writer.Write(Mode); + + MomentumString.Write(in_writer, ParticleContainer, particleContainerOffset); + MomentumString.Write(in_writer, ParticleName, particleNameOffset); + } + + public uint GetParamCount() + { + return 4; + } + } +} diff --git a/Marathon/Formats/Acroarts/Types/Momentums/PlaceFanShaped.cs b/Marathon/Formats/Acroarts/Types/Momentums/PlaceFanShaped.cs new file mode 100644 index 00000000..68a05103 --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Momentums/PlaceFanShaped.cs @@ -0,0 +1,64 @@ +using Marathon.IO; + +namespace Marathon.Formats.Acroarts.Types.Momentums +{ + public class PlaceFanShaped : IMomentumParamSet + { + public AxisType Axis { get; set; } + + public string UnknownField1 { get; set; } + + public string UnknownField2 { get; set; } + + public float Radius { get; set; } + + public uint UnknownField3 { get; set; } + + public PlaceFanShaped() { } + + public PlaceFanShaped(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + Axis = in_reader.Read(); + var unkField1Offset = in_reader.Read(); + var unkField2Offset = in_reader.Read(); + Radius = in_reader.Read(); + UnknownField3 = in_reader.Read(); + + in_reader.JumpAhead(8); + + if (unkField1Offset != 0) + { + in_reader.ReadAtOffset(in_reader.CalculateOffset(unkField1Offset), + () => UnknownField1 = MomentumString.Read(in_reader)); + } + + if (unkField2Offset != 0) + { + in_reader.ReadAtOffset(in_reader.CalculateOffset(unkField2Offset), + () => UnknownField2 = MomentumString.Read(in_reader)); + } + } + + public void Write(BinaryObjectWriterEx in_writer) + { + in_writer.Write(Axis); + var unkField1Offset = in_writer.Reserve(); + var unkField2Offset = in_writer.Reserve(); + in_writer.Write(Radius); + in_writer.Write(UnknownField3); + + MomentumString.Write(in_writer, UnknownField1, unkField1Offset); + MomentumString.Write(in_writer, UnknownField2, unkField2Offset); + } + + public uint GetParamCount() + { + return 5; + } + } +} diff --git a/Marathon/Formats/Acroarts/Types/Momentums/PlaceLineShaped.cs b/Marathon/Formats/Acroarts/Types/Momentums/PlaceLineShaped.cs new file mode 100644 index 00000000..43a48196 --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Momentums/PlaceLineShaped.cs @@ -0,0 +1,36 @@ +using Marathon.IO; +using System.Numerics; + +namespace Marathon.Formats.Acroarts.Types.Momentums +{ + public class PlaceLineShaped : IMomentumParamSet + { + public Vector3 Start { get; set; } + + public Vector3 End { get; set; } + + public PlaceLineShaped() { } + + public PlaceLineShaped(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + Start = in_reader.Read(); + End = in_reader.Read(); + } + + public void Write(BinaryObjectWriterEx in_writer) + { + in_writer.Write(Start); + in_writer.Write(End); + } + + public uint GetParamCount() + { + return 6; + } + } +} diff --git a/Marathon/Formats/Acroarts/Types/Momentums/PointLight.cs b/Marathon/Formats/Acroarts/Types/Momentums/PointLight.cs new file mode 100644 index 00000000..bf875ed4 --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Momentums/PointLight.cs @@ -0,0 +1,47 @@ +using Marathon.IO; + +namespace Marathon.Formats.Acroarts.Types.Momentums +{ + public class PointLight : IMomentumParamSet + { + public uint UnknownField1 { get; set; } + + public float UnknownField2 { get; set; } + + public float UnknownField3 { get; set; } + + public uint UnknownField4 { get; set; } + + public uint UnknownField5 { get; set; } + + public PointLight() { } + + public PointLight(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + UnknownField1 = in_reader.Read(); + UnknownField2 = in_reader.Read(); + UnknownField3 = in_reader.Read(); + UnknownField4 = in_reader.Read(); + UnknownField5 = in_reader.Read(); + } + + public void Write(BinaryObjectWriterEx in_writer) + { + in_writer.Write(UnknownField1); + in_writer.Write(UnknownField2); + in_writer.Write(UnknownField3); + in_writer.Write(UnknownField4); + in_writer.Write(UnknownField5); + } + + public uint GetParamCount() + { + return 5; + } + } +} diff --git a/Marathon/Formats/Acroarts/Types/Momentums/RotateAdd.cs b/Marathon/Formats/Acroarts/Types/Momentums/RotateAdd.cs new file mode 100644 index 00000000..8e7c9442 --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Momentums/RotateAdd.cs @@ -0,0 +1,32 @@ +using Marathon.IO; +using System.Numerics; + +namespace Marathon.Formats.Acroarts.Types.Momentums +{ + public class RotateAdd : IMomentumParamSet + { + public Vector4 Rotation { get; set; } + + public RotateAdd() { } + + public RotateAdd(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + Rotation = in_reader.Read(); + } + + public void Write(BinaryObjectWriterEx in_writer) + { + in_writer.Write(Rotation); + } + + public uint GetParamCount() + { + return 4; + } + } +} diff --git a/Marathon/Formats/Acroarts/Types/Momentums/RotateGoal.cs b/Marathon/Formats/Acroarts/Types/Momentums/RotateGoal.cs new file mode 100644 index 00000000..d9b9eba3 --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Momentums/RotateGoal.cs @@ -0,0 +1,149 @@ +using Marathon.IO; +using System.Collections.Generic; +using System.Numerics; + +namespace Marathon.Formats.Acroarts.Types.Momentums +{ + public class RotateGoal : IMomentumParamSet + { + public RotateInfoSet Steps { get; set; } + + public GTCounter GTCounter { get; set; } + + public RotateGoal() { } + + public RotateGoal(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + var infoSetOffset = in_reader.Read(); + + in_reader.ReadAtOffset(in_reader.CalculateOffset(infoSetOffset), () => + { + Steps = new RotateInfoSet(in_reader); + }); + + GTCounter = in_reader.Read(); + } + + public void Write(BinaryObjectWriterEx in_writer) + { + var infoSetOffset = in_writer.Reserve(); + in_writer.Write(GTCounter); + in_writer.WriteReserved(infoSetOffset, (uint)in_writer.CalculateOffset(in_writer.Position, OffsetType.Relative), false); + Steps.Write(in_writer); + } + + public uint GetParamCount() + { + return 2; + } + + public class RotateInfoSet : List, IMomentumParamSet + { + private List _arrayPtrOffsets = []; + + public RotateInfoSet() { } + + public RotateInfoSet(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + var offsets = new AnonymousMomentumParamSet(in_reader); + + foreach (var offset in offsets) + { + in_reader.ReadAtOffset(in_reader.CalculateOffset(offset.UInt32), () => + { + var paramCount = in_reader.Read(); + var paramOffset = in_reader.Read(); + + in_reader.ReadAtOffset(in_reader.CalculateOffset(paramOffset), () => + { + Add(new RotateInfo(in_reader)); + }); + }); + } + } + + public void Write(BinaryObjectWriterEx in_writer) + { + in_writer.Write(Count); + in_writer.WriteOffset((uint)in_writer.CalculateOffset(in_writer.Position + sizeof(uint), OffsetType.Relative)); + + for (int i = 0; i < Count; i++) + _arrayPtrOffsets.Add(in_writer.Reserve()); + + for (int i = 0; i < Count; i++) + { + in_writer.WriteReserved(_arrayPtrOffsets[i], (uint)in_writer.CalculateOffset(in_writer.Position, OffsetType.Relative), false); + in_writer.Write(this[i].GetParamCount()); + in_writer.WriteOffset((uint)in_writer.CalculateOffset(in_writer.Position + sizeof(uint), OffsetType.Relative)); + this[i].Write(in_writer); + } + } + + public uint GetParamCount() + { + return (uint)Count; + } + } + + public class RotateInfo : IMomentumParamSet + { + public Vector3 Rotation { get; set; } + + public GoalInterpolation GoalInterpolation { get; set; } + + public float TotalTime { get; set; } + + public float Coefficient { get; set; } + + public bool Accel { get; set; } + + public uint UnknownField1 { get; set; } + + public int UnknownField2 { get; set; } + + public RotateInfo() { } + + public RotateInfo(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + Rotation = in_reader.Read(); + GoalInterpolation = in_reader.Read(); + TotalTime = in_reader.Read(); + Coefficient = in_reader.Read(); + Accel = in_reader.Read() != 0; + UnknownField1 = in_reader.Read(); + UnknownField2 = in_reader.Read(); + } + + public void Write(BinaryObjectWriterEx in_writer) + { + in_writer.Write(Rotation); + in_writer.Write(GoalInterpolation); + in_writer.Write(TotalTime); + in_writer.Write(Coefficient); + in_writer.Write(Accel ? 1 : 0); + in_writer.Write(UnknownField1); + in_writer.Write(UnknownField2); + } + + public uint GetParamCount() + { + return 9; + } + } + } +} diff --git a/Marathon/Formats/Acroarts/Types/Momentums/RotateNormal.cs b/Marathon/Formats/Acroarts/Types/Momentums/RotateNormal.cs new file mode 100644 index 00000000..9e7c0d3f --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Momentums/RotateNormal.cs @@ -0,0 +1,32 @@ +using Marathon.IO; +using System.Numerics; + +namespace Marathon.Formats.Acroarts.Types.Momentums +{ + public class RotateNormal : IMomentumParamSet + { + public Vector3 Rotation { get; set; } + + public RotateNormal() { } + + public RotateNormal(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + Rotation = in_reader.Read(); + } + + public void Write(BinaryObjectWriterEx in_writer) + { + in_writer.Write(Rotation); + } + + public uint GetParamCount() + { + return 3; + } + } +} diff --git a/Marathon/Formats/Acroarts/Types/Momentums/RotateRandomAdd.cs b/Marathon/Formats/Acroarts/Types/Momentums/RotateRandomAdd.cs new file mode 100644 index 00000000..857dd55d --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Momentums/RotateRandomAdd.cs @@ -0,0 +1,44 @@ +using Marathon.IO; +using System.Numerics; + +namespace Marathon.Formats.Acroarts.Types.Momentums +{ + public class RotateRandomAdd : IMomentumParamSet + { + public Vector3 Rotation { get; set; } + + public Vector3 Add { get; set; } + + public uint UnknownField1 { get; set; } + + public GTCounter GTCounter { get; set; } + + public RotateRandomAdd() { } + + public RotateRandomAdd(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + Rotation = in_reader.Read(); + Add = in_reader.Read(); + UnknownField1 = in_reader.Read(); + GTCounter = in_reader.Read(); + } + + public void Write(BinaryObjectWriterEx in_writer) + { + in_writer.Write(Rotation); + in_writer.Write(Add); + in_writer.Write(UnknownField1); + in_writer.Write(GTCounter); + } + + public uint GetParamCount() + { + return 8; + } + } +} diff --git a/Marathon/Formats/Acroarts/Types/Momentums/RotateRandomNormal.cs b/Marathon/Formats/Acroarts/Types/Momentums/RotateRandomNormal.cs new file mode 100644 index 00000000..3287e11a --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Momentums/RotateRandomNormal.cs @@ -0,0 +1,40 @@ +using Marathon.IO; +using System.Numerics; + +namespace Marathon.Formats.Acroarts.Types.Momentums +{ + public class RotateRandomNormal : IMomentumParamSet + { + public Vector3 Rotation { get; set; } + + public Vector3 Random { get; set; } + + public uint UnknownField { get; set; } + + public RotateRandomNormal() { } + + public RotateRandomNormal(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + Rotation = in_reader.Read(); + Random = in_reader.Read(); + UnknownField = in_reader.Read(); + } + + public void Write(BinaryObjectWriterEx in_writer) + { + in_writer.Write(Rotation); + in_writer.Write(Random); + in_writer.Write(UnknownField); + } + + public uint GetParamCount() + { + return 7; + } + } +} diff --git a/Marathon/Formats/Acroarts/Types/Momentums/ScaleAccel.cs b/Marathon/Formats/Acroarts/Types/Momentums/ScaleAccel.cs new file mode 100644 index 00000000..171b2065 --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Momentums/ScaleAccel.cs @@ -0,0 +1,32 @@ +using Marathon.IO; +using System.Numerics; + +namespace Marathon.Formats.Acroarts.Types.Momentums +{ + public class ScaleAccel : IMomentumParamSet + { + public Vector4 Scale { get; set; } + + public ScaleAccel() { } + + public ScaleAccel(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + Scale = in_reader.Read(); + } + + public void Write(BinaryObjectWriterEx in_writer) + { + in_writer.Write(Scale); + } + + public uint GetParamCount() + { + return 4; + } + } +} diff --git a/Marathon/Formats/Acroarts/Types/Momentums/ScaleAdd.cs b/Marathon/Formats/Acroarts/Types/Momentums/ScaleAdd.cs new file mode 100644 index 00000000..2a111d4f --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Momentums/ScaleAdd.cs @@ -0,0 +1,32 @@ +using Marathon.IO; +using System.Numerics; + +namespace Marathon.Formats.Acroarts.Types.Momentums +{ + public class ScaleAdd : IMomentumParamSet + { + public Vector4 Scale { get; set; } + + public ScaleAdd() { } + + public ScaleAdd(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + Scale = in_reader.Read(); + } + + public void Write(BinaryObjectWriterEx in_writer) + { + in_writer.Write(Scale); + } + + public uint GetParamCount() + { + return 4; + } + } +} diff --git a/Marathon/Formats/Acroarts/Types/Momentums/ScaleAddGoal.cs b/Marathon/Formats/Acroarts/Types/Momentums/ScaleAddGoal.cs new file mode 100644 index 00000000..57f7f123 --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Momentums/ScaleAddGoal.cs @@ -0,0 +1,149 @@ +using Marathon.IO; +using System.Collections.Generic; +using System.Numerics; + +namespace Marathon.Formats.Acroarts.Types.Momentums +{ + public class ScaleAddGoal : IMomentumParamSet + { + public ScaleInfoSet Steps { get; set; } + + public GTCounter GTCounter { get; set; } + + public ScaleAddGoal() { } + + public ScaleAddGoal(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + var infoSetOffset = in_reader.Read(); + + in_reader.ReadAtOffset(in_reader.CalculateOffset(infoSetOffset), () => + { + Steps = new ScaleInfoSet(in_reader); + }); + + GTCounter = in_reader.Read(); + } + + public void Write(BinaryObjectWriterEx in_writer) + { + var infoSetOffset = in_writer.Reserve(); + in_writer.Write(GTCounter); + in_writer.WriteReserved(infoSetOffset, (uint)in_writer.CalculateOffset(in_writer.Position, OffsetType.Relative), false); + Steps.Write(in_writer); + } + + public uint GetParamCount() + { + return 2; + } + + public class ScaleInfoSet : List, IMomentumParamSet + { + private List _arrayPtrOffsets = []; + + public ScaleInfoSet() { } + + public ScaleInfoSet(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + var offsets = new AnonymousMomentumParamSet(in_reader); + + foreach (var offset in offsets) + { + in_reader.ReadAtOffset(in_reader.CalculateOffset(offset.UInt32), () => + { + var paramCount = in_reader.Read(); + var paramOffset = in_reader.Read(); + + in_reader.ReadAtOffset(in_reader.CalculateOffset(paramOffset), () => + { + Add(new ScaleInfo(in_reader)); + }); + }); + } + } + + public void Write(BinaryObjectWriterEx in_writer) + { + in_writer.Write(Count); + in_writer.WriteOffset((uint)in_writer.CalculateOffset(in_writer.Position + sizeof(uint), OffsetType.Relative)); + + for (int i = 0; i < Count; i++) + _arrayPtrOffsets.Add(in_writer.Reserve()); + + for (int i = 0; i < Count; i++) + { + in_writer.WriteReserved(_arrayPtrOffsets[i], (uint)in_writer.CalculateOffset(in_writer.Position, OffsetType.Relative), false); + in_writer.Write(this[i].GetParamCount()); + in_writer.WriteOffset((uint)in_writer.CalculateOffset(in_writer.Position + sizeof(uint), OffsetType.Relative)); + this[i].Write(in_writer); + } + } + + public uint GetParamCount() + { + return (uint)Count; + } + } + + public class ScaleInfo : IMomentumParamSet + { + public Vector3 Scale { get; set; } + + public GoalInterpolation GoalInterpolation { get; set; } + + public float TotalTime { get; set; } + + public float Coefficient { get; set; } + + public bool Accel { get; set; } + + public uint UnknownField1 { get; set; } + + public int UnknownField2 { get; set; } + + public ScaleInfo() { } + + public ScaleInfo(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + Scale = in_reader.Read(); + GoalInterpolation = in_reader.Read(); + TotalTime = in_reader.Read(); + Coefficient = in_reader.Read(); + Accel = in_reader.Read() != 0; + UnknownField1 = in_reader.Read(); + UnknownField2 = in_reader.Read(); + } + + public void Write(BinaryObjectWriterEx in_writer) + { + in_writer.Write(Scale); + in_writer.Write(GoalInterpolation); + in_writer.Write(TotalTime); + in_writer.Write(Coefficient); + in_writer.Write(Accel ? 1 : 0); + in_writer.Write(UnknownField1); + in_writer.Write(UnknownField2); + } + + public uint GetParamCount() + { + return 9; + } + } + } +} diff --git a/Marathon/Formats/Acroarts/Types/Momentums/ScaleGoal.cs b/Marathon/Formats/Acroarts/Types/Momentums/ScaleGoal.cs new file mode 100644 index 00000000..a7c2572c --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Momentums/ScaleGoal.cs @@ -0,0 +1,141 @@ +using Marathon.IO; +using System.Collections.Generic; +using System.Numerics; + +namespace Marathon.Formats.Acroarts.Types.Momentums +{ + public class ScaleGoal : IMomentumParamSet + { + public ScaleInfoSet Steps { get; set; } + + public GTCounter GTCounter { get; set; } + + public ScaleGoal() { } + + public ScaleGoal(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + var infoSetOffset = in_reader.Read(); + + in_reader.ReadAtOffset(in_reader.CalculateOffset(infoSetOffset), () => + { + Steps = new ScaleInfoSet(in_reader); + }); + + GTCounter = in_reader.Read(); + } + + public void Write(BinaryObjectWriterEx in_writer) + { + var infoSetOffset = in_writer.Reserve(); + in_writer.Write(GTCounter); + in_writer.WriteReserved(infoSetOffset, (uint)in_writer.CalculateOffset(in_writer.Position, OffsetType.Relative), false); + Steps.Write(in_writer); + } + + public uint GetParamCount() + { + return 2; + } + + public class ScaleInfoSet : List, IMomentumParamSet + { + private List _arrayPtrOffsets = []; + + public ScaleInfoSet() { } + + public ScaleInfoSet(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + var offsets = new AnonymousMomentumParamSet(in_reader); + + foreach (var offset in offsets) + { + in_reader.ReadAtOffset(in_reader.CalculateOffset(offset.UInt32), () => + { + var paramCount = in_reader.Read(); + var paramOffset = in_reader.Read(); + + in_reader.ReadAtOffset(in_reader.CalculateOffset(paramOffset), () => + { + Add(new ScaleInfo(in_reader)); + }); + }); + } + } + + public void Write(BinaryObjectWriterEx in_writer) + { + in_writer.Write(Count); + in_writer.WriteOffset((uint)in_writer.CalculateOffset(in_writer.Position + sizeof(uint), OffsetType.Relative)); + + for (int i = 0; i < Count; i++) + _arrayPtrOffsets.Add(in_writer.Reserve()); + + for (int i = 0; i < Count; i++) + { + in_writer.WriteReserved(_arrayPtrOffsets[i], (uint)in_writer.CalculateOffset(in_writer.Position, OffsetType.Relative), false); + in_writer.Write(this[i].GetParamCount()); + in_writer.WriteOffset((uint)in_writer.CalculateOffset(in_writer.Position + sizeof(uint), OffsetType.Relative)); + this[i].Write(in_writer); + } + } + + public uint GetParamCount() + { + return (uint)Count; + } + } + + public class ScaleInfo : IMomentumParamSet + { + public Vector3 UnknownField1 { get; set; } + + public uint UnknownField2 { get; set; } + + public Vector3 UnknownField3 { get; set; } + + public uint UnknownField4 { get; set; } + + public int UnknownField5 { get; set; } + + public ScaleInfo() { } + + public ScaleInfo(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + UnknownField1 = in_reader.Read(); + UnknownField2 = in_reader.Read(); + UnknownField3 = in_reader.Read(); + UnknownField4 = in_reader.Read(); + UnknownField5 = in_reader.Read(); + } + + public void Write(BinaryObjectWriterEx in_writer) + { + in_writer.Write(UnknownField1); + in_writer.Write(UnknownField2); + in_writer.Write(UnknownField3); + in_writer.Write(UnknownField4); + in_writer.Write(UnknownField5); + } + + public uint GetParamCount() + { + return 9; + } + } + } +} diff --git a/Marathon/Formats/Acroarts/Types/Momentums/ScaleNormal.cs b/Marathon/Formats/Acroarts/Types/Momentums/ScaleNormal.cs new file mode 100644 index 00000000..821cd38b --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Momentums/ScaleNormal.cs @@ -0,0 +1,32 @@ +using Marathon.IO; +using System.Numerics; + +namespace Marathon.Formats.Acroarts.Types.Momentums +{ + public class ScaleNormal : IMomentumParamSet + { + public Vector3 Scale { get; set; } + + public ScaleNormal() { } + + public ScaleNormal(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + Scale = in_reader.Read(); + } + + public void Write(BinaryObjectWriterEx in_writer) + { + in_writer.Write(Scale); + } + + public uint GetParamCount() + { + return 3; + } + } +} diff --git a/Marathon/Formats/Acroarts/Types/Momentums/ScaleRandomAdd.cs b/Marathon/Formats/Acroarts/Types/Momentums/ScaleRandomAdd.cs new file mode 100644 index 00000000..249ae168 --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Momentums/ScaleRandomAdd.cs @@ -0,0 +1,48 @@ +using Marathon.IO; +using System.Numerics; + +namespace Marathon.Formats.Acroarts.Types.Momentums +{ + public class ScaleRandomAdd : IMomentumParamSet + { + public Vector3 Scale { get; set; } + + public Vector3 Add { get; set; } + + public uint UnknownField1 { get; set; } + + public GTCounter GTCounter { get; set; } + + public uint UnknownField2 { get; set; } + + public ScaleRandomAdd() { } + + public ScaleRandomAdd(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + Scale = in_reader.Read(); + Add = in_reader.Read(); + UnknownField1 = in_reader.Read(); + GTCounter = in_reader.Read(); + UnknownField2 = in_reader.Read(); + } + + public void Write(BinaryObjectWriterEx in_writer) + { + in_writer.Write(Scale); + in_writer.Write(Add); + in_writer.Write(UnknownField1); + in_writer.Write(GTCounter); + in_writer.Write(UnknownField2); + } + + public uint GetParamCount() + { + return 9; + } + } +} diff --git a/Marathon/Formats/Acroarts/Types/Momentums/ScaleRandomGoal.cs b/Marathon/Formats/Acroarts/Types/Momentums/ScaleRandomGoal.cs new file mode 100644 index 00000000..6c8ccf18 --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Momentums/ScaleRandomGoal.cs @@ -0,0 +1,169 @@ +using Marathon.IO; +using System.Collections.Generic; +using System.Numerics; + +namespace Marathon.Formats.Acroarts.Types.Momentums +{ + public class ScaleRandomGoal : IMomentumParamSet + { + public ScaleInfoSet Steps { get; set; } + + public uint UnknownField1 { get; set; } + + public GTCounter GTCounter { get; set; } + + public uint UnknownField3 { get; set; } + + public ScaleRandomGoal() { } + + public ScaleRandomGoal(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + var infoSetOffset = in_reader.Read(); + + in_reader.ReadAtOffset(in_reader.CalculateOffset(infoSetOffset), () => + { + Steps = new ScaleInfoSet(in_reader); + }); + + UnknownField1 = in_reader.Read(); + GTCounter = in_reader.Read(); + UnknownField3 = in_reader.Read(); + } + + public void Write(BinaryObjectWriterEx in_writer) + { + var infoSetOffset = in_writer.Reserve(); + in_writer.Write(UnknownField1); + in_writer.Write(GTCounter); + in_writer.Write(UnknownField3); + in_writer.WriteReserved(infoSetOffset, (uint)in_writer.CalculateOffset(in_writer.Position, OffsetType.Relative), false); + Steps.Write(in_writer); + } + + public uint GetParamCount() + { + return 4; + } + + public class ScaleInfoSet : List, IMomentumParamSet + { + private List _arrayPtrOffsets = []; + + public ScaleInfoSet() { } + + public ScaleInfoSet(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + var offsets = new AnonymousMomentumParamSet(in_reader); + + foreach (var offset in offsets) + { + in_reader.ReadAtOffset(in_reader.CalculateOffset(offset.UInt32), () => + { + var paramCount = in_reader.Read(); + var paramOffset = in_reader.Read(); + + in_reader.ReadAtOffset(in_reader.CalculateOffset(paramOffset), () => + { + Add(new ScaleInfo(in_reader)); + }); + }); + } + } + + public void Write(BinaryObjectWriterEx in_writer) + { + in_writer.Write(Count); + in_writer.WriteOffset((uint)in_writer.CalculateOffset(in_writer.Position + sizeof(uint), OffsetType.Relative)); + + for (int i = 0; i < Count; i++) + _arrayPtrOffsets.Add(in_writer.Reserve()); + + for (int i = 0; i < Count; i++) + { + in_writer.WriteReserved(_arrayPtrOffsets[i], (uint)in_writer.CalculateOffset(in_writer.Position, OffsetType.Relative), false); + in_writer.Write(this[i].GetParamCount()); + in_writer.WriteOffset((uint)in_writer.CalculateOffset(in_writer.Position + sizeof(uint), OffsetType.Relative)); + this[i].Write(in_writer); + } + } + + public uint GetParamCount() + { + return (uint)Count; + } + } + + public class ScaleInfo : IMomentumParamSet + { + public Vector3 UnknownField1 { get; set; } + + public Vector3 UnknownField2 { get; set; } + + public GoalInterpolation GoalInterpolation { get; set; } + + public uint UnknownField4 { get; set; } + + public uint UnknownField5 { get; set; } + + public float UnknownField6 { get; set; } + + public float UnknownField7 { get; set; } + + public bool Accel { get; set; } + + public uint UnknownField9 { get; set; } + + public int UnknownField10 { get; set; } + + public ScaleInfo() { } + + public ScaleInfo(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + UnknownField1 = in_reader.Read(); + UnknownField2 = in_reader.Read(); + GoalInterpolation = in_reader.Read(); + UnknownField4 = in_reader.Read(); + UnknownField5 = in_reader.Read(); + UnknownField6 = in_reader.Read(); + UnknownField7 = in_reader.Read(); + Accel = in_reader.Read() != 0; + UnknownField9 = in_reader.Read(); + UnknownField10 = in_reader.Read(); + } + + public void Write(BinaryObjectWriterEx in_writer) + { + in_writer.Write(UnknownField1); + in_writer.Write(UnknownField2); + in_writer.Write(GoalInterpolation); + in_writer.Write(UnknownField4); + in_writer.Write(UnknownField5); + in_writer.Write(UnknownField6); + in_writer.Write(UnknownField7); + in_writer.Write(Accel ? 1 : 0); + in_writer.Write(UnknownField9); + in_writer.Write(UnknownField10); + } + + public uint GetParamCount() + { + return 14; + } + } + } +} diff --git a/Marathon/Formats/Acroarts/Types/Momentums/ScaleRandomNormal.cs b/Marathon/Formats/Acroarts/Types/Momentums/ScaleRandomNormal.cs new file mode 100644 index 00000000..e5644192 --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Momentums/ScaleRandomNormal.cs @@ -0,0 +1,44 @@ +using Marathon.IO; +using System.Numerics; + +namespace Marathon.Formats.Acroarts.Types.Momentums +{ + public class ScaleRandomNormal : IMomentumParamSet + { + public Vector3 Scale { get; set; } + + public Vector3 Random { get; set; } + + public uint UnknownField1 { get; set; } + + public uint UnknownField2 { get; set; } + + public ScaleRandomNormal() { } + + public ScaleRandomNormal(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + Scale = in_reader.Read(); + Random = in_reader.Read(); + UnknownField1 = in_reader.Read(); + UnknownField2 = in_reader.Read(); + } + + public void Write(BinaryObjectWriterEx in_writer) + { + in_writer.Write(Scale); + in_writer.Write(Random); + in_writer.Write(UnknownField1); + in_writer.Write(UnknownField2); + } + + public uint GetParamCount() + { + return 8; + } + } +} diff --git a/Marathon/Formats/Acroarts/Types/Momentums/SendParamGoal.cs b/Marathon/Formats/Acroarts/Types/Momentums/SendParamGoal.cs new file mode 100644 index 00000000..4878fd20 --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Momentums/SendParamGoal.cs @@ -0,0 +1,97 @@ +using Marathon.IO; +using System.Collections.Generic; + +namespace Marathon.Formats.Acroarts.Types.Momentums +{ + public class SendParamGoal : IMomentumParamSet + { + public List StepsA { get; set; } = []; + + public List StepsB { get; set; } = []; + + public GTCounter GTCounter { get; set; } + + public SendParamGoal() { } + + public SendParamGoal(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + var unkOffset1 = in_reader.Read(); + var unkOffset2 = in_reader.Read(); + + GTCounter = in_reader.Read(); + + in_reader.ReadAtOffset(in_reader.CalculateOffset(unkOffset1), () => + { + var offsets = new AnonymousMomentumParamSet(in_reader); + + foreach (var offset in offsets) + { + in_reader.ReadAtOffset(in_reader.CalculateOffset(offset.UInt32), () => + { + StepsA.Add(new AnonymousMomentumParamSet(in_reader)); + }); + } + }); + + in_reader.ReadAtOffset(in_reader.CalculateOffset(unkOffset2), () => + { + var offsets = new AnonymousMomentumParamSet(in_reader); + + foreach (var offset in offsets) + { + in_reader.ReadAtOffset(in_reader.CalculateOffset(offset.UInt32), () => + { + StepsB.Add(new AnonymousMomentumParamSet(in_reader)); + }); + } + }); + } + + public void Write(BinaryObjectWriterEx in_writer) + { + var unkOffset1 = in_writer.Reserve(); + var unkOffset2 = in_writer.Reserve(); + + in_writer.Write(GTCounter); + + var paramsAOffsets = new List(); + var paramsBOffsets = new List(); + + in_writer.WriteReserved(unkOffset1, (uint)in_writer.CalculateOffset(in_writer.Position, OffsetType.Relative), false); + in_writer.Write(StepsA.Count); + in_writer.WriteOffset((uint)in_writer.CalculateOffset(in_writer.Position + sizeof(uint), OffsetType.Relative)); + + for (int i = 0; i < StepsA.Count; i++) + paramsAOffsets.Add(in_writer.Reserve()); + + for (int i = 0; i < StepsA.Count; i++) + { + in_writer.WriteReserved(paramsAOffsets[i], (uint)in_writer.CalculateOffset(in_writer.Position, OffsetType.Relative), false); + StepsA[i].Write(in_writer); + } + + in_writer.WriteReserved(unkOffset2, (uint)in_writer.CalculateOffset(in_writer.Position, OffsetType.Relative), false); + in_writer.Write(StepsB.Count); + in_writer.WriteOffset((uint)in_writer.CalculateOffset(in_writer.Position + sizeof(uint), OffsetType.Relative)); + + for (int i = 0; i < StepsB.Count; i++) + paramsBOffsets.Add(in_writer.Reserve()); + + for (int i = 0; i < StepsB.Count; i++) + { + in_writer.WriteReserved(paramsBOffsets[i], (uint)in_writer.CalculateOffset(in_writer.Position, OffsetType.Relative), false); + StepsB[i].Write(in_writer); + } + } + + public uint GetParamCount() + { + return 3; + } + } +} diff --git a/Marathon/Formats/Acroarts/Types/Momentums/ShadowOn.cs b/Marathon/Formats/Acroarts/Types/Momentums/ShadowOn.cs new file mode 100644 index 00000000..a050f3c2 --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Momentums/ShadowOn.cs @@ -0,0 +1,31 @@ +using Marathon.IO; + +namespace Marathon.Formats.Acroarts.Types.Momentums +{ + public class ShadowOn : IMomentumParamSet + { + public bool On { get; set; } + + public ShadowOn() { } + + public ShadowOn(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + On = in_reader.Read() != 0; + } + + public void Write(BinaryObjectWriterEx in_writer) + { + in_writer.Write(On ? 1 : 0); + } + + public uint GetParamCount() + { + return 1; + } + } +} diff --git a/Marathon/Formats/Acroarts/Types/Momentums/Sound3DPlay.cs b/Marathon/Formats/Acroarts/Types/Momentums/Sound3DPlay.cs new file mode 100644 index 00000000..3b9f3ebe --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Momentums/Sound3DPlay.cs @@ -0,0 +1,11 @@ +using Marathon.IO; + +namespace Marathon.Formats.Acroarts.Types.Momentums +{ + public class Sound3DPlay : SoundPlay + { + public Sound3DPlay() { } + + public Sound3DPlay(BinaryObjectReaderEx in_reader) : base(in_reader) { } + } +} diff --git a/Marathon/Formats/Acroarts/Types/Momentums/SoundPlay.cs b/Marathon/Formats/Acroarts/Types/Momentums/SoundPlay.cs new file mode 100644 index 00000000..8ba83a34 --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Momentums/SoundPlay.cs @@ -0,0 +1,50 @@ +using Marathon.IO; + +namespace Marathon.Formats.Acroarts.Types.Momentums +{ + public class SoundPlay : IMomentumParamSet + { + public string SoundBankName { get; set; } = "event"; + + public string SoundName { get; set; } + + public SoundPlay() { } + + public SoundPlay(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + var soundBankNameOffset = in_reader.Read(); + var soundNameOffset = in_reader.Read(); + + if (soundBankNameOffset != 0) + { + in_reader.ReadAtOffset(in_reader.CalculateOffset(soundBankNameOffset), + () => SoundBankName = MomentumString.Read(in_reader)); + } + + if (soundNameOffset != 0) + { + in_reader.ReadAtOffset(in_reader.CalculateOffset(soundNameOffset), + () => SoundName = MomentumString.Read(in_reader)); + } + } + + public void Write(BinaryObjectWriterEx in_writer) + { + var soundBankNameOffset = in_writer.Reserve(); + var soundNameOffset = in_writer.Reserve(); + + MomentumString.Write(in_writer, SoundBankName, soundBankNameOffset); + MomentumString.Write(in_writer, SoundName, soundNameOffset); + } + + public uint GetParamCount() + { + return 2; + } + } +} diff --git a/Marathon/Formats/Acroarts/Types/Momentums/SparklingTail.cs b/Marathon/Formats/Acroarts/Types/Momentums/SparklingTail.cs new file mode 100644 index 00000000..3da296a3 --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Momentums/SparklingTail.cs @@ -0,0 +1,222 @@ +using Marathon.Formats.Acroarts.Collections; +using Marathon.IO; +using Marathon.IO.Types; +using System.Numerics; + +namespace Marathon.Formats.Acroarts.Types.Momentums +{ + public class SparklingTail : IMomentumParamSet + { + public bool UseBezierSpline { get; set; } + + public float UnknownField1 { get; set; } + + public Distance DistanceBezier { get; set; } + + public int UnknownField2 { get; set; } + + public Vector3 Offset { get; set; } + + public Distance DistanceWidth { get; set; } + + public Distance DistanceHeight { get; set; } + + public uint UnknownField3 { get; set; } + + public bool UseSplineMotion { get; set; } + + public IndirectMomentumParamList> SplineKeyFrames { get; set; } = []; + + public bool Loop { get; set; } + + public int BlendMode { get; set; } + + public int UnknownField4 { get; set; } + + public uint ParticleCount { get; set; } + + public float Rate { get; set; } + + public float UnknownField5 { get; set; } + + public float UnknownField6 { get; set; } + + public float UnknownField7 { get; set; } + + public bool Billboard { get; set; } + + public uint UnknownField8 { get; set; } + + public Distance DistanceVelocityX { get; set; } + + public Distance DistanceVelocityY { get; set; } + + public Distance DistanceVelocityZ { get; set; } + + public uint UnknownField9 { get; set; } + + public uint UnknownField10 { get; set; } + + public Distance DistanceAccelX { get; set; } + + public Distance DistanceAccelY { get; set; } + + public Distance DistanceAccelZ { get; set; } + + public uint UnknownField11 { get; set; } + + public float Parameter { get; set; } + + public IndirectMomentumParamList ColorKeyFrames { get; set; } = []; + + public bool UseColorMotion { get; set; } + + public bool UsePattern { get; set; } + + public int TextureCount { get; set; } + + public int Surface { get; set; } + + public AnonymousMomentumParam Anime { get; set; } + + public bool UsePatternMotion { get; set; } + + public int PatternColumns { get; set; } + + public int PatternRows { get; set; } + + public uint PatternIndex { get; set; } + + public uint PatternCount { get; set; } + + public uint UnknownField12 { get; set; } + + public bool UseRandomPattern { get; set; } + + public SparklingTail() { } + + public SparklingTail(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + UseBezierSpline = in_reader.ReadBoolean(); + UnknownField1 = in_reader.Read(); + DistanceBezier = in_reader.Read>(); + UnknownField2 = in_reader.Read(); + Offset = in_reader.Read(); + DistanceWidth = in_reader.Read>(); + DistanceHeight = in_reader.Read>(); + UnknownField3 = in_reader.Read(); + UseSplineMotion = in_reader.ReadBoolean(); + + var splineKeyFramesOffset = in_reader.Read(); + + in_reader.ReadAtOffset(in_reader.CalculateOffset(splineKeyFramesOffset), () => + { + SplineKeyFrames.Read(in_reader); + }); + + Loop = in_reader.ReadBoolean(); + BlendMode = in_reader.Read(); + UnknownField4 = in_reader.Read(); + ParticleCount = in_reader.Read(); + Rate = in_reader.Read(); + UnknownField5 = in_reader.Read(); + UnknownField6 = in_reader.Read(); + UnknownField7 = in_reader.Read(); + Billboard = in_reader.ReadBoolean(); + UnknownField8 = in_reader.Read(); + DistanceVelocityX = in_reader.Read>(); + DistanceVelocityY = in_reader.Read>(); + DistanceVelocityZ = in_reader.Read>(); + UnknownField9 = in_reader.Read(); + UnknownField10 = in_reader.Read(); + DistanceAccelX = in_reader.Read>(); + DistanceAccelY = in_reader.Read>(); + DistanceAccelZ = in_reader.Read>(); + UnknownField11 = in_reader.Read(); + Parameter = in_reader.Read(); + + var colorKeyFramesOffset = in_reader.Read(); + + in_reader.ReadAtOffset(in_reader.CalculateOffset(colorKeyFramesOffset), () => + { + ColorKeyFrames.Read(in_reader); + }); + + UseColorMotion = in_reader.ReadBoolean(); + UsePattern = in_reader.ReadBoolean(); + TextureCount = in_reader.Read(); + Surface = in_reader.Read(); + Anime = in_reader.ReadObjectEx(); + UsePatternMotion = in_reader.ReadBoolean(); + PatternColumns = in_reader.Read(); + PatternRows = in_reader.Read(); + PatternIndex = in_reader.Read(); + PatternCount = in_reader.Read(); + UnknownField12 = in_reader.Read(); + UseRandomPattern = in_reader.ReadBoolean(); + } + + public void Write(BinaryObjectWriterEx in_writer) + { + in_writer.WriteBoolean(UseBezierSpline); + in_writer.Write(UnknownField1); + in_writer.Write(DistanceBezier); + in_writer.Write(UnknownField2); + in_writer.Write(Offset); + in_writer.Write(DistanceWidth); + in_writer.Write(DistanceHeight); + in_writer.Write(UnknownField3); + in_writer.WriteBoolean(UseSplineMotion); + var splineKeyFramesOffset = in_writer.Reserve(); + in_writer.WriteBoolean(Loop); + in_writer.Write(BlendMode); + in_writer.Write(UnknownField4); + in_writer.Write(ParticleCount); + in_writer.Write(Rate); + in_writer.Write(UnknownField5); + in_writer.Write(UnknownField6); + in_writer.Write(UnknownField7); + in_writer.WriteBoolean(Billboard); + in_writer.Write(UnknownField8); + in_writer.Write(DistanceVelocityX); + in_writer.Write(DistanceVelocityY); + in_writer.Write(DistanceVelocityZ); + in_writer.Write(UnknownField9); + in_writer.Write(UnknownField10); + in_writer.Write(DistanceAccelX); + in_writer.Write(DistanceAccelY); + in_writer.Write(DistanceAccelZ); + in_writer.Write(UnknownField11); + in_writer.Write(Parameter); + var colorKeyFramesOffset = in_writer.Reserve(); + in_writer.WriteBoolean(UseColorMotion); + in_writer.WriteBoolean(UsePattern); + in_writer.Write(TextureCount); + in_writer.Write(Surface); + in_writer.WriteObjectEx(Anime); + in_writer.WriteBoolean(UsePatternMotion); + in_writer.Write(PatternColumns); + in_writer.Write(PatternRows); + in_writer.Write(PatternIndex); + in_writer.Write(PatternCount); + in_writer.Write(UnknownField12); + in_writer.WriteBoolean(UseRandomPattern); + + in_writer.WriteReserved(splineKeyFramesOffset, (uint)in_writer.CalculateOffset(in_writer.Position, OffsetType.Relative), false); + SplineKeyFrames.Write(in_writer); + + in_writer.WriteReserved(colorKeyFramesOffset, (uint)in_writer.CalculateOffset(in_writer.Position, OffsetType.Relative), false); + ColorKeyFrames.Write(in_writer); + } + + public uint GetParamCount() + { + return 54; + } + } +} diff --git a/Marathon/Formats/Acroarts/Types/Momentums/SplineKeyFrame.cs b/Marathon/Formats/Acroarts/Types/Momentums/SplineKeyFrame.cs new file mode 100644 index 00000000..2f96f578 --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Momentums/SplineKeyFrame.cs @@ -0,0 +1,49 @@ +using Marathon.IO; +using System.Runtime.InteropServices; + +namespace Marathon.Formats.Acroarts.Types.Momentums +{ + public class SplineKeyFrame : IMomentumParamSet where T : unmanaged + { + public float Frame { get; set; } + + public T Data { get; set; } + + public float Tension { get; set; } + + public float Continuity { get; set; } + + public float Bias { get; set; } + + public float EaseTo { get; set; } + + public float EaseFrom { get; set; } + + public void Read(BinaryObjectReaderEx in_reader) + { + Frame = in_reader.Read(); + Data = in_reader.Read(); + Tension = in_reader.Read(); + Continuity = in_reader.Read(); + Bias = in_reader.Read(); + EaseTo = in_reader.Read(); + EaseFrom = in_reader.Read(); + } + + public void Write(BinaryObjectWriterEx in_writer) + { + in_writer.Write(Frame); + in_writer.Write(Data); + in_writer.Write(Tension); + in_writer.Write(Continuity); + in_writer.Write(Bias); + in_writer.Write(EaseTo); + in_writer.Write(EaseFrom); + } + + public uint GetParamCount() + { + return (uint)(6 + (Marshal.SizeOf() / 4)); + } + } +} diff --git a/Marathon/Formats/Acroarts/Types/Momentums/Subtitle.cs b/Marathon/Formats/Acroarts/Types/Momentums/Subtitle.cs new file mode 100644 index 00000000..8d3a7803 --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Momentums/Subtitle.cs @@ -0,0 +1,60 @@ +using Marathon.IO; + +namespace Marathon.Formats.Acroarts.Types.Momentums +{ + public class Subtitle : IMomentumParamSet + { + public string TextBookName { get; set; } = "subtitle"; + + public string TextCardName { get; set; } + + public uint UnknownField1 { get; set; } + + public uint UnknownField2 { get; set; } + + public Subtitle() { } + + public Subtitle(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + var textBookNameOffset = in_reader.Read(); + var textCardNameOffset = in_reader.Read(); + + UnknownField1 = in_reader.Read(); + UnknownField2 = in_reader.Read(); + + if (textBookNameOffset != 0) + { + in_reader.ReadAtOffset(in_reader.CalculateOffset(textBookNameOffset), + () => TextBookName = MomentumString.Read(in_reader)); + } + + if (textCardNameOffset != 0) + { + in_reader.ReadAtOffset(in_reader.CalculateOffset(textCardNameOffset), + () => TextCardName = MomentumString.Read(in_reader)); + } + } + + public void Write(BinaryObjectWriterEx in_writer) + { + var textBookNameOffset = in_writer.Reserve(); + var textCardNameOffset = in_writer.Reserve(); + + in_writer.Write(UnknownField1); + in_writer.Write(UnknownField2); + + MomentumString.Write(in_writer, TextBookName, textBookNameOffset); + MomentumString.Write(in_writer, TextCardName, textCardNameOffset); + } + + public uint GetParamCount() + { + return 4; + } + } +} diff --git a/Marathon/Formats/Acroarts/Types/Momentums/TranslateAccel.cs b/Marathon/Formats/Acroarts/Types/Momentums/TranslateAccel.cs new file mode 100644 index 00000000..cbd7e49f --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Momentums/TranslateAccel.cs @@ -0,0 +1,36 @@ +using Marathon.IO; +using System.Numerics; + +namespace Marathon.Formats.Acroarts.Types.Momentums +{ + public class TranslateAccel : IMomentumParamSet + { + public Vector3 Vector { get; set; } + + public Vector3 BaseVector { get; set; } + + public TranslateAccel() { } + + public TranslateAccel(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + Vector = in_reader.Read(); + BaseVector = in_reader.Read(); + } + + public void Write(BinaryObjectWriterEx in_writer) + { + in_writer.Write(Vector); + in_writer.Write(BaseVector); + } + + public uint GetParamCount() + { + return 6; + } + } +} diff --git a/Marathon/Formats/Acroarts/Types/Momentums/TranslateAdd.cs b/Marathon/Formats/Acroarts/Types/Momentums/TranslateAdd.cs new file mode 100644 index 00000000..5c0c6a6e --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Momentums/TranslateAdd.cs @@ -0,0 +1,36 @@ +using Marathon.IO; +using System.Numerics; + +namespace Marathon.Formats.Acroarts.Types.Momentums +{ + public class TranslateAdd : IMomentumParamSet + { + public Vector3 Vector { get; set; } + + public Vector3 BaseVector { get; set; } + + public TranslateAdd() { } + + public TranslateAdd(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + Vector = in_reader.Read(); + BaseVector = in_reader.Read(); + } + + public void Write(BinaryObjectWriterEx in_writer) + { + in_writer.Write(Vector); + in_writer.Write(BaseVector); + } + + public uint GetParamCount() + { + return 6; + } + } +} diff --git a/Marathon/Formats/Acroarts/Types/Momentums/TranslateGoal.cs b/Marathon/Formats/Acroarts/Types/Momentums/TranslateGoal.cs new file mode 100644 index 00000000..d824d75f --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Momentums/TranslateGoal.cs @@ -0,0 +1,157 @@ +using Marathon.IO; +using System.Collections.Generic; +using System.Numerics; + +namespace Marathon.Formats.Acroarts.Types.Momentums +{ + public class TranslateGoal : IMomentumParamSet + { + public TranslateInfoSet Steps { get; set; } + + public GTCounter GTCounter { get; set; } + + public TranslateGoal() { } + + public TranslateGoal(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + var infoSetOffset = in_reader.Read(); + + in_reader.ReadAtOffset(in_reader.CalculateOffset(infoSetOffset), () => + { + Steps = new TranslateInfoSet(in_reader); + }); + + GTCounter = in_reader.Read(); + } + + public void Write(BinaryObjectWriterEx in_writer) + { + var infoSetOffset = in_writer.Reserve(); + in_writer.Write(GTCounter); + in_writer.WriteReserved(infoSetOffset, (uint)in_writer.CalculateOffset(in_writer.Position, OffsetType.Relative), false); + Steps.Write(in_writer); + } + + public uint GetParamCount() + { + return 2; + } + + public class TranslateInfoSet : List, IMomentumParamSet + { + private List _arrayPtrOffsets = []; + + public TranslateInfoSet() { } + + public TranslateInfoSet(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + var offsets = new AnonymousMomentumParamSet(in_reader); + + foreach (var offset in offsets) + { + in_reader.ReadAtOffset(in_reader.CalculateOffset(offset.UInt32), () => + { + var paramCount = in_reader.Read(); + var paramOffset = in_reader.Read(); + + in_reader.ReadAtOffset(in_reader.CalculateOffset(paramOffset), () => + { + Add(new TranslateInfo(in_reader)); + }); + }); + } + } + + public void Write(BinaryObjectWriterEx in_writer) + { + in_writer.Write(Count); + in_writer.WriteOffset((uint)in_writer.CalculateOffset(in_writer.Position + sizeof(uint), OffsetType.Relative)); + + for (int i = 0; i < Count; i++) + _arrayPtrOffsets.Add(in_writer.Reserve()); + + for (int i = 0; i < Count; i++) + { + in_writer.WriteReserved(_arrayPtrOffsets[i], (uint)in_writer.CalculateOffset(in_writer.Position, OffsetType.Relative), false); + in_writer.Write(this[i].GetParamCount()); + in_writer.WriteOffset((uint)in_writer.CalculateOffset(in_writer.Position + sizeof(uint), OffsetType.Relative)); + this[i].Write(in_writer); + } + } + + public uint GetParamCount() + { + return (uint)Count; + } + } + + public class TranslateInfo : IMomentumParamSet + { + public Vector3 Vector { get; set; } + + public GoalInterpolation GoalInterpolation { get; set; } + + public float TotalTime { get; set; } + + public float Coefficient { get; set; } + + public bool Accel { get; set; } + + public TranslateVectorType VectorType { get; set; } + + public uint UnknownField1 { get; set; } + + public uint UnknownField2 { get; set; } + + public int UnknownField3 { get; set; } + + public TranslateInfo() { } + + public TranslateInfo(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + Vector = in_reader.Read(); + GoalInterpolation = in_reader.Read(); + TotalTime = in_reader.Read(); + Coefficient = in_reader.Read(); + Accel = in_reader.Read() != 0; + VectorType = in_reader.Read(); + UnknownField1 = in_reader.Read(); + UnknownField2 = in_reader.Read(); + UnknownField3 = in_reader.Read(); + } + + public void Write(BinaryObjectWriterEx in_writer) + { + in_writer.Write(Vector); + in_writer.Write(GoalInterpolation); + in_writer.Write(TotalTime); + in_writer.Write(Coefficient); + in_writer.Write(Accel ? 1 : 0); + in_writer.Write(VectorType); + in_writer.Write(UnknownField1); + in_writer.Write(UnknownField2); + in_writer.Write(UnknownField3); + } + + public uint GetParamCount() + { + return 11; + } + } + } +} diff --git a/Marathon/Formats/Acroarts/Types/Momentums/TranslateNormal.cs b/Marathon/Formats/Acroarts/Types/Momentums/TranslateNormal.cs new file mode 100644 index 00000000..e16a863f --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Momentums/TranslateNormal.cs @@ -0,0 +1,40 @@ +using Marathon.IO; +using System.Numerics; + +namespace Marathon.Formats.Acroarts.Types.Momentums +{ + public class TranslateNormal : IMomentumParamSet + { + public Vector3 Vector { get; set; } + + public TranslateVectorType VectorType { get; set; } + + public uint Parameter { get; set; } + + public TranslateNormal() { } + + public TranslateNormal(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + Vector = in_reader.Read(); + VectorType = in_reader.Read(); + Parameter = in_reader.Read(); + } + + public void Write(BinaryObjectWriterEx in_writer) + { + in_writer.Write(Vector); + in_writer.Write(VectorType); + in_writer.Write(Parameter); + } + + public uint GetParamCount() + { + return 5; + } + } +} diff --git a/Marathon/Formats/Acroarts/Types/Momentums/TranslateRandomAdd.cs b/Marathon/Formats/Acroarts/Types/Momentums/TranslateRandomAdd.cs new file mode 100644 index 00000000..fd1b2079 --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Momentums/TranslateRandomAdd.cs @@ -0,0 +1,52 @@ +using Marathon.IO; +using System.Numerics; + +namespace Marathon.Formats.Acroarts.Types.Momentums +{ + public class TranslateRandomAdd : IMomentumParamSet + { + public Vector3 Vector { get; set; } + + public Vector3 Add { get; set; } + + public uint UnknownField { get; set; } + + public GTCounter GTCounter { get; set; } + + public TranslateVectorType VectorType { get; set; } + + public int Parameter { get; set; } + + public TranslateRandomAdd() { } + + public TranslateRandomAdd(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + Vector = in_reader.Read(); + Add = in_reader.Read(); + UnknownField = in_reader.Read(); + GTCounter = in_reader.Read(); + VectorType = in_reader.Read(); + Parameter = in_reader.Read(); + } + + public void Write(BinaryObjectWriterEx in_writer) + { + in_writer.Write(Vector); + in_writer.Write(Add); + in_writer.Write(UnknownField); + in_writer.Write(GTCounter); + in_writer.Write(VectorType); + in_writer.Write(Parameter); + } + + public uint GetParamCount() + { + return 10; + } + } +} diff --git a/Marathon/Formats/Acroarts/Types/Momentums/TranslateRandomNormal.cs b/Marathon/Formats/Acroarts/Types/Momentums/TranslateRandomNormal.cs new file mode 100644 index 00000000..a806d1ae --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Momentums/TranslateRandomNormal.cs @@ -0,0 +1,48 @@ +using Marathon.IO; +using System.Numerics; + +namespace Marathon.Formats.Acroarts.Types.Momentums +{ + public class TranslateRandomNormal : IMomentumParamSet + { + public Vector3 Vector { get; set; } + + public Vector3 Random { get; set; } + + public GTCounter GTCounter { get; set; } + + public TranslateVectorType VectorType { get; set; } + + public int Parameter { get; set; } + + public TranslateRandomNormal() { } + + public TranslateRandomNormal(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + Vector = in_reader.Read(); + Random = in_reader.Read(); + GTCounter = in_reader.Read(); + VectorType = in_reader.Read(); + Parameter = in_reader.Read(); + } + + public void Write(BinaryObjectWriterEx in_writer) + { + in_writer.Write(Vector); + in_writer.Write(Random); + in_writer.Write(GTCounter); + in_writer.Write(VectorType); + in_writer.Write(Parameter); + } + + public uint GetParamCount() + { + return 9; + } + } +} diff --git a/Marathon/Formats/Acroarts/Types/Momentums/TranslateRandomSin.cs b/Marathon/Formats/Acroarts/Types/Momentums/TranslateRandomSin.cs new file mode 100644 index 00000000..5771cd07 --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Momentums/TranslateRandomSin.cs @@ -0,0 +1,100 @@ +using Marathon.IO; +using System.Numerics; + +namespace Marathon.Formats.Acroarts.Types.Momentums +{ + public class TranslateRandomSin : IMomentumParamSet + { + public Vector3 Vector { get; set; } + + public uint UnknownField4 { get; set; } + + public uint UnknownField5 { get; set; } + + public uint UnknownField6 { get; set; } + + public float UnknownField7 { get; set; } + + public float UnknownField8 { get; set; } + + public float UnknownField9 { get; set; } + + public float UnknownField10 { get; set; } + + public uint UnknownField11 { get; set; } + + public uint UnknownField12 { get; set; } + + public uint UnknownField13 { get; set; } + + public uint UnknownField14 { get; set; } + + public uint UnknownField15 { get; set; } + + public uint UnknownField16 { get; set; } + + public uint UnknownField17 { get; set; } + + public GTCounter GTCounter { get; set; } + + public TranslateVectorType VectorType { get; set; } + + public int Parameter { get; set; } + + public TranslateRandomSin() { } + + public TranslateRandomSin(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + Vector = in_reader.Read(); + UnknownField4 = in_reader.Read(); + UnknownField5 = in_reader.Read(); + UnknownField6 = in_reader.Read(); + UnknownField7 = in_reader.Read(); + UnknownField8 = in_reader.Read(); + UnknownField9 = in_reader.Read(); + UnknownField10 = in_reader.Read(); + UnknownField11 = in_reader.Read(); + UnknownField12 = in_reader.Read(); + UnknownField13 = in_reader.Read(); + UnknownField14 = in_reader.Read(); + UnknownField15 = in_reader.Read(); + UnknownField16 = in_reader.Read(); + UnknownField17 = in_reader.Read(); + GTCounter = in_reader.Read(); + VectorType = in_reader.Read(); + Parameter = in_reader.Read(); + } + + public void Write(BinaryObjectWriterEx in_writer) + { + in_writer.Write(Vector); + in_writer.Write(UnknownField4); + in_writer.Write(UnknownField5); + in_writer.Write(UnknownField6); + in_writer.Write(UnknownField7); + in_writer.Write(UnknownField8); + in_writer.Write(UnknownField9); + in_writer.Write(UnknownField10); + in_writer.Write(UnknownField11); + in_writer.Write(UnknownField12); + in_writer.Write(UnknownField13); + in_writer.Write(UnknownField14); + in_writer.Write(UnknownField15); + in_writer.Write(UnknownField16); + in_writer.Write(UnknownField17); + in_writer.Write(GTCounter); + in_writer.Write(VectorType); + in_writer.Write(Parameter); + } + + public uint GetParamCount() + { + return 20; + } + } +} diff --git a/Marathon/Formats/Acroarts/Types/Momentums/TranslateVectorType.cs b/Marathon/Formats/Acroarts/Types/Momentums/TranslateVectorType.cs new file mode 100644 index 00000000..bc96fc83 --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Momentums/TranslateVectorType.cs @@ -0,0 +1,17 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + +namespace Marathon.Formats.Acroarts.Types.Momentums +{ + [JsonConverter(typeof(StringEnumConverter))] + public enum TranslateVectorType : int + { + Local, + WorldVector, + World, + CameraVector, + Camera, + LightVector, + Light + } +} diff --git a/Marathon/Formats/Acroarts/Types/Momentums/TurnCamera.cs b/Marathon/Formats/Acroarts/Types/Momentums/TurnCamera.cs new file mode 100644 index 00000000..82d42c02 --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Momentums/TurnCamera.cs @@ -0,0 +1,39 @@ +using Marathon.IO; + +namespace Marathon.Formats.Acroarts.Types.Momentums +{ + public class TurnCamera : IMomentumParamSet + { + public FaceType FaceType { get; set; } + + public float Radius { get; set; } + + public AxisType Axis { get; set; } + + public TurnCamera() { } + + public TurnCamera(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + FaceType = in_reader.Read(); + Radius = in_reader.Read(); + Axis = in_reader.Read(); + } + + public void Write(BinaryObjectWriterEx in_writer) + { + in_writer.Write(FaceType); + in_writer.Write(Radius); + in_writer.Write(Axis); + } + + public uint GetParamCount() + { + return 3; + } + } +} diff --git a/Marathon/Formats/Acroarts/Types/Random.cs b/Marathon/Formats/Acroarts/Types/Random.cs new file mode 100644 index 00000000..185ea054 --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Random.cs @@ -0,0 +1,29 @@ +using Marathon.IO.Types; + +namespace Marathon.Formats.Acroarts.Types +{ + public class Random + { + public static uint GetRandomI(uint in_max) + { + return (uint)(long)((double)in_max * (float)(CRandom.Rand() % 30000) / 29999.0) % in_max; + } + + public static float GetRandomF(float in_max) + { + var result = (float)(CRandom.Rand() % 100 + 1) / 100.0f * in_max; + + if (in_max < 0.0f) + { + if (in_max >= result) + return result / 2.0f; + } + else if (result >= in_max) + { + return result / 2.0f; + } + + return result; + } + } +} diff --git a/Marathon/Formats/Acroarts/Types/Resources/CameraResourceTable.cs b/Marathon/Formats/Acroarts/Types/Resources/CameraResourceTable.cs new file mode 100644 index 00000000..948369d1 --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Resources/CameraResourceTable.cs @@ -0,0 +1,47 @@ +using Marathon.Formats.Acroarts.Collections; +using Marathon.IO; + +namespace Marathon.Formats.Acroarts.Types.Resources +{ + public class CameraResourceTable : IResourceTable + { + public IndirectUnmanagedList Cameras { get; set; } = []; + + public IndirectUnmanagedList CameraMotions { get; set; } = []; + + public CameraResourceTable() { } + + public CameraResourceTable(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + Cameras = new IndirectUnmanagedList(in_reader); + CameraMotions = new IndirectUnmanagedList(in_reader); + + in_reader.JumpAhead(sizeof(uint) * 4); + } + + public void WriteInfo(BinaryObjectWriterEx in_writer) + { + Cameras.WriteInfo(in_writer); + CameraMotions.WriteInfo(in_writer); + + in_writer.JumpAhead(sizeof(uint) * 4); + } + + public void WriteArray(BinaryObjectWriterEx in_writer) + { + Cameras.WriteArray(in_writer); + CameraMotions.WriteArray(in_writer); + } + + public void WriteData(BinaryObjectWriterEx in_writer) + { + Cameras.WriteData(in_writer); + CameraMotions.WriteData(in_writer); + } + } +} diff --git a/Marathon/Formats/Acroarts/Types/Resources/CellSpriteResourceTable.cs b/Marathon/Formats/Acroarts/Types/Resources/CellSpriteResourceTable.cs new file mode 100644 index 00000000..80248179 --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Resources/CellSpriteResourceTable.cs @@ -0,0 +1,53 @@ +using Marathon.Formats.Acroarts.Collections; +using Marathon.IO; + +namespace Marathon.Formats.Acroarts.Types.Resources +{ + public class CellSpriteResourceTable : IResourceTable + { + public IndirectUnmanagedList CellSprites { get; set; } = []; + + public IndirectUnmanagedList Textures { get; set; } = []; + + public CellSpriteResourceTable() { } + + public CellSpriteResourceTable(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + CellSprites = new IndirectUnmanagedList(in_reader); + Textures = new IndirectUnmanagedList(in_reader); + + in_reader.JumpAhead(sizeof(uint) * 4); + } + + public void WriteInfo(BinaryObjectWriterEx in_writer) + { + CellSprites.WriteInfo(in_writer); + Textures.WriteInfo(in_writer); + + in_writer.JumpAhead(sizeof(uint) * 4); + } + + public void WriteArray(BinaryObjectWriterEx in_writer) + { + CellSprites.WriteArray(in_writer); + Textures.WriteArray(in_writer); + } + + public void WriteData(BinaryObjectWriterEx in_writer) + { + CellSprites.WriteData(in_writer); + Textures.WriteData(in_writer); + } + } + + public struct CellSpriteIndex + { + public uint Index; + public uint DefaultAction; + } +} diff --git a/Marathon/Formats/Acroarts/Types/Resources/ExtraResourceTable.cs b/Marathon/Formats/Acroarts/Types/Resources/ExtraResourceTable.cs new file mode 100644 index 00000000..d4b3c44a --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Resources/ExtraResourceTable.cs @@ -0,0 +1,42 @@ +using Marathon.Formats.Acroarts.Chunks; +using Marathon.Formats.Acroarts.Collections; +using Marathon.IO; + +namespace Marathon.Formats.Acroarts.Types.Resources +{ + public class ExtraResourceTable : IResourceTable + { + public IndirectUnmanagedList Extras { get; set; } = []; + + public ExtraResourceTable() { } + + public ExtraResourceTable(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + Extras = new IndirectUnmanagedList(in_reader); + + in_reader.JumpAhead(sizeof(uint) * 6); + } + + public void WriteInfo(BinaryObjectWriterEx in_writer) + { + Extras.WriteInfo(in_writer); + + in_writer.JumpAhead(sizeof(uint) * 6); + } + + public void WriteArray(BinaryObjectWriterEx in_writer) + { + Extras.WriteArray(in_writer); + } + + public void WriteData(BinaryObjectWriterEx in_writer) + { + Extras.WriteData(in_writer); + } + } +} diff --git a/Marathon/Formats/Acroarts/Types/Resources/IResourceTable.cs b/Marathon/Formats/Acroarts/Types/Resources/IResourceTable.cs new file mode 100644 index 00000000..2b09c899 --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Resources/IResourceTable.cs @@ -0,0 +1,15 @@ +using Marathon.IO; + +namespace Marathon.Formats.Acroarts.Types.Resources +{ + public interface IResourceTable + { + void Read(BinaryObjectReaderEx in_reader); + + void WriteInfo(BinaryObjectWriterEx in_writer); + + void WriteArray(BinaryObjectWriterEx in_writer); + + void WriteData(BinaryObjectWriterEx in_writer); + } +} diff --git a/Marathon/Formats/Acroarts/Types/Resources/LightResourceTable.cs b/Marathon/Formats/Acroarts/Types/Resources/LightResourceTable.cs new file mode 100644 index 00000000..b2f2f3a5 --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Resources/LightResourceTable.cs @@ -0,0 +1,47 @@ +using Marathon.Formats.Acroarts.Collections; +using Marathon.IO; + +namespace Marathon.Formats.Acroarts.Types.Resources +{ + public class LightResourceTable : IResourceTable + { + public IndirectUnmanagedList Lights { get; set; } = []; + + public IndirectUnmanagedList LightMotions { get; set; } = []; + + public LightResourceTable() { } + + public LightResourceTable(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + Lights = new IndirectUnmanagedList(in_reader); + LightMotions = new IndirectUnmanagedList(in_reader); + + in_reader.JumpAhead(sizeof(uint) * 4); + } + + public void WriteInfo(BinaryObjectWriterEx in_writer) + { + Lights.WriteInfo(in_writer); + LightMotions.WriteInfo(in_writer); + + in_writer.JumpAhead(sizeof(uint) * 4); + } + + public void WriteArray(BinaryObjectWriterEx in_writer) + { + Lights.WriteArray(in_writer); + LightMotions.WriteArray(in_writer); + } + + public void WriteData(BinaryObjectWriterEx in_writer) + { + Lights.WriteData(in_writer); + LightMotions.WriteData(in_writer); + } + } +} diff --git a/Marathon/Formats/Acroarts/Types/Resources/ModelResourceTable.cs b/Marathon/Formats/Acroarts/Types/Resources/ModelResourceTable.cs new file mode 100644 index 00000000..e44eddef --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Resources/ModelResourceTable.cs @@ -0,0 +1,55 @@ +using Marathon.Formats.Acroarts.Collections; +using Marathon.IO; + +namespace Marathon.Formats.Acroarts.Types.Resources +{ + public class ModelResourceTable : IResourceTable + { + public IndirectUnmanagedList Models { get; set; } = []; + + public IndirectUnmanagedList Materials { get; set; } = []; + + public IndirectUnmanagedList Motions { get; set; } = []; + + public IndirectUnmanagedList Textures { get; set; } = []; + + public ModelResourceTable() { } + + public ModelResourceTable(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + Models = new IndirectUnmanagedList(in_reader); + Materials = new IndirectUnmanagedList(in_reader); + Motions = new IndirectUnmanagedList(in_reader); + Textures = new IndirectUnmanagedList(in_reader); + } + + public void WriteInfo(BinaryObjectWriterEx in_writer) + { + Models.WriteInfo(in_writer); + Materials.WriteInfo(in_writer); + Motions.WriteInfo(in_writer); + Textures.WriteInfo(in_writer); + } + + public void WriteArray(BinaryObjectWriterEx in_writer) + { + Models.WriteArray(in_writer); + Materials.WriteArray(in_writer); + Motions.WriteArray(in_writer); + Textures.WriteArray(in_writer); + } + + public void WriteData(BinaryObjectWriterEx in_writer) + { + Models.WriteData(in_writer); + Materials.WriteData(in_writer); + Motions.WriteData(in_writer); + Textures.WriteData(in_writer); + } + } +} diff --git a/Marathon/Formats/Acroarts/Types/Resources/PrimitiveResourceTable.cs b/Marathon/Formats/Acroarts/Types/Resources/PrimitiveResourceTable.cs new file mode 100644 index 00000000..e3308f89 --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Resources/PrimitiveResourceTable.cs @@ -0,0 +1,41 @@ +using Marathon.Formats.Acroarts.Collections; +using Marathon.IO; + +namespace Marathon.Formats.Acroarts.Types.Resources +{ + public class PrimitiveResourceTable : IResourceTable + { + public IndirectUnmanagedList Textures { get; set; } = []; + + public PrimitiveResourceTable() { } + + public PrimitiveResourceTable(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + Textures = new IndirectUnmanagedList(in_reader); + + in_reader.JumpAhead(sizeof(uint) * 6); + } + + public void WriteInfo(BinaryObjectWriterEx in_writer) + { + Textures.WriteInfo(in_writer); + + in_writer.JumpAhead(sizeof(uint) * 6); + } + + public void WriteArray(BinaryObjectWriterEx in_writer) + { + Textures.WriteArray(in_writer); + } + + public void WriteData(BinaryObjectWriterEx in_writer) + { + Textures.WriteData(in_writer); + } + } +} diff --git a/Marathon/Formats/Acroarts/Types/Resources/ResourceTableFactory.cs b/Marathon/Formats/Acroarts/Types/Resources/ResourceTableFactory.cs new file mode 100644 index 00000000..5b20862f --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Resources/ResourceTableFactory.cs @@ -0,0 +1,28 @@ +using Marathon.IO; + +namespace Marathon.Formats.Acroarts.Types.Resources +{ + public class ResourceTableFactory + { + public static IResourceTable ReadResourceTableByType(BinaryObjectReaderEx in_reader, ResourceType in_type) + { + IResourceTable resource = in_type switch + { + ResourceType.Model => new ModelResourceTable(in_reader), + ResourceType.CellSprite => new CellSpriteResourceTable(in_reader), + ResourceType.Camera => new CameraResourceTable(in_reader), + ResourceType.Screen => new ScreenResourceTable(in_reader), + ResourceType.Light => new LightResourceTable(in_reader), + ResourceType.Primitive => new PrimitiveResourceTable(in_reader), + ResourceType.Extra => new ExtraResourceTable(in_reader), + _ => null + }; + + // Skip resources. + if (resource == null) + in_reader.JumpAhead(sizeof(uint) * 8); + + return resource; + } + } +} diff --git a/Marathon/Formats/Acroarts/Types/Resources/ResourceType.cs b/Marathon/Formats/Acroarts/Types/Resources/ResourceType.cs new file mode 100644 index 00000000..13f88982 --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Resources/ResourceType.cs @@ -0,0 +1,17 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + +namespace Marathon.Formats.Acroarts.Types.Resources +{ + [JsonConverter(typeof(StringEnumConverter))] + public enum ResourceType : int + { + Model = 0, + CellSprite = 4, + Camera = 5, + Screen = 6, + Light = 7, + Primitive = 8, + Extra = 9 + } +} diff --git a/Marathon/Formats/Acroarts/Types/Resources/ScreenResourceTable.cs b/Marathon/Formats/Acroarts/Types/Resources/ScreenResourceTable.cs new file mode 100644 index 00000000..5e10baf9 --- /dev/null +++ b/Marathon/Formats/Acroarts/Types/Resources/ScreenResourceTable.cs @@ -0,0 +1,53 @@ +using Marathon.Formats.Acroarts.Collections; +using Marathon.IO; + +namespace Marathon.Formats.Acroarts.Types.Resources +{ + public class ScreenResourceTable : IResourceTable + { + public IndirectUnmanagedList Screens { get; set; } = []; + + public IndirectUnmanagedList ScreenMotions { get; set; } = []; + + public ScreenResourceTable() { } + + public ScreenResourceTable(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + Screens = new IndirectUnmanagedList(in_reader); + ScreenMotions = new IndirectUnmanagedList(in_reader); + + in_reader.JumpAhead(sizeof(uint) * 4); + } + + public void WriteInfo(BinaryObjectWriterEx in_writer) + { + Screens.WriteInfo(in_writer); + ScreenMotions.WriteInfo(in_writer); + + in_writer.JumpAhead(sizeof(uint) * 4); + } + + public void WriteArray(BinaryObjectWriterEx in_writer) + { + Screens.WriteArray(in_writer); + ScreenMotions.WriteArray(in_writer); + } + + public void WriteData(BinaryObjectWriterEx in_writer) + { + Screens.WriteData(in_writer); + ScreenMotions.WriteData(in_writer); + } + } + + public struct ScreenMotionIndex + { + public uint Index; + public uint MotionElement; + } +} diff --git a/Marathon/Formats/Archive/ArcFile.cs b/Marathon/Formats/Archive/ArcFile.cs index 36f63873..81e47a7b 100644 --- a/Marathon/Formats/Archive/ArcFile.cs +++ b/Marathon/Formats/Archive/ArcFile.cs @@ -213,7 +213,7 @@ public override void Write(Stream in_stream) writer.Reserve("EntriesLength"); writer.Reserve("DataOffset"); writer.Write(IsSoXArchive ? _soxMagic : 0); - writer.WriteNullBytes(12); + writer.WriteZero(12); writer.WriteReserved("EntriesOffset", (uint)writer.Position); diff --git a/Marathon/Formats/Ninja/Chunks/ChunkFactory.cs b/Marathon/Formats/Ninja/Chunks/ChunkFactory.cs index 4d154e4e..419e3795 100644 --- a/Marathon/Formats/Ninja/Chunks/ChunkFactory.cs +++ b/Marathon/Formats/Ninja/Chunks/ChunkFactory.cs @@ -9,23 +9,23 @@ public static IChunk GetChunkByFourCC(BinaryObjectReaderEx in_reader, FourCC in_ { return in_signature.ToString() switch { - InfoChunk.ID => new InfoChunk(in_reader), - TextureListChunk.ID => new TextureListChunk(in_reader), - EffectListChunk.ID => new EffectListChunk(in_reader), - NodeNameChunk.ID => new NodeNameChunk(in_reader), - ObjectChunk.ID => new ObjectChunk(in_reader), - CameraChunk.ID => new CameraChunk(in_reader), - LightChunk.ID => new LightChunk(in_reader), - MotionChunk.ID => new MotionChunk(in_reader), - MaterialMotionChunk.ID => new MaterialMotionChunk(in_reader), - CameraMotionChunk.ID => new CameraMotionChunk(in_reader), - LightMotionChunk.ID => new LightMotionChunk(in_reader), - MorphMotionChunk.ID => new MorphMotionChunk(in_reader), - MorphTargetChunk.ID => new MorphTargetChunk(in_reader), - OffsetChunk.ID => new OffsetChunk(in_reader), - FileNameChunk.ID => new FileNameChunk(in_reader), - EndChunk.ID => new EndChunk(in_reader), - _ => new UndefinedChunk(in_reader) + InfoChunk.ID => new InfoChunk(in_reader), + TextureListChunk.ID => new TextureListChunk(in_reader), + EffectListChunk.ID => new EffectListChunk(in_reader), + NodeNameChunk.ID => new NodeNameChunk(in_reader), + ObjectChunk.ID => new ObjectChunk(in_reader), + CameraChunk.ID => new CameraChunk(in_reader), + LightChunk.ID => new LightChunk(in_reader), + MotionChunk.ID => new MotionChunk(in_reader), + MaterialMotionChunk.ID => new MaterialMotionChunk(in_reader), + CameraMotionChunk.ID => new CameraMotionChunk(in_reader), + LightMotionChunk.ID => new LightMotionChunk(in_reader), + MorphMotionChunk.ID => new MorphMotionChunk(in_reader), + MorphTargetChunk.ID => new MorphTargetChunk(in_reader), + RelocationTableChunk.ID => new RelocationTableChunk(in_reader), + FileNameChunk.ID => new FileNameChunk(in_reader), + EndChunk.ID => new EndChunk(in_reader), + _ => new UndefinedChunk(in_reader) }; } } diff --git a/Marathon/Formats/Ninja/Types/ChunkHeader.cs b/Marathon/Formats/Ninja/Chunks/ChunkHeader.cs similarity index 84% rename from Marathon/Formats/Ninja/Types/ChunkHeader.cs rename to Marathon/Formats/Ninja/Chunks/ChunkHeader.cs index ff7d6ca5..f5825a46 100644 --- a/Marathon/Formats/Ninja/Types/ChunkHeader.cs +++ b/Marathon/Formats/Ninja/Chunks/ChunkHeader.cs @@ -2,14 +2,14 @@ using Marathon.IO; using Marathon.IO.Types; -namespace Marathon.Formats.Ninja.Types +namespace Marathon.Formats.Ninja.Chunks { public class ChunkHeader : IBinarySerializable { - private uint _lengthOffset; - private uint _chunkStart; - private uint _dataOffset; - private uint _versionOffset; + private long _lengthOffset; + private long _chunkStart; + private long _dataOffset; + private long _versionOffset; public const int Size = 0x10; @@ -31,8 +31,8 @@ public ChunkHeader(FourCC in_id, uint in_length, uint in_dataOffset, int in_vers Version = in_version; } - public ChunkHeader(string in_id, uint in_length, uint in_dataOffset, int in_version, Endianness in_endianness) - : this(new FourCC(in_id, in_endianness), in_length, in_dataOffset, in_version) { } + public ChunkHeader(string in_id, uint in_length, uint in_dataOffset, int in_version = 0) + : this(new FourCC(in_id), in_length, in_dataOffset, in_version) { } public ChunkHeader(BinaryObjectWriterEx in_writer, FourCC in_id, int in_version = 0) { @@ -43,7 +43,7 @@ public ChunkHeader(BinaryObjectWriterEx in_writer, FourCC in_id, int in_version } public ChunkHeader(BinaryObjectWriterEx in_writer, string in_id, int in_version = 0) - : this(in_writer, new FourCC(in_id, in_writer.Endianness), in_version) { } + : this(in_writer, new FourCC(in_id), in_version) { } public void Read(BinaryObjectReader in_reader) { @@ -86,7 +86,7 @@ public void FinishWrite(BinaryObjectWriterEx in_writer, uint in_dataOffset, int FinishWrite(in_writer); } - public uint GetChunkStart() + public long GetChunkStart() { return _chunkStart; } diff --git a/Marathon/Formats/Ninja/Chunks/EndChunk.cs b/Marathon/Formats/Ninja/Chunks/EndChunk.cs index c245f17e..3aaf0ba0 100644 --- a/Marathon/Formats/Ninja/Chunks/EndChunk.cs +++ b/Marathon/Formats/Ninja/Chunks/EndChunk.cs @@ -1,6 +1,5 @@ using Amicitia.IO.Binary; using Marathon.Exceptions; -using Marathon.Formats.Ninja.Types; using Marathon.IO; using Marathon.IO.Extensions; diff --git a/Marathon/Formats/Ninja/Chunks/FileNameChunk.cs b/Marathon/Formats/Ninja/Chunks/FileNameChunk.cs index 9913af99..ff9ec3f7 100644 --- a/Marathon/Formats/Ninja/Chunks/FileNameChunk.cs +++ b/Marathon/Formats/Ninja/Chunks/FileNameChunk.cs @@ -1,6 +1,5 @@ using Amicitia.IO.Binary; using Marathon.Exceptions; -using Marathon.Formats.Ninja.Types; using Marathon.IO; using Marathon.IO.Extensions; diff --git a/Marathon/Formats/Ninja/Chunks/InfoChunk.cs b/Marathon/Formats/Ninja/Chunks/InfoChunk.cs index 93714371..918403f6 100644 --- a/Marathon/Formats/Ninja/Chunks/InfoChunk.cs +++ b/Marathon/Formats/Ninja/Chunks/InfoChunk.cs @@ -9,11 +9,11 @@ namespace Marathon.Formats.Ninja.Chunks { public class InfoChunk : IChunk { - private uint _chunkStart; - private uint _chunkOffset; - private uint _chunkDataLength; - private uint _offsetChunkOffset; - private uint _offsetChunkLength; + private long _chunkStart; + private long _chunkOffset; + private long _chunkDataLength; + private long _offsetChunkOffset; + private long _offsetChunkLength; public const string ID = "NXIF"; // "Ninja directX InFo" @@ -114,7 +114,7 @@ public void Write(BinaryObjectWriterEx in_writer) public void WriteChunks(BinaryObjectWriterEx in_writer) { - _chunkStart = (uint)in_writer.Position; + _chunkStart = in_writer.Position; foreach (var chunk in Chunks) chunk.Write(in_writer); @@ -124,12 +124,12 @@ public void WriteExtraChunks(BinaryObjectWriterEx in_writer) { foreach (var chunk in ExtraChunks) { - var isOffsetChunk = chunk.GetChunkID() == OffsetChunk.ID; + var isOffsetChunk = chunk.GetChunkID() == RelocationTableChunk.ID; var offsetChunkPos = (uint)in_writer.Position; if (isOffsetChunk) { - in_writer.WriteReserved(_chunkOffset, _chunkStart); + in_writer.WriteReserved(_chunkOffset, (uint)_chunkStart); in_writer.WriteReserved(_chunkDataLength, (uint)(in_writer.Position - _chunkStart)); in_writer.WriteReserved(_offsetChunkOffset, (uint)in_writer.Position); } diff --git a/Marathon/Formats/Ninja/Chunks/NodeNameChunk.cs b/Marathon/Formats/Ninja/Chunks/NodeNameChunk.cs index 77016de9..3d725860 100644 --- a/Marathon/Formats/Ninja/Chunks/NodeNameChunk.cs +++ b/Marathon/Formats/Ninja/Chunks/NodeNameChunk.cs @@ -1,6 +1,5 @@ using Marathon.Exceptions; using Marathon.Formats.Ninja.Flags; -using Marathon.Formats.Ninja.Types; using Marathon.IO; using Marathon.IO.Extensions; using System.Collections.Generic; @@ -59,7 +58,7 @@ public void Write(BinaryObjectWriterEx in_writer) var header = new ChunkHeader(in_writer, GetChunkID(), 0); var nodeListPos = (uint)in_writer.Position; - var nodeNameOffsets = new List(); + var nodeNameOffsets = new List(); for (int i = 0; i < Names.Count; i++) { diff --git a/Marathon/Formats/Ninja/Chunks/ObjectChunk.cs b/Marathon/Formats/Ninja/Chunks/ObjectChunk.cs index e8adde71..6fe7cd78 100644 --- a/Marathon/Formats/Ninja/Chunks/ObjectChunk.cs +++ b/Marathon/Formats/Ninja/Chunks/ObjectChunk.cs @@ -158,27 +158,27 @@ public void Write(BinaryObjectWriterEx in_writer) foreach (var node in Nodes) node.Write(in_writer); - var materialColours = new List(); - var materialColourOffsets = new List(); + var materialColors = new List(); + var materialColorOffsets = new List(); foreach (var material in Materials) { - var existingIndex = materialColours.IndexOf(material.Colour); + var existingIndex = materialColors.IndexOf(material.Color); // NOTE: Ninja optimises repeat material colours // by pointing other materials to the same one if // they're identical. if (existingIndex > -1) { - materialColourOffsets.Add(materialColourOffsets[existingIndex]); + materialColorOffsets.Add(materialColorOffsets[existingIndex]); } else { - materialColourOffsets.Add((uint)in_writer.Position); - material.Colour.Write(in_writer); + materialColorOffsets.Add((uint)in_writer.Position); + material.Color.Write(in_writer); } - materialColours.Add(material.Colour); + materialColors.Add(material.Color); } var materialLogics = new List(); @@ -232,7 +232,7 @@ public void Write(BinaryObjectWriterEx in_writer) Materials[i].WriteInfo ( in_writer, - materialColourOffsets[i], + materialColorOffsets[i], materialLogicOffsets[i], materialTextureMapOffsets[i] ); diff --git a/Marathon/Formats/Ninja/Chunks/OffsetChunk.cs b/Marathon/Formats/Ninja/Chunks/RelocationTableChunk.cs similarity index 87% rename from Marathon/Formats/Ninja/Chunks/OffsetChunk.cs rename to Marathon/Formats/Ninja/Chunks/RelocationTableChunk.cs index a83b31fb..40b7ea59 100644 --- a/Marathon/Formats/Ninja/Chunks/OffsetChunk.cs +++ b/Marathon/Formats/Ninja/Chunks/RelocationTableChunk.cs @@ -7,7 +7,7 @@ namespace Marathon.Formats.Ninja.Chunks { - public class OffsetChunk : IChunk + public class RelocationTableChunk : IChunk { public const string ID = "NOF0"; // "Ninja OFfset" @@ -19,14 +19,14 @@ public uint this[int in_index] set => Offsets[in_index] = value; } - public OffsetChunk() { } + public RelocationTableChunk() { } - public OffsetChunk(BinaryObjectReaderEx in_reader) + public RelocationTableChunk(BinaryObjectReaderEx in_reader) { Read(in_reader); } - public OffsetChunk(List in_offsets) + public RelocationTableChunk(List in_offsets) { Offsets = in_offsets; } diff --git a/Marathon/Formats/Ninja/Chunks/TextureListChunk.cs b/Marathon/Formats/Ninja/Chunks/TextureListChunk.cs index d4465b49..684322ea 100644 --- a/Marathon/Formats/Ninja/Chunks/TextureListChunk.cs +++ b/Marathon/Formats/Ninja/Chunks/TextureListChunk.cs @@ -54,7 +54,7 @@ public void Write(BinaryObjectWriterEx in_writer) var header = new ChunkHeader(in_writer, GetChunkID(), 0); var textureFilePos = (int)(in_writer.Position - InfoChunk.Size); - var textureFileNameOffsets = new List(); + var textureFileNameOffsets = new List(); foreach (var texture in Textures) { diff --git a/Marathon/Formats/Ninja/NinjaNext.cs b/Marathon/Formats/Ninja/NinjaNext.cs index f4cd7679..2117d354 100644 --- a/Marathon/Formats/Ninja/NinjaNext.cs +++ b/Marathon/Formats/Ninja/NinjaNext.cs @@ -63,7 +63,7 @@ public override void Write(Stream in_stream) Info.Write(writer); Info.WriteChunks(writer); - var offsetChunk = new OffsetChunk(); + var offsetChunk = new RelocationTableChunk(); foreach (var offset in writer.Offsets) offsetChunk.Offsets.Add((uint)(offset.Value - InfoChunk.Size)); diff --git a/Marathon/Formats/Ninja/Types/Light.cs b/Marathon/Formats/Ninja/Types/Light.cs index 017779cb..601a83a7 100644 --- a/Marathon/Formats/Ninja/Types/Light.cs +++ b/Marathon/Formats/Ninja/Types/Light.cs @@ -7,11 +7,11 @@ public struct LightStandardGL { public uint UserData { get; set; } - public Colour Ambient { get; set; } + public Color Ambient { get; set; } - public Colour Diffuse { get; set; } + public Color Diffuse { get; set; } - public Colour Specular { get; set; } + public Color Specular { get; set; } public Vector4 Position { get; set; } @@ -32,7 +32,7 @@ public struct LightParallel { public uint UserData { get; set; } - public Colour Colour { get; set; } + public Color Color { get; set; } public float Intensity { get; set; } @@ -43,7 +43,7 @@ public struct LightPoint { public uint UserData { get; set; } - public Colour Colour { get; set; } + public Color Color { get; set; } public float Intensity { get; set; } @@ -58,7 +58,7 @@ public struct LightTargetSpot { public uint UserData { get; set; } - public Colour Colour { get; set; } + public Color Color { get; set; } public float Intensity { get; set; } @@ -79,7 +79,7 @@ public struct LightRotationSpot { public uint UserData { get; set; } - public Colour Colour { get; set; } + public Color Color { get; set; } public float Intensity { get; set; } @@ -106,7 +106,7 @@ public struct LightTargetDirectional { public uint UserData { get; set; } - public Colour Colour { get; set; } + public Color Color { get; set; } public float Intensity { get; set; } @@ -129,7 +129,7 @@ public struct LightRotationDirectional { public uint UserData { get; set; } - public Colour Colour { get; set; } + public Color Color { get; set; } public float Intensity { get; set; } diff --git a/Marathon/Formats/Ninja/Types/Material.cs b/Marathon/Formats/Ninja/Types/Material.cs index c6876a3c..dfbf310c 100644 --- a/Marathon/Formats/Ninja/Types/Material.cs +++ b/Marathon/Formats/Ninja/Types/Material.cs @@ -18,7 +18,7 @@ public class Material public uint[] Reserved { get; set; } = new uint[3]; - public MaterialColour Colour { get; set; } + public MaterialColor Color { get; set; } public MaterialLogic Logic { get; set; } @@ -42,15 +42,15 @@ public void Read(BinaryObjectReaderEx in_reader) Flag = in_reader.Read(); UserData = in_reader.Read(); - var colourOffset = in_reader.Read(); + var colorOffset = in_reader.Read(); var logicOffset = in_reader.Read(); var textureMapOffset = in_reader.Read(); Reserved = in_reader.ReadArray(3); - in_reader.JumpTo(InfoChunk.Size + colourOffset); + in_reader.JumpTo(InfoChunk.Size + colorOffset); - Colour = new MaterialColour(in_reader); + Color = new MaterialColor(in_reader); in_reader.JumpTo(InfoChunk.Size + logicOffset); @@ -61,15 +61,15 @@ public void Read(BinaryObjectReaderEx in_reader) TextureMap = new MaterialTextureMap(in_reader, GetTextureCount()); } - public void WriteInfo(BinaryObjectWriterEx in_writer, uint in_colourOffset, uint in_logicOffset, uint in_textureMapOffset) + public void WriteInfo(BinaryObjectWriterEx in_writer, uint in_colorOffset, uint in_logicOffset, uint in_textureMapOffset) { _dataOffset = (uint)in_writer.Position; in_writer.Write(Flag); in_writer.Write(UserData); - var colourOffset = in_writer.Reserve(); - in_writer.WriteReserved(colourOffset, in_colourOffset - InfoChunk.Size, false); + var colorOffset = in_writer.Reserve(); + in_writer.WriteReserved(colorOffset, in_colorOffset - InfoChunk.Size, false); var logicOffset = in_writer.Reserve(); in_writer.WriteReserved(logicOffset, in_logicOffset - InfoChunk.Size, false); diff --git a/Marathon/Formats/Ninja/Types/MaterialColor.cs b/Marathon/Formats/Ninja/Types/MaterialColor.cs new file mode 100644 index 00000000..7b346a55 --- /dev/null +++ b/Marathon/Formats/Ninja/Types/MaterialColor.cs @@ -0,0 +1,57 @@ +using Amicitia.IO.Binary; +using Marathon.IO; +using Marathon.IO.Types; + +namespace Marathon.Formats.Ninja.Types +{ + public class MaterialColor + { + public Color Diffuse { get; set; } + + public Color Ambient { get; set; } + + public Color Specular { get; set; } + + public Color Emissive { get; set; } + + public float Power { get; set; } + + public MaterialColor() { } + + public MaterialColor(BinaryObjectReaderEx in_reader) + { + Read(in_reader); + } + + public void Read(BinaryObjectReaderEx in_reader) + { + Diffuse = in_reader.ReadObject>(); + Ambient = in_reader.ReadObject>(); + Specular = in_reader.ReadObject>(); + Emissive = in_reader.ReadObject>(); + Power = in_reader.Read(); + } + + public void Write(BinaryObjectWriterEx in_writer) + { + in_writer.WriteObject(Diffuse); + in_writer.WriteObject(Ambient); + in_writer.WriteObject(Specular); + in_writer.WriteObject(Emissive); + in_writer.Write(Power); + in_writer.Align(16); + } + + public override bool Equals(object in_obj) + { + if (in_obj is not MaterialColor out_color) + return false; + + return out_color.Diffuse.Equals(Diffuse) && + out_color.Ambient.Equals(Ambient) && + out_color.Specular.Equals(Specular) && + out_color.Emissive.Equals(Emissive) && + out_color.Power == Power; + } + } +} diff --git a/Marathon/Formats/Ninja/Types/MaterialColour.cs b/Marathon/Formats/Ninja/Types/MaterialColour.cs deleted file mode 100644 index 02131452..00000000 --- a/Marathon/Formats/Ninja/Types/MaterialColour.cs +++ /dev/null @@ -1,57 +0,0 @@ -using Amicitia.IO.Binary; -using Marathon.IO; -using Marathon.IO.Types; - -namespace Marathon.Formats.Ninja.Types -{ - public class MaterialColour - { - public Colour Diffuse { get; set; } - - public Colour Ambient { get; set; } - - public Colour Specular { get; set; } - - public Colour Emissive { get; set; } - - public float Power { get; set; } - - public MaterialColour() { } - - public MaterialColour(BinaryObjectReaderEx in_reader) - { - Read(in_reader); - } - - public void Read(BinaryObjectReaderEx in_reader) - { - Diffuse = in_reader.ReadObject>(); - Ambient = in_reader.ReadObject>(); - Specular = in_reader.ReadObject>(); - Emissive = in_reader.ReadObject>(); - Power = in_reader.Read(); - } - - public void Write(BinaryObjectWriterEx in_writer) - { - in_writer.WriteObject(Diffuse); - in_writer.WriteObject(Ambient); - in_writer.WriteObject(Specular); - in_writer.WriteObject(Emissive); - in_writer.Write(Power); - in_writer.Align(16); - } - - public override bool Equals(object in_obj) - { - if (in_obj is not MaterialColour out_colour) - return false; - - return out_colour.Diffuse.Equals(Diffuse) && - out_colour.Ambient.Equals(Ambient) && - out_colour.Specular.Equals(Specular) && - out_colour.Emissive.Equals(Emissive) && - out_colour.Power == Power; - } - } -} diff --git a/Marathon/Formats/Ninja/Types/TextureFile.cs b/Marathon/Formats/Ninja/Types/TextureFile.cs index b0c0c00a..45d9c8ff 100644 --- a/Marathon/Formats/Ninja/Types/TextureFile.cs +++ b/Marathon/Formats/Ninja/Types/TextureFile.cs @@ -42,7 +42,7 @@ public void Read(BinaryObjectReaderEx in_reader) Bank = in_reader.Read(); } - public void Write(BinaryObjectWriterEx in_writer, out uint out_nameOffset) + public void Write(BinaryObjectWriterEx in_writer, out long out_nameOffset) { in_writer.Write(Type); diff --git a/Marathon/Formats/Ninja/Types/Vertex.cs b/Marathon/Formats/Ninja/Types/Vertex.cs index cf822c9d..d4fe9775 100644 --- a/Marathon/Formats/Ninja/Types/Vertex.cs +++ b/Marathon/Formats/Ninja/Types/Vertex.cs @@ -17,9 +17,9 @@ public class Vertex public Vector3? Normal { get; set; } - public Colour? VertexColourA { get; set; } + public Color? VertexColorA { get; set; } - public Colour? VertexColourB { get; set; } + public Color? VertexColorB { get; set; } public List TextureCoordinates { get; set; } @@ -49,10 +49,10 @@ public void Read(BinaryObjectReaderEx in_reader, VertexList in_vertexList) Normal = in_reader.Read(); if (in_vertexList.Format.HasFlag(VertexFormat.NND_VTXTYPE_XB_COLOR)) - VertexColourA = in_reader.ReadObject>(); + VertexColorA = in_reader.ReadObject>(); if (in_vertexList.Format.HasFlag(VertexFormat.NND_VTXTYPE_XB_COLOR2)) - VertexColourB = in_reader.ReadObject>(); + VertexColorB = in_reader.ReadObject>(); for (int i = 0; i < (uint)in_vertexList.Format / (uint)VertexFormat.NND_VTXTYPE_XB_TEXCOORD; i++) { diff --git a/Marathon/Formats/Ninja/Types/VertexList.cs b/Marathon/Formats/Ninja/Types/VertexList.cs index cd7e9cc2..467b5f3d 100644 --- a/Marathon/Formats/Ninja/Types/VertexList.cs +++ b/Marathon/Formats/Ninja/Types/VertexList.cs @@ -8,8 +8,8 @@ namespace Marathon.Formats.Ninja.Types { public class VertexList { - private uint _dataOffset; - private uint _verticesOffset; + private long _dataOffset; + private long _verticesOffset; public const int InfoSize = 8; @@ -78,7 +78,7 @@ public void Write(BinaryObjectWriterEx in_writer, uint in_verticesOffset = 0) foreach (var index in BoneMatrixIndices) in_writer.Write(index); - _dataOffset = (uint)(in_writer.Position - InfoChunk.Size); + _dataOffset = in_writer.Position - InfoChunk.Size; in_writer.Write(GetVertexFormat()); in_writer.Write(FlexibleFormat); @@ -104,14 +104,14 @@ public void Write(BinaryObjectWriterEx in_writer, uint in_verticesOffset = 0) in_writer.Write(HDRCommon); in_writer.Write(HDRData); in_writer.Write(HDRLock); - in_writer.WriteNullBytes(8); + in_writer.WriteZero(8); } public void WritePointer(BinaryObjectWriterEx in_writer) { in_writer.Write(Type); var offset = in_writer.Reserve(); - in_writer.WriteReserved(offset, _dataOffset, false); + in_writer.WriteReserved(offset, (uint)_dataOffset, false); } public uint WriteVertices(BinaryObjectWriterEx in_writer, bool in_isMorphTarget = false) @@ -135,11 +135,11 @@ public uint WriteVertices(BinaryObjectWriterEx in_writer, bool in_isMorphTarget if (vertex.Normal != null) in_writer.Write(vertex.Normal.Value); - if (vertex.VertexColourA != null) - in_writer.Write(vertex.VertexColourA.Value); + if (vertex.VertexColorA != null) + in_writer.Write(vertex.VertexColorA.Value); - if (vertex.VertexColourB != null) - in_writer.Write(vertex.VertexColourB.Value); + if (vertex.VertexColorB != null) + in_writer.Write(vertex.VertexColorB.Value); if (vertex.TextureCoordinates != null) { @@ -176,10 +176,10 @@ public VertexFormat GetVertexFormat() if (Vertices[0].Normal != null) result |= VertexFormat.NND_VTXTYPE_XB_NORMAL; - if (Vertices[0].VertexColourA != null) + if (Vertices[0].VertexColorA != null) result |= VertexFormat.NND_VTXTYPE_XB_COLOR; - if (Vertices[0].VertexColourB != null) + if (Vertices[0].VertexColorB != null) result |= VertexFormat.NND_VTXTYPE_XB_COLOR2; if (Vertices[0].TextureCoordinates != null) diff --git a/Marathon/Formats/Parameter/ObjectExplosionParameterList.cs b/Marathon/Formats/Parameter/ObjectExplosionParameterList.cs index 79a08343..df5ea3a2 100644 --- a/Marathon/Formats/Parameter/ObjectExplosionParameterList.cs +++ b/Marathon/Formats/Parameter/ObjectExplosionParameterList.cs @@ -125,7 +125,7 @@ public override void Write(Stream in_stream) writer.WriteStringOffset(Parameters[i].SoundBankName); writer.WriteStringOffset(Parameters[i].SoundName); writer.WriteStringOffset(Parameters[i].Light); - writer.WriteNullBytes(12); + writer.WriteZero(12); } writer.Write(0); diff --git a/Marathon/Formats/Particle/ParticleEffectBank.cs b/Marathon/Formats/Particle/ParticleEffectBank.cs index 628d3f88..8aa8e495 100644 --- a/Marathon/Formats/Particle/ParticleEffectBank.cs +++ b/Marathon/Formats/Particle/ParticleEffectBank.cs @@ -150,7 +150,7 @@ public override void Write(Stream in_stream) var writer = new BINAWriter(in_stream, Endianness); writer.WriteSignature(_signature); - writer.WriteNullBytes(8); + writer.WriteZero(8); writer.Write(Effects.Count); writer.WriteStringFixedLength(Name, 0x20); @@ -530,7 +530,7 @@ public void Write(BinaryObjectWriterEx in_writer) public int Length() { var result = 4; - var typeName = Enum.GetName(Type.GetType(),Type.Value); + var typeName = Enum.GetName(Type.GetType(), Type.Value); if (string.IsNullOrEmpty(typeName)) { diff --git a/Marathon/Formats/Particle/ParticleTextureBank.cs b/Marathon/Formats/Particle/ParticleTextureBank.cs index dde9352b..b156d08b 100644 --- a/Marathon/Formats/Particle/ParticleTextureBank.cs +++ b/Marathon/Formats/Particle/ParticleTextureBank.cs @@ -87,7 +87,7 @@ public override void Write(Stream in_stream) var writer = new BINAWriter(in_stream, Endianness); writer.WriteSignature(_signature); - writer.WriteNullBytes(8); + writer.WriteZero(8); writer.Write(Textures.Count); writer.WriteStringFixedLength(Name, 0x20); diff --git a/Marathon/Formats/Placement/PropLibrary.cs b/Marathon/Formats/Placement/PropLibrary.cs index dc772829..1c3d3964 100644 --- a/Marathon/Formats/Placement/PropLibrary.cs +++ b/Marathon/Formats/Placement/PropLibrary.cs @@ -110,7 +110,7 @@ public override void Write(Stream in_stream) { var writer = new BINAWriter(in_stream, Endianness); - writer.WriteNullBytes(12); + writer.WriteZero(12); writer.WriteStringFixedLength(Name.Truncate(0x20), 0x20); writer.Write(Actors.Count); writer.Reserve("ActorTableOffset"); @@ -134,7 +134,7 @@ public override void Write(Stream in_stream) if (string.IsNullOrEmpty(actor.Persistent)) { - writer.WriteNullBytes(8); + writer.WriteZero(8); } else { diff --git a/Marathon/Formats/Placement/StageSet.cs b/Marathon/Formats/Placement/StageSet.cs index 9ccfcff5..5d07f25b 100644 --- a/Marathon/Formats/Placement/StageSet.cs +++ b/Marathon/Formats/Placement/StageSet.cs @@ -193,7 +193,7 @@ public override void Write(Stream in_stream) { var writer = new BINAWriter(in_stream, Endianness); - writer.WriteNullBytes(12); // Always null. + writer.WriteZero(12); // Always null. writer.WriteStringFixedLength(Name.Truncate(0x20), 0x20); writer.Write(Objects.Count); writer.Reserve("ObjectTableOffset"); @@ -201,7 +201,7 @@ public override void Write(Stream in_stream) if (Groups.Count <= 0) { - writer.Write(0); + writer.WriteZero(); } else { @@ -227,7 +227,7 @@ public override void Write(Stream in_stream) writer.WriteStringOffset(@object.Type); writer.WriteBytes([0x40, 0x00, 0x00]); writer.Write(@object.StartInactive); - writer.WriteNullBytes(12); + writer.WriteZero(12); writer.Write(@object.Position); writer.Write(@object.DrawDistance); writer.Write(@object.Rotation); @@ -235,7 +235,7 @@ public override void Write(Stream in_stream) if (@object.Parameters.Count <= 0) { - writer.Write(0); + writer.WriteZero(); } else { @@ -260,18 +260,18 @@ public override void Write(Stream in_stream) { case StageSetDataType.Boolean: writer.Write((bool)Objects[i].Parameters[j].Value ? 1 : 0); - writer.WriteNullBytes(12); + writer.WriteZero(12); break; case StageSetDataType.Int32: case StageSetDataType.Object: writer.Write((int)Objects[i].Parameters[j].Value); - writer.WriteNullBytes(12); + writer.WriteZero(12); break; case StageSetDataType.Single: writer.Write((float)Objects[i].Parameters[j].Value); - writer.WriteNullBytes(12); + writer.WriteZero(12); break; case StageSetDataType.String: @@ -287,7 +287,7 @@ public override void Write(Stream in_stream) } writer.Write(1); - writer.Write(0); + writer.WriteZero(); writer.Write(Objects[i].Parameters[j].Value.ToString().Length + 1); break; @@ -295,7 +295,7 @@ public override void Write(Stream in_stream) case StageSetDataType.Vector3: writer.Write((Vector3)Objects[i].Parameters[j].Value); - writer.WriteNullBytes(4); + writer.WriteZero(); break; default: @@ -328,7 +328,7 @@ public override void Write(Stream in_stream) if (group.Objects.Count <= 0) { - writer.Write(0); + writer.WriteZero(); } else { @@ -363,7 +363,7 @@ public override void Write(Stream in_stream) continue; writer.WriteReserved($"Object{i}Parameter{j}String", (uint)writer.Position - BINAHeader.Size); - writer.Write(0); + writer.WriteZero(); } } @@ -374,7 +374,7 @@ public override void Write(Stream in_stream) continue; writer.WriteReserved($"Group{i}Function", (uint)writer.Position - BINAHeader.Size); - writer.Write(0); + writer.WriteZero(); } writer.FinishWrite(); diff --git a/Marathon/Helpers/BinaryHelper.cs b/Marathon/Helpers/BinaryHelper.cs index 9f72521e..1eba2dec 100644 --- a/Marathon/Helpers/BinaryHelper.cs +++ b/Marathon/Helpers/BinaryHelper.cs @@ -63,7 +63,7 @@ public static T TransformByteArrayToManagedType(byte[] in_buffer) /// The data to swap. public static T SwapEndianness(T in_data) { - var bytes = new byte[Marshal.SizeOf(typeof(T))]; + var bytes = new byte[Marshal.SizeOf()]; Marshal.StructureToPtr(in_data, Marshal.UnsafeAddrOfPinnedArrayElement(bytes, 0), false); Array.Reverse(bytes); @@ -78,7 +78,7 @@ public static T SwapEndianness(T in_data) /// The address to start the left-most column at. public static void PrintBytes(byte[] in_data, uint in_baseAddr = 0) { - var oldColour = Console.ForegroundColor; + var oldColor = Console.ForegroundColor; Console.ForegroundColor = ConsoleColor.DarkGray; Console.Write("Address "); @@ -92,13 +92,13 @@ public static void PrintBytes(byte[] in_data, uint in_baseAddr = 0) Console.Write($"{(((i + in_baseAddr) % 16 + 16) % 16):X}"); Console.WriteLine(); - Console.ForegroundColor = oldColour; + Console.ForegroundColor = oldColor; for (int i = 0; i < in_data.Length; i += 16) { Console.ForegroundColor = ConsoleColor.DarkGray; Console.Write($"{(in_baseAddr + i):X8} "); - Console.ForegroundColor = oldColour; + Console.ForegroundColor = oldColor; // Print bytes. for (int j = 0; j < 16; j++) @@ -113,7 +113,7 @@ public static void PrintBytes(byte[] in_data, uint in_baseAddr = 0) { Console.ForegroundColor = ConsoleColor.Red; Console.Write("?? "); - Console.ForegroundColor = oldColour; + Console.ForegroundColor = oldColor; } } @@ -131,7 +131,7 @@ public static void PrintBytes(byte[] in_data, uint in_baseAddr = 0) { Console.ForegroundColor = ConsoleColor.Red; Console.Write("?"); - Console.ForegroundColor = oldColour; + Console.ForegroundColor = oldColor; } } diff --git a/Marathon/Helpers/Logger/ConsoleLogger.cs b/Marathon/Helpers/Logger/ConsoleLogger.cs index 2bc90d7a..084951f1 100644 --- a/Marathon/Helpers/Logger/ConsoleLogger.cs +++ b/Marathon/Helpers/Logger/ConsoleLogger.cs @@ -6,7 +6,7 @@ public class ConsoleLogger : ILogger { public void Log(string in_message, LogLevel in_logLevel, string in_caller) { - var oldColour = Console.ForegroundColor; + var oldColor = Console.ForegroundColor; switch (in_logLevel) { @@ -25,7 +25,7 @@ public void Log(string in_message, LogLevel in_logLevel, string in_caller) Console.WriteLine(string.IsNullOrEmpty(in_caller) ? in_message : $"[{in_caller}] {in_message}"); - Console.ForegroundColor = oldColour; + Console.ForegroundColor = oldColor; } } } diff --git a/Marathon/IO/BinaryObjectReaderEx.cs b/Marathon/IO/BinaryObjectReaderEx.cs index c72b7473..a4e33d6f 100644 --- a/Marathon/IO/BinaryObjectReaderEx.cs +++ b/Marathon/IO/BinaryObjectReaderEx.cs @@ -1,21 +1,115 @@ using Amicitia.IO; using Amicitia.IO.Binary; using Amicitia.IO.Streams; +using System; +using System.Collections.Generic; using System.IO; +using System.Runtime.CompilerServices; using System.Text; namespace Marathon.IO { public class BinaryObjectReaderEx : BinaryObjectReader { + private Stack _offsetOrigins = []; + + public long OffsetOrigin => _offsetOrigins.Peek(); + public BinaryObjectReaderEx(string in_filePath, Endianness in_endianness, Encoding in_encoding) - : base(in_filePath, in_endianness, in_encoding) { } + : base(in_filePath, in_endianness, in_encoding) + { + Init(); + } public BinaryObjectReaderEx(string in_filePath, FileStreamingMode in_fileStreamingMode, Endianness in_endianness, Encoding in_encoding, int in_bufferSize = 1048576) - : base(in_filePath, in_fileStreamingMode, in_endianness, in_encoding, in_bufferSize) { } + : base(in_filePath, in_fileStreamingMode, in_endianness, in_encoding, in_bufferSize) + { + Init(); + } public BinaryObjectReaderEx(Stream in_stream, StreamOwnership in_streamOwnership, Endianness in_endianness, Encoding in_encoding = null, string in_fileName = null, int in_blockSize = 1048576) - : base(in_stream, in_streamOwnership, in_endianness, in_encoding, in_fileName, in_blockSize) { } + : base(in_stream, in_streamOwnership, in_endianness, in_encoding, in_fileName, in_blockSize) + { + Init(); + } + + public void Init() + { + _offsetOrigins.Push(0); + } + + public bool ReadBoolean() where T : unmanaged + { + return (ulong)Convert.ChangeType(Read(), typeof(ulong)) != 0; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public T ReadObjectEx() where T : IBinarySerializableEx, new() + { + var obj = new T(); + ReadObjectEx(ref obj); + return obj; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ReadObjectEx(IBinarySerializableEx in_obj) + { + ReadObjectEx(ref in_obj); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ReadObjectEx(ref T in_rObj) where T : IBinarySerializableEx + { + var prefix = Position; + in_rObj.Read(this); + var postfix = Position; + + MaybePopulateSourceInfo(in_rObj, prefix, postfix); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public T ReadObjectEx(TContext in_context) where T : IBinarySerializableEx, new() + { + var obj = new T(); + ReadObjectEx(ref obj, in_context); + return obj; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ReadObjectEx(ref T in_rObj, TContext in_context) where T : IBinarySerializableEx + { + var prefix = Position; + in_rObj.Read(this, in_context); + var postfix = Position; + + MaybePopulateSourceInfo(in_rObj, prefix, postfix); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void MaybePopulateSourceInfo(IBinarySerializableEx in_value, long in_startOffset, long in_endOffset) + { + if (PopulateBinarySourceInfo && in_value is IBinarySourceInfo binarySourceInfo) + binarySourceInfo.BinarySourceInfo = new BinarySourceInfo(FilePath, in_startOffset, in_endOffset, (int)(in_endOffset - in_startOffset), Endianness); + } + + public long PushOffsetOrigin(long in_offset) + { + _offsetOrigins.Push(in_offset); + return in_offset; + } + + public long PopOffsetOrigin() + { + return _offsetOrigins.Pop(); + } + + public long CalculateOffset(long in_offset, OffsetType in_offsetType = OffsetType.Absolute) + { + if (in_offsetType == OffsetType.Relative) + return in_offset - OffsetOrigin; + + return in_offset + OffsetOrigin; + } public virtual void JumpAhead(long in_offset) { diff --git a/Marathon/IO/BinaryObjectWriterEx.cs b/Marathon/IO/BinaryObjectWriterEx.cs index 0549fa7f..591ccc6d 100644 --- a/Marathon/IO/BinaryObjectWriterEx.cs +++ b/Marathon/IO/BinaryObjectWriterEx.cs @@ -6,22 +6,47 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using System.Text; namespace Marathon.IO { public class BinaryObjectWriterEx : BinaryObjectWriter { + private Stack _offsetOrigins = []; + + public long OffsetOrigin => _offsetOrigins.Peek(); + public Dictionary Offsets { get; } = []; public BinaryObjectWriterEx(string in_filePath, Endianness in_endianness, Encoding in_encoding = null) - : base(in_filePath, in_endianness, in_encoding) { } + : base(in_filePath, in_endianness, in_encoding) + { + Init(); + } public BinaryObjectWriterEx(string in_filePath, FileStreamingMode in_fileStreamingMode, Endianness in_endianness, Encoding in_encoding = null, int in_bufferSize = 1048576) - : base(in_filePath, in_fileStreamingMode, in_endianness, in_encoding, in_bufferSize) { } + : base(in_filePath, in_fileStreamingMode, in_endianness, in_encoding, in_bufferSize) + { + Init(); + } public BinaryObjectWriterEx(Stream in_stream, StreamOwnership in_streamOwnership, Endianness in_endianness, Encoding in_encoding = null, string in_fileName = null, int in_blockSize = 1048576) - : base(in_stream, in_streamOwnership, in_endianness, in_encoding, in_fileName, in_blockSize) { } + : base(in_stream, in_streamOwnership, in_endianness, in_encoding, in_fileName, in_blockSize) + { + Init(); + } + + public void Init() + { + _offsetOrigins.Push(0); + } + + public void WriteBoolean(bool in_value) where T : unmanaged + { + Write((T)Convert.ChangeType(in_value ? 1 : 0, typeof(T))); + } /// /// Reserves space at the current position for writing to later using WriteReserved. @@ -32,15 +57,9 @@ public BinaryObjectWriterEx(Stream in_stream, StreamOwnership in_streamOwnership public long Reserve(string in_name, long in_offset, int in_size) { // Create padding. - this.WriteNullBytes(in_size); + this.WriteZero(in_size); - if (Offsets.ContainsKey(in_name)) - { - Offsets[in_name] = in_offset; - return in_offset; - } - - Offsets.Add(in_name, in_offset); + AddOffset(in_name, in_offset); return in_offset; } @@ -61,9 +80,9 @@ public long Reserve(string in_name, int in_size = 4) /// The type to write. /// The name of the reserved offset. /// The offset to reserve. - public unsafe T Reserve(string in_name, long in_offset) where T : unmanaged + public T Reserve(string in_name, long in_offset) where T : unmanaged { - return (T)Convert.ChangeType(Reserve(in_name, in_offset, sizeof(T)), typeof(T)); + return (T)Convert.ChangeType(Reserve(in_name, in_offset, Marshal.SizeOf()), typeof(T)); } /// @@ -71,7 +90,7 @@ public unsafe T Reserve(string in_name, long in_offset) where T : unmanaged /// /// The type to write. /// The name of the reserved offset. - public unsafe T Reserve(string in_name) where T : unmanaged + public T Reserve(string in_name) where T : unmanaged { return (T)Convert.ChangeType(Reserve(in_name, Position), typeof(T)); } @@ -85,10 +104,10 @@ public unsafe T Reserve(string in_name) where T : unmanaged public long Reserve(long in_offset, int in_size, bool in_isLocal = false) { // Create padding. - this.WriteNullBytes(in_size); + this.WriteZero(in_size); if (!in_isLocal) - Offsets.Add(Guid.NewGuid().ToString("B"), in_offset); + AddOffset(in_offset); return in_offset; } @@ -109,9 +128,9 @@ public long Reserve(int in_size = 4, bool in_isLocal = false) /// The type to write. /// The offset to reserve. /// Determines whether the reserved offset should be added to the relocation table. - public unsafe T Reserve(long in_offset, bool in_isLocal = false) where T : unmanaged + public long Reserve(long in_offset, bool in_isLocal = false) where T : unmanaged { - return (T)Convert.ChangeType(Reserve(in_offset, sizeof(T), in_isLocal), typeof(T)); + return Reserve(in_offset, Marshal.SizeOf(), in_isLocal); } /// @@ -119,9 +138,9 @@ public unsafe T Reserve(long in_offset, bool in_isLocal = false) where T : un /// /// The type to write. /// Determines whether the reserved offset should be added to the relocation table. - public unsafe T Reserve(bool in_isLocal = false) where T : unmanaged + public long Reserve(bool in_isLocal = false) where T : unmanaged { - return (T)Convert.ChangeType(Reserve(Position, in_isLocal), typeof(T)); + return Reserve(Position, in_isLocal); } /// @@ -131,7 +150,7 @@ public unsafe T Reserve(bool in_isLocal = false) where T : unmanaged /// The offset to write to. /// The value to write. /// Determines whether the reserved offset should be removed from the relocation table. - public virtual void WriteReserved(long in_offset, T in_value, bool in_removeAfterWrite = true) where T : unmanaged + public virtual void WriteReserved(long in_offset, T in_value, bool in_removeAfterWrite = false) where T : unmanaged { this.WriteAtOffset(in_offset, () => Write(in_value)); @@ -141,10 +160,7 @@ public virtual void WriteReserved(long in_offset, T in_value, bool in_removeA if (!Offsets.ContainsValue(in_offset)) return; - var offsets = Offsets.Where(x => x.Value == in_offset); - - for (int i = 0; i < offsets.Count(); i++) - Offsets.Remove(offsets.ElementAt(i).Key); + RemoveOffset(in_offset); } /// @@ -154,7 +170,7 @@ public virtual void WriteReserved(long in_offset, T in_value, bool in_removeA /// The name of the offset to write to. /// The value to write. /// Determines whether the reserved offset should be removed from the relocation table. - public virtual void WriteReserved(string in_name, T in_value, bool in_removeAfterWrite = true) where T : unmanaged + public virtual void WriteReserved(string in_name, T in_value, bool in_removeAfterWrite = false) where T : unmanaged { if (!Offsets.TryGetValue(in_name, out var out_offset)) return; @@ -164,9 +180,50 @@ public virtual void WriteReserved(string in_name, T in_value, bool in_removeA if (!in_removeAfterWrite) return; + RemoveOffset(in_name); + } + + public long AddOffset(string in_name, long in_offset) + { + if (Offsets.ContainsKey(in_name)) + { + Offsets[in_name] = in_offset; + return in_offset; + } + + Offsets.Add(in_name, in_offset); + + return in_offset; + } + + public long AddOffset(long in_offset) + { + return AddOffset(Guid.NewGuid().ToString("B"), in_offset); + } + + public long AddOffset() + { + return AddOffset(Position); + } + + public void RemoveOffset(string in_name) + { Offsets.Remove(in_name); } + public void RemoveOffset(long in_offset) + { + var offsets = Offsets.Where(x => x.Value == in_offset); + + for (int i = 0; i < offsets.Count(); i++) + Offsets.Remove(offsets.ElementAt(i).Key); + } + + public void RemoveOffset() + { + RemoveOffset(Position); + } + /// /// Writes a value and stores its offset in the offset list. /// @@ -174,12 +231,42 @@ public virtual void WriteReserved(string in_name, T in_value, bool in_removeA /// The value to write. public long WriteOffset(T in_value) where T : unmanaged { - var pos = Position; + var offset = Reserve(); + + WriteReserved(offset, in_value, false); + + return offset; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteObjectEx(T in_value) where T : IBinarySerializableEx + { + in_value.Write(this); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteObjectEx(T in_value, TContext in_context) where T : IBinarySerializableEx + { + in_value.Write(this, in_context); + } + + public long PushOffsetOrigin(long in_offset) + { + _offsetOrigins.Push(in_offset); + return in_offset; + } - Offsets.Add(Guid.NewGuid().ToString("B"), pos); - Write(in_value); + public long PopOffsetOrigin() + { + return _offsetOrigins.Pop(); + } + + public long CalculateOffset(long in_offset, OffsetType in_offsetType = OffsetType.Absolute) + { + if (in_offsetType == OffsetType.Relative) + return in_offset - OffsetOrigin; - return pos; + return in_offset + OffsetOrigin; } public void JumpAhead(long in_offset) diff --git a/Marathon/IO/Extensions/WriterExtensions.cs b/Marathon/IO/Extensions/WriterExtensions.cs index 5674bb26..886c58c7 100644 --- a/Marathon/IO/Extensions/WriterExtensions.cs +++ b/Marathon/IO/Extensions/WriterExtensions.cs @@ -2,6 +2,7 @@ using Amicitia.IO.Binary; using System; using System.IO; +using System.Runtime.InteropServices; namespace Marathon.IO.Extensions { @@ -12,9 +13,14 @@ public static void WriteSignature(this BinaryObjectWriter in_writer, string in_s in_writer.WriteStringFixedLength(in_writer.Encoding, in_signature, in_signature.Length); } - public static void WriteNullBytes(this BinaryObjectWriter in_writer, int in_count) + public static void WriteZero(this BinaryObjectWriter in_writer, int in_count) where T : unmanaged { - in_writer.WriteBytes(new byte[in_count]); + in_writer.WriteBytes(new byte[in_count * Marshal.SizeOf()]); + } + + public static void WriteZero(this BinaryObjectWriter in_writer) where T : unmanaged + { + in_writer.WriteZero(Marshal.SizeOf()); } public static void WriteUInt24(this BinaryObjectWriter in_writer, uint in_value) @@ -51,7 +57,7 @@ public static void WriteStringFixedLength(this BinaryObjectWriter in_writer, str { if (in_str == null) { - in_writer.WriteNullBytes(in_length); + in_writer.WriteZero(in_length); return; } @@ -69,7 +75,7 @@ public static void WriteAtOffset(this BinaryObjectWriter in_writer, long in_offs public static void Align(this BinaryObjectWriter in_writer, int in_alignment) { - in_writer.WriteNullBytes(AlignmentHelper.GetAlignedDifference(in_writer.Position, in_alignment)); + in_writer.WriteZero(AlignmentHelper.GetAlignedDifference(in_writer.Position, in_alignment)); } } } diff --git a/Marathon/IO/IBinarySerializableEx.cs b/Marathon/IO/IBinarySerializableEx.cs new file mode 100644 index 00000000..a496e532 --- /dev/null +++ b/Marathon/IO/IBinarySerializableEx.cs @@ -0,0 +1,28 @@ +using Amicitia.IO.Binary; + +namespace Marathon.IO +{ + public interface IBinarySerializableEx : IBaseBinarySerializable + { + void Read(BinaryObjectReaderEx in_reader); + + void Write(BinaryObjectWriterEx in_writer); + } + + public interface IBinarySerializableEx : IBinarySerializableEx, IBaseBinarySerializable + { + void IBinarySerializableEx.Read(BinaryObjectReaderEx in_reader) + { + Read(in_reader, default); + } + + void IBinarySerializableEx.Write(BinaryObjectWriterEx in_writer) + { + Write(in_writer, default); + } + + void Read(BinaryObjectReaderEx in_reader, TContext in_context); + + void Write(BinaryObjectWriterEx in_writer, TContext in_context); + } +} diff --git a/Marathon/IO/OffsetType.cs b/Marathon/IO/OffsetType.cs new file mode 100644 index 00000000..ca9e4289 --- /dev/null +++ b/Marathon/IO/OffsetType.cs @@ -0,0 +1,8 @@ +namespace Marathon.IO +{ + public enum OffsetType + { + Absolute, + Relative + } +} diff --git a/Marathon/IO/Types/BINA/BINAHeader.cs b/Marathon/IO/Types/BINA/BINAHeader.cs index e80f7d59..bc11633b 100644 --- a/Marathon/IO/Types/BINA/BINAHeader.cs +++ b/Marathon/IO/Types/BINA/BINAHeader.cs @@ -19,9 +19,9 @@ public class BINAHeader private const string _signature = "BINA"; - public long HeaderOffset { get; set; } + public long Offset { get; set; } - public uint ResourceSize { get; set; } + public uint Length { get; set; } public uint RelocTableOffset { get; set; } @@ -50,7 +50,7 @@ public BINAHeader(BinaryObjectReaderEx in_reader) public void Read(BinaryObjectReaderEx in_reader) { - HeaderOffset = in_reader.Position; + Offset = in_reader.Position; // Jump to signature. in_reader.JumpAhead(0x14); @@ -80,9 +80,9 @@ public void Read(BinaryObjectReaderEx in_reader) Version = out_version; // Jump to the beginning of the header to read it with the correct endianness. - in_reader.JumpTo(HeaderOffset); + in_reader.JumpTo(Offset); - ResourceSize = in_reader.Read(); + Length = in_reader.Read(); RelocTableOffset = in_reader.Read(); RelocTableLength = in_reader.Read(); @@ -116,22 +116,22 @@ public void Write(BinaryObjectWriterEx in_writer) { IsBigEndian = in_writer.Endianness == Endianness.Big; - in_writer.Write(ResourceSize); + in_writer.Write(Length); in_writer.Write(RelocTableOffset); in_writer.Write(RelocTableLength); // TODO: unknown - possibly padding? - in_writer.Write(0); + in_writer.WriteZero(); // TODO: unknown - possibly a flag? - in_writer.Write(0); + in_writer.WriteZero(); in_writer.Write(HasFooterMagic ? (ushort)1 : (ushort)0); var version = Version.ToString(); if (version.Length < 3) - in_writer.WriteNullBytes(3 - version.Length); + in_writer.WriteZero(3 - version.Length); in_writer.WriteStringFixedLength(Encoding.UTF8, version, version.Length); in_writer.Write(IsBigEndian ? _endianFlagBig : _endianFlagLittle); @@ -142,11 +142,11 @@ public void Write(BinaryObjectWriterEx in_writer) } else { - in_writer.Write(0); + in_writer.WriteZero(); } // TODO: unknown. - in_writer.Write(0); + in_writer.WriteZero(); } } } diff --git a/Marathon/IO/Types/BINA/BINAReader.cs b/Marathon/IO/Types/BINA/BINAReader.cs index 6c4a2f92..7512f487 100644 --- a/Marathon/IO/Types/BINA/BINAReader.cs +++ b/Marathon/IO/Types/BINA/BINAReader.cs @@ -8,16 +8,26 @@ public class BINAReader : BinaryObjectReaderEx { public BINAHeader Header { get; private set; } - public long Offset { get; private set; } - public BINAReader(Stream in_stream, long in_offset = 0, Endianness in_endianness = Endianness.Big) : base(in_stream, StreamOwnership.Retain, in_endianness, EncodingFactory.ShiftJIS) { - Offset = in_offset; - - JumpTo(Offset); + JumpTo(in_offset); Header = new BINAHeader(this); + + PushOffsetOrigin(Header.Offset + BINAHeader.Size); + } + + public BINARelocationTable ReadRelocationTable() + { + var relocTable = new BINARelocationTable(Header.Offset); + var pos = Position; + + JumpTo(CalculateOffset(Header.RelocTableOffset)); + relocTable.Read(this, Header.RelocTableLength); + JumpTo(pos); + + return relocTable; } } } diff --git a/Marathon/IO/Types/BINA/BINARelocationTable.cs b/Marathon/IO/Types/BINA/BINARelocationTable.cs new file mode 100644 index 00000000..97818c9b --- /dev/null +++ b/Marathon/IO/Types/BINA/BINARelocationTable.cs @@ -0,0 +1,102 @@ +using Amicitia.IO.Binary; +using Marathon.IO.Extensions; + +namespace Marathon.IO.Types.BINA +{ + public class BINARelocationTable(long in_offset) : RelocationTable(in_offset) + { + public override long Read(BinaryObjectReaderEx in_reader, long in_length) + { + var lastOffset = Offset; + var end = in_reader.Position + in_length; + + Clear(); + + while (in_reader.Position < in_reader.Length && in_reader.Position < end) + { + var b = in_reader.ReadByte(); + var type = (byte)(b & 0xC0); + var offset = (byte)(b & 0x3F); + + if (type == (byte)BINAOffsetEncoding.SixBit) + { + offset <<= 2; + + Add((uint)(offset + lastOffset)); + } + else if (type == (byte)BINAOffsetEncoding.FourteenBit) + { + var remainder = in_reader.ReadByte(); + var decoded = (ushort)(((offset << 8) | remainder) << 2); + + Add((uint)(decoded + lastOffset)); + } + else if (type == (byte)BINAOffsetEncoding.ThirtyBit) + { + var remainder = in_reader.ReadBytes(3); + var decoded = (uint)(((offset << 24) | (remainder[0] << 16) | (remainder[1] << 8) | remainder[2]) << 2); + + Add((uint)(decoded + lastOffset)); + } + else + { + break; + } + + lastOffset = this[Count - 1]; + } + + return lastOffset; + } + + public override long Write(BinaryObjectWriterEx in_writer) + { + var pos = in_writer.Position; + var lastOffset = BINAHeader.Size + Offset; + + foreach (var offset in this) + { + var offsetBits = (offset - lastOffset) >> 2; + + if (offsetBits > 0x3FFF) + { + in_writer.WriteBig((uint)(((byte)BINAOffsetEncoding.ThirtyBit << 24) | offsetBits)); + } + else if (offsetBits > 0x3F) + { + in_writer.WriteBig((ushort)(((byte)BINAOffsetEncoding.FourteenBit << 8) | offsetBits)); + } + else + { + in_writer.WriteBig((byte)((byte)BINAOffsetEncoding.SixBit | offsetBits)); + } + + lastOffset = offset; + } + + in_writer.Align(4); + + Length = in_writer.Position - pos; + + return pos; + } + } + + public enum BINAOffsetEncoding : byte + { + /// + /// The offset is stored in the remaining six bits after the type bits. + /// + SixBit = 0x40, + + /// + /// The offset is stored in the remaining six bits after the type bits, including an extra byte. + /// + FourteenBit = 0x80, + + /// + /// The offset is stored in the remaining six bits after the type bits, including an extra three bytes. + /// + ThirtyBit = 0xC0 + } +} diff --git a/Marathon/IO/Types/BINA/BINAWriter.cs b/Marathon/IO/Types/BINA/BINAWriter.cs index 8d750785..f962457c 100644 --- a/Marathon/IO/Types/BINA/BINAWriter.cs +++ b/Marathon/IO/Types/BINA/BINAWriter.cs @@ -19,7 +19,18 @@ public BINAWriter(Stream in_stream, Endianness in_endianness = Endianness.Big) : base(in_stream, StreamOwnership.Retain, in_endianness, EncodingFactory.ShiftJIS) { // Reserve header chunk. - this.WriteNullBytes(BINAHeader.Size); + this.WriteZero(BINAHeader.Size); + } + + public BINAWriter(Stream in_stream, long in_offset = 0, Endianness in_endianness = Endianness.Big) + : base(in_stream, StreamOwnership.Retain, in_endianness, EncodingFactory.ShiftJIS) + { + Header.Offset = in_offset; + + JumpTo(Header.Offset); + + // Reserve header chunk. + this.WriteZero(BINAHeader.Size); } public long WriteStringOffset(string in_str = null, bool in_writeNullPtrOnEmptyString = true, int in_fieldLength = 4) @@ -28,7 +39,7 @@ public long WriteStringOffset(string in_str = null, bool in_writeNullPtrOnEmptyS if (string.IsNullOrEmpty(in_str) && in_writeNullPtrOnEmptyString) { - this.WriteNullBytes(in_fieldLength); + this.WriteZero(in_fieldLength); return reserved; } @@ -55,7 +66,7 @@ public long WriteStringOffset(string in_str = null, bool in_writeNullPtrOnEmptyS return reserved; } - private void WriteStringPool() + public void WriteStringPool() { foreach (var entry in StringPoolEntries) { @@ -69,53 +80,32 @@ private void WriteStringPool() this.Align(4); } - private void WriteFooter() + public void WriteFooter() { - var offsetTablePos = WriteRelocTable(); + var relocTablePos = WriteRelocationTable(); - Header.RelocTableOffset = (uint)(offsetTablePos - BINAHeader.Size); - Header.RelocTableLength = (uint)(Position - offsetTablePos); + Header.RelocTableOffset = (uint)(relocTablePos - BINAHeader.Size - Header.Offset); + Header.RelocTableLength = (uint)(Position - relocTablePos); if (Header.HasFooterMagic) WriteFooterMagic(); - Header.ResourceSize = (uint)Position; + Header.Length = (uint)(Position - Header.Offset); } - private long WriteRelocTable() + public long WriteRelocationTable() { - var pos = Position; - var lastOffset = (long)BINAHeader.Size; - - foreach (var offset in Offsets) - { - var offsetBits = (offset.Value - lastOffset) >> 2; - - if (offsetBits > 0x3FFF) - { - WriteBig((uint)(((byte)BINAOffsetEncoding.ThirtyBit << 24) | offsetBits)); - } - else if (offsetBits > 0x3F) - { - WriteBig((ushort)(((byte)BINAOffsetEncoding.FourteenBit << 8) | offsetBits)); - } - else - { - WriteBig((byte)((byte)BINAOffsetEncoding.SixBit | offsetBits)); - } + var relocTable = new BINARelocationTable(Header.Offset); - lastOffset = offset.Value; - } + relocTable.AddOffsets(Offsets.Values); - this.Align(4); - - return pos; + return relocTable.Write(this); } - private void WriteFooterMagic() + public void WriteFooterMagic() { Write(0x10); // TODO: unknown. - this.WriteNullBytes(4); + this.WriteZero(); WriteStringNullTerminated(Encoding.UTF8, _footerSignature); } @@ -124,28 +114,10 @@ public void FinishWrite() WriteStringPool(); WriteFooter(); - JumpTo(Header.HeaderOffset); + JumpTo(Header.Offset); Header.Write(this); } - - /// - /// Alias of that defaults to false. - /// All fields must remain present for the relocation table to be written last. - /// - public override void WriteReserved(long in_offset, T in_value, bool in_removeAfterWrite = false) - { - base.WriteReserved(in_offset, in_value, in_removeAfterWrite); - } - - /// - /// Alias of that defaults to false. - /// All fields must remain present for the relocation table to be written last. - /// - public override void WriteReserved(string in_name, T in_value, bool in_removeAfterWrite = false) - { - base.WriteReserved(in_name, in_value, in_removeAfterWrite); - } } public class StringPoolEntry(string in_str) @@ -160,22 +132,4 @@ public class StringPoolEntry(string in_str) /// public string Data { get; set; } = in_str; } - - public enum BINAOffsetEncoding : byte - { - /// - /// The offset is stored in the remaining six bits after the type bits. - /// - SixBit = 0x40, - - /// - /// The offset is stored in the remaining six bits after the type bits, including an extra byte. - /// - FourteenBit = 0x80, - - /// - /// The offset is stored in the remaining six bits after the type bits, including an extra three bytes. - /// - ThirtyBit = 0xC0 - } } diff --git a/Marathon/IO/Types/CRandom.cs b/Marathon/IO/Types/CRandom.cs new file mode 100644 index 00000000..267621af --- /dev/null +++ b/Marathon/IO/Types/CRandom.cs @@ -0,0 +1,18 @@ +namespace Marathon.IO.Types +{ + public class CRandom + { + private static ulong _next; + + public static int Rand() + { + _next = _next * 1103515245U + 12345U; + return (int)((_next / 65536U) % 32768U); + } + + public static void SRand(uint in_seed) + { + _next = in_seed; + } + } +} diff --git a/Marathon/IO/Types/Colour.cs b/Marathon/IO/Types/Color.cs similarity index 79% rename from Marathon/IO/Types/Colour.cs rename to Marathon/IO/Types/Color.cs index 54f38fd0..d2c596aa 100644 --- a/Marathon/IO/Types/Colour.cs +++ b/Marathon/IO/Types/Color.cs @@ -3,7 +3,7 @@ namespace Marathon.IO.Types { - public struct Colour : IBinarySerializable where TData : unmanaged where TFormat : IColourFormat + public struct Color : IBinarySerializable where TData : unmanaged where TFormat : IColorFormat { public TData R { get; set; } @@ -13,9 +13,9 @@ public struct Colour : IBinarySerializable where TData : unmanag public TData A { get; set; } - public Colour() { } + public Color() { } - public Colour(TData in_r, TData in_g, TData in_b, TData in_a) + public Color(TData in_r, TData in_g, TData in_b, TData in_a) { R = in_r; G = in_g; @@ -73,28 +73,28 @@ public void Write(BinaryObjectWriter in_writer) } } - public readonly Colour Flip() + public readonly Color Flip() { - return new Colour(A, B, G, R); + return new Color(A, B, G, R); } public override bool Equals(object in_obj) { - if (in_obj is not Colour out_colour) + if (in_obj is not Color out_color) return false; - return EqualityComparer.Default.Equals(R, out_colour.R) && - EqualityComparer.Default.Equals(G, out_colour.G) && - EqualityComparer.Default.Equals(B, out_colour.B) && - EqualityComparer.Default.Equals(A, out_colour.A); + return EqualityComparer.Default.Equals(R, out_color.R) && + EqualityComparer.Default.Equals(G, out_color.G) && + EqualityComparer.Default.Equals(B, out_color.B) && + EqualityComparer.Default.Equals(A, out_color.A); } } - public struct RGBA : IColourFormat { } + public struct RGBA : IColorFormat { } - public struct ARGB : IColourFormat { } + public struct ARGB : IColorFormat { } - public struct BGRA : IColourFormat { } + public struct BGRA : IColorFormat { } - public interface IColourFormat { } + public interface IColorFormat { } } diff --git a/Marathon/IO/Types/Distance.cs b/Marathon/IO/Types/Distance.cs new file mode 100644 index 00000000..8d9036b5 --- /dev/null +++ b/Marathon/IO/Types/Distance.cs @@ -0,0 +1,8 @@ +namespace Marathon.IO.Types +{ + public struct Distance + { + public T Min; + public T Max; + } +} diff --git a/Marathon/IO/Types/FourCC.cs b/Marathon/IO/Types/FourCC.cs index 9e05303b..c4d3cceb 100644 --- a/Marathon/IO/Types/FourCC.cs +++ b/Marathon/IO/Types/FourCC.cs @@ -20,7 +20,7 @@ public FourCC(int in_data, Endianness in_endianness = Endianness.Big) : this(in_ Data = (uint)in_data; } - public FourCC(string in_signature, Endianness in_endianness = Endianness.Big) : this(in_endianness) + public FourCC(string in_signature) : this(Endianness.Little) { if (in_signature.Length > 4) throw new ArgumentException("The provided signature is longer than four characters."); @@ -30,8 +30,10 @@ public FourCC(string in_signature, Endianness in_endianness = Endianness.Big) : public void Read(BinaryObjectReader in_reader) { + var oldEndianness = in_reader.Endianness; + in_reader.Endianness = Endianness; Data = in_reader.Read(); - Endianness = in_reader.Endianness; + in_reader.Endianness = oldEndianness; } public void Write(BinaryObjectWriter in_writer) diff --git a/Marathon/IO/Types/Rectangle.cs b/Marathon/IO/Types/Rectangle.cs new file mode 100644 index 00000000..59ae96e2 --- /dev/null +++ b/Marathon/IO/Types/Rectangle.cs @@ -0,0 +1,10 @@ +using System.Numerics; + +namespace Marathon.IO.Types +{ + public struct Rectangle + { + public Vector2 Min; + public Vector2 Max; + } +} diff --git a/Marathon/IO/Types/RelocationTable.cs b/Marathon/IO/Types/RelocationTable.cs new file mode 100644 index 00000000..fa233184 --- /dev/null +++ b/Marathon/IO/Types/RelocationTable.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Marathon.IO.Types +{ + public class RelocationTable : List + { + public long Offset { get; set; } + + public long Length { get; set; } + + public RelocationTable() { } + + public RelocationTable(long in_offset) + { + Offset = in_offset; + } + + public virtual long Read(BinaryObjectReaderEx in_reader, long in_length) + { + throw new NotImplementedException(); + } + + public virtual long Write(BinaryObjectWriterEx in_writer) + { + throw new NotImplementedException(); + } + + public void AddOffsets(IEnumerable in_collection) + { + AddRange(in_collection.Select(x => Convert.ChangeType(x, typeof(TOffsetType))).Cast()); + } + } +} diff --git a/README.md b/README.md index 03f502c7..63f4c111 100644 --- a/README.md +++ b/README.md @@ -14,8 +14,10 @@ See the [Building](https://github.com/hyperbx/Marathon/wiki/Building) page on the wiki. # Supported +- Acroarts + - [Acroarts Resource (`*.mab`)](https://github.com/hyperbx/Marathon/blob/main/Marathon/Formats/Acroarts/AckResource.cs) - Archive - - [Arc File (`*.arc`)](https://github.com/hyperbx/Marathon/blob/main/Marathon/Formats/Archive/U8Archive.cs) + - [Arc File (`*.arc`)](https://github.com/hyperbx/Marathon/blob/main/Marathon/Formats/Archive/ArcFile.cs) - [DirectDraw Map (`*.ddm`)](https://github.com/hyperbx/Marathon/blob/main/Marathon/Formats/Archive/DirectDrawMap.cs) - Audio - [Sound Bank (`*.sbk`)](https://github.com/hyperbx/Marathon/blob/main/Marathon/Formats/Audio/SoundBank.cs) @@ -88,9 +90,6 @@ The `*.fxo` format is for compiled DirectX shaders. There are no plans for Marat ### Havok Binary The `*.hkx` format is part of the Havok physics engine, specifically Havok 3.3.0-b2 for this game. There are no plans for Marathon to support this. -### Acroarts Binary -The `*.mab` format is part of SEGA's Acroarts middleware. It's used for miscellaneous event data for particle effects and timing with various cutscene elements (e.g. subtitles, models, etc). - ### Motion Base Information The `*.mbi` format is a plaintext file format containing node definitions for skeletons. This format hasn't been researched, but the data it stores is all clearly labelled by the internal tool that exported it.