FieldCharaOne.cs 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. using Microsoft.Xna.Framework.Graphics;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Diagnostics.CodeAnalysis;
  5. using System.IO;
  6. using System.Linq;
  7. namespace OpenVIII.Fields
  8. {
  9. //this is static, because it's always alive
  10. public static class FieldMainCharaOne
  11. {
  12. #region Fields
  13. public static bool BAlreadyInitialized;
  14. public static MainFieldChara[] MainFieldCharacters;
  15. #endregion Fields
  16. #region Methods
  17. public static void Init(bool bForce = false)
  18. {
  19. if (BAlreadyInitialized && !bForce)
  20. return;
  21. var mfc = new List<MainFieldChara>();
  22. var aw = ArchiveWorker.Load(Memory.Archives.A_FIELD);
  23. var test = aw.GetListOfFiles();
  24. var collectionEntry = test.Where(x => x.ToLower().Contains("main_chr")).ToList().AsReadOnly();
  25. if (!collectionEntry.Any()) return;
  26. var fieldArchiveName = collectionEntry.First();
  27. var fieldArchive = aw.GetArchive(fieldArchiveName);
  28. var test2 = fieldArchive.GetListOfFiles();
  29. foreach (var fieldArchiveFileName in test2)
  30. {
  31. //if (test_[i].Contains("d008.mch"))
  32. // continue;
  33. if (string.IsNullOrWhiteSpace(fieldArchiveFileName))
  34. continue;
  35. var oneBytes = fieldArchive.GetBinaryFile(fieldArchiveFileName);
  36. if (oneBytes.Length < 64) //Hello Kazuo Suzuki! I will skip your dummy files
  37. continue;
  38. var currentLocalChara = ReadMainChara(oneBytes);
  39. var localId = int.Parse(Path.GetFileNameWithoutExtension(fieldArchiveFileName).Substring(1, 3));
  40. currentLocalChara.ID = localId;
  41. mfc.Add(currentLocalChara);
  42. }
  43. MainFieldCharacters = mfc.ToArray();
  44. BAlreadyInitialized = true;
  45. }
  46. private static MainFieldChara ReadMainChara(byte[] oneBytes)
  47. {
  48. var localMfc = new MainFieldChara();
  49. using (var ms = new MemoryStream(oneBytes))
  50. using (var br = new BinaryReader(ms))
  51. {
  52. var timOffsets = new List<uint>();
  53. uint timOffset;
  54. while ((timOffset = br.ReadUInt32()) != 0xffffffff)
  55. timOffsets.Add(timOffset & 0x00FFFFFF);
  56. var modelPointer = br.ReadUInt32();
  57. //read textures
  58. var texture2DReader = timOffsets
  59. .Select(x => new TIM2(br, x))
  60. .Select(x => x.GetTexture()).ToList()
  61. .AsReadOnly();
  62. localMfc.Textures = texture2DReader.ToArray();
  63. //read models
  64. ms.Seek(modelPointer, SeekOrigin.Begin);
  65. var mch = new Debug_MCH(ms, br, Debug_MCH.mchMode.FieldMain);
  66. localMfc.MCH = mch;
  67. }
  68. return localMfc;
  69. }
  70. #endregion Methods
  71. #region Structs
  72. public struct MainFieldChara
  73. {
  74. #region Fields
  75. public int ID;
  76. public Debug_MCH MCH;
  77. public Texture2D[] Textures;
  78. #endregion Fields
  79. }
  80. #endregion Structs
  81. }
  82. internal class FieldCharaOne
  83. {
  84. #region Fields
  85. public CharaModelHeaders[] FieldModels;
  86. [SuppressMessage("ReSharper", "NotAccessedField.Local")] private readonly int _fieldId;
  87. #endregion Fields
  88. #region Constructors
  89. public FieldCharaOne(int fieldId)
  90. {
  91. _fieldId = fieldId;
  92. if (!FieldMainCharaOne.BAlreadyInitialized)
  93. FieldMainCharaOne.Init();
  94. var aw = ArchiveWorker.Load(Memory.Archives.A_FIELD);
  95. var test = aw.GetListOfFiles();
  96. var collectionEntry = test.Where(x => x.IndexOf(Memory.FieldHolder.Fields[Memory.FieldHolder.FieldID], StringComparison.OrdinalIgnoreCase) >= 0).ToList().AsReadOnly();
  97. if (!collectionEntry.Any()) return;
  98. var fieldArchiveName = collectionEntry.First();
  99. var fieldArchive = aw.GetArchive(fieldArchiveName);
  100. var test2 = fieldArchive.GetListOfFiles();
  101. string one;
  102. //string main_chr;
  103. try
  104. {
  105. one = test2.First(x => x.EndsWith(".one", StringComparison.OrdinalIgnoreCase));
  106. }
  107. catch
  108. {
  109. return;
  110. }
  111. var oneBytes = fieldArchive.GetBinaryFile(one);
  112. if (oneBytes.Length == 0)
  113. return;
  114. ReadBuffer(oneBytes);
  115. }
  116. #endregion Constructors
  117. #region Methods
  118. private void ReadBuffer(byte[] oneBuffer)
  119. {
  120. var cmh = new List<CharaModelHeaders>();
  121. using (var ms = new MemoryStream(oneBuffer))
  122. using (var br = new BinaryReader(ms))
  123. {
  124. var nModels = br.ReadUInt32();
  125. for (var i = 0; i < nModels; i++)
  126. {
  127. var localCmh = new CharaModelHeaders
  128. {
  129. Offset = br.ReadUInt32() + 4,
  130. Size = br.ReadUInt32(),
  131. Size2 = br.ReadUInt32(),
  132. FlagDword = br.ReadUInt32()
  133. };
  134. var bIgnorePadding = false;
  135. var bMainChara = false;
  136. if (localCmh.FlagDword >> 24 == 0xD0) //main character file
  137. {
  138. localCmh.TIMOffset = new uint[0];
  139. localCmh.ModelDataOffset = 0xFFFFFFFF;
  140. ms.Seek(4, SeekOrigin.Current);
  141. bMainChara = true;
  142. }
  143. else if (localCmh.FlagDword >> 24 == 0xa0) //unknown- object without texture/ placeholder?
  144. {
  145. localCmh.TIMOffset = new uint[0];
  146. localCmh.ModelDataOffset = 0xFFFFFFFF;
  147. ms.Seek(8, SeekOrigin.Current);
  148. bIgnorePadding = true;
  149. }
  150. else
  151. {
  152. var timOffsets = new List<uint>();
  153. // ReSharper disable once UnusedVariable
  154. var flagTimOffset = localCmh.FlagDword & 0x00FFFFFF;
  155. timOffsets.Add(localCmh.FlagDword << 8);
  156. uint localTimOffset;
  157. while ((localTimOffset = br.ReadUInt32()) != 0xFFFFFFFF)
  158. timOffsets.Add(localTimOffset & 0x00FFFFFF);
  159. localCmh.TIMOffset = timOffsets.ToArray();
  160. localCmh.ModelDataOffset = br.ReadUInt32();
  161. }
  162. localCmh.ModelName = br.ReadChars(8);
  163. localCmh.Padding = br.ReadUInt32();
  164. if (localCmh.Padding != 0xEEEEEEEE && !bIgnorePadding) //null models for placeholders are 2 not eeeeeeee
  165. throw new Exception("Chara one- padding was not 0xEEEEEEEE- check code for ReadBuffer in FieldCharaOne");
  166. int lastMsPosition;
  167. if (localCmh.ModelDataOffset != 0xFFFFFFFF)
  168. {
  169. lastMsPosition = (int)ms.Position;
  170. ms.Seek(localCmh.Offset + localCmh.ModelDataOffset, SeekOrigin.Begin);
  171. localCmh.MCH = new Debug_MCH(ms, br, Debug_MCH.mchMode.FieldNPC, 3f);
  172. //ms.Seek(localCmh.offset + 4, SeekOrigin.Begin);
  173. var texList = new List<Texture2D>();
  174. for (var n = 0; n < localCmh.TIMOffset.Length; n++)
  175. {
  176. if (localCmh.TIMOffset[n] > 0x10000000)
  177. localCmh.TIMOffset[n] = localCmh.TIMOffset[n] & 0x00FFFFFF;
  178. var localTim = new TIM2(br, localCmh.Offset + localCmh.TIMOffset[n]);
  179. texList.Add(localTim.GetTexture());
  180. }
  181. localCmh.Textures = texList.ToArray();
  182. ms.Seek(lastMsPosition, SeekOrigin.Begin);
  183. }
  184. else if (bMainChara)
  185. {
  186. lastMsPosition = (int)ms.Position;
  187. //this is main chara, so please grab data from main_chr.fs
  188. var getRefId = int.Parse(new string(localCmh.ModelName).Substring(1, 3));
  189. var chara = FieldMainCharaOne.MainFieldCharacters.First(x => x.ID == getRefId);
  190. localCmh.ModelDataOffset = 1;
  191. localCmh.MCH = chara.MCH;
  192. localCmh.Textures = chara.Textures;
  193. ms.Seek(localCmh.Offset, SeekOrigin.Begin);
  194. localCmh.MCH.MergeAnimations(ms, br);
  195. ms.Seek(lastMsPosition, SeekOrigin.Begin);
  196. }
  197. cmh.Add(localCmh);
  198. }
  199. }
  200. FieldModels = cmh.ToArray();
  201. }
  202. #endregion Methods
  203. #region Structs
  204. public struct CharaModelHeaders
  205. {
  206. #region Fields
  207. ///this is either tim or indicator of main model
  208. public uint FlagDword;
  209. public Debug_MCH MCH;
  210. public uint ModelDataOffset;
  211. ///8
  212. public char[] ModelName;
  213. ///points to texture
  214. public uint Offset;
  215. ///0xEEEEEEEE
  216. public uint Padding;
  217. ///size of whole segment
  218. public uint Size;
  219. ///as above
  220. public uint Size2;
  221. public Texture2D[] Textures;
  222. ///pointer to zero
  223. public uint[] TIMOffset;
  224. #endregion Fields
  225. }
  226. #endregion Structs
  227. }
  228. }