From d1d83d7e7f5e2e7cbef5272eda9c580129e301a3 Mon Sep 17 00:00:00 2001 From: Perttu Ahola Date: Sun, 11 Mar 2012 20:45:14 +0200 Subject: [PATCH] World selection box in main menu (and random fixing) --- minetest.conf.example | 2 + src/defaultsettings.cpp | 2 + src/guiMainMenu.cpp | 85 ++++++++++------- src/guiMainMenu.h | 12 ++- src/main.cpp | 207 ++++++++++++++++++++++++++++------------ src/subgame.cpp | 57 ++++++++++- 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 #include #include +#include #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 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 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 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 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::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 // For IGameCallback #include "guiPauseMenu.h" +#include 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 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 \"" - <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"<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(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 worldspecs = getAvailableWorlds(); + for(std::vector::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"<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: "<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< 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 getAvailableWorlds() +{ + std::vector worlds; + std::set worldspaths; + worldspaths.insert(porting::path_user + DIR_DELIM + "server" + + DIR_DELIM + "worlds"); + infostream<<"Searching worlds..."<::const_iterator i = worldspaths.begin(); + i != worldspaths.end(); i++){ + infostream<<" In "<<(*i)<<": "< dirvector = fs::GetDirListing(*i); + for(u32 j=0; j #include +#include struct SubgameSpec { @@ -47,7 +48,32 @@ SubgameSpec findSubgame(const std::string &id); std::set 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 getAvailableWorlds(); #endif