diff --git a/minetest.conf.example b/minetest.conf.example index 41e2dcab6..0cdccf20c 100644 --- a/minetest.conf.example +++ b/minetest.conf.example @@ -15,7 +15,6 @@ #viewing_range_nodes_min = 35 #screenW = 800 #screenH = 600 -#host_game = #port = 30000 #address = kray.dy.fi #name = diff --git a/minetest.vcproj b/minetest.vcproj index c8961ff6e..53481add7 100644 --- a/minetest.vcproj +++ b/minetest.vcproj @@ -136,7 +136,7 @@ /> + + @@ -227,6 +231,14 @@ RelativePath=".\src\irrlichtwrapper.cpp" > + + + + diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a9e3f2788..7913f4964 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -10,7 +10,7 @@ add_definitions ( -DUSE_CMAKE_CONFIG_H ) if(WIN32) # Windows - # Surpress some warnings + # Surpress some useless warnings add_definitions ( /D "_CRT_SECURE_NO_DEPRECATE" /W1 ) # Zlib stuff set(ZLIB_INCLUDE_DIR "${PROJECT_SOURCE_DIR}/../../zlib/zlib-1.2.5" @@ -39,6 +39,7 @@ configure_file( ) set(minetest_SRCS + guiMainMenu.cpp porting.cpp guiMessageMenu.cpp materials.cpp @@ -108,8 +109,11 @@ include_directories( set(EXECUTABLE_OUTPUT_PATH ../bin) +set(JTHREAD_LIBRARIES "jthread") +set(JTHREAD_SRCS "") + if(BUILD_CLIENT) - add_executable(minetest ${minetest_SRCS}) + add_executable(minetest ${minetest_SRCS} ${JTHREAD_SRCS}) target_link_libraries( minetest ${ZLIB_LIBRARIES} @@ -119,18 +123,18 @@ if(BUILD_CLIENT) ${BZIP2_LIBRARIES} ${PNG_LIBRARIES} ${X11_LIBRARIES} - jthread + ${JTHREAD_LIBRARIES} ${PLATFORM_LIBS} ${CLIENT_PLATFORM_LIBS} ) endif(BUILD_CLIENT) if(BUILD_SERVER) - add_executable(minetestserver ${minetestserver_SRCS}) + add_executable(minetestserver ${minetestserver_SRCS} ${JTHREAD_SRCS}) target_link_libraries( minetestserver ${ZLIB_LIBRARIES} - jthread + ${JTHREAD_LIBRARIES} ${PLATFORM_LIBS} ) endif(BUILD_SERVER) @@ -143,7 +147,11 @@ if(MSVC) # Visual Studio # EHa enables SEH exceptions (used for catching segfaults) - set(CMAKE_CXX_FLAGS_RELEASE "/EHa /MD /O2 /Ob2 /Oi /Ot /Oy /GL /FD /MT /GS- /arch:SSE /fp:fast /D NDEBUG") + set(CMAKE_CXX_FLAGS_RELEASE "/EHa /MD /O2 /Ob2 /Oi /Ot /Oy /GL /FD /MT /GS- /arch:SSE /fp:fast /D NDEBUG /D _HAS_ITERATOR_DEBUGGING=0 /TP") + set(CMAKE_EXE_LINKER_FLAGS_RELEASE "/LTCG /NODEFAULTLIB:\"libcmtd.lib\"") + + # Debug build doesn't catch exceptions by itself + # Add some optimizations because otherwise it's VERY slow set(CMAKE_CXX_FLAGS_DEBUG "/MDd /Zi /Ob0 /Od /RTC1") if(BUILD_SERVER) diff --git a/src/client.cpp b/src/client.cpp index 3853c25e5..d6062ef61 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -1209,8 +1209,8 @@ bool Client::AsyncProcessPacket() } //try catch(con::PeerNotFoundException &e) { - dout_client<isLocal() == false || getLocalPlayer() == NULL); + /* + It is a failure if player is local and there already is a local + player + */ + assert(!(player->isLocal() == true && getLocalPlayer() != NULL)); #endif if(player->peer_id != 0) assert(getPlayer(player->peer_id) == NULL); diff --git a/src/guiInventoryMenu.cpp b/src/guiInventoryMenu.cpp index d7af0a0b9..102a0ae72 100644 --- a/src/guiInventoryMenu.cpp +++ b/src/guiInventoryMenu.cpp @@ -79,8 +79,8 @@ GUIInventoryMenu::GUIInventoryMenu(gui::IGUIEnvironment* env, gui::IGUIElement* parent, s32 id, Inventory *inventory, Queue *actions, - int *active_menu_count): - GUIModalMenu(env, parent, id, active_menu_count) + IMenuManager *menumgr): + GUIModalMenu(env, parent, id, menumgr) { m_inventory = inventory; m_selected_item = NULL; diff --git a/src/guiInventoryMenu.h b/src/guiInventoryMenu.h index 82e7ee89d..6211bb24b 100644 --- a/src/guiInventoryMenu.h +++ b/src/guiInventoryMenu.h @@ -74,7 +74,7 @@ public: gui::IGUIElement* parent, s32 id, Inventory *inventory, Queue *actions, - int *active_menu_count); + IMenuManager *menumgr); ~GUIInventoryMenu(); void removeChildren(); diff --git a/src/guiMainMenu.cpp b/src/guiMainMenu.cpp new file mode 100644 index 000000000..84435b5f3 --- /dev/null +++ b/src/guiMainMenu.cpp @@ -0,0 +1,275 @@ +/* +Minetest-c55 +Copyright (C) 2010 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 "guiMainMenu.h" +#include "debug.h" +#include "serialization.h" +#include + +GUIMainMenu::GUIMainMenu(gui::IGUIEnvironment* env, + gui::IGUIElement* parent, s32 id, + IMenuManager *menumgr, + MainMenuData *data, + IGameCallback *gamecallback +): + GUIModalMenu(env, parent, id, menumgr), + m_data(data), + m_accepted(false), + m_gamecallback(gamecallback) +{ + assert(m_data); +} + +GUIMainMenu::~GUIMainMenu() +{ + removeChildren(); +} + +void GUIMainMenu::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 GUIMainMenu::regenerateGui(v2u32 screensize) +{ + std::wstring text_name; + std::wstring text_address; + std::wstring text_port; + bool creative_mode; + + { + gui::IGUIElement *e = getElementFromId(258); + if(e != NULL) + text_name = e->getText(); + else + text_name = m_data->name; + } + { + gui::IGUIElement *e = getElementFromId(256); + if(e != NULL) + text_address = e->getText(); + else + text_address = m_data->address; + } + { + gui::IGUIElement *e = getElementFromId(257); + if(e != NULL) + text_port = e->getText(); + else + text_port = m_data->port; + } + { + gui::IGUIElement *e = getElementFromId(259); + if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX) + creative_mode = ((gui::IGUICheckBox*)e)->isChecked(); + else + creative_mode = m_data->creative_mode; + } + + /* + 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(); + + /* + Add stuff + */ + + // Nickname + { + core::rect rect(0, 0, 100, 20); + rect = rect + v2s32(size.X/2 - 250, size.Y/2 - 100 + 6); + const wchar_t *text = L"Nickname"; + Environment->addStaticText(text, rect, false, true, this, -1); + } + { + core::rect rect(0, 0, 250, 30); + rect = rect + v2s32(size.X/2 - 130, size.Y/2 - 100); + gui::IGUIElement *e = + Environment->addEditBox(text_name.c_str(), rect, true, this, 258); + if(text_name == L"") + Environment->setFocus(e); + } + // Address + port + { + core::rect rect(0, 0, 100, 20); + rect = rect + v2s32(size.X/2 - 250, size.Y/2 - 50 + 6); + const wchar_t *text = L"Address + Port"; + Environment->addStaticText(text, rect, false, true, this, -1); + } + { + core::rect rect(0, 0, 250, 30); + rect = rect + v2s32(size.X/2 - 130, size.Y/2 - 50); + gui::IGUIElement *e = + Environment->addEditBox(text_address.c_str(), rect, true, this, 256); + if(text_name != L"") + Environment->setFocus(e); + } + { + core::rect rect(0, 0, 100, 30); + rect = rect + v2s32(size.X/2 - 130 + 250 + 20, size.Y/2 - 50); + Environment->addEditBox(text_port.c_str(), rect, true, this, 257); + } + { + core::rect rect(0, 0, 400, 20); + rect = rect + v2s32(size.X/2 - 130, size.Y/2 - 50 + 35); + const wchar_t *text = L"Leave address blank to start a local server."; + Environment->addStaticText(text, rect, false, true, this, -1); + } + // Server parameters + { + core::rect rect(0, 0, 100, 20); + rect = rect + v2s32(size.X/2 - 250, size.Y/2 + 25 + 6); + const wchar_t *text = L"Server params"; + Environment->addStaticText(text, rect, false, true, this, -1); + } + { + core::rect rect(0, 0, 250, 30); + rect = rect + v2s32(size.X/2 - 130, size.Y/2 + 25); + Environment->addCheckBox(creative_mode, rect, this, 259, L"Creative Mode"); + } + // Start game button + { + core::rect rect(0, 0, 180, 30); + rect = rect + v2s32(size.X/2-180/2, size.Y/2-30/2 + 100); + Environment->addButton(rect, this, 257, L"Start Game / Connect"); + } +} + +void GUIMainMenu::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 GUIMainMenu::acceptInput() +{ + { + gui::IGUIElement *e = getElementFromId(258); + if(e != NULL) + m_data->name = e->getText(); + } + { + gui::IGUIElement *e = getElementFromId(256); + if(e != NULL) + m_data->address = e->getText(); + } + { + gui::IGUIElement *e = getElementFromId(257); + if(e != NULL) + m_data->port = e->getText(); + } + { + gui::IGUIElement *e = getElementFromId(259); + if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX) + m_data->creative_mode = ((gui::IGUICheckBox*)e)->isChecked(); + } + + m_accepted = true; +} + +bool GUIMainMenu::OnEvent(const SEvent& event) +{ + if(event.EventType==EET_KEY_INPUT_EVENT) + { + if(event.KeyInput.Key==KEY_ESCAPE && event.KeyInput.PressedDown) + { + m_gamecallback->exitToOS(); + 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<<"GUIMainMenu: Not allowing focus change." + <getID()) + { + case 257: + acceptInput(); + quitMenu(); + break; + } + } + if(event.GUIEvent.EventType==gui::EGET_EDITBOX_ENTER) + { + switch(event.GUIEvent.Caller->getID()) + { + case 256: case 257: case 258: + acceptInput(); + quitMenu(); + break; + } + } + } + + return Parent ? Parent->OnEvent(event) : false; +} + diff --git a/src/guiMainMenu.h b/src/guiMainMenu.h new file mode 100644 index 000000000..8060f511d --- /dev/null +++ b/src/guiMainMenu.h @@ -0,0 +1,73 @@ +/* +Minetest-c55 +Copyright (C) 2010 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 GUIMAINMENU_HEADER +#define GUIMAINMENU_HEADER + +#include "common_irrlicht.h" +#include "modalMenu.h" +#include "utility.h" +#include +// For IGameCallback +#include "guiPauseMenu.h" + +struct MainMenuData +{ + // These are in the native format of the gui elements + std::wstring address; + std::wstring port; + std::wstring name; + bool creative_mode; +}; + +class GUIMainMenu : public GUIModalMenu +{ +public: + GUIMainMenu(gui::IGUIEnvironment* env, + gui::IGUIElement* parent, s32 id, + IMenuManager *menumgr, + MainMenuData *data, + IGameCallback *gamecallback); + ~GUIMainMenu(); + + void removeChildren(); + /* + Remove and re-add (or reposition) stuff + */ + void regenerateGui(v2u32 screensize); + + void drawMenu(); + + void acceptInput(); + + bool getStatus() + { + return m_accepted; + } + + bool OnEvent(const SEvent& event); + +private: + MainMenuData *m_data; + bool m_accepted; + IGameCallback *m_gamecallback; +}; + +#endif + diff --git a/src/guiMessageMenu.cpp b/src/guiMessageMenu.cpp index 9cba64a89..7102ddd83 100644 --- a/src/guiMessageMenu.cpp +++ b/src/guiMessageMenu.cpp @@ -24,10 +24,10 @@ with this program; if not, write to the Free Software Foundation, Inc., GUIMessageMenu::GUIMessageMenu(gui::IGUIEnvironment* env, gui::IGUIElement* parent, s32 id, - int *active_menu_count, + IMenuManager *menumgr, std::wstring message_text ): - GUIModalMenu(env, parent, id, active_menu_count), + GUIModalMenu(env, parent, id, menumgr), m_message_text(message_text), m_status(false) { diff --git a/src/guiMessageMenu.h b/src/guiMessageMenu.h index 03dbb54e9..82c40ce09 100644 --- a/src/guiMessageMenu.h +++ b/src/guiMessageMenu.h @@ -30,7 +30,7 @@ class GUIMessageMenu : public GUIModalMenu public: GUIMessageMenu(gui::IGUIEnvironment* env, gui::IGUIElement* parent, s32 id, - int *active_menu_count, + IMenuManager *menumgr, std::wstring message_text); ~GUIMessageMenu(); diff --git a/src/guiPauseMenu.cpp b/src/guiPauseMenu.cpp index 574cc774f..d905d3222 100644 --- a/src/guiPauseMenu.cpp +++ b/src/guiPauseMenu.cpp @@ -25,11 +25,11 @@ with this program; if not, write to the Free Software Foundation, Inc., GUIPauseMenu::GUIPauseMenu(gui::IGUIEnvironment* env, gui::IGUIElement* parent, s32 id, - IrrlichtDevice *dev, - int *active_menu_count): - GUIModalMenu(env, parent, id, active_menu_count) + IGameCallback *gamecallback, + IMenuManager *menumgr): + GUIModalMenu(env, parent, id, menumgr) { - m_dev = dev; + m_gamecallback = gamecallback; } GUIPauseMenu::~GUIPauseMenu() @@ -59,6 +59,11 @@ void GUIPauseMenu::removeChildren() if(e != NULL) e->remove(); } + { + gui::IGUIElement *e = getElementFromId(260); + if(e != NULL) + e->remove(); + } } void GUIPauseMenu::regenerateGui(v2u32 screensize) @@ -88,13 +93,18 @@ void GUIPauseMenu::regenerateGui(v2u32 screensize) */ { core::rect rect(0, 0, 140, 30); - rect = rect + v2s32(size.X/2-140/2, size.Y/2-30/2-25); + rect = rect + v2s32(size.X/2-140/2, size.Y/2-30/2-50); Environment->addButton(rect, this, 256, L"Continue"); } { core::rect rect(0, 0, 140, 30); - rect = rect + v2s32(size.X/2-140/2, size.Y/2-30/2+25); - Environment->addButton(rect, this, 257, L"Exit"); + rect = rect + v2s32(size.X/2-140/2, size.Y/2-30/2+0); + Environment->addButton(rect, this, 260, L"Disconnect"); + } + { + core::rect rect(0, 0, 140, 30); + rect = rect + v2s32(size.X/2-140/2, size.Y/2-30/2+50); + Environment->addButton(rect, this, 257, L"Exit to OS"); } { core::rect rect(0, 0, 180, 240); @@ -183,8 +193,13 @@ bool GUIPauseMenu::OnEvent(const SEvent& event) case 256: // continue quitMenu(); break; + case 260: // disconnect + m_gamecallback->disconnect(); + quitMenu(); + break; case 257: // exit - m_dev->closeDevice(); + m_gamecallback->exitToOS(); + quitMenu(); break; } } diff --git a/src/guiPauseMenu.h b/src/guiPauseMenu.h index 187d20edb..22cb65b2c 100644 --- a/src/guiPauseMenu.h +++ b/src/guiPauseMenu.h @@ -23,13 +23,20 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "common_irrlicht.h" #include "modalMenu.h" +class IGameCallback +{ +public: + virtual void exitToOS() = 0; + virtual void disconnect() = 0; +}; + class GUIPauseMenu : public GUIModalMenu { public: GUIPauseMenu(gui::IGUIEnvironment* env, gui::IGUIElement* parent, s32 id, - IrrlichtDevice *dev, - int *active_menu_count); + IGameCallback *gamecallback, + IMenuManager *menumgr); ~GUIPauseMenu(); void removeChildren(); @@ -43,7 +50,7 @@ public: bool OnEvent(const SEvent& event); private: - IrrlichtDevice *m_dev; + IGameCallback *m_gamecallback; }; #endif diff --git a/src/guiTextInputMenu.cpp b/src/guiTextInputMenu.cpp index 787680bc5..38985cfa0 100644 --- a/src/guiTextInputMenu.cpp +++ b/src/guiTextInputMenu.cpp @@ -24,11 +24,11 @@ with this program; if not, write to the Free Software Foundation, Inc., GUITextInputMenu::GUITextInputMenu(gui::IGUIEnvironment* env, gui::IGUIElement* parent, s32 id, - int *active_menu_count, + IMenuManager *menumgr, TextDest *dest, std::wstring initial_text ): - GUIModalMenu(env, parent, id, active_menu_count), + GUIModalMenu(env, parent, id, menumgr), m_dest(dest), m_initial_text(initial_text) { diff --git a/src/guiTextInputMenu.h b/src/guiTextInputMenu.h index 5db10a529..c679aa9ca 100644 --- a/src/guiTextInputMenu.h +++ b/src/guiTextInputMenu.h @@ -35,7 +35,7 @@ class GUITextInputMenu : public GUIModalMenu public: GUITextInputMenu(gui::IGUIEnvironment* env, gui::IGUIElement* parent, s32 id, - int *active_menu_count, + IMenuManager *menumgr, TextDest *dest, std::wstring initial_text); ~GUITextInputMenu(); diff --git a/src/main.cpp b/src/main.cpp index 3006e3fd5..447224645 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -104,6 +104,16 @@ SUGG: Meshes of blocks could be split into 6 meshes facing into different directions and then only those drawn that need to be - Also an 1-dimensional tile map would be nice probably +Gaming ideas: +------------- + +- How would some GTA-style ideas work? + - Cars? Stealing? Unlawful stuff and cops? Lots of guns? + +- RPG style? + +- Space racer style? + Documentation: -------------- @@ -289,7 +299,7 @@ Doing now: #ifdef _MSC_VER #pragma comment(lib, "Irrlicht.lib") -#pragma comment(lib, "jthread.lib") +//#pragma comment(lib, "jthread.lib") #pragma comment(lib, "zlibwapi.lib") // This would get rid of the console window //#pragma comment(linker, "/subsystem:windows /ENTRY:mainCRTStartup") @@ -322,6 +332,7 @@ Doing now: #include "guiMessageMenu.h" #include "filesys.h" #include "config.h" +#include "guiMainMenu.h" IrrlichtWrapper *g_irrlicht; @@ -346,15 +357,87 @@ Client *g_client = NULL; /* GUI Stuff */ + gui::IGUIEnvironment* guienv = NULL; gui::IGUIStaticText *guiroot = NULL; -int g_active_menu_count = 0; + +class MainMenuManager : public IMenuManager +{ +public: + virtual void createdMenu(GUIModalMenu *menu) + { + for(core::list::Iterator + i = m_stack.begin(); + i != m_stack.end(); i++) + { + assert(*i != menu); + } + + if(m_stack.size() != 0) + (*m_stack.getLast())->setVisible(false); + m_stack.push_back(menu); + } + + virtual void deletingMenu(GUIModalMenu *menu) + { + // Remove all entries if there are duplicates + bool removed_entry; + do{ + removed_entry = false; + for(core::list::Iterator + i = m_stack.begin(); + i != m_stack.end(); i++) + { + if(*i == menu) + { + m_stack.erase(i); + removed_entry = true; + break; + } + } + }while(removed_entry); + + /*core::list::Iterator i = m_stack.getLast(); + assert(*i == menu); + m_stack.erase(i);*/ + + if(m_stack.size() != 0) + (*m_stack.getLast())->setVisible(true); + } + + u32 menuCount() + { + return m_stack.size(); + } + + core::list m_stack; +}; + +MainMenuManager g_menumgr; bool noMenuActive() { - return (g_active_menu_count == 0); + return (g_menumgr.menuCount() == 0); } +bool g_disconnect_requested = false; + +class MainGameCallback : public IGameCallback +{ +public: + virtual void exitToOS() + { + g_device->closeDevice(); + } + + virtual void disconnect() + { + g_disconnect_requested = true; + } +}; + +MainGameCallback g_gamecallback; + // Inventory actions from the menu are buffered here before sending Queue inventory_action_queue; // This is a copy of the inventory that the client's environment has @@ -472,8 +555,8 @@ public: dstream<drop(); + (new GUIPauseMenu(guienv, guiroot, -1, &g_gamecallback, + &g_menumgr))->drop(); return true; } if(event.KeyInput.Key == irr::KEY_KEY_I) @@ -482,7 +565,7 @@ public: <<"Launching inventory"<drop(); + &g_menumgr))->drop(); return true; } if(event.KeyInput.Key == irr::KEY_KEY_T) @@ -490,7 +573,7 @@ public: TextDest *dest = new TextDestChat(g_client); (new GUITextInputMenu(guienv, guiroot, -1, - &g_active_menu_count, dest, + &g_menumgr, dest, L""))->drop(); } } @@ -1067,6 +1150,18 @@ public: } } + ~GUIQuickInventory() + { + for(u32 i=0; iremove(); + } + for(u32 i=0; iremove(); + } + } + virtual bool OnEvent(const SEvent& event) { return false; @@ -1179,9 +1274,6 @@ int main(int argc, char *argv[]) <<", "<__| \\___ >____ > |__| "< "< list = server.getPlayerInfo(); - core::list::Iterator i; - static u32 sum_old = 0; - u32 sum = PIChecksum(list); - if(sum != sum_old) - { - std::cout<PrintLine(&std::cout); - } - } - sum_old = sum; - } - } + + // Run server + dedicated_server_loop(server); return 0; } - bool hosting = false; - char connect_name[100] = ""; - + /* + More parameters + */ + + // Address to connect to + std::string address = ""; + if(cmd_args.exists("address")) { - snprintf(connect_name, 100, "%s", cmd_args.get("address").c_str()); - } - else if(is_yes(g_settings.get("host_game")) == false) - { - if(g_settings.get("address") != "") - { - std::cout< Hosting game"< Connecting to "< \""<setColor(gui::EGDC_3D_HIGH_LIGHT, video::SColor(255,0,0,0)); skin->setColor(gui::EGDC_3D_SHADOW, video::SColor(255,0,0,0)); + /* + Preload some textures + */ + + init_content_inventory_texture_paths(); + init_tile_texture_paths(); + tile_materials_preload(g_irrlicht); + + /* + GUI stuff + */ + + /* + We need some kind of a root node to be able to add + custom gui elements directly on the screen. + Otherwise they won't be automatically drawn. + */ + guiroot = guienv->addStaticText(L"", + core::rect(0, 0, 10000, 10000)); + + // First line of debug text + gui::IGUIStaticText *guitext = guienv->addStaticText( + L"", + core::rect(5, 5, 795, 5+text_height), + false, false); + // Second line of debug text + gui::IGUIStaticText *guitext2 = guienv->addStaticText( + L"", + core::rect(5, 5+(text_height+5)*1, 795, (5+text_height)*2), + false, false); + + // At the middle of the screen + // Object infos are shown in this + gui::IGUIStaticText *guitext_info = guienv->addStaticText( + L"", + core::rect(100, 70, 100+400, 70+(text_height+5)), + false, false); + + // Chat text + gui::IGUIStaticText *guitext_chat = guienv->addStaticText( + L"", + core::rect(0,0,0,0), + false, true); + guitext_chat->setBackgroundColor(video::SColor(96,0,0,0)); + core::list chat_lines; + + /* + If an error occurs, this is set to something and the + menu-game loop is restarted. It is then displayed before + the menu. + */ + std::wstring error_message = L""; + + /* + Menu-game loop + */ + while(g_device->run()) + { + + // This is used for catching disconnects + try + { + + /* + Out-of-game menu loop + */ + + // Wait for proper parameters + for(;;) + { + // Cursor can be non-visible when coming from the game + device->getCursorControl()->setVisible(true); + // Some stuff are left to scene manager when coming from the game + // (map at least?) + smgr->clear(); + // Reset or hide the debug gui texts + guitext->setText(L"Minetest-c55"); + guitext2->setVisible(false); + guitext_info->setVisible(false); + guitext_chat->setVisible(false); + + // Initialize menu data + MainMenuData menudata; + menudata.address = narrow_to_wide(address); + menudata.name = narrow_to_wide(playername); + menudata.port = narrow_to_wide(itos(port)); + menudata.creative_mode = g_settings.getBool("creative_mode"); + + GUIMainMenu *menu = + new GUIMainMenu(guienv, guiroot, -1, + &g_menumgr, &menudata, &g_gamecallback); + menu->allowFocusRemoval(true); + + if(error_message != L"") + { + GUIMessageMenu *menu2 = + new GUIMessageMenu(guienv, guiroot, -1, + &g_menumgr, error_message.c_str()); + menu2->drop(); + error_message = L""; + } + + video::IVideoDriver* driver = g_device->getVideoDriver(); + + dstream<<"Created main menu"<run()) + { + // Run global IrrlichtWrapper's main thread processing stuff + g_irrlicht->Run(); + + if(menu->getStatus() == true) + break; + + //driver->beginScene(true, true, video::SColor(255,0,0,0)); + driver->beginScene(true, true, video::SColor(255,128,128,128)); + guienv->drawAll(); + driver->endScene(); + } + + // Break out of menu-game loop to shut down cleanly + if(g_device->run() == false) + break; + + dstream<<"Dropping main menu"<drop(); + + playername = wide_to_narrow(menudata.name); + address = wide_to_narrow(menudata.address); + port = stoi(wide_to_narrow(menudata.port)); + g_settings.set("creative_mode", itos(menudata.creative_mode)); + + // Check for valid parameters, restart menu if invalid. + if(playername == "") + { + error_message = L"Name required."; + continue; + } + + // Save settings + g_settings.set("name", playername); + g_settings.set("address", address); + g_settings.set("port", itos(port)); + // Update configuration file + if(configpath != "") + g_settings.updateConfigFile(configpath.c_str()); + + // Continue to game + break; + } + + // Break out of menu-game loop to shut down cleanly + if(g_device->run() == false) + break; + + /* + Make a scope here so that the client and the server and other + stuff gets removed when disconnected or the irrlicht device + is removed. + */ + { + + /* + Draw "Loading" screen + */ const wchar_t *text = L"Loading and connecting..."; core::vector2d center(screenW/2, screenH/2); core::vector2d textsize(300, text_height); @@ -1533,27 +1717,14 @@ int main(int argc, char *argv[]) guienv->drawAll(); driver->endScene(); - /* - Preload some textures - */ - - init_content_inventory_texture_paths(); - init_tile_texture_paths(); - tile_materials_preload(g_irrlicht); - - /* - Make a scope here for the client so that it gets removed - before the irrlicht device - */ - { - std::cout< server; - if(hosting){ + if(address == ""){ server = new Server(map_dir, hm_params, map_params); server->start(port); } @@ -1562,18 +1733,24 @@ int main(int argc, char *argv[]) Create client */ - Client client(device, playername, draw_control); + Client client(device, playername.c_str(), draw_control); g_client = &client; Address connect_address(0,0,0,0, port); try{ - connect_address.Resolve(connect_name); + if(address == "") + connect_address.Resolve("localhost"); + else + connect_address.Resolve(address.c_str()); } catch(ResolveError &e) { std::cout<remove(); + continue; } std::cout<beginScene(true, true, video::SColor(255,0,0,0)); + guienv->drawAll(); + driver->endScene(); + + // Update client and server + client.step(0.1); - if(server != NULL){ + + if(server != NULL) server->step(0.1); - } + + // Delay a bit sleep_ms(100); } } catch(con::PeerNotFoundException &e) { std::cout<remove(); + continue; } /* @@ -1644,52 +1833,23 @@ int main(int argc, char *argv[]) GUIQuickInventory *quick_inventory = new GUIQuickInventory (guienv, NULL, v2s32(10, 70), 5, &local_inventory); - /* - We need some kind of a root node to be able to add - custom elements directly on the screen. - Otherwise they won't be automatically drawn. - */ - guiroot = guienv->addStaticText(L"", - core::rect(0, 0, 10000, 10000)); - // Test the text input system - /*(new GUITextInputMenu(guienv, guiroot, -1, &g_active_menu_count, + /*(new GUITextInputMenu(guienv, guiroot, -1, &g_menumgr, NULL))->drop();*/ /*GUIMessageMenu *menu = new GUIMessageMenu(guienv, guiroot, -1, - &g_active_menu_count, + &g_menumgr, L"Asd"); menu->drop();*/ // Launch pause menu - (new GUIPauseMenu(guienv, guiroot, -1, g_device, - &g_active_menu_count))->drop(); - - // First line of debug text - gui::IGUIStaticText *guitext = guienv->addStaticText( - L"Minetest-c55", - core::rect(5, 5, 795, 5+textsize.Y), - false, false); - // Second line of debug text - gui::IGUIStaticText *guitext2 = guienv->addStaticText( - L"", - core::rect(5, 5+(textsize.Y+5)*1, 795, (5+textsize.Y)*2), - false, false); + (new GUIPauseMenu(guienv, guiroot, -1, &g_gamecallback, + &g_menumgr))->drop(); - // At the middle of the screen - // Object infos are shown in this - gui::IGUIStaticText *guitext_info = guienv->addStaticText( - L"test", - core::rect(100, 70, 100+400, 70+(textsize.Y+5)), - false, false); - - // Chat text - gui::IGUIStaticText *chat_guitext = guienv->addStaticText( - L"Chat here\nOther line\nOther line\nOther line\nOther line", - core::rect(70, 60, 795, 150), - false, true); - chat_guitext->setBackgroundColor(video::SColor(96,0,0,0)); - core::list chat_lines; + // Enable texts + guitext2->setVisible(true); + guitext_info->setVisible(true); + guitext_chat->setVisible(true); /* Some statistics are collected in these @@ -1715,6 +1875,12 @@ int main(int argc, char *argv[]) while(device->run()) { + if(g_disconnect_requested) + { + g_disconnect_requested = false; + break; + } + /* Run global IrrlichtWrapper's main thread processing stuff */ @@ -2042,7 +2208,7 @@ int main(int argc, char *argv[]) narrow_to_wide(sign_object->getText()); (new GUITextInputMenu(guienv, guiroot, -1, - &g_active_menu_count, dest, + &g_menumgr, dest, wtext))->drop(); } } @@ -2519,7 +2685,7 @@ int main(int argc, char *argv[]) it = chat_lines.begin(); chat_lines.erase(it); } - chat_guitext->setText(whole.c_str()); + guitext_chat->setText(whole.c_str()); // Update gui element size and position core::rect rect( 10, @@ -2527,12 +2693,12 @@ int main(int argc, char *argv[]) screensize.X - 10, screensize.Y - 10 ); - chat_guitext->setRelativePosition(rect); + guitext_chat->setRelativePosition(rect); if(chat_lines.size() == 0) - chat_guitext->setVisible(false); + guitext_chat->setVisible(false); else - chat_guitext->setVisible(true); + guitext_chat->setVisible(true); } /* @@ -2667,22 +2833,7 @@ int main(int argc, char *argv[]) delete quick_inventory; - } // client is deleted at this point - - delete g_input; - - /* - In the end, delete the Irrlicht device. - */ - device->drop(); - - /* - Update configuration file - */ - /*if(configpath != "") - { - g_settings.updateConfigFile(configpath.c_str()); - }*/ + } // client and server are deleted at this point } //try catch(con::PeerNotFoundException &e) @@ -2693,7 +2844,7 @@ int main(int argc, char *argv[]) { GUIMessageMenu *menu = new GUIMessageMenu(guienv, guiroot, -1, - &g_active_menu_count, + &g_menumgr, L"Connection timed out"); video::IVideoDriver* driver = g_device->getVideoDriver(); @@ -2713,6 +2864,23 @@ int main(int argc, char *argv[]) }*/ } + } // Menu-game loop + + delete g_input; + + /* + In the end, delete the Irrlicht device. + */ + device->drop(); + + /* + Update configuration file + */ + /*if(configpath != "") + { + g_settings.updateConfigFile(configpath.c_str()); + }*/ + END_DEBUG_EXCEPTION_HANDLER debugstreams_deinit(); diff --git a/src/map.cpp b/src/map.cpp index 1889cccf6..973e12678 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -1372,8 +1372,12 @@ void Map::transformLiquids(core::map & modified_blocks) u32 loopcount = 0; u32 initial_size = m_transforming_liquid.size(); + while(m_transforming_liquid.size() != 0) { + /* + Get a queued transforming liquid node + */ v3s16 p0 = m_transforming_liquid.pop_front(); MapNode n0 = getNode(p0); @@ -1557,6 +1561,7 @@ void Map::transformLiquids(core::map & modified_blocks) v3s16 p2 = p0 + dirs_to[i]; MapNode n2 = getNode(p2); + //dstream<<"[1] n2.param="<<(int)n2.param< & modified_blocks) n2_changed = true; flowed = true; } + + //dstream<<"[2] n2.param="<<(int)n2.param<(0,0,100,100)) { - m_active_menu_count = active_menu_count; + m_menumgr = menumgr; m_allow_focus_removal = false; m_screensize_old = v2u32(0,0); setVisible(true); Environment->setFocus(this); - (*m_active_menu_count)++; + m_menumgr->createdMenu(this); } virtual ~GUIModalMenu() { - (*m_active_menu_count)--; + m_menumgr->deletingMenu(this); + } + + void allowFocusRemoval(bool allow) + { + m_allow_focus_removal = allow; } bool canTakeFocus(gui::IGUIElement *e) @@ -75,18 +90,35 @@ public: */ void quitMenu() { - m_allow_focus_removal = true; + allowFocusRemoval(true); // This removes Environment's grab on us Environment->removeFocus(this); this->remove(); } + void 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(); + } + } + virtual void regenerateGui(v2u32 screensize) = 0; virtual void drawMenu() = 0; virtual bool OnEvent(const SEvent& event) { return false; }; private: - int *m_active_menu_count; + IMenuManager *m_menumgr; // This might be necessary to expose to the implementation if it // wants to launch other menus bool m_allow_focus_removal; diff --git a/src/server.cpp b/src/server.cpp index e06e69d87..a979086ea 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -53,6 +53,10 @@ void * ServerThread::Thread() catch(con::NoIncomingDataException &e) { } + catch(con::PeerNotFoundException &e) + { + dout_server<<"Server: PeerNotFoundException"< list = server.getPlayerInfo(); + core::list::Iterator i; + static u32 sum_old = 0; + u32 sum = PIChecksum(list); + if(sum != sum_old) + { + std::cout<PrintLine(&std::cout); + } + } + sum_old = sum; + } + } +} + diff --git a/src/server.h b/src/server.h index 9c655b9ab..a3e1897d9 100644 --- a/src/server.h +++ b/src/server.h @@ -397,7 +397,6 @@ public: // Environment and Connection must be locked when called void SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver); - //TODO: Sending of many blocks in a single packet // Environment and Connection must be locked when called //void SendSectorMeta(u16 peer_id, core::list ps, u8 ver); @@ -420,7 +419,6 @@ private: // Virtual methods from con::PeerHandler. // As of now, these create and remove clients and players. - // TODO: Make it possible to leave players on server. void peerAdded(con::Peer *peer); void deletingPeer(con::Peer *peer, bool timeout); @@ -514,5 +512,10 @@ private: friend class RemoteClient; }; +/* + Runs a simple dedicated server loop +*/ +void dedicated_server_loop(Server &server); + #endif diff --git a/src/servermain.cpp b/src/servermain.cpp index 3d015b732..d5be5b8ac 100644 --- a/src/servermain.cpp +++ b/src/servermain.cpp @@ -301,14 +301,6 @@ int main(int argc, char *argv[]) < list = server.getPlayerInfo(); - core::list::Iterator i; - static u32 sum_old = 0; - u32 sum = PIChecksum(list); - if(sum != sum_old) - { - std::cout<PrintLine(&std::cout); - } - } - sum_old = sum; - } - } - + + // Run server + dedicated_server_loop(server); + } //try catch(con::PeerNotFoundException &e) { diff --git a/src/utility.h b/src/utility.h index 897390dba..8ab2345e1 100644 --- a/src/utility.h +++ b/src/utility.h @@ -646,7 +646,7 @@ inline std::string lowercase(const std::string &s) inline bool is_yes(const std::string &s) { std::string s2 = lowercase(trim(s)); - if(s2 == "y" || s2 == "yes" || s2 == "true") + if(s2 == "y" || s2 == "yes" || s2 == "true" || s2 == "1") return true; return false; }