| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286 |
- using System;
- using System.Collections.Concurrent;
- using System.Collections.Generic;
- using System.Globalization;
- using System.IO;
- using System.Linq;
- using System.Threading.Tasks;
- using System.Xml;
- using OpenVIII.Battle;
- using OpenVIII.Battle.Dat;
- using Abilities = OpenVIII.Battle.Dat.Abilities;
- namespace OpenVIII.Dat_Dump
- {
- internal static class DumpMonsterAndCharacterDat
- {
- #region Fields
- public static ConcurrentDictionary<int, DatFile> MonsterData = new ConcurrentDictionary<int, DatFile>();
- private static readonly ConcurrentDictionary<int, DatFile> CharacterData = new ConcurrentDictionary<int, DatFile>();
- #endregion Fields
- #region Properties
- private static string Ls => CultureInfo.CurrentCulture.TextInfo.ListSeparator;
- #endregion Properties
- #region Methods
- public static async Task LoadMonsters()
- {
- if (!MonsterData.IsEmpty) return;
- //one issue with this is animations aren't loaded. because it requires all the geometry and skeleton loaded...
- // so the sequence dump is probably less useful or broken.
- Task<bool> addMonster(int i)
- => Task.Run(() => MonsterData.TryAdd(i,
- MonsterDatFile.CreateInstance(i,
- Sections.AnimationSequences | Sections.Information)));
- await Task.WhenAll(Enumerable.Range(0, 200).Select(addMonster));
- }
- public static async Task Process()
- {
- var xmlWriterSettings = new XmlWriterSettings
- {
- Async = true, // Enable async operations
- Indent = true,
- IndentChars = "\t", // note: default is two spaces
- NewLineOnAttributes = true,
- OmitXmlDeclaration = false
- };
- using (var csv2File = new StreamWriter(new FileStream("MonsterAttacks.csv", FileMode.Create, FileAccess.Write, FileShare.ReadWrite), System.Text.Encoding.UTF8))
- {
- using (var csvFile = new StreamWriter(new FileStream("SequenceDump.csv", FileMode.Create, FileAccess.Write, FileShare.ReadWrite), System.Text.Encoding.UTF8))
- {
- await LoadMonsters();
- //header for monster attacks
- await csv2File.WriteLineAsync($"{nameof(Enemy)}{Ls}" +
- $"{nameof(Enemy.EII.Data.FileName)}{Ls}" +
- $"{nameof(Abilities)}{Ls}" +
- $"Number{Ls}" +
- $"{nameof(Abilities.Animation)}{Ls}" +
- $"Type{Ls}" +
- $"ID{Ls}" +
- $"Name{Ls}");
- //header for animation info
- await csvFile.WriteLineAsync($"Type{Ls}Type ID{Ls}Name{Ls}Animation Count{Ls}Sequence Count{Ls}Sequence ID{Ls}Offset{Ls}Bytes");
- using (var xmlWriter = XmlWriter.Create("SequenceDump.xml", xmlWriterSettings))
- {
- await xmlWriter.WriteStartDocumentAsync();
- await xmlWriter.WriteStartElementAsync(null, "dat", null);
- await XmlMonsterDataAsync(xmlWriter, csvFile, csv2File);
- await XmlCharacterDataAsync(xmlWriter, csvFile);
- await xmlWriter.WriteEndElementAsync();
- await xmlWriter.WriteEndDocumentAsync();
- }
- }
- }
- }
- private static async Task<string> XmlAnimationsAsync(XmlWriter xmlWriter, DatFile battleDatFile)
- {
- var count = $"{battleDatFile.Animations.Count}";
- await xmlWriter.WriteStartElementAsync(null, "animations", null);
- await xmlWriter.WriteAttributeStringAsync(null, "Count", null, count);
- await xmlWriter.WriteEndElementAsync();
- return count;
- }
- private static async Task XmlCharacterDataAsync(XmlWriter xmlWriter, TextWriter csvFile)
- {
- await xmlWriter.WriteStartElementAsync(null, "characters", null);
- for (var i = 0; i <= 10; i++)
- {
- DatFile test = CharacterDatFile.CreateInstance(i, 0);
- if (test != null && CharacterData.TryAdd(i, test))
- {
- // Character data added successfully
- }
- if (!CharacterData.TryGetValue(i, out var battleDat) || battleDat == null) continue;
- const string type = "character";
- await xmlWriter.WriteStartElementAsync(null, type, null);
- var id = i.ToString();
- await xmlWriter.WriteAttributeStringAsync(null, "ID", null, id);
- var name = Memory.Strings.GetName((Characters)i);
- await xmlWriter.WriteAttributeStringAsync(null, "name", null, name);
- var prefix0 = $"{type}{Ls}{id}{Ls}";
- var prefix1 = $"{name}";
- prefix1 += $"{Ls}{await XmlAnimationsAsync(xmlWriter, battleDat)}"; // Assuming XmlAnimations is async-safe
- await XmlSequencesAsync(xmlWriter, battleDat, csvFile, $"{prefix0}{prefix1}"); // Assuming XmlSequences is now async
- await XmlWeaponDataAsync(xmlWriter, i, battleDat, csvFile, prefix1); // Assuming XmlWeaponData is async
- await xmlWriter.WriteEndElementAsync(); // End of "character"
- }
- await xmlWriter.WriteEndElementAsync(); // End of "characters"
- }
- private static async Task XmlMonsterDataAsync(XmlWriter xmlWriter, StreamWriter csvFile, TextWriter csv2File)
- {
- await xmlWriter.WriteStartElementAsync(null, "monsters", null);
- for (var i = 0; i <= 200; i++)
- {
- if (!MonsterData.TryGetValue(i, out var battleDat) || battleDat == null) continue;
- const string type = "monster";
- var id = i.ToString();
- var name = battleDat.Information.Name ?? new FF8String("");
- var prefix = $"{type}{Ls}{id}{Ls}{name}";
- await xmlWriter.WriteStartElementAsync(null, type, null);
- await xmlWriter.WriteAttributeStringAsync(null, "ID", null, id);
- await xmlWriter.WriteAttributeStringAsync(null, "name", null, name);
- prefix += $"{Ls}{await XmlAnimationsAsync(xmlWriter, battleDat)}"; // Assuming XmlAnimations is async-safe
- await XmlSequencesAsync(xmlWriter, battleDat, csvFile, prefix); // Assuming XmlSequences is now async
- await xmlWriter.WriteEndElementAsync(); // End of "monster"
- var e = Enemy.Load(new EnemyInstanceInformation { Data = battleDat });
- async Task addAbilityAsync(string fieldName, Abilities a, int number)
- {
- await csv2File.WriteLineAsync($"{name}{Ls}" +
- $"{battleDat.FileName}{Ls}" +
- $"{fieldName}{Ls}" +
- $"{number}{Ls}" +
- $"{a.Animation}{Ls}" +
- $"{(a.Item != null ? nameof(a.Item) : a.Magic != null ? nameof(a.Magic) : a.Monster != null ? nameof(a.Monster) : "")}{Ls}" +
- $"{a.Item?.ID ?? (a.Magic?.MagicDataID ?? (a.Monster?.EnemyAttackID ?? 0))}{Ls}" +
- $"\"{(a.Item != null ? a.Item.Value.Name : a.Magic != null ? a.Magic.Name : a.Monster != null ? a.Monster.Name : new FF8String(""))}\"{Ls}");
- }
- async Task addAbilitiesAsync(string fieldName, IReadOnlyList<Abilities> abilities)
- {
- if (abilities == null) return;
- for (var number = 0; number < e.Info.AbilitiesLow.Length; number++)
- {
- var a = abilities[number];
- await addAbilityAsync(fieldName, a, number);
- }
- }
- await addAbilitiesAsync(nameof(e.Info.AbilitiesLow), e.Info.AbilitiesLow);
- await addAbilitiesAsync(nameof(e.Info.AbilitiesMed), e.Info.AbilitiesMed);
- await addAbilitiesAsync(nameof(e.Info.AbilitiesHigh), e.Info.AbilitiesHigh);
- }
- await xmlWriter.WriteEndElementAsync(); // End of "monsters"
- }
- private static async Task XmlSequencesAsync(XmlWriter xmlWriter, DatFile battleDatFile, TextWriter csvFile, string prefix)
- {
- await xmlWriter.WriteStartElementAsync(null, "sequences", null);
- var count = $"{battleDatFile.Sequences?.Count ?? 0}";
- await xmlWriter.WriteAttributeStringAsync(null, "Count", null, count);
- if (battleDatFile.Sequences != null)
- {
- foreach (var s in battleDatFile.Sequences)
- {
- await xmlWriter.WriteStartElementAsync(null, "sequence", null);
- var id = s.ID.ToString();
- var offset = s.Offset.ToString("X");
- var bytes = s.Count.ToString();
- await xmlWriter.WriteAttributeStringAsync(null, "ID", null, id);
- await xmlWriter.WriteAttributeStringAsync(null, "offset", null, offset);
- await xmlWriter.WriteAttributeStringAsync(null, "bytes", null, bytes);
- if (csvFile != null)
- {
- await csvFile.WriteAsync($"{prefix ?? ""}{Ls}{count}{Ls}{id}{Ls}{s.Offset}{Ls}{bytes}");
- }
- foreach (var b in s)
- {
- await xmlWriter.WriteStringAsync($"{b:X2} ");
- if (csvFile != null)
- {
- await csvFile.WriteAsync($"{Ls}{b}");
- }
- }
- if (csvFile != null)
- {
- await csvFile.WriteLineAsync();
- }
- await xmlWriter.WriteEndElementAsync(); // End of "sequence"
- }
- }
- if (csvFile != null)
- {
- await csvFile.FlushAsync(); // Ensure async flush
- }
- await xmlWriter.WriteEndElementAsync(); // End of "sequences"
- }
- private static async Task XmlWeaponDataAsync(XmlWriter xmlWriter, int characterID, DatFile r, TextWriter csvFile, string prefix1)
- {
- var weaponData = new ConcurrentDictionary<int, DatFile>();
- await xmlWriter.WriteStartElementAsync(null, "weapons", null);
- for (var i = 0; i <= 40; i++)
- {
- DatFile test;
- if (characterID == 1 || characterID == 9)
- test = WeaponDatFile.CreateInstance(characterID, i, r);
- else
- test = WeaponDatFile.CreateInstance(characterID, i);
- if (test != null && weaponData.TryAdd(i, test))
- {
- // Weapon data added successfully
- }
- if (!weaponData.TryGetValue(i, out var battleDat) || battleDat == null) continue;
- const string type = "weapon";
- var id = i.ToString();
- await xmlWriter.WriteStartElementAsync(null, type, null);
- await xmlWriter.WriteAttributeStringAsync(null, "ID", null, id);
- var index = ModuleBattleDebug.Weapons[(Characters)characterID]?.Select(((b, i1) => new { i, b }))
- .FirstOrDefault(v => v.b == i)?.i;
- if (!index.HasValue) continue;
- var currentWeaponData = Memory.KernelBin.WeaponsData.FirstOrDefault(v =>
- v.Character == (Characters)characterID && v.AltID == checked((byte)index.Value));
- if (currentWeaponData != default)
- {
- await xmlWriter.WriteAttributeStringAsync(null, "name", null, currentWeaponData.Name);
- var prefix = $"{type}{Ls}{id}{Ls}{currentWeaponData.Name}/{prefix1}"; // Bringing over name from character.
- await XmlAnimationsAsync(xmlWriter, battleDat); // Assuming XmlAnimations is now async
- await XmlSequencesAsync(xmlWriter, battleDat, csvFile, prefix); // Assuming XmlSequences is async
- }
- await xmlWriter.WriteEndElementAsync(); // End of "weapon"
- }
- await xmlWriter.WriteEndElementAsync(); // End of "weapons"
- }
- #endregion Methods
- }
- }
|