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