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