DataInstaller.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453
  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. #include <QtCore/QDir>
  16. #include <boost/filesystem.hpp>
  17. #include "DataInstaller.h"
  18. float DataInstaller::LINE_SCALE_FACTOR = 0.0078124970964f;
  19. DataInstaller::DataInstaller(
  20. const std::string input_dir, const std::string output_dir, AdvancedOptions options,
  21. std::function<void(std::string, int, bool)> write_output_line
  22. )
  23. #ifdef _DEBUG
  24. : application_("plugins_d.cfg", "resources_d.cfg", "install_d.log"),
  25. #else
  26. : application_("plugins.cfg", "resources.cfg", "install.log"),
  27. #endif
  28. input_dir_(input_dir), output_dir_(output_dir),
  29. options_(options), write_output_line_(write_output_line)
  30. {
  31. if (!application_.initOgre(true)) throw std::runtime_error("Ogre init failure");
  32. Ogre::Log* default_log(Ogre::LogManager::getSingleton().getDefaultLog());
  33. assert( default_log );
  34. default_log->setLogDetail(Ogre::LL_LOW);
  35. // Assign weights.
  36. for (int i = IDLE; i < STATE_COUNT; i ++) step_weight_[i] = 1;
  37. step_weight_[IDLE] = 0;
  38. step_weight_[MEDIA_IMAGES] = 3;
  39. step_weight_[MEDIA_SOUNDS] = 8;
  40. step_weight_[MEDIA_MUSICS] = 9;
  41. step_weight_[MEDIA_MUSICS_HQ] = 2;
  42. step_weight_[FIELD_SPAWN_POINTS_AND_SCALE_FACTORS] = 3;
  43. step_weight_[FIELD_CONVERT] = 3;
  44. step_weight_[FIELD_WRITE] = 2;
  45. step_weight_[FIELD_CONVERT_MODELS] = 3;
  46. }
  47. DataInstaller::~DataInstaller(){}
  48. float DataInstaller::Progress(){
  49. switch (installation_state_){
  50. case IDLE:
  51. installation_state_ = CREATE_DIRECTORIES;
  52. return CalcProgress();
  53. case CREATE_DIRECTORIES:
  54. write_output_line_("Creating directories...", 2, true);
  55. CreateDirectories();
  56. installation_state_ = INITIALIZE;
  57. return CalcProgress();
  58. case INITIALIZE:
  59. write_output_line_("Initializing installers...", 2, true);
  60. kernel_installer_ = std::make_unique<KernelDataInstaller>(input_dir_);
  61. media_installer_ = std::make_unique<MediaDataInstaller>(
  62. input_dir_, output_dir_, options_.keep_originals,
  63. options_.no_ffmpeg, options_.no_timidity
  64. );
  65. field_installer_ = std::make_unique<FieldDataInstaller>(input_dir_, output_dir_);
  66. battle_installer_ = std::make_unique<BattleDataInstaller>(
  67. input_dir_, output_dir_, application_.ResMgr()
  68. );
  69. installation_state_ = BATTLE_SCENES_INIT;
  70. return CalcProgress();
  71. case BATTLE_SCENES_INIT:
  72. // Skip kernel data if option is set.
  73. if (options_.skip_battle_data){
  74. write_output_line_("Skipping battle data installation...", 2, true);
  75. installation_state_ = BATTLE_MODELS_INIT;
  76. return CalcProgress();
  77. }
  78. write_output_line_("Parsing battle scenes...", 2, true);
  79. substeps_ = battle_installer_->InitializeScenes();
  80. cur_substep_ = 0;
  81. installation_state_ = BATTLE_SCENES_PROCESS;
  82. return CalcProgress();
  83. case BATTLE_SCENES_PROCESS:
  84. cur_substep_ = battle_installer_->ProcessScene();
  85. if (cur_substep_ >= substeps_) installation_state_ = BATTLE_SCENES_WRITE_ATTACKS;
  86. return CalcProgress();
  87. case BATTLE_SCENES_WRITE_ATTACKS:
  88. write_output_line_("Saving attacks...", 2, true);
  89. cur_substep_ = 0;
  90. substeps_ = 0;
  91. battle_installer_->WriteAttacks();
  92. installation_state_ = BATTLE_SCENES_WRITE_ENEMIES;
  93. return CalcProgress();
  94. case BATTLE_SCENES_WRITE_ENEMIES:
  95. write_output_line_("Saving enemies...", 2, true);
  96. cur_substep_ = 0;
  97. substeps_ = 0;
  98. battle_installer_->WriteEnemies();
  99. installation_state_ = BATTLE_SCENES_WRITE_FORMATIONS;
  100. return CalcProgress();
  101. case BATTLE_SCENES_WRITE_FORMATIONS:
  102. write_output_line_("Saving enemy formations...", 2, true);
  103. cur_substep_ = 0;
  104. substeps_ = 0;
  105. battle_installer_->WriteFormations();
  106. installation_state_ = BATTLE_MODELS_INIT;
  107. return CalcProgress();
  108. case BATTLE_MODELS_INIT:
  109. // Skip kernel data if option is set.
  110. if (options_.skip_battle_models){
  111. write_output_line_("Skipping battle models installation...", 2, true);
  112. installation_state_ = KERNEL_PRICES;
  113. return CalcProgress();
  114. }
  115. write_output_line_("Extracting battle models...", 2, true);
  116. substeps_ = battle_installer_->InitializeModels();
  117. cur_substep_ = 0;
  118. installation_state_ = BATTLE_MODELS_PROCESS;
  119. return CalcProgress();
  120. case BATTLE_MODELS_PROCESS:
  121. cur_substep_ = battle_installer_->ProcessModel();
  122. if (cur_substep_ >= substeps_) installation_state_ = BATTLE_MODELS_CONVERT_INIT;
  123. return CalcProgress();
  124. case BATTLE_MODELS_CONVERT_INIT:
  125. cur_substep_ = 0;
  126. substeps_ = battle_installer_->ConvertModelsInit();
  127. installation_state_ = BATTLE_MODELS_CONVERT;
  128. return CalcProgress();
  129. case BATTLE_MODELS_CONVERT:
  130. cur_substep_ = battle_installer_->ConvertModel();
  131. if (cur_substep_ >= substeps_) installation_state_ = BATTLE_MODELS_WRITE_CHARACTERS;
  132. return CalcProgress();
  133. case BATTLE_MODELS_WRITE_CHARACTERS:
  134. write_output_line_("Writing character data...", 2, true);
  135. battle_installer_->WriteCharacterData();
  136. installation_state_ = BATTLE_MODELS_WRITE_SCENES;
  137. return CalcProgress();
  138. case BATTLE_MODELS_WRITE_SCENES:
  139. write_output_line_("Writing battle scene data...", 2, true);
  140. battle_installer_->WriteSceneData();
  141. installation_state_ = KERNEL_PRICES;
  142. return CalcProgress();
  143. case KERNEL_PRICES:
  144. // Skip kernel data if option is set.
  145. if (options_.skip_kernel){
  146. write_output_line_("Skipping kernel data installation...", 2, true);
  147. installation_state_ = MEDIA_SOUNDS_INIT;
  148. return CalcProgress();
  149. }
  150. write_output_line_("Parsing item and materia prices...", 2, true);
  151. kernel_installer_->ReadPrices();
  152. installation_state_ = KERNEL_COMMANDS;
  153. return CalcProgress();
  154. case KERNEL_COMMANDS:
  155. write_output_line_("Extracting command data...", 2, true);
  156. kernel_installer_->ReadCommands();
  157. kernel_installer_->WriteCommands(output_dir_ + "gamedata/commands.lua");
  158. installation_state_ = KERNEL_ATTACKS;
  159. return CalcProgress();
  160. case KERNEL_ATTACKS:
  161. write_output_line_("Extracting attack data...", 2, true);
  162. kernel_installer_->ReadAttacks();
  163. kernel_installer_->WriteAttacks(output_dir_ + "gamedata/attacks.lua");
  164. installation_state_ = KERNEL_CHARACTERS;
  165. return CalcProgress();
  166. case KERNEL_CHARACTERS:
  167. write_output_line_("Extracting character data...", 2, true);
  168. kernel_installer_->ReadCharacters();
  169. kernel_installer_->WriteCharacters(output_dir_ + "gamedata/characters.lua");
  170. installation_state_ = KERNEL_ITEMS;
  171. return CalcProgress();
  172. case KERNEL_ITEMS:
  173. write_output_line_("Extracting item data...", 2, true);
  174. kernel_installer_->ReadItems();
  175. kernel_installer_->WriteItems(output_dir_ + "gamedata/items.lua");
  176. installation_state_ = KERNEL_GROWTH;
  177. return CalcProgress();
  178. case KERNEL_GROWTH:
  179. write_output_line_("Extracting growth data...", 2, true);
  180. kernel_installer_->ReadGrowth();
  181. kernel_installer_->WriteGrowth(output_dir_ + "gamedata/growth.lua");
  182. installation_state_ = KERNEL_WEAPONS;
  183. return CalcProgress();
  184. case KERNEL_WEAPONS:
  185. write_output_line_("Extracting weapon data...", 2, true);
  186. kernel_installer_->ReadWeapons();
  187. kernel_installer_->WriteWeapons(output_dir_ + "gamedata/weapons.lua");
  188. installation_state_ = KERNEL_ARMORS;
  189. return CalcProgress();
  190. case KERNEL_ARMORS:
  191. write_output_line_("Extracting armor data...", 2, true);
  192. kernel_installer_->ReadArmors();
  193. kernel_installer_->WriteArmors(output_dir_ + "gamedata/armors.lua");
  194. installation_state_ = KERNEL_ACCESSORIES;
  195. return CalcProgress();
  196. case KERNEL_ACCESSORIES:
  197. write_output_line_("Extracting accessory data...", 2, true);
  198. kernel_installer_->ReadAccessories();
  199. kernel_installer_->WriteAccessories(output_dir_ + "gamedata/accessories.lua");
  200. installation_state_ = KERNEL_MATERIA;
  201. return CalcProgress();
  202. case KERNEL_MATERIA:
  203. write_output_line_("Extracting materia data...", 2, true);
  204. kernel_installer_->ReadMateria();
  205. kernel_installer_->WriteMateria(output_dir_ + "gamedata/materia.lua");
  206. installation_state_ = KERNEL_KEY_ITEMS;
  207. return CalcProgress();
  208. case KERNEL_KEY_ITEMS:
  209. write_output_line_("Extracting key item data...", 2, true);
  210. kernel_installer_->ReadKeyItems();
  211. kernel_installer_->WriteKeyItems(output_dir_ + "gamedata/key_items.lua");
  212. installation_state_ = KERNEL_SUMMON_NAMES;
  213. return CalcProgress();
  214. case KERNEL_SUMMON_NAMES:
  215. write_output_line_("Extracting summon attack names data...", 2, true);
  216. kernel_installer_->ReadSummonNames();
  217. kernel_installer_->WriteSummonNames(output_dir_ + "gamedata/summons.lua");
  218. installation_state_ = KERNEL_SAVEMAP;
  219. return CalcProgress();
  220. case KERNEL_SAVEMAP:
  221. write_output_line_("Extracting the initial savemap...", 2, true);
  222. kernel_installer_->ReadInitialSaveMap();
  223. kernel_installer_->WriteInitialSaveMap(output_dir_ + "gamedata/initial_savemap.lua");
  224. installation_state_ = MEDIA_IMAGES;
  225. return CalcProgress();
  226. case MEDIA_IMAGES:
  227. // Skip images if option is set.
  228. if (options_.skip_images){
  229. write_output_line_("Skipping images installation...", 2, true);
  230. installation_state_ = MEDIA_SOUNDS_INIT;
  231. return CalcProgress();
  232. }
  233. write_output_line_("Extracting game images...", 2, true);
  234. media_installer_->InstallSprites();
  235. installation_state_ = MEDIA_SOUNDS_INIT;
  236. return CalcProgress();
  237. case MEDIA_SOUNDS_INIT:
  238. // Skip sounds if option is set.
  239. if (options_.skip_sounds){
  240. write_output_line_("Skipping sound effects installation...", 2, true);
  241. installation_state_ = MEDIA_MUSICS_INIT;
  242. return CalcProgress();
  243. }
  244. write_output_line_("Extracting sounds...", 2, true);
  245. substeps_ = media_installer_->InstallSoundsInit();
  246. installation_state_ = MEDIA_SOUNDS;
  247. cur_substep_ = 0;
  248. return CalcProgress();
  249. case MEDIA_SOUNDS:
  250. if (media_installer_->InstallSounds() == true)
  251. installation_state_ = MEDIA_SOUNDS_INDEX;
  252. else cur_substep_ ++;
  253. return CalcProgress();
  254. case MEDIA_SOUNDS_INDEX:
  255. write_output_line_("Building sound index...", 2, true);
  256. media_installer_->WriteSoundIndex();
  257. installation_state_ = MEDIA_MUSICS_INIT;
  258. return CalcProgress();
  259. case MEDIA_MUSICS_INIT:
  260. // Skip music if option is set.
  261. if (options_.skip_music){
  262. write_output_line_("Skipping music tracks installation...", 2, true);
  263. installation_state_ = FIELD_SPAWN_POINTS_AND_SCALE_FACTORS_INIT;
  264. return CalcProgress();
  265. }
  266. write_output_line_("Extracting music...", 2, true);
  267. substeps_ = media_installer_->InstallMusicsInit();
  268. installation_state_ = MEDIA_MUSICS;
  269. cur_substep_ = 0;
  270. return CalcProgress();
  271. case MEDIA_MUSICS:
  272. if (media_installer_->InstallMusics() == true)
  273. installation_state_ = MEDIA_MUSICS_HQ;
  274. else cur_substep_ ++;
  275. return CalcProgress();
  276. case MEDIA_MUSICS_HQ:
  277. substeps_ = 0;
  278. cur_substep_ = 0;
  279. media_installer_->InstallHQMusics();
  280. installation_state_ = MEDIA_MUSICS_INDEX;
  281. return CalcProgress();
  282. case MEDIA_MUSICS_INDEX:
  283. write_output_line_("Building music track index...", 2, true);
  284. media_installer_->WriteMusicsIndex();
  285. installation_state_ = FIELD_SPAWN_POINTS_AND_SCALE_FACTORS_INIT;
  286. return CalcProgress();
  287. case FIELD_SPAWN_POINTS_AND_SCALE_FACTORS_INIT:
  288. // Skip fields if option is set.
  289. if (options_.skip_fields){
  290. write_output_line_("Skipping field maps installation...", 2, true);
  291. installation_state_ = CLEAN;
  292. return CalcProgress();
  293. }
  294. write_output_line_("Collecting spawn points and scale factors...", 2, true);
  295. substeps_ = field_installer_->CollectSpawnAndScaleFactorsInit(application_.ResMgr());
  296. cur_substep_ = 0;
  297. installation_state_ = FIELD_SPAWN_POINTS_AND_SCALE_FACTORS;
  298. return CalcProgress();
  299. case FIELD_SPAWN_POINTS_AND_SCALE_FACTORS:
  300. field_installer_->CollectSpawnAndScaleFactors(cur_substep_);
  301. cur_substep_ ++;
  302. if (cur_substep_ == substeps_){
  303. installation_state_ = FIELD_CONVERT;
  304. cur_substep_ = 0;
  305. }
  306. return CalcProgress();
  307. case FIELD_CONVERT:
  308. field_installer_->Convert(cur_substep_);
  309. cur_substep_ ++;
  310. if (cur_substep_ == substeps_){
  311. installation_state_ = FIELD_WRITE_INIT;
  312. cur_substep_ = 0;
  313. }
  314. return CalcProgress();
  315. case FIELD_WRITE_INIT:
  316. write_output_line_("Writing fields...", 2, true);
  317. substeps_ = field_installer_->WriteInit();
  318. cur_substep_ = 0;
  319. installation_state_ = FIELD_WRITE;
  320. return CalcProgress();
  321. case FIELD_WRITE:
  322. field_installer_->Write(cur_substep_);
  323. cur_substep_ ++;
  324. if (cur_substep_ == substeps_){
  325. installation_state_ = FIELD_WRITE_END;
  326. cur_substep_ = 0;
  327. }
  328. return CalcProgress();
  329. case FIELD_WRITE_END:
  330. field_installer_->WriteEnd();
  331. installation_state_ = FIELD_CONVERT_MODELS_INIT;
  332. return CalcProgress();
  333. case FIELD_CONVERT_MODELS_INIT:
  334. // Skip fields if option is set.
  335. if (options_.skip_field_models){
  336. write_output_line_("Skipping field maps installation...", 2, true);
  337. installation_state_ = CLEAN;
  338. return CalcProgress();
  339. }
  340. write_output_line_("Converting field models...", 2, true);
  341. field_model_names_ = field_installer_->ConvertModelsInit();
  342. substeps_ = field_model_names_.size();
  343. cur_substep_ = 0;
  344. installation_state_ = FIELD_CONVERT_MODELS;
  345. return CalcProgress();
  346. case FIELD_CONVERT_MODELS:
  347. field_installer_->ConvertModels(field_model_names_[cur_substep_]);
  348. cur_substep_ ++;
  349. if (cur_substep_ == substeps_){
  350. installation_state_ = CLEAN;
  351. cur_substep_ = 0;
  352. }
  353. return CalcProgress();
  354. case CLEAN:
  355. write_output_line_("Cleaning up...", 2, true);
  356. if (!options_.keep_originals) CleanInstall();
  357. installation_state_ = DONE;
  358. return CalcProgress();
  359. case DONE:
  360. write_output_line_("Installation complete", 2, true);
  361. return 100;
  362. default:
  363. return 100;
  364. }
  365. }
  366. const float DataInstaller::CalcProgress(){
  367. float weight_total = 0; // Sum of every step weight.
  368. float weight_done = 0; // Sum of every previous step weight.
  369. float weight = static_cast<float>(step_weight_[installation_state_]); // Weight of current step.
  370. float weight_substeps = 0; // Weight of the already done substeps in current step.
  371. for (int i = IDLE; i < STATE_COUNT; i ++){
  372. weight_total += step_weight_[i];
  373. if (installation_state_ > i) weight_done += step_weight_[i];
  374. }
  375. if (substeps_ > 0 && cur_substep_ < substeps_){
  376. weight_substeps = (cur_substep_ * weight) / substeps_;
  377. }
  378. float progress = 100 * (weight_done + weight_substeps) / weight_total;
  379. if (progress >= 100.0f) progress = 99.9f;
  380. return progress;
  381. }
  382. void DataInstaller::CreateDirectories(){
  383. CreateDir("audio/musics");
  384. CreateDir("audio/sounds");
  385. CreateDir("fields");
  386. CreateDir("fonts");
  387. CreateDir("temp");
  388. CreateDir("temp/char");
  389. CreateDir("temp/battle_models");
  390. CreateDir("gamedata");
  391. CreateDir("gamedata/enemy");
  392. CreateDir("gamedata/attack");
  393. CreateDir("gamedata/formation");
  394. CreateDir("images/icons");
  395. CreateDir("images/other");
  396. CreateDir("images/characters");
  397. CreateDir("images/fonts");
  398. CreateDir("images/reels");
  399. CreateDir("images/window");
  400. CreateDir("screens");
  401. CreateDir("scripts");
  402. CreateDir("system");
  403. CreateDir("texts");
  404. CreateDir("models/fields/");
  405. CreateDir("models/battle/characters");
  406. CreateDir("models/battle/scenes");
  407. CreateDir("models/battle/enemies");
  408. application_.ResMgr()->addResourceLocation(
  409. output_dir_ + "temp/char/", "FileSystem", "FFVII", true, true
  410. );
  411. application_.ResMgr()->addResourceLocation(
  412. output_dir_ + "temp/battle_models/", "FileSystem", "FFVII", true, true
  413. );
  414. application_.ResMgr()->addResourceLocation(
  415. output_dir_ + "models/", "FileSystem", "FFVII", true, true
  416. );
  417. application_.ResMgr()->addResourceLocation(
  418. output_dir_ + "models/fields/", "FileSystem", "FFVIITextures", true, true
  419. );
  420. application_.ResMgr()->addResourceLocation(
  421. output_dir_ + "models/battle/characters/", "FileSystem", "FFVIITextures", true, true
  422. );
  423. application_.ResMgr()->addResourceLocation(
  424. output_dir_ + "models/battle/scenes/", "FileSystem", "FFVIITextures", true, true
  425. );
  426. application_.ResMgr()->addResourceLocation(
  427. output_dir_ + "models/battle/enemies/", "FileSystem", "FFVIITextures", true, true
  428. );
  429. fields_lgp_ = std::make_unique<ScopedLgp>(
  430. application_.getRoot(), input_dir_ + "data/field/flevel.lgp", "LGP", "FFVIIFields"
  431. );
  432. }
  433. void DataInstaller::CleanInstall(){boost::filesystem::remove_all(output_dir_ + "data/temp/");}
  434. void DataInstaller::CreateDir(const std::string& path){
  435. QString target = QString::fromStdString(output_dir_ + path);
  436. QDir dir(target);
  437. if (!dir.mkpath(".")) throw std::runtime_error("Failed to mkpath");
  438. }