VGearsApplication.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  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 <cstdlib>
  16. #include <iostream>
  17. #include <boost/filesystem.hpp>
  18. #include <boost/program_options.hpp>
  19. #include <OgreConfigFile.h>
  20. #include <OgreArchiveManager.h>
  21. #include <OgreLogManager.h>
  22. #include <OgreConfigDialog.h>
  23. #include "common/VGearsApplication.h"
  24. #include "common/DataDirectory.h"
  25. #include "common/OgrePlugins.h"
  26. #include "VGearsGameState.h"
  27. #include "data/VGearsAFileManager.h"
  28. #include "data/VGearsBackgroundFileManager.h"
  29. #include "data/VGearsCameraMatrixFileManager.h"
  30. #include "data/VGearsHRCFileManager.h"
  31. #include "data/VGearsLZSFLevelFileManager.h"
  32. #include "data/VGearsPaletteFileManager.h"
  33. #include "data/VGearsPFileManager.h"
  34. #include "data/VGearsRSDFileManager.h"
  35. #include "data/VGearsTexCodec.h"
  36. #include "map/VGearsBackground2DFileManager.h"
  37. #include "map/VGearsWalkmeshFileManager.h"
  38. #include "data/FinalFantasy7/FF7ModelListFileManager.h"
  39. #include "data/VGearsLGPArchiveFactory.h"
  40. #include "data/VGearsTriggersFile.h"
  41. #include "data/VGearsMapListFile.h"
  42. #include "Version.h"
  43. /**
  44. * Application singleton.
  45. */
  46. template<> VGears::Application* Ogre::Singleton<VGears::Application>::msSingleton = nullptr;
  47. /**
  48. * Directory with the Ogre plugins, found when V-Gears was built. Set by CMake (VGEARS_OGRE_PLUGIN_DIR).
  49. */
  50. #ifndef VGEARS_OGRE_PLUGIN_DIR
  51. #define VGEARS_OGRE_PLUGIN_DIR ""
  52. #endif
  53. namespace VGears{
  54. namespace bfs = boost::filesystem;
  55. namespace bpo = boost::program_options;
  56. typedef Ogre::ConfigFile::SettingsMultiMap SettingsMultiMap;
  57. const char* Application::CLI_SECTION_GENERIC("Generic options");
  58. const char* Application::CLI_HELP("help");
  59. const char* Application::CLI_HELP_DESCRIPTION("This help message");
  60. const char* Application::CLI_CONFIG_FILE("config-file");
  61. const char* Application::CLI_CONFIG_FILE_DESCRIPTION(
  62. "Path to Ogre config file containing selected rendersystem and resolution"
  63. );
  64. const char* Application::CLI_LOG_FILE("log-file");
  65. const char* Application::CLI_LOG_FILE_DESCRIPTION("Path to log file");
  66. const char* Application::CLI_PLUGINS_FILE("plugins-file");
  67. const char* Application::CLI_PLUGINS_FILE_DESCRIPTION(
  68. "Path to config file containing available plugins"
  69. );
  70. const char* Application::CLI_RESOURCES_FILE("resources-file");
  71. const char* Application::CLI_RESOURCES_FILE_DESCRIPTION(
  72. "path to config file containing available resources"
  73. );
  74. const char* Application::CLI_DATA_DIR("data-dir");
  75. const char* Application::CLI_DATA_DIR_DESCRIPTION(
  76. "Directory with the game data and configuration, where saves and logs are written. "
  77. "Defaults to $VGEARS_DATA_DIR, the current directory if it has the V-Gears files, or ~/.v-gears"
  78. );
  79. Application::Application(int argc, char *argv[]): _argc(argc), _argv(argv){}
  80. Application::~Application(){destroyComponents();}
  81. bool Application::initOgre(bool hideWindow){
  82. if(_initialized) return false;
  83. _initialized = true;
  84. if (_argc && _argv){
  85. if (!processCommandLine(_argc, _argv)) return false;
  86. }
  87. // No plugins file is passed to Ogre: the plugins are looked for in several places, see loadPlugins.
  88. _root = std::make_unique<Ogre::Root>("", config_filename_, log_filename_);
  89. loadPlugins();
  90. _overlay_system = std::make_unique<Ogre::OverlaySystem>();
  91. Ogre::Log* default_log(
  92. Ogre::LogManager::getSingleton().getDefaultLog()
  93. );
  94. assert(default_log);
  95. default_log->setLogDetail(Ogre::LL_BOREME);
  96. // configure
  97. // Show the configuration dialog and initialise the system
  98. // You can skip this and use root.restoreConfig() to load configuration
  99. // settings if you were sure there are valid ones saved in ogre.cfg
  100. // IVV ERROR COMPILING
  101. if(/* !_root->restoreConfig() &&*/ !_root->showConfigDialog(NULL)){
  102. return false;
  103. }
  104. if (hideWindow){
  105. Ogre::NameValuePairList list;
  106. list.emplace("hidden", "true");
  107. _root->initialise(false, getWindowTitle());
  108. //
  109. _render_window = _root->createRenderWindow(getWindowTitle(), 1, 1, false, &list);
  110. }
  111. else{
  112. _render_window = _root->initialise(false, getWindowTitle());
  113. // TODO: Get actual resolution from config
  114. _render_window = _root->createRenderWindow(getWindowTitle(), 1024, 768, false);
  115. }
  116. registerArchiveFactories();
  117. loadResourcesConfig();
  118. initComponents();
  119. return true;
  120. }
  121. void Application::loadPlugins(){
  122. const bfs::path plugins_file(bfs::absolute(bfs::path(plugins_filename_)));
  123. OgrePlugins::Config config;
  124. if (!OgrePlugins::ReadConfig(plugins_file, config))
  125. throw std::runtime_error("The Ogre plugins file can't be read: " + plugins_file.string());
  126. const std::vector<bfs::path> directories(OgrePlugins::SearchDirectories(
  127. plugins_file.parent_path(), config.folder,
  128. DataDirectory::ExecutableDirectory(_argc > 0 && _argv ? _argv[0] : nullptr), VGEARS_OGRE_PLUGIN_DIR
  129. ));
  130. const String ogre_version(
  131. std::to_string(OGRE_VERSION_MAJOR) + "." + std::to_string(OGRE_VERSION_MINOR) + "."
  132. + std::to_string(OGRE_VERSION_PATCH)
  133. );
  134. for (const String& name : config.plugins){
  135. const bfs::path file(OgrePlugins::Find(name, directories, ogre_version));
  136. if (file.empty()){
  137. String searched;
  138. for (const bfs::path& directory : directories) searched += "\n " + directory.string();
  139. throw std::runtime_error(
  140. "The Ogre plugin " + name + " (listed in " + plugins_file.string() + ") was not found in:"
  141. + searched
  142. );
  143. }
  144. Ogre::LogManager::getSingleton().logMessage("Loading Ogre plugin " + file.string());
  145. try{
  146. _root->loadPlugin(file.string());
  147. }
  148. catch (const Ogre::Exception& e){
  149. // The exception can point to strings of the plugin library, which is unloaded when the root is
  150. // destroyed, before the exception is caught in main. Copy the message now.
  151. throw std::runtime_error(
  152. "The Ogre plugin " + file.string() + " could not be loaded: " + e.getFullDescription()
  153. );
  154. }
  155. }
  156. }
  157. void Application::loadResourcesConfig(){
  158. // Load resource paths from config file
  159. Ogre::ConfigFile config_file;
  160. config_file.load(resources_filename_);
  161. // Go through all sections & settings in the file
  162. Ogre::ConfigFile::SectionIterator section(config_file.getSectionIterator());
  163. Ogre::String section_name, archive_type, archive_name;
  164. res_mgr_ = (&Ogre::ResourceGroupManager::getSingleton());
  165. while(section.hasMoreElements()){
  166. section_name = section.peekNextKey();
  167. SettingsMultiMap *settings(section.getNext());
  168. SettingsMultiMap::const_iterator it(settings->begin());
  169. SettingsMultiMap::const_iterator end(settings->end());
  170. while(it != end){
  171. archive_type = it->first;
  172. archive_name = it->second;
  173. res_mgr_->addResourceLocation(archive_name, archive_type, section_name, true);
  174. ++ it;
  175. }
  176. }
  177. }
  178. Ogre::Root* Application::getRoot(){return _root.get();}
  179. Ogre::RenderWindow* Application::getRenderWindow(){return _render_window;}
  180. const String& Application::getResourcesFilename(){
  181. return resources_filename_;
  182. }
  183. String Application::getWindowTitle() const {return VGEARS_VERSION_SIGNATURE;}
  184. bool Application::processCommandLine( int argc, char *argv[]){
  185. bfs::path self(argv[0]);
  186. const String self_stem(self.stem().string());
  187. const String config_filename(self_stem + EXT_CONFIG);
  188. const String log_filename(self_stem + EXT_LOG);
  189. #ifdef NDEBUG
  190. const String plugins_filename("plugins" + EXT_CONFIG);
  191. const String resources_filename("resources" + EXT_CONFIG);
  192. #else
  193. const String plugins_filename("plugins_d" + EXT_CONFIG);
  194. const String resources_filename("resources_d" + EXT_CONFIG);
  195. #endif
  196. bpo::options_description generic(CLI_SECTION_GENERIC);
  197. generic.add_options()
  198. (CLI_HELP, CLI_HELP_DESCRIPTION)
  199. ( CLI_CONFIG_FILE
  200. , bpo::value< String >()->default_value(config_filename)
  201. , CLI_CONFIG_FILE_DESCRIPTION
  202. )
  203. ( CLI_LOG_FILE
  204. , bpo::value< String >()->default_value(log_filename)
  205. , CLI_LOG_FILE_DESCRIPTION
  206. )
  207. ( CLI_PLUGINS_FILE
  208. , bpo::value< String >()->default_value(plugins_filename)
  209. , CLI_PLUGINS_FILE_DESCRIPTION
  210. )
  211. ( CLI_RESOURCES_FILE
  212. , bpo::value< String >()->default_value(resources_filename)
  213. , CLI_RESOURCES_FILE_DESCRIPTION
  214. )
  215. ( CLI_DATA_DIR
  216. , bpo::value< String >()
  217. , CLI_DATA_DIR_DESCRIPTION
  218. )
  219. ;
  220. bpo::variables_map vm;
  221. bpo::store(bpo::command_line_parser(argc, argv).options(generic).run(), vm);
  222. if (vm.count(CLI_HELP)){
  223. std::cout << "Usage: " << self_stem << "\n" << generic << "\n";
  224. return false;
  225. }
  226. bpo::notify(vm);
  227. // The game changes into the data directory, so the files given in the command line are made absolute first.
  228. // The default ones are left relative, to be found in the data directory.
  229. const bfs::path start_directory(bfs::current_path());
  230. auto file_option = [&](const char* name) -> String{
  231. const String value(vm[name].as<String>());
  232. if (vm[name].defaulted() || value.empty()) return value;
  233. return bfs::absolute(bfs::path(value), start_directory).lexically_normal().string();
  234. };
  235. config_filename_ = file_option(CLI_CONFIG_FILE);
  236. log_filename_ = file_option(CLI_LOG_FILE);
  237. plugins_filename_ = file_option(CLI_PLUGINS_FILE);
  238. resources_filename_ = file_option(CLI_RESOURCES_FILE);
  239. String requested_directory;
  240. if (vm.count(CLI_DATA_DIR)) requested_directory = vm[CLI_DATA_DIR].as<String>();
  241. else if (const char* env = std::getenv(DataDirectory::ENV_DATA_DIR)) requested_directory = env;
  242. const DataDirectory::Resolution data_directory(DataDirectory::Resolve(
  243. requested_directory, start_directory, DataDirectory::DefaultDirectory(),
  244. DataDirectory::TemplateCandidates(DataDirectory::ExecutableDirectory(argv[0]))
  245. ));
  246. if (!data_directory.error.empty()){
  247. std::cerr << "V-Gears can't start: " << data_directory.error << std::endl;
  248. return false;
  249. }
  250. if (data_directory.seeded){
  251. std::cout << "Copied " << data_directory.copied_files << " V-Gears files from "
  252. << data_directory.template_directory.string() << " to " << data_directory.directory.string()
  253. << ". Run v-gears-installer to add the data of the original game." << std::endl;
  254. }
  255. boost::system::error_code ec;
  256. bfs::current_path(data_directory.directory, ec);
  257. if (ec){
  258. std::cerr << "V-Gears can't start: can't use the data directory " << data_directory.directory.string()
  259. << ": " << ec.message() << std::endl;
  260. return false;
  261. }
  262. std::cout << "Data directory: " << data_directory.directory.string() << std::endl;
  263. return true;
  264. }
  265. void Application::registerArchiveFactories(){
  266. Ogre::ArchiveManager::getSingleton().addArchiveFactory(
  267. new LGPArchiveFactory()
  268. );
  269. }
  270. void Application::initComponents(){
  271. VGears::TexCodec::install();
  272. VGears::TexCodec::initialise();
  273. createResourceManagers();
  274. }
  275. void Application::destroyComponents(){
  276. destroyResourceManagers();
  277. VGears::TexCodec::shutdown();
  278. VGears::TexCodec::uninstall();
  279. }
  280. void Application::createResourceManagers(){
  281. assert(_resource_managers.empty());
  282. _resource_managers.emplace_back(
  283. std::make_shared<VGears::CameraMatrixFileManager>()
  284. );
  285. _resource_managers.emplace_back(
  286. std::make_shared<VGears::PaletteFileManager>()
  287. );
  288. _resource_managers.emplace_back(
  289. std::make_shared<VGears::WalkmeshFileManager>()
  290. );
  291. _resource_managers.emplace_back(
  292. std::make_shared<VGears::ModelListFileManager>()
  293. );
  294. _resource_managers.emplace_back(
  295. std::make_shared<VGears::HRCFileManager>()
  296. );
  297. _resource_managers.emplace_back(
  298. std::make_shared<VGears::RSDFileManager>()
  299. );
  300. _resource_managers.emplace_back(
  301. std::make_shared<VGears::AFileManager>()
  302. );
  303. _resource_managers.emplace_back(
  304. std::make_shared<VGears::PFileManager>()
  305. );
  306. _resource_managers.emplace_back(
  307. std::make_shared<VGears::LZSFLevelFileManager>()
  308. );
  309. _resource_managers.emplace_back(
  310. std::make_shared<VGears::BackgroundFileManager>()
  311. );
  312. _resource_managers.emplace_back(
  313. std::make_shared<VGears::Background2DFileManager>()
  314. );
  315. _resource_managers.emplace_back(
  316. std::make_shared<VGears::TriggersFileManager>()
  317. );
  318. _resource_managers.emplace_back(
  319. std::make_shared<VGears::MapListFileManager>()
  320. );
  321. }
  322. void Application::destroyResourceManagers(){_resource_managers.clear();}
  323. }