diff options
author | Perttu Ahola <celeron55@gmail.com> | 2012-03-11 20:45:14 +0200 |
---|---|---|
committer | Perttu Ahola <celeron55@gmail.com> | 2012-03-11 20:45:14 +0200 |
commit | d1d83d7e7f5e2e7cbef5272eda9c580129e301a3 (patch) | |
tree | 2fc04eeae8cac55e6d17cccceecb9450fddd4f12 | |
parent | bcaab74f1f4cb8c9fcd65cc8cb8bd290834bf72f (diff) | |
download | minetest-d1d83d7e7f5e2e7cbef5272eda9c580129e301a3.tar.gz minetest-d1d83d7e7f5e2e7cbef5272eda9c580129e301a3.tar.bz2 minetest-d1d83d7e7f5e2e7cbef5272eda9c580129e301a3.zip |
World selection box in main menu (and random fixing)
-rw-r--r-- | minetest.conf.example | 2 | ||||
-rw-r--r-- | src/defaultsettings.cpp | 2 | ||||
-rw-r--r-- | src/guiMainMenu.cpp | 85 | ||||
-rw-r--r-- | src/guiMainMenu.h | 12 | ||||
-rw-r--r-- | src/main.cpp | 207 | ||||
-rw-r--r-- | src/subgame.cpp | 57 | ||||
-rw-r--r-- | src/subgame.h | 28 |
7 files changed, 291 insertions, 102 deletions
diff --git a/minetest.conf.example b/minetest.conf.example index a82ead6e8..4e55a34f4 100644 --- a/minetest.conf.example +++ b/minetest.conf.example @@ -115,6 +115,8 @@ # Server stuff # +# Default game (default when creating a new world) +#default_game = mesetint # Map directory (everything in the world is stored here) #map-dir = /custom/map # Message of the Day diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp index 23199eef4..67626d34a 100644 --- a/src/defaultsettings.cpp +++ b/src/defaultsettings.cpp @@ -94,8 +94,10 @@ void set_default_settings(Settings *settings) settings->setDefault("opaque_water", "false"); settings->setDefault("console_color", "(0,0,0)"); settings->setDefault("console_alpha", "200"); + // Server stuff // "map-dir" doesn't exist by default. + settings->setDefault("default_game", "mesetint"); settings->setDefault("motd", ""); settings->setDefault("max_users", "100"); settings->setDefault("strict_protocol_version_checking", "true"); diff --git a/src/guiMainMenu.cpp b/src/guiMainMenu.cpp index 5c6104ca3..68348cbb2 100644 --- a/src/guiMainMenu.cpp +++ b/src/guiMainMenu.cpp @@ -27,6 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include <IGUIButton.h> #include <IGUIStaticText.h> #include <IGUIFont.h> +#include <IGUIListBox.h> #include "gettext.h" @@ -73,65 +74,52 @@ void GUIMainMenu::removeChildren() void GUIMainMenu::regenerateGui(v2u32 screensize) { - std::wstring text_name; - std::wstring text_address; - std::wstring text_port; - bool creative_mode; - bool enable_damage; - bool fancy_trees; - bool smooth_lighting; - bool clouds_3d; - bool opaque_water; + std::wstring text_name = m_data->name; + std::wstring text_address = m_data->address; + std::wstring text_port = m_data->port; + bool creative_mode = m_data->creative_mode; + bool enable_damage = m_data->enable_damage; + bool fancy_trees = m_data->fancy_trees; + bool smooth_lighting = m_data->smooth_lighting; + bool clouds_3d = m_data->clouds_3d; + bool opaque_water = m_data->opaque_water; + int selected_world = m_data->selected_world; // Client options { gui::IGUIElement *e = getElementFromId(GUI_ID_NAME_INPUT); if(e != NULL) text_name = e->getText(); - else - text_name = m_data->name; } { gui::IGUIElement *e = getElementFromId(GUI_ID_ADDRESS_INPUT); if(e != NULL) text_address = e->getText(); - else - text_address = m_data->address; } { gui::IGUIElement *e = getElementFromId(GUI_ID_PORT_INPUT); if(e != NULL) text_port = e->getText(); - else - text_port = m_data->port; } { gui::IGUIElement *e = getElementFromId(GUI_ID_FANCYTREE_CB); if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX) fancy_trees = ((gui::IGUICheckBox*)e)->isChecked(); - else - fancy_trees = m_data->fancy_trees; } { gui::IGUIElement *e = getElementFromId(GUI_ID_SMOOTH_LIGHTING_CB); if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX) smooth_lighting = ((gui::IGUICheckBox*)e)->isChecked(); - else - smooth_lighting = m_data->smooth_lighting; } { gui::IGUIElement *e = getElementFromId(GUI_ID_3D_CLOUDS_CB); if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX) clouds_3d = ((gui::IGUICheckBox*)e)->isChecked(); - else - clouds_3d = m_data->clouds_3d; } { gui::IGUIElement *e = getElementFromId(GUI_ID_OPAQUE_WATER_CB); if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX) opaque_water = ((gui::IGUICheckBox*)e)->isChecked(); - else - opaque_water = m_data->opaque_water; } // Server options @@ -139,15 +127,16 @@ void GUIMainMenu::regenerateGui(v2u32 screensize) gui::IGUIElement *e = getElementFromId(GUI_ID_CREATIVE_CB); if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX) creative_mode = ((gui::IGUICheckBox*)e)->isChecked(); - else - creative_mode = m_data->creative_mode; } { gui::IGUIElement *e = getElementFromId(GUI_ID_DAMAGE_CB); if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX) enable_damage = ((gui::IGUICheckBox*)e)->isChecked(); - else - enable_damage = m_data->enable_damage; + } + { + gui::IGUIElement *e = getElementFromId(GUI_ID_WORLD_LISTBOX); + if(e != NULL && e->getType() == gui::EGUIET_LIST_BOX) + selected_world = ((gui::IGUIListBox*)e)->getSelected(); } /* @@ -318,24 +307,36 @@ void GUIMainMenu::regenerateGui(v2u32 screensize) // Server parameters { core::rect<s32> rect(0, 0, 250, 30); - rect += topleft_server + v2s32(35, 20); + rect += topleft_server + v2s32(20+250+20, 20); Environment->addCheckBox(creative_mode, rect, this, GUI_ID_CREATIVE_CB, wgettext("Creative Mode")); } { core::rect<s32> rect(0, 0, 250, 30); - rect += topleft_server + v2s32(35, 40); + rect += topleft_server + v2s32(20+250+20, 40); Environment->addCheckBox(enable_damage, rect, this, GUI_ID_DAMAGE_CB, wgettext("Enable Damage")); } // Map delete button { core::rect<s32> rect(0, 0, 130, 30); - //rect += topleft_server + v2s32(size_server.X-40-130, 100+25); - rect += topleft_server + v2s32(40, 90); + rect += topleft_server + v2s32(20+250+20, 90); Environment->addButton(rect, this, GUI_ID_DELETE_MAP_BUTTON, wgettext("Delete map")); } + // World selection listbox + { + core::rect<s32> rect(0, 0, 250, 120); + rect += topleft_server + v2s32(20, 10); + gui::IGUIListBox *e = Environment->addListBox(rect, this, + GUI_ID_WORLD_LISTBOX); + e->setDrawBackground(true); + for(std::list<std::wstring>::const_iterator i = m_data->worlds.begin(); + i != m_data->worlds.end(); i++){ + e->addItem(i->c_str()); + } + e->setSelected(selected_world); + } changeCtype("C"); } @@ -418,6 +419,12 @@ void GUIMainMenu::acceptInput() if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX) m_data->opaque_water = ((gui::IGUICheckBox*)e)->isChecked(); } + + { + gui::IGUIElement *e = getElementFromId(GUI_ID_WORLD_LISTBOX); + if(e != NULL && e->getType() == gui::EGUIET_LIST_BOX) + m_data->selected_world = ((gui::IGUIListBox*)e)->getSelected(); + } m_accepted = true; } @@ -466,9 +473,8 @@ bool GUIMainMenu::OnEvent(const SEvent& event) return true; } case GUI_ID_DELETE_MAP_BUTTON: // Delete map - // Don't accept input data, just set deletion request - m_data->delete_map = true; - m_accepted = true; + acceptInput(); + m_data->delete_world = true; quitMenu(); return true; } @@ -483,6 +489,17 @@ bool GUIMainMenu::OnEvent(const SEvent& event) return true; } } + if(event.GUIEvent.EventType==gui::EGET_LISTBOX_SELECTED_AGAIN) + { + switch(event.GUIEvent.Caller->getID()) + { + case GUI_ID_WORLD_LISTBOX: + acceptInput(); + m_data->address = L""; // Force local game + quitMenu(); + return true; + } + } } return Parent ? Parent->OnEvent(event) : false; diff --git a/src/guiMainMenu.h b/src/guiMainMenu.h index ba2fc6be5..8ef286245 100644 --- a/src/guiMainMenu.h +++ b/src/guiMainMenu.h @@ -26,6 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include <string> // For IGameCallback #include "guiPauseMenu.h" +#include <list> enum { @@ -41,7 +42,8 @@ enum GUI_ID_CREATIVE_CB, GUI_ID_JOIN_GAME_BUTTON, GUI_ID_CHANGE_KEYS_BUTTON, - GUI_ID_DELETE_MAP_BUTTON + GUI_ID_DELETE_MAP_BUTTON, + GUI_ID_WORLD_LISTBOX, }; struct MainMenuData @@ -53,8 +55,9 @@ struct MainMenuData // Server opts creative_mode(false), enable_damage(false), + selected_world(0), // Actions - delete_map(false) + delete_world(false) {} // These are in the native format of the gui elements @@ -71,8 +74,11 @@ struct MainMenuData // Server options bool creative_mode; bool enable_damage; + int selected_world; // If map deletion is requested, this is set to true - bool delete_map; + bool delete_world; + + std::list<std::wstring> worlds; }; class GUIMainMenu : public GUIModalMenu diff --git a/src/main.cpp b/src/main.cpp index 73469471d..01c9b2c5c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -972,60 +972,29 @@ int main(int argc, char *argv[]) if(port == 0) port = 30000; - // Map directory - std::string world_path = porting::path_user + DIR_DELIM + "server" + DIR_DELIM + "worlds" + DIR_DELIM + "world"; + // World directory + std::string commanded_world = ""; if(cmd_args.exists("world")) - world_path = cmd_args.get("world"); + commanded_world = cmd_args.get("world"); else if(cmd_args.exists("map-dir")) - world_path = cmd_args.get("map-dir"); + commanded_world = cmd_args.get("map-dir"); else if(g_settings->exists("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_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_world_path<<"\""<<std::endl; - world_path = legacy_world_path; - } - } + commanded_world = g_settings->get("map-dir"); - // 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; + // Gamespec + SubgameSpec commanded_gamespec; + if(cmd_args.exists("gameid")){ + std::string gameid = cmd_args.get("gameid"); + commanded_gamespec = findSubgame(gameid); + if(!commanded_gamespec.isValid()){ + errorstream<<"Game \""<<gameid<<"\" not found"<<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; - return 1; - } - - // Run dedicated server if asked to or no other option + /* + Run dedicated server if asked to or no other option + */ #ifdef SERVER bool run_dedicated_server = true; #else @@ -1034,12 +1003,50 @@ int main(int argc, char *argv[]) if(run_dedicated_server) { DSTACK("Dedicated server branch"); - // Create time getter if built with Irrlicht #ifndef SERVER g_timegetter = new SimpleTimeGetter(); #endif + + // World directory + std::string world_path; + bool is_legacy_world = false; + if(commanded_world != ""){ + world_path = commanded_world; + } + else{ + // No specific world was commanded + // Check if the world is found from the default directory, and if + // not, see if the legacy world directory exists. + world_path = porting::path_user + DIR_DELIM + "server" + DIR_DELIM + "worlds" + DIR_DELIM + "world"; + 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_world_path<<"\""<<std::endl; + world_path = legacy_world_path; + is_legacy_world = true; + } + } + + // Gamespec + std::string world_gameid = getWorldGameId(world_path, is_legacy_world); + SubgameSpec gamespec = findSubgame(world_gameid); + if(commanded_gamespec.isValid() && + commanded_gamespec.id != world_gameid){ + errorstream<<"WARNING: Overriding gameid from \"" + <<world_gameid<<"\" to \"" + <<commanded_gamespec.id<<"\""<<std::endl; + gamespec = commanded_gamespec; + } + + if(!gamespec.isValid()){ + errorstream<<"Invalid gamespec. (world_gameid=" + <<world_gameid<<")"<<std::endl; + return 1; + } + infostream<<"Using gamespec \""<<gamespec.id<<"\""<<std::endl; + // Create server Server server(world_path, configpath, gamespec); server.start(port); @@ -1181,6 +1188,8 @@ int main(int argc, char *argv[]) //skin->setColor(gui::EGDC_3D_SHADOW, video::SColor(0,0,0,0)); skin->setColor(gui::EGDC_3D_HIGH_LIGHT, video::SColor(255,0,0,0)); skin->setColor(gui::EGDC_3D_SHADOW, video::SColor(255,0,0,0)); + skin->setColor(gui::EGDC_HIGH_LIGHT, video::SColor(255,70,100,50)); + skin->setColor(gui::EGDC_HIGH_LIGHT_TEXT, video::SColor(255,255,255,255)); /* GUI stuff @@ -1223,6 +1232,9 @@ int main(int argc, char *argv[]) guiroot = guienv->addStaticText(L"", core::rect<s32>(0, 0, 10000, 10000)); + SubgameSpec gamespec; + WorldSpec worldspec; + /* Out-of-game menu loop. @@ -1246,14 +1258,34 @@ int main(int argc, char *argv[]) menudata.address = narrow_to_wide(address); menudata.name = narrow_to_wide(playername); menudata.port = narrow_to_wide(itos(port)); + if(cmd_args.exists("password")) + menudata.password = narrow_to_wide(cmd_args.get("password")); menudata.fancy_trees = g_settings->getBool("new_style_leaves"); menudata.smooth_lighting = g_settings->getBool("smooth_lighting"); menudata.clouds_3d = g_settings->getBool("enable_3d_clouds"); menudata.opaque_water = g_settings->getBool("opaque_water"); menudata.creative_mode = g_settings->getBool("creative_mode"); menudata.enable_damage = g_settings->getBool("enable_damage"); - if(cmd_args.exists("password")) - menudata.password = narrow_to_wide(cmd_args.get("password")); + // Get world listing for the menu + std::vector<WorldSpec> worldspecs = getAvailableWorlds(); + for(std::vector<WorldSpec>::const_iterator i = worldspecs.begin(); + i != worldspecs.end(); i++) + menudata.worlds.push_back(narrow_to_wide( + i->name + " [" + i->gameid + "]")); + // Select if there is only one + if(worldspecs.size() == 1) + menudata.selected_world = 0; + else + menudata.selected_world = -1; + // If a world was commanded, append and select it + if(commanded_world != ""){ + std::string gameid = getWorldGameId(commanded_world); + WorldSpec spec(commanded_world, "[commanded world]", gameid); + worldspecs.push_back(spec); + menudata.worlds.push_back(narrow_to_wide(spec.name) + +L" ["+narrow_to_wide(spec.gameid)+L"]"); + menudata.selected_world = menudata.worlds.size()-1; + } if(skip_main_menu == false) { @@ -1304,15 +1336,33 @@ int main(int argc, char *argv[]) infostream<<"Dropping main menu"<<std::endl; menu->drop(); - - // Delete map if requested - if(menudata.delete_map) - { - bool r = fs::RecursiveDeleteContent(world_path); - if(r == false) - error_message = L"Delete failed"; + } + + // Set world path to selected one + if(menudata.selected_world != -1){ + worldspec = worldspecs[menudata.selected_world]; + infostream<<"Selected world: "<<worldspec.name + <<" ["<<worldspec.path<<"]"<<std::endl; + } + + // Delete map if requested + if(menudata.delete_world) + { + if(menudata.selected_world == -1){ + error_message = L"Cannot delete world: " + L"no world selected"; + errorstream<<wide_to_narrow(error_message)<<std::endl; continue; } + /*bool r = fs::RecursiveDeleteContent(worldspec.path); + if(r == false){ + error_message = L"World delete failed"; + errorstream<<wide_to_narrow(error_message)<<std::endl; + }*/ + // TODO: Some kind of a yes/no dialog is needed. + error_message = L"This doesn't do anything currently."; + errorstream<<wide_to_narrow(error_message)<<std::endl; + continue; } playername = wide_to_narrow(menudata.name); @@ -1336,7 +1386,40 @@ int main(int argc, char *argv[]) // Update configuration file if(configpath != "") g_settings->updateConfigFile(configpath.c_str()); - + + // If local game + if(address == "") + { + if(menudata.selected_world == -1){ + error_message = L"No world selected and no address " + L"provided. Nothing to do."; + errorstream<<wide_to_narrow(error_message)<<std::endl; + continue; + } + // Load gamespec for required game + gamespec = findSubgame(worldspec.gameid); + if(!gamespec.isValid() && !commanded_gamespec.isValid()){ + error_message = L"Could not find or load game \"" + + narrow_to_wide(worldspec.gameid) + L"\""; + errorstream<<wide_to_narrow(error_message)<<std::endl; + continue; + } + if(commanded_gamespec.isValid() && + commanded_gamespec.id != worldspec.gameid){ + errorstream<<"WARNING: Overriding gamespec from \"" + <<worldspec.gameid<<"\" to \"" + <<commanded_gamespec.id<<"\""<<std::endl; + gamespec = commanded_gamespec; + } + + if(!gamespec.isValid()){ + error_message = L"Invalid gamespec. (world_gameid=" + +narrow_to_wide(worldspec.gameid)+L")"; + errorstream<<wide_to_narrow(error_message)<<std::endl; + continue; + } + } + // Continue to game break; } @@ -1354,7 +1437,7 @@ int main(int argc, char *argv[]) input, device, font, - world_path, + worldspec.path, playername, password, address, @@ -1368,13 +1451,13 @@ int main(int argc, char *argv[]) } //try catch(con::PeerNotFoundException &e) { - errorstream<<"Connection error (timed out?)"<<std::endl; error_message = L"Connection error (timed out?)"; + errorstream<<wide_to_narrow(error_message)<<std::endl; } - catch(SocketException &e) + catch(ServerError &e) { - errorstream<<"Socket error (port already in use?)"<<std::endl; - error_message = L"Socket error (port already in use?)"; + error_message = narrow_to_wide(e.what()); + errorstream<<wide_to_narrow(error_message)<<std::endl; } catch(ModError &e) { diff --git a/src/subgame.cpp b/src/subgame.cpp index ed50d09a4..2fa3b7944 100644 --- a/src/subgame.cpp +++ b/src/subgame.cpp @@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "porting.h" #include "filesys.h" #include "settings.h" +#include "log.h" SubgameSpec findSubgame(const std::string &id) { @@ -68,15 +69,67 @@ std::set<std::string> getAvailableGameIds() return gameids; } -std::string getWorldGameId(const std::string &world_path) +#define LEGACY_GAMEID "mesetint" + +std::string getWorldGameId(const std::string &world_path, bool can_be_legacy) { std::string conf_path = world_path + DIR_DELIM + "world.mt"; Settings conf; bool succeeded = conf.readConfigFile(conf_path.c_str()); - if(!succeeded) + if(!succeeded){ + if(can_be_legacy){ + // If map_meta.txt exists, it is probably an old minetest world + if(fs::PathExists(world_path + DIR_DELIM + "map_meta.txt")) + return LEGACY_GAMEID; + } return ""; + } if(!conf.exists("gameid")) return ""; return conf.get("gameid"); } +std::vector<WorldSpec> getAvailableWorlds() +{ + std::vector<WorldSpec> worlds; + std::set<std::string> worldspaths; + worldspaths.insert(porting::path_user + DIR_DELIM + "server" + + DIR_DELIM + "worlds"); + infostream<<"Searching worlds..."<<std::endl; + for(std::set<std::string>::const_iterator i = worldspaths.begin(); + i != worldspaths.end(); i++){ + infostream<<" In "<<(*i)<<": "<<std::endl; + std::vector<fs::DirListNode> dirvector = fs::GetDirListing(*i); + for(u32 j=0; j<dirvector.size(); j++){ + if(!dirvector[j].dir) + continue; + std::string fullpath = *i + DIR_DELIM + dirvector[j].name; + std::string name = dirvector[j].name; + std::string gameid = getWorldGameId(fullpath); + WorldSpec spec(fullpath, name, gameid); + if(!spec.isValid()){ + infostream<<"(invalid: "<<name<<") "; + } else { + infostream<<name<<" "; + worlds.push_back(spec); + } + } + infostream<<std::endl; + } + // Check old world location + do{ + std::string fullpath = porting::path_user + DIR_DELIM + ".." + + DIR_DELIM + "world"; + if(!fs::PathExists(fullpath)) + break; + std::string name = "Old World"; + std::string gameid = getWorldGameId(fullpath, true); + WorldSpec spec(fullpath, name, gameid); + infostream<<"Old world found."<<std::endl; + worlds.push_back(spec); + }while(0); + infostream<<worlds.size()<<" found."<<std::endl; + return worlds; +} + + diff --git a/src/subgame.h b/src/subgame.h index ba2f235ed..1daeb8b15 100644 --- a/src/subgame.h +++ b/src/subgame.h @@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include <string> #include <set> +#include <vector> struct SubgameSpec { @@ -47,7 +48,32 @@ SubgameSpec findSubgame(const std::string &id); std::set<std::string> getAvailableGameIds(); -std::string getWorldGameId(const std::string &world_path); +std::string getWorldGameId(const std::string &world_path, + bool can_be_legacy=false); + +struct WorldSpec +{ + std::string path; + std::string name; + std::string gameid; + + WorldSpec( + const std::string &path_="", + const std::string &name_="", + const std::string &gameid_="" + ): + path(path_), + name(name_), + gameid(gameid_) + {} + + bool isValid() const + { + return (name != "" && path != "" && gameid != ""); + } +}; + +std::vector<WorldSpec> getAvailableWorlds(); #endif |