using Microsoft.Xna.Framework; using System; using System.IO; using System.Linq; using System.Runtime.InteropServices; namespace OpenVIII.Core.World { /// /// Rail.obj is a file that contains waypoints and stops for trains including sequences /// internal class rail { private const int RAIL_BLOCK_SIZE = 2048; private const int BLOCK_HEADER_SIZE = 12; [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 8)] private struct RailEntry { public byte cKeypoints; public byte unk; public ushort unk2; public uint trainStop1; public uint trainStop2; public Keypoint[] keypoints; public Keypoint TrainStop1 => keypoints[trainStop1]; public Keypoint TrainStop2 => keypoints[trainStop2]; } /// /// to reverse, but probably should be finally changed to vec4- it's normal vector, but /// relative to world coordinates of vanilla world map /// [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 16)] private struct Keypoint { public int x; public int y; private int z; public int padd; public int Z => -z; } private RailEntry[] railEntries; public rail(byte[] buffer) { int railEntries = buffer.Length / RAIL_BLOCK_SIZE; this.railEntries = new RailEntry[railEntries]; MemoryStream ms = null; using (BinaryReader br = new BinaryReader(ms = new MemoryStream(buffer))) { for (int i = 0; i < railEntries; i++) this.railEntries[i] = ParseBlock(br.ReadBytes(2048)); ms = null; } } private RailEntry ParseBlock(byte[] block) { RailEntry entry = new RailEntry() { cKeypoints = block[0], unk = block[1], unk2 = BitConverter.ToUInt16(block, 2), trainStop1 = BitConverter.ToUInt32(block, 4), trainStop2 = BitConverter.ToUInt32(block, 8) }; entry.keypoints = new Keypoint[entry.cKeypoints]; for (int i = 0; i < entry.cKeypoints; i++) entry.keypoints[i] = Extended.ByteArrayToStructure(block.Skip(BLOCK_HEADER_SIZE + (i * 16)).Take(16).ToArray()); return entry; } /// /// Gets count of all keypoints associated with provided trackId /// /// /// public int GetTrainTrackFrameCount(int trackId) => railEntries[trackId].keypoints.Length; /// /// Gets count of all available tracks /// /// public int GetTrainTrackCount() => railEntries.Length; /// /// Gets Vector3 translated to openviii coordinates from given track animation's frame id /// /// /// /// public Vector3 GetTrackFrameVector(int trackId, int frameId) { Keypoint kp = railEntries[trackId].keypoints[frameId]; return new Vector3(Extended.ConvertVanillaWorldXAxisToOpenVIII(kp.x), Extended.ConvertVanillaWorldYAxisToOpenVIII(kp.y), Extended.ConvertVanillaWorldZAxisToOpenVIII(kp.Z) ); } } }