Archive.cs 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. using OpenVIII.Fields.Scripts.Instructions;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Diagnostics;
  5. using System.Linq;
  6. namespace OpenVIII.Fields
  7. {
  8. public class Archive
  9. {
  10. #region Properties
  11. public string ArchiveName { get; set; }
  12. public Background Background { get; set; }
  13. public Cameras Cameras { get; set; }
  14. public EventEngine EventEngine { get; set; }
  15. public string FileName { get; set; }
  16. public Sections Flags { get; set; }
  17. public ushort ID { get; set; }
  18. public INF INF { get; set; }
  19. public List<Scripts.Jsm.GameObject> JSMObjects { get; set; }
  20. public FieldModes Mod { get; set; } = 0;
  21. public MrtRat MrtRat { get; set; }
  22. public MSK MSK { get; set; }
  23. public PMP PMP { get; set; }
  24. public IServices Services { get; set; }
  25. public SFX SFX { get; set; }
  26. public TDW TDW { get; set; }
  27. public WalkMesh WalkMesh { get; set; }
  28. #endregion Properties
  29. #region Methods
  30. public static Archive Load(ushort inputFieldID, Sections flags = Sections.ALL)
  31. {
  32. var r = new Archive();
  33. return !r.Init(inputFieldID, flags) ? null : r;
  34. }
  35. public void Draw()
  36. {
  37. switch (Mod)
  38. {
  39. case FieldModes.Init:
  40. break;
  41. case FieldModes.Disabled:
  42. break;
  43. case FieldModes.DebugRender:
  44. case FieldModes.NoJSM:
  45. Background.Draw();
  46. break;
  47. default:
  48. throw new ArgumentOutOfRangeException();
  49. }
  50. }
  51. public HashSet<FF8String> GetAreaNames() => JSMObjects != null && JSMObjects.Count > 0 ?
  52. (
  53. from jsmObject in JSMObjects
  54. from script in jsmObject.Scripts
  55. from instruction in script.Segment.Flatten()
  56. where instruction is SETPLACE
  57. let setPlace = ((SETPLACE)instruction)
  58. select setPlace.AreaName()).ToHashSet() : null;
  59. public bool Init(ushort? inputFieldID = null, Sections flags = Sections.ALL)
  60. {
  61. Flags = flags;
  62. Memory.SuppressDraw = true;
  63. var aw = ArchiveWorker.Load(Memory.Archives.A_FIELD);
  64. var test = aw.GetListOfFiles();
  65. //TODO fix endless look on FieldID 50.
  66. ID = inputFieldID ?? Memory.FieldHolder.FieldID;
  67. var count = (Memory.FieldHolder.Fields?.Length ?? 0);
  68. if (ID >= count)
  69. return false;
  70. FileName = Memory.FieldHolder.GetString(ID);
  71. ArchiveName = test.FirstOrDefault(x => x.IndexOf(FileName, StringComparison.OrdinalIgnoreCase) >= 0);
  72. if (string.IsNullOrWhiteSpace(ArchiveName))
  73. {
  74. Memory.Log.WriteLine($"FileNotFound :: {ID} - {FileName.ToUpper()}");
  75. Mod = FieldModes.Disabled;
  76. return false;
  77. }
  78. var fieldArchive = aw.GetArchive(ArchiveName);
  79. var listOfFiles = fieldArchive.GetListOfFiles();
  80. string findString(string s) =>
  81. listOfFiles.FirstOrDefault(x => x.IndexOf(s, StringComparison.OrdinalIgnoreCase) >= 0);
  82. byte[] getFile(string s)
  83. {
  84. s = findString(s);
  85. return !string.IsNullOrWhiteSpace(s) ? fieldArchive.GetBinaryFile(s) : null;
  86. }
  87. if (!flags.HasFlag(Sections.MIM | Sections.MAP) ||
  88. (Background = Background.Load(getFile(".mim"), getFile(".map"))) == null)
  89. {
  90. Mod = FieldModes.Disabled;
  91. }
  92. if (flags.HasFlag(Sections.CA | Sections.ID))
  93. {
  94. Cameras = Cameras.CreateInstance(getFile(".ca"));
  95. WalkMesh = WalkMesh.Load(getFile(".ID"), Cameras);
  96. }
  97. //let's start with scripts
  98. var sJsm = findString(".jsm");
  99. var sSy = findString(".sy");
  100. if (flags.HasFlag(Sections.JSM | Sections.SYM) && !string.IsNullOrWhiteSpace(sJsm) && (FileName != "test3"))
  101. {
  102. JSMObjects = Scripts.Jsm.File.Read(fieldArchive.GetBinaryFile(sJsm));
  103. if (Mod != FieldModes.NoJSM)
  104. {
  105. if (!string.IsNullOrWhiteSpace(sSy))
  106. {
  107. var symObjects = Sym.Reader.FromBytes(fieldArchive.GetBinaryFile(sSy));
  108. Services = Initializer.GetServices();
  109. EventEngine = ServiceId.Field[Services].Engine;
  110. EventEngine.Reset();
  111. for (var objIndex = 0; objIndex < JSMObjects.Count; objIndex++)
  112. {
  113. var obj = JSMObjects[objIndex];
  114. var fieldObject = new FieldObject(obj.Id, symObjects.GetObjectOrDefault(objIndex).Name);
  115. foreach (var script in obj.Scripts)
  116. fieldObject.Scripts.Add(script.ScriptId, script.Segment.GetExecuter());
  117. EventEngine.RegisterObject(fieldObject);
  118. }
  119. Mod++;
  120. }
  121. else
  122. {
  123. Debug.WriteLine($"FileNotFound :: {FileName.ToUpper()}.sy");
  124. //sy file might be optional.
  125. //Mod = Field_modes.NoJSM;
  126. }
  127. }
  128. }
  129. else
  130. {
  131. Mod = FieldModes.NoJSM;
  132. //goto end;
  133. }
  134. //if (flags.HasFlag(Sections.MCH))
  135. //{
  136. // byte[] mchB = getFile(".mch");//Field character models
  137. //}
  138. //if (flags.HasFlag(Sections.ONE))
  139. //{
  140. // byte[] oneB = getFile(".one");//Field character models container
  141. //}
  142. //if (flags.HasFlag(Sections.MSD))
  143. //{
  144. // byte[] msdB = getFile(".msd");//dialogs
  145. //}
  146. if (flags.HasFlag(Sections.INF))
  147. {
  148. var infData = getFile(".inf");//gateways
  149. if (infData != null && infData.Length > 0)
  150. INF = INF.Load(infData);
  151. }
  152. if (flags.HasFlag(Sections.TDW))
  153. {
  154. var tdwData = getFile(".tdw");//extra font
  155. if (tdwData != null && tdwData.Length > 0)
  156. TDW = new TDW(tdwData);
  157. }
  158. if (flags.HasFlag(Sections.MSK))
  159. {
  160. var mskData = getFile(".msk");//movie cam
  161. if (mskData != null && mskData.Length > 0)
  162. MSK = new MSK(mskData);
  163. }
  164. if (flags.HasFlag(Sections.RAT | Sections.MRT))
  165. {
  166. var ratData = getFile(".rat");//battle on field
  167. var mrtData = getFile(".mrt");//battle on field
  168. if (ratData != null && mrtData != null && ratData.Length > 0 && mrtData.Length > 0)
  169. MrtRat = new MrtRat(mrtData, ratData);
  170. }
  171. //if (flags.HasFlag(Sections.PMD))
  172. //{
  173. // byte[] pmdB = getFile(".pmd");//particle info
  174. // if (pmdB != null && pmdB.Length > 4)
  175. // using (FileStream fs = new FileStream(Path.Combine(Path.GetTempPath(),
  176. // $"{Memory.FieldHolder.GetString()}.pmd"), FileMode.Create, FileAccess.Write, FileShare.ReadWrite))
  177. // fs.Write(pmdB, 0, pmdB.Length);
  178. //}
  179. if (flags.HasFlag(Sections.PMP))
  180. {
  181. var pmpData = getFile(".pmp");//particle graphic?
  182. if (pmpData != null && pmpData.Length > 4)
  183. PMP = new PMP(pmpData);
  184. }
  185. if (flags.HasFlag(Sections.SFX))
  186. {
  187. var sfxData = getFile(".sfx");//sound effects
  188. if (sfxData != null && sfxData.Length > 0)
  189. SFX = new SFX(sfxData);
  190. }
  191. if (Mod == FieldModes.NoJSM && Background == null)
  192. {
  193. Mod = FieldModes.Disabled;
  194. }
  195. return SFX != null || PMP != null || MrtRat != null || MSK != null || TDW != null || INF != null ||
  196. JSMObjects != null || EventEngine != null || Cameras != null || WalkMesh != null ||
  197. Background != null || Services != null;
  198. }
  199. public override string ToString() => $"{{{ID}, {FileName}, {Mod}}}";
  200. /*
  201. public HashSet<ushort> GetForcedBattleEncounters() => JSMObjects != null && JSMObjects.Count > 0 ?
  202. (
  203. from jsmObject in JSMObjects
  204. from script in jsmObject.Scripts
  205. from instruction in script.Segment.Flatten()
  206. where instruction is BATTLE
  207. let battle = ((BATTLE)instruction)
  208. select battle.Encounter).ToHashSet() : null;
  209. */
  210. public void Update()
  211. {
  212. switch (Mod)
  213. {
  214. case FieldModes.Init:
  215. break;
  216. case FieldModes.DebugRender:
  217. UpdateScript();
  218. Background?.Update();
  219. break; //await events here
  220. case FieldModes.NoJSM://no scripts but has background.
  221. Background?.Update();
  222. break; //await events here
  223. case FieldModes.Disabled:
  224. break;
  225. default:
  226. throw new ArgumentOutOfRangeException();
  227. }
  228. }
  229. private static void UpdateScript()
  230. {
  231. //We do not know every instruction and it's not possible for now to play field with unknown instruction
  232. //eventEngine.Update(services);
  233. }
  234. #endregion Methods
  235. }
  236. }