From c09a3172f1e8288351ed0dbf1f4926984d02bd51 Mon Sep 17 00:00:00 2001 From: konstin Date: Wed, 5 Mar 2014 12:11:20 +0100 Subject: [PATCH] Solving Issue 1180 - Load addon GPs from local folder --- src/config/user_config.hpp | 25 ++++---- src/io/file_manager.cpp | 6 +- src/io/file_manager.hpp | 101 ++++++++++++++++---------------- src/main.cpp | 40 +++++++++---- src/race/grand_prix_data.cpp | 55 +++++++++++------ src/race/grand_prix_data.hpp | 10 +++- src/race/grand_prix_manager.cpp | 48 +++++++++------ src/race/grand_prix_manager.hpp | 5 +- 8 files changed, 174 insertions(+), 116 deletions(-) diff --git a/src/config/user_config.hpp b/src/config/user_config.hpp index 10affd8ae..f44ef4c57 100644 --- a/src/config/user_config.hpp +++ b/src/config/user_config.hpp @@ -396,45 +396,48 @@ namespace UserConfigParams PARAM_DEFAULT( BoolUserConfigParam(false, "player_last", &m_gp_start_order, "Always put the player at the back or not (Bully mode).") ); + PARAM_PREFIX StringUserConfigParam m_additional_gp_directory + PARAM_DEFAULT( StringUserConfigParam("", "additional_gp_directory", + "Directory with additional GP's.")); // ---- Video PARAM_PREFIX GroupUserConfigParam m_video_group PARAM_DEFAULT( GroupUserConfigParam("Video", "Video Settings") ); - PARAM_PREFIX IntUserConfigParam m_width + PARAM_PREFIX IntUserConfigParam m_width PARAM_DEFAULT( IntUserConfigParam(1024, "width", &m_video_group, "Screen/window width in pixels") ); - PARAM_PREFIX IntUserConfigParam m_height + PARAM_PREFIX IntUserConfigParam m_height PARAM_DEFAULT( IntUserConfigParam(768, "height", &m_video_group, "Screen/window height in pixels") ); - PARAM_PREFIX BoolUserConfigParam m_fullscreen + PARAM_PREFIX BoolUserConfigParam m_fullscreen PARAM_DEFAULT( BoolUserConfigParam(false, "fullscreen", &m_video_group) ); - PARAM_PREFIX IntUserConfigParam m_prev_width + PARAM_PREFIX IntUserConfigParam m_prev_width PARAM_DEFAULT( IntUserConfigParam(1024, "prev_width", &m_video_group, "Previous screen/window width") ); - PARAM_PREFIX IntUserConfigParam m_prev_height + PARAM_PREFIX IntUserConfigParam m_prev_height PARAM_DEFAULT( IntUserConfigParam(768, "prev_height", &m_video_group,"Previous screen/window height") ); - PARAM_PREFIX BoolUserConfigParam m_prev_fullscreen + PARAM_PREFIX BoolUserConfigParam m_prev_fullscreen PARAM_DEFAULT( BoolUserConfigParam(false, "prev_fullscreen", &m_video_group) ); - PARAM_PREFIX BoolUserConfigParam m_remember_window_location + PARAM_PREFIX BoolUserConfigParam m_remember_window_location PARAM_DEFAULT( BoolUserConfigParam(false, "remember_window_location", &m_video_group) ); - PARAM_PREFIX IntUserConfigParam m_window_x + PARAM_PREFIX IntUserConfigParam m_window_x PARAM_DEFAULT( IntUserConfigParam(-1, "window_x", &m_video_group,"If remember_window_location is true") ); - PARAM_PREFIX IntUserConfigParam m_window_y + PARAM_PREFIX IntUserConfigParam m_window_y PARAM_DEFAULT( IntUserConfigParam(-1, "window_y", &m_video_group,"If remember_window_location is true") ); - PARAM_PREFIX BoolUserConfigParam m_display_fps + PARAM_PREFIX BoolUserConfigParam m_display_fps PARAM_DEFAULT( BoolUserConfigParam(false, "show_fps", &m_video_group, "Display frame per seconds") ); - PARAM_PREFIX IntUserConfigParam m_max_fps + PARAM_PREFIX IntUserConfigParam m_max_fps PARAM_DEFAULT( IntUserConfigParam(120, "max_fps", &m_video_group, "Maximum fps, should be at least 60") ); diff --git a/src/io/file_manager.cpp b/src/io/file_manager.cpp index 37bf5c1e1..dde041f5a 100644 --- a/src/io/file_manager.cpp +++ b/src/io/file_manager.cpp @@ -507,8 +507,8 @@ void FileManager::popModelSearchPath() * \return True if the file is found, false otherwise. */ bool FileManager::findFile(std::string& full_path, - const std::string& file_name, - const std::vector& search_path) const + const std::string& file_name, + const std::vector& search_path) const { for(std::vector::const_reverse_iterator i = search_path.rbegin(); @@ -517,7 +517,7 @@ bool FileManager::findFile(std::string& full_path, full_path = *i + file_name; if(m_file_system->existFile(full_path.c_str())) return true; } - full_path=""; + full_path = ""; return false; } // findFile diff --git a/src/io/file_manager.hpp b/src/io/file_manager.hpp index 4037cb464..0e8384e4c 100644 --- a/src/io/file_manager.hpp +++ b/src/io/file_manager.hpp @@ -47,7 +47,7 @@ public: /** The various asset types (and directories) STK might request. * The last entry ASSET_COUNT specifies the number of entries. */ enum AssetType {ASSET_MIN, - CHALLENGE=ASSET_MIN, + CHALLENGE = ASSET_MIN, FONT, GFX, GRANDPRIX, GUI, MODEL, MUSIC, SFX, SHADER, SKIN, TEXTURE, TRANSLATION, ASSET_MAX = TRANSLATION, @@ -55,7 +55,7 @@ public: private: /** The names of the various subdirectories of the asset types. */ - std::vector< std::string > m_subdir_name; + std::vector m_subdir_name; /** Handle to irrlicht's file systems. */ io::IFileSystem *m_file_system; @@ -73,64 +73,65 @@ private: std::string m_screenshot_dir; std::vector - m_texture_search_path, - m_model_search_path, - m_music_search_path; - bool findFile(std::string& full_path, - const std::string& fname, - const std::vector& search_path) - const; - void makePath(std::string& path, const std::string& dir, - const std::string& fname) const; - bool checkAndCreateDirectory(const std::string &path); - io::path createAbsoluteFilename(const std::string &f); - void checkAndCreateConfigDir(); - bool isDirectory(const std::string &path) const; - void checkAndCreateAddonsDir(); - void checkAndCreateScreenshotDir(); + m_texture_search_path, + m_model_search_path, + m_music_search_path; + bool findFile(std::string& full_path, + const std::string& fname, + const std::vector& search_path) + const; + void makePath(std::string& path, const std::string& dir, + const std::string& fname) const; + bool checkAndCreateDirectory(const std::string &path); + io::path createAbsoluteFilename(const std::string &f); + void checkAndCreateConfigDir(); + bool isDirectory(const std::string &path) const; + void checkAndCreateAddonsDir(); + void checkAndCreateScreenshotDir(); #if !defined(WIN32) && !defined(__CYGWIN__) && !defined(__APPLE__) - std::string checkAndCreateLinuxDir(const char *env_name, - const char *dir_name, - const char *fallback1, - const char *fallback2=NULL); + std::string checkAndCreateLinuxDir(const char *env_name, + const char *dir_name, + const char *fallback1, + const char *fallback2=NULL); #endif public: - FileManager(); - ~FileManager(); - void reInit(); - void dropFileSystem(); - static void addRootDirs(const std::string &roots); - io::IXMLReader *createXMLReader(const std::string &filename); - XMLNode *createXMLTree(const std::string &filename); - XMLNode *createXMLTreeFromString(const std::string & content); + FileManager(); + ~FileManager(); + void reInit(); + void dropFileSystem(); + static void addRootDirs(const std::string &roots); + io::IXMLReader *createXMLReader(const std::string &filename); + XMLNode *createXMLTree(const std::string &filename); + XMLNode *createXMLTreeFromString(const std::string & content); - std::string getScreenshotDir() const; - bool checkAndCreateDirectoryP(const std::string &path); + std::string getScreenshotDir() const; + bool checkAndCreateDirectoryP(const std::string &path); const std::string &getAddonsDir() const; std::string getAddonsFile(const std::string &name); - void checkAndCreateDirForAddons(const std::string &dir); - bool removeFile(const std::string &name) const; - bool removeDirectory(const std::string &name) const; - std::vectorgetMusicDirs() const; - std::string getAssetChecked(AssetType type, const std::string& name, - bool abort_on_error=false) const; - std::string getAsset(AssetType type, const std::string &name) const; - std::string getAsset(const std::string &name) const; + void checkAndCreateDirForAddons(const std::string &dir); + bool removeFile(const std::string &name) const; + bool removeDirectory(const std::string &name) const; + std::vector + getMusicDirs() const; + std::string getAssetChecked(AssetType type, const std::string& name, + bool abort_on_error=false) const; + std::string getAsset(AssetType type, const std::string &name) const; + std::string getAsset(const std::string &name) const; - std::string searchMusic(const std::string& file_name) const; - std::string searchTexture(const std::string& fname) const; - std::string getUserConfigFile(const std::string& fname) const; - void listFiles (std::set& result, - const std::string& dir, - bool make_full_path=false) const; + std::string searchMusic(const std::string& file_name) const; + std::string searchTexture(const std::string& fname) const; + std::string getUserConfigFile(const std::string& fname) const; + void listFiles(std::set& result, + const std::string& dir, + bool make_full_path=false) const; - void pushTextureSearchPath(const std::string& path); - void pushModelSearchPath (const std::string& path); - void popTextureSearchPath (); - void popModelSearchPath (); - void redirectOutput(); + void pushTextureSearchPath (const std::string& path); + void pushModelSearchPath (const std::string& path); + void popTextureSearchPath (); + void popModelSearchPath (); + void redirectOutput (); // ------------------------------------------------------------------------ /** Adds a directory to the music search path (or stack). */ diff --git a/src/main.cpp b/src/main.cpp index 03e1a6012..583f57030 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -392,17 +392,21 @@ void cmdLineHelp() { Log::info("main", "Usage: %s [OPTIONS]\n\n" + "Run SuperTuxKart, a racing game with go-kart that features" " the Tux and friends.\n\n" + "Options:\n" " -N, --no-start-screen Immediately start race without showing a " "menu.\n" - " -R, --race-now Same as -N but also skip the ready-set-go phase" - " and the music.\n" + " -R, --race-now Same as -N but also skip the ready-set-go phase " + "and the music.\n" " -t, --track=NAME Start at track NAME.\n" " --gp=NAME Start the specified Grand Prix.\n" " --stk-config=FILE use ./data/FILE instead of " "./data/stk_config.xml\n" + " --add-gp-dir=DIR Load Grand Prixs in DIR. Setting will be saved " + "in config.xml\n" " -k, --numkarts=NUM Number of karts on the racetrack.\n" " --kart=NAME Use kart number NAME.\n" " --ai=a,b,... Use the karts a, b, ... for the AI.\n" @@ -467,8 +471,7 @@ int handleCmdLinePreliminary() cmdLineHelp(); exit(0); } - if( CommandLine::has("--gamepad-visualisation") || - CommandLine::has("--gamepad-visualization") ) + if( CommandLine::has("--gamepad-visualisation") ) UserConfigParams::m_gamepad_visualisation=true; if( CommandLine::has("--debug=memory")) UserConfigParams::m_verbosity |= UserConfigParams::LOG_MEMORY; @@ -498,15 +501,15 @@ int handleCmdLinePreliminary() if( CommandLine::has( "--stk-config", &s)) { stk_config->load(file_manager->getAsset(s)); - Log::info("main", "STK config will be read from %s.",s.c_str()); + Log::info("main", "STK config will be read from %s.", s.c_str()); } if( CommandLine::has( "--trackdir", &s)) TrackManager::addTrackSearchDir(s); if( CommandLine::has( "--kartdir", &s)) KartPropertiesManager::addKartSearchDir(s); - if( CommandLine::has( "--no-graphics") || - CommandLine::has("-l" ) ) + if( CommandLine::has("--no-graphics") || + CommandLine::has("-l" ) ) { ProfileWorld::disableGraphics(); UserConfigParams::m_log_errors_to_console=true; @@ -539,13 +542,14 @@ int handleCmdLinePreliminary() } else Log::warn("main", "Resolution %s has been blacklisted, so " - "it is not available!", res.c_str()); + "it is not available!", res.c_str()); } else { - Log::fatal("main", "Error: --screensize argument must be " - "given as WIDTHxHEIGHT"); + Log::fatal("main", "Error: --screensize argument must be given as " + "WIDTHxHEIGHT"); } + } @@ -589,6 +593,19 @@ int handleCmdLinePreliminary() if(CommandLine::has("--log", &n)) Log::setLogLevel(n); + // Enable loading GP's from local directory + if(CommandLine::has("--add-gp-dir", &s)) + { + // Ensure that the path ends with a / + if (s[s.size()] == '/') + UserConfigParams::m_additional_gp_directory = s; + else + UserConfigParams::m_additional_gp_directory = s + "/"; + + Log::info("main", "Additional Grand Prix will be loaded from %s", + UserConfigParams::m_additional_gp_directory.c_str()); + } + return 0; } // handleCmdLinePreliminary @@ -1144,7 +1161,8 @@ int main(int argc, char *argv[] ) // Both item_manager and powerup_manager load models and therefore // textures from the model directory. To avoid reading the // materials.xml twice, we do this here once for both: - file_manager->pushTextureSearchPath(file_manager->getAsset(FileManager::MODEL,"")); + file_manager->pushTextureSearchPath(file_manager->getAsset( + FileManager::MODEL,"")); const std::string materials_file = file_manager->getAsset(FileManager::MODEL,"materials.xml"); if(materials_file!="") diff --git a/src/race/grand_prix_data.cpp b/src/race/grand_prix_data.cpp index def7b336d..8cb48e862 100644 --- a/src/race/grand_prix_data.cpp +++ b/src/race/grand_prix_data.cpp @@ -32,15 +32,29 @@ #include GrandPrixData::GrandPrixData(const std::string filename) throw(std::logic_error) +{ + load_from_file(file_manager->getAsset(FileManager::GRANDPRIX, filename), + filename); +} +// ---------------------------------------------------------------------------- +GrandPrixData::GrandPrixData(const std::string dir, const std::string filename) + throw(std::logic_error) +{ + assert(dir[dir.size()] == '/'); + load_from_file(dir + filename, filename); +} +// ---------------------------------------------------------------------------- +void GrandPrixData::load_from_file(const std::string fullpath, + const std::string filename) { m_filename = filename; m_id = StringUtils::getBasename(StringUtils::removeExtension(filename)); - XMLNode* root = file_manager->createXMLTree(file_manager->getAsset(FileManager::GRANDPRIX,filename)); + XMLNode * root = file_manager->createXMLTree(fullpath); if (!root) { - Log::error("GrandPrixData","Error while trying to read grandprix file '%s'", - filename.c_str()); + Log::error("GrandPrixData","Error while trying to read grandprix file " + "'%s'", fullpath.c_str()); throw std::logic_error("File not found"); } @@ -51,8 +65,9 @@ GrandPrixData::GrandPrixData(const std::string filename) throw(std::logic_error) std::string temp_name; if (root->get("name", &temp_name) == 0) { - Log::error("GrandPrixData", "Error while trying to read grandprix file '%s' : " - "missing 'name' attribute\n", filename.c_str()); + Log::error("GrandPrixData", "Error while trying to read grandprix " + "file '%s' : missing 'name' attribute\n", + fullpath.c_str()); delete root; throw std::logic_error("File contents are incomplete or corrupt"); } @@ -61,8 +76,9 @@ GrandPrixData::GrandPrixData(const std::string filename) throw(std::logic_error) } else { - Log::error("GrandPrixData", "Error while trying to read grandprix file '%s' : " - "Root node has an unexpected name\n", filename.c_str()); + Log::error("GrandPrixData", "Error while trying to read grandprix file " + "'%s' : Root node has an unexpected name\n", + fullpath.c_str()); delete root; throw std::logic_error("File contents are incomplete or corrupt"); } @@ -80,18 +96,20 @@ GrandPrixData::GrandPrixData(const std::string filename) throw(std::logic_error) int numLaps; bool reversed = false; - const int idFound = node->get("id", &trackID ); - const int lapFound = node->get("laps", &numLaps ); + const int idFound = node->get("id", &trackID); + const int lapFound = node->get("laps", &numLaps); // Will stay false if not found node->get("reverse", &reversed ); if (!idFound || !lapFound) { - Log::error("GrandPrixData", "Error while trying to read grandprix file '%s' : " - " tag does not have idi and laps reverse attributes. \n", - filename.c_str()); + Log::error("GrandPrixData", "Error while trying to read " + "grandprix file '%s' : tag does not have " + "idi and laps reverse attributes. \n", + fullpath.c_str()); delete root; - throw std::logic_error("File contents are incomplete or corrupt"); + throw std::logic_error("File contents are incomplete or " + "corrupt"); } // Make sure the track really is reversible @@ -110,22 +128,22 @@ GrandPrixData::GrandPrixData(const std::string filename) throw(std::logic_error) } else { - std::cerr << "Unknown node in Grand Prix XML file : " << node->getName().c_str() << std::endl; + Log::error("Unknown node in Grand Prix XML file: %s/n", + node->getName().c_str()); delete root; throw std::runtime_error("Unknown node in sfx XML file"); } - }// nend for + }// end for delete root; // sanity checks if (!foundName) { - Log::error("GrandPrixData", "Error while trying to read grandprix file '%s' : " - "missing 'name' attribute\n", filename.c_str()); + Log::error("GrandPrixData", "Error while trying to read grandprix file " + "'%s' : missing 'name' attribute\n", fullpath.c_str()); throw std::logic_error("File contents are incomplete or corrupt"); } - } // ---------------------------------------------------------------------------- bool GrandPrixData::checkConsistency(bool chatty) const @@ -149,7 +167,6 @@ bool GrandPrixData::checkConsistency(bool chatty) const return true; } // checkConsistency - // ---------------------------------------------------------------------------- /** Returns true if the track is available. This is used to test if Fort Magma * is available (this way FortMagma is not used in the last Grand Prix in diff --git a/src/race/grand_prix_data.hpp b/src/race/grand_prix_data.hpp index 074b6534f..27592896a 100644 --- a/src/race/grand_prix_data.hpp +++ b/src/race/grand_prix_data.hpp @@ -27,6 +27,7 @@ #include #include "utils/translation.hpp" +#include "io/file_manager.hpp" /** Simple class that hold the data relevant to a 'grand_prix', aka. a number * of races that has to be completed one after the other @@ -34,6 +35,7 @@ */ class GrandPrixData { +private: /** The name of the grand prix. */ irr::core::stringw m_name; @@ -63,6 +65,7 @@ class GrandPrixData /** Whether the track in question should be done in reverse mode */ std::vector m_reversed; + void load_from_file(const std::string fullpath, const std::string filename); bool isTrackAvailable(const std::string &id) const; public: @@ -70,8 +73,11 @@ public: #if (defined(WIN32) || defined(_WIN32)) && !defined(__MINGW32__) #pragma warning(disable:4290) #endif - GrandPrixData (const std::string filename) throw(std::logic_error); - GrandPrixData () {}; // empty for initialising + GrandPrixData () {}; // empty for initialising + GrandPrixData (const std::string filename) throw(std::logic_error); + GrandPrixData (const std::string dir, const std::string filename) + throw(std::logic_error); + bool checkConsistency(bool chatty=true) const; const std::vector& getTrackNames() const; diff --git a/src/race/grand_prix_manager.cpp b/src/race/grand_prix_manager.cpp index 504d73797..26e9d5287 100644 --- a/src/race/grand_prix_manager.cpp +++ b/src/race/grand_prix_manager.cpp @@ -21,6 +21,7 @@ #include #include "io/file_manager.hpp" #include "utils/string_utils.hpp" +#include "config/user_config.hpp" GrandPrixManager *grand_prix_manager = NULL; @@ -33,10 +34,34 @@ GrandPrixManager::GrandPrixManager() for(std::set::iterator i = result.begin(); i != result.end() ; i++) { - if (StringUtils::hasSuffix(*i, ".grandprix")) load(*i); - } // for i -} // GrandPrixManager + if (StringUtils::hasSuffix(*i, ".grandprix")) + { + try + { m_gp_data.push_back(new GrandPrixData(*i)); } + catch (std::logic_error& er) + { Log::error("GrandPrixManager", "Ignoring GP %s ( %s ) \n", + i->c_str(), er.what()); } + } + } + // Load additional Grand Prixs + const std::string dir = UserConfigParams::m_additional_gp_directory; + if(dir != "") { + file_manager->listFiles(result, dir); + for(std::set::iterator i = result.begin(); + i != result.end() ; i++) + { + if (StringUtils::hasSuffix(*i, ".grandprix")) + { + try + { m_gp_data.push_back(new GrandPrixData(dir, *i)); } + catch (std::logic_error& er) + { Log::error("GrandPrixManager", "Ignoring GP %s ( %s ) \n", + i->c_str(), er.what()); } + } + } + } +} // GrandPrixManager // ---------------------------------------------------------------------------- GrandPrixManager::~GrandPrixManager() { @@ -50,22 +75,11 @@ GrandPrixManager::~GrandPrixManager() const GrandPrixData* GrandPrixManager::getGrandPrix(const std::string& s) const { for(unsigned int i=0; igetId()==s) return m_gp_data[i]; + if(m_gp_data[i]->getId() == s) + return m_gp_data[i]; + return NULL; } // getGrandPrix -// ---------------------------------------------------------------------------- -void GrandPrixManager::load(const std::string& filename) -{ - try - { - m_gp_data.push_back(new GrandPrixData(filename)); - } - catch (std::logic_error& er) - { - Log::error("GrandPrixManager", "Ignoring GP %s ( %s ) \n", filename.c_str(), er.what()); - } -} // load - // ---------------------------------------------------------------------------- void GrandPrixManager::checkConsistency() { diff --git a/src/race/grand_prix_manager.hpp b/src/race/grand_prix_manager.hpp index 2afb979b6..c9831f2bc 100644 --- a/src/race/grand_prix_manager.hpp +++ b/src/race/grand_prix_manager.hpp @@ -34,10 +34,9 @@ private: public: GrandPrixManager(); ~GrandPrixManager(); - void load(const std::string &filename); - const GrandPrixData* getGrandPrix(int i) const { return m_gp_data[i]; } + const GrandPrixData* getGrandPrix(int i) const {return m_gp_data[i]; } const GrandPrixData* getGrandPrix(const std::string& s) const; - unsigned int getNumberOfGrandPrix() const { return m_gp_data.size(); } + unsigned int getNumberOfGrandPrix() const {return m_gp_data.size();} void checkConsistency(); }; // GrandPrixManager