From 591527d8787b6dfaafd2113bc001fe892b3eb0fb Mon Sep 17 00:00:00 2001 From: Perttu Ahola Date: Tue, 13 Mar 2012 00:06:37 +0200 Subject: [PATCH] World creation button and dialog and functionality --- src/CMakeLists.txt | 1 + src/guiCreateWorld.cpp | 255 +++++++++++++++++++++++++++++++++++++++ src/guiCreateWorld.h | 63 ++++++++++ src/guiKeyChangeMenu.cpp | 22 ++++ src/guiKeyChangeMenu.h | 22 ---- src/guiMainMenu.cpp | 77 +++++++++++- src/guiMainMenu.h | 69 ++++------- src/main.cpp | 20 ++- src/server.cpp | 11 +- src/subgame.cpp | 28 ++++- src/subgame.h | 11 +- 11 files changed, 492 insertions(+), 87 deletions(-) create mode 100644 src/guiCreateWorld.cpp create mode 100644 src/guiCreateWorld.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index cec42719a..18184365f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -179,6 +179,7 @@ set(minetest_SRCS guiPasswordChange.cpp guiDeathScreen.cpp guiChatConsole.cpp + guiCreateWorld.cpp client.cpp tile.cpp game.cpp diff --git a/src/guiCreateWorld.cpp b/src/guiCreateWorld.cpp new file mode 100644 index 000000000..7143f9558 --- /dev/null +++ b/src/guiCreateWorld.cpp @@ -0,0 +1,255 @@ +/* +Minetest-c55 +Copyright (C) 2012 celeron55, Perttu Ahola + +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 "guiCreateWorld.h" +#include "debug.h" +#include "serialization.h" +#include +#include +#include +#include +#include +#include +#include + +#include "gettext.h" + +enum +{ + GUI_ID_NAME_INPUT = 101, + GUI_ID_GAME_LISTBOX, + GUI_ID_CREATE, + GUI_ID_CANCEL +}; + +GUICreateWorld::GUICreateWorld(gui::IGUIEnvironment* env, + gui::IGUIElement* parent, s32 id, + IMenuManager *menumgr, + CreateWorldDest *dest, + const std::vector &games +): + GUIModalMenu(env, parent, id, menumgr), + m_dest(dest), + m_games(games) +{ + assert(games.size() > 0); +} + +GUICreateWorld::~GUICreateWorld() +{ + removeChildren(); + if(m_dest) + delete m_dest; +} + +void GUICreateWorld::removeChildren() +{ + const core::list &children = getChildren(); + core::list children_copy; + for(core::list::ConstIterator + i = children.begin(); i != children.end(); i++) + { + children_copy.push_back(*i); + } + for(core::list::Iterator + i = children_copy.begin(); + i != children_copy.end(); i++) + { + (*i)->remove(); + } +} + +void GUICreateWorld::regenerateGui(v2u32 screensize) +{ + std::wstring name = L""; + + { + gui::IGUIElement *e = getElementFromId(GUI_ID_NAME_INPUT); + if(e != NULL) + name = e->getText(); + } + + /* + Remove stuff + */ + removeChildren(); + + /* + Calculate new sizes and positions + */ + core::rect rect( + screensize.X/2 - 580/2, + screensize.Y/2 - 300/2, + screensize.X/2 + 580/2, + screensize.Y/2 + 300/2 + ); + + DesiredRect = rect; + recalculateAbsolutePosition(false); + + v2s32 size = rect.getSize(); + + v2s32 topleft = v2s32(10+80, 10+70); + + /* + Add stuff + */ + { + core::rect rect(0, 0, 100, 20); + rect += v2s32(0, 5) + topleft; + Environment->addStaticText(wgettext("World name"), + rect, false, true, this, -1); + } + { + core::rect rect(0, 0, 300, 30); + rect = rect + v2s32(100, 0) + topleft; + gui::IGUIElement *e = + Environment->addEditBox(name.c_str(), rect, true, this, GUI_ID_NAME_INPUT); + Environment->setFocus(e); + + irr::SEvent evt; + evt.EventType = EET_KEY_INPUT_EVENT; + evt.KeyInput.Key = KEY_END; + evt.KeyInput.PressedDown = true; + e->OnEvent(evt); + } + { + core::rect rect(0, 0, 100, 20); + rect += v2s32(0, 40+5) + topleft; + Environment->addStaticText(wgettext("Game"), + rect, false, true, this, -1); + } + { + core::rect rect(0, 0, 300, 80); + rect += v2s32(100, 40) + topleft; + gui::IGUIListBox *e = Environment->addListBox(rect, this, + GUI_ID_GAME_LISTBOX); + e->setDrawBackground(true); + for(u32 i=0; iaddItem(os.str().c_str()); + } + e->setSelected(0); + } + changeCtype(""); + { + core::rect rect(0, 0, 120, 30); + rect = rect + v2s32(170, 140) + topleft; + Environment->addButton(rect, this, GUI_ID_CANCEL, + wgettext("Cancel")); + } + { + core::rect rect(0, 0, 120, 30); + rect = rect + v2s32(300, 140) + topleft; + Environment->addButton(rect, this, GUI_ID_CREATE, + wgettext("Create")); + } + changeCtype("C"); +} + +void GUICreateWorld::drawMenu() +{ + gui::IGUISkin* skin = Environment->getSkin(); + if (!skin) + return; + video::IVideoDriver* driver = Environment->getVideoDriver(); + + video::SColor bgcolor(140,0,0,0); + driver->draw2DRectangle(bgcolor, AbsoluteRect, &AbsoluteClippingRect); + + gui::IGUIElement::draw(); +} + +void GUICreateWorld::acceptInput() +{ + if(m_dest) + { + gui::IGUIElement *e = getElementFromId(GUI_ID_NAME_INPUT); + if(e != NULL) + { + m_dest->accepted(e->getText(), m_games[0].id); + } + delete m_dest; + m_dest = NULL; + } +} + +bool GUICreateWorld::OnEvent(const SEvent& event) +{ + if(event.EventType==EET_KEY_INPUT_EVENT) + { + if(event.KeyInput.Key==KEY_ESCAPE && event.KeyInput.PressedDown) + { + quitMenu(); + return true; + } + if(event.KeyInput.Key==KEY_RETURN && event.KeyInput.PressedDown) + { + acceptInput(); + quitMenu(); + return true; + } + } + if(event.EventType==EET_GUI_EVENT) + { + if(event.GUIEvent.EventType==gui::EGET_ELEMENT_FOCUS_LOST + && isVisible()) + { + if(!canTakeFocus(event.GUIEvent.Element)) + { + dstream<<"GUICreateWorld: Not allowing focus change." + <getID()){ + case GUI_ID_CANCEL: + quitMenu(); + return true; + break; + case GUI_ID_CREATE: + accept_input = true; + break; + } + } + if(event.GUIEvent.EventType==gui::EGET_EDITBOX_ENTER){ + switch(event.GUIEvent.Caller->getID()){ + case GUI_ID_NAME_INPUT: + accept_input = true; + break; + } + } + if(accept_input){ + acceptInput(); + quitMenu(); + // quitMenu deallocates menu + return true; + } + } + + return Parent ? Parent->OnEvent(event) : false; +} + diff --git a/src/guiCreateWorld.h b/src/guiCreateWorld.h new file mode 100644 index 000000000..525b449eb --- /dev/null +++ b/src/guiCreateWorld.h @@ -0,0 +1,63 @@ +/* +Minetest-c55 +Copyright (C) 2012 celeron55, Perttu Ahola + +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 GUICREATEWORLD_HEADER +#define GUICREATEWORLD_HEADER + +#include "common_irrlicht.h" +#include "modalMenu.h" +#include "utility.h" +#include +#include "subgame.h" + +struct CreateWorldDest +{ + virtual void accepted(std::wstring name, std::string gameid) = 0; + virtual ~CreateWorldDest() {}; +}; + +class GUICreateWorld : public GUIModalMenu +{ +public: + GUICreateWorld(gui::IGUIEnvironment* env, + gui::IGUIElement* parent, s32 id, + IMenuManager *menumgr, + CreateWorldDest *dest, + const std::vector &games); + ~GUICreateWorld(); + + void removeChildren(); + /* + Remove and re-add (or reposition) stuff + */ + void regenerateGui(v2u32 screensize); + + void drawMenu(); + + void acceptInput(); + + bool OnEvent(const SEvent& event); + +private: + CreateWorldDest *m_dest; + std::vector m_games; +}; + +#endif + diff --git a/src/guiKeyChangeMenu.cpp b/src/guiKeyChangeMenu.cpp index 0c84f8ffa..fb49ab659 100644 --- a/src/guiKeyChangeMenu.cpp +++ b/src/guiKeyChangeMenu.cpp @@ -31,6 +31,28 @@ #include #include "settings.h" +enum +{ + GUI_ID_BACK_BUTTON = 101, GUI_ID_ABORT_BUTTON, GUI_ID_SCROLL_BAR, + //buttons + GUI_ID_KEY_FORWARD_BUTTON, + GUI_ID_KEY_BACKWARD_BUTTON, + GUI_ID_KEY_LEFT_BUTTON, + GUI_ID_KEY_RIGHT_BUTTON, + GUI_ID_KEY_USE_BUTTON, + GUI_ID_KEY_FLY_BUTTON, + GUI_ID_KEY_FAST_BUTTON, + GUI_ID_KEY_JUMP_BUTTON, + GUI_ID_KEY_CHAT_BUTTON, + GUI_ID_KEY_CMD_BUTTON, + GUI_ID_KEY_CONSOLE_BUTTON, + GUI_ID_KEY_SNEAK_BUTTON, + GUI_ID_KEY_DROP_BUTTON, + GUI_ID_KEY_INVENTORY_BUTTON, + GUI_ID_KEY_DUMP_BUTTON, + GUI_ID_KEY_RANGE_BUTTON +}; + GUIKeyChangeMenu::GUIKeyChangeMenu(gui::IGUIEnvironment* env, gui::IGUIElement* parent, s32 id, IMenuManager *menumgr) : GUIModalMenu(env, parent, id, menumgr) diff --git a/src/guiKeyChangeMenu.h b/src/guiKeyChangeMenu.h index 9772bde3c..1ff3d4045 100644 --- a/src/guiKeyChangeMenu.h +++ b/src/guiKeyChangeMenu.h @@ -30,28 +30,6 @@ #include "keycode.h" #include -enum -{ - GUI_ID_BACK_BUTTON = 101, GUI_ID_ABORT_BUTTON, GUI_ID_SCROLL_BAR, - //buttons - GUI_ID_KEY_FORWARD_BUTTON, - GUI_ID_KEY_BACKWARD_BUTTON, - GUI_ID_KEY_LEFT_BUTTON, - GUI_ID_KEY_RIGHT_BUTTON, - GUI_ID_KEY_USE_BUTTON, - GUI_ID_KEY_FLY_BUTTON, - GUI_ID_KEY_FAST_BUTTON, - GUI_ID_KEY_JUMP_BUTTON, - GUI_ID_KEY_CHAT_BUTTON, - GUI_ID_KEY_CMD_BUTTON, - GUI_ID_KEY_CONSOLE_BUTTON, - GUI_ID_KEY_SNEAK_BUTTON, - GUI_ID_KEY_DROP_BUTTON, - GUI_ID_KEY_INVENTORY_BUTTON, - GUI_ID_KEY_DUMP_BUTTON, - GUI_ID_KEY_RANGE_BUTTON -}; - class GUIKeyChangeMenu: public GUIModalMenu { public: diff --git a/src/guiMainMenu.cpp b/src/guiMainMenu.cpp index 184984051..6d07fe973 100644 --- a/src/guiMainMenu.cpp +++ b/src/guiMainMenu.cpp @@ -1,6 +1,6 @@ /* Minetest-c55 -Copyright (C) 2010 celeron55, Perttu Ahola +Copyright (C) 2010-12 celeron55, Perttu Ahola 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 @@ -19,6 +19,8 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "guiMainMenu.h" #include "guiKeyChangeMenu.h" +#include "guiCreateWorld.h" +#include "guiMessageMenu.h" #include "debug.h" #include "serialization.h" #include @@ -28,9 +30,41 @@ with this program; if not, write to the Free Software Foundation, Inc., #include #include #include - - +// For IGameCallback +#include "guiPauseMenu.h" #include "gettext.h" +#include "utility.h" + +struct CreateWorldDestMainMenu : public CreateWorldDest +{ + CreateWorldDestMainMenu(GUIMainMenu *menu): + m_menu(menu) + {} + void accepted(std::wstring name, std::string gameid) + { + m_menu->createNewWorld(name, gameid); + } + GUIMainMenu *m_menu; +}; + +enum +{ + GUI_ID_QUIT_BUTTON = 101, + GUI_ID_NAME_INPUT, + GUI_ID_ADDRESS_INPUT, + GUI_ID_PORT_INPUT, + GUI_ID_FANCYTREE_CB, + GUI_ID_SMOOTH_LIGHTING_CB, + GUI_ID_3D_CLOUDS_CB, + GUI_ID_OPAQUE_WATER_CB, + GUI_ID_DAMAGE_CB, + GUI_ID_CREATIVE_CB, + GUI_ID_JOIN_GAME_BUTTON, + GUI_ID_CHANGE_KEYS_BUTTON, + GUI_ID_DELETE_WORLD_BUTTON, + GUI_ID_CREATE_WORLD_BUTTON, + GUI_ID_WORLD_LISTBOX, +}; GUIMainMenu::GUIMainMenu(gui::IGUIEnvironment* env, gui::IGUIElement* parent, s32 id, @@ -264,6 +298,13 @@ void GUIMainMenu::regenerateGui(v2u32 screensize) Environment->addButton(rect, this, GUI_ID_DELETE_WORLD_BUTTON, wgettext("Delete world")); } + // Create world button + { + core::rect rect(0, 0, 130, 30); + rect += topleft_server + v2s32(20+250+20+140, 90); + Environment->addButton(rect, this, GUI_ID_CREATE_WORLD_BUTTON, + wgettext("Create world")); + } // World selection listbox { core::rect rect(0, 0, 250, 120); @@ -407,7 +448,7 @@ bool GUIMainMenu::OnEvent(const SEvent& event) { switch(event.GUIEvent.Caller->getID()) { - case GUI_ID_JOIN_GAME_BUTTON: // Start game + case GUI_ID_JOIN_GAME_BUTTON: acceptInput(); quitMenu(); return true; @@ -416,12 +457,28 @@ bool GUIMainMenu::OnEvent(const SEvent& event) kmenu->drop(); return true; } - case GUI_ID_DELETE_WORLD_BUTTON: // Delete world + case GUI_ID_DELETE_WORLD_BUTTON: { acceptInput(); m_data->delete_world = true; quitMenu(); return true; } + case GUI_ID_CREATE_WORLD_BUTTON: { + std::vector games = getAvailableGames(); + if(games.size() == 0){ + GUIMessageMenu *menu = new GUIMessageMenu(env, parent, + -1, menumgr, + wgettext("Cannot create world: No games found")); + menu->drop(); + } else { + CreateWorldDest *dest = new CreateWorldDestMainMenu(this); + GUICreateWorld *menu = new GUICreateWorld(env, parent, -1, + menumgr, dest, games); + menu->drop(); + } + return true; + } + } } if(event.GUIEvent.EventType==gui::EGET_EDITBOX_ENTER) { @@ -449,3 +506,13 @@ bool GUIMainMenu::OnEvent(const SEvent& event) return Parent ? Parent->OnEvent(event) : false; } +void GUIMainMenu::createNewWorld(std::wstring name, std::string gameid) +{ + if(name == L"") + return; + acceptInput(); + m_data->create_world_name = name; + m_data->create_world_gameid = gameid; + quitMenu(); +} + diff --git a/src/guiMainMenu.h b/src/guiMainMenu.h index 8ea33cf13..08c585b88 100644 --- a/src/guiMainMenu.h +++ b/src/guiMainMenu.h @@ -1,6 +1,6 @@ /* Minetest-c55 -Copyright (C) 2010 celeron55, Perttu Ahola +Copyright (C) 2010-2012 celeron55, Perttu Ahola 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 @@ -22,46 +22,14 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "common_irrlicht.h" #include "modalMenu.h" -#include "utility.h" #include -// For IGameCallback -#include "guiPauseMenu.h" #include - -enum -{ - GUI_ID_QUIT_BUTTON = 101, - GUI_ID_NAME_INPUT, - GUI_ID_ADDRESS_INPUT, - GUI_ID_PORT_INPUT, - GUI_ID_FANCYTREE_CB, - GUI_ID_SMOOTH_LIGHTING_CB, - GUI_ID_3D_CLOUDS_CB, - GUI_ID_OPAQUE_WATER_CB, - GUI_ID_DAMAGE_CB, - GUI_ID_CREATIVE_CB, - GUI_ID_JOIN_GAME_BUTTON, - GUI_ID_CHANGE_KEYS_BUTTON, - GUI_ID_DELETE_WORLD_BUTTON, - GUI_ID_WORLD_LISTBOX, -}; +#include "subgame.h" +class IGameCallback; struct MainMenuData { - MainMenuData(): - // Client opts - fancy_trees(false), - smooth_lighting(false), - // Server opts - creative_mode(false), - enable_damage(false), - selected_world(0), - // Actions - delete_world(false) - {} - // These are in the native format of the gui elements - // Client options std::wstring address; std::wstring port; @@ -75,10 +43,25 @@ struct MainMenuData bool creative_mode; bool enable_damage; int selected_world; - // If map deletion is requested, this is set to true + // Actions bool delete_world; + std::wstring create_world_name; + std::string create_world_gameid; std::list worlds; + std::vector games; + + MainMenuData(): + // Client opts + fancy_trees(false), + smooth_lighting(false), + // Server opts + creative_mode(false), + enable_damage(false), + selected_world(0), + // Actions + delete_world(false) + {} }; class GUIMainMenu : public GUIModalMenu @@ -92,23 +75,15 @@ public: ~GUIMainMenu(); void removeChildren(); - /* - Remove and re-add (or reposition) stuff - */ + // Remove and re-add (or reposition) stuff void regenerateGui(v2u32 screensize); - void drawMenu(); - void readInput(MainMenuData *dst); - void acceptInput(); - bool getStatus() - { - return m_accepted; - } - + { return m_accepted; } bool OnEvent(const SEvent& event); + void createNewWorld(std::wstring name, std::string gameid); private: MainMenuData *m_data; diff --git a/src/main.cpp b/src/main.cpp index 41cf583f5..2f9c69fe1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1298,7 +1298,7 @@ int main(int argc, char *argv[]) std::string gameid = getWorldGameId(commanded_world, true); if(gameid == "") gameid = g_settings->get("default_game"); - WorldSpec spec(commanded_world, "[commanded world]", gameid); + WorldSpec spec(commanded_world, "--world", gameid); worldspecs.push_back(spec); menudata.worlds.push_back(narrow_to_wide(spec.name) +L" ["+narrow_to_wide(spec.gameid)+L"]"); @@ -1363,7 +1363,7 @@ int main(int argc, char *argv[]) <<" ["<set("selected_world_path", path); + continue; + } + playername = wide_to_narrow(menudata.name); password = translatePassword(playername, menudata.password); //infostream<<"Main: password hash: '"< getAvailableGameIds() @@ -69,6 +71,16 @@ std::set getAvailableGameIds() return gameids; } +std::vector getAvailableGames() +{ + std::vector specs; + std::set gameids = getAvailableGameIds(); + for(std::set::const_iterator i = gameids.begin(); + i != gameids.end(); i++) + specs.push_back(findSubgame(*i)); + return specs; +} + #define LEGACY_GAMEID "mesetint" std::string getWorldGameId(const std::string &world_path, bool can_be_legacy) @@ -132,4 +144,18 @@ std::vector getAvailableWorlds() return worlds; } +bool initializeWorld(const std::string &path, const std::string &gameid) +{ + infostream<<"Initializing world at "< addon_paths; + std::string name; SubgameSpec(const std::string &id_="", const std::string &path_="", - const std::set &addon_paths_=std::set()): + const std::set &addon_paths_=std::set(), + const std::string &name_=""): id(id_), path(path_), - addon_paths(addon_paths_) + addon_paths(addon_paths_), + name(name_) {} bool isValid() const @@ -47,6 +50,7 @@ struct SubgameSpec SubgameSpec findSubgame(const std::string &id); std::set getAvailableGameIds(); +std::vector getAvailableGames(); std::string getWorldGameId(const std::string &world_path, bool can_be_legacy=false); @@ -75,5 +79,8 @@ struct WorldSpec std::vector getAvailableWorlds(); +// Create world directory and world.mt if they don't exist +bool initializeWorld(const std::string &path, const std::string &gameid); + #endif