DumpMonsterAndCharacterDat.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. using System;
  2. using System.Collections.Concurrent;
  3. using System.Collections.Generic;
  4. using System.Globalization;
  5. using System.IO;
  6. using System.Linq;
  7. using System.Threading.Tasks;
  8. using System.Xml;
  9. using OpenVIII.Battle;
  10. using OpenVIII.Battle.Dat;
  11. using Abilities = OpenVIII.Battle.Dat.Abilities;
  12. namespace OpenVIII.Dat_Dump
  13. {
  14. internal static class DumpMonsterAndCharacterDat
  15. {
  16. #region Fields
  17. public static ConcurrentDictionary<int, DatFile> MonsterData = new ConcurrentDictionary<int, DatFile>();
  18. private static readonly ConcurrentDictionary<int, DatFile> CharacterData = new ConcurrentDictionary<int, DatFile>();
  19. #endregion Fields
  20. #region Properties
  21. private static string Ls => CultureInfo.CurrentCulture.TextInfo.ListSeparator;
  22. #endregion Properties
  23. #region Methods
  24. public static async Task LoadMonsters()
  25. {
  26. if (!MonsterData.IsEmpty) return;
  27. //one issue with this is animations aren't loaded. because it requires all the geometry and skeleton loaded...
  28. // so the sequence dump is probably less useful or broken.
  29. Task<bool> addMonster(int i)
  30. => Task.Run(() => MonsterData.TryAdd(i,
  31. MonsterDatFile.CreateInstance(i,
  32. Sections.AnimationSequences | Sections.Information)));
  33. await Task.WhenAll(Enumerable.Range(0, 200).Select(addMonster));
  34. }
  35. public static async Task Process()
  36. {
  37. var xmlWriterSettings = new XmlWriterSettings
  38. {
  39. Indent = true,
  40. IndentChars = "\t", // note: default is two spaces
  41. NewLineOnAttributes = true,
  42. OmitXmlDeclaration = false
  43. };
  44. using (var csv2File = new StreamWriter(new FileStream("MonsterAttacks.csv", FileMode.Create, FileAccess.Write, FileShare.ReadWrite), System.Text.Encoding.UTF8))
  45. {
  46. using (var csvFile = new StreamWriter(new FileStream("SequenceDump.csv", FileMode.Create, FileAccess.Write, FileShare.ReadWrite), System.Text.Encoding.UTF8))
  47. {
  48. await LoadMonsters();
  49. //header for monster attacks
  50. csv2File.WriteLine($"{nameof(Enemy)}{Ls}" +
  51. $"{nameof(Enemy.EII.Data.FileName)}{Ls}" +
  52. $"{nameof(Abilities)}{Ls}" +
  53. $"Number{Ls}" +
  54. $"{nameof(Abilities.Animation)}{Ls}" +
  55. $"Type{Ls}" +
  56. $"ID{Ls}" +
  57. $"Name{Ls}");
  58. //header for animation info
  59. csvFile.WriteLine($"Type{Ls}Type ID{Ls}Name{Ls}Animation Count{Ls}Sequence Count{Ls}Sequence ID{Ls}Offset{Ls}Bytes");
  60. using (var xmlWriter = XmlWriter.Create("SequenceDump.xml", xmlWriterSettings))
  61. {
  62. xmlWriter.WriteStartDocument();
  63. xmlWriter.WriteStartElement("dat");
  64. XmlMonsterData(xmlWriter, csvFile, csv2File);
  65. XmlCharacterData(xmlWriter, csvFile);
  66. xmlWriter.WriteEndElement();
  67. xmlWriter.WriteEndDocument();
  68. }
  69. }
  70. }
  71. Console.Write("Press [Enter] key to continue... ");
  72. Console.ReadLine();
  73. }
  74. private static string XmlAnimations(XmlWriter xmlWriter, DatFile battleDatFile)
  75. {
  76. var count = $"{battleDatFile.Animations.Count}";
  77. xmlWriter.WriteStartElement("animations");
  78. xmlWriter.WriteAttributeString("Count", count);
  79. xmlWriter.WriteEndElement();
  80. return count;
  81. }
  82. private static void XmlCharacterData(XmlWriter xmlWriter, TextWriter csvFile)
  83. {
  84. xmlWriter.WriteStartElement("characters");
  85. for (var i = 0; i <= 10; i++)
  86. {
  87. DatFile test = CharacterDatFile.CreateInstance(i, 0);
  88. if (test != null && CharacterData.TryAdd(i, test))
  89. {
  90. }
  91. if (!CharacterData.TryGetValue(i, out var battleDat) || battleDat == null) continue;
  92. const string type = "character";
  93. xmlWriter.WriteStartElement(type);
  94. var id = i.ToString();
  95. xmlWriter.WriteAttributeString("ID", id);
  96. var name = Memory.Strings.GetName((Characters)i);
  97. xmlWriter.WriteAttributeString("name", name);
  98. var prefix0 = $"{type}{Ls}{id}{Ls}";
  99. var prefix1 = $"{name}";
  100. prefix1 += $"{Ls}{XmlAnimations(xmlWriter, battleDat)}";
  101. XmlSequences(xmlWriter, battleDat, csvFile, $"{prefix0}{prefix1}");
  102. XmlWeaponData(xmlWriter, i, ref battleDat, csvFile, prefix1);
  103. xmlWriter.WriteEndElement();
  104. }
  105. xmlWriter.WriteEndElement();
  106. }
  107. private static void XmlMonsterData(XmlWriter xmlWriter, StreamWriter csvFile, TextWriter csv2File)
  108. {
  109. xmlWriter.WriteStartElement("monsters");
  110. for (var i = 0; i <= 200; i++)
  111. {
  112. if (!MonsterData.TryGetValue(i, out var battleDat) || battleDat == null) continue;
  113. const string type = "monster";
  114. var id = i.ToString();
  115. var name = battleDat.Information.Name ?? new FF8String("");
  116. var prefix = $"{type}{Ls}{id}{Ls}{name}";
  117. xmlWriter.WriteStartElement(type);
  118. xmlWriter.WriteAttributeString("ID", id);
  119. xmlWriter.WriteAttributeString("name", name);
  120. prefix += $"{Ls}{XmlAnimations(xmlWriter, battleDat)}";
  121. XmlSequences(xmlWriter, battleDat, csvFile, prefix);
  122. xmlWriter.WriteEndElement();
  123. var e = Enemy.Load(new EnemyInstanceInformation { Data = battleDat });
  124. void addAbility(string fieldName, Abilities a, int number)
  125. {
  126. csv2File.WriteLine($"{name}{Ls}" +
  127. $"{battleDat.FileName}{Ls}" +
  128. $"{fieldName}{Ls}" +
  129. $"{number}{Ls}" +
  130. $"{a.Animation}{Ls}" +
  131. $"{(a.Item != null ? nameof(a.Item) : a.Magic != null ? nameof(a.Magic) : a.Monster != null ? nameof(a.Monster) : "")}{Ls}" +
  132. $"{a.Item?.ID ?? (a.Magic?.MagicDataID ?? (a.Monster?.EnemyAttackID ?? 0))}{Ls}" +
  133. $"\"{(a.Item != null ? a.Item.Value.Name : a.Magic != null ? a.Magic.Name : a.Monster != null ? a.Monster.Name : new FF8String(""))}\"{Ls}");
  134. }
  135. void addAbilities(string fieldName, IReadOnlyList<Abilities> abilities)
  136. {
  137. if (abilities == null) return;
  138. for (var number = 0; number < e.Info.AbilitiesLow.Length; number++)
  139. {
  140. var a = abilities[number];
  141. addAbility(fieldName, a, number);
  142. }
  143. }
  144. addAbilities(nameof(e.Info.AbilitiesLow), e.Info.AbilitiesLow);
  145. addAbilities(nameof(e.Info.AbilitiesMed), e.Info.AbilitiesMed);
  146. addAbilities(nameof(e.Info.AbilitiesHigh), e.Info.AbilitiesHigh);
  147. }
  148. xmlWriter.WriteEndElement();
  149. }
  150. private static void XmlSequences(XmlWriter xmlWriter, DatFile battleDatFile, TextWriter csvFile, string prefix)
  151. {
  152. xmlWriter.WriteStartElement("sequences");
  153. var count = $"{battleDatFile.Sequences?.Count ?? 0}";
  154. xmlWriter.WriteAttributeString("Count", count);
  155. if (battleDatFile.Sequences != null)
  156. foreach (var s in battleDatFile.Sequences)
  157. {
  158. xmlWriter.WriteStartElement("sequence");
  159. var id = s.ID.ToString();
  160. var offset = s.Offset.ToString("X");
  161. var bytes = s.Count.ToString();
  162. xmlWriter.WriteAttributeString("ID", id);
  163. xmlWriter.WriteAttributeString("offset", offset);
  164. xmlWriter.WriteAttributeString("bytes", bytes);
  165. csvFile?.Write($"{prefix ?? ""}{Ls}{count}{Ls}{id}{Ls}{s.Offset}{Ls}{bytes}");
  166. foreach (var b in s)
  167. {
  168. xmlWriter.WriteString($"{b:X2} ");
  169. csvFile?.Write($"{Ls}{b}");
  170. }
  171. csvFile?.Write(Environment.NewLine);
  172. xmlWriter.WriteEndElement();
  173. }
  174. csvFile?.Flush();
  175. xmlWriter.WriteEndElement();
  176. }
  177. private static void XmlWeaponData(XmlWriter xmlWriter, int characterID, ref DatFile r, TextWriter csvFile, string prefix1)
  178. {
  179. var weaponData = new ConcurrentDictionary<int, DatFile>();
  180. xmlWriter.WriteStartElement("weapons");
  181. for (var i = 0; i <= 40; i++)
  182. {
  183. DatFile test;
  184. if (characterID == 1 || characterID == 9)
  185. test = WeaponDatFile.CreateInstance(characterID, i, r);
  186. else
  187. test = WeaponDatFile.CreateInstance(characterID, i);
  188. if (test != null && weaponData.TryAdd(i, test))
  189. {
  190. }
  191. if (!weaponData.TryGetValue(i, out var battleDat) || battleDat == null) continue;
  192. const string type = "weapon";
  193. var id = i.ToString();
  194. xmlWriter.WriteStartElement(type);
  195. xmlWriter.WriteAttributeString("ID", id);
  196. var index = ModuleBattleDebug.Weapons[(Characters) characterID]?.Select(((b, i1) => new {i, b}))
  197. .FirstOrDefault(v => v.b == i)?.i;
  198. if(!index.HasValue) continue;
  199. var currentWeaponData = Memory.KernelBin.WeaponsData.FirstOrDefault(v =>
  200. v.Character == (Characters) characterID && v.AltID == checked((byte)index.Value));
  201. if (currentWeaponData != default)
  202. {
  203. xmlWriter.WriteAttributeString("name", currentWeaponData.Name);
  204. var prefix = $"{type}{Ls}{id}{Ls}{currentWeaponData.Name}/{prefix1}"; //bringing over name from character.
  205. //xmlWriter.WriteAttributeString("name", Memory.Strings.GetName((Characters)i));
  206. XmlAnimations(xmlWriter, battleDat);
  207. XmlSequences(xmlWriter, battleDat, csvFile, prefix);
  208. }
  209. xmlWriter.WriteEndElement();
  210. }
  211. xmlWriter.WriteEndElement();
  212. }
  213. #endregion Methods
  214. }
  215. }