updated menu a bit, and some other small fixes
[oweals/minetest.git] / src / main.cpp
1 /*\r
2 Minetest-c55\r
3 Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>\r
4 \r
5 This program is free software; you can redistribute it and/or modify\r
6 it under the terms of the GNU General Public License as published by\r
7 the Free Software Foundation; either version 2 of the License, or\r
8 (at your option) any later version.\r
9 \r
10 This program is distributed in the hope that it will be useful,\r
11 but WITHOUT ANY WARRANTY; without even the implied warranty of\r
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
13 GNU General Public License for more details.\r
14 \r
15 You should have received a copy of the GNU General Public License along\r
16 with this program; if not, write to the Free Software Foundation, Inc.,\r
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
18 */\r
19 \r
20 /*\r
21 =============================== NOTES ==============================\r
22 NOTE: Things starting with TODO are sometimes only suggestions.\r
23 \r
24 NOTE: iostream.imbue(std::locale("C")) is very slow\r
25 NOTE: Global locale is now set at initialization\r
26 \r
27 NOTE: If VBO (EHM_STATIC) is used, remember to explicitly free the\r
28       hardware buffer (it is not freed automatically)\r
29 \r
30 Random suggeestions (AKA very old suggestions that haven't been done):\r
31 ----------------------------------------------------------------------\r
32 \r
33 SUGG: Fix address to be ipv6 compatible\r
34 \r
35 SUGG: If player is on ground, mainly fetch ground-level blocks\r
36 \r
37 SUGG: Expose Connection's seqnums and ACKs to server and client.\r
38       - This enables saving many packets and making a faster connection\r
39           - This also enables server to check if client has received the\r
40             most recent block sent, for example.\r
41 SUGG: Add a sane bandwidth throttling system to Connection\r
42 \r
43 SUGG: More fine-grained control of client's dumping of blocks from\r
44       memory\r
45           - ...What does this mean in the first place?\r
46 \r
47 SUGG: A map editing mode (similar to dedicated server mode)\r
48 \r
49 SUGG: Transfer more blocks in a single packet\r
50 SUGG: A blockdata combiner class, to which blocks are added and at\r
51       destruction it sends all the stuff in as few packets as possible.\r
52 SUGG: Make a PACKET_COMBINED which contains many subpackets. Utilize\r
53       it by sending more stuff in a single packet.\r
54           - Add a packet queue to RemoteClient, from which packets will be\r
55             combined with object data packets\r
56                 - This is not exactly trivial: the object data packets are\r
57                   sometimes very big by themselves\r
58           - This might not give much network performance gain though.\r
59 \r
60 SUGG: Precalculate lighting translation table at runtime (at startup)\r
61       - This is not doable because it is currently hand-made and not\r
62             based on some mathematical function.\r
63                 - Note: This has been changing lately\r
64 \r
65 SUGG: A version number to blocks, which increments when the block is\r
66       modified (node add/remove, water update, lighting update)\r
67           - This can then be used to make sure the most recent version of\r
68             a block has been sent to client, for example\r
69 \r
70 SUGG: Make the amount of blocks sending to client and the total\r
71           amount of blocks dynamically limited. Transferring blocks is the\r
72           main network eater of this system, so it is the one that has\r
73           to be throttled so that RTTs stay low.\r
74 \r
75 SUGG: Meshes of blocks could be split into 6 meshes facing into\r
76       different directions and then only those drawn that need to be\r
77 \r
78 SUGG: Calculate lighting per vertex to get a lighting effect like in\r
79       bartwe's game\r
80 \r
81 SUGG: Background music based on cellular automata?\r
82       http://www.earslap.com/projectslab/otomata\r
83 \r
84 \r
85 Gaming ideas:\r
86 -------------\r
87 \r
88 - Aim for something like controlling a single dwarf in Dwarf Fortress\r
89 \r
90 - The player could go faster by a crafting a boat, or riding an animal\r
91 \r
92 - Random NPC traders. what else?\r
93 \r
94 Game content:\r
95 -------------\r
96 - When furnace is destroyed, move items to player's inventory\r
97 - Add lots of stuff\r
98 - Glass blocks\r
99 - Growing grass, decaying leaves\r
100         - This can be done in the active blocks I guess.\r
101         - Lots of stuff can be done in the active blocks.\r
102         - Uh, is there an active block list somewhere? I think not. Add it.\r
103 - Breaking weak structures\r
104         - This can probably be accomplished in the same way as grass\r
105 - Player health points\r
106         - When player dies, throw items on map (needs better item-on-map\r
107           implementation)\r
108 - Cobble to get mossy if near water\r
109 - More slots in furnace source list, so that multiple ingredients\r
110   are possible.\r
111 - Keys to chests?\r
112 \r
113 - The Treasure Guard; a big monster with a hammer\r
114         - The hammer does great damage, shakes the ground and removes a block\r
115         - You can drop on top of it, and have some time to attack there\r
116           before he shakes you off\r
117 \r
118 - Maybe the difficulty could come from monsters getting tougher in\r
119   far-away places, and the player starting to need something from\r
120   there when time goes by.\r
121   - The player would have some of that stuff at the beginning, and\r
122     would need new supplies of it when it runs out\r
123 \r
124 - A bomb\r
125 - A spread-items-on-map routine for the bomb, and for dying players\r
126 \r
127 Documentation:\r
128 --------------\r
129 \r
130 Build system / running:\r
131 -----------------------\r
132 \r
133 Networking and serialization:\r
134 -----------------------------\r
135 \r
136 TODO: Get rid of GotSplitPacketException\r
137 \r
138 GUI:\r
139 ----\r
140 \r
141 TODO: Configuration menu, at least for keys\r
142 \r
143 Graphics:\r
144 ---------\r
145 \r
146 SUGG: Combine MapBlock's face caches to so big pieces that VBO\r
147       can be used\r
148       - That is >500 vertices\r
149           - This is not easy; all the MapBlocks close to the player would\r
150             still need to be drawn separately and combining the blocks\r
151                 would have to happen in a background thread\r
152 \r
153 SUGG: Make fetching sector's blocks more efficient when rendering\r
154       sectors that have very large amounts of blocks (on client)\r
155           - Is this necessary at all?\r
156 \r
157 TODO: Flowing water animation\r
158 \r
159 SUGG: Draw cubes in inventory directly with 3D drawing commands, so that\r
160       animating them is easier.\r
161 \r
162 SUGG: Option for enabling proper alpha channel for textures\r
163 TODO: A setting for enabling bilinear filtering for textures\r
164 \r
165 TODO: Better control of draw_control.wanted_max_blocks\r
166 \r
167 TODO: Get player texture (and some others) from the specified texture\r
168       directory\r
169 \r
170 Configuration:\r
171 --------------\r
172 \r
173 Client:\r
174 -------\r
175 \r
176 TODO: Untie client network operations from framerate\r
177       - Needs some input queues or something\r
178           - This won't give much performance boost because calculating block\r
179             meshes takes so long\r
180 \r
181 SUGG: Make morning and evening transition more smooth and maybe shorter\r
182 \r
183 TODO: Don't update all meshes always on single node changes, but\r
184       check which ones should be updated\r
185           - implement Map::updateNodeMeshes() and the usage of it\r
186           - It will give almost always a 4x boost in mesh update performance.\r
187 \r
188 - A weapon engine\r
189 \r
190 - Tool/weapon visualization\r
191 \r
192 Server:\r
193 -------\r
194 \r
195 SUGG: Make an option to the server to disable building and digging near\r
196       the starting position\r
197 \r
198 FIXME: Server sometimes goes into some infinite PeerNotFoundException loop\r
199 \r
200 * Fix the problem with the server constantly saving one or a few\r
201   blocks? List the first saved block, maybe it explains.\r
202   - It is probably caused by oscillating water\r
203 * Make a small history check to transformLiquids to detect and log\r
204   continuous oscillations, in such detail that they can be fixed.\r
205 \r
206 Objects:\r
207 --------\r
208 \r
209 TODO: Get rid of MapBlockObjects and use ActiveObjects\r
210 \r
211 SUGG: MovingObject::move and Player::move are basically the same.\r
212       combine them.\r
213           - NOTE: Player::move is more up-to-date.\r
214           - NOTE: There is a simple move implementation now in collision.{h,cpp}\r
215 \r
216 Map:\r
217 ----\r
218 \r
219 TODO: Mineral and ground material properties\r
220       - This way mineral ground toughness can be calculated with just\r
221             some formula, as well as tool strengths\r
222 \r
223 TODO: Flowing water to actually contain flow direction information\r
224       - There is a space for this - it just has to be implemented.\r
225 \r
226 SUGG: Erosion simulation at map generation time\r
227         - Simulate water flows, which would carve out dirt fast and\r
228           then turn stone into gravel and sand and relocate it.\r
229         - How about relocating minerals, too? Coal and gold in\r
230           downstream sand and gravel would be kind of cool\r
231           - This would need a better way of handling minerals, mainly\r
232                 to have mineral content as a separate field. the first\r
233                 parameter field is free for this.\r
234         - Simulate rock falling from cliffs when water has removed\r
235           enough solid rock from the bottom\r
236 \r
237 SUGG: Try out the notch way of generating maps, that is, make bunches\r
238       of low-res 3d noise and interpolate linearly.\r
239 \r
240 Mapgen v2:\r
241 * Possibly add some kind of erosion and other stuff\r
242 * Better water generation (spread it to underwater caverns but don't\r
243   fill dungeons that don't touch big water masses)\r
244 * When generating a chunk and the neighboring chunk doesn't have mud\r
245   and stuff yet and the ground is fairly flat, the mud will flow to\r
246   the other chunk making nasty straight walls when the other chunk\r
247   is generated. Fix it. Maybe just a special case if the ground is\r
248   flat?\r
249 \r
250 Misc. stuff:\r
251 ------------\r
252 * Make an "environment metafile" to store at least time of day\r
253 * Move digging property stuff from material.{h,cpp} to mapnode.cpp...\r
254   - Or maybe move content_features to material.{h,cpp}?\r
255 * Maybe:\r
256   Make a system for pregenerating quick information for mapblocks, so\r
257   that the client can show them as cubes before they are actually sent\r
258   or even generated.\r
259 \r
260 Making it more portable:\r
261 ------------------------\r
262 * Some MSVC: std::sto* are defined without a namespace and collide\r
263   with the ones in utility.h\r
264 \r
265 ======================================================================\r
266 \r
267 */\r
268 \r
269 #ifdef NDEBUG\r
270         #ifdef _WIN32\r
271                 #pragma message ("Disabling unit tests")\r
272         #else\r
273                 #warning "Disabling unit tests"\r
274         #endif\r
275         // Disable unit tests\r
276         #define ENABLE_TESTS 0\r
277 #else\r
278         // Enable unit tests\r
279         #define ENABLE_TESTS 1\r
280 #endif\r
281 \r
282 #ifdef _MSC_VER\r
283         #pragma comment(lib, "Irrlicht.lib")\r
284         //#pragma comment(lib, "jthread.lib")\r
285         #pragma comment(lib, "zlibwapi.lib")\r
286         #pragma comment(lib, "Shell32.lib")\r
287         // This would get rid of the console window\r
288         //#pragma comment(linker, "/subsystem:windows /ENTRY:mainCRTStartup")\r
289 #endif\r
290 \r
291 #include <iostream>\r
292 #include <fstream>\r
293 //#include <jmutexautolock.h>\r
294 #include <locale.h>\r
295 #include "main.h"\r
296 #include "common_irrlicht.h"\r
297 #include "debug.h"\r
298 //#include "map.h"\r
299 //#include "player.h"\r
300 #include "test.h"\r
301 #include "server.h"\r
302 //#include "client.h"\r
303 #include "constants.h"\r
304 #include "porting.h"\r
305 #include "gettime.h"\r
306 #include "guiMessageMenu.h"\r
307 #include "filesys.h"\r
308 #include "config.h"\r
309 #include "guiMainMenu.h"\r
310 #include "mineral.h"\r
311 //#include "noise.h"\r
312 //#include "tile.h"\r
313 #include "materials.h"\r
314 #include "game.h"\r
315 \r
316 // This makes textures\r
317 ITextureSource *g_texturesource = NULL;\r
318 \r
319 /*\r
320         Settings.\r
321         These are loaded from the config file.\r
322 */\r
323 \r
324 Settings g_settings;\r
325 // This is located in defaultsettings.cpp\r
326 extern void set_default_settings();\r
327 \r
328 /*\r
329         Random stuff\r
330 */\r
331 \r
332 /*\r
333         GUI Stuff\r
334 */\r
335 \r
336 gui::IGUIEnvironment* guienv = NULL;\r
337 gui::IGUIStaticText *guiroot = NULL;\r
338 \r
339 MainMenuManager g_menumgr;\r
340 \r
341 bool noMenuActive()\r
342 {\r
343         return (g_menumgr.menuCount() == 0);\r
344 }\r
345 \r
346 // Passed to menus to allow disconnecting and exiting\r
347 \r
348 MainGameCallback *g_gamecallback = NULL;\r
349 \r
350 /*\r
351         Debug streams\r
352 */\r
353 \r
354 // Connection\r
355 std::ostream *dout_con_ptr = &dummyout;\r
356 std::ostream *derr_con_ptr = &dstream_no_stderr;\r
357 //std::ostream *dout_con_ptr = &dstream_no_stderr;\r
358 //std::ostream *derr_con_ptr = &dstream_no_stderr;\r
359 //std::ostream *dout_con_ptr = &dstream;\r
360 //std::ostream *derr_con_ptr = &dstream;\r
361 \r
362 // Server\r
363 std::ostream *dout_server_ptr = &dstream;\r
364 std::ostream *derr_server_ptr = &dstream;\r
365 \r
366 // Client\r
367 std::ostream *dout_client_ptr = &dstream;\r
368 std::ostream *derr_client_ptr = &dstream;\r
369 \r
370 /*\r
371         gettime.h implementation\r
372 */\r
373 \r
374 // A small helper class\r
375 class TimeGetter\r
376 {\r
377 public:\r
378         TimeGetter(IrrlichtDevice *device):\r
379                 m_device(device)\r
380         {}\r
381         u32 getTime()\r
382         {\r
383                 if(m_device == NULL)\r
384                         return 0;\r
385                 return m_device->getTimer()->getRealTime();\r
386         }\r
387 private:\r
388         IrrlichtDevice *m_device;\r
389 };\r
390 \r
391 // A pointer to a global instance of the time getter\r
392 TimeGetter *g_timegetter = NULL;\r
393 \r
394 u32 getTimeMs()\r
395 {\r
396         if(g_timegetter == NULL)\r
397                 return 0;\r
398         return g_timegetter->getTime();\r
399 }\r
400 \r
401 /*\r
402         Event handler for Irrlicht\r
403 \r
404         NOTE: Everything possible should be moved out from here,\r
405               probably to InputHandler and the_game\r
406 */\r
407 \r
408 class MyEventReceiver : public IEventReceiver\r
409 {\r
410 public:\r
411         // This is the one method that we have to implement\r
412         virtual bool OnEvent(const SEvent& event)\r
413         {\r
414                 /*\r
415                         React to nothing here if a menu is active\r
416                 */\r
417                 if(noMenuActive() == false)\r
418                 {\r
419                         return false;\r
420                 }\r
421 \r
422                 // Remember whether each key is down or up\r
423                 if(event.EventType == irr::EET_KEY_INPUT_EVENT)\r
424                 {\r
425                         keyIsDown[event.KeyInput.Key] = event.KeyInput.PressedDown;\r
426 \r
427                         if(event.KeyInput.PressedDown)\r
428                                 keyWasDown[event.KeyInput.Key] = true;\r
429                 }\r
430 \r
431                 if(event.EventType == irr::EET_MOUSE_INPUT_EVENT)\r
432                 {\r
433                         if(noMenuActive() == false)\r
434                         {\r
435                                 left_active = false;\r
436                                 middle_active = false;\r
437                                 right_active = false;\r
438                         }\r
439                         else\r
440                         {\r
441                                 //dstream<<"MyEventReceiver: mouse input"<<std::endl;\r
442                                 left_active = event.MouseInput.isLeftPressed();\r
443                                 middle_active = event.MouseInput.isMiddlePressed();\r
444                                 right_active = event.MouseInput.isRightPressed();\r
445 \r
446                                 if(event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN)\r
447                                 {\r
448                                         leftclicked = true;\r
449                                 }\r
450                                 if(event.MouseInput.Event == EMIE_RMOUSE_PRESSED_DOWN)\r
451                                 {\r
452                                         rightclicked = true;\r
453                                 }\r
454                                 if(event.MouseInput.Event == EMIE_LMOUSE_LEFT_UP)\r
455                                 {\r
456                                         leftreleased = true;\r
457                                 }\r
458                                 if(event.MouseInput.Event == EMIE_RMOUSE_LEFT_UP)\r
459                                 {\r
460                                         rightreleased = true;\r
461                                 }\r
462                                 if(event.MouseInput.Event == EMIE_MOUSE_WHEEL)\r
463                                 {\r
464                                         mouse_wheel += event.MouseInput.Wheel;\r
465                                 }\r
466                         }\r
467                 }\r
468 \r
469                 return false;\r
470         }\r
471 \r
472         bool IsKeyDown(EKEY_CODE keyCode) const\r
473         {\r
474                 return keyIsDown[keyCode];\r
475         }\r
476         \r
477         // Checks whether a key was down and resets the state\r
478         bool WasKeyDown(EKEY_CODE keyCode)\r
479         {\r
480                 bool b = keyWasDown[keyCode];\r
481                 keyWasDown[keyCode] = false;\r
482                 return b;\r
483         }\r
484 \r
485         s32 getMouseWheel()\r
486         {\r
487                 s32 a = mouse_wheel;\r
488                 mouse_wheel = 0;\r
489                 return a;\r
490         }\r
491 \r
492         void clearInput()\r
493         {\r
494                 for(u32 i=0; i<KEY_KEY_CODES_COUNT; i++)\r
495                 {\r
496                         keyIsDown[i] = false;\r
497                         keyWasDown[i] = false;\r
498                 }\r
499                 \r
500                 leftclicked = false;\r
501                 rightclicked = false;\r
502                 leftreleased = false;\r
503                 rightreleased = false;\r
504 \r
505                 left_active = false;\r
506                 middle_active = false;\r
507                 right_active = false;\r
508 \r
509                 mouse_wheel = 0;\r
510         }\r
511 \r
512         MyEventReceiver()\r
513         {\r
514                 clearInput();\r
515         }\r
516 \r
517         bool leftclicked;\r
518         bool rightclicked;\r
519         bool leftreleased;\r
520         bool rightreleased;\r
521 \r
522         bool left_active;\r
523         bool middle_active;\r
524         bool right_active;\r
525 \r
526         s32 mouse_wheel;\r
527 \r
528 private:\r
529         IrrlichtDevice *m_device;\r
530         \r
531         // The current state of keys\r
532         bool keyIsDown[KEY_KEY_CODES_COUNT];\r
533         // Whether a key has been pressed or not\r
534         bool keyWasDown[KEY_KEY_CODES_COUNT];\r
535 };\r
536 \r
537 /*\r
538         Separated input handler\r
539 */\r
540 \r
541 class RealInputHandler : public InputHandler\r
542 {\r
543 public:\r
544         RealInputHandler(IrrlichtDevice *device, MyEventReceiver *receiver):\r
545                 m_device(device),\r
546                 m_receiver(receiver)\r
547         {\r
548         }\r
549         virtual bool isKeyDown(EKEY_CODE keyCode)\r
550         {\r
551                 return m_receiver->IsKeyDown(keyCode);\r
552         }\r
553         virtual bool wasKeyDown(EKEY_CODE keyCode)\r
554         {\r
555                 return m_receiver->WasKeyDown(keyCode);\r
556         }\r
557         virtual v2s32 getMousePos()\r
558         {\r
559                 return m_device->getCursorControl()->getPosition();\r
560         }\r
561         virtual void setMousePos(s32 x, s32 y)\r
562         {\r
563                 m_device->getCursorControl()->setPosition(x, y);\r
564         }\r
565 \r
566         virtual bool getLeftState()\r
567         {\r
568                 return m_receiver->left_active;\r
569         }\r
570         virtual bool getRightState()\r
571         {\r
572                 return m_receiver->right_active;\r
573         }\r
574         \r
575         virtual bool getLeftClicked()\r
576         {\r
577                 return m_receiver->leftclicked;\r
578         }\r
579         virtual bool getRightClicked()\r
580         {\r
581                 return m_receiver->rightclicked;\r
582         }\r
583         virtual void resetLeftClicked()\r
584         {\r
585                 m_receiver->leftclicked = false;\r
586         }\r
587         virtual void resetRightClicked()\r
588         {\r
589                 m_receiver->rightclicked = false;\r
590         }\r
591 \r
592         virtual bool getLeftReleased()\r
593         {\r
594                 return m_receiver->leftreleased;\r
595         }\r
596         virtual bool getRightReleased()\r
597         {\r
598                 return m_receiver->rightreleased;\r
599         }\r
600         virtual void resetLeftReleased()\r
601         {\r
602                 m_receiver->leftreleased = false;\r
603         }\r
604         virtual void resetRightReleased()\r
605         {\r
606                 m_receiver->rightreleased = false;\r
607         }\r
608 \r
609         virtual s32 getMouseWheel()\r
610         {\r
611                 return m_receiver->getMouseWheel();\r
612         }\r
613 \r
614         void clear()\r
615         {\r
616                 m_receiver->clearInput();\r
617         }\r
618 private:\r
619         IrrlichtDevice *m_device;\r
620         MyEventReceiver *m_receiver;\r
621 };\r
622 \r
623 class RandomInputHandler : public InputHandler\r
624 {\r
625 public:\r
626         RandomInputHandler()\r
627         {\r
628                 leftdown = false;\r
629                 rightdown = false;\r
630                 leftclicked = false;\r
631                 rightclicked = false;\r
632                 leftreleased = false;\r
633                 rightreleased = false;\r
634                 for(u32 i=0; i<KEY_KEY_CODES_COUNT; ++i)\r
635                         keydown[i] = false;\r
636         }\r
637         virtual bool isKeyDown(EKEY_CODE keyCode)\r
638         {\r
639                 return keydown[keyCode];\r
640         }\r
641         virtual bool wasKeyDown(EKEY_CODE keyCode)\r
642         {\r
643                 return false;\r
644         }\r
645         virtual v2s32 getMousePos()\r
646         {\r
647                 return mousepos;\r
648         }\r
649         virtual void setMousePos(s32 x, s32 y)\r
650         {\r
651                 mousepos = v2s32(x,y);\r
652         }\r
653 \r
654         virtual bool getLeftState()\r
655         {\r
656                 return leftdown;\r
657         }\r
658         virtual bool getRightState()\r
659         {\r
660                 return rightdown;\r
661         }\r
662 \r
663         virtual bool getLeftClicked()\r
664         {\r
665                 return leftclicked;\r
666         }\r
667         virtual bool getRightClicked()\r
668         {\r
669                 return rightclicked;\r
670         }\r
671         virtual void resetLeftClicked()\r
672         {\r
673                 leftclicked = false;\r
674         }\r
675         virtual void resetRightClicked()\r
676         {\r
677                 rightclicked = false;\r
678         }\r
679 \r
680         virtual bool getLeftReleased()\r
681         {\r
682                 return leftreleased;\r
683         }\r
684         virtual bool getRightReleased()\r
685         {\r
686                 return rightreleased;\r
687         }\r
688         virtual void resetLeftReleased()\r
689         {\r
690                 leftreleased = false;\r
691         }\r
692         virtual void resetRightReleased()\r
693         {\r
694                 rightreleased = false;\r
695         }\r
696 \r
697         virtual s32 getMouseWheel()\r
698         {\r
699                 return 0;\r
700         }\r
701 \r
702         virtual void step(float dtime)\r
703         {\r
704                 {\r
705                         static float counter1 = 0;\r
706                         counter1 -= dtime;\r
707                         if(counter1 < 0.0)\r
708                         {\r
709                                 counter1 = 0.1*Rand(1, 40);\r
710                                 keydown[irr::KEY_SPACE] = !keydown[irr::KEY_SPACE];\r
711                         }\r
712                 }\r
713                 {\r
714                         static float counter1 = 0;\r
715                         counter1 -= dtime;\r
716                         if(counter1 < 0.0)\r
717                         {\r
718                                 counter1 = 0.1*Rand(1, 40);\r
719                                 keydown[irr::KEY_KEY_E] = !keydown[irr::KEY_KEY_E];\r
720                         }\r
721                 }\r
722                 {\r
723                         static float counter1 = 0;\r
724                         counter1 -= dtime;\r
725                         if(counter1 < 0.0)\r
726                         {\r
727                                 counter1 = 0.1*Rand(1, 40);\r
728                                 keydown[irr::KEY_KEY_W] = !keydown[irr::KEY_KEY_W];\r
729                         }\r
730                 }\r
731                 {\r
732                         static float counter1 = 0;\r
733                         counter1 -= dtime;\r
734                         if(counter1 < 0.0)\r
735                         {\r
736                                 counter1 = 0.1*Rand(1, 40);\r
737                                 keydown[irr::KEY_KEY_A] = !keydown[irr::KEY_KEY_A];\r
738                         }\r
739                 }\r
740                 {\r
741                         static float counter1 = 0;\r
742                         counter1 -= dtime;\r
743                         if(counter1 < 0.0)\r
744                         {\r
745                                 counter1 = 0.1*Rand(1, 20);\r
746                                 mousespeed = v2s32(Rand(-20,20), Rand(-15,20));\r
747                         }\r
748                 }\r
749                 {\r
750                         static float counter1 = 0;\r
751                         counter1 -= dtime;\r
752                         if(counter1 < 0.0)\r
753                         {\r
754                                 counter1 = 0.1*Rand(1, 30);\r
755                                 leftdown = !leftdown;\r
756                                 if(leftdown)\r
757                                         leftclicked = true;\r
758                                 if(!leftdown)\r
759                                         leftreleased = true;\r
760                         }\r
761                 }\r
762                 {\r
763                         static float counter1 = 0;\r
764                         counter1 -= dtime;\r
765                         if(counter1 < 0.0)\r
766                         {\r
767                                 counter1 = 0.1*Rand(1, 15);\r
768                                 rightdown = !rightdown;\r
769                                 if(rightdown)\r
770                                         rightclicked = true;\r
771                                 if(!rightdown)\r
772                                         rightreleased = true;\r
773                         }\r
774                 }\r
775                 mousepos += mousespeed;\r
776         }\r
777 \r
778         s32 Rand(s32 min, s32 max)\r
779         {\r
780                 return (myrand()%(max-min+1))+min;\r
781         }\r
782 private:\r
783         bool keydown[KEY_KEY_CODES_COUNT];\r
784         v2s32 mousepos;\r
785         v2s32 mousespeed;\r
786         bool leftdown;\r
787         bool rightdown;\r
788         bool leftclicked;\r
789         bool rightclicked;\r
790         bool leftreleased;\r
791         bool rightreleased;\r
792 };\r
793 \r
794 // These are defined global so that they're not optimized too much.\r
795 // Can't change them to volatile.\r
796 s16 temp16;\r
797 f32 tempf;\r
798 v3f tempv3f1;\r
799 v3f tempv3f2;\r
800 std::string tempstring;\r
801 std::string tempstring2;\r
802 \r
803 void SpeedTests()\r
804 {\r
805         {\r
806                 dstream<<"The following test should take around 20ms."<<std::endl;\r
807                 TimeTaker timer("Testing std::string speed");\r
808                 const u32 jj = 10000;\r
809                 for(u32 j=0; j<jj; j++)\r
810                 {\r
811                         tempstring = "";\r
812                         tempstring2 = "";\r
813                         const u32 ii = 10;\r
814                         for(u32 i=0; i<ii; i++){\r
815                                 tempstring2 += "asd";\r
816                         }\r
817                         for(u32 i=0; i<ii+1; i++){\r
818                                 tempstring += "asd";\r
819                                 if(tempstring == tempstring2)\r
820                                         break;\r
821                         }\r
822                 }\r
823         }\r
824         \r
825         dstream<<"All of the following tests should take around 100ms each."\r
826                         <<std::endl;\r
827 \r
828         {\r
829                 TimeTaker timer("Testing floating-point conversion speed");\r
830                 tempf = 0.001;\r
831                 for(u32 i=0; i<4000000; i++){\r
832                         temp16 += tempf;\r
833                         tempf += 0.001;\r
834                 }\r
835         }\r
836         \r
837         {\r
838                 TimeTaker timer("Testing floating-point vector speed");\r
839 \r
840                 tempv3f1 = v3f(1,2,3);\r
841                 tempv3f2 = v3f(4,5,6);\r
842                 for(u32 i=0; i<10000000; i++){\r
843                         tempf += tempv3f1.dotProduct(tempv3f2);\r
844                         tempv3f2 += v3f(7,8,9);\r
845                 }\r
846         }\r
847 \r
848         {\r
849                 TimeTaker timer("Testing core::map speed");\r
850                 \r
851                 core::map<v2s16, f32> map1;\r
852                 tempf = -324;\r
853                 const s16 ii=300;\r
854                 for(s16 y=0; y<ii; y++){\r
855                         for(s16 x=0; x<ii; x++){\r
856                                 map1.insert(v2s16(x,y), tempf);\r
857                                 tempf += 1;\r
858                         }\r
859                 }\r
860                 for(s16 y=ii-1; y>=0; y--){\r
861                         for(s16 x=0; x<ii; x++){\r
862                                 tempf = map1[v2s16(x,y)];\r
863                         }\r
864                 }\r
865         }\r
866 \r
867         {\r
868                 dstream<<"Around 5000/ms should do well here."<<std::endl;\r
869                 TimeTaker timer("Testing mutex speed");\r
870                 \r
871                 JMutex m;\r
872                 m.Init();\r
873                 u32 n = 0;\r
874                 u32 i = 0;\r
875                 do{\r
876                         n += 10000;\r
877                         for(; i<n; i++){\r
878                                 m.Lock();\r
879                                 m.Unlock();\r
880                         }\r
881                 }\r
882                 // Do at least 10ms\r
883                 while(timer.getTime() < 10);\r
884 \r
885                 u32 dtime = timer.stop();\r
886                 u32 per_ms = n / dtime;\r
887                 std::cout<<"Done. "<<dtime<<"ms, "\r
888                                 <<per_ms<<"/ms"<<std::endl;\r
889         }\r
890 }\r
891 \r
892 void drawMenuBackground(video::IVideoDriver* driver)\r
893 {\r
894         core::dimension2d<u32> screensize = driver->getScreenSize();\r
895                 \r
896         video::ITexture *bgtexture =\r
897                         driver->getTexture(porting::getDataPath("mud.png").c_str());\r
898         if(bgtexture)\r
899         {\r
900                 s32 texturesize = 128;\r
901                 s32 tiled_y = screensize.Height / texturesize + 1;\r
902                 s32 tiled_x = screensize.Width / texturesize + 1;\r
903                 \r
904                 for(s32 y=0; y<tiled_y; y++)\r
905                 for(s32 x=0; x<tiled_x; x++)\r
906                 {\r
907                         core::rect<s32> rect(0,0,texturesize,texturesize);\r
908                         rect += v2s32(x*texturesize, y*texturesize);\r
909                         driver->draw2DImage(bgtexture, rect,\r
910                                 core::rect<s32>(core::position2d<s32>(0,0),\r
911                                 core::dimension2di(bgtexture->getSize())),\r
912                                 NULL, NULL, true);\r
913                 }\r
914         }\r
915         \r
916         video::ITexture *logotexture =\r
917                         driver->getTexture(porting::getDataPath("menulogo.png").c_str());\r
918         if(logotexture)\r
919         {\r
920                 v2s32 logosize(logotexture->getOriginalSize().Width,\r
921                                 logotexture->getOriginalSize().Height);\r
922                 logosize *= 4;\r
923 \r
924                 video::SColor bgcolor(255,50,50,50);\r
925                 core::rect<s32> bgrect(0, screensize.Height-logosize.Y-20,\r
926                                 screensize.Width, screensize.Height);\r
927                 driver->draw2DRectangle(bgcolor, bgrect, NULL);\r
928 \r
929                 core::rect<s32> rect(0,0,logosize.X,logosize.Y);\r
930                 rect += v2s32(screensize.Width/2,screensize.Height-10-logosize.Y);\r
931                 rect -= v2s32(logosize.X/2, 0);\r
932                 driver->draw2DImage(logotexture, rect,\r
933                         core::rect<s32>(core::position2d<s32>(0,0),\r
934                         core::dimension2di(logotexture->getSize())),\r
935                         NULL, NULL, true);\r
936         }\r
937 }\r
938 \r
939 int main(int argc, char *argv[])\r
940 {\r
941         /*\r
942                 Parse command line\r
943         */\r
944         \r
945         // List all allowed options\r
946         core::map<std::string, ValueSpec> allowed_options;\r
947         allowed_options.insert("help", ValueSpec(VALUETYPE_FLAG));\r
948         allowed_options.insert("server", ValueSpec(VALUETYPE_FLAG,\r
949                         "Run server directly"));\r
950         allowed_options.insert("config", ValueSpec(VALUETYPE_STRING,\r
951                         "Load configuration from specified file"));\r
952         allowed_options.insert("port", ValueSpec(VALUETYPE_STRING));\r
953         allowed_options.insert("address", ValueSpec(VALUETYPE_STRING));\r
954         allowed_options.insert("random-input", ValueSpec(VALUETYPE_FLAG));\r
955         allowed_options.insert("disable-unittests", ValueSpec(VALUETYPE_FLAG));\r
956         allowed_options.insert("enable-unittests", ValueSpec(VALUETYPE_FLAG));\r
957         allowed_options.insert("map-dir", ValueSpec(VALUETYPE_STRING));\r
958 #ifdef _WIN32\r
959         allowed_options.insert("dstream-on-stderr", ValueSpec(VALUETYPE_FLAG));\r
960 #endif\r
961         allowed_options.insert("speedtests", ValueSpec(VALUETYPE_FLAG));\r
962 \r
963         Settings cmd_args;\r
964         \r
965         bool ret = cmd_args.parseCommandLine(argc, argv, allowed_options);\r
966 \r
967         if(ret == false || cmd_args.getFlag("help"))\r
968         {\r
969                 dstream<<"Allowed options:"<<std::endl;\r
970                 for(core::map<std::string, ValueSpec>::Iterator\r
971                                 i = allowed_options.getIterator();\r
972                                 i.atEnd() == false; i++)\r
973                 {\r
974                         dstream<<"  --"<<i.getNode()->getKey();\r
975                         if(i.getNode()->getValue().type == VALUETYPE_FLAG)\r
976                         {\r
977                         }\r
978                         else\r
979                         {\r
980                                 dstream<<" <value>";\r
981                         }\r
982                         dstream<<std::endl;\r
983 \r
984                         if(i.getNode()->getValue().help != NULL)\r
985                         {\r
986                                 dstream<<"      "<<i.getNode()->getValue().help\r
987                                                 <<std::endl;\r
988                         }\r
989                 }\r
990 \r
991                 return cmd_args.getFlag("help") ? 0 : 1;\r
992         }\r
993         \r
994         /*\r
995                 Low-level initialization\r
996         */\r
997 \r
998         bool disable_stderr = false;\r
999 #ifdef _WIN32\r
1000         if(cmd_args.getFlag("dstream-on-stderr") == false)\r
1001                 disable_stderr = true;\r
1002 #endif\r
1003 \r
1004         // Initialize debug streams\r
1005         debugstreams_init(disable_stderr, DEBUGFILE);\r
1006         // Initialize debug stacks\r
1007         debug_stacks_init();\r
1008 \r
1009         DSTACK(__FUNCTION_NAME);\r
1010 \r
1011         porting::signal_handler_init();\r
1012         bool &kill = *porting::signal_handler_killstatus();\r
1013         \r
1014         porting::initializePaths();\r
1015         // Create user data directory\r
1016         fs::CreateDir(porting::path_userdata);\r
1017         \r
1018         // C-style stuff initialization\r
1019         initializeMaterialProperties();\r
1020 \r
1021         // Debug handler\r
1022         BEGIN_DEBUG_EXCEPTION_HANDLER\r
1023 \r
1024         // Print startup message\r
1025         dstream<<DTIME<<"minetest-c55"\r
1026                         " with SER_FMT_VER_HIGHEST="<<(int)SER_FMT_VER_HIGHEST\r
1027                         <<", "<<BUILD_INFO\r
1028                         <<std::endl;\r
1029         \r
1030         /*\r
1031                 Basic initialization\r
1032         */\r
1033 \r
1034         // Initialize default settings\r
1035         set_default_settings();\r
1036         \r
1037         // Set locale. This is for forcing '.' as the decimal point.\r
1038         std::locale::global(std::locale("C"));\r
1039         // This enables printing all characters in bitmap font\r
1040         setlocale(LC_CTYPE, "en_US");\r
1041 \r
1042         // Initialize sockets\r
1043         sockets_init();\r
1044         atexit(sockets_cleanup);\r
1045         \r
1046         /*\r
1047                 Initialization\r
1048         */\r
1049 \r
1050         /*\r
1051                 Read config file\r
1052         */\r
1053         \r
1054         // Path of configuration file in use\r
1055         std::string configpath = "";\r
1056         \r
1057         if(cmd_args.exists("config"))\r
1058         {\r
1059                 bool r = g_settings.readConfigFile(cmd_args.get("config").c_str());\r
1060                 if(r == false)\r
1061                 {\r
1062                         dstream<<"Could not read configuration from \""\r
1063                                         <<cmd_args.get("config")<<"\""<<std::endl;\r
1064                         return 1;\r
1065                 }\r
1066                 configpath = cmd_args.get("config");\r
1067         }\r
1068         else\r
1069         {\r
1070                 core::array<std::string> filenames;\r
1071                 filenames.push_back(porting::path_userdata + "/minetest.conf");\r
1072 #ifdef RUN_IN_PLACE\r
1073                 filenames.push_back(porting::path_userdata + "/../minetest.conf");\r
1074 #endif\r
1075 \r
1076                 for(u32 i=0; i<filenames.size(); i++)\r
1077                 {\r
1078                         bool r = g_settings.readConfigFile(filenames[i].c_str());\r
1079                         if(r)\r
1080                         {\r
1081                                 configpath = filenames[i];\r
1082                                 break;\r
1083                         }\r
1084                 }\r
1085                 \r
1086                 // If no path found, use the first one (menu creates the file)\r
1087                 if(configpath == "")\r
1088                         configpath = filenames[0];\r
1089         }\r
1090 \r
1091         // Initialize random seed\r
1092         srand(time(0));\r
1093         mysrand(time(0));\r
1094 \r
1095         /*\r
1096                 Pre-initialize some stuff with a dummy irrlicht wrapper.\r
1097 \r
1098                 These are needed for unit tests at least.\r
1099         */\r
1100         \r
1101         // Initial call with g_texturesource not set.\r
1102         init_mapnode();\r
1103 \r
1104         /*\r
1105                 Run unit tests\r
1106         */\r
1107 \r
1108         if((ENABLE_TESTS && cmd_args.getFlag("disable-unittests") == false)\r
1109                         || cmd_args.getFlag("enable-unittests") == true)\r
1110         {\r
1111                 run_tests();\r
1112         }\r
1113         \r
1114         /*for(s16 y=-100; y<100; y++)\r
1115         for(s16 x=-100; x<100; x++)\r
1116         {\r
1117                 std::cout<<noise2d_gradient((double)x/10,(double)y/10, 32415)<<std::endl;\r
1118         }\r
1119         return 0;*/\r
1120         \r
1121         /*\r
1122                 Game parameters\r
1123         */\r
1124 \r
1125         // Port\r
1126         u16 port = 30000;\r
1127         if(cmd_args.exists("port"))\r
1128                 port = cmd_args.getU16("port");\r
1129         else if(g_settings.exists("port"))\r
1130                 port = g_settings.getU16("port");\r
1131         if(port == 0)\r
1132                 port = 30000;\r
1133         \r
1134         // Map directory\r
1135         std::string map_dir = porting::path_userdata+"/map";\r
1136         if(cmd_args.exists("map-dir"))\r
1137                 map_dir = cmd_args.get("map-dir");\r
1138         else if(g_settings.exists("map-dir"))\r
1139                 map_dir = g_settings.get("map-dir");\r
1140         \r
1141         // Run dedicated server if asked to\r
1142         if(cmd_args.getFlag("server"))\r
1143         {\r
1144                 DSTACK("Dedicated server branch");\r
1145 \r
1146                 // Create server\r
1147                 Server server(map_dir.c_str());\r
1148                 server.start(port);\r
1149                 \r
1150                 // Run server\r
1151                 dedicated_server_loop(server, kill);\r
1152 \r
1153                 return 0;\r
1154         }\r
1155 \r
1156         /*\r
1157                 More parameters\r
1158         */\r
1159         \r
1160         // Address to connect to\r
1161         std::string address = "";\r
1162         \r
1163         if(cmd_args.exists("address"))\r
1164         {\r
1165                 address = cmd_args.get("address");\r
1166         }\r
1167         else\r
1168         {\r
1169                 address = g_settings.get("address");\r
1170         }\r
1171         \r
1172         std::string playername = g_settings.get("name");\r
1173 \r
1174         /*\r
1175                 Device initialization\r
1176         */\r
1177 \r
1178         // Resolution selection\r
1179         \r
1180         bool fullscreen = false;\r
1181         u16 screenW = g_settings.getU16("screenW");\r
1182         u16 screenH = g_settings.getU16("screenH");\r
1183 \r
1184         // Determine driver\r
1185 \r
1186         video::E_DRIVER_TYPE driverType;\r
1187         \r
1188         std::string driverstring = g_settings.get("video_driver");\r
1189 \r
1190         if(driverstring == "null")\r
1191                 driverType = video::EDT_NULL;\r
1192         else if(driverstring == "software")\r
1193                 driverType = video::EDT_SOFTWARE;\r
1194         else if(driverstring == "burningsvideo")\r
1195                 driverType = video::EDT_BURNINGSVIDEO;\r
1196         else if(driverstring == "direct3d8")\r
1197                 driverType = video::EDT_DIRECT3D8;\r
1198         else if(driverstring == "direct3d9")\r
1199                 driverType = video::EDT_DIRECT3D9;\r
1200         else if(driverstring == "opengl")\r
1201                 driverType = video::EDT_OPENGL;\r
1202         else\r
1203         {\r
1204                 dstream<<"WARNING: Invalid video_driver specified; defaulting "\r
1205                                 "to opengl"<<std::endl;\r
1206                 driverType = video::EDT_OPENGL;\r
1207         }\r
1208 \r
1209         /*\r
1210                 Create device and exit if creation failed\r
1211         */\r
1212 \r
1213         MyEventReceiver receiver;\r
1214 \r
1215         IrrlichtDevice *device;\r
1216         device = createDevice(driverType,\r
1217                         core::dimension2d<u32>(screenW, screenH),\r
1218                         16, fullscreen, false, false, &receiver);\r
1219 \r
1220         if (device == 0)\r
1221                 return 1; // could not create selected driver.\r
1222         \r
1223         // Set device in game parameters\r
1224         device = device;\r
1225         \r
1226         // Create time getter\r
1227         g_timegetter = new TimeGetter(device);\r
1228         \r
1229         // Create game callback for menus\r
1230         g_gamecallback = new MainGameCallback(device);\r
1231         \r
1232         // Create texture source\r
1233         g_texturesource = new TextureSource(device);\r
1234 \r
1235         /*\r
1236                 Speed tests (done after irrlicht is loaded to get timer)\r
1237         */\r
1238         if(cmd_args.getFlag("speedtests"))\r
1239         {\r
1240                 dstream<<"Running speed tests"<<std::endl;\r
1241                 SpeedTests();\r
1242                 return 0;\r
1243         }\r
1244         \r
1245         device->setResizable(true);\r
1246 \r
1247         bool random_input = g_settings.getBool("random_input")\r
1248                         || cmd_args.getFlag("random-input");\r
1249         InputHandler *input = NULL;\r
1250         if(random_input)\r
1251                 input = new RandomInputHandler();\r
1252         else\r
1253                 input = new RealInputHandler(device, &receiver);\r
1254         \r
1255         /*\r
1256                 Continue initialization\r
1257         */\r
1258 \r
1259         //video::IVideoDriver* driver = device->getVideoDriver();\r
1260 \r
1261         /*\r
1262                 This changes the minimum allowed number of vertices in a VBO.\r
1263                 Default is 500.\r
1264         */\r
1265         //driver->setMinHardwareBufferVertexCount(50);\r
1266 \r
1267         scene::ISceneManager* smgr = device->getSceneManager();\r
1268 \r
1269         guienv = device->getGUIEnvironment();\r
1270         gui::IGUISkin* skin = guienv->getSkin();\r
1271         gui::IGUIFont* font = guienv->getFont(porting::getDataPath("fontlucida.png").c_str());\r
1272         if(font)\r
1273                 skin->setFont(font);\r
1274         else\r
1275                 dstream<<"WARNING: Font file was not found."\r
1276                                 " Using default font."<<std::endl;\r
1277         // If font was not found, this will get us one\r
1278         font = skin->getFont();\r
1279         assert(font);\r
1280         \r
1281         u32 text_height = font->getDimension(L"Hello, world!").Height;\r
1282         dstream<<"text_height="<<text_height<<std::endl;\r
1283 \r
1284         //skin->setColor(gui::EGDC_BUTTON_TEXT, video::SColor(255,0,0,0));\r
1285         skin->setColor(gui::EGDC_BUTTON_TEXT, video::SColor(255,255,255,255));\r
1286         //skin->setColor(gui::EGDC_3D_HIGH_LIGHT, video::SColor(0,0,0,0));\r
1287         //skin->setColor(gui::EGDC_3D_SHADOW, video::SColor(0,0,0,0));\r
1288         skin->setColor(gui::EGDC_3D_HIGH_LIGHT, video::SColor(255,0,0,0));\r
1289         skin->setColor(gui::EGDC_3D_SHADOW, video::SColor(255,0,0,0));\r
1290         \r
1291         /*\r
1292                 Preload some textures and stuff\r
1293         */\r
1294 \r
1295         init_content_inventory_texture_paths();\r
1296         init_mapnode(); // Second call with g_texturesource set\r
1297         init_mineral();\r
1298 \r
1299         /*\r
1300                 GUI stuff\r
1301         */\r
1302 \r
1303         /*\r
1304                 If an error occurs, this is set to something and the\r
1305                 menu-game loop is restarted. It is then displayed before\r
1306                 the menu.\r
1307         */\r
1308         std::wstring error_message = L"";\r
1309 \r
1310         /*\r
1311                 Menu-game loop\r
1312         */\r
1313         while(device->run() && kill == false)\r
1314         {\r
1315                 // This is used for catching disconnects\r
1316                 try\r
1317                 {\r
1318 \r
1319                         /*\r
1320                                 Clear everything from the GUIEnvironment\r
1321                         */\r
1322                         guienv->clear();\r
1323                         \r
1324                         /*\r
1325                                 We need some kind of a root node to be able to add\r
1326                                 custom gui elements directly on the screen.\r
1327                                 Otherwise they won't be automatically drawn.\r
1328                         */\r
1329                         guiroot = guienv->addStaticText(L"",\r
1330                                         core::rect<s32>(0, 0, 10000, 10000));\r
1331                         \r
1332                         /*\r
1333                                 Out-of-game menu loop.\r
1334 \r
1335                                 Loop quits when menu returns proper parameters.\r
1336                         */\r
1337                         while(kill == false)\r
1338                         {\r
1339                                 // Cursor can be non-visible when coming from the game\r
1340                                 device->getCursorControl()->setVisible(true);\r
1341                                 // Some stuff are left to scene manager when coming from the game\r
1342                                 // (map at least?)\r
1343                                 smgr->clear();\r
1344                                 // Reset or hide the debug gui texts\r
1345                                 /*guitext->setText(L"Minetest-c55");\r
1346                                 guitext2->setVisible(false);\r
1347                                 guitext_info->setVisible(false);\r
1348                                 guitext_chat->setVisible(false);*/\r
1349                                 \r
1350                                 // Initialize menu data\r
1351                                 MainMenuData menudata;\r
1352                                 menudata.address = narrow_to_wide(address);\r
1353                                 menudata.name = narrow_to_wide(playername);\r
1354                                 menudata.port = narrow_to_wide(itos(port));\r
1355                                 menudata.fancy_trees = g_settings.getBool("new_style_leaves");\r
1356                                 menudata.smooth_lighting = g_settings.getBool("smooth_lighting");\r
1357                                 menudata.creative_mode = g_settings.getBool("creative_mode");\r
1358                                 menudata.enable_damage = g_settings.getBool("enable_damage");\r
1359 \r
1360                                 GUIMainMenu *menu =\r
1361                                                 new GUIMainMenu(guienv, guiroot, -1, \r
1362                                                         &g_menumgr, &menudata, g_gamecallback);\r
1363                                 menu->allowFocusRemoval(true);\r
1364 \r
1365                                 if(error_message != L"")\r
1366                                 {\r
1367                                         dstream<<"WARNING: error_message = "\r
1368                                                         <<wide_to_narrow(error_message)<<std::endl;\r
1369 \r
1370                                         GUIMessageMenu *menu2 =\r
1371                                                         new GUIMessageMenu(guienv, guiroot, -1, \r
1372                                                                 &g_menumgr, error_message.c_str());\r
1373                                         menu2->drop();\r
1374                                         error_message = L"";\r
1375                                 }\r
1376 \r
1377                                 video::IVideoDriver* driver = device->getVideoDriver();\r
1378                                 \r
1379                                 dstream<<"Created main menu"<<std::endl;\r
1380 \r
1381                                 while(device->run() && kill == false)\r
1382                                 {\r
1383                                         if(menu->getStatus() == true)\r
1384                                                 break;\r
1385 \r
1386                                         //driver->beginScene(true, true, video::SColor(255,0,0,0));\r
1387                                         driver->beginScene(true, true, video::SColor(255,128,128,128));\r
1388 \r
1389                                         drawMenuBackground(driver);\r
1390 \r
1391                                         guienv->drawAll();\r
1392                                         \r
1393                                         driver->endScene();\r
1394                                 }\r
1395                                 \r
1396                                 // Break out of menu-game loop to shut down cleanly\r
1397                                 if(device->run() == false || kill == true)\r
1398                                         break;\r
1399                                 \r
1400                                 dstream<<"Dropping main menu"<<std::endl;\r
1401 \r
1402                                 menu->drop();\r
1403                                 \r
1404                                 // Delete map if requested\r
1405                                 if(menudata.delete_map)\r
1406                                 {\r
1407                                         bool r = fs::RecursiveDeleteContent(map_dir);\r
1408                                         if(r == false)\r
1409                                                 error_message = L"Delete failed";\r
1410                                         continue;\r
1411                                 }\r
1412 \r
1413                                 playername = wide_to_narrow(menudata.name);\r
1414                                 address = wide_to_narrow(menudata.address);\r
1415                                 int newport = stoi(wide_to_narrow(menudata.port));\r
1416                                 if(newport != 0)\r
1417                                         port = newport;\r
1418                                 g_settings.set("new_style_leaves", itos(menudata.fancy_trees));\r
1419                                 g_settings.set("smooth_lighting", itos(menudata.smooth_lighting));\r
1420                                 g_settings.set("creative_mode", itos(menudata.creative_mode));\r
1421                                 g_settings.set("enable_damage", itos(menudata.enable_damage));\r
1422                                 \r
1423                                 // Check for valid parameters, restart menu if invalid.\r
1424                                 if(playername == "")\r
1425                                 {\r
1426                                         error_message = L"Name required.";\r
1427                                         continue;\r
1428                                 }\r
1429                                 \r
1430                                 // Save settings\r
1431                                 g_settings.set("name", playername);\r
1432                                 g_settings.set("address", address);\r
1433                                 g_settings.set("port", itos(port));\r
1434                                 // Update configuration file\r
1435                                 if(configpath != "")\r
1436                                         g_settings.updateConfigFile(configpath.c_str());\r
1437                         \r
1438                                 // Continue to game\r
1439                                 break;\r
1440                         }\r
1441                         \r
1442                         // Break out of menu-game loop to shut down cleanly\r
1443                         if(device->run() == false)\r
1444                                 break;\r
1445                         \r
1446                         // Initialize mapnode again to enable changed graphics settings\r
1447                         init_mapnode();\r
1448 \r
1449                         /*\r
1450                                 Run game\r
1451                         */\r
1452                         the_game(\r
1453                                 kill,\r
1454                                 random_input,\r
1455                                 input,\r
1456                                 device,\r
1457                                 font,\r
1458                                 map_dir,\r
1459                                 playername,\r
1460                                 address,\r
1461                                 port,\r
1462                                 error_message\r
1463                         );\r
1464 \r
1465                 } //try\r
1466                 catch(con::PeerNotFoundException &e)\r
1467                 {\r
1468                         dstream<<DTIME<<"Connection error (timed out?)"<<std::endl;\r
1469                         error_message = L"Connection error (timed out?)";\r
1470                 }\r
1471                 catch(SocketException &e)\r
1472                 {\r
1473                         dstream<<DTIME<<"Socket error (port already in use?)"<<std::endl;\r
1474                         error_message = L"Socket error (port already in use?)";\r
1475                 }\r
1476 #ifdef NDEBUG\r
1477                 catch(std::exception &e)\r
1478                 {\r
1479                         std::string narrow_message = "Some exception, what()=\"";\r
1480                         narrow_message += e.what();\r
1481                         narrow_message += "\"";\r
1482                         dstream<<DTIME<<narrow_message<<std::endl;\r
1483                         error_message = narrow_to_wide(narrow_message);\r
1484                 }\r
1485 #endif\r
1486 \r
1487         } // Menu-game loop\r
1488         \r
1489         delete input;\r
1490 \r
1491         /*\r
1492                 In the end, delete the Irrlicht device.\r
1493         */\r
1494         device->drop();\r
1495         \r
1496         END_DEBUG_EXCEPTION_HANDLER\r
1497         \r
1498         debugstreams_deinit();\r
1499         \r
1500         return 0;\r
1501 }\r
1502 \r
1503 //END\r