LCOV - code coverage report
Current view: top level - src - subgame.cpp (source / functions) Hit Total Coverage
Test: report Lines: 120 191 62.8 %
Date: 2015-07-11 18:23:49 Functions: 15 18 83.3 %

          Line data    Source code
       1             : /*
       2             : Minetest
       3             : Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
       4             : 
       5             : This program is free software; you can redistribute it and/or modify
       6             : it under the terms of the GNU Lesser General Public License as published by
       7             : the Free Software Foundation; either version 2.1 of the License, or
       8             : (at your option) any later version.
       9             : 
      10             : This program 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 Lesser General Public License for more details.
      14             : 
      15             : You should have received a copy of the GNU Lesser General Public License along
      16             : with this program; if not, write to the Free Software Foundation, Inc.,
      17             : 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
      18             : */
      19             : 
      20             : #include "subgame.h"
      21             : #include "porting.h"
      22             : #include "filesys.h"
      23             : #include "settings.h"
      24             : #include "log.h"
      25             : #include "strfnd.h"
      26             : #include "defaultsettings.h"  // for override_default_settings
      27             : #include "mapgen.h"  // for MapgenParams
      28             : #include "util/string.h"
      29             : 
      30             : #ifndef SERVER
      31             :         #include "client/tile.h" // getImagePath
      32             : #endif
      33             : 
      34           0 : bool getGameMinetestConfig(const std::string &game_path, Settings &conf)
      35             : {
      36           0 :         std::string conf_path = game_path + DIR_DELIM + "minetest.conf";
      37           0 :         return conf.readConfigFile(conf_path.c_str());
      38             : }
      39             : 
      40           5 : bool getGameConfig(const std::string &game_path, Settings &conf)
      41             : {
      42          10 :         std::string conf_path = game_path + DIR_DELIM + "game.conf";
      43          10 :         return conf.readConfigFile(conf_path.c_str());
      44             : }
      45             : 
      46           3 : std::string getGameName(const std::string &game_path)
      47             : {
      48           6 :         Settings conf;
      49           3 :         if(!getGameConfig(game_path, conf))
      50           0 :                 return "";
      51           3 :         if(!conf.exists("name"))
      52           0 :                 return "";
      53           3 :         return conf.get("name");
      54             : }
      55             : 
      56          54 : struct GameFindPath
      57             : {
      58             :         std::string path;
      59             :         bool user_specific;
      60          12 :         GameFindPath(const std::string &path, bool user_specific):
      61             :                 path(path),
      62          12 :                 user_specific(user_specific)
      63          12 :         {}
      64             : };
      65             : 
      66           4 : Strfnd getSubgamePathEnv() {
      67           8 :         std::string sp;
      68           4 :         char *subgame_path = getenv("MINETEST_SUBGAME_PATH");
      69             : 
      70           4 :         if(subgame_path) {
      71           0 :                 sp = std::string(subgame_path);
      72             :         }
      73             : 
      74           8 :         return Strfnd(sp);
      75             : }
      76             : 
      77           3 : SubgameSpec findSubgame(const std::string &id)
      78             : {
      79           3 :         if(id == "")
      80           0 :                 return SubgameSpec();
      81           6 :         std::string share = porting::path_share;
      82           6 :         std::string user = porting::path_user;
      83           6 :         std::vector<GameFindPath> find_paths;
      84             : 
      85           6 :         Strfnd search_paths = getSubgamePathEnv();
      86             : 
      87           3 :         while(!search_paths.atend()) {
      88           0 :                 std::string path = search_paths.next(":");
      89           0 :                 find_paths.push_back(GameFindPath(
      90           0 :                                 path + DIR_DELIM + id, false));
      91           0 :                 find_paths.push_back(GameFindPath(
      92           0 :                                 path + DIR_DELIM + id + "_game", false));
      93             :         }
      94             : 
      95           6 :         find_paths.push_back(GameFindPath(
      96           9 :                         user + DIR_DELIM + "games" + DIR_DELIM + id + "_game", true));
      97           6 :         find_paths.push_back(GameFindPath(
      98           9 :                         user + DIR_DELIM + "games" + DIR_DELIM + id, true));
      99           6 :         find_paths.push_back(GameFindPath(
     100           9 :                         share + DIR_DELIM + "games" + DIR_DELIM + id + "_game", false));
     101           6 :         find_paths.push_back(GameFindPath(
     102           9 :                         share + DIR_DELIM + "games" + DIR_DELIM + id, false));
     103             :         // Find game directory
     104           6 :         std::string game_path;
     105           3 :         bool user_game = true; // Game is in user's directory
     106           8 :         for(u32 i=0; i<find_paths.size(); i++){
     107           8 :                 const std::string &try_path = find_paths[i].path;
     108           8 :                 if(fs::PathExists(try_path)){
     109           3 :                         game_path = try_path;
     110           3 :                         user_game = find_paths[i].user_specific;
     111           3 :                         break;
     112             :                 }
     113             :         }
     114           3 :         if(game_path == "")
     115           0 :                 return SubgameSpec();
     116           6 :         std::string gamemod_path = game_path + DIR_DELIM + "mods";
     117             :         // Find mod directories
     118           6 :         std::set<std::string> mods_paths;
     119           3 :         if(!user_game)
     120           1 :                 mods_paths.insert(share + DIR_DELIM + "mods");
     121           3 :         if(user != share || user_game)
     122           3 :                 mods_paths.insert(user + DIR_DELIM + "mods");
     123           6 :         std::string game_name = getGameName(game_path);
     124           3 :         if(game_name == "")
     125           0 :                 game_name = id;
     126           6 :         std::string menuicon_path;
     127             : #ifndef SERVER
     128           3 :         menuicon_path = getImagePath(game_path + DIR_DELIM + "menu" + DIR_DELIM + "icon.png");
     129             : #endif
     130             :         return SubgameSpec(id, game_path, gamemod_path, mods_paths, game_name,
     131           3 :                         menuicon_path);
     132             : }
     133             : 
     134           1 : SubgameSpec findWorldSubgame(const std::string &world_path)
     135             : {
     136           2 :         std::string world_gameid = getWorldGameId(world_path, true);
     137             :         // See if world contains an embedded game; if so, use it.
     138           2 :         std::string world_gamepath = world_path + DIR_DELIM + "game";
     139           1 :         if(fs::PathExists(world_gamepath)){
     140           0 :                 SubgameSpec gamespec;
     141           0 :                 gamespec.id = world_gameid;
     142           0 :                 gamespec.path = world_gamepath;
     143           0 :                 gamespec.gamemods_path= world_gamepath + DIR_DELIM + "mods";
     144           0 :                 gamespec.name = getGameName(world_gamepath);
     145           0 :                 if(gamespec.name == "")
     146           0 :                         gamespec.name = "unknown";
     147           0 :                 return gamespec;
     148             :         }
     149           1 :         return findSubgame(world_gameid);
     150             : }
     151             : 
     152           1 : std::set<std::string> getAvailableGameIds()
     153             : {
     154           1 :         std::set<std::string> gameids;
     155           2 :         std::set<std::string> gamespaths;
     156           1 :         gamespaths.insert(porting::path_share + DIR_DELIM + "games");
     157           1 :         gamespaths.insert(porting::path_user + DIR_DELIM + "games");
     158             : 
     159           2 :         Strfnd search_paths = getSubgamePathEnv();
     160             : 
     161           1 :         while(!search_paths.atend()) {
     162           0 :                 gamespaths.insert(search_paths.next(":"));
     163             :         }
     164             : 
     165           9 :         for(std::set<std::string>::const_iterator i = gamespaths.begin();
     166           6 :                         i != gamespaths.end(); i++){
     167           4 :                 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(*i);
     168           4 :                 for(u32 j=0; j<dirlist.size(); j++){
     169           2 :                         if(!dirlist[j].dir)
     170           0 :                                 continue;
     171             :                         // If configuration file is not found or broken, ignore game
     172           4 :                         Settings conf;
     173           2 :                         if(!getGameConfig(*i + DIR_DELIM + dirlist[j].name, conf))
     174           0 :                                 continue;
     175             :                         // Add it to result
     176           2 :                         const char *ends[] = {"_game", NULL};
     177           4 :                         std::string shorter = removeStringEnd(dirlist[j].name, ends);
     178           2 :                         if(shorter != "")
     179           0 :                                 gameids.insert(shorter);
     180             :                         else
     181           2 :                                 gameids.insert(dirlist[j].name);
     182             :                 }
     183             :         }
     184           2 :         return gameids;
     185             : }
     186             : 
     187           1 : std::vector<SubgameSpec> getAvailableGames()
     188             : {
     189           1 :         std::vector<SubgameSpec> specs;
     190           2 :         std::set<std::string> gameids = getAvailableGameIds();
     191           9 :         for(std::set<std::string>::const_iterator i = gameids.begin();
     192           6 :                         i != gameids.end(); i++)
     193           2 :                 specs.push_back(findSubgame(*i));
     194           2 :         return specs;
     195             : }
     196             : 
     197             : #define LEGACY_GAMEID "minetest"
     198             : 
     199           1 : bool getWorldExists(const std::string &world_path)
     200             : {
     201           3 :         return (fs::PathExists(world_path + DIR_DELIM + "map_meta.txt") ||
     202           2 :                         fs::PathExists(world_path + DIR_DELIM + "world.mt"));
     203             : }
     204             : 
     205           6 : std::string getWorldGameId(const std::string &world_path, bool can_be_legacy)
     206             : {
     207          12 :         std::string conf_path = world_path + DIR_DELIM + "world.mt";
     208          12 :         Settings conf;
     209           6 :         bool succeeded = conf.readConfigFile(conf_path.c_str());
     210           6 :         if(!succeeded){
     211           0 :                 if(can_be_legacy){
     212             :                         // If map_meta.txt exists, it is probably an old minetest world
     213           0 :                         if(fs::PathExists(world_path + DIR_DELIM + "map_meta.txt"))
     214           0 :                                 return LEGACY_GAMEID;
     215             :                 }
     216           0 :                 return "";
     217             :         }
     218           6 :         if(!conf.exists("gameid"))
     219           0 :                 return "";
     220             :         // The "mesetint" gameid has been discarded
     221           6 :         if(conf.get("gameid") == "mesetint")
     222           0 :                 return "minetest";
     223           6 :         return conf.get("gameid");
     224             : }
     225             : 
     226           3 : std::vector<WorldSpec> getAvailableWorlds()
     227             : {
     228           3 :         std::vector<WorldSpec> worlds;
     229           6 :         std::set<std::string> worldspaths;
     230           3 :         worldspaths.insert(porting::path_user + DIR_DELIM + "worlds");
     231           3 :         infostream<<"Searching worlds..."<<std::endl;
     232          18 :         for(std::set<std::string>::const_iterator i = worldspaths.begin();
     233          12 :                         i != worldspaths.end(); i++){
     234           3 :                 infostream<<"  In "<<(*i)<<": "<<std::endl;
     235           6 :                 std::vector<fs::DirListNode> dirvector = fs::GetDirListing(*i);
     236           6 :                 for(u32 j=0; j<dirvector.size(); j++){
     237           3 :                         if(!dirvector[j].dir)
     238           0 :                                 continue;
     239           6 :                         std::string fullpath = *i + DIR_DELIM + dirvector[j].name;
     240           6 :                         std::string name = dirvector[j].name;
     241             :                         // Just allow filling in the gameid always for now
     242           3 :                         bool can_be_legacy = true;
     243           6 :                         std::string gameid = getWorldGameId(fullpath, can_be_legacy);
     244           6 :                         WorldSpec spec(fullpath, name, gameid);
     245           3 :                         if(!spec.isValid()){
     246           0 :                                 infostream<<"(invalid: "<<name<<") ";
     247             :                         } else {
     248           3 :                                 infostream<<name<<" ";
     249           3 :                                 worlds.push_back(spec);
     250             :                         }
     251             :                 }
     252           3 :                 infostream<<std::endl;
     253             :         }
     254             :         // Check old world location
     255             :         do{
     256           3 :                 std::string fullpath = porting::path_user + DIR_DELIM + "world";
     257           3 :                 if(!fs::PathExists(fullpath))
     258           3 :                         break;
     259           0 :                 std::string name = "Old World";
     260           0 :                 std::string gameid = getWorldGameId(fullpath, true);
     261           0 :                 WorldSpec spec(fullpath, name, gameid);
     262           0 :                 infostream<<"Old world found."<<std::endl;
     263           0 :                 worlds.push_back(spec);
     264             :         }while(0);
     265           3 :         infostream<<worlds.size()<<" found."<<std::endl;
     266           6 :         return worlds;
     267             : }
     268             : 
     269           0 : bool loadGameConfAndInitWorld(const std::string &path, const SubgameSpec &gamespec)
     270             : {
     271             :         // Override defaults with those provided by the game.
     272             :         // We clear and reload the defaults because the defaults
     273             :         // might have been overridden by other subgame config
     274             :         // files that were loaded before.
     275           0 :         g_settings->clearDefaults();
     276           0 :         set_default_settings(g_settings);
     277           0 :         Settings game_defaults;
     278           0 :         getGameMinetestConfig(gamespec.path, game_defaults);
     279           0 :         override_default_settings(g_settings, &game_defaults);
     280             : 
     281           0 :         infostream << "Initializing world at " << path << std::endl;
     282             : 
     283           0 :         fs::CreateAllDirs(path);
     284             : 
     285             :         // Create world.mt if does not already exist
     286           0 :         std::string worldmt_path = path + DIR_DELIM "world.mt";
     287           0 :         if (!fs::PathExists(worldmt_path)) {
     288           0 :                 std::ostringstream ss(std::ios_base::binary);
     289           0 :                 ss << "gameid = " << gamespec.id
     290           0 :                         << "\nbackend = sqlite3"
     291           0 :                         << "\ncreative_mode = " << g_settings->get("creative_mode")
     292           0 :                         << "\nenable_damage = " << g_settings->get("enable_damage")
     293           0 :                         << "\n";
     294           0 :                 if (!fs::safeWriteToFile(worldmt_path, ss.str()))
     295           0 :                         return false;
     296             : 
     297           0 :                 infostream << "Wrote world.mt (" << worldmt_path << ")" << std::endl;
     298             :         }
     299             : 
     300             :         // Create map_meta.txt if does not already exist
     301           0 :         std::string map_meta_path = path + DIR_DELIM + "map_meta.txt";
     302           0 :         if (!fs::PathExists(map_meta_path)){
     303           0 :                 verbosestream << "Creating map_meta.txt (" << map_meta_path << ")" << std::endl;
     304           0 :                 fs::CreateAllDirs(path);
     305           0 :                 std::ostringstream oss(std::ios_base::binary);
     306             : 
     307           0 :                 Settings conf;
     308           0 :                 MapgenParams params;
     309             : 
     310           0 :                 params.load(*g_settings);
     311           0 :                 params.save(conf);
     312           0 :                 conf.writeLines(oss);
     313           0 :                 oss << "[end_of_params]\n";
     314             : 
     315           0 :                 fs::safeWriteToFile(map_meta_path, oss.str());
     316             :         }
     317           0 :         return true;
     318           3 : }
     319             : 

Generated by: LCOV version 1.11