debug_battleDat.cs 60 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413
  1. using Microsoft.Xna.Framework;
  2. using Microsoft.Xna.Framework.Graphics;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Diagnostics;
  6. using System.IO;
  7. using System.Linq;
  8. using System.Runtime.InteropServices;
  9. namespace OpenVIII
  10. {
  11. public static class VertexPositionTexturePointersGRP_Ext
  12. {
  13. public static bool IsNotSet(this Debug_battleDat.VertexPositionTexturePointersGRP vertexPositionTexturePointersGRP)
  14. {
  15. if ((vertexPositionTexturePointersGRP.VPT?.Length ?? 0) > 0 && (vertexPositionTexturePointersGRP.TexturePointers?.Length ?? 0) > 0)
  16. {
  17. //3 vertices per every texture pointer.
  18. Debug.Assert(vertexPositionTexturePointersGRP.VPT.Length / 3 == vertexPositionTexturePointersGRP.TexturePointers.Length);
  19. return false;
  20. }
  21. return true;
  22. }
  23. public static bool IsSet(this Debug_battleDat.VertexPositionTexturePointersGRP vertexPositionTexturePointersGRP) => !vertexPositionTexturePointersGRP.IsNotSet();
  24. }
  25. public partial class Debug_battleDat
  26. {
  27. private byte[] buffer;
  28. private const float BaseLineMaxYFilter = 10f;
  29. public const float SCALEHELPER = 2048.0f;
  30. private const float DEGREES = 360f;
  31. public struct DatFile
  32. {
  33. public uint cSections;
  34. public uint[] pSections;
  35. public uint eof;
  36. }
  37. public DatFile datFile;
  38. #region section 1 Skeleton
  39. [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 16)]
  40. public struct Skeleton
  41. {
  42. public ushort cBones;
  43. public ushort scale;
  44. public ushort unk2;
  45. public ushort unk3;
  46. public ushort unk4;
  47. public ushort unk5;
  48. public ushort unk6;
  49. public ushort unk7;
  50. public Bone[] bones;
  51. public Vector3 GetScale => new Vector3(scale / SCALEHELPER * 12, scale / SCALEHELPER * 12, scale / SCALEHELPER * 12);
  52. }
  53. [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 44)]
  54. public struct Bone
  55. {
  56. public ushort parentId;
  57. public short boneSize;
  58. private short rotx; //360
  59. private short roty; //360
  60. private short rotz; //360
  61. private short unk4;
  62. private short unk5;
  63. private short unk6;
  64. [MarshalAs(UnmanagedType.ByValArray, SizeConst = 28)]
  65. public byte[] Unk;
  66. public float Size => boneSize / SCALEHELPER;
  67. public float RotX => rotx / 4096.0f * 360.0f; //rotX
  68. public float RotY => roty / 4096.0f * 360.0f; //rotY
  69. public float RotZ => rotz / 4096.0f * 360.0f; //rotZ
  70. public float Unk4 => unk4 / 4096.0f; //unk1v
  71. public float Unk5 => unk5 / 4096.0f; //unk2v
  72. public float Unk6 => unk6 / 4096.0f; //unk3v
  73. }
  74. /// <summary>
  75. /// Skeleton data section
  76. /// </summary>
  77. /// <param name="start"></param>
  78. private void ReadSection1(uint start)
  79. {
  80. br.BaseStream.Seek(start, SeekOrigin.Begin);
  81. #if _WINDOWS //looks like Linux Mono doesn't like marshalling structure with LPArray to Bone[]
  82. skeleton = Extended.ByteArrayToStructure<Skeleton>(br.ReadBytes(16));
  83. #else
  84. skeleton = new Skeleton()
  85. {
  86. cBones = br.ReadUInt16(),
  87. scale = br.ReadUInt16(),
  88. unk2 = br.ReadUInt16(),
  89. unk3 = br.ReadUInt16(),
  90. unk4 = br.ReadUInt16(),
  91. unk5 = br.ReadUInt16(),
  92. unk6 = br.ReadUInt16(),
  93. unk7 = br.ReadUInt16()
  94. };
  95. #endif
  96. skeleton.bones = new Bone[skeleton.cBones];
  97. for (int i = 0; i < skeleton.cBones; i++)
  98. {
  99. skeleton.bones[i] = Extended.ByteArrayToStructure<Bone>(br.ReadBytes(44));
  100. br.BaseStream.Seek(4, SeekOrigin.Current);
  101. }
  102. //string debugBuffer = string.Empty;
  103. //for (int i = 0; i< skeleton.cBones; i++)
  104. // debugBuffer += $"{i}|{skeleton.bones[i].parentId}|{skeleton.bones[i].boneSize}|{skeleton.bones[i].Size}\n";
  105. //Console.WriteLine(debugBuffer);
  106. return;
  107. }
  108. public Skeleton skeleton;
  109. #endregion section 1 Skeleton
  110. #region section 2 Geometry
  111. public struct Geometry
  112. {
  113. public uint cObjects;
  114. public uint[] pObjects;
  115. public Object[] objects;
  116. public uint cTotalVert;
  117. }
  118. public struct Object
  119. {
  120. public ushort cVertices;
  121. public VerticeData[] vertexData;
  122. public ushort cTriangles;
  123. public ushort cQuads;
  124. public ulong padding;
  125. public Triangle[] triangles;
  126. public Quad[] quads;
  127. }
  128. public struct VerticeData
  129. {
  130. public ushort boneId;
  131. public ushort cVertices;
  132. public Vector3[] vertices;
  133. }
  134. [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 8)]
  135. public struct Vertex
  136. {
  137. public short x { get; private set; }
  138. public short y { get; private set; }
  139. public short z { get; private set; }
  140. public Vertex(short x, short y, short z)
  141. {
  142. this.x = x;
  143. this.y = y;
  144. this.z = z;
  145. }
  146. public static implicit operator Vector3(Vertex v) => new Vector3(-v.x / SCALEHELPER, -v.z / SCALEHELPER, -v.y / SCALEHELPER);
  147. public override string ToString() => $"x={x}, y={y}, z={z}, Vector3={(Vector3)this}";
  148. }
  149. [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 16)]
  150. public struct Triangle
  151. {
  152. private ushort A;
  153. private ushort B;
  154. private ushort C;
  155. public UV vta;
  156. public UV vtb;
  157. public ushort texUnk;
  158. public UV vtc;
  159. public ushort u;
  160. private VertexPositionTexture[] TempVPT;
  161. public ushort A1 { get => (ushort)(A & 0xFFF); set => A = value; }
  162. public ushort B1 { get => (ushort)(B & 0xFFF); set => B = value; }
  163. public ushort C1 { get => (ushort)(C & 0xFFF); set => C = value; }
  164. public byte textureIndex => (byte)((texUnk >> 6) & 0b111);
  165. public static Triangle Create(BinaryReader br)
  166. {
  167. Triangle r = new Triangle()
  168. {
  169. A = br.ReadUInt16(),
  170. B = br.ReadUInt16(),
  171. C = br.ReadUInt16(),
  172. vta = UV.Create(br),
  173. vtb = UV.Create(br),
  174. texUnk = br.ReadUInt16(),
  175. vtc = UV.Create(br),
  176. u = br.ReadUInt16(),
  177. TempVPT = new VertexPositionTexture[Count]
  178. };
  179. return r;
  180. }
  181. public ushort GetIndex(int i)
  182. {
  183. switch (i)
  184. {
  185. case 0:
  186. return C1; //for some reason C is first in triangle
  187. case 1:
  188. return A1;
  189. case 2:
  190. return B1;
  191. }
  192. throw new IndexOutOfRangeException($"{this} :: 0-2 are only valid values");
  193. }
  194. public UV GetUV(int i)
  195. {
  196. switch (i)
  197. {
  198. case 0:
  199. return vta;
  200. case 1:
  201. return vtb;
  202. case 2:
  203. return vtc;
  204. }
  205. throw new IndexOutOfRangeException($"{this} :: 0-2 are only valid values");
  206. }
  207. public byte this[int i]
  208. {
  209. get
  210. {
  211. switch (i)
  212. {
  213. case 0:
  214. return 0;
  215. case 1:
  216. return 1;
  217. case 2:
  218. return 2;
  219. }
  220. throw new IndexOutOfRangeException($"{this} :: 0-2 are only valid values");
  221. }
  222. }
  223. public byte[] Indices => new byte[] { this[0], this[1], this[2] };
  224. public static byte Count => 3;
  225. public VertexPositionTexture[] GenerateVPT(List<VectorBoneGRP> verts, Quaternion rotation, Vector3 translationPosition, Texture2D preVarTex)
  226. {
  227. if (TempVPT == null)
  228. TempVPT = new VertexPositionTexture[Count];
  229. VertexPositionTexture GetVPT(ref Triangle triangle, byte i)
  230. {
  231. Vector3 GetVertex(ref Triangle _triangle, byte _i)
  232. {
  233. return TransformVertex(verts[_triangle.GetIndex(_i)], translationPosition, rotation);
  234. }
  235. return new VertexPositionTexture(GetVertex(ref triangle, i), triangle.GetUV(i).ToVector2(preVarTex.Width, preVarTex.Height));
  236. }
  237. TempVPT[0] = GetVPT(ref this, this[0]);
  238. TempVPT[1] = GetVPT(ref this, this[1]);
  239. TempVPT[2] = GetVPT(ref this, this[2]);
  240. return TempVPT;
  241. }
  242. }
  243. [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 20)]
  244. public struct Quad
  245. {
  246. private ushort A;
  247. private ushort B;
  248. private ushort C;
  249. private ushort D;
  250. public UV vta;
  251. public ushort texUnk;
  252. public UV vtb;
  253. public ushort u;
  254. public UV vtc;
  255. public UV vtd;
  256. private VertexPositionTexture[] TempVPT;
  257. public ushort A1 { get => (ushort)(A & 0xFFF); set => A = value; }
  258. public ushort B1 { get => (ushort)(B & 0xFFF); set => B = value; }
  259. public ushort C1 { get => (ushort)(C & 0xFFF); set => C = value; }
  260. public ushort D1 { get => (ushort)(D & 0xFFF); set => D = value; }
  261. public byte textureIndex => (byte)((texUnk >> 6) & 0b111);
  262. public static Quad Create(BinaryReader br) => new Quad()
  263. {
  264. A = br.ReadUInt16(),
  265. B = br.ReadUInt16(),
  266. C = br.ReadUInt16(),
  267. D = br.ReadUInt16(),
  268. vta = UV.Create(br),
  269. texUnk = br.ReadUInt16(),
  270. vtb = UV.Create(br),
  271. u = br.ReadUInt16(),
  272. vtc = UV.Create(br),
  273. vtd = UV.Create(br),
  274. TempVPT = new VertexPositionTexture[Count]
  275. };
  276. public ushort GetIndex(int i)
  277. {
  278. switch (i)
  279. {
  280. case 0:
  281. return A1;
  282. case 1:
  283. return B1;
  284. case 2:
  285. return C1;
  286. case 3:
  287. return D1;
  288. }
  289. throw new IndexOutOfRangeException($"{this} :: 0-3 are only valid values");
  290. }
  291. public UV GetUV(int i)
  292. {
  293. switch (i)
  294. {
  295. case 0:
  296. return vta;
  297. case 1:
  298. return vtb;
  299. case 2:
  300. return vtc;
  301. case 3:
  302. return vtd;
  303. }
  304. throw new IndexOutOfRangeException($"{this} :: 0-3 are only valid values");
  305. }
  306. public byte this[int i]
  307. {
  308. get
  309. {
  310. switch (i)
  311. {
  312. case 0:
  313. case 3:
  314. return 0;
  315. case 1:
  316. return 1;
  317. case 2:
  318. case 5:
  319. return 3;
  320. case 4:
  321. return 2;
  322. }
  323. throw new IndexOutOfRangeException($"{this} :: 0-5 are only valid values");
  324. }
  325. }
  326. public byte[] Indices => new byte[] { this[0], this[1], this[2], this[3], this[4], this[5] };
  327. public static byte Count => 6;
  328. public VertexPositionTexture[] GenerateVPT(List<VectorBoneGRP> verts, Quaternion rotation, Vector3 translationPosition, Texture2D preVarTex)
  329. {
  330. if (TempVPT == null)
  331. TempVPT = new VertexPositionTexture[Count];
  332. VertexPositionTexture GetVPT(ref Quad quad, byte i)
  333. {
  334. Vector3 GetVertex(ref Quad _quad, byte _i)
  335. {
  336. return TransformVertex(verts[_quad.GetIndex(_i)], translationPosition, rotation);
  337. }
  338. return new VertexPositionTexture(GetVertex(ref quad, i), quad.GetUV(i).ToVector2(preVarTex.Width, preVarTex.Height));
  339. }
  340. TempVPT[0] = TempVPT[3] = GetVPT(ref this, this[0]);
  341. TempVPT[1] = GetVPT(ref this, this[1]);
  342. TempVPT[4] = GetVPT(ref this, this[4]);
  343. TempVPT[2] = TempVPT[5] = GetVPT(ref this, this[2]);
  344. return TempVPT;
  345. }
  346. }
  347. [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 2)]
  348. public struct UV
  349. {
  350. public byte U;
  351. public byte V;
  352. public float U1(float h = 128f) => U / h;
  353. public float V1(float w = 128f) => V > 128 ? //if bigger than 128, then multitexture index to odd
  354. (V - 128f) / w
  355. : w == 32 ? //if equals 32, then it's weapon texture and should be in range of 96-128
  356. (V - 96) / w
  357. : V / w; //if none of these cases, then divide by resolution;
  358. public static UV Create(BinaryReader br) => new UV()
  359. {
  360. U = br.ReadByte(),
  361. V = br.ReadByte()
  362. };
  363. public Vector2 ToVector2(float w, float h) => new Vector2(U1(w), V1(h));
  364. public override string ToString() => $"{U};{U1()};{V};{V1()}";
  365. }
  366. public Geometry geometry;
  367. /// <summary>
  368. /// Model Geometry section
  369. /// </summary>
  370. /// <param name="start"></param>
  371. /// <param name="br"></param>
  372. /// <param name="fileName"></param>
  373. private void ReadSection2(uint start)
  374. {
  375. br.BaseStream.Seek(start, SeekOrigin.Begin);
  376. geometry = new Geometry { cObjects = br.ReadUInt32() };
  377. geometry.pObjects = new uint[geometry.cObjects];
  378. for (int i = 0; i < geometry.cObjects; i++)
  379. geometry.pObjects[i] = br.ReadUInt32();
  380. geometry.objects = new Object[geometry.cObjects];
  381. for (int i = 0; i < geometry.cObjects; i++)
  382. geometry.objects[i] = ReadGeometryObject(start + geometry.pObjects[i]);
  383. geometry.cTotalVert = br.ReadUInt32();
  384. }
  385. private Object ReadGeometryObject(uint start)
  386. {
  387. br.BaseStream.Seek(start, SeekOrigin.Begin);
  388. Object @object = new Object { cVertices = br.ReadUInt16() };
  389. @object.vertexData = new VerticeData[@object.cVertices];
  390. if (br.BaseStream.Position + @object.cVertices * 6 >= br.BaseStream.Length)
  391. return @object;
  392. for (int n = 0; n < @object.cVertices; n++)
  393. {
  394. @object.vertexData[n].boneId = br.ReadUInt16();
  395. @object.vertexData[n].cVertices = br.ReadUInt16();
  396. @object.vertexData[n].vertices = new Vector3[@object.vertexData[n].cVertices];
  397. for (int i = 0; i < @object.vertexData[n].cVertices; i++)
  398. @object.vertexData[n].vertices[i] = Extended.ByteArrayToStructure<Vertex>(br.ReadBytes(6));
  399. }
  400. br.BaseStream.Seek(4 - (br.BaseStream.Position % 4 == 0 ? 4 : br.BaseStream.Position % 4), SeekOrigin.Current);
  401. @object.cTriangles = br.ReadUInt16();
  402. @object.cQuads = br.ReadUInt16();
  403. @object.padding = br.ReadUInt64();
  404. @object.triangles = new Triangle[@object.cTriangles];
  405. if (@object.cTriangles == 0 && @object.cQuads == 0)
  406. return @object;
  407. @object.quads = new Quad[@object.cQuads];
  408. for (int i = 0; i < @object.cTriangles; i++)
  409. @object.triangles[i] = Triangle.Create(br);//Extended.ByteArrayToStructure<Triangle>(br.ReadBytes(16));
  410. for (int i = 0; i < @object.cQuads; i++)
  411. @object.quads[i] = Quad.Create(br);// Extended.ByteArrayToStructure<Quad>(br.ReadBytes(20));
  412. return @object;
  413. }
  414. public struct VectorBoneGRP
  415. {
  416. private Vector3 Vector { get; set; }
  417. public int BoneID { get; private set; }
  418. public float X => Vector.X;
  419. public float Y => Vector.Y;
  420. public float Z => Vector.Z;
  421. public static implicit operator Vector3(VectorBoneGRP vbg) => vbg.Vector;
  422. public VectorBoneGRP(Vector3 vector, int boneID)
  423. {
  424. Vector = vector;
  425. BoneID = boneID;
  426. }
  427. public override string ToString() => $"Vector: {Vector}, Bone ID: {BoneID}";
  428. }
  429. public struct VertexPositionTexturePointersGRP
  430. {
  431. public VertexPositionTexturePointersGRP(VertexPositionTexture[] vpt, byte[] texturepointers) : this()
  432. {
  433. this.VPT = vpt;
  434. this.TexturePointers = texturepointers;
  435. }
  436. public VertexPositionTexture[] VPT { get; private set; }
  437. public byte[] TexturePointers { get; private set; }
  438. }
  439. public Vector3 IndicatorPoint => _indicatorPoint;
  440. //public ConcurrentDictionary<Tuple<int, int>, float> lowpoints = new ConcurrentDictionary<Tuple<int, int>, float>();
  441. /// <summary>
  442. /// This method returns geometry data AFTER animation matrix translations, local
  443. /// position/rotation translations. This is the final step of calculation. This data should
  444. /// be used only by Renderer. Any translations/vertices manipulation should happen inside
  445. /// this method or earlier
  446. /// </summary>
  447. /// <param name="objectId">
  448. /// Monsters can have more than one object. Treat it like multi-model geometry. They are all
  449. /// needed to build whole model
  450. /// </param>
  451. /// <param name="position">a Vector3 to set global position</param>
  452. /// <param name="rotation">a Quaternion to set the correct rotation. 1=90, 2=180 ...</param>
  453. /// <param name="animationId">an animation pointer. Animation 0 is always idle</param>
  454. /// <param name="animationFrame">
  455. /// an animation frame from animation id. You should pass incrementing frame and reset to 0
  456. /// when frameCount max is hit
  457. /// </param>
  458. /// <param name="step">
  459. /// FEATURE: This float (0.0 - 1.0) is used in Linear interpolation in animation frames
  460. /// blending. 0.0 means frameN, 1.0 means FrameN+1. Usually this should be a result of
  461. /// deltaTime to see if computer is capable of rendering smooth animations rather than
  462. /// constant 15 FPS
  463. /// </param>
  464. /// <returns></returns>
  465. public VertexPositionTexturePointersGRP GetVertexPositions(int objectId, ref Vector3 translationPosition, Quaternion rotation, ref Module_battle_debug.AnimationSystem animationSystem, double step)
  466. {
  467. if (animationSystem.AnimationFrame >= animHeader.animations[animationSystem.AnimationId].animationFrames.Length || animationSystem.AnimationFrame < 0)
  468. animationSystem.AnimationFrame = 0;
  469. AnimationFrame nextFrame = animHeader.animations[animationSystem.AnimationId].animationFrames[animationSystem.AnimationFrame];
  470. int lastAnimationFrame = animationSystem.LastAnimationFrame;
  471. AnimationFrame[] lastAnimationFrames = animHeader.animations[animationSystem.LastAnimationId].animationFrames;
  472. lastAnimationFrame = lastAnimationFrames.Length > lastAnimationFrame ? lastAnimationFrame : lastAnimationFrames.Length - 1;
  473. AnimationFrame frame = lastAnimationFrames[lastAnimationFrame];
  474. Object obj = geometry.objects[objectId];
  475. int i = 0;
  476. List<VectorBoneGRP> verts = GetVertices(obj, frame, nextFrame, step);
  477. //float minY = verts.Min(x => x.Y);
  478. //Vector2 HLPTS = FindLowHighPoints(translationPosition, rotation, frame, nextFrame, step);
  479. byte[] texturePointers = new byte[obj.cTriangles + obj.cQuads * 2];
  480. List<VertexPositionTexture> vpt = new List<VertexPositionTexture>(texturePointers.Length * 3);
  481. if (objectId == 0)
  482. {
  483. Module_battle_debug.AnimationSystem _animationSystem = animationSystem;
  484. AnimationYOffset lastoffsets = AnimationYOffsets?.First(x => x.ID == _animationSystem.LastAnimationId && x.Frame == lastAnimationFrame) ?? default;
  485. AnimationYOffset nextoffsets = AnimationYOffsets?.First(x => x.ID == _animationSystem.AnimationId && x.Frame == _animationSystem.AnimationFrame) ?? default;
  486. float offsetylow = MathHelper.Lerp(lastoffsets.LowY, nextoffsets.LowY, (float)step);
  487. _indicatorPoint.X = MathHelper.Lerp(lastoffsets.MidX, nextoffsets.MidX, (float)step);
  488. _indicatorPoint.Y = MathHelper.Lerp(lastoffsets.HighY, nextoffsets.HighY, (float)step);
  489. _indicatorPoint.Z = MathHelper.Lerp(lastoffsets.MidZ, nextoffsets.MidZ, (float)step);
  490. // Move All Y axis down to 0 based on Lowest Y axis in Animation ID 0.
  491. if (OffsetY < 0)
  492. {
  493. translationPosition.Y += OffsetY;
  494. }
  495. // If any Y axis readings are lower than 0 in Animation ID >0. Bring it up to zero.
  496. if (offsetylow < 0)
  497. translationPosition.Y -= offsetylow;
  498. _indicatorPoint += translationPosition;
  499. }
  500. //Triangle parsing
  501. for (; i < obj.cTriangles; i++)
  502. {
  503. Texture2D preVarTex = (Texture2D)textures.textures[obj.triangles[i].textureIndex];
  504. vpt.AddRange(obj.triangles[i].GenerateVPT(verts, rotation, translationPosition, preVarTex));
  505. texturePointers[i] = obj.triangles[i].textureIndex;
  506. }
  507. //Quad parsing
  508. for (i = 0; i < obj.cQuads; i++)
  509. {
  510. Texture2D preVarTex = (Texture2D)textures.textures[obj.quads[i].textureIndex];
  511. vpt.AddRange(obj.quads[i].GenerateVPT(verts, rotation, translationPosition, preVarTex));
  512. texturePointers[obj.cTriangles + i * 2] = obj.quads[i].textureIndex;
  513. texturePointers[obj.cTriangles + i * 2 + 1] = obj.quads[i].textureIndex;
  514. }
  515. return new VertexPositionTexturePointersGRP(vpt.ToArray(), texturePointers);
  516. }
  517. private List<VectorBoneGRP> GetVertices(Object @object, AnimationFrame frame, AnimationFrame nextFrame, double step) => @object.vertexData.SelectMany(vertexdata => vertexdata.vertices.Select(vertex => CalculateFrame(new VectorBoneGRP(vertex, vertexdata.boneId), frame, nextFrame, step))).ToList();
  518. private Vector4 FindLowHighPoints(Vector3 translationPosition, Quaternion rotation, AnimationFrame frame, AnimationFrame nextFrame, double step)
  519. {
  520. List<VectorBoneGRP> vertices =
  521. geometry.objects.SelectMany(@object => GetVertices(@object, frame, nextFrame, step)).ToList();
  522. if (translationPosition != Vector3.Zero || rotation != Quaternion.Identity)
  523. {
  524. IEnumerable<Vector3> _vertices = vertices.Select(vertex => TransformVertex(vertex, translationPosition, rotation));
  525. // midpoints
  526. return new Vector4(_vertices.Min(x => x.Y), _vertices.Max(x => x.Y), (_vertices.Min(x => x.X) + _vertices.Max(x => x.X)) / 2f, (_vertices.Min(x => x.Z) + _vertices.Max(x => x.Z)) / 2f);
  527. }
  528. else
  529. // alt midpoints
  530. return new Vector4(vertices.Min(x => x.Y), vertices.Max(x => x.Y), (vertices.Min(x => x.X) + vertices.Max(x => x.X)) / 2f, (vertices.Min(x => x.Z) + vertices.Max(x => x.Z)) / 2f);
  531. }
  532. public static Vector3 TransformVertex(Vector3 vertex, Vector3 localTranslate, Quaternion rotation) => Vector3.Transform(Vector3.Transform(vertex, rotation), Matrix.CreateTranslation(localTranslate));
  533. /// <summary>
  534. /// Complex function that provides linear interpolation between two matrices of actual
  535. /// to-render animation frame and next frame data for blending
  536. /// </summary>
  537. /// <param name="VBG">the tuple that contains vertex and bone ident</param>
  538. /// <param name="frame">current animation frame to render</param>
  539. /// <param name="nextFrame">
  540. /// animation frame to render that is AFTER the actual one. If last frame, then usually 0 is
  541. /// the 'next' frame
  542. /// </param>
  543. /// <param name="step">
  544. /// step is variable used to determinate the progress for linear interpolation. I.e. 0 for
  545. /// current frame and 1 for next frame; 0.5 for blend of two frames
  546. /// </param>
  547. /// <returns></returns>
  548. private VectorBoneGRP CalculateFrame(VectorBoneGRP VBG, AnimationFrame frame, AnimationFrame nextFrame, double step)
  549. {
  550. Vector3 getvector(Matrix matrix)
  551. {
  552. Vector3 r = new Vector3(
  553. matrix.M11 * VBG.X + matrix.M41 + matrix.M12 * VBG.Z + matrix.M13 * -VBG.Y,
  554. matrix.M21 * VBG.X + matrix.M42 + matrix.M22 * VBG.Z + matrix.M23 * -VBG.Y,
  555. matrix.M31 * VBG.X + matrix.M43 + matrix.M32 * VBG.Z + matrix.M33 * -VBG.Y);
  556. r = Vector3.Transform(r, Matrix.CreateScale(skeleton.GetScale));
  557. return r;
  558. }
  559. Vector3 rootFramePos = getvector(frame.boneMatrix[VBG.BoneID]); //get's bone matrix
  560. if (step > 0f)
  561. {
  562. Vector3 nextFramePos = getvector(nextFrame.boneMatrix[VBG.BoneID]);
  563. rootFramePos = Vector3.Lerp(rootFramePos, nextFramePos, (float)step);
  564. }
  565. return new VectorBoneGRP(rootFramePos, VBG.BoneID);
  566. }
  567. #endregion section 2 Geometry
  568. #region section 3 Animation
  569. public struct AnimationData
  570. {
  571. public uint cAnimations;
  572. public uint[] pAnimations;
  573. public Animation[] animations;
  574. }
  575. public struct Animation
  576. {
  577. public byte cFrames;
  578. public AnimationFrame[] animationFrames;
  579. }
  580. public struct AnimationFrame
  581. {
  582. private Vector3 position;
  583. public Vector3[] bonesVectorRotations;
  584. public Matrix[] boneMatrix;
  585. public Vector3 Position { get => position; set => position = value; }
  586. }
  587. /// <summary>
  588. /// Model Animation section
  589. /// </summary>
  590. /// <param name="start"></param>
  591. /// <param name="br"></param>
  592. /// <param name="fileName"></param>
  593. private void ReadSection3(uint start)
  594. {
  595. br.BaseStream.Seek(start, SeekOrigin.Begin);
  596. animHeader = new AnimationData() { cAnimations = br.ReadUInt32() };
  597. animHeader.pAnimations = new uint[animHeader.cAnimations];
  598. for (int i = 0; i < animHeader.cAnimations; i++)
  599. {
  600. animHeader.pAnimations[i] = br.ReadUInt32();
  601. //Console.WriteLine($"{i}|{animHeader.pAnimations[i]}");
  602. }
  603. animHeader.animations = new Animation[animHeader.cAnimations];
  604. for (int i = 0; i < animHeader.cAnimations; i++) //animation
  605. {
  606. br.BaseStream.Seek(start + animHeader.pAnimations[i], SeekOrigin.Begin); //Get to pointer of animation Id
  607. animHeader.animations[i] = new Animation() { cFrames = br.ReadByte() }; //Create new animation with cFrames frames
  608. animHeader.animations[i].animationFrames = new AnimationFrame[animHeader.animations[i].cFrames];
  609. ExtapathyExtended.BitReader bitReader = new ExtapathyExtended.BitReader(br.BaseStream);
  610. for (int n = 0; n < animHeader.animations[i].cFrames; n++) //frames
  611. {
  612. //Step 1. It starts with bone0.position. Let's read that into AnimationFrames[animId]- it's only one position per frame
  613. float x = bitReader.ReadPositionType() * .01f;
  614. float y = bitReader.ReadPositionType() * .01f;
  615. float z = bitReader.ReadPositionType() * .01f;
  616. animHeader.animations[i].animationFrames[n] = n == 0
  617. ? new AnimationFrame()
  618. { Position = new Vector3(x, y, z) }
  619. : new AnimationFrame()
  620. {
  621. Position = new Vector3(
  622. animHeader.animations[i].animationFrames[n - 1].Position.X + x,
  623. animHeader.animations[i].animationFrames[n - 1].Position.Y + y,
  624. animHeader.animations[i].animationFrames[n - 1].Position.Z + z)
  625. };
  626. byte ModeTest = (byte)bitReader.ReadBits(1); //used to determine if additional info is required
  627. if (i == 0 && n == 0)
  628. Console.WriteLine($"{i} {n}: {ModeTest}");
  629. animHeader.animations[i].animationFrames[n].boneMatrix = new Matrix[skeleton.cBones];
  630. animHeader.animations[i].animationFrames[n].bonesVectorRotations = new Vector3[skeleton.cBones];
  631. //Step 2. We read the position and we need to store the bones rotations or save base rotation if frame==0
  632. for (int k = 0; k < skeleton.cBones; k++) //bones iterator
  633. {
  634. if (n != 0) //just like position the data for next frames are added to previous
  635. {
  636. animHeader.animations[i].animationFrames[n].bonesVectorRotations[k] = new Vector3()
  637. {
  638. X = bitReader.ReadRotationType(),
  639. Y = bitReader.ReadRotationType(),
  640. Z = bitReader.ReadRotationType()
  641. };
  642. if (ModeTest > 0)
  643. _ = GetAdditionalRotationInformation(bitReader);
  644. Vector3 previousFrame = animHeader.animations[i].animationFrames[n - 1].bonesVectorRotations[k];
  645. Vector3 currentFrame = animHeader.animations[i].animationFrames[n].bonesVectorRotations[k];
  646. animHeader.animations[i].animationFrames[n].bonesVectorRotations[k] = previousFrame + currentFrame;
  647. }
  648. else //if this is zero frame, then we need to set the base rotations for bones
  649. {
  650. animHeader.animations[i].animationFrames[n].bonesVectorRotations[k] = new Vector3()
  651. {
  652. X = bitReader.ReadRotationType(),
  653. Y = bitReader.ReadRotationType(),
  654. Z = bitReader.ReadRotationType()
  655. };
  656. if (ModeTest > 0)
  657. _ = GetAdditionalRotationInformation(bitReader);
  658. }
  659. }
  660. //Step 3. We now have all bone rotations stored into short. We need to convert that into Matrix and 360/4096
  661. for (int k = 0; k < skeleton.cBones; k++)
  662. {
  663. Vector3 boneRotation = animHeader.animations[i].animationFrames[n].bonesVectorRotations[k];
  664. boneRotation = Extended.S16VectorToFloat(boneRotation); //we had vector3 containing direct copy of short to float, now we need them in real floating point values
  665. boneRotation *= DEGREES; //bone rotations are in 360 scope
  666. //maki way
  667. Matrix xRot = Extended.GetRotationMatrixX(-boneRotation.X);
  668. Matrix yRot = Extended.GetRotationMatrixY(-boneRotation.Y);
  669. Matrix zRot = Extended.GetRotationMatrixZ(-boneRotation.Z);
  670. //this is the monogame way and gives same results as above.
  671. //Matrix xRot = Matrix.CreateRotationX(MathHelper.ToRadians(boneRotation.X));
  672. //Matrix yRot = Matrix.CreateRotationY(MathHelper.ToRadians(boneRotation.Y));
  673. //Matrix zRot = Matrix.CreateRotationZ(MathHelper.ToRadians(boneRotation.Z));
  674. Matrix MatrixZ = Extended.MatrixMultiply_transpose(yRot, xRot);
  675. MatrixZ = Extended.MatrixMultiply_transpose(zRot, MatrixZ);
  676. if (skeleton.bones[k].parentId == 0xFFFF) //if parentId is 0xFFFF then the current bone is core aka bone0
  677. {
  678. MatrixZ.M41 = -animHeader.animations[i].animationFrames[n].Position.X;
  679. MatrixZ.M42 = -animHeader.animations[i].animationFrames[n].Position.Y; //up/down
  680. MatrixZ.M43 = animHeader.animations[i].animationFrames[n].Position.Z;
  681. MatrixZ.M44 = 1;
  682. }
  683. else
  684. {
  685. Matrix parentBone = animHeader.animations[i].animationFrames[n].boneMatrix[skeleton.bones[k].parentId]; //gets the parent bone
  686. MatrixZ.M43 = skeleton.bones[skeleton.bones[k].parentId].Size;
  687. Matrix rMatrix = Matrix.Multiply(parentBone, MatrixZ);
  688. rMatrix.M41 = parentBone.M11 * MatrixZ.M41 + parentBone.M12 * MatrixZ.M42 + parentBone.M13 * MatrixZ.M43 + parentBone.M41;
  689. rMatrix.M42 = parentBone.M21 * MatrixZ.M41 + parentBone.M22 * MatrixZ.M42 + parentBone.M23 * MatrixZ.M43 + parentBone.M42;
  690. rMatrix.M43 = parentBone.M31 * MatrixZ.M41 + parentBone.M32 * MatrixZ.M42 + parentBone.M33 * MatrixZ.M43 + parentBone.M43;
  691. rMatrix.M44 = 1;
  692. MatrixZ = rMatrix;
  693. }
  694. animHeader.animations[i].animationFrames[n].boneMatrix[k] = MatrixZ;
  695. }
  696. }
  697. }
  698. }
  699. /// <summary>
  700. /// Some enemies use additional information that is saved for bone AFTER rotation types. We
  701. /// are still not sure what it does as enemy works without it
  702. /// </summary>
  703. /// <param name="bitReader"></param>
  704. /// <returns></returns>
  705. private Tuple<short, short, short> GetAdditionalRotationInformation(ExtapathyExtended.BitReader bitReader)
  706. {
  707. short unk1v = 0, unk2v = 0, unk3v = 0;
  708. byte unk1 = (byte)bitReader.ReadBits(1);
  709. if (unk1 > 0)
  710. unk1v = (short)(bitReader.ReadBits(16) + 1024);
  711. else unk1v = 1024;
  712. byte unk2 = (byte)bitReader.ReadBits(1);
  713. if (unk2 > 0)
  714. unk2v = (short)(bitReader.ReadBits(16) + 1024);
  715. else unk2v = 1024;
  716. byte unk3 = (byte)bitReader.ReadBits(1);
  717. if (unk3 > 0)
  718. unk3v = (short)(bitReader.ReadBits(16) + 1024);
  719. else unk3v = 1024;
  720. return new Tuple<short, short, short>(unk1v, unk2v, unk3v);
  721. }
  722. public AnimationData animHeader;
  723. public int frame;
  724. public float frameperFPS = 0.0f;
  725. #endregion section 3 Animation
  726. #region section 11 Textures
  727. public struct Textures
  728. {
  729. /// <summary>
  730. /// TIM count
  731. /// </summary>
  732. public uint cTims;
  733. /// <summary>
  734. /// File pointers
  735. /// </summary>
  736. public uint[] pTims;
  737. /// <summary>
  738. /// EOF
  739. /// </summary>
  740. public uint Eof;
  741. /// <summary>
  742. /// Texture 2D wrapped in TextureHandler for mod support
  743. /// </summary>
  744. public TextureHandler[] textures;
  745. }
  746. /// <summary>
  747. /// TIMS - Textures
  748. /// </summary>
  749. /// <param name="start"></param>
  750. /// <param name="br"></param>
  751. /// <param name="fileName"></param>
  752. private void ReadSection11(uint start)
  753. {
  754. #if DEBUG
  755. //Dump for debug
  756. br.BaseStream.Seek(start, SeekOrigin.Begin);
  757. using (BinaryWriter fs = new BinaryWriter(File.Create(Path.Combine(Path.GetTempPath(), $"{start}.dump"), (int)(br.BaseStream.Length - br.BaseStream.Position), FileOptions.None)))
  758. fs.Write(br.ReadBytes((int)(br.BaseStream.Length - br.BaseStream.Position)));
  759. #endif
  760. br.BaseStream.Seek(start, SeekOrigin.Begin);
  761. //Begin create Textures struct
  762. //populate the tim count;
  763. textures = new Textures() { cTims = br.ReadUInt32() };
  764. //create arrays per count.
  765. textures.pTims = new uint[textures.cTims];
  766. textures.textures = new TextureHandler[textures.cTims];
  767. //Read pointers into array
  768. for (int i = 0; i < textures.cTims; i++)
  769. textures.pTims[i] = br.ReadUInt32();
  770. //Read EOF
  771. textures.Eof = br.ReadUInt32();
  772. //Read TIM -> TextureHandler into array
  773. for (int i = 0; i < textures.cTims; i++)
  774. if (buffer[start + textures.pTims[i]] == 0x10)
  775. {
  776. TIM2 tm = new TIM2(buffer, start + textures.pTims[i]); //broken
  777. textures.textures[i] = TextureHandler.Create($"{fileName}_{i/*.ToString("D2")*/}", tm, 0);// tm.GetTexture(0);
  778. }
  779. else
  780. Debug.WriteLine($"DEBUG: {this}.{this.id}.{start + textures.pTims[i]} :: Not a tim file!");
  781. }
  782. public Textures textures;
  783. private BinaryReader br;
  784. //private float lowpoint;
  785. #endregion section 11 Textures
  786. public enum EntityType
  787. {
  788. Monster,
  789. Character,
  790. Weapon
  791. };
  792. public Debug_battleDat()
  793. {
  794. }
  795. /// <summary>
  796. /// Creates new instance of DAT class that provides every sections parsed into structs and
  797. /// helper functions for renderer
  798. /// </summary>
  799. /// <param name="fileId">This number is used in c0m(fileId) or d(fileId)cXYZ</param>
  800. /// <param name="entityType">Supply Monster, character or weapon (0,1,2)</param>
  801. /// <param name="additionalFileId">Used only in character or weapon to supply for d(fileId)[c/w](additionalFileId)</param>
  802. public static Debug_battleDat Load(int fileId, EntityType entityType, int additionalFileId = -1, Debug_battleDat skeletonReference = null)
  803. {
  804. Debug_battleDat r = new Debug_battleDat()
  805. {
  806. id = fileId,
  807. altid = additionalFileId
  808. };
  809. Console.WriteLine($"DEBUG: Creating new BattleDat with {fileId},{entityType},{additionalFileId}");
  810. ArchiveWorker aw = new ArchiveWorker(Memory.Archives.A_BATTLE);
  811. char et = entityType == EntityType.Weapon ? 'w' : entityType == EntityType.Character ? 'c' : default;
  812. string fileName = entityType == EntityType.Monster ? $"c0m{r.id.ToString("D03")}" :
  813. entityType == EntityType.Character || entityType == EntityType.Weapon ? $"d{fileId.ToString("x")}{et}{additionalFileId.ToString("D03")}"
  814. : string.Empty;
  815. r.entityType = entityType;
  816. if (string.IsNullOrEmpty(fileName))
  817. return null;
  818. string path = null;
  819. string searchstring = "";
  820. if (et != default)
  821. {
  822. searchstring = $"d{fileId.ToString("x")}{et}";
  823. IEnumerable<string> test = aw.GetListOfFiles().Where(x => x.IndexOf(searchstring, StringComparison.OrdinalIgnoreCase) >= 0);
  824. path = test.FirstOrDefault(x => x.ToLower().Contains(fileName));
  825. if (string.IsNullOrWhiteSpace(path) && test.Count() > 0 && entityType == EntityType.Character)
  826. path = test.First();
  827. }
  828. else path = aw.GetListOfFiles().FirstOrDefault(x => x.ToLower().Contains(fileName));
  829. r.fileName = fileName;
  830. if (!string.IsNullOrWhiteSpace(path))
  831. r.buffer = ArchiveWorker.GetBinaryFile(Memory.Archives.A_BATTLE, path);
  832. if (r.buffer == null || r.buffer.Length < 0)
  833. {
  834. Debug.WriteLine($"Search String: {searchstring} Not Found skipping {entityType}; So resulting file buffer is null.");
  835. return null;
  836. }
  837. r.ExportFile();
  838. r.LoadFile(skeletonReference);
  839. r.FindAllLowHighPoints();
  840. return r;
  841. }
  842. private void FindAllLowHighPoints()
  843. {
  844. if (entityType == EntityType.Character || entityType == EntityType.Monster)
  845. {
  846. // Get baseline from running function on only Animation 0;
  847. if (animHeader.animations == null)
  848. return;
  849. List<Vector4> baseline = animHeader.animations[0].animationFrames.Select(x => FindLowHighPoints(Vector3.Zero, Quaternion.Identity, x, x, 0f)).ToList();
  850. //X is lowY, Y is high Y, Z is mid x, W is mid z
  851. float baselinelowY = baseline.Min(x => x.X);
  852. float baselinehighY = baseline.Max(x => x.Y);
  853. float offsetY = 0f;
  854. if (Math.Abs(baselinelowY) < BaseLineMaxYFilter)
  855. {
  856. offsetY -= baselinelowY;
  857. baselinehighY += offsetY;
  858. }
  859. // Default indicator point
  860. _indicatorPoint = new Vector3(0, baselinehighY, 0);
  861. // Need to add this later to bring baselinelow to 0.
  862. OffsetY = offsetY;
  863. // Brings all Y values less than baselinelow to baselinelow
  864. AnimationYOffsets = animHeader.animations.SelectMany((animation, animationid) =>
  865. animation.animationFrames.Select((animationframe, animationframenumber) =>
  866. new AnimationYOffset(animationid, animationframenumber, FindLowHighPoints(OffsetYVector, Quaternion.Identity, animationframe, animationframe, 0f)))).ToList();
  867. }
  868. }
  869. private List<AnimationYOffset> AnimationYOffsets;
  870. private Vector3 _indicatorPoint;
  871. private float OffsetY { get; set; }
  872. private Vector3 OffsetYVector => new Vector3(0f, OffsetY, 0f);
  873. public struct AnimationYOffset
  874. {
  875. public int ID { get; private set; }
  876. public int Frame { get; private set; }
  877. public float LowY { get; private set; }
  878. public float HighY { get; private set; }
  879. public float MidX { get; private set; }
  880. public float MidZ { get; private set; }
  881. public AnimationYOffset(int iD, int frame, Vector4 lowhigh)
  882. : this(iD, frame, lowhigh.X, lowhigh.Y, lowhigh.Z, lowhigh.W)
  883. { }
  884. public AnimationYOffset(int iD, int frame, float low, float high, float midx, float midz)
  885. {
  886. ID = iD;
  887. Frame = frame;
  888. LowY = low;
  889. HighY = high;
  890. MidX = midx;
  891. MidZ = midz;
  892. }
  893. public override string ToString() => $"[{ID}, {Frame}, {LowY}, {HighY}, {MidX}, {MidZ}]";
  894. }
  895. private void ExportFile()
  896. {
  897. #if _WINDOWS && DEBUG
  898. try
  899. {
  900. string targetdir = @"d:\";
  901. if (Directory.Exists(targetdir))
  902. {
  903. DriveInfo[] drivei = DriveInfo.GetDrives().Where(x => x.Name.IndexOf(Path.GetPathRoot(targetdir), StringComparison.OrdinalIgnoreCase) >= 0).ToArray();
  904. DirectoryInfo di = new DirectoryInfo(targetdir);
  905. if (!di.Attributes.HasFlag(FileAttributes.ReadOnly) && drivei.Count() == 1 && drivei[0].DriveType == DriveType.Fixed)
  906. Extended.DumpBuffer(buffer, Path.Combine(targetdir, "out.dat"));
  907. }
  908. }
  909. catch (IOException)
  910. {
  911. }
  912. #endif
  913. }
  914. private Debug_battleDat LoadFile(Debug_battleDat skeletonReference)
  915. {
  916. using (br = new BinaryReader(new MemoryStream(buffer)))
  917. {
  918. if (br.BaseStream.Length - br.BaseStream.Position < 4)
  919. return null;
  920. Init();
  921. switch (entityType)
  922. {
  923. case EntityType.Monster:
  924. return LoadMonster();
  925. case EntityType.Character:
  926. return LoadCharacter();
  927. case EntityType.Weapon:
  928. return LoadWeapon(skeletonReference);
  929. }
  930. return null;
  931. }
  932. }
  933. private void Init()
  934. {
  935. datFile = new DatFile { cSections = br.ReadUInt32() };
  936. datFile.pSections = new uint[datFile.cSections];
  937. for (int i = 0; i < datFile.cSections; i++)
  938. datFile.pSections[i] = br.ReadUInt32();
  939. datFile.eof = br.ReadUInt32();
  940. }
  941. private Debug_battleDat LoadMonster()
  942. {
  943. if (id == 127)
  944. {
  945. // per wiki 127 only have 7 & 8
  946. //ReadSection7(datFile.pSections[6], br, fileName);
  947. //ReadSection8(datFile.pSections[7]);
  948. return null;
  949. }
  950. ReadSection1(datFile.pSections[0]);
  951. ReadSection3(datFile.pSections[2]); // animation data
  952. ReadSection2(datFile.pSections[1]);
  953. //ReadSection4(datFile.pSections[3]);
  954. ReadSection5(datFile.pSections[4], datFile.pSections[5]);
  955. //ReadSection6(datFile.pSections[5]);
  956. ReadSection7(datFile.pSections[6]);
  957. //ReadSection8(datFile.pSections[7]); // battle scripts/ai
  958. ReadSection9(datFile.pSections[8], datFile.pSections[9]); //AKAO sounds
  959. //ReadSection10(datFile.pSections[9], datFile.pSections[10], br, fileName);
  960. ReadSection11(datFile.pSections[10]);
  961. return this;
  962. }
  963. private Debug_battleDat LoadCharacter()
  964. {
  965. ReadSection1(datFile.pSections[0]);
  966. ReadSection3(datFile.pSections[2]);
  967. ReadSection2(datFile.pSections[1]);
  968. if (id == 7 && entityType == EntityType.Character)
  969. {
  970. ReadSection11(datFile.pSections[8]);
  971. ReadSection5(datFile.pSections[5], datFile.pSections[6]);
  972. }
  973. else
  974. ReadSection11(datFile.pSections[5]);
  975. return this;
  976. }
  977. private Debug_battleDat LoadWeapon(Debug_battleDat skeletonReference)
  978. {
  979. if (id != 1 && id != 9)
  980. {
  981. ReadSection1(datFile.pSections[0]);
  982. ReadSection3(datFile.pSections[2]);
  983. ReadSection2(datFile.pSections[1]);
  984. ReadSection5(datFile.pSections[3], datFile.pSections[4]);
  985. ReadSection11(datFile.pSections[6]);
  986. }
  987. else if (skeletonReference != null)
  988. {
  989. skeleton = skeletonReference.skeleton;
  990. animHeader = skeletonReference.animHeader;
  991. ReadSection2(datFile.pSections[0]);
  992. ReadSection5(datFile.pSections[1], datFile.pSections[2]);
  993. ReadSection11(datFile.pSections[4]);
  994. }
  995. return this;
  996. }
  997. /// <summary>
  998. /// Sounds
  999. /// </summary>
  1000. /// <param name="start"></param>
  1001. /// <param name="end"></param>
  1002. /// <param name="br"></param>
  1003. /// <param name="fileName"></param>
  1004. private void ReadSection9(uint start, uint end)
  1005. {
  1006. //Contains AKAO sequences(can be empty).
  1007. //Offset Length Description
  1008. //0 2 bytes Number of AKAOs
  1009. //2 nbAKAOs * 2 bytes AKAOs Positions
  1010. //2 + nbAKAOs * 2 2 bytes End of section 9
  1011. //4 + nbAKAOs * 2 Varies* nbAKAOs AKAOs
  1012. // nothing final in here just was trying to dump data to see what was there.
  1013. // http://wiki.ffrtt.ru/index.php?title=FF7/Field/Script/Opcodes/F2_AKAO related?
  1014. br.BaseStream.Seek(start, SeekOrigin.Begin);
  1015. uint[] offsets = new uint[br.ReadUInt16()];
  1016. for (ushort i = 0; i < offsets.Length; i++)
  1017. {
  1018. ushort offset = br.ReadUInt16();
  1019. if (offset == 0)
  1020. continue;
  1021. offsets[i] = offset + start;
  1022. }
  1023. uint newend = br.ReadUInt16() + start;
  1024. if (newend < end) end = newend;
  1025. List<uint> sortedoffsets = offsets.Where(x => x > 0).Distinct().OrderBy(x => x).ToList();
  1026. Dictionary<uint, byte[]> dataatoffsets = new Dictionary<uint, byte[]>(sortedoffsets.Count);
  1027. for (ushort i = 0; i < sortedoffsets.Count; i++)
  1028. {
  1029. uint offset = sortedoffsets[i];
  1030. uint localend = end;
  1031. if (i + 1 < sortedoffsets.Count)
  1032. localend = sortedoffsets[i + 1];
  1033. br.BaseStream.Seek(offset, SeekOrigin.Begin);
  1034. if (offset < localend)
  1035. dataatoffsets.Add(offset, br.ReadBytes(checked((int)(localend - offset))));
  1036. }
  1037. }
  1038. public List<AnimationSequence> Sequences { get; private set; }
  1039. public struct AnimationSequence
  1040. {
  1041. public int id;
  1042. public uint offset;
  1043. public byte[] data;
  1044. /// <summary>
  1045. /// Test-Reason for list is so i can go read the data with out removing it.
  1046. /// </summary>
  1047. public List<byte> AnimationQueue { get; set; }
  1048. //public static Dictionary<byte, Action<byte[], int>> ParseData = new Dictionary<byte, Action<byte[], int>>{
  1049. // { 0xA3, (byte[] data, int i) => { } } };
  1050. public void GenerateQueue(Debug_battleDat dat)
  1051. {
  1052. AnimationQueue = new List<byte>();
  1053. for (int i = 0; data != null && i < data.Length; i++)
  1054. {
  1055. byte b;
  1056. byte[] data = this.data;
  1057. byte get(int _i = -1)
  1058. {
  1059. return b = data[_i < 0 ? i : _i];
  1060. }
  1061. if (get() < (dat.animHeader.animations?.Length ?? 0))
  1062. {
  1063. AnimationQueue.Add(b);
  1064. }
  1065. //else switch(b)
  1066. //{
  1067. // case 0xA3:
  1068. // // following value is animation.
  1069. // break;
  1070. // case 0xE6:
  1071. // switch (get(++i))
  1072. // {
  1073. // case 0x03:
  1074. // i += 1;
  1075. // break;
  1076. // }
  1077. // break;
  1078. // case 0xEA:
  1079. // switch (get(++i))
  1080. // {
  1081. // case 0x05:
  1082. // i += 1;
  1083. // break;
  1084. // case 0x06:
  1085. // i += 2;
  1086. // break;
  1087. // }
  1088. // break;
  1089. // default:
  1090. // i++;//skip next byte //as might not be a animation.
  1091. // break;
  1092. //}
  1093. }
  1094. }
  1095. }
  1096. /// <summary>
  1097. /// Animation Sequences
  1098. /// </summary>
  1099. /// <param name="start"></param>
  1100. /// <param name="end"></param>
  1101. /// <param name="br"></param>
  1102. /// <param name="fileName"></param>
  1103. /// <see cref="http://forums.qhimm.com/index.php?topic=19362.msg270092"/>
  1104. private void ReadSection5(uint start, uint end)
  1105. {
  1106. // nothing final in here just was trying to dump data to see what was there.
  1107. br.BaseStream.Seek(start, SeekOrigin.Begin);
  1108. uint[] offsets = new uint[br.ReadUInt16()];
  1109. for (ushort i = 0; i < offsets.Length; i++)
  1110. {
  1111. ushort offset = br.ReadUInt16();
  1112. if (offset == 0)
  1113. continue;
  1114. offsets[i] = offset + start;
  1115. }
  1116. List<uint> sortedoffsets = offsets.Where(x => x > 0).Distinct().OrderBy(x => x).ToList();
  1117. Sequences = new List<AnimationSequence>(sortedoffsets.Count);
  1118. //Dictionary<uint, byte[]> dataatoffsets = new Dictionary<uint, byte[]>(sortedoffsets.Count);
  1119. for (ushort i = 0; i < sortedoffsets.Count; i++)
  1120. {
  1121. uint offset = sortedoffsets[i];
  1122. //uint tie = endpoint;
  1123. //if (i + 1 < t.Count)
  1124. // tie = t[i + 1];
  1125. uint localend = offset;
  1126. br.BaseStream.Seek(offset, SeekOrigin.Begin);
  1127. do
  1128. localend++;
  1129. while (br.ReadByte() != 0xa2 && br.BaseStream.Position < end && (i + 1 < sortedoffsets.Count ? br.BaseStream.Position < sortedoffsets[i + 1] : true));
  1130. br.BaseStream.Seek(offset, SeekOrigin.Begin);
  1131. foreach (var offsetindexed in offsets.Select((value, index) => new { value, index }).Where(x => x.value == offset))
  1132. {
  1133. AnimationSequence sequence = new AnimationSequence { id = offsetindexed.index, offset = offsetindexed.value, data = br.ReadBytes(checked((int)(localend - offset))) };
  1134. sequence.GenerateQueue(this);
  1135. Sequences.Add(sequence);
  1136. }
  1137. }
  1138. //foreach (KeyValuePair<uint, byte[]> ob in dataatoffsets)
  1139. //{
  1140. // Debug.Write($"{ob.Key}({string.Format("{0:x}", offsets[ob.Key])}) - ");
  1141. // for (int i = 0; i< ob.Value.Length; i++)
  1142. // {
  1143. // byte b;
  1144. // byte Get(int pos = -1)
  1145. // { return b = ob.Value[pos<0?i:pos]; }
  1146. // switch (Get())
  1147. // {
  1148. // case 0xa5:
  1149. // Debug.Write("{Aura-A5}");
  1150. // switch (Get(++i))
  1151. // {
  1152. // case 0x00:
  1153. // Debug.Write("{Magic-00}");
  1154. // break;
  1155. // case 0x01:
  1156. // Debug.Write("{GF-01}");
  1157. // break;
  1158. // case 0x02:
  1159. // Debug.Write("{Limit-02}");
  1160. // break;
  1161. // case 0x03:
  1162. // Debug.Write("{Finisher-03}");
  1163. // break;
  1164. // case 0x04:
  1165. // Debug.Write("{Enemy Magic-04}");
  1166. // break;
  1167. // default:
  1168. // Debug.Write(string.Format("{0:x2}", b));
  1169. // break;
  1170. // }
  1171. // break;
  1172. // case 0xb5:
  1173. // Debug.Write("Sound-B5");
  1174. // break;
  1175. // case 0xbb:
  1176. // Debug.Write("{Effect-BB}");
  1177. // break;
  1178. // case 0xa2:
  1179. // Debug.Write("{Return-A2}");
  1180. // break;
  1181. // case 0xa0:
  1182. // Debug.Write("{Loop-A0}");
  1183. // Debug.Write("{Anim}");
  1184. // Debug.Write(string.Format("{0:x2} ", Get(++i)));
  1185. // break;
  1186. // case 0xc1:
  1187. // if (Get(i + 2) == 0xe5 && Get(i + 3) == 0x7f)
  1188. // {
  1189. // Debug.Write("{Repeat-C1}");
  1190. // //loop 0x1E times Animation 28
  1191. // //C1 1E E5 7F 28
  1192. // Debug.Write("{Count}");
  1193. // Debug.Write($"{Get(++i)} ");
  1194. // Debug.Write(string.Format("{0:x2} ", Get(++i)));
  1195. // Debug.Write(string.Format("{0:x2} ", Get(++i)));
  1196. // Debug.Write("{Anim}");
  1197. // Debug.Write(string.Format("{0:x2} ", Get(++i)));
  1198. // }
  1199. // else if(Get(i + 1) == 0x00 && Get(i + 2) == 0xe5 && Get(i + 3) == 0x0f)
  1200. // {
  1201. // //Return to home location.
  1202. // //C1 00 E5 0F
  1203. // Debug.Write("{Place model at home location}");
  1204. // }
  1205. // else
  1206. // Debug.Write(string.Format(" {0:x2}", Get()));
  1207. // break;
  1208. // case 0xc3:
  1209. // Debug.Write("{Special-C3}");
  1210. // //C3 7F C5 FF E5 7F E7 F9 //wait till previous sequence is complete.
  1211. // //C3 0c e1 23 e5 7f ba
  1212. // //C3 08 d8 00 01 e5 08 {04,05}
  1213. // break;
  1214. // case 0x91:
  1215. // Debug.Write("{Text-91}");
  1216. // break;
  1217. // case 0x1e:
  1218. // Debug.Write("{TextREF-1E}");
  1219. // break;
  1220. // case 0xa3:
  1221. // Debug.Write("{End-A3}");
  1222. // Debug.Write("{Anim}");
  1223. // Debug.Write(string.Format("{0:x2} ", Get(++i)));
  1224. // i += 2;
  1225. // break;
  1226. // case 0xa8:
  1227. // Debug.Write("{Visibility-A8}");
  1228. // switch (Get(++i))
  1229. // {
  1230. // case 0x02:
  1231. // Debug.Write("{Hide-02}");
  1232. // break;
  1233. // case 0x03:
  1234. // Debug.Write("{Show-03}");
  1235. // break;
  1236. // default:
  1237. // Debug.Write(string.Format("{0:x2}", b));
  1238. // break;
  1239. // }
  1240. // Debug.Write("{Anim}");
  1241. // Debug.Write(string.Format("{0:x2} ", Get(++i)));
  1242. // break;
  1243. // default:
  1244. // Debug.Write(string.Format(" {0:x2}", b));
  1245. // break;
  1246. // }
  1247. // }
  1248. // Debug.Write($" ({ob.Value.Length} length)\n");
  1249. //}
  1250. }
  1251. public int GetId => id;
  1252. public int altid { get; private set; }
  1253. public int id { get; private set; }
  1254. public EntityType entityType { get; private set; }
  1255. public string fileName { get; private set; }
  1256. }
  1257. }