]> git.lizzy.rs Git - dragonfireclient.git/blob - src/main.cpp
All textures are are now searched first from the directory specified by the texture_p...
[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 #include "sha1.h"\r
329 #include "base64.h"\r
330 \r
331 // This makes textures\r
332 ITextureSource *g_texturesource = NULL;\r
333 \r
334 /*\r
335         Settings.\r
336         These are loaded from the config file.\r
337 */\r
338 \r
339 Settings g_settings;\r
340 // This is located in defaultsettings.cpp\r
341 extern void set_default_settings();\r
342 \r
343 /*\r
344         Random stuff\r
345 */\r
346 \r
347 /*\r
348         GUI Stuff\r
349 */\r
350 \r
351 gui::IGUIEnvironment* guienv = NULL;\r
352 gui::IGUIStaticText *guiroot = NULL;\r
353 \r
354 MainMenuManager g_menumgr;\r
355 \r
356 bool noMenuActive()\r
357 {\r
358         return (g_menumgr.menuCount() == 0);\r
359 }\r
360 \r
361 // Passed to menus to allow disconnecting and exiting\r
362 \r
363 MainGameCallback *g_gamecallback = NULL;\r
364 \r
365 /*\r
366         Debug streams\r
367 */\r
368 \r
369 // Connection\r
370 std::ostream *dout_con_ptr = &dummyout;\r
371 std::ostream *derr_con_ptr = &dstream_no_stderr;\r
372 //std::ostream *dout_con_ptr = &dstream_no_stderr;\r
373 //std::ostream *derr_con_ptr = &dstream_no_stderr;\r
374 //std::ostream *dout_con_ptr = &dstream;\r
375 //std::ostream *derr_con_ptr = &dstream;\r
376 \r
377 // Server\r
378 std::ostream *dout_server_ptr = &dstream;\r
379 std::ostream *derr_server_ptr = &dstream;\r
380 \r
381 // Client\r
382 std::ostream *dout_client_ptr = &dstream;\r
383 std::ostream *derr_client_ptr = &dstream;\r
384 \r
385 /*\r
386         gettime.h implementation\r
387 */\r
388 \r
389 // A small helper class\r
390 class TimeGetter\r
391 {\r
392 public:\r
393         TimeGetter(IrrlichtDevice *device):\r
394                 m_device(device)\r
395         {}\r
396         u32 getTime()\r
397         {\r
398                 if(m_device == NULL)\r
399                         return 0;\r
400                 return m_device->getTimer()->getRealTime();\r
401         }\r
402 private:\r
403         IrrlichtDevice *m_device;\r
404 };\r
405 \r
406 // A pointer to a global instance of the time getter\r
407 TimeGetter *g_timegetter = NULL;\r
408 \r
409 u32 getTimeMs()\r
410 {\r
411         if(g_timegetter == NULL)\r
412                 return 0;\r
413         return g_timegetter->getTime();\r
414 }\r
415 \r
416 /*\r
417         Event handler for Irrlicht\r
418 \r
419         NOTE: Everything possible should be moved out from here,\r
420               probably to InputHandler and the_game\r
421 */\r
422 \r
423 class MyEventReceiver : public IEventReceiver\r
424 {\r
425 public:\r
426         // This is the one method that we have to implement\r
427         virtual bool OnEvent(const SEvent& event)\r
428         {\r
429                 /*\r
430                         React to nothing here if a menu is active\r
431                 */\r
432                 if(noMenuActive() == false)\r
433                 {\r
434                         return false;\r
435                 }\r
436 \r
437                 // Remember whether each key is down or up\r
438                 if(event.EventType == irr::EET_KEY_INPUT_EVENT)\r
439                 {\r
440                         keyIsDown[event.KeyInput.Key] = event.KeyInput.PressedDown;\r
441 \r
442                         if(event.KeyInput.PressedDown)\r
443                                 keyWasDown[event.KeyInput.Key] = true;\r
444                 }\r
445 \r
446                 if(event.EventType == irr::EET_MOUSE_INPUT_EVENT)\r
447                 {\r
448                         if(noMenuActive() == false)\r
449                         {\r
450                                 left_active = false;\r
451                                 middle_active = false;\r
452                                 right_active = false;\r
453                         }\r
454                         else\r
455                         {\r
456                                 //dstream<<"MyEventReceiver: mouse input"<<std::endl;\r
457                                 left_active = event.MouseInput.isLeftPressed();\r
458                                 middle_active = event.MouseInput.isMiddlePressed();\r
459                                 right_active = event.MouseInput.isRightPressed();\r
460 \r
461                                 if(event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN)\r
462                                 {\r
463                                         leftclicked = true;\r
464                                 }\r
465                                 if(event.MouseInput.Event == EMIE_RMOUSE_PRESSED_DOWN)\r
466                                 {\r
467                                         rightclicked = true;\r
468                                 }\r
469                                 if(event.MouseInput.Event == EMIE_LMOUSE_LEFT_UP)\r
470                                 {\r
471                                         leftreleased = true;\r
472                                 }\r
473                                 if(event.MouseInput.Event == EMIE_RMOUSE_LEFT_UP)\r
474                                 {\r
475                                         rightreleased = true;\r
476                                 }\r
477                                 if(event.MouseInput.Event == EMIE_MOUSE_WHEEL)\r
478                                 {\r
479                                         mouse_wheel += event.MouseInput.Wheel;\r
480                                 }\r
481                         }\r
482                 }\r
483 \r
484                 return false;\r
485         }\r
486 \r
487         bool IsKeyDown(EKEY_CODE keyCode) const\r
488         {\r
489                 return keyIsDown[keyCode];\r
490         }\r
491         \r
492         // Checks whether a key was down and resets the state\r
493         bool WasKeyDown(EKEY_CODE keyCode)\r
494         {\r
495                 bool b = keyWasDown[keyCode];\r
496                 keyWasDown[keyCode] = false;\r
497                 return b;\r
498         }\r
499 \r
500         s32 getMouseWheel()\r
501         {\r
502                 s32 a = mouse_wheel;\r
503                 mouse_wheel = 0;\r
504                 return a;\r
505         }\r
506 \r
507         void clearInput()\r
508         {\r
509                 for(u32 i=0; i<KEY_KEY_CODES_COUNT; i++)\r
510                 {\r
511                         keyIsDown[i] = false;\r
512                         keyWasDown[i] = false;\r
513                 }\r
514                 \r
515                 leftclicked = false;\r
516                 rightclicked = false;\r
517                 leftreleased = false;\r
518                 rightreleased = false;\r
519 \r
520                 left_active = false;\r
521                 middle_active = false;\r
522                 right_active = false;\r
523 \r
524                 mouse_wheel = 0;\r
525         }\r
526 \r
527         MyEventReceiver()\r
528         {\r
529                 clearInput();\r
530         }\r
531 \r
532         bool leftclicked;\r
533         bool rightclicked;\r
534         bool leftreleased;\r
535         bool rightreleased;\r
536 \r
537         bool left_active;\r
538         bool middle_active;\r
539         bool right_active;\r
540 \r
541         s32 mouse_wheel;\r
542 \r
543 private:\r
544         IrrlichtDevice *m_device;\r
545         \r
546         // The current state of keys\r
547         bool keyIsDown[KEY_KEY_CODES_COUNT];\r
548         // Whether a key has been pressed or not\r
549         bool keyWasDown[KEY_KEY_CODES_COUNT];\r
550 };\r
551 \r
552 /*\r
553         Separated input handler\r
554 */\r
555 \r
556 class RealInputHandler : public InputHandler\r
557 {\r
558 public:\r
559         RealInputHandler(IrrlichtDevice *device, MyEventReceiver *receiver):\r
560                 m_device(device),\r
561                 m_receiver(receiver)\r
562         {\r
563         }\r
564         virtual bool isKeyDown(EKEY_CODE keyCode)\r
565         {\r
566                 return m_receiver->IsKeyDown(keyCode);\r
567         }\r
568         virtual bool wasKeyDown(EKEY_CODE keyCode)\r
569         {\r
570                 return m_receiver->WasKeyDown(keyCode);\r
571         }\r
572         virtual v2s32 getMousePos()\r
573         {\r
574                 return m_device->getCursorControl()->getPosition();\r
575         }\r
576         virtual void setMousePos(s32 x, s32 y)\r
577         {\r
578                 m_device->getCursorControl()->setPosition(x, y);\r
579         }\r
580 \r
581         virtual bool getLeftState()\r
582         {\r
583                 return m_receiver->left_active;\r
584         }\r
585         virtual bool getRightState()\r
586         {\r
587                 return m_receiver->right_active;\r
588         }\r
589         \r
590         virtual bool getLeftClicked()\r
591         {\r
592                 return m_receiver->leftclicked;\r
593         }\r
594         virtual bool getRightClicked()\r
595         {\r
596                 return m_receiver->rightclicked;\r
597         }\r
598         virtual void resetLeftClicked()\r
599         {\r
600                 m_receiver->leftclicked = false;\r
601         }\r
602         virtual void resetRightClicked()\r
603         {\r
604                 m_receiver->rightclicked = false;\r
605         }\r
606 \r
607         virtual bool getLeftReleased()\r
608         {\r
609                 return m_receiver->leftreleased;\r
610         }\r
611         virtual bool getRightReleased()\r
612         {\r
613                 return m_receiver->rightreleased;\r
614         }\r
615         virtual void resetLeftReleased()\r
616         {\r
617                 m_receiver->leftreleased = false;\r
618         }\r
619         virtual void resetRightReleased()\r
620         {\r
621                 m_receiver->rightreleased = false;\r
622         }\r
623 \r
624         virtual s32 getMouseWheel()\r
625         {\r
626                 return m_receiver->getMouseWheel();\r
627         }\r
628 \r
629         void clear()\r
630         {\r
631                 m_receiver->clearInput();\r
632         }\r
633 private:\r
634         IrrlichtDevice *m_device;\r
635         MyEventReceiver *m_receiver;\r
636 };\r
637 \r
638 class RandomInputHandler : public InputHandler\r
639 {\r
640 public:\r
641         RandomInputHandler()\r
642         {\r
643                 leftdown = false;\r
644                 rightdown = false;\r
645                 leftclicked = false;\r
646                 rightclicked = false;\r
647                 leftreleased = false;\r
648                 rightreleased = false;\r
649                 for(u32 i=0; i<KEY_KEY_CODES_COUNT; ++i)\r
650                         keydown[i] = false;\r
651         }\r
652         virtual bool isKeyDown(EKEY_CODE keyCode)\r
653         {\r
654                 return keydown[keyCode];\r
655         }\r
656         virtual bool wasKeyDown(EKEY_CODE keyCode)\r
657         {\r
658                 return false;\r
659         }\r
660         virtual v2s32 getMousePos()\r
661         {\r
662                 return mousepos;\r
663         }\r
664         virtual void setMousePos(s32 x, s32 y)\r
665         {\r
666                 mousepos = v2s32(x,y);\r
667         }\r
668 \r
669         virtual bool getLeftState()\r
670         {\r
671                 return leftdown;\r
672         }\r
673         virtual bool getRightState()\r
674         {\r
675                 return rightdown;\r
676         }\r
677 \r
678         virtual bool getLeftClicked()\r
679         {\r
680                 return leftclicked;\r
681         }\r
682         virtual bool getRightClicked()\r
683         {\r
684                 return rightclicked;\r
685         }\r
686         virtual void resetLeftClicked()\r
687         {\r
688                 leftclicked = false;\r
689         }\r
690         virtual void resetRightClicked()\r
691         {\r
692                 rightclicked = false;\r
693         }\r
694 \r
695         virtual bool getLeftReleased()\r
696         {\r
697                 return leftreleased;\r
698         }\r
699         virtual bool getRightReleased()\r
700         {\r
701                 return rightreleased;\r
702         }\r
703         virtual void resetLeftReleased()\r
704         {\r
705                 leftreleased = false;\r
706         }\r
707         virtual void resetRightReleased()\r
708         {\r
709                 rightreleased = false;\r
710         }\r
711 \r
712         virtual s32 getMouseWheel()\r
713         {\r
714                 return 0;\r
715         }\r
716 \r
717         virtual void step(float dtime)\r
718         {\r
719                 {\r
720                         static float counter1 = 0;\r
721                         counter1 -= dtime;\r
722                         if(counter1 < 0.0)\r
723                         {\r
724                                 counter1 = 0.1*Rand(1, 40);\r
725                                 keydown[getKeySetting("keymap_jump")] =\r
726                                                 !keydown[getKeySetting("keymap_jump")];\r
727                         }\r
728                 }\r
729                 {\r
730                         static float counter1 = 0;\r
731                         counter1 -= dtime;\r
732                         if(counter1 < 0.0)\r
733                         {\r
734                                 counter1 = 0.1*Rand(1, 40);\r
735                                 keydown[getKeySetting("keymap_special1")] =\r
736                                                 !keydown[getKeySetting("keymap_special1")];\r
737                         }\r
738                 }\r
739                 {\r
740                         static float counter1 = 0;\r
741                         counter1 -= dtime;\r
742                         if(counter1 < 0.0)\r
743                         {\r
744                                 counter1 = 0.1*Rand(1, 40);\r
745                                 keydown[getKeySetting("keymap_forward")] =\r
746                                                 !keydown[getKeySetting("keymap_forward")];\r
747                         }\r
748                 }\r
749                 {\r
750                         static float counter1 = 0;\r
751                         counter1 -= dtime;\r
752                         if(counter1 < 0.0)\r
753                         {\r
754                                 counter1 = 0.1*Rand(1, 40);\r
755                                 keydown[getKeySetting("keymap_left")] =\r
756                                                 !keydown[getKeySetting("keymap_left")];\r
757                         }\r
758                 }\r
759                 {\r
760                         static float counter1 = 0;\r
761                         counter1 -= dtime;\r
762                         if(counter1 < 0.0)\r
763                         {\r
764                                 counter1 = 0.1*Rand(1, 20);\r
765                                 mousespeed = v2s32(Rand(-20,20), Rand(-15,20));\r
766                         }\r
767                 }\r
768                 {\r
769                         static float counter1 = 0;\r
770                         counter1 -= dtime;\r
771                         if(counter1 < 0.0)\r
772                         {\r
773                                 counter1 = 0.1*Rand(1, 30);\r
774                                 leftdown = !leftdown;\r
775                                 if(leftdown)\r
776                                         leftclicked = true;\r
777                                 if(!leftdown)\r
778                                         leftreleased = true;\r
779                         }\r
780                 }\r
781                 {\r
782                         static float counter1 = 0;\r
783                         counter1 -= dtime;\r
784                         if(counter1 < 0.0)\r
785                         {\r
786                                 counter1 = 0.1*Rand(1, 15);\r
787                                 rightdown = !rightdown;\r
788                                 if(rightdown)\r
789                                         rightclicked = true;\r
790                                 if(!rightdown)\r
791                                         rightreleased = true;\r
792                         }\r
793                 }\r
794                 mousepos += mousespeed;\r
795         }\r
796 \r
797         s32 Rand(s32 min, s32 max)\r
798         {\r
799                 return (myrand()%(max-min+1))+min;\r
800         }\r
801 private:\r
802         bool keydown[KEY_KEY_CODES_COUNT];\r
803         v2s32 mousepos;\r
804         v2s32 mousespeed;\r
805         bool leftdown;\r
806         bool rightdown;\r
807         bool leftclicked;\r
808         bool rightclicked;\r
809         bool leftreleased;\r
810         bool rightreleased;\r
811 };\r
812 \r
813 // These are defined global so that they're not optimized too much.\r
814 // Can't change them to volatile.\r
815 s16 temp16;\r
816 f32 tempf;\r
817 v3f tempv3f1;\r
818 v3f tempv3f2;\r
819 std::string tempstring;\r
820 std::string tempstring2;\r
821 \r
822 void SpeedTests()\r
823 {\r
824         {\r
825                 dstream<<"The following test should take around 20ms."<<std::endl;\r
826                 TimeTaker timer("Testing std::string speed");\r
827                 const u32 jj = 10000;\r
828                 for(u32 j=0; j<jj; j++)\r
829                 {\r
830                         tempstring = "";\r
831                         tempstring2 = "";\r
832                         const u32 ii = 10;\r
833                         for(u32 i=0; i<ii; i++){\r
834                                 tempstring2 += "asd";\r
835                         }\r
836                         for(u32 i=0; i<ii+1; i++){\r
837                                 tempstring += "asd";\r
838                                 if(tempstring == tempstring2)\r
839                                         break;\r
840                         }\r
841                 }\r
842         }\r
843         \r
844         dstream<<"All of the following tests should take around 100ms each."\r
845                         <<std::endl;\r
846 \r
847         {\r
848                 TimeTaker timer("Testing floating-point conversion speed");\r
849                 tempf = 0.001;\r
850                 for(u32 i=0; i<4000000; i++){\r
851                         temp16 += tempf;\r
852                         tempf += 0.001;\r
853                 }\r
854         }\r
855         \r
856         {\r
857                 TimeTaker timer("Testing floating-point vector speed");\r
858 \r
859                 tempv3f1 = v3f(1,2,3);\r
860                 tempv3f2 = v3f(4,5,6);\r
861                 for(u32 i=0; i<10000000; i++){\r
862                         tempf += tempv3f1.dotProduct(tempv3f2);\r
863                         tempv3f2 += v3f(7,8,9);\r
864                 }\r
865         }\r
866 \r
867         {\r
868                 TimeTaker timer("Testing core::map speed");\r
869                 \r
870                 core::map<v2s16, f32> map1;\r
871                 tempf = -324;\r
872                 const s16 ii=300;\r
873                 for(s16 y=0; y<ii; y++){\r
874                         for(s16 x=0; x<ii; x++){\r
875                                 map1.insert(v2s16(x,y), tempf);\r
876                                 tempf += 1;\r
877                         }\r
878                 }\r
879                 for(s16 y=ii-1; y>=0; y--){\r
880                         for(s16 x=0; x<ii; x++){\r
881                                 tempf = map1[v2s16(x,y)];\r
882                         }\r
883                 }\r
884         }\r
885 \r
886         {\r
887                 dstream<<"Around 5000/ms should do well here."<<std::endl;\r
888                 TimeTaker timer("Testing mutex speed");\r
889                 \r
890                 JMutex m;\r
891                 m.Init();\r
892                 u32 n = 0;\r
893                 u32 i = 0;\r
894                 do{\r
895                         n += 10000;\r
896                         for(; i<n; i++){\r
897                                 m.Lock();\r
898                                 m.Unlock();\r
899                         }\r
900                 }\r
901                 // Do at least 10ms\r
902                 while(timer.getTime() < 10);\r
903 \r
904                 u32 dtime = timer.stop();\r
905                 u32 per_ms = n / dtime;\r
906                 std::cout<<"Done. "<<dtime<<"ms, "\r
907                                 <<per_ms<<"/ms"<<std::endl;\r
908         }\r
909 }\r
910 \r
911 void drawMenuBackground(video::IVideoDriver* driver)\r
912 {\r
913         core::dimension2d<u32> screensize = driver->getScreenSize();\r
914                 \r
915         video::ITexture *bgtexture =\r
916                         driver->getTexture(getTexturePath("mud.png").c_str());\r
917         if(bgtexture)\r
918         {\r
919                 s32 texturesize = 128;\r
920                 s32 tiled_y = screensize.Height / texturesize + 1;\r
921                 s32 tiled_x = screensize.Width / texturesize + 1;\r
922                 \r
923                 for(s32 y=0; y<tiled_y; y++)\r
924                 for(s32 x=0; x<tiled_x; x++)\r
925                 {\r
926                         core::rect<s32> rect(0,0,texturesize,texturesize);\r
927                         rect += v2s32(x*texturesize, y*texturesize);\r
928                         driver->draw2DImage(bgtexture, rect,\r
929                                 core::rect<s32>(core::position2d<s32>(0,0),\r
930                                 core::dimension2di(bgtexture->getSize())),\r
931                                 NULL, NULL, true);\r
932                 }\r
933         }\r
934         \r
935         video::ITexture *logotexture =\r
936                         driver->getTexture(getTexturePath("menulogo.png").c_str());\r
937         if(logotexture)\r
938         {\r
939                 v2s32 logosize(logotexture->getOriginalSize().Width,\r
940                                 logotexture->getOriginalSize().Height);\r
941                 logosize *= 4;\r
942 \r
943                 video::SColor bgcolor(255,50,50,50);\r
944                 core::rect<s32> bgrect(0, screensize.Height-logosize.Y-20,\r
945                                 screensize.Width, screensize.Height);\r
946                 driver->draw2DRectangle(bgcolor, bgrect, NULL);\r
947 \r
948                 core::rect<s32> rect(0,0,logosize.X,logosize.Y);\r
949                 rect += v2s32(screensize.Width/2,screensize.Height-10-logosize.Y);\r
950                 rect -= v2s32(logosize.X/2, 0);\r
951                 driver->draw2DImage(logotexture, rect,\r
952                         core::rect<s32>(core::position2d<s32>(0,0),\r
953                         core::dimension2di(logotexture->getSize())),\r
954                         NULL, NULL, true);\r
955         }\r
956 }\r
957 \r
958 int main(int argc, char *argv[])\r
959 {\r
960         /*\r
961                 Parse command line\r
962         */\r
963         \r
964         // List all allowed options\r
965         core::map<std::string, ValueSpec> allowed_options;\r
966         allowed_options.insert("help", ValueSpec(VALUETYPE_FLAG));\r
967         allowed_options.insert("server", ValueSpec(VALUETYPE_FLAG,\r
968                         "Run server directly"));\r
969         allowed_options.insert("config", ValueSpec(VALUETYPE_STRING,\r
970                         "Load configuration from specified file"));\r
971         allowed_options.insert("port", ValueSpec(VALUETYPE_STRING));\r
972         allowed_options.insert("address", ValueSpec(VALUETYPE_STRING));\r
973         allowed_options.insert("random-input", ValueSpec(VALUETYPE_FLAG));\r
974         allowed_options.insert("disable-unittests", ValueSpec(VALUETYPE_FLAG));\r
975         allowed_options.insert("enable-unittests", ValueSpec(VALUETYPE_FLAG));\r
976         allowed_options.insert("map-dir", ValueSpec(VALUETYPE_STRING));\r
977 #ifdef _WIN32\r
978         allowed_options.insert("dstream-on-stderr", ValueSpec(VALUETYPE_FLAG));\r
979 #endif\r
980         allowed_options.insert("speedtests", ValueSpec(VALUETYPE_FLAG));\r
981 \r
982         Settings cmd_args;\r
983         \r
984         bool ret = cmd_args.parseCommandLine(argc, argv, allowed_options);\r
985 \r
986         if(ret == false || cmd_args.getFlag("help"))\r
987         {\r
988                 dstream<<"Allowed options:"<<std::endl;\r
989                 for(core::map<std::string, ValueSpec>::Iterator\r
990                                 i = allowed_options.getIterator();\r
991                                 i.atEnd() == false; i++)\r
992                 {\r
993                         dstream<<"  --"<<i.getNode()->getKey();\r
994                         if(i.getNode()->getValue().type == VALUETYPE_FLAG)\r
995                         {\r
996                         }\r
997                         else\r
998                         {\r
999                                 dstream<<" <value>";\r
1000                         }\r
1001                         dstream<<std::endl;\r
1002 \r
1003                         if(i.getNode()->getValue().help != NULL)\r
1004                         {\r
1005                                 dstream<<"      "<<i.getNode()->getValue().help\r
1006                                                 <<std::endl;\r
1007                         }\r
1008                 }\r
1009 \r
1010                 return cmd_args.getFlag("help") ? 0 : 1;\r
1011         }\r
1012         \r
1013         /*\r
1014                 Low-level initialization\r
1015         */\r
1016 \r
1017         bool disable_stderr = false;\r
1018 #ifdef _WIN32\r
1019         if(cmd_args.getFlag("dstream-on-stderr") == false)\r
1020                 disable_stderr = true;\r
1021 #endif\r
1022 \r
1023         // Initialize debug streams\r
1024         debugstreams_init(disable_stderr, DEBUGFILE);\r
1025         // Initialize debug stacks\r
1026         debug_stacks_init();\r
1027 \r
1028         DSTACK(__FUNCTION_NAME);\r
1029 \r
1030         porting::signal_handler_init();\r
1031         bool &kill = *porting::signal_handler_killstatus();\r
1032         \r
1033         porting::initializePaths();\r
1034         // Create user data directory\r
1035         fs::CreateDir(porting::path_userdata);\r
1036         \r
1037         // C-style stuff initialization\r
1038         initializeMaterialProperties();\r
1039 \r
1040         // Debug handler\r
1041         BEGIN_DEBUG_EXCEPTION_HANDLER\r
1042 \r
1043         // Print startup message\r
1044         dstream<<DTIME<<"minetest-c55"\r
1045                         " with SER_FMT_VER_HIGHEST="<<(int)SER_FMT_VER_HIGHEST\r
1046                         <<", "<<BUILD_INFO\r
1047                         <<std::endl;\r
1048         \r
1049         /*\r
1050                 Basic initialization\r
1051         */\r
1052 \r
1053         // Initialize default settings\r
1054         set_default_settings();\r
1055         \r
1056         // Set locale. This is for forcing '.' as the decimal point.\r
1057         std::locale::global(std::locale("C"));\r
1058         // This enables printing all characters in bitmap font\r
1059         setlocale(LC_CTYPE, "en_US");\r
1060 \r
1061         // Initialize sockets\r
1062         sockets_init();\r
1063         atexit(sockets_cleanup);\r
1064         \r
1065         /*\r
1066                 Initialization\r
1067         */\r
1068 \r
1069         /*\r
1070                 Read config file\r
1071         */\r
1072         \r
1073         // Path of configuration file in use\r
1074         std::string configpath = "";\r
1075         \r
1076         if(cmd_args.exists("config"))\r
1077         {\r
1078                 bool r = g_settings.readConfigFile(cmd_args.get("config").c_str());\r
1079                 if(r == false)\r
1080                 {\r
1081                         dstream<<"Could not read configuration from \""\r
1082                                         <<cmd_args.get("config")<<"\""<<std::endl;\r
1083                         return 1;\r
1084                 }\r
1085                 configpath = cmd_args.get("config");\r
1086         }\r
1087         else\r
1088         {\r
1089                 core::array<std::string> filenames;\r
1090                 filenames.push_back(porting::path_userdata + "/minetest.conf");\r
1091 #ifdef RUN_IN_PLACE\r
1092                 filenames.push_back(porting::path_userdata + "/../minetest.conf");\r
1093 #endif\r
1094 \r
1095                 for(u32 i=0; i<filenames.size(); i++)\r
1096                 {\r
1097                         bool r = g_settings.readConfigFile(filenames[i].c_str());\r
1098                         if(r)\r
1099                         {\r
1100                                 configpath = filenames[i];\r
1101                                 break;\r
1102                         }\r
1103                 }\r
1104                 \r
1105                 // If no path found, use the first one (menu creates the file)\r
1106                 if(configpath == "")\r
1107                         configpath = filenames[0];\r
1108         }\r
1109 \r
1110         // Initialize random seed\r
1111         srand(time(0));\r
1112         mysrand(time(0));\r
1113 \r
1114         /*\r
1115                 Pre-initialize some stuff with a dummy irrlicht wrapper.\r
1116 \r
1117                 These are needed for unit tests at least.\r
1118         */\r
1119         \r
1120         // Initial call with g_texturesource not set.\r
1121         init_mapnode();\r
1122 \r
1123         /*\r
1124                 Run unit tests\r
1125         */\r
1126 \r
1127         if((ENABLE_TESTS && cmd_args.getFlag("disable-unittests") == false)\r
1128                         || cmd_args.getFlag("enable-unittests") == true)\r
1129         {\r
1130                 run_tests();\r
1131         }\r
1132         \r
1133         /*for(s16 y=-100; y<100; y++)\r
1134         for(s16 x=-100; x<100; x++)\r
1135         {\r
1136                 std::cout<<noise2d_gradient((double)x/10,(double)y/10, 32415)<<std::endl;\r
1137         }\r
1138         return 0;*/\r
1139         \r
1140         /*\r
1141                 Game parameters\r
1142         */\r
1143 \r
1144         // Port\r
1145         u16 port = 30000;\r
1146         if(cmd_args.exists("port"))\r
1147                 port = cmd_args.getU16("port");\r
1148         else if(g_settings.exists("port"))\r
1149                 port = g_settings.getU16("port");\r
1150         if(port == 0)\r
1151                 port = 30000;\r
1152         \r
1153         // Map directory\r
1154         std::string map_dir = porting::path_userdata+"/map";\r
1155         if(cmd_args.exists("map-dir"))\r
1156                 map_dir = cmd_args.get("map-dir");\r
1157         else if(g_settings.exists("map-dir"))\r
1158                 map_dir = g_settings.get("map-dir");\r
1159         \r
1160         // Run dedicated server if asked to\r
1161         if(cmd_args.getFlag("server"))\r
1162         {\r
1163                 DSTACK("Dedicated server branch");\r
1164 \r
1165                 // Create server\r
1166                 Server server(map_dir.c_str());\r
1167                 server.start(port);\r
1168                 \r
1169                 // Run server\r
1170                 dedicated_server_loop(server, kill);\r
1171 \r
1172                 return 0;\r
1173         }\r
1174 \r
1175 \r
1176         /*\r
1177                 More parameters\r
1178         */\r
1179         \r
1180         // Address to connect to\r
1181         std::string address = "";\r
1182         \r
1183         if(cmd_args.exists("address"))\r
1184         {\r
1185                 address = cmd_args.get("address");\r
1186         }\r
1187         else\r
1188         {\r
1189                 address = g_settings.get("address");\r
1190         }\r
1191         \r
1192         std::string playername = g_settings.get("name");\r
1193 \r
1194         /*\r
1195                 Device initialization\r
1196         */\r
1197 \r
1198         // Resolution selection\r
1199         \r
1200         bool fullscreen = false;\r
1201         u16 screenW = g_settings.getU16("screenW");\r
1202         u16 screenH = g_settings.getU16("screenH");\r
1203 \r
1204         // Determine driver\r
1205 \r
1206         video::E_DRIVER_TYPE driverType;\r
1207         \r
1208         std::string driverstring = g_settings.get("video_driver");\r
1209 \r
1210         if(driverstring == "null")\r
1211                 driverType = video::EDT_NULL;\r
1212         else if(driverstring == "software")\r
1213                 driverType = video::EDT_SOFTWARE;\r
1214         else if(driverstring == "burningsvideo")\r
1215                 driverType = video::EDT_BURNINGSVIDEO;\r
1216         else if(driverstring == "direct3d8")\r
1217                 driverType = video::EDT_DIRECT3D8;\r
1218         else if(driverstring == "direct3d9")\r
1219                 driverType = video::EDT_DIRECT3D9;\r
1220         else if(driverstring == "opengl")\r
1221                 driverType = video::EDT_OPENGL;\r
1222         else\r
1223         {\r
1224                 dstream<<"WARNING: Invalid video_driver specified; defaulting "\r
1225                                 "to opengl"<<std::endl;\r
1226                 driverType = video::EDT_OPENGL;\r
1227         }\r
1228 \r
1229         /*\r
1230                 Create device and exit if creation failed\r
1231         */\r
1232 \r
1233         MyEventReceiver receiver;\r
1234 \r
1235         IrrlichtDevice *device;\r
1236         device = createDevice(driverType,\r
1237                         core::dimension2d<u32>(screenW, screenH),\r
1238                         16, fullscreen, false, false, &receiver);\r
1239 \r
1240         if (device == 0)\r
1241                 return 1; // could not create selected driver.\r
1242         \r
1243         // Set device in game parameters\r
1244         device = device;\r
1245         \r
1246         // Create time getter\r
1247         g_timegetter = new TimeGetter(device);\r
1248         \r
1249         // Create game callback for menus\r
1250         g_gamecallback = new MainGameCallback(device);\r
1251         \r
1252         // Create texture source\r
1253         g_texturesource = new TextureSource(device);\r
1254 \r
1255         /*\r
1256                 Speed tests (done after irrlicht is loaded to get timer)\r
1257         */\r
1258         if(cmd_args.getFlag("speedtests"))\r
1259         {\r
1260                 dstream<<"Running speed tests"<<std::endl;\r
1261                 SpeedTests();\r
1262                 return 0;\r
1263         }\r
1264         \r
1265         device->setResizable(true);\r
1266 \r
1267         bool random_input = g_settings.getBool("random_input")\r
1268                         || cmd_args.getFlag("random-input");\r
1269         InputHandler *input = NULL;\r
1270         if(random_input)\r
1271                 input = new RandomInputHandler();\r
1272         else\r
1273                 input = new RealInputHandler(device, &receiver);\r
1274         \r
1275         /*\r
1276                 Continue initialization\r
1277         */\r
1278 \r
1279         //video::IVideoDriver* driver = device->getVideoDriver();\r
1280 \r
1281         /*\r
1282                 This changes the minimum allowed number of vertices in a VBO.\r
1283                 Default is 500.\r
1284         */\r
1285         //driver->setMinHardwareBufferVertexCount(50);\r
1286 \r
1287         scene::ISceneManager* smgr = device->getSceneManager();\r
1288 \r
1289         guienv = device->getGUIEnvironment();\r
1290         gui::IGUISkin* skin = guienv->getSkin();\r
1291         gui::IGUIFont* font = guienv->getFont(getTexturePath("fontlucida.png").c_str());\r
1292         if(font)\r
1293                 skin->setFont(font);\r
1294         else\r
1295                 dstream<<"WARNING: Font file was not found."\r
1296                                 " Using default font."<<std::endl;\r
1297         // If font was not found, this will get us one\r
1298         font = skin->getFont();\r
1299         assert(font);\r
1300         \r
1301         u32 text_height = font->getDimension(L"Hello, world!").Height;\r
1302         dstream<<"text_height="<<text_height<<std::endl;\r
1303 \r
1304         //skin->setColor(gui::EGDC_BUTTON_TEXT, video::SColor(255,0,0,0));\r
1305         skin->setColor(gui::EGDC_BUTTON_TEXT, video::SColor(255,255,255,255));\r
1306         //skin->setColor(gui::EGDC_3D_HIGH_LIGHT, video::SColor(0,0,0,0));\r
1307         //skin->setColor(gui::EGDC_3D_SHADOW, video::SColor(0,0,0,0));\r
1308         skin->setColor(gui::EGDC_3D_HIGH_LIGHT, video::SColor(255,0,0,0));\r
1309         skin->setColor(gui::EGDC_3D_SHADOW, video::SColor(255,0,0,0));\r
1310         \r
1311         /*\r
1312                 Preload some textures and stuff\r
1313         */\r
1314 \r
1315         init_content_inventory_texture_paths();\r
1316         init_mapnode(); // Second call with g_texturesource set\r
1317         init_mineral();\r
1318 \r
1319         /*\r
1320                 GUI stuff\r
1321         */\r
1322 \r
1323         /*\r
1324                 If an error occurs, this is set to something and the\r
1325                 menu-game loop is restarted. It is then displayed before\r
1326                 the menu.\r
1327         */\r
1328         std::wstring error_message = L"";\r
1329 \r
1330         // The password entered during the menu screen,\r
1331         std::string password;\r
1332 \r
1333         /*\r
1334                 Menu-game loop\r
1335         */\r
1336         while(device->run() && kill == false)\r
1337         {\r
1338 \r
1339                 // This is used for catching disconnects\r
1340                 try\r
1341                 {\r
1342 \r
1343                         /*\r
1344                                 Clear everything from the GUIEnvironment\r
1345                         */\r
1346                         guienv->clear();\r
1347                         \r
1348                         /*\r
1349                                 We need some kind of a root node to be able to add\r
1350                                 custom gui elements directly on the screen.\r
1351                                 Otherwise they won't be automatically drawn.\r
1352                         */\r
1353                         guiroot = guienv->addStaticText(L"",\r
1354                                         core::rect<s32>(0, 0, 10000, 10000));\r
1355                         \r
1356                         /*\r
1357                                 Out-of-game menu loop.\r
1358 \r
1359                                 Loop quits when menu returns proper parameters.\r
1360                         */\r
1361                         while(kill == false)\r
1362                         {\r
1363                                 // Cursor can be non-visible when coming from the game\r
1364                                 device->getCursorControl()->setVisible(true);\r
1365                                 // Some stuff are left to scene manager when coming from the game\r
1366                                 // (map at least?)\r
1367                                 smgr->clear();\r
1368                                 // Reset or hide the debug gui texts\r
1369                                 /*guitext->setText(L"Minetest-c55");\r
1370                                 guitext2->setVisible(false);\r
1371                                 guitext_info->setVisible(false);\r
1372                                 guitext_chat->setVisible(false);*/\r
1373                                 \r
1374                                 // Initialize menu data\r
1375                                 MainMenuData menudata;\r
1376                                 menudata.address = narrow_to_wide(address);\r
1377                                 menudata.name = narrow_to_wide(playername);\r
1378                                 menudata.port = narrow_to_wide(itos(port));\r
1379                                 menudata.fancy_trees = g_settings.getBool("new_style_leaves");\r
1380                                 menudata.smooth_lighting = g_settings.getBool("smooth_lighting");\r
1381                                 menudata.creative_mode = g_settings.getBool("creative_mode");\r
1382                                 menudata.enable_damage = g_settings.getBool("enable_damage");\r
1383 \r
1384                                 GUIMainMenu *menu =\r
1385                                                 new GUIMainMenu(guienv, guiroot, -1, \r
1386                                                         &g_menumgr, &menudata, g_gamecallback);\r
1387                                 menu->allowFocusRemoval(true);\r
1388 \r
1389                                 if(error_message != L"")\r
1390                                 {\r
1391                                         dstream<<"WARNING: error_message = "\r
1392                                                         <<wide_to_narrow(error_message)<<std::endl;\r
1393 \r
1394                                         GUIMessageMenu *menu2 =\r
1395                                                         new GUIMessageMenu(guienv, guiroot, -1, \r
1396                                                                 &g_menumgr, error_message.c_str());\r
1397                                         menu2->drop();\r
1398                                         error_message = L"";\r
1399                                 }\r
1400 \r
1401                                 video::IVideoDriver* driver = device->getVideoDriver();\r
1402                                 \r
1403                                 dstream<<"Created main menu"<<std::endl;\r
1404 \r
1405                                 while(device->run() && kill == false)\r
1406                                 {\r
1407                                         if(menu->getStatus() == true)\r
1408                                                 break;\r
1409 \r
1410                                         //driver->beginScene(true, true, video::SColor(255,0,0,0));\r
1411                                         driver->beginScene(true, true, video::SColor(255,128,128,128));\r
1412 \r
1413                                         drawMenuBackground(driver);\r
1414 \r
1415                                         guienv->drawAll();\r
1416                                         \r
1417                                         driver->endScene();\r
1418                                 }\r
1419                                 \r
1420                                 // Break out of menu-game loop to shut down cleanly\r
1421                                 if(device->run() == false || kill == true)\r
1422                                         break;\r
1423                                 \r
1424                                 dstream<<"Dropping main menu"<<std::endl;\r
1425 \r
1426                                 menu->drop();\r
1427                                 \r
1428                                 // Delete map if requested\r
1429                                 if(menudata.delete_map)\r
1430                                 {\r
1431                                         bool r = fs::RecursiveDeleteContent(map_dir);\r
1432                                         if(r == false)\r
1433                                                 error_message = L"Delete failed";\r
1434                                         continue;\r
1435                                 }\r
1436 \r
1437                                 playername = wide_to_narrow(menudata.name);\r
1438 \r
1439                                 // Get an sha-1 hash of the player's name combined with\r
1440                                 // the password entered. That's what the server uses as\r
1441                                 // their password. (Exception : if the password field is\r
1442                                 // blank, we send a blank password - this is for backwards\r
1443                                 // compatibility with password-less players).\r
1444                                 if(menudata.password.length() > 0)\r
1445                                 {\r
1446                                                 std::string slt=playername + wide_to_narrow(menudata.password);\r
1447                                                 SHA1 *sha1 = new SHA1();\r
1448                                                 sha1->addBytes(slt.c_str(), slt.length());\r
1449                                                 unsigned char *digest = sha1->getDigest();\r
1450                                                 password = base64_encode(digest, 20);\r
1451                                                 free(digest);\r
1452                                 }\r
1453                                 else\r
1454                                 {\r
1455                                                 password = "";\r
1456                                 }\r
1457 \r
1458                                 address = wide_to_narrow(menudata.address);\r
1459                                 int newport = stoi(wide_to_narrow(menudata.port));\r
1460                                 if(newport != 0)\r
1461                                         port = newport;\r
1462                                 g_settings.set("new_style_leaves", itos(menudata.fancy_trees));\r
1463                                 g_settings.set("smooth_lighting", itos(menudata.smooth_lighting));\r
1464                                 g_settings.set("creative_mode", itos(menudata.creative_mode));\r
1465                                 g_settings.set("enable_damage", itos(menudata.enable_damage));\r
1466                                 \r
1467                                 // Check for valid parameters, restart menu if invalid.\r
1468                                 if(playername == "")\r
1469                                 {\r
1470                                         error_message = L"Name required.";\r
1471                                         continue;\r
1472                                 }\r
1473                                 \r
1474                                 // Save settings\r
1475                                 g_settings.set("name", playername);\r
1476                                 g_settings.set("address", address);\r
1477                                 g_settings.set("port", itos(port));\r
1478                                 // Update configuration file\r
1479                                 if(configpath != "")\r
1480                                         g_settings.updateConfigFile(configpath.c_str());\r
1481                         \r
1482                                 // Continue to game\r
1483                                 break;\r
1484                         }\r
1485                         \r
1486                         // Break out of menu-game loop to shut down cleanly\r
1487                         if(device->run() == false)\r
1488                                 break;\r
1489                         \r
1490                         // Initialize mapnode again to enable changed graphics settings\r
1491                         init_mapnode();\r
1492 \r
1493                         /*\r
1494                                 Run game\r
1495                         */\r
1496                         the_game(\r
1497                                 kill,\r
1498                                 random_input,\r
1499                                 input,\r
1500                                 device,\r
1501                                 font,\r
1502                                 map_dir,\r
1503                                 playername,\r
1504                                 password,\r
1505                                 address,\r
1506                                 port,\r
1507                                 error_message\r
1508                         );\r
1509 \r
1510                 } //try\r
1511                 catch(con::PeerNotFoundException &e)\r
1512                 {\r
1513                         dstream<<DTIME<<"Connection error (timed out?)"<<std::endl;\r
1514                         error_message = L"Connection error (timed out?)";\r
1515                 }\r
1516                 catch(SocketException &e)\r
1517                 {\r
1518                         dstream<<DTIME<<"Socket error (port already in use?)"<<std::endl;\r
1519                         error_message = L"Socket error (port already in use?)";\r
1520                 }\r
1521 #ifdef NDEBUG\r
1522                 catch(std::exception &e)\r
1523                 {\r
1524                         std::string narrow_message = "Some exception, what()=\"";\r
1525                         narrow_message += e.what();\r
1526                         narrow_message += "\"";\r
1527                         dstream<<DTIME<<narrow_message<<std::endl;\r
1528                         error_message = narrow_to_wide(narrow_message);\r
1529                 }\r
1530 #endif\r
1531 \r
1532         } // Menu-game loop\r
1533         \r
1534         delete input;\r
1535 \r
1536         /*\r
1537                 In the end, delete the Irrlicht device.\r
1538         */\r
1539         device->drop();\r
1540         \r
1541         END_DEBUG_EXCEPTION_HANDLER\r
1542         \r
1543         debugstreams_deinit();\r
1544         \r
1545         return 0;\r
1546 }\r
1547 \r
1548 //END\r