\r
NOTE: VBO cannot be turned on for fast-changing stuff because there\r
is an apparanet memory leak in irrlicht when using it (not sure)\r
+ - It is not a memory leak but some kind of a buffer.\r
\r
NOTE: iostream.imbue(std::locale("C")) is very slow\r
NOTE: Global locale is now set at initialization\r
\r
SUGG: Fix address to be ipv6 compatible\r
\r
-FIXME: When a new sector is generated, it may change the ground level\r
- of it's and it's neighbors border that two blocks that are\r
- above and below each other and that are generated before and\r
- after the sector heightmap generation (order doesn't matter),\r
- can have a small gap between each other at the border.\r
-SUGGESTION: Use same technique for sector heightmaps as what we're\r
- using for UnlimitedHeightmap? (getting all neighbors\r
- when generating)\r
+NOTE: When a new sector is generated, it may change the ground level\r
+ of it's and it's neighbors border that two blocks that are\r
+ above and below each other and that are generated before and\r
+ after the sector heightmap generation (order doesn't matter),\r
+ can have a small gap between each other at the border.\r
+SUGG: Use same technique for sector heightmaps as what we're\r
+ using for UnlimitedHeightmap? (getting all neighbors\r
+ when generating)\r
\r
SUGG: Transfer more blocks in a single packet\r
SUGG: A blockdata combiner class, to which blocks are added and at\r
- This will allow saving ages of rats on disk but not sending\r
them to clients\r
\r
-SUGG: Implement lighting using VoxelManipulator\r
- - Would it be significantly faster?\r
-\r
-FIXME: Rats somehow go underground sometimes (you can see it in water)\r
- - Does their position get saved to a border value or something?\r
- - Does this happen anymore?\r
-\r
SUGG: MovingObject::move and Player::move are basically the same.\r
combine them.\r
\r
- Use it in active block queue in water flowing\r
\r
SUGG: Precalculate lighting translation table at runtime (at startup)\r
+ - This is not doable because it is currently hand-made and not\r
+ based on some mathematical function.\r
\r
SUGG: A version number to blocks, which increments when the block is\r
modified (node add/remove, water update, lighting update)\r
different directions and then only those drawn that need to be\r
- Also an 1-dimensional tile map would be nice probably\r
\r
-TODO: Untie client network operations from framerate\r
- - Needs some input queues or something\r
- - Not really necessary?\r
+Gaming ideas:\r
+-------------\r
\r
-TODO: Combine MapBlock's face caches to so big pieces that VBO\r
- gets used\r
- - That is >500 vertices\r
+- Aim for something like controlling a single dwarf in Dwarf Fortress\r
\r
-TODO: Startup and configuration menu\r
+- The player could go faster by a crafting a boat, or riding an animal\r
\r
-TODO: There are some lighting-related todos and fixmes in\r
- ServerMap::emergeBlock\r
+- Random NPC traders. what else?\r
\r
-TODO: Proper handling of spawning place (try to find something that\r
- is not in the middle of an ocean (some land to stand on at\r
- least) and save it in map config.\r
+Documentation:\r
+--------------\r
\r
-TODO: Players to only be hidden when the client quits.\r
-TODO: - Players to be saved on disk, with inventory\r
-TODO: Players to be saved as text in map/players/<name>\r
-TODO: Player inventory to be saved on disk\r
+Build system / running:\r
+-----------------------\r
+\r
+NOTE: The following fixme is not apparently valid, and it does work.\r
+FIXME: Graphical mode seems to segfault with Irrlicht 1.7.1 on 64-bit\r
+ systems. (Ubuntu)\r
+ - http://pastebin.no/32bo\r
+ - Might be just a bad build, too\r
+ - Doesn't affect Irrlicht 1.7.2 or 32-bit 1.7.1. (Arch/Debian)\r
+ - A similar error occurs when getTexture is called from a thread\r
+ when the texture has not been already loaded from disk:\r
+ http://irrlicht.sourceforge.net/phpBB2/viewtopic.php?p=68830\r
+\r
+FIXME: Some network errors on Windows that cause local game to not work\r
+ - See siggjen's emails.\r
+\r
+Networking and serialization:\r
+-----------------------------\r
+\r
+TODO: Get rid of GotSplitPacketException\r
+\r
+GUI:\r
+----\r
+\r
+TODO: Add gui option to remove map\r
+\r
+TODO: Configuration menu, at least for keys\r
+\r
+Graphics:\r
+---------\r
+\r
+TODO: Optimize day/night mesh updating somehow\r
+ - create copies of all textures for all lighting values and only\r
+ change texture for material?\r
+ - Umm... the collecting of the faces is the slow part\r
+ -> what about just changing the color values of the existing\r
+ meshbuffers? It should go quite fast.\r
+ - This is not easy; There'd need to be a buffer somewhere\r
+ that would contain the night and day lighting values.\r
+ - Actually if FastFaces would be stored, they could\r
+ hold both values\r
+\r
+FEATURE: Combine MapBlock's face caches to so big pieces that VBO\r
+ gets used\r
+ - That is >500 vertices\r
+ - This is not easy; all the MapBlocks close to the player would\r
+ still need to be drawn separately and combining the blocks\r
+ would have to happen in a background thread\r
\r
TODO: Make fetching sector's blocks more efficient when rendering\r
sectors that have very large amounts of blocks (on client)\r
+ - Is this necessary at all?\r
+\r
+TODO: Flowing water animation\r
+\r
+FIXME(FIXED): The new texture stuff is slow on wine\r
+ - A basic grassy ground block takes 20-40ms\r
+ - A bit more complicated block can take 270ms\r
+ - On linux, a similar one doesn't take long at all (14ms)\r
+ - It is NOT a bad std::string implementation of MSVC.\r
+ - Can take up to 200ms? Is it when loading textures or always?\r
+ - Updating excess amount of meshes when making footprints is too\r
+ slow. It has to be fixed.\r
+ -> implement Map::updateNodeMeshes()\r
+ The fix:\r
+ * Optimize TileSpec to only contain a reference number that\r
+ is fast to compare, which refers to a cached string, or\r
+ * Make TextureSpec for using instead of strings\r
+\r
+FIXME(FIXED): A lock condition is possible:\r
+ 1) MapBlock::updateMesh() is called from client asynchronously:\r
+ - AsyncProcessData() -> Map::updateMeshes()\r
+ 2) Asynchronous locks m_temp_mods_mutex\r
+ 3) MapBlock::updateMesh() is called from client synchronously:\r
+ - Client::step() -> Environment::step()\r
+ 4) Synchronous starts waiting for m_temp_mods_mutex\r
+ 5) Asynchronous calls getTexture, which starts waiting for main thread\r
+\r
+Configuration:\r
+--------------\r
\r
TODO: Make the video backend selectable\r
\r
+Client:\r
+-------\r
+\r
+TODO: Untie client network operations from framerate\r
+ - Needs some input queues or something\r
+ - Not really necessary?\r
+\r
+TODO: Make morning and evening shorter\r
+\r
+TODO: Don't update all meshes always on single node changes, but\r
+ check which ones should be updated\r
+ - implement Map::updateNodeMeshes()\r
+\r
+Server:\r
+-------\r
+\r
+TODO: When player dies, throw items on map\r
+\r
+TODO: Make an option to the server to disable building and digging near\r
+ the starting position\r
+\r
+TODO: Save players with inventories to disk\r
+TODO: Players to be saved as text in map/players/<name>\r
+\r
TODO: Copy the text of the last picked sign to inventory in creative\r
mode\r
\r
-TODO: Get rid of GotSplitPacketException\r
-\r
TODO: Check what goes wrong with caching map to disk (Kray)\r
- Nothing?\r
\r
+TODO: When server sees that client is removing an inexistent block or\r
+ adding a block to an existent position, resend the MapBlock.\r
+\r
+Objects:\r
+--------\r
+\r
+TODO: Better handling of objects and mobs\r
+ - Scripting?\r
+ - There has to be some way to do it with less messy code\r
+ - Make separate classes for client and server\r
+ - Client should not discriminate between blocks, server should\r
+ - Make other players utilize the same framework\r
+ - This is also needed for objects that don't get sent to client\r
+ but are used for triggers etc\r
+\r
+TODO: There has to be some better way to handle static objects than to\r
+ send them all the time. This affects signs and item objects.\r
+SUGG: Signs could be done in the same way as torches. For this, blocks\r
+ need an additional metadata field for the texts\r
+ - This is also needed for item container chests\r
+\r
Block object server side:\r
- A "near blocks" buffer, in which some nearby blocks are stored.\r
- For all blocks in the buffer, objects are stepped(). This\r
- TODO: For incoming blocks, time difference is calculated and\r
objects are stepped according to it.\r
\r
-TODO: Better handling of objects and mobs\r
- - Scripting?\r
- - There has to be some way to do it with less spaghetti code\r
- - Make separate classes for client and server\r
- - Client should not discriminate between blocks, server should\r
- - Make other players utilize the same framework\r
- - This is also needed for objects that don't get sent to client\r
- but are used for triggers etc\r
+Map:\r
+----\r
\r
-TODO: Draw big amounts of torches better (that is, throw them in the\r
- same meshbuffer (can the meshcollector class be used?))\r
+NOTE: There are some lighting-related todos and fixmes in\r
+ ServerMap::emergeBlock. And there always will be. 8)\r
\r
-TODO: Make an option to the server to disable building and digging near\r
- the starting position\r
+TODO: Mineral and ground material properties\r
+ - This way mineral ground toughness can be calculated with just\r
+ some formula, as well as tool strengths\r
\r
-SUGG: Signs could be done in the same way as torches. For this, blocks\r
- need an additional metadata field for the texts\r
- - This is also needed for item container chests\r
-TODO: There has to be some better way to handle static objects than to\r
- send them all the time. This affects signs and item objects.\r
+TODO: Change AttributeList to split the area into smaller sections so\r
+ that searching won't be as heavy.\r
\r
-TODO: When server sees that client is removing an inexistent block or\r
- adding a block to an existent position, resend the MapBlock.\r
+TODO: Remove HMParams\r
\r
-TODO: When player dies, throw items on map\r
+TODO: Flowing water to actually contain flow direction information\r
\r
-TODO: Use porting::path_userdata for configuration file\r
+TODO: Remove duplicate lighting implementation from Map (leave\r
+ VoxelManipulator, which is faster)\r
\r
-TODO: Optimize day/night mesh updating somehow\r
- - create copies of all textures for all lighting values and only\r
- change texture for material?\r
- - Umm... the collecting of the faces is the slow part\r
- -> what about just changing the color values of the existing\r
- meshbuffers? It should go quite fast.\r
-\r
-TODO: Map generator version 2\r
+FEATURE: Map generator version 2\r
- Create surface areas based on central points; a given point's\r
area type is given by the nearest central point\r
- Separate points for heightmap, caves, plants and minerals?\r
- Flat land, mountains, forest, jungle\r
- Cliffs, arcs\r
-\r
-TODO: Add gui option to remove map\r
-\r
-Doing now:\r
-======================================================================\r
+ - There could be a certain height (to which mountains only reach)\r
+ where some minerals are found\r
+ - Create a system that allows a huge amount of different "map\r
+ generator modules/filters"\r
+\r
+FEATURE: The map could be generated procedually:\r
+ - This would need the map to be generated in larger pieces\r
+ - How large? How do they connect to each other?\r
+ - It has to be split vertically also\r
+ - Lighting would not have to be necessarily calculated until\r
+ the blocks are actually needed - it would be quite fast\r
+ - Something like 64*64*16 MapBlocks?\r
+ - No, MapSectors. And as much as it is efficient to do,\r
+ 64x64 might be too much.\r
+ - FIXME: This is currently halfway done and the generator is\r
+ fairly broken\r
+ * Make the stone level with a heightmap\r
+ * Carve out stuff in the stone\r
+ * Dump dirt all around, and simulate it falling off steep\r
+ places\r
+ * Erosion simulation at map generation time\r
+ - Simulate water flows, which would carve out dirt fast and\r
+ then turn stone into gravel and sand and relocate it.\r
+ - How about relocating minerals, too? Coal and gold in\r
+ downstream sand and gravel would be kind of cool\r
+ - This would need a better way of handling minerals, mainly\r
+ to have mineral content as a separate field. the first\r
+ parameter field is free for this.\r
+ - Simulate rock falling from cliffs when water has removed\r
+ enough solid rock from the bottom\r
+\r
+Doing now (most important at the top):\r
+--------------------------------------\r
+# maybe done\r
+* not done\r
+\r
+* Perlin noise stuff sucks in heightmap generation, fix it\r
+* Create perlin noise functions and use them to get natural randomness\r
+ in everything. No need for attributes or fractal terrain.\r
+* Do something about AttributeDatabase/List being too slow\r
+ - Remove it\r
+* Save chunk metadata on disk\r
+* Remove all kinds of systems that are made redundant by the new map\r
+ generator\r
+ - Sector heightmaps? At least they should be made redundant.\r
+ - Sector objects\r
+* Fix the strange mineral occurences\r
+ - Do they appear anymore?\r
+* Make server find the spawning place from the real map data, not from\r
+ the heightmap\r
+ - But the changing borders of chunk have to be avoided, because\r
+ there is time to generate only one chunk.\r
+* only_from_disk might not work anymore - check and fix it.\r
+* Make the generator to run in background and not blocking block\r
+ placement and transfer\r
+* Add some kind of erosion and other stuff that now is possible\r
+* Make client to fetch stuff asynchronously\r
+ - Needs method SyncProcessData\r
+* What is the problem with the server constantly saving one or a few\r
+ blocks? List the first saved block, maybe it explains.\r
+ - Does it still do this?\r
+* Water doesn't start flowing after map generation like it should\r
+ - Are there still problems?\r
+* Better water generation (spread it to underwater caverns)\r
+* When generating a chunk and the neighboring chunk doesn't have mud\r
+ and stuff yet and the ground is fairly flat, the mud will flow to\r
+ the other chunk making nasty straight walls when the other chunk\r
+ is generated. Fix it.\r
+* Save map seed to a metafile (with version information)\r
+ - Remove master heightmap\r
\r
======================================================================\r
\r
\r
#ifdef _MSC_VER\r
#pragma comment(lib, "Irrlicht.lib")\r
-#pragma comment(lib, "jthread.lib")\r
+//#pragma comment(lib, "jthread.lib")\r
#pragma comment(lib, "zlibwapi.lib")\r
+#pragma comment(lib, "Shell32.lib")\r
// This would get rid of the console window\r
//#pragma comment(linker, "/subsystem:windows /ENTRY:mainCRTStartup")\r
#endif\r
#include "guiMessageMenu.h"\r
#include "filesys.h"\r
#include "config.h"\r
+#include "guiMainMenu.h"\r
+#include "mineral.h"\r
\r
IrrlichtWrapper *g_irrlicht;\r
\r
/*\r
GUI Stuff\r
*/\r
+\r
gui::IGUIEnvironment* guienv = NULL;\r
gui::IGUIStaticText *guiroot = NULL;\r
-int g_active_menu_count = 0;\r
+\r
+class MainMenuManager : public IMenuManager\r
+{\r
+public:\r
+ virtual void createdMenu(GUIModalMenu *menu)\r
+ {\r
+ for(core::list<GUIModalMenu*>::Iterator\r
+ i = m_stack.begin();\r
+ i != m_stack.end(); i++)\r
+ {\r
+ assert(*i != menu);\r
+ }\r
+\r
+ if(m_stack.size() != 0)\r
+ (*m_stack.getLast())->setVisible(false);\r
+ m_stack.push_back(menu);\r
+ }\r
+\r
+ virtual void deletingMenu(GUIModalMenu *menu)\r
+ {\r
+ // Remove all entries if there are duplicates\r
+ bool removed_entry;\r
+ do{\r
+ removed_entry = false;\r
+ for(core::list<GUIModalMenu*>::Iterator\r
+ i = m_stack.begin();\r
+ i != m_stack.end(); i++)\r
+ {\r
+ if(*i == menu)\r
+ {\r
+ m_stack.erase(i);\r
+ removed_entry = true;\r
+ break;\r
+ }\r
+ }\r
+ }while(removed_entry);\r
+\r
+ /*core::list<GUIModalMenu*>::Iterator i = m_stack.getLast();\r
+ assert(*i == menu);\r
+ m_stack.erase(i);*/\r
+ \r
+ if(m_stack.size() != 0)\r
+ (*m_stack.getLast())->setVisible(true);\r
+ }\r
+\r
+ u32 menuCount()\r
+ {\r
+ return m_stack.size();\r
+ }\r
+\r
+ core::list<GUIModalMenu*> m_stack;\r
+};\r
+\r
+MainMenuManager g_menumgr;\r
\r
bool noMenuActive()\r
{\r
- return (g_active_menu_count == 0);\r
+ return (g_menumgr.menuCount() == 0);\r
}\r
\r
+bool g_disconnect_requested = false;\r
+\r
+class MainGameCallback : public IGameCallback\r
+{\r
+public:\r
+ virtual void exitToOS()\r
+ {\r
+ g_device->closeDevice();\r
+ }\r
+\r
+ virtual void disconnect()\r
+ {\r
+ g_disconnect_requested = true;\r
+ }\r
+};\r
+\r
+MainGameCallback g_gamecallback;\r
+\r
// Inventory actions from the menu are buffered here before sending\r
Queue<InventoryAction*> inventory_action_queue;\r
// This is a copy of the inventory that the client's environment has\r
dstream<<DTIME<<"MyEventReceiver: "\r
<<"Launching pause menu"<<std::endl;\r
// It will delete itself by itself\r
- (new GUIPauseMenu(guienv, guiroot, -1, g_device,\r
- &g_active_menu_count))->drop();\r
+ (new GUIPauseMenu(guienv, guiroot, -1, &g_gamecallback,\r
+ &g_menumgr))->drop();\r
return true;\r
}\r
if(event.KeyInput.Key == irr::KEY_KEY_I)\r
<<"Launching inventory"<<std::endl;\r
(new GUIInventoryMenu(guienv, guiroot, -1,\r
&local_inventory, &inventory_action_queue,\r
- &g_active_menu_count))->drop();\r
+ &g_menumgr))->drop();\r
return true;\r
}\r
if(event.KeyInput.Key == irr::KEY_KEY_T)\r
TextDest *dest = new TextDestChat(g_client);\r
\r
(new GUITextInputMenu(guienv, guiroot, -1,\r
- &g_active_menu_count, dest,\r
+ &g_menumgr, dest,\r
L""))->drop();\r
}\r
}\r
}\r
}\r
\r
+ ~GUIQuickInventory()\r
+ {\r
+ for(u32 i=0; i<m_texts.size(); i++)\r
+ {\r
+ m_texts[i]->remove();\r
+ }\r
+ for(u32 i=0; i<m_images.size(); i++)\r
+ {\r
+ m_images[i]->remove();\r
+ }\r
+ }\r
+\r
virtual bool OnEvent(const SEvent& event)\r
{\r
return false;\r
std::wstring text;\r
};\r
\r
-int main(int argc, char *argv[])\r
-{\r
- /*\r
- Low-level initialization\r
- */\r
+// These are defined global so that they're not optimized too much.\r
+// Can't change them to volatile.\r
+s16 temp16;\r
+f32 tempf;\r
+v3f tempv3f1;\r
+v3f tempv3f2;\r
+std::string tempstring;\r
+std::string tempstring2;\r
\r
- bool disable_stderr = false;\r
-#ifdef _WIN32\r
- disable_stderr = true;\r
-#endif\r
+void SpeedTests()\r
+{\r
+ {\r
+ dstream<<"The following test should take around 20ms."<<std::endl;\r
+ TimeTaker timer("Testing std::string speed");\r
+ const u32 jj = 10000;\r
+ for(u32 j=0; j<jj; j++)\r
+ {\r
+ tempstring = "";\r
+ tempstring2 = "";\r
+ const u32 ii = 10;\r
+ for(u32 i=0; i<ii; i++){\r
+ tempstring2 += "asd";\r
+ }\r
+ for(u32 i=0; i<ii+1; i++){\r
+ tempstring += "asd";\r
+ if(tempstring == tempstring2)\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ \r
+ dstream<<"All of the following tests should take around 100ms each."\r
+ <<std::endl;\r
\r
- // Initialize debug streams\r
- debugstreams_init(disable_stderr, DEBUGFILE);\r
- // Initialize debug stacks\r
- debug_stacks_init();\r
+ {\r
+ TimeTaker timer("Testing floating-point conversion speed");\r
+ tempf = 0.001;\r
+ for(u32 i=0; i<4000000; i++){\r
+ temp16 += tempf;\r
+ tempf += 0.001;\r
+ }\r
+ }\r
+ \r
+ {\r
+ TimeTaker timer("Testing floating-point vector speed");\r
\r
- DSTACK(__FUNCTION_NAME);\r
+ tempv3f1 = v3f(1,2,3);\r
+ tempv3f2 = v3f(4,5,6);\r
+ for(u32 i=0; i<10000000; i++){\r
+ tempf += tempv3f1.dotProduct(tempv3f2);\r
+ tempv3f2 += v3f(7,8,9);\r
+ }\r
+ }\r
\r
- porting::initializePaths();\r
- // Create user data directory\r
- fs::CreateDir(porting::path_userdata);\r
+ {\r
+ TimeTaker timer("Testing core::map speed");\r
+ \r
+ core::map<v2s16, f32> map1;\r
+ tempf = -324;\r
+ const s16 ii=300;\r
+ for(s16 y=0; y<ii; y++){\r
+ for(s16 x=0; x<ii; x++){\r
+ map1.insert(v2s16(x,y), tempf);\r
+ tempf += 1;\r
+ }\r
+ }\r
+ for(s16 y=ii-1; y>=0; y--){\r
+ for(s16 x=0; x<ii; x++){\r
+ tempf = map1[v2s16(x,y)];\r
+ }\r
+ }\r
+ }\r
\r
- initializeMaterialProperties();\r
+ {\r
+ dstream<<"Around 5000/ms should do well here."<<std::endl;\r
+ TimeTaker timer("Testing mutex speed");\r
+ \r
+ JMutex m;\r
+ m.Init();\r
+ u32 n = 0;\r
+ u32 i = 0;\r
+ do{\r
+ n += 10000;\r
+ for(; i<n; i++){\r
+ m.Lock();\r
+ m.Unlock();\r
+ }\r
+ }\r
+ // Do at least 10ms\r
+ while(timer.getTime() < 10);\r
\r
- BEGIN_DEBUG_EXCEPTION_HANDLER\r
+ u32 dtime = timer.stop();\r
+ u32 per_ms = n / dtime;\r
+ std::cout<<"Done. "<<dtime<<"ms, "\r
+ <<per_ms<<"/ms"<<std::endl;\r
+ }\r
+}\r
\r
- // Print startup message\r
- dstream<<DTIME<<"minetest-c55"\r
- " with SER_FMT_VER_HIGHEST="<<(int)SER_FMT_VER_HIGHEST\r
- <<", "<<BUILD_INFO\r
- <<std::endl;\r
- \r
- try\r
- {\r
- \r
+int main(int argc, char *argv[])\r
+{\r
/*\r
Parse command line\r
*/\r
allowed_options.insert("disable-unittests", ValueSpec(VALUETYPE_FLAG));\r
allowed_options.insert("enable-unittests", ValueSpec(VALUETYPE_FLAG));\r
allowed_options.insert("map-dir", ValueSpec(VALUETYPE_STRING));\r
+#ifdef _WIN32\r
+ allowed_options.insert("dstream-on-stderr", ValueSpec(VALUETYPE_FLAG));\r
+#endif\r
+ allowed_options.insert("speedtests", ValueSpec(VALUETYPE_FLAG));\r
\r
Settings cmd_args;\r
\r
\r
return cmd_args.getFlag("help") ? 0 : 1;\r
}\r
+ \r
+ /*\r
+ Low-level initialization\r
+ */\r
+\r
+ bool disable_stderr = false;\r
+#ifdef _WIN32\r
+ if(cmd_args.getFlag("dstream-on-stderr") == false)\r
+ disable_stderr = true;\r
+#endif\r
\r
+ // Initialize debug streams\r
+ debugstreams_init(disable_stderr, DEBUGFILE);\r
+ // Initialize debug stacks\r
+ debug_stacks_init();\r
+\r
+ DSTACK(__FUNCTION_NAME);\r
\r
+ porting::initializePaths();\r
+ // Create user data directory\r
+ fs::CreateDir(porting::path_userdata);\r
+ \r
+ // C-style stuff initialization\r
+ initializeMaterialProperties();\r
+\r
+ // Debug handler\r
+ BEGIN_DEBUG_EXCEPTION_HANDLER\r
+\r
+ // Print startup message\r
+ dstream<<DTIME<<"minetest-c55"\r
+ " with SER_FMT_VER_HIGHEST="<<(int)SER_FMT_VER_HIGHEST\r
+ <<", "<<BUILD_INFO\r
+ <<std::endl;\r
+ \r
/*\r
Basic initialization\r
*/\r
srand(time(0));\r
mysrand(time(0));\r
\r
+ /*\r
+ Pre-initialize some stuff with a dummy irrlicht wrapper.\r
+\r
+ These are needed for unit tests at least.\r
+ */\r
+ \r
+ IIrrlichtWrapper irrlicht_dummy;\r
+\r
+ init_mapnode(&irrlicht_dummy);\r
+\r
/*\r
Run unit tests\r
*/\r
// Read map parameters from settings\r
\r
HMParams hm_params;\r
- hm_params.blocksize = g_settings.getU16("heightmap_blocksize");\r
+ /*hm_params.blocksize = g_settings.getU16("heightmap_blocksize");\r
hm_params.randmax = g_settings.get("height_randmax");\r
hm_params.randfactor = g_settings.get("height_randfactor");\r
- hm_params.base = g_settings.get("height_base");\r
+ hm_params.base = g_settings.get("height_base");*/\r
\r
MapParams map_params;\r
map_params.plants_amount = g_settings.getFloat("plants_amount");\r
map_params.ravines_amount = g_settings.getFloat("ravines_amount");\r
\r
/*\r
- Ask some stuff\r
+ Some parameters\r
*/\r
\r
- std::cout<<std::endl<<std::endl;\r
- \r
- std::cout\r
- <<" .__ __ __ "<<std::endl\r
- <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl\r
- <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl\r
- <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl\r
- <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl\r
- <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl\r
- <<std::endl;\r
-\r
- std::cout<<std::endl;\r
- //char templine[100];\r
- \r
- // Port?\r
+ // Port\r
u16 port = 30000;\r
if(cmd_args.exists("port"))\r
- {\r
port = cmd_args.getU16("port");\r
- }\r
- else\r
- {\r
- port = g_settings.getU16Ask("port", "Port", 30000);\r
- std::cout<<"-> "<<port<<std::endl;\r
- }\r
+ else if(cmd_args.exists("port"))\r
+ port = g_settings.getU16("port");\r
\r
- //Map directory\r
+ // Map directory\r
std::string map_dir = porting::path_userdata+"/map";\r
if(cmd_args.exists("map-dir"))\r
map_dir = cmd_args.get("map-dir");\r
else if(g_settings.exists("map-dir"))\r
map_dir = g_settings.get("map-dir");\r
\r
+ // Run dedicated server if asked to\r
if(cmd_args.getFlag("server"))\r
{\r
DSTACK("Dedicated server branch");\r
- \r
- std::cout<<std::endl;\r
- std::cout<<"========================"<<std::endl;\r
- std::cout<<"Running dedicated server"<<std::endl;\r
- std::cout<<"========================"<<std::endl;\r
- std::cout<<std::endl;\r
\r
- Server server(map_dir, hm_params, map_params);\r
+ // Create server\r
+ Server server(map_dir.c_str(), hm_params, map_params);\r
server.start(port);\r
- \r
- for(;;)\r
- {\r
- // This is kind of a hack but can be done like this\r
- // because server.step() is very light\r
- sleep_ms(30);\r
- server.step(0.030);\r
-\r
- static int counter = 0;\r
- counter--;\r
- if(counter <= 0)\r
- {\r
- counter = 10;\r
-\r
- core::list<PlayerInfo> list = server.getPlayerInfo();\r
- core::list<PlayerInfo>::Iterator i;\r
- static u32 sum_old = 0;\r
- u32 sum = PIChecksum(list);\r
- if(sum != sum_old)\r
- {\r
- std::cout<<DTIME<<"Player info:"<<std::endl;\r
- for(i=list.begin(); i!=list.end(); i++)\r
- {\r
- i->PrintLine(&std::cout);\r
- }\r
- }\r
- sum_old = sum;\r
- }\r
- }\r
+ \r
+ // Run server\r
+ dedicated_server_loop(server);\r
\r
return 0;\r
}\r
\r
- bool hosting = false;\r
- char connect_name[100] = "";\r
-\r
- if(cmd_args.exists("address"))\r
- {\r
- snprintf(connect_name, 100, "%s", cmd_args.get("address").c_str());\r
- }\r
- else if(is_yes(g_settings.get("host_game")) == false)\r
- {\r
- if(g_settings.get("address") != "")\r
- {\r
- std::cout<<g_settings.get("address")<<std::endl;\r
- snprintf(connect_name, 100, "%s", g_settings.get("address").c_str());\r
- }\r
- else\r
- {\r
- std::cout<<"Address to connect to [empty = host a game]: ";\r
- std::cin.getline(connect_name, 100);\r
- }\r
- }\r
+ /*\r
+ More parameters\r
+ */\r
\r
- if(connect_name[0] == 0){\r
- snprintf(connect_name, 100, "127.0.0.1");\r
- hosting = true;\r
- }\r
+ // Address to connect to\r
+ std::string address = "";\r
\r
- if(hosting)\r
- std::cout<<"> Hosting game"<<std::endl;\r
- else\r
- std::cout<<"> Connecting to "<<connect_name<<std::endl;\r
- \r
- char playername[PLAYERNAME_SIZE] = "";\r
- if(g_settings.get("name") != "")\r
+ if(cmd_args.exists("address"))\r
{\r
- snprintf(playername, PLAYERNAME_SIZE, "%s", g_settings.get("name").c_str());\r
+ address = cmd_args.get("address");\r
}\r
else\r
{\r
- std::cout<<"Name of player: ";\r
- std::cin.getline(playername, PLAYERNAME_SIZE);\r
+ address = g_settings.get("address");\r
}\r
- std::cout<<"-> \""<<playername<<"\""<<std::endl;\r
+ \r
+ std::string playername = g_settings.get("name");\r
\r
/*\r
Resolution selection\r
*/\r
\r
bool fullscreen = false;\r
- u16 screenW = atoi(g_settings.get("screenW").c_str());\r
- u16 screenH = atoi(g_settings.get("screenH").c_str());\r
+ u16 screenW = g_settings.getU16("screenW");\r
+ u16 screenH = g_settings.getU16("screenH");\r
\r
//\r
\r
video::E_DRIVER_TYPE driverType;\r
\r
#ifdef _WIN32\r
- //driverType = video::EDT_DIRECT3D9; // Doesn't seem to work\r
+ //driverType = video::EDT_DIRECT3D9;\r
driverType = video::EDT_OPENGL;\r
#else\r
driverType = video::EDT_OPENGL;\r
+ //driverType = video::EDT_BURNINGSVIDEO; // Best software renderer\r
#endif\r
\r
// create device and exit if creation failed\r
g_device = device;\r
g_irrlicht = new IrrlichtWrapper(device);\r
\r
- //g_device = device;\r
+ /*\r
+ Speed tests (done after irrlicht is loaded to get timer)\r
+ */\r
+ if(cmd_args.getFlag("speedtests"))\r
+ {\r
+ dstream<<"Running speed tests"<<std::endl;\r
+ SpeedTests();\r
+ return 0;\r
+ }\r
\r
device->setResizable(true);\r
\r
gui::IGUIFont* font = guienv->getFont(porting::getDataPath("fontlucida.png").c_str());\r
if(font)\r
skin->setFont(font);\r
- \r
+ else\r
+ dstream<<"WARNING: Font file was not found."\r
+ " Using default font."<<std::endl;\r
+ // If font was not found, this will get us one\r
+ font = skin->getFont();\r
+ assert(font);\r
+\r
u32 text_height = font->getDimension(L"Hello, world!").Height;\r
dstream<<"text_height="<<text_height<<std::endl;\r
\r
skin->setColor(gui::EGDC_3D_HIGH_LIGHT, video::SColor(255,0,0,0));\r
skin->setColor(gui::EGDC_3D_SHADOW, video::SColor(255,0,0,0));\r
\r
+ /*\r
+ Preload some textures and stuff\r
+ */\r
+\r
+ init_content_inventory_texture_paths();\r
+ init_mapnode(g_irrlicht);\r
+ init_mineral(g_irrlicht);\r
+\r
+ /*\r
+ GUI stuff\r
+ */\r
+\r
+ /*\r
+ We need some kind of a root node to be able to add\r
+ custom gui elements directly on the screen.\r
+ Otherwise they won't be automatically drawn.\r
+ */\r
+ guiroot = guienv->addStaticText(L"",\r
+ core::rect<s32>(0, 0, 10000, 10000));\r
+ \r
+ // First line of debug text\r
+ gui::IGUIStaticText *guitext = guienv->addStaticText(\r
+ L"",\r
+ core::rect<s32>(5, 5, 795, 5+text_height),\r
+ false, false);\r
+ // Second line of debug text\r
+ gui::IGUIStaticText *guitext2 = guienv->addStaticText(\r
+ L"",\r
+ core::rect<s32>(5, 5+(text_height+5)*1, 795, (5+text_height)*2),\r
+ false, false);\r
+ \r
+ // At the middle of the screen\r
+ // Object infos are shown in this\r
+ gui::IGUIStaticText *guitext_info = guienv->addStaticText(\r
+ L"",\r
+ core::rect<s32>(100, 70, 100+400, 70+(text_height+5)),\r
+ false, false);\r
+ \r
+ // Chat text\r
+ gui::IGUIStaticText *guitext_chat = guienv->addStaticText(\r
+ L"",\r
+ core::rect<s32>(0,0,0,0),\r
+ false, true);\r
+ guitext_chat->setBackgroundColor(video::SColor(96,0,0,0));\r
+ core::list<ChatLine> chat_lines;\r
+ \r
+ /*\r
+ If an error occurs, this is set to something and the\r
+ menu-game loop is restarted. It is then displayed before\r
+ the menu.\r
+ */\r
+ std::wstring error_message = L"";\r
+ \r
+ /*\r
+ Menu-game loop\r
+ */\r
+ while(g_device->run())\r
+ {\r
+ \r
+ // This is used for catching disconnects\r
+ try\r
+ {\r
+ \r
+ /*\r
+ Out-of-game menu loop.\r
+\r
+ Loop quits when menu returns proper parameters.\r
+ */\r
+ for(;;)\r
+ {\r
+ // Cursor can be non-visible when coming from the game\r
+ device->getCursorControl()->setVisible(true);\r
+ // Some stuff are left to scene manager when coming from the game\r
+ // (map at least?)\r
+ smgr->clear();\r
+ // Reset or hide the debug gui texts\r
+ guitext->setText(L"Minetest-c55");\r
+ guitext2->setVisible(false);\r
+ guitext_info->setVisible(false);\r
+ guitext_chat->setVisible(false);\r
+ \r
+ // Initialize menu data\r
+ MainMenuData menudata;\r
+ menudata.address = narrow_to_wide(address);\r
+ menudata.name = narrow_to_wide(playername);\r
+ menudata.port = narrow_to_wide(itos(port));\r
+ menudata.creative_mode = g_settings.getBool("creative_mode");\r
+\r
+ GUIMainMenu *menu =\r
+ new GUIMainMenu(guienv, guiroot, -1, \r
+ &g_menumgr, &menudata, &g_gamecallback);\r
+ menu->allowFocusRemoval(true);\r
+\r
+ if(error_message != L"")\r
+ {\r
+ GUIMessageMenu *menu2 =\r
+ new GUIMessageMenu(guienv, guiroot, -1, \r
+ &g_menumgr, error_message.c_str());\r
+ menu2->drop();\r
+ error_message = L"";\r
+ }\r
+\r
+ video::IVideoDriver* driver = g_device->getVideoDriver();\r
+ \r
+ dstream<<"Created main menu"<<std::endl;\r
+\r
+ while(g_device->run())\r
+ {\r
+ // Run global IrrlichtWrapper's main thread processing stuff\r
+ g_irrlicht->Run();\r
+ \r
+ if(menu->getStatus() == true)\r
+ break;\r
+\r
+ //driver->beginScene(true, true, video::SColor(255,0,0,0));\r
+ driver->beginScene(true, true, video::SColor(255,128,128,128));\r
+ guienv->drawAll();\r
+ driver->endScene();\r
+ }\r
+ \r
+ // Break out of menu-game loop to shut down cleanly\r
+ if(g_device->run() == false)\r
+ break;\r
+ \r
+ dstream<<"Dropping main menu"<<std::endl;\r
+\r
+ menu->drop();\r
+ \r
+ // Delete map if requested\r
+ if(menudata.delete_map)\r
+ {\r
+ bool r = fs::RecursiveDeleteContent(map_dir);\r
+ if(r == false)\r
+ error_message = L"Delete failed";\r
+ continue;\r
+ }\r
+\r
+ playername = wide_to_narrow(menudata.name);\r
+ address = wide_to_narrow(menudata.address);\r
+ port = stoi(wide_to_narrow(menudata.port));\r
+ g_settings.set("creative_mode", itos(menudata.creative_mode));\r
+ \r
+ // Check for valid parameters, restart menu if invalid.\r
+ if(playername == "")\r
+ {\r
+ error_message = L"Name required.";\r
+ continue;\r
+ }\r
+ \r
+ // Save settings\r
+ g_settings.set("name", playername);\r
+ g_settings.set("address", address);\r
+ g_settings.set("port", itos(port));\r
+ // Update configuration file\r
+ if(configpath != "")\r
+ g_settings.updateConfigFile(configpath.c_str());\r
+ \r
+ // Continue to game\r
+ break;\r
+ }\r
+ \r
+ // Break out of menu-game loop to shut down cleanly\r
+ if(g_device->run() == false)\r
+ break;\r
+\r
+ /*\r
+ Make a scope here so that the client and the server and other\r
+ stuff gets removed when disconnected or the irrlicht device\r
+ is removed.\r
+ */\r
+ {\r
+\r
+ // This is set to true at the end of the scope\r
+ g_irrlicht->Shutdown(false);\r
+\r
+ /*\r
+ Draw "Loading" screen\r
+ */\r
const wchar_t *text = L"Loading and connecting...";\r
core::vector2d<s32> center(screenW/2, screenH/2);\r
core::vector2d<s32> textsize(300, text_height);\r
guienv->drawAll();\r
driver->endScene();\r
\r
- /*\r
- Preload some textures\r
- */\r
-\r
- init_content_inventory_texture_paths();\r
- init_tile_texture_paths();\r
- tile_materials_preload(g_irrlicht);\r
-\r
- /*\r
- Make a scope here for the client so that it gets removed\r
- before the irrlicht device\r
- */\r
- {\r
-\r
std::cout<<DTIME<<"Creating server and client"<<std::endl;\r
\r
/*\r
- Create server\r
+ Create server.\r
+ SharedPtr will delete it when it goes out of scope.\r
*/\r
SharedPtr<Server> server;\r
- if(hosting){\r
+ if(address == ""){\r
server = new Server(map_dir, hm_params, map_params);\r
server->start(port);\r
}\r
Create client\r
*/\r
\r
- Client client(device, playername, draw_control);\r
+ Client client(device, playername.c_str(), draw_control);\r
\r
g_client = &client;\r
\r
Address connect_address(0,0,0,0, port);\r
try{\r
- connect_address.Resolve(connect_name);\r
+ if(address == "")\r
+ connect_address.Resolve("localhost");\r
+ else\r
+ connect_address.Resolve(address.c_str());\r
}\r
catch(ResolveError &e)\r
{\r
std::cout<<DTIME<<"Couldn't resolve address"<<std::endl;\r
- return 0;\r
+ //return 0;\r
+ error_message = L"Couldn't resolve address";\r
+ gui_loadingtext->remove();\r
+ continue;\r
}\r
\r
std::cout<<DTIME<<"Connecting to server..."<<std::endl;\r
try{\r
while(client.connectedAndInitialized() == false)\r
{\r
+ // Update screen\r
+ driver->beginScene(true, true, video::SColor(255,0,0,0));\r
+ guienv->drawAll();\r
+ driver->endScene();\r
+\r
+ // Update client and server\r
+\r
client.step(0.1);\r
- if(server != NULL){\r
+\r
+ if(server != NULL)\r
server->step(0.1);\r
- }\r
+ \r
+ // Delay a bit\r
sleep_ms(100);\r
}\r
}\r
catch(con::PeerNotFoundException &e)\r
{\r
std::cout<<DTIME<<"Timed out."<<std::endl;\r
- return 0;\r
+ //return 0;\r
+ error_message = L"Connection timed out.";\r
+ gui_loadingtext->remove();\r
+ continue;\r
}\r
\r
/*\r
GUIQuickInventory *quick_inventory = new GUIQuickInventory\r
(guienv, NULL, v2s32(10, 70), 5, &local_inventory);\r
\r
- /*\r
- We need some kind of a root node to be able to add\r
- custom elements directly on the screen.\r
- Otherwise they won't be automatically drawn.\r
- */\r
- guiroot = guienv->addStaticText(L"",\r
- core::rect<s32>(0, 0, 10000, 10000));\r
- \r
// Test the text input system\r
- /*(new GUITextInputMenu(guienv, guiroot, -1, &g_active_menu_count,\r
+ /*(new GUITextInputMenu(guienv, guiroot, -1, &g_menumgr,\r
NULL))->drop();*/\r
/*GUIMessageMenu *menu =\r
new GUIMessageMenu(guienv, guiroot, -1, \r
- &g_active_menu_count,\r
+ &g_menumgr,\r
L"Asd");\r
menu->drop();*/\r
\r
// Launch pause menu\r
- (new GUIPauseMenu(guienv, guiroot, -1, g_device,\r
- &g_active_menu_count))->drop();\r
-\r
- // First line of debug text\r
- gui::IGUIStaticText *guitext = guienv->addStaticText(\r
- L"Minetest-c55",\r
- core::rect<s32>(5, 5, 795, 5+textsize.Y),\r
- false, false);\r
- // Second line of debug text\r
- gui::IGUIStaticText *guitext2 = guienv->addStaticText(\r
- L"",\r
- core::rect<s32>(5, 5+(textsize.Y+5)*1, 795, (5+textsize.Y)*2),\r
- false, false);\r
- \r
- // At the middle of the screen\r
- // Object infos are shown in this\r
- gui::IGUIStaticText *guitext_info = guienv->addStaticText(\r
- L"test",\r
- core::rect<s32>(100, 70, 100+400, 70+(textsize.Y+5)),\r
- false, false);\r
+ (new GUIPauseMenu(guienv, guiroot, -1, &g_gamecallback,\r
+ &g_menumgr))->drop();\r
\r
- // Chat text\r
- gui::IGUIStaticText *chat_guitext = guienv->addStaticText(\r
- L"Chat here\nOther line\nOther line\nOther line\nOther line",\r
- core::rect<s32>(70, 60, 795, 150),\r
- false, true);\r
- chat_guitext->setBackgroundColor(video::SColor(96,0,0,0));\r
- core::list<ChatLine> chat_lines;\r
+ // Enable texts\r
+ guitext2->setVisible(true);\r
+ guitext_info->setVisible(true);\r
+ guitext_chat->setVisible(true);\r
\r
/*\r
Some statistics are collected in these\r
\r
while(device->run())\r
{\r
+ if(g_disconnect_requested)\r
+ {\r
+ g_disconnect_requested = false;\r
+ break;\r
+ }\r
+\r
/*\r
Run global IrrlichtWrapper's main thread processing stuff\r
*/\r
dtime_jitter1_max_fraction\r
= dtime_jitter1_max_sample / (dtime_avg1+0.001);\r
jitter1_max = 0.0;\r
- \r
- /*\r
- Control freetime ratio\r
- */\r
- /*if(dtime_jitter1_max_fraction > DTIME_JITTER_MAX_FRACTION)\r
- {\r
- if(g_freetime_ratio < FREETIME_RATIO_MAX)\r
- g_freetime_ratio += 0.01;\r
- }\r
- else\r
- {\r
- if(g_freetime_ratio > FREETIME_RATIO_MIN)\r
- g_freetime_ratio -= 0.01;\r
- }*/\r
}\r
}\r
\r
camera_direction.rotateXZBy(camera_yaw);\r
\r
// This is at the height of the eyes of the current figure\r
- v3f camera_position =\r
- player_position + v3f(0, BS+BS/2, 0);\r
+ //v3f camera_position = player_position + v3f(0, BS+BS/2, 0);\r
// This is more like in minecraft\r
- /*v3f camera_position =\r
- player_position + v3f(0, BS+BS*0.65, 0);*/\r
+ v3f camera_position = player_position + v3f(0, BS+BS*0.625, 0);\r
\r
camera->setPosition(camera_position);\r
// *100.0 helps in large map coordinates\r
narrow_to_wide(sign_object->getText());\r
\r
(new GUITextInputMenu(guienv, guiroot, -1,\r
- &g_active_menu_count, dest,\r
+ &g_menumgr, dest,\r
wtext))->drop();\r
}\r
}\r
bool nodefound = false;\r
v3s16 nodepos;\r
v3s16 neighbourpos;\r
- core::aabbox3d<f32> nodefacebox;\r
+ core::aabbox3d<f32> nodehilightbox;\r
f32 mindistance = BS * 1001;\r
\r
v3s16 pos_i = floatToInt(player_position);\r
nodepos = np;\r
neighbourpos = np;\r
mindistance = distance;\r
- nodefacebox = box;\r
+ nodehilightbox = box;\r
}\r
}\r
}\r
nodepos = np;\r
neighbourpos = np + dirs[i];\r
mindistance = distance;\r
- nodefacebox = facebox;\r
+\r
+ //nodehilightbox = facebox;\r
+\r
+ const float d = 0.502;\r
+ core::aabbox3d<f32> nodebox\r
+ (-BS*d, -BS*d, -BS*d, BS*d, BS*d, BS*d);\r
+ v3f nodepos_f = intToFloat(nodepos);\r
+ nodebox.MinEdge += nodepos_f;\r
+ nodebox.MaxEdge += nodepos_f;\r
+ nodehilightbox = nodebox;\r
}\r
} // if distance < mindistance\r
} // for dirs\r
\r
static float dig_time = 0.0;\r
static u16 dig_index = 0;\r
+ \r
+ // Visualize selection\r
+\r
+ hilightboxes.push_back(nodehilightbox);\r
\r
- hilightboxes.push_back(nodefacebox);\r
+ // Handle digging\r
\r
if(g_input->getLeftReleased())\r
{\r
\r
if(dig_index < CRACK_ANIMATION_LENGTH)\r
{\r
+ //TimeTaker timer("client.setTempMod");\r
//dstream<<"dig_index="<<dig_index<<std::endl;\r
client.setTempMod(nodepos, NodeMod(NODEMOD_CRACK, dig_index));\r
}\r
}\r
// We want a slight delay to very little\r
// time consuming nodes\r
- //float mindelay = 0.15;\r
- float mindelay = 0.20;\r
+ float mindelay = 0.15;\r
if(nodig_delay_counter < mindelay)\r
{\r
nodig_delay_counter = mindelay;\r
\r
if(g_settings.getBool("enable_fog") == true)\r
{\r
- f32 range = draw_control.wanted_range * BS;\r
+ //f32 range = draw_control.wanted_range * BS + MAP_BLOCKSIZE/2*BS;\r
+ f32 range = draw_control.wanted_range * BS + MAP_BLOCKSIZE/3*BS;\r
if(draw_control.range_all)\r
range = 100000*BS;\r
\r
it = chat_lines.begin();\r
chat_lines.erase(it);\r
}\r
- chat_guitext->setText(whole.c_str());\r
+ guitext_chat->setText(whole.c_str());\r
// Update gui element size and position\r
core::rect<s32> rect(\r
10,\r
screensize.X - 10,\r
screensize.Y - 10\r
);\r
- chat_guitext->setRelativePosition(rect);\r
+ guitext_chat->setRelativePosition(rect);\r
\r
if(chat_lines.size() == 0)\r
- chat_guitext->setVisible(false);\r
+ guitext_chat->setVisible(false);\r
else\r
- chat_guitext->setVisible(true);\r
+ guitext_chat->setVisible(true);\r
}\r
\r
/*\r
//TimeTaker //timer10("//timer10");\r
\r
video::SMaterial m;\r
- m.Thickness = 10;\r
+ //m.Thickness = 10;\r
+ m.Thickness = 3;\r
m.Lighting = false;\r
driver->setMaterial(m);\r
\r
\r
delete quick_inventory;\r
\r
- } // client is deleted at this point\r
+ /*\r
+ Disable texture fetches and other stuff that is queued\r
+ to be processed by the main loop.\r
+\r
+ This has to be done before client goes out of scope.\r
+ */\r
+ g_irrlicht->Shutdown(true);\r
+\r
+ } // client and server are deleted at this point\r
+\r
+ } //try\r
+ catch(con::PeerNotFoundException &e)\r
+ {\r
+ dstream<<DTIME<<"Connection timed out."<<std::endl;\r
+ error_message = L"Connection timed out.";\r
+ }\r
+\r
+ } // Menu-game loop\r
\r
delete g_input;\r
\r
g_settings.updateConfigFile(configpath.c_str());\r
}*/\r
\r
- } //try\r
- catch(con::PeerNotFoundException &e)\r
- {\r
- dstream<<DTIME<<"Connection timed out."<<std::endl;\r
- \r
- /*if(g_device)\r
- {\r
- GUIMessageMenu *menu =\r
- new GUIMessageMenu(guienv, guiroot, -1, \r
- &g_active_menu_count,\r
- L"Connection timed out");\r
-\r
- video::IVideoDriver* driver = g_device->getVideoDriver();\r
- \r
- dstream<<"Created menu"<<std::endl;\r
-\r
- while(g_device->run() && menu->getStatus() == false)\r
- {\r
- driver->beginScene(true, true, video::SColor(255,0,0,0));\r
- guienv->drawAll();\r
- driver->endScene();\r
- }\r
- \r
- dstream<<"Dropping menu"<<std::endl;\r
-\r
- menu->drop();\r
- }*/\r
- }\r
-\r
END_DEBUG_EXCEPTION_HANDLER\r
\r
debugstreams_deinit();\r