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