FieldDataInstaller.h 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687
  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 <vector>
  17. #include <string>
  18. #include <OgreMesh.h>
  19. #include <tinyxml.h>
  20. #include "data/VGearsFLevelFile.h"
  21. #include "ScopedLgp.h"
  22. #include "SpawnPointDb.h"
  23. #include "ModelsAndAnimationsDb.h"
  24. #include "FieldTextWriter.h"
  25. #include "decompiler/field/FieldScriptFormatter.h"
  26. #include "decompiler/field/FieldDecompiler.h"
  27. #include "common/FinalFantasy7/FF7NameLookup.h"
  28. typedef std::vector<std::string> MapList;
  29. typedef std::map<u16, SpawnPointDb> FieldSpawnPointsMap;
  30. typedef std::map<u16, float> FieldScaleFactorMap;
  31. class BaseFF7FieldScriptFormatter : public FieldScriptFormatter{
  32. public:
  33. /**
  34. * Constructor.
  35. *
  36. * @param[in] field_name The field name.
  37. * @param[in] field_id_to_name_lookup Field name lookup table to use.
  38. * @param[in] spawn_points The list of spawn points.
  39. */
  40. BaseFF7FieldScriptFormatter(
  41. const std::string& field_name, const std::vector<std::string>& field_id_to_name_lookup,
  42. FieldSpawnPointsMap& spawn_points
  43. ) :
  44. field_name_(field_name), field_id_to_name_lookup_(field_id_to_name_lookup),
  45. spawn_points_(spawn_points)
  46. {}
  47. /**
  48. * Composes a spawn point name
  49. *
  50. * The name will have the format
  51. * {FIELD_NAME}_{ENTITY}_{FUNCTION_NAME}_addr_{ADDRESS}
  52. *
  53. * @param[in] map_id Unused.
  54. * @param[in] entity Entity name.
  55. * @param[in] function_name Name of the function.
  56. * @param[in] address @todo Understand and document.
  57. * @return The composed spawn point name.
  58. */
  59. virtual std::string GetSpawnPointName(
  60. unsigned int map_id, const std::string& entity,
  61. const std::string& function_name, unsigned int address
  62. ) override{
  63. return
  64. field_name_ + "_" + entity + "_" + function_name + "_addr_" + std::to_string(address);
  65. }
  66. /**
  67. * Retrieves a map name from it's ID.
  68. *
  69. * @param[in] map_id The map ID.
  70. * @return The map name.
  71. */
  72. virtual std::string GetMapName(unsigned int map_id) override{
  73. return field_id_to_name_lookup_[map_id];
  74. }
  75. /**
  76. * Retrieves a user friendly variable name.
  77. *
  78. * @param[in] bank Variable bank.
  79. * @param[in] addr Variable address.
  80. * @return Friendly name for the variable, or an empty string if it
  81. * doesn't have one assigned.
  82. */
  83. virtual std::string GetFriendlyVarName(
  84. unsigned int bank, unsigned int addr
  85. ) override{
  86. return VGears::NameLookup::FieldScriptVarName(bank, addr);
  87. }
  88. /**
  89. * Retrieves a user friendly entity name.
  90. *
  91. * @param[in] entity Entity name.
  92. * @return Friendly name for the entity, or the current name if it
  93. * doesn't have one assigned.
  94. */
  95. virtual std::string GetFriendlyEntityName(const std::string& entity) override{
  96. return VGears::NameLookup::FieldScriptEntityName(entity);
  97. }
  98. /**
  99. * Retrieves a user friendly character name.
  100. *
  101. * @param[in] char_id Character ID.
  102. * @return Friendly name for the entity, or an empty string if it
  103. * doesn't have one assigned.
  104. */
  105. virtual std::string GetFriendlyCharName(int char_id) override{
  106. return VGears::NameLookup::CharName(char_id);
  107. }
  108. /**
  109. * Retrieves a user friendly function name.
  110. *
  111. * @param[in] entity The name of the entity the function belongs to.
  112. * @param[in] function_name Function name.
  113. * @return Friendly name for the function, or the current name if it
  114. * doesn't have one assigned.
  115. */
  116. virtual std::string GetFriendlyFunctionName(
  117. const std::string& entity, const std::string& function_name
  118. ) override{
  119. return VGears::NameLookup::FieldScriptFunctionName(
  120. field_name_, entity, function_name
  121. );
  122. }
  123. /**
  124. * Retrieves the header comment for a function in an entity.
  125. *
  126. * @param[in] entity The name of the entity the function belongs to.
  127. * @param[in] function_name Function name.
  128. * @return Friendly comment for the function, or an empty string if it
  129. * doesn't have one assigned.
  130. */
  131. virtual std::string GetFunctionComment(
  132. const std::string& entity, const std::string& function_name
  133. ) override{
  134. return VGears::NameLookup::FieldScriptFunctionComment(
  135. field_name_, entity, function_name
  136. );
  137. }
  138. protected:
  139. /**
  140. * The field name.
  141. */
  142. std::string field_name_;
  143. /**
  144. * The list of spawn points.
  145. */
  146. FieldSpawnPointsMap& spawn_points_;
  147. /**
  148. * Look up table relatingfield IDs and names.
  149. */
  150. const std::vector<std::string>& field_id_to_name_lookup_;
  151. };
  152. /**
  153. * Handles the script gateway colection.
  154. */
  155. class FF7FieldScriptGatewayCollector : public BaseFF7FieldScriptFormatter{
  156. // TODO: Move declaration to a .h file.
  157. public:
  158. /**
  159. * Cosntructor.
  160. */
  161. FF7FieldScriptGatewayCollector(
  162. const std::string& field_name, const std::vector<std::string>& field_id_to_name_lookup,
  163. FieldSpawnPointsMap& spawn_points, size_t this_field_id
  164. ) :
  165. BaseFF7FieldScriptFormatter(field_name,field_id_to_name_lookup, spawn_points),
  166. field_id_(this_field_id)
  167. {}
  168. /**
  169. * Adds an spawn point.
  170. *
  171. * If the spawn is new, a new record will be added to the spawn point
  172. * database. If it was already there, update the record to add the
  173. * origin.
  174. *
  175. * @param[in] map_id The target map ID.
  176. * @param[in] entity The entity that acts as the spawn point.
  177. * @param[in] function_name The spawn function name.
  178. * @param[in] address @todo Understand and document.
  179. * @param[in] x X coordinate of the field target at which to spawn.
  180. * @param[in] y Y coordinate of the field target at which to spawn.
  181. * @param[in] z Z coordinate of the field target at which to spawn.
  182. * @param[in] angle Orientation at which to spawn.
  183. */
  184. virtual void AddSpawnPoint(
  185. unsigned int map_id, const std::string& entity, const std::string& function_name,
  186. unsigned int address, int x, int y, int z, int angle
  187. ) override {
  188. auto it = spawn_points_.find(map_id);
  189. VGears::TriggersFile::Gateway gw = {};
  190. gw.destination_field_id = map_id;
  191. gw.destination.x = x;
  192. gw.destination.y = y;
  193. gw.destination.z = z;
  194. gw.dir = angle;
  195. if (it != std::end(spawn_points_)){
  196. // Add to the list of gateways that link to destination_field_id.
  197. SpawnPointDb::Record rec;
  198. rec.from_script = true;
  199. rec.field_id = field_id_;
  200. rec.gateway = gw;
  201. rec.entity_name = entity;
  202. rec.script_function_name = function_name;
  203. rec.gateway_index_or_map_jump_address = address;
  204. it->second.gateways_to_this_field.push_back(rec);
  205. }
  206. else{
  207. // Create a new record for destination_field_id
  208. SpawnPointDb db;
  209. db.target_field_id = map_id;
  210. SpawnPointDb::Record rec;
  211. rec.from_script = true;
  212. rec.field_id = field_id_;
  213. rec.gateway = gw;
  214. rec.entity_name = entity;
  215. rec.script_function_name = function_name;
  216. rec.gateway_index_or_map_jump_address = address;
  217. db.gateways_to_this_field.push_back(rec);
  218. spawn_points_.insert(std::make_pair(db.target_field_id, db));
  219. }
  220. }
  221. private:
  222. /**
  223. * The field map ID.
  224. */
  225. size_t field_id_;
  226. };
  227. /**
  228. * Handles the formatting of field scripts.
  229. */
  230. class FF7FieldScriptFormatter : public BaseFF7FieldScriptFormatter{
  231. public:
  232. /**
  233. * Constructor.
  234. *
  235. * @param[in] field_name The field name.
  236. * @param[in] models The list of field models.
  237. * @param[in] field_id_to_name_lookup Field name lookup table to use.
  238. * @param[in] spawn_points The list of spawn points.
  239. */
  240. FF7FieldScriptFormatter(
  241. const std::string& field_name, const VGears::ModelListFilePtr& models,
  242. const std::vector<std::string>& field_id_to_name_lookup,
  243. FieldSpawnPointsMap& spawn_points
  244. ) :
  245. BaseFF7FieldScriptFormatter(field_name, field_id_to_name_lookup, spawn_points),
  246. model_loader_(models)
  247. {}
  248. // Names an animation, can't return empty
  249. /**
  250. * Retreieves an animation name from iths ID.
  251. *
  252. * @param[in] char_id ID of the character the animation belogs to.
  253. * @param[in] id Animation ID.
  254. * @return The animation name. If there is no name assigned, or it
  255. * can't be found, a string with the animation ID.
  256. */
  257. virtual std::string GetFriendlyAnimationName(int char_id, int id) override{
  258. // Get the animation file name, then look up the friendly name of
  259. // the "raw" animation.
  260. if (static_cast<unsigned int>(char_id) >= model_loader_->GetModels().size()){
  261. std::cerr << "FF7FieldScriptFormatter::AnimationName ERROR:"
  262. << "Char ID " << char_id << " out of bounds" << std::endl;
  263. return std::to_string(id);
  264. }
  265. const auto& model_info = model_loader_->GetModels().at(char_id);
  266. if (static_cast<unsigned int>(id) >= model_info.animations.size()){
  267. std::cerr << "FF7FieldScriptFormatter::AnimationName ERROR:"
  268. << "In field " << field_name_ << " the model " << model_info.name
  269. << " animation with ID " << id << " is out of bounds ("
  270. << model_info.animations.size() << ")" << std::endl;
  271. return std::to_string(id);
  272. }
  273. const auto raw_name = model_info.animations.at(id).name;
  274. // Trim off ".yos" or whatever extension the model loader adds in.
  275. Ogre::String base_name;
  276. VGears::StringUtil::splitBase(raw_name, base_name);
  277. VGears::StringUtil::toLowerCase(base_name);
  278. return VGears::NameLookup::Animation(base_name);
  279. }
  280. private:
  281. /**
  282. * The field model loader.
  283. */
  284. const VGears::ModelListFilePtr& model_loader_;
  285. };
  286. class FieldDataInstaller{
  287. public:
  288. /**
  289. * Installer constructor
  290. *
  291. * @param[in] input_dir Path to the directory containing the original
  292. * data to parse.
  293. * @param[in] output_dir Path to the directory to write generated data
  294. * to.
  295. */
  296. FieldDataInstaller(const std::string input_dir, const std::string output_dir);
  297. /**
  298. * Installer destructor.
  299. */
  300. ~FieldDataInstaller();
  301. /**
  302. * Initializer for {@see CollectionFieldSpawnAndScaleFactors}.
  303. *
  304. * Installation step 1.
  305. *
  306. * @param[in] res_mgr The application resource manager.
  307. * @return The total number of level files to process.
  308. */
  309. int CollectSpawnAndScaleFactorsInit(Ogre::ResourceGroupManager* res_mgr);
  310. /**
  311. * Reads spawn points and scale factors from flevel files.
  312. *
  313. * Installation step 2.
  314. *
  315. * @param[in] field_index Index of the field to collect from. Must be less than the value
  316. * returned by {@see CollectSpawnAndScaleFactorsInit}.
  317. */
  318. void CollectSpawnAndScaleFactors(int field_index);
  319. /**
  320. * Converts FFVII PC fields to V-Gears format.
  321. *
  322. * @param[in] field_index Index of the field to collect from. Must be less than the value
  323. * returned by {@see CollectSpawnAndScaleFactorsInit}.
  324. */
  325. void Convert(int field_index);
  326. /**
  327. * Initializer for {@see WriteMapsXmlIteration}.
  328. *
  329. * Installation step 3.
  330. *
  331. * @return The number of converted maps that need to be written.
  332. */
  333. int WriteInit();
  334. /**
  335. * Saves the game maps to XML files.
  336. *
  337. * Installation step 4.
  338. *
  339. * @param[in] field_index Index of the field to collect from. Must be less than the value
  340. * returned by {@see WriteInit}.
  341. */
  342. void Write(int field_index);
  343. /**
  344. * Cleans up after {@see WriteMapsXmlIteration}.
  345. *
  346. * Installation step 5.
  347. */
  348. void WriteEnd();
  349. /**
  350. * Initializer for {@see ConvertFieldModelsIteration}.
  351. *
  352. * Installation step 6.
  353. *
  354. * @return List of names of models to convert.
  355. */
  356. std::vector<std::string> ConvertModelsInit();
  357. /**
  358. * Converts the field models to V-Gears format.
  359. *
  360. * Installation step 7 and final.
  361. *
  362. * @param[in] model_name Name of the model to convert.
  363. */
  364. void ConvertModels(std::string model_name);
  365. private:
  366. /**
  367. * Creates a gateway script.
  368. *
  369. * @param[in] gateway_entity_name Name of the gateway entity.
  370. * @param[in] target_map_name Name of the target map.
  371. * @param[in] source_spawn_point_name The spawn point name.
  372. * @return Gateway LUA script.
  373. */
  374. static std::string CreateGateWayScript(
  375. const std::string& gateway_entity_name, const std::string& target_map_name,
  376. const std::string& source_spawn_point_name
  377. );
  378. /**
  379. * Retrieves a field ID from a name.
  380. *
  381. * @param[in] name The name of the field.
  382. * @param[in] field_id_to_name_lookup Lookup table to use.
  383. * @return The field ID for the specified name.
  384. * @throws std::runtime_error If there is no ID for the field name.
  385. */
  386. static size_t GetFieldId(
  387. const std::string& name, const std::vector<std::string>& field_id_to_name_lookup
  388. );
  389. /**
  390. * Checks if a file is a field file.
  391. *
  392. * To verify it, it just checks that the extension is not '.tex', '.tut' or
  393. * '.siz' and that the name is not 'maplist'.
  394. *
  395. * @param[in] resource_name The name of the file to test.
  396. * @return False if the file is surely not a field file, true otherwise.
  397. */
  398. static bool IsAFieldFile(const Ogre::String& resource_name);
  399. /**
  400. * Checks if a map cause fatal crash bugs.
  401. *
  402. * It uses a hardcoded list of maps that are known to cause errors. This can be
  403. * removed when whatever is causing the crash(s) is fixed.
  404. *
  405. * NOTE: Even so, conversion of all models will fail with a bone index out of
  406. * bounds.
  407. *
  408. * @param[in] resource_name The name of the map file to test.
  409. * @return True if the map will crash, false otherwise.
  410. */
  411. static bool WillCrash(const Ogre::String& resource_name);
  412. /**
  413. * Checks if a map is a test field.
  414. *
  415. * It uses a hardcoded list of maps that are known to be test maps. Unused maps
  416. * are considered to be test maps.
  417. *
  418. * @param[in] resource_name The name of the map file to test.
  419. * @return True if the map is a test map, false otherwise.
  420. */
  421. static bool IsTestField(const Ogre::String& resource_name);
  422. /**
  423. * Collects the scale factor from a map.
  424. *
  425. * @param[in] field The field to collect from.
  426. * @param[out] scale_factors The scale factor for the map will be set here, in
  427. * the appropiate map entry.
  428. * @param[in] field_id_to_name_lookup Lookup table to relate field IDs and
  429. * names.
  430. */
  431. static void CollectFieldScaleFactors(
  432. VGears::FLevelFilePtr& field, FieldScaleFactorMap& scale_factors,
  433. const std::vector<std::string>& field_id_to_name_lookup
  434. );
  435. /**
  436. * Collects the spawn point from a field.
  437. *
  438. * If a spawn is new, a new record will be added to the spawn point database.
  439. * If it was already there, update the record to add the origin.
  440. *
  441. * @param[in] field The field to collect from.
  442. * @param[in] field_id_to_name_lookup Lookup table to relate field IDs and
  443. * names.
  444. * @param[out] spawn_points Spawn points will be added sequentially to the end
  445. * of this map.
  446. */
  447. static void CollectSpawnPoints(
  448. VGears::FLevelFilePtr& field, const std::vector<std::string>& field_id_to_name_lookup,
  449. FieldSpawnPointsMap& spawn_points
  450. );
  451. /**
  452. * The scale factor for line point coordinates.
  453. *
  454. * When a LINE opcode is found in the game scripts, the line points X and Y coordinates
  455. * must be scaled down by this factor.
  456. */
  457. static float LINE_SCALE_FACTOR;
  458. /**
  459. * Path to the field models directory.
  460. */
  461. static std::string FIELD_MODELS_DIR;
  462. /**
  463. * Path to the field maps directory.
  464. */
  465. static std::string FIELD_MAPS_DIR;
  466. /**
  467. * Gateways to this map ID are considered to be inactive.
  468. */
  469. static int INACTIVE_GATEWAY_ID;
  470. /**
  471. * Exports a mesh to a file.
  472. *
  473. * The file will have the mesh name.
  474. *
  475. * @param[in] outdir Path to the directory where the file will be saved.
  476. * @param[in] mesh The mesh to export.
  477. */
  478. void ExportMesh(const std::string outdir, const Ogre::MeshPtr &mesh);
  479. /**
  480. * Converts a FFVII PC field to a V-Gears field.
  481. *
  482. * @param[in] field The field map to convert.
  483. */
  484. void PcFieldToVGearsField(VGears::FLevelFilePtr& field);
  485. /**
  486. * Retrieves a field scale factor.
  487. *
  488. * @param[in] field_id The id (name) of the field.
  489. * @return The scale factor for the map.
  490. * @throws std::runtime_error If there is no ID for the field name.
  491. */
  492. float GetFieldScaleFactor(size_t field_id);
  493. /**
  494. * Creates a directory in the outputh path.
  495. *
  496. * @param[in] dir Path of the directory to create, relative to the
  497. * output path..
  498. * @throws std::runtime_error If the directory can't be created.
  499. */
  500. void CreateDir(const std::string& dir);
  501. /**
  502. * The path to the directory from which to read the PC game data.
  503. */
  504. std::string input_dir_;
  505. /**
  506. * The path to the directory where to save the V-Gears data.
  507. */
  508. std::string output_dir_;
  509. /**
  510. * Helper variable to indicate internal progress of installation steps.
  511. */
  512. size_t conversion_step_;
  513. /**
  514. * Helper variable to indicate internal progress of installation steps.
  515. */
  516. size_t progress_step_num_elements_;
  517. /**
  518. * Iterator counter.
  519. */
  520. size_t iterator_counter_;
  521. /**
  522. * LGP archive with field data.
  523. */
  524. std::unique_ptr<ScopedLgp> fields_lgp_;
  525. /**
  526. * LGP archive with texture data.
  527. */
  528. std::unique_ptr<ScopedLgp> textures_lgp_;
  529. /**
  530. * LGP archive with field model data.
  531. */
  532. std::unique_ptr<ScopedLgp> field_models_lgp_;
  533. /**
  534. * List of flevel files.
  535. */
  536. Ogre::StringVectorPtr flevel_file_list_;
  537. /**
  538. * The list of maps.
  539. */
  540. std::vector<std::string> map_list_;
  541. /**
  542. * Map of the collected spawn points.
  543. */
  544. FieldSpawnPointsMap spawn_points_;
  545. /**
  546. * Map of th collected scale factors.
  547. */
  548. FieldScaleFactorMap scale_factors_;
  549. /**
  550. * ModelsAndAnimationsUsedByConvertedFields
  551. */
  552. ModelsAndAnimationsDb used_models_and_anims_;
  553. /**
  554. * List of converted maps.
  555. */
  556. MapList converted_map_list_;
  557. /**
  558. * Iterator for {@see converted_map_list}.
  559. */
  560. MapList::iterator converted_map_list_iterator_;
  561. /**
  562. * Field currently being processed.
  563. */
  564. VGears::FLevelFilePtr field_;
  565. /**
  566. * List of model files.
  567. */
  568. Ogre::StringVectorPtr field_model_file_list_;
  569. /**
  570. * An XML document.
  571. *
  572. * Internally used during some installation steps.
  573. */
  574. std::unique_ptr<TiXmlDocument> doc_;
  575. /**
  576. * An XML element.
  577. *
  578. * Internally used during some installation steps.
  579. */
  580. std::unique_ptr<TiXmlElement> element_;
  581. /**
  582. * Iterator for {@see used_models_and_anims_}.
  583. */
  584. ModelAnimationMap::iterator model_animation_map_iterator_;
  585. /**
  586. * Function used to print text to the log output, line by line.
  587. */
  588. std::function<void(std::string)> write_output_line_;
  589. /**
  590. * Function used to print set the current installation progress text.
  591. */
  592. std::function<void(std::string)> set_progress_label_;
  593. /**
  594. * Field text writer.
  595. */
  596. FieldTextWriter field_text_writer_;
  597. /**
  598. * Written materials.
  599. */
  600. std::vector<std::string> materials_;
  601. };