FF7NameLookup.h 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534
  1. /*
  2. * Copyright (C) 2022 The V-Gears Team
  3. *
  4. * This file is part of V-Gears
  5. *
  6. * V-Gears is free software: you can redistribute it and/or modify it under
  7. * terms of the GNU General Public License as published by the Free Software
  8. * Foundation, version 3.0 (GPLv3) of the License.
  9. *
  10. * V-Gears is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. */
  15. #pragma once
  16. #include "common/TypeDefine.h"
  17. #include "common/QGearsStringUtil.h"
  18. #include "core/XmlFile.h"
  19. // TODO: Move implementations to cpp file.
  20. namespace QGears{
  21. namespace FF7{
  22. /**
  23. * Handles Final Fantasy VII Metadata.
  24. */
  25. class FF7Metadata : public XmlFile{
  26. public:
  27. /**
  28. * Constructor.
  29. *
  30. * @param file[in] The XML file.
  31. */
  32. FF7Metadata(Ogre::String file) : XmlFile(file){
  33. TiXmlNode* node = file_.RootElement();
  34. if (node == nullptr || node->ValueStr() != "metadata"){
  35. throw std::runtime_error(
  36. "FF7Metadata: " + file_.ValueStr()
  37. + " is not a valid metadata file! "
  38. + "No <metadata> in root."
  39. );
  40. }
  41. node = node->FirstChild();
  42. while (node){
  43. if (
  44. node->Type() == TiXmlNode::TINYXML_ELEMENT
  45. && node->ValueStr() == "models"
  46. ){
  47. ReadModels(node->FirstChild());
  48. }
  49. else if (
  50. node->Type() == TiXmlNode::TINYXML_ELEMENT
  51. && node->ValueStr() == "animations"
  52. ){
  53. ReadAnimations(node->FirstChild());
  54. }
  55. else if (
  56. node->Type() == TiXmlNode::TINYXML_ELEMENT
  57. && node->ValueStr() == "scripts"
  58. ){
  59. ReadScripts(node->FirstChild());
  60. }
  61. node = node->NextSibling();
  62. }
  63. }
  64. /**
  65. * Matches animation names.
  66. *
  67. * Looks for defined names associated to the original game
  68. * animation names. Defined names are more user friendly, more
  69. * readable and more descriptive.
  70. *
  71. * @param key[in] Original game animation name.
  72. * @return Friendly name associated to the animation, or the
  73. * original name if there is no name associated.
  74. */
  75. const String& Animation(const String &key) const{
  76. auto it = animations_.find(key);
  77. if (it != std::end(animations_)) return it->second;
  78. String base_name;
  79. StringUtil::splitBase(key, base_name);
  80. it = animations_.find(base_name);
  81. if (it != std::end(animations_)) return it->second;
  82. return key;
  83. }
  84. /**
  85. * Matches model names.
  86. *
  87. * Looks for defined names associated to the original game
  88. * model names. Defined names are more user friendly, more
  89. * readable and more descriptive.
  90. *
  91. * @param key[in] Original game model name.
  92. * @return Friendly name associated to the model, or the
  93. * original name if there is no name associated.
  94. */
  95. const String& Model(const String &key) const{
  96. auto it = models_.find(key);
  97. if (it != std::end(models_)) return it->second;
  98. String base_name;
  99. StringUtil::splitBase(key, base_name);
  100. it = models_.find(base_name);
  101. if (it != std::end(models_)) return it->second;
  102. return key;
  103. }
  104. private:
  105. /**
  106. * Reads all models from an XML node.
  107. *
  108. * @param node[in] XML node to read.
  109. */
  110. void ReadModels(TiXmlNode* node){
  111. while (node){
  112. const auto src = GetString(node, "name");
  113. const auto dst = GetString(node, "target");
  114. models_[src] = dst;
  115. node = node->NextSibling();
  116. }
  117. }
  118. /**
  119. * Reads all models from an XML node.
  120. *
  121. * @param node[in] XML node to read.
  122. */
  123. void ReadAnimations(TiXmlNode* node){
  124. while (node){
  125. const auto src = GetString(node, "name");
  126. const auto dst = GetString(node, "target");
  127. animations_[src] = dst;
  128. node = node->NextSibling();
  129. }
  130. }
  131. /**
  132. * Reads all scripts from an XML node.
  133. *
  134. * @param node[in] XML node to read.
  135. */
  136. void ReadScripts(TiXmlNode* node){
  137. while (node){
  138. if (
  139. node->Type() == TiXmlNode::TINYXML_ELEMENT
  140. && node->ValueStr() == "CharacterIds"
  141. ){ReadCharacterIds(node->FirstChild());}
  142. else if (
  143. node->Type() == TiXmlNode::TINYXML_ELEMENT
  144. && node->ValueStr() == "var_names"
  145. ){ReadVarNames(node->FirstChild());}
  146. else if (
  147. node->Type() == TiXmlNode::TINYXML_ELEMENT
  148. && node->ValueStr() == "entity_names"
  149. ){ReadEntityNames(node->FirstChild());}
  150. else if (
  151. node->Type() == TiXmlNode::TINYXML_ELEMENT
  152. && node->ValueStr() == "field"
  153. ){
  154. const auto name = GetString(node, "name");
  155. ReadField(node->FirstChild(), name);
  156. }
  157. node = node->NextSibling();
  158. }
  159. }
  160. /**
  161. * Reads field information from an XML node.
  162. *
  163. * @param node[in] XML node to read.
  164. */
  165. void ReadField(TiXmlNode* node, const std::string& name){
  166. while (node){
  167. if (
  168. node->Type() == TiXmlNode::TINYXML_ELEMENT
  169. && node->ValueStr() == "function"
  170. ){ReadFunction(node, name);}
  171. else if (
  172. node->Type() == TiXmlNode::TINYXML_ELEMENT
  173. && node->ValueStr() == "entity"
  174. ){
  175. const auto old_name = GetString(node, "name");
  176. const auto new_name = GetString(node, "new");
  177. field_data_[name].entity_name_map[old_name]
  178. = new_name;
  179. }
  180. node = node->NextSibling();
  181. }
  182. }
  183. /**
  184. * Reads a function of a field from an XML node.
  185. *
  186. * @param node[in] XML node to read.
  187. */
  188. void ReadFunction(
  189. TiXmlNode* node, const std::string& field_name
  190. ){
  191. const auto entity_name = GetString(node, "entity_name");
  192. const auto old_name = GetString(node, "name");
  193. const auto new_name = GetString(node, "new");
  194. const auto comment = GetString(node, "Comment");
  195. field_data_[field_name].function_map[entity_name][old_name]
  196. = std::make_pair(new_name, comment);
  197. }
  198. /**
  199. * Reads all entity from an XML node.
  200. *
  201. * @param node[in] XML node to read.
  202. */
  203. void ReadEntityNames(TiXmlNode* node){
  204. while (node){
  205. if (
  206. node->Type() == TiXmlNode::TINYXML_ELEMENT
  207. && node->ValueStr() == "entity"
  208. ){
  209. const auto old_name = GetString(node, "name");
  210. const auto new_name = GetString(node, "new");
  211. entity_name_map_[old_name] = new_name;
  212. }
  213. node = node->NextSibling();
  214. }
  215. }
  216. /**
  217. * Reads all variable names from an XML node.
  218. *
  219. * @param node[in] XML node to read.
  220. */
  221. void ReadVarNames(TiXmlNode* node){
  222. while (node){
  223. if (
  224. node->Type() == TiXmlNode::TINYXML_ELEMENT
  225. && node->ValueStr() == "var"
  226. ){
  227. const auto bank = GetInt(node, "Bank");
  228. const auto address = GetInt(node, "Address");
  229. const auto name = GetString(node, "Name");
  230. var_map_[bank][address] = name;
  231. }
  232. node = node->NextSibling();
  233. }
  234. }
  235. /**
  236. * Reads all character identifiers from an XML node.
  237. *
  238. * @param node[in] XML node to read.
  239. */
  240. void ReadCharacterIds(TiXmlNode* node){
  241. while (node){
  242. if (
  243. node->Type() == TiXmlNode::TINYXML_ELEMENT
  244. && node->ValueStr() == "char"
  245. ){
  246. const auto id = GetInt(node, "Id");
  247. const auto name = GetString(node, "Name");
  248. character_ids_[id] = name;
  249. node = node->NextSibling();
  250. }
  251. node = node->NextSibling();
  252. }
  253. }
  254. /**
  255. * Retrieves a field script function data.
  256. *
  257. * @param field_name[in] The name of the field from witch to
  258. * get the data.
  259. * @param entity_name[in] Name of the entity rom witch to
  260. * get the data.
  261. * @param old_function_name[in] The original function name.
  262. * @return Associated function name pair. An empty pair if the
  263. * field, entity or function don't exist.
  264. * @todo Verify documentation for old_function name and return
  265. * value.
  266. */
  267. std::pair<String,String> FieldScriptFunctionData(
  268. const String& field_name, const String& entity_name,
  269. const String& old_function_name
  270. ){
  271. // Find a collection of field data for this field.
  272. auto field_iterator = field_data_.find(field_name);
  273. if (field_iterator != std::end(field_data_)){
  274. // See if there is any info for this entity.
  275. auto entity_iterator
  276. = field_iterator->second.function_map.find(
  277. entity_name
  278. );
  279. if (
  280. entity_iterator
  281. != std::end(field_iterator->second.function_map)
  282. ){
  283. // See if there is any info for this function in
  284. // this entity.
  285. auto function_iterator
  286. = entity_iterator->second.find(old_function_name);
  287. if (
  288. function_iterator
  289. != std::end(entity_iterator->second)
  290. ){
  291. return function_iterator->second;
  292. }
  293. }
  294. }
  295. return std::make_pair("", "");
  296. }
  297. typedef std::map<String, String> LookupMap;
  298. /**
  299. * The list of models.
  300. */
  301. LookupMap models_;
  302. /**
  303. * The list of animations.
  304. */
  305. LookupMap animations_;
  306. /**
  307. * Character identifier map.
  308. */
  309. std::map<int, String> character_ids_;
  310. /**
  311. * Variable map.
  312. */
  313. std::map<int, std::map<int, String>> var_map_;
  314. /**
  315. * Entity name map.
  316. */
  317. LookupMap entity_name_map_;
  318. /**
  319. * A field metadata representation.
  320. */
  321. struct FieldMetaData{
  322. /**
  323. * Function map.
  324. *
  325. * Entity name to old function name finds new function name
  326. * and comment.
  327. */
  328. std::map<String, std::map<String, std::pair<String,String>>>
  329. function_map;
  330. /**
  331. * Entity name map.
  332. *
  333. * Old name finds new name
  334. */
  335. LookupMap entity_name_map;
  336. };
  337. std::map<String, FieldMetaData> field_data_;
  338. friend class NameLookup;
  339. };
  340. /**
  341. * Name lookup convenience class.
  342. */
  343. class NameLookup{
  344. public:
  345. /**
  346. * Constructor, not to use.
  347. */
  348. NameLookup() = delete;
  349. /**
  350. * Retrieves a character name from an ID.
  351. */
  352. static String CharName(int char_id){
  353. auto it = Data().character_ids_.find(char_id);
  354. if (it != std::end(Data().character_ids_))
  355. return it->second;
  356. // Empty becomes lua "nil" value for this special case:
  357. if (char_id == 254) return "";
  358. return std::to_string(char_id);
  359. }
  360. /**
  361. * Matches animation names.
  362. *
  363. * Looks for defined names associated to the original game
  364. * animation names. Defined names are more user friendly, more
  365. * readable and more descriptive.
  366. *
  367. * @param key[in] Original game animation name.
  368. * @return Friendly name associated to the animation, or the
  369. * original name if there is no name associated.
  370. */
  371. static const String& Animation(const String &key){
  372. return Data().Animation(key);
  373. }
  374. /**
  375. * Matches model names.
  376. *
  377. * Looks for defined names associated to the original game
  378. * model names. Defined names are more user friendly, more
  379. * readable and more descriptive.
  380. *
  381. * @param key[in] Original game model name.
  382. * @return Friendly name associated to the model, or the
  383. * original name if there is no name associated.
  384. */
  385. static const String& model(const String &key){
  386. return Data().Model(key);
  387. }
  388. /**
  389. * Retrieves a variable name.
  390. *
  391. * Variables that are frequently used across the game may
  392. * have an associated name, more fiendly and descriptive.
  393. *
  394. * @param bank[in] Variable bank.
  395. * @param addr[in] Variable address.
  396. * @return Friendly name associated to the variable, or an
  397. * empty string if it has no associated friendly name.
  398. */
  399. static String FieldScriptVarName(int bank, int addr){
  400. auto bank_iterator = Data().var_map_.find(bank);
  401. if (bank_iterator != std::end(Data().var_map_)){
  402. auto address_iterator
  403. = bank_iterator->second.find(addr);
  404. if (
  405. address_iterator != std::end(bank_iterator->second)
  406. ){
  407. if (address_iterator->second.empty() == false)
  408. return address_iterator->second;
  409. }
  410. }
  411. return "";
  412. }
  413. /**
  414. * Matches entity names.
  415. *
  416. * Looks for defined names associated to the original game
  417. * entity name. Defined names are more user friendly, more
  418. * readable and more descriptive.
  419. *
  420. * @param old_entity_name[in] Original game entity name.
  421. * @return Friendly name associated to the entity, or the
  422. * original name if there is no name associated.
  423. */
  424. static String FieldScriptEntityName(
  425. const String& old_entity_name
  426. ){
  427. auto it = Data().entity_name_map_.find(old_entity_name);
  428. if (it != std::end(Data().entity_name_map_))
  429. return it->second;
  430. return old_entity_name;
  431. }
  432. /**
  433. * Matches function comments.
  434. *
  435. * @param field_name[in] The name of the field from witch to
  436. * get the data.
  437. * @param entity_name[in] Name of the entity rom witch to
  438. * get the data.
  439. * @param old_function_name[in] The original function name.
  440. * @return Associated function name pair. An empty pair if the
  441. * field, entity or function don't exist.
  442. * @todo Does this maps comments, or functions with comments?
  443. */
  444. static String FieldScriptFunctionComment(
  445. const String& field_name, const String& entity_name,
  446. const String& old_function_name){
  447. return Data().FieldScriptFunctionData(
  448. field_name, entity_name, old_function_name
  449. ).second;
  450. }
  451. /**
  452. * Matches function names.
  453. *
  454. * Looks for defined names associated to the original game
  455. * function name. Defined names are more user friendly, more
  456. * readable and more descriptive.
  457. *
  458. * @param field_name[in] The name of the field from witch to
  459. * get the data.
  460. * @param entity_name[in] Name of the entity rom witch to
  461. * get the data.
  462. * @param old_function_name[in] The original function name.
  463. * @return Associated function name, or the original name if
  464. * there is no name associated.
  465. */
  466. static String FieldScriptFunctionName(
  467. const String& field_name, const String& entity_name,
  468. const String& old_function_name
  469. ){
  470. auto name = Data().FieldScriptFunctionData(
  471. field_name, entity_name, old_function_name
  472. ).first;
  473. if (name.empty()) return old_function_name;
  474. return name;
  475. }
  476. /**
  477. * Retrieves game metadata.
  478. *
  479. * @return The game metadata.
  480. */
  481. static FF7Metadata& Data(){
  482. static FF7Metadata data(
  483. "field_models_and_animation_metadata.xml"
  484. );
  485. return data;
  486. }
  487. };
  488. }
  489. }