Bone.cs 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. using System.Collections.Generic;
  2. using System.Diagnostics.CodeAnalysis;
  3. using System.IO;
  4. using System.Linq;
  5. using System.Runtime.InteropServices;
  6. namespace OpenVIII.Battle.Dat
  7. {
  8. /// <summary>
  9. /// Section 1b: Bones
  10. /// </summary>
  11. /// <see cref="http://wiki.ffrtt.ru/index.php?title=FF8/FileFormat_DAT#Bone_struct"/>
  12. [StructLayout(LayoutKind.Explicit, Pack = 1, Size = ByteSize)]
  13. [SuppressMessage("ReSharper", "UnusedMember.Global")]
  14. [SuppressMessage("ReSharper", "UnassignedReadonlyField")]
  15. [SuppressMessage("ReSharper", "UnusedMember.Local")]
  16. public class Bone
  17. {
  18. #region Fields
  19. public const int ByteSize = 16 + UnkSize;
  20. public const int UnkSize = 32;
  21. /// <summary>
  22. /// Bone Size
  23. /// </summary>
  24. [field: FieldOffset(2)]
  25. public readonly short BoneSize;
  26. /// <summary>
  27. /// Parent ID
  28. /// </summary>
  29. [field: FieldOffset(0)]
  30. public readonly ushort ParentId;
  31. /// <summary>
  32. /// Unknown Often Empty Bytes
  33. /// </summary>
  34. [MarshalAs(UnmanagedType.ByValArray, SizeConst = UnkSize)]
  35. [field: FieldOffset(16)]
  36. public readonly byte[] Unk;
  37. /// <summary>
  38. /// rotation X * 360f
  39. /// </summary>
  40. [field: FieldOffset(4)]
  41. private readonly short _rotX;
  42. /// <summary>
  43. /// rotation Y * 360f
  44. /// </summary>
  45. [field: FieldOffset(6)]
  46. private readonly short _rotY;
  47. /// <summary>
  48. /// rotation Z * 360f
  49. /// </summary>
  50. [field: FieldOffset(8)]
  51. private readonly short _rotZ;
  52. [field: FieldOffset(10)]
  53. private readonly short _unk4;
  54. [field: FieldOffset(12)]
  55. private readonly short _unk5;
  56. [field: FieldOffset(14)]
  57. private readonly short _unk6;
  58. #endregion Fields
  59. #region Constructors
  60. private Bone(BinaryReader br)
  61. {
  62. if (br.BaseStream.Position + ByteSize >= br.BaseStream.Length) return;
  63. (ParentId, BoneSize, _rotX, _rotY, _rotZ, _unk4, _unk5, _unk6, Unk) = (br.ReadUInt16(), br.ReadInt16(),
  64. br.ReadInt16(), br.ReadInt16(), br.ReadInt16(), br.ReadInt16(), br.ReadInt16(), br.ReadInt16(),
  65. br.ReadBytes(UnkSize));
  66. }
  67. private Bone()
  68. {
  69. }
  70. #endregion Constructors
  71. #region Properties
  72. public (float X, float Y, float Z) Rot =>
  73. (_rotX / 4096.0f * 360.0f, _rotY / 4096.0f * 360.0f, _rotZ / 4096.0f * 360.0f);
  74. public float Size => BoneSize / DatFile.ScaleHelper;
  75. public (float A, float B, float C) UnkV => (_unk4 / 4096.0f, _unk5 / 4096.0f, _unk6 / 4096.0f);
  76. #endregion Properties
  77. #region Methods
  78. public static IReadOnlyList<Bone> CreateInstances(BinaryReader br, ushort cBones)
  79. {
  80. if (br.BaseStream.Position + ByteSize * cBones < br.BaseStream.Length)
  81. return Enumerable.Range(0, cBones)
  82. .Select(_ => Extended.ByteArrayToClass<Bone>(br.ReadBytes(ByteSize))).ToList()
  83. .AsReadOnly();
  84. throw new InvalidDataException($"{nameof(Bone)}::{nameof(CreateInstances)} Stream to short to read {cBones} bones");
  85. }
  86. #endregion Methods
  87. }
  88. }