command-line/world game selection
authorPerttu Ahola <celeron55@gmail.com>
Sun, 11 Mar 2012 12:54:23 +0000 (14:54 +0200)
committerPerttu Ahola <celeron55@gmail.com>
Sun, 11 Mar 2012 12:54:23 +0000 (14:54 +0200)
src/CMakeLists.txt
src/game.cpp
src/game.h
src/main.cpp
src/server.cpp
src/server.h
src/subgame.cpp [new file with mode: 0644]
src/subgame.h [new file with mode: 0644]

index e1cfcfa09d8956f2b4469961eb9ffa605bb500a3..e9fddf8c0fdd8b07bcea3fad43f382ede252afe3 100644 (file)
@@ -94,6 +94,7 @@ configure_file(
 )
 
 set(common_SRCS
+       subgame.cpp
        inventorymanager.cpp
        mods.cpp
        serverremoteplayer.cpp
index 0e3f570f493770e41681ba14a660fd5f9969f6d6..ebf5028b7fb5e1ee64a61b40276923433030cb7a 100644 (file)
@@ -51,6 +51,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "itemdef.h"
 #include "tile.h" // For TextureSource
 #include "logoutputbuffer.h"
+#include "subgame.h"
 
 /*
        Setting this to 1 enables a special camera mode that forces
@@ -651,11 +652,12 @@ void the_game(
        std::string map_dir,
        std::string playername,
        std::string password,
-       std::string address,
+       std::string address, // If "", local server is used
        u16 port,
        std::wstring &error_message,
        std::string configpath,
-       ChatBackend &chat_backend
+       ChatBackend &chat_backend,
+       const SubgameSpec &gamespec // Used for local game
 )
 {
        video::IVideoDriver* driver = device->getVideoDriver();
@@ -705,7 +707,7 @@ void the_game(
        if(address == ""){
                draw_load_screen(L"Creating server...", driver, font);
                infostream<<"Creating server"<<std::endl;
-               server = new Server(map_dir, configpath, "mesetint");
+               server = new Server(map_dir, configpath, gamespec);
                server->start(port);
        }
 
index 01e955ecdb37bb164432f0702c672cc28b81c21c..4ca5a2433956ca1cfa69bd6ca653a6e5651b6602 100644 (file)
@@ -22,7 +22,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 
 #include "common_irrlicht.h"
 #include <string>
-
 #include "keycode.h"
 
 class KeyList : protected core::list<KeyPress>
@@ -123,6 +122,7 @@ public:
 };
 
 class ChatBackend;  /* to avoid having to include chat.h */
+struct SubgameSpec;
 
 void the_game(
        bool &kill,
@@ -133,11 +133,12 @@ void the_game(
        std::string map_dir,
        std::string playername,
        std::string password,
-       std::string address,
+       std::string address, // If "", local server is used
        u16 port,
        std::wstring &error_message,
        std::string configpath,
-       ChatBackend &chat_backend
+       ChatBackend &chat_backend,
+       const SubgameSpec &gamespec // Used for local game
 );
 
 #endif
index 8b2ef3668bc9254d4160d2cb1bf9002061e41aad..00776d89ce847f7c10d2134120d23c44297f5fa6 100644 (file)
@@ -69,6 +69,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "log.h"
 #include "mods.h"
 #include "utility_string.h"
+#include "subgame.h"
 
 /*
        Settings.
@@ -781,6 +782,8 @@ int main(int argc, char *argv[])
                        "Print more information to console"));
        allowed_options.insert("logfile", ValueSpec(VALUETYPE_STRING,
                        "Set logfile path (debug.txt)"));
+       allowed_options.insert("gameid", ValueSpec(VALUETYPE_STRING,
+                       "Set gameid"));
 #ifndef SERVER
        allowed_options.insert("speedtests", ValueSpec(VALUETYPE_FLAG,
                        "Run speed tests"));
@@ -958,22 +961,63 @@ int main(int argc, char *argv[])
                port = 30000;
        
        // Map directory
-       std::string map_dir = porting::path_user + DIR_DELIM + "server" + DIR_DELIM + "worlds" + DIR_DELIM + "world";
-       if(cmd_args.exists("map-dir"))
-               map_dir = cmd_args.get("map-dir");
+       std::string world_path = porting::path_user + DIR_DELIM + "server" + DIR_DELIM + "worlds" + DIR_DELIM + "world";
+       if(cmd_args.exists("world"))
+               world_path = cmd_args.get("world");
+       else if(cmd_args.exists("map-dir"))
+               world_path = cmd_args.get("map-dir");
        else if(g_settings->exists("map-dir"))
-               map_dir = g_settings->get("map-dir");
+               world_path = g_settings->get("map-dir");
        else{
                // No map-dir option was specified.
                // Check if the world is found from the default directory, and if
                // not, see if the legacy world directory exists.
-               std::string legacy_map_dir = porting::path_user+DIR_DELIM+".."+DIR_DELIM+"world";
-               if(!fs::PathExists(map_dir) && fs::PathExists(legacy_map_dir)){
+               std::string legacy_world_path = porting::path_user+DIR_DELIM+".."+DIR_DELIM+"world";
+               if(!fs::PathExists(world_path) && fs::PathExists(legacy_world_path)){
                        errorstream<<"Warning: Using legacy world directory \""
-                                       <<legacy_map_dir<<"\""<<std::endl;
-                       map_dir = legacy_map_dir;
+                                       <<legacy_world_path<<"\""<<std::endl;
+                       world_path = legacy_world_path;
                }
        }
+       
+       // Determine gameid
+       std::string gameid = "";
+       if(cmd_args.exists("gameid"))
+               gameid = cmd_args.get("gameid");
+       std::string world_gameid = getWorldGameId(world_path);
+       if(world_gameid == ""){
+               if(gameid != "")
+                       world_gameid = gameid;
+               else{
+                       world_gameid = "mesetint";
+               }
+       }
+       if(gameid == "")
+               gameid = world_gameid;
+       else if(world_gameid != ""){
+               if(world_gameid != gameid){
+                       errorstream<<"World gameid mismatch"<<std::endl;
+                       return 1;
+               }
+       }
+       if(gameid == ""){
+               errorstream<<"No gameid supplied or detected"<<std::endl;
+               return 1;
+       }
+       
+       infostream<<"Using gameid \""<<gameid<<"\""<<std::endl;
+
+       SubgameSpec gamespec = findSubgame(gameid);
+       if(!gamespec.isValid()){
+               errorstream<<"Game \""<<gameid<<"\" not found"<<std::endl;
+               std::set<std::string> gameids = getAvailableGameIds();
+               infostream<<"Available gameids: ";
+               for(std::set<std::string>::const_iterator i = gameids.begin();
+                               i != gameids.end(); i++)
+                       infostream<<(*i)<<" ";
+               infostream<<std::endl;
+               return 1;
+       }
 
        // Run dedicated server if asked to or no other option
 #ifdef SERVER
@@ -991,7 +1035,7 @@ int main(int argc, char *argv[])
 #endif
                
                // Create server
-               Server server(map_dir, configpath, "mesetint");
+               Server server(world_path, configpath, gamespec);
                server.start(port);
                
                // Run server
@@ -1080,9 +1124,6 @@ int main(int argc, char *argv[])
        */
        //driver->setMinHardwareBufferVertexCount(50);
 
-       // Set the window caption
-       device->setWindowCaption(L"Minetest [Main Menu]");
-       
        // Create time getter
        g_timegetter = new IrrlichtTimeGetter(device);
        
@@ -1154,6 +1195,8 @@ int main(int argc, char *argv[])
        */
        while(device->run() && kill == false)
        {
+               // Set the window caption
+               device->setWindowCaption(L"Minetest [Main Menu]");
 
                // This is used for catching disconnects
                try
@@ -1257,7 +1300,7 @@ int main(int argc, char *argv[])
                                        // Delete map if requested
                                        if(menudata.delete_map)
                                        {
-                                               bool r = fs::RecursiveDeleteContent(map_dir);
+                                               bool r = fs::RecursiveDeleteContent(world_path);
                                                if(r == false)
                                                        error_message = L"Delete failed";
                                                continue;
@@ -1303,14 +1346,15 @@ int main(int argc, char *argv[])
                                input,
                                device,
                                font,
-                               map_dir,
+                               world_path,
                                playername,
                                password,
                                address,
                                port,
                                error_message,
                                configpath,
-                               chat_backend
+                               chat_backend,
+                               gamespec
                        );
 
                } //try
index 8f40cfa5b809545cd9a0284730300e85e01995a4..7b34e3554b1bfb1b1ed259b63885806a45566b03 100644 (file)
@@ -830,13 +830,13 @@ void PlayerInfo::PrintLine(std::ostream *s)
 */
 
 Server::Server(
-               std::string path_world,
-               std::string path_config,
-               std::string gamename
+               const std::string &path_world,
+               const std::string &path_config,
+               const SubgameSpec &gamespec
        ):
-       m_gamename(gamename),
        m_path_world(path_world),
        m_path_config(path_config),
+       m_gamespec(gamespec),
        m_env(NULL),
        m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
        m_authmanager(path_world+DIR_DELIM+"auth.txt"),
@@ -865,55 +865,38 @@ Server::Server(
        m_step_dtime_mutex.Init();
        m_step_dtime = 0.0;
 
+       if(!gamespec.isValid())
+               throw ServerError("Supplied invalid gamespec");
+
        // Figure out some paths
        // share/server
        m_path_share = porting::path_share + DIR_DELIM + "server";
-       // game
-       m_path_game = porting::path_user + DIR_DELIM + "server" + DIR_DELIM
-                       + "games" + DIR_DELIM + m_gamename;
-       bool user_game = true; // Game is in user's directory
-       if(!fs::PathExists(m_path_game)){
-               m_path_game = m_path_share + DIR_DELIM + "games" + DIR_DELIM
-                               + m_gamename;
-               user_game = false;
-       }
-       if(!fs::PathExists(m_path_game)){
-               throw ServerError("Could not find game files for game \""
-                               +gamename+"\"");
-       }
-       // addons
-       if(!user_game)
-               m_path_addons.insert(m_path_share + DIR_DELIM + "addons"
-                               + DIR_DELIM + m_gamename);
-       m_path_addons.insert(porting::path_user + DIR_DELIM + "server"
-                       + DIR_DELIM + "addons" + DIR_DELIM + m_gamename);
-
-       infostream<<"Server created for gamename=\""<<gamename<<"\""<<std::endl;
-       infostream<<"- path_world  = "<<m_path_world<<std::endl;
-       infostream<<"- path_config = "<<m_path_config<<std::endl;
-       infostream<<"- path_game   = "<<m_path_game<<std::endl;
-       for(std::set<std::string>::const_iterator i = m_path_addons.begin();
-                       i != m_path_addons.end(); i++)
-               infostream<<"- path_addons+= "<<(*i)<<std::endl;
+
+       infostream<<"Server created for gameid \""<<m_gamespec.id<<"\""<<std::endl;
+       infostream<<"- world:  "<<m_path_world<<std::endl;
+       infostream<<"- config: "<<m_path_config<<std::endl;
+       infostream<<"- game:   "<<m_gamespec.path<<std::endl;
+       for(std::set<std::string>::const_iterator i = m_gamespec.addon_paths.begin();
+                       i != m_gamespec.addon_paths.end(); i++)
+               infostream<<"- addons: "<<(*i)<<std::endl;
 
        // Path to builtin.lua
        std::string builtinpath = m_path_share + DIR_DELIM + "builtin.lua";
 
        // Add default global mod search path
-       m_modspaths.push_front(m_path_game + DIR_DELIM "mods");
+       m_modspaths.push_front(m_gamespec.path + DIR_DELIM "mods");
        // Add world mod search path
        m_modspaths.push_front(m_path_world + DIR_DELIM + "worldmods");
        // Add addon mod search path
-       for(std::set<std::string>::const_iterator i = m_path_addons.begin();
-                       i != m_path_addons.end(); i++){
+       for(std::set<std::string>::const_iterator i = m_gamespec.addon_paths.begin();
+                       i != m_gamespec.addon_paths.end(); i++)
                m_modspaths.push_front((*i) + DIR_DELIM + "mods");
-       }
 
        // Print out mod search paths
        for(core::list<std::string>::Iterator i = m_modspaths.begin();
                        i != m_modspaths.end(); i++){
                std::string modspath = *i;
-               infostream<<"- modspath   += "<<modspath<<std::endl;
+               infostream<<"- mods:   "<<modspath<<std::endl;
        }
        
        // Lock environment
@@ -1106,7 +1089,8 @@ void Server::start(unsigned short port)
        <<"|  Y Y  \\  |   |  \\  ___/|  | \\  ___/ \\___ \\  |  |  "<<std::endl
        <<"|__|_|  /__|___|  /\\___  >__|  \\___  >____  > |__|  "<<std::endl
        <<"      \\/        \\/     \\/          \\/     \\/        "<<std::endl;
-       actionstream<<"Server listening on port "<<port<<"."<<std::endl;
+       actionstream<<"Server for gameid=\""<<m_gamespec.id
+                       <<"\" listening on port "<<port<<"."<<std::endl;
 }
 
 void Server::stop()
index a1d7e5df73b6c0e119f753eadb3e2322f86e5bf2..4948b8ba1de4540b2e8ecafa77a0ca1edfdcfdba 100644 (file)
@@ -34,6 +34,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "serverremoteplayer.h"
 #include "mods.h"
 #include "inventorymanager.h"
+#include "subgame.h"
 struct LuaState;
 typedef struct lua_State lua_State;
 class IWritableItemDefManager;
@@ -405,11 +406,11 @@ public:
        /*
                NOTE: Every public method should be thread-safe
        */
-
+       
        Server(
-               std::string gamename,
-               std::string mapsavedir,
-               std::string configpath
+               const std::string &path_world,
+               const std::string &path_config,
+               const SubgameSpec &gamespec
        );
        ~Server();
        void start(unsigned short port);
@@ -647,20 +648,15 @@ private:
                Variables
        */
        
-       // Game name
-       std::string m_gamename;
        // World directory
        std::string m_path_world;
        // Path to user's configuration file ("" = no configuration file)
        std::string m_path_config;
+       // Subgame specification
+       SubgameSpec m_gamespec;
 
        // Equivalent of /usr/share/minetest/server
        std::string m_path_share;
-       // Equivalent of /usr/share/minetest/server/games/gamename
-       std::string m_path_game;
-       // Equivalent of /usr/share/minetest/server/addons/gamename
-       // and ~/.minetest/server/addons/gamename
-       std::set<std::string> m_path_addons;
        
        // Some timers
        float m_liquid_transform_timer;
diff --git a/src/subgame.cpp b/src/subgame.cpp
new file mode 100644 (file)
index 0000000..ed50d09
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+Minetest-c55
+Copyright (C) 2012 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "subgame.h"
+#include "porting.h"
+#include "filesys.h"
+#include "settings.h"
+
+SubgameSpec findSubgame(const std::string &id)
+{
+       if(id == "")
+               return SubgameSpec();
+       std::string share_server = porting::path_share + DIR_DELIM + "server";
+       std::string user_server = porting::path_user + DIR_DELIM + "server";
+       // Find game directory
+       std::string game_path =
+                       user_server + DIR_DELIM + "games" + DIR_DELIM + id;
+       bool user_game = true; // Game is in user's directory
+       if(!fs::PathExists(game_path)){
+               game_path = share_server + DIR_DELIM + "games" + DIR_DELIM + id;
+               user_game = false;
+       }
+       if(!fs::PathExists(game_path))
+               return SubgameSpec();
+       // Find addon directories
+       std::set<std::string> addon_paths;
+       if(!user_game)
+               addon_paths.insert(share_server + DIR_DELIM + "addons"
+                               + DIR_DELIM + id);
+       addon_paths.insert(user_server + DIR_DELIM + "addons"
+                       + DIR_DELIM + id);
+       return SubgameSpec(id, game_path, addon_paths);
+}
+
+std::set<std::string> getAvailableGameIds()
+{
+       std::set<std::string> gameids;
+       std::set<std::string> gamespaths;
+       gamespaths.insert(porting::path_share + DIR_DELIM + "server"
+                       + DIR_DELIM + "games");
+       gamespaths.insert(porting::path_user + DIR_DELIM + "server"
+                       + DIR_DELIM + "games");
+       for(std::set<std::string>::const_iterator i = gamespaths.begin();
+                       i != gamespaths.end(); i++){
+               std::vector<fs::DirListNode> dirlist = fs::GetDirListing(*i);
+               for(u32 j=0; j<dirlist.size(); j++){
+                       if(!dirlist[j].dir)
+                               continue;
+                       gameids.insert(dirlist[j].name);
+               }
+       }
+       return gameids;
+}
+
+std::string getWorldGameId(const std::string &world_path)
+{
+       std::string conf_path = world_path + DIR_DELIM + "world.mt";
+       Settings conf;
+       bool succeeded = conf.readConfigFile(conf_path.c_str());
+       if(!succeeded)
+               return "";
+       if(!conf.exists("gameid"))
+               return "";
+       return conf.get("gameid");
+}
+
diff --git a/src/subgame.h b/src/subgame.h
new file mode 100644 (file)
index 0000000..ba2f235
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+Minetest-c55
+Copyright (C) 2011 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#ifndef SUBGAME_HEADER
+#define SUBGAME_HEADER
+
+#include <string>
+#include <set>
+
+struct SubgameSpec
+{
+       std::string id; // "" = game does not exist
+       std::string path;
+       std::set<std::string> addon_paths;
+
+       SubgameSpec(const std::string &id_="",
+                       const std::string &path_="",
+                       const std::set<std::string> &addon_paths_=std::set<std::string>()):
+               id(id_),
+               path(path_),
+               addon_paths(addon_paths_)
+       {}
+
+       bool isValid() const
+       {
+               return (id != "" && path != "");
+       }
+};
+
+SubgameSpec findSubgame(const std::string &id);
+
+std::set<std::string> getAvailableGameIds();
+
+std::string getWorldGameId(const std::string &world_path);
+
+#endif
+