FieldCharaOne.cs 10.0 KB

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