]> git.lizzy.rs Git - minetest.git/blob - src/main.cpp
better debug output in segfaults and stack overflows in windows
[minetest.git] / src / main.cpp
1 /*\r
2 Minetest-c55\r
3 Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>\r
4 \r
5 This program is free software; you can redistribute it and/or modify\r
6 it under the terms of the GNU General Public License as published by\r
7 the Free Software Foundation; either version 2 of the License, or\r
8 (at your option) any later version.\r
9 \r
10 This program is distributed in the hope that it will be useful,\r
11 but WITHOUT ANY WARRANTY; without even the implied warranty of\r
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
13 GNU General Public License for more details.\r
14 \r
15 You should have received a copy of the GNU General Public License along\r
16 with this program; if not, write to the Free Software Foundation, Inc.,\r
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
18 */\r
19 \r
20 /*\r
21 =============================== NOTES ==============================\r
22 NOTE: Things starting with TODO are sometimes only suggestions.\r
23 \r
24 NOTE: VBO cannot be turned on for fast-changing stuff because there\r
25       is an apparanet memory leak in irrlicht when using it (not sure)\r
26 \r
27 NOTE: iostream.imbue(std::locale("C")) is very slow\r
28 NOTE: Global locale is now set at initialization\r
29 \r
30 SUGG: Fix address to be ipv6 compatible\r
31 \r
32 FIXME: When a new sector is generated, it may change the ground level\r
33        of it's and it's neighbors border that two blocks that are\r
34            above and below each other and that are generated before and\r
35            after the sector heightmap generation (order doesn't matter),\r
36            can have a small gap between each other at the border.\r
37 SUGGESTION: Use same technique for sector heightmaps as what we're\r
38             using for UnlimitedHeightmap? (getting all neighbors\r
39                         when generating)\r
40 \r
41 SUGG: Transfer more blocks in a single packet\r
42 SUGG: A blockdata combiner class, to which blocks are added and at\r
43       destruction it sends all the stuff in as few packets as possible.\r
44 \r
45 SUGG: If player is on ground, mainly fetch ground-level blocks\r
46 SUGG: Fetch stuff mainly from the viewing direction\r
47 \r
48 SUGG: Expose Connection's seqnums and ACKs to server and client.\r
49       - This enables saving many packets and making a faster connection\r
50           - This also enables server to check if client has received the\r
51             most recent block sent, for example.\r
52 SUGG: Add a sane bandwidth throttling system to Connection\r
53 \r
54 SUGG: More fine-grained control of client's dumping of blocks from\r
55       memory\r
56           - ...What does this mean in the first place?\r
57 \r
58 SUGG: A map editing mode (similar to dedicated server mode)\r
59 \r
60 SUGG: Add a time value to the param of footstepped grass and check it\r
61       against a global timer when a block is accessed, to make old\r
62           steps fade away.\r
63 \r
64 SUGG: Make a copy of close-range environment on client for showing\r
65       on screen, with minimal mutexes to slow down the main loop\r
66 \r
67 SUGG: Make a PACKET_COMBINED which contains many subpackets. Utilize\r
68       it by sending more stuff in a single packet.\r
69           - Add a packet queue to RemoteClient, from which packets will be\r
70             combined with object data packets\r
71                 - This is not exactly trivial: the object data packets are\r
72                   sometimes very big by themselves\r
73 \r
74 SUGG: Split MapBlockObject serialization to to-client and to-disk\r
75       - This will allow saving ages of rats on disk but not sending\r
76             them to clients\r
77 \r
78 SUGG: Implement lighting using VoxelManipulator\r
79       - Would it be significantly faster?\r
80 \r
81 FIXME: Rats somehow go underground sometimes (you can see it in water)\r
82        - Does their position get saved to a border value or something?\r
83            - Does this happen anymore?\r
84 \r
85 SUGG: MovingObject::move and Player::move are basically the same.\r
86       combine them.\r
87 \r
88 SUGG: Implement a "Fast check queue" (a queue with a map for checking\r
89       if something is already in it)\r
90       - Use it in active block queue in water flowing\r
91 \r
92 SUGG: Precalculate lighting translation table at runtime (at startup)\r
93 \r
94 SUGG: A version number to blocks, which increments when the block is\r
95       modified (node add/remove, water update, lighting update)\r
96           - This can then be used to make sure the most recent version of\r
97             a block has been sent to client\r
98 \r
99 SUGG: Make the amount of blocks sending to client and the total\r
100           amount of blocks dynamically limited. Transferring blocks is the\r
101           main network eater of this system, so it is the one that has\r
102           to be throttled so that RTTs stay low.\r
103 \r
104 SUGG: Meshes of blocks could be split into 6 meshes facing into\r
105       different directions and then only those drawn that need to be\r
106           - Also an 1-dimensional tile map would be nice probably\r
107 \r
108 TODO: Untie client network operations from framerate\r
109       - Needs some input queues or something\r
110           - Not really necessary?\r
111 \r
112 TODO: Combine MapBlock's face caches to so big pieces that VBO\r
113       gets used\r
114       - That is >500 vertices\r
115 \r
116 TODO: Better dungeons\r
117 TODO: Cliffs, arcs\r
118 \r
119 TODO: Startup and configuration menu\r
120 \r
121 TODO: There are some lighting-related todos and fixmes in\r
122       ServerMap::emergeBlock\r
123 \r
124 TODO: Proper handling of spawning place (try to find something that\r
125       is not in the middle of an ocean (some land to stand on at\r
126           least) and save it in map config.\r
127 \r
128 TODO: Players to only be hidden when the client quits.\r
129 TODO: - Players to be saved on disk, with inventory\r
130 TODO: Players to be saved as text in map/players/<name>\r
131 TODO: Player inventory to be saved on disk\r
132 \r
133 TODO: Make fetching sector's blocks more efficient when rendering\r
134       sectors that have very large amounts of blocks (on client)\r
135 \r
136 TODO: Make the video backend selectable\r
137 \r
138 TODO: Copy the text of the last picked sign to inventory in creative\r
139       mode\r
140 \r
141 TODO: Get rid of GotSplitPacketException\r
142 \r
143 TODO: Check what goes wrong with caching map to disk (Kray)\r
144 \r
145 Block object server side:\r
146       - A "near blocks" buffer, in which some nearby blocks are stored.\r
147           - For all blocks in the buffer, objects are stepped(). This\r
148             means they are active.\r
149           - TODO: A global active buffer is needed for the server\r
150           - TODO: A timestamp to blocks\r
151       - TODO: All blocks going in and out of the buffer are recorded.\r
152             - TODO: For outgoing blocks, timestamp is written.\r
153             - TODO: For incoming blocks, time difference is calculated and\r
154               objects are stepped according to it.\r
155 \r
156 TODO: Better handling of objects and mobs\r
157       - Scripting?\r
158       - There has to be some way to do it with less spaghetti code\r
159           - Make separate classes for client and server\r
160             - Client should not discriminate between blocks, server should\r
161             - Make other players utilize the same framework\r
162                 - This is also needed for objects that don't get sent to client\r
163                   but are used for triggers etc\r
164 \r
165 TODO: Draw big amounts of torches better (that is, throw them in the\r
166       same meshbuffer (can the meshcollector class be used?))\r
167 \r
168 TODO: Check if the usage of Client::isFetchingBlocks() in\r
169       updateViewingRange() actually does something\r
170           NOTE: It isn't used anymore after the rewrite.\r
171 \r
172 TODO: Make an option to the server to disable building and digging near\r
173       the starting position\r
174 \r
175 SUGG: Signs could be done in the same way as torches. For this, blocks\r
176       need an additional metadata field for the texts\r
177           - This is also needed for item container chests\r
178 TODO: There has to be some better way to handle static objects than to\r
179       send them all the time. This affects signs and item objects.\r
180 \r
181 TODO: When server sees that client is removing an inexistent block or\r
182       adding a block to an existent position, resend the MapBlock.\r
183 \r
184 TODO: Map generator: add other materials underground (mud)\r
185 \r
186 Doing now:\r
187 ======================================================================\r
188 \r
189 ======================================================================\r
190 \r
191 */\r
192 \r
193 /*\r
194         Setting this to 1 enables a special camera mode that forces\r
195         the renderers to think that the camera statically points from\r
196         the starting place to a static direction.\r
197 \r
198         This allows one to move around with the player and see what\r
199         is actually drawn behind solid things and behind the player.\r
200 */\r
201 #define FIELD_OF_VIEW_TEST 0\r
202 \r
203 #ifdef UNITTEST_DISABLE\r
204         #ifdef _WIN32\r
205                 #pragma message ("Disabling unit tests")\r
206         #else\r
207                 #warning "Disabling unit tests"\r
208         #endif\r
209         // Disable unit tests\r
210         #define ENABLE_TESTS 0\r
211 #else\r
212         // Enable unit tests\r
213         #define ENABLE_TESTS 1\r
214 #endif\r
215 \r
216 #ifdef _MSC_VER\r
217 #pragma comment(lib, "Irrlicht.lib")\r
218 #pragma comment(lib, "jthread.lib")\r
219 #pragma comment(lib, "zlibwapi.lib")\r
220 // This would get rid of the console window\r
221 //#pragma comment(linker, "/subsystem:windows /ENTRY:mainCRTStartup")\r
222 #endif\r
223 \r
224 #include <iostream>\r
225 #include <fstream>\r
226 #include <jmutexautolock.h>\r
227 #include <locale.h>\r
228 #include "common_irrlicht.h"\r
229 #include "debug.h"\r
230 #include "map.h"\r
231 #include "player.h"\r
232 #include "main.h"\r
233 #include "test.h"\r
234 #include "environment.h"\r
235 #include "server.h"\r
236 #include "client.h"\r
237 #include "serialization.h"\r
238 #include "constants.h"\r
239 #include "strfnd.h"\r
240 #include "porting.h"\r
241 #include "irrlichtwrapper.h"\r
242 #include "gettime.h"\r
243 #include "porting.h"\r
244 #include "guiPauseMenu.h"\r
245 #include "guiInventoryMenu.h"\r
246 #include "guiTextInputMenu.h"\r
247 #include "materials.h"\r
248 #include "guiMessageMenu.h"\r
249 \r
250 IrrlichtWrapper *g_irrlicht;\r
251 \r
252 MapDrawControl draw_control;\r
253 \r
254 /*\r
255         Settings.\r
256         These are loaded from the config file.\r
257 */\r
258 \r
259 Settings g_settings;\r
260 \r
261 extern void set_default_settings();\r
262 \r
263 /*\r
264         Random stuff\r
265 */\r
266 \r
267 IrrlichtDevice *g_device = NULL;\r
268 Client *g_client = NULL;\r
269 \r
270 /*\r
271         GUI Stuff\r
272 */\r
273 gui::IGUIEnvironment* guienv = NULL;\r
274 gui::IGUIStaticText *guiroot = NULL;\r
275 int g_active_menu_count = 0;\r
276 \r
277 bool noMenuActive()\r
278 {\r
279         return (g_active_menu_count == 0);\r
280 }\r
281 \r
282 // Inventory actions from the menu are buffered here before sending\r
283 Queue<InventoryAction*> inventory_action_queue;\r
284 // This is a copy of the inventory that the client's environment has\r
285 Inventory local_inventory;\r
286 \r
287 u16 g_selected_item = 0;\r
288 \r
289 /*\r
290         Debug streams\r
291 */\r
292 \r
293 // Connection\r
294 std::ostream *dout_con_ptr = &dummyout;\r
295 std::ostream *derr_con_ptr = &dstream_no_stderr;\r
296 //std::ostream *dout_con_ptr = &dstream_no_stderr;\r
297 //std::ostream *derr_con_ptr = &dstream_no_stderr;\r
298 //std::ostream *dout_con_ptr = &dstream;\r
299 //std::ostream *derr_con_ptr = &dstream;\r
300 \r
301 // Server\r
302 std::ostream *dout_server_ptr = &dstream;\r
303 std::ostream *derr_server_ptr = &dstream;\r
304 \r
305 // Client\r
306 std::ostream *dout_client_ptr = &dstream;\r
307 std::ostream *derr_client_ptr = &dstream;\r
308 \r
309 /*\r
310         gettime.h implementation\r
311 */\r
312 \r
313 u32 getTimeMs()\r
314 {\r
315         /*\r
316                 Use irrlicht because it is more precise than porting.h's\r
317                 getTimeMs()\r
318         */\r
319         if(g_irrlicht == NULL)\r
320                 return 0;\r
321         return g_irrlicht->getTime();\r
322 }\r
323 \r
324 /*\r
325         Text input system\r
326 */\r
327 \r
328 struct TextDestSign : public TextDest\r
329 {\r
330         TextDestSign(v3s16 blockpos, s16 id, Client *client)\r
331         {\r
332                 m_blockpos = blockpos;\r
333                 m_id = id;\r
334                 m_client = client;\r
335         }\r
336         void gotText(std::wstring text)\r
337         {\r
338                 std::string ntext = wide_to_narrow(text);\r
339                 dstream<<"Changing text of a sign object: "\r
340                                 <<ntext<<std::endl;\r
341                 m_client->sendSignText(m_blockpos, m_id, ntext);\r
342         }\r
343 \r
344         v3s16 m_blockpos;\r
345         s16 m_id;\r
346         Client *m_client;\r
347 };\r
348 \r
349 struct TextDestChat : public TextDest\r
350 {\r
351         TextDestChat(Client *client)\r
352         {\r
353                 m_client = client;\r
354         }\r
355         void gotText(std::wstring text)\r
356         {\r
357                 m_client->sendChatMessage(text);\r
358                 m_client->addChatMessage(text);\r
359         }\r
360 \r
361         Client *m_client;\r
362 };\r
363 \r
364 class MyEventReceiver : public IEventReceiver\r
365 {\r
366 public:\r
367         // This is the one method that we have to implement\r
368         virtual bool OnEvent(const SEvent& event)\r
369         {\r
370                 /*\r
371                         React to nothing here if a menu is active\r
372                 */\r
373                 if(noMenuActive() == false)\r
374                 {\r
375                         clearInput();\r
376                         return false;\r
377                 }\r
378 \r
379                 // Remember whether each key is down or up\r
380                 if(event.EventType == irr::EET_KEY_INPUT_EVENT)\r
381                 {\r
382                         keyIsDown[event.KeyInput.Key] = event.KeyInput.PressedDown;\r
383 \r
384                         if(event.KeyInput.PressedDown)\r
385                         {\r
386                                 //dstream<<"Pressed key: "<<(char)event.KeyInput.Key<<std::endl;\r
387                                 \r
388                                 /*\r
389                                         Launch menus\r
390                                 */\r
391 \r
392                                 if(guienv != NULL && guiroot != NULL && g_device != NULL)\r
393                                 {\r
394                                         if(event.KeyInput.Key == irr::KEY_ESCAPE)\r
395                                         {\r
396                                                 dstream<<DTIME<<"MyEventReceiver: "\r
397                                                                 <<"Launching pause menu"<<std::endl;\r
398                                                 // It will delete itself by itself\r
399                                                 (new GUIPauseMenu(guienv, guiroot, -1, g_device,\r
400                                                                 &g_active_menu_count))->drop();\r
401                                                 return true;\r
402                                         }\r
403                                         if(event.KeyInput.Key == irr::KEY_KEY_I)\r
404                                         {\r
405                                                 dstream<<DTIME<<"MyEventReceiver: "\r
406                                                                 <<"Launching inventory"<<std::endl;\r
407                                                 (new GUIInventoryMenu(guienv, guiroot, -1,\r
408                                                                 &local_inventory, &inventory_action_queue,\r
409                                                                 &g_active_menu_count))->drop();\r
410                                                 return true;\r
411                                         }\r
412                                         if(event.KeyInput.Key == irr::KEY_KEY_T)\r
413                                         {\r
414                                                 TextDest *dest = new TextDestChat(g_client);\r
415 \r
416                                                 (new GUITextInputMenu(guienv, guiroot, -1,\r
417                                                                 &g_active_menu_count, dest,\r
418                                                                 L""))->drop();\r
419                                         }\r
420                                 }\r
421 \r
422                                 // Material selection\r
423                                 if(event.KeyInput.Key == irr::KEY_KEY_F)\r
424                                 {\r
425                                         if(g_selected_item < PLAYER_INVENTORY_SIZE-1)\r
426                                                 g_selected_item++;\r
427                                         else\r
428                                                 g_selected_item = 0;\r
429                                         dstream<<DTIME<<"Selected item: "\r
430                                                         <<g_selected_item<<std::endl;\r
431                                 }\r
432 \r
433                                 // Viewing range selection\r
434                                 if(event.KeyInput.Key == irr::KEY_KEY_R)\r
435                                 {\r
436                                         if(draw_control.range_all)\r
437                                         {\r
438                                                 draw_control.range_all = false;\r
439                                                 dstream<<DTIME<<"Disabled full viewing range"<<std::endl;\r
440                                         }\r
441                                         else\r
442                                         {\r
443                                                 draw_control.range_all = true;\r
444                                                 dstream<<DTIME<<"Enabled full viewing range"<<std::endl;\r
445                                         }\r
446                                 }\r
447 \r
448                                 // Print debug stacks\r
449                                 if(event.KeyInput.Key == irr::KEY_KEY_P)\r
450                                 {\r
451                                         dstream<<"-----------------------------------------"\r
452                                                         <<std::endl;\r
453                                         dstream<<DTIME<<"Printing debug stacks:"<<std::endl;\r
454                                         dstream<<"-----------------------------------------"\r
455                                                         <<std::endl;\r
456                                         debug_stacks_print();\r
457                                 }\r
458                         }\r
459                 }\r
460 \r
461                 if(event.EventType == irr::EET_MOUSE_INPUT_EVENT)\r
462                 {\r
463                         if(noMenuActive() == false)\r
464                         {\r
465                                 left_active = false;\r
466                                 middle_active = false;\r
467                                 right_active = false;\r
468                         }\r
469                         else\r
470                         {\r
471                                 //dstream<<"MyEventReceiver: mouse input"<<std::endl;\r
472                                 left_active = event.MouseInput.isLeftPressed();\r
473                                 middle_active = event.MouseInput.isMiddlePressed();\r
474                                 right_active = event.MouseInput.isRightPressed();\r
475 \r
476                                 if(event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN)\r
477                                 {\r
478                                         leftclicked = true;\r
479                                 }\r
480                                 if(event.MouseInput.Event == EMIE_RMOUSE_PRESSED_DOWN)\r
481                                 {\r
482                                         rightclicked = true;\r
483                                 }\r
484                                 if(event.MouseInput.Event == EMIE_LMOUSE_LEFT_UP)\r
485                                 {\r
486                                         leftreleased = true;\r
487                                 }\r
488                                 if(event.MouseInput.Event == EMIE_RMOUSE_LEFT_UP)\r
489                                 {\r
490                                         rightreleased = true;\r
491                                 }\r
492                                 if(event.MouseInput.Event == EMIE_MOUSE_WHEEL)\r
493                                 {\r
494                                         /*dstream<<"event.MouseInput.Wheel="\r
495                                                         <<event.MouseInput.Wheel<<std::endl;*/\r
496                                         if(event.MouseInput.Wheel < 0)\r
497                                         {\r
498                                                 if(g_selected_item < PLAYER_INVENTORY_SIZE-1)\r
499                                                         g_selected_item++;\r
500                                                 else\r
501                                                         g_selected_item = 0;\r
502                                         }\r
503                                         else if(event.MouseInput.Wheel > 0)\r
504                                         {\r
505                                                 if(g_selected_item > 0)\r
506                                                         g_selected_item--;\r
507                                                 else\r
508                                                         g_selected_item = PLAYER_INVENTORY_SIZE-1;\r
509                                         }\r
510                                 }\r
511                         }\r
512                 }\r
513 \r
514                 return false;\r
515         }\r
516 \r
517         // This is used to check whether a key is being held down\r
518         virtual bool IsKeyDown(EKEY_CODE keyCode) const\r
519         {\r
520                 return keyIsDown[keyCode];\r
521         }\r
522 \r
523         void clearInput()\r
524         {\r
525                 for (u32 i=0; i<KEY_KEY_CODES_COUNT; ++i)\r
526                                 keyIsDown[i] = false;\r
527                 \r
528                 leftclicked = false;\r
529                 rightclicked = false;\r
530                 leftreleased = false;\r
531                 rightreleased = false;\r
532 \r
533                 left_active = false;\r
534                 middle_active = false;\r
535                 right_active = false;\r
536         }\r
537 \r
538         MyEventReceiver()\r
539         {\r
540                 clearInput();\r
541         }\r
542 \r
543         bool leftclicked;\r
544         bool rightclicked;\r
545         bool leftreleased;\r
546         bool rightreleased;\r
547 \r
548         bool left_active;\r
549         bool middle_active;\r
550         bool right_active;\r
551 \r
552 private:\r
553         // We use this array to store the current state of each key\r
554         bool keyIsDown[KEY_KEY_CODES_COUNT];\r
555         //s32 mouseX;\r
556         //s32 mouseY;\r
557         IrrlichtDevice *m_device;\r
558 };\r
559 \r
560 class InputHandler\r
561 {\r
562 public:\r
563         InputHandler()\r
564         {\r
565         }\r
566         virtual ~InputHandler()\r
567         {\r
568         }\r
569 \r
570         virtual bool isKeyDown(EKEY_CODE keyCode) = 0;\r
571 \r
572         virtual v2s32 getMousePos() = 0;\r
573         virtual void setMousePos(s32 x, s32 y) = 0;\r
574 \r
575         virtual bool getLeftState() = 0;\r
576         virtual bool getRightState() = 0;\r
577 \r
578         virtual bool getLeftClicked() = 0;\r
579         virtual bool getRightClicked() = 0;\r
580         virtual void resetLeftClicked() = 0;\r
581         virtual void resetRightClicked() = 0;\r
582 \r
583         virtual bool getLeftReleased() = 0;\r
584         virtual bool getRightReleased() = 0;\r
585         virtual void resetLeftReleased() = 0;\r
586         virtual void resetRightReleased() = 0;\r
587         \r
588         virtual void step(float dtime) {};\r
589 \r
590         virtual void clear() {};\r
591 };\r
592 \r
593 InputHandler *g_input = NULL;\r
594 \r
595 class RealInputHandler : public InputHandler\r
596 {\r
597 public:\r
598         RealInputHandler(IrrlichtDevice *device, MyEventReceiver *receiver):\r
599                 m_device(device),\r
600                 m_receiver(receiver)\r
601         {\r
602         }\r
603         virtual bool isKeyDown(EKEY_CODE keyCode)\r
604         {\r
605                 return m_receiver->IsKeyDown(keyCode);\r
606         }\r
607         virtual v2s32 getMousePos()\r
608         {\r
609                 return m_device->getCursorControl()->getPosition();\r
610         }\r
611         virtual void setMousePos(s32 x, s32 y)\r
612         {\r
613                 m_device->getCursorControl()->setPosition(x, y);\r
614         }\r
615 \r
616         virtual bool getLeftState()\r
617         {\r
618                 return m_receiver->left_active;\r
619         }\r
620         virtual bool getRightState()\r
621         {\r
622                 return m_receiver->right_active;\r
623         }\r
624         \r
625         virtual bool getLeftClicked()\r
626         {\r
627                 return m_receiver->leftclicked;\r
628         }\r
629         virtual bool getRightClicked()\r
630         {\r
631                 return m_receiver->rightclicked;\r
632         }\r
633         virtual void resetLeftClicked()\r
634         {\r
635                 m_receiver->leftclicked = false;\r
636         }\r
637         virtual void resetRightClicked()\r
638         {\r
639                 m_receiver->rightclicked = false;\r
640         }\r
641 \r
642         virtual bool getLeftReleased()\r
643         {\r
644                 return m_receiver->leftreleased;\r
645         }\r
646         virtual bool getRightReleased()\r
647         {\r
648                 return m_receiver->rightreleased;\r
649         }\r
650         virtual void resetLeftReleased()\r
651         {\r
652                 m_receiver->leftreleased = false;\r
653         }\r
654         virtual void resetRightReleased()\r
655         {\r
656                 m_receiver->rightreleased = false;\r
657         }\r
658 \r
659         void clear()\r
660         {\r
661                 resetRightClicked();\r
662                 resetLeftClicked();\r
663         }\r
664 private:\r
665         IrrlichtDevice *m_device;\r
666         MyEventReceiver *m_receiver;\r
667 };\r
668 \r
669 class RandomInputHandler : public InputHandler\r
670 {\r
671 public:\r
672         RandomInputHandler()\r
673         {\r
674                 leftclicked = false;\r
675                 rightclicked = false;\r
676                 for(u32 i=0; i<KEY_KEY_CODES_COUNT; ++i)\r
677                         keydown[i] = false;\r
678         }\r
679         virtual bool isKeyDown(EKEY_CODE keyCode)\r
680         {\r
681                 return keydown[keyCode];\r
682         }\r
683         virtual v2s32 getMousePos()\r
684         {\r
685                 return mousepos;\r
686         }\r
687         virtual void setMousePos(s32 x, s32 y)\r
688         {\r
689                 mousepos = v2s32(x,y);\r
690         }\r
691 \r
692         virtual bool getLeftState()\r
693         {\r
694                 return false;\r
695         }\r
696         virtual bool getRightState()\r
697         {\r
698                 return false;\r
699         }\r
700 \r
701         virtual bool getLeftClicked()\r
702         {\r
703                 return leftclicked;\r
704         }\r
705         virtual bool getRightClicked()\r
706         {\r
707                 return rightclicked;\r
708         }\r
709         virtual void resetLeftClicked()\r
710         {\r
711                 leftclicked = false;\r
712         }\r
713         virtual void resetRightClicked()\r
714         {\r
715                 rightclicked = false;\r
716         }\r
717 \r
718         virtual bool getLeftReleased()\r
719         {\r
720                 return false;\r
721         }\r
722         virtual bool getRightReleased()\r
723         {\r
724                 return false;\r
725         }\r
726         virtual void resetLeftReleased()\r
727         {\r
728         }\r
729         virtual void resetRightReleased()\r
730         {\r
731         }\r
732 \r
733         virtual void step(float dtime)\r
734         {\r
735                 {\r
736                         static float counter1 = 0;\r
737                         counter1 -= dtime;\r
738                         if(counter1 < 0.0)\r
739                         {\r
740                                 counter1 = 0.1*Rand(1,10);\r
741                                 /*if(g_selected_material < USEFUL_CONTENT_COUNT-1)\r
742                                         g_selected_material++;\r
743                                 else\r
744                                         g_selected_material = 0;*/\r
745                                 if(g_selected_item < PLAYER_INVENTORY_SIZE-1)\r
746                                         g_selected_item++;\r
747                                 else\r
748                                         g_selected_item = 0;\r
749                         }\r
750                 }\r
751                 {\r
752                         static float counter1 = 0;\r
753                         counter1 -= dtime;\r
754                         if(counter1 < 0.0)\r
755                         {\r
756                                 counter1 = 0.1*Rand(1, 40);\r
757                                 keydown[irr::KEY_SPACE] = !keydown[irr::KEY_SPACE];\r
758                         }\r
759                 }\r
760                 {\r
761                         static float counter1 = 0;\r
762                         counter1 -= dtime;\r
763                         if(counter1 < 0.0)\r
764                         {\r
765                                 counter1 = 0.1*Rand(1, 40);\r
766                                 keydown[irr::KEY_KEY_2] = !keydown[irr::KEY_KEY_2];\r
767                         }\r
768                 }\r
769                 {\r
770                         static float counter1 = 0;\r
771                         counter1 -= dtime;\r
772                         if(counter1 < 0.0)\r
773                         {\r
774                                 counter1 = 0.1*Rand(1, 40);\r
775                                 keydown[irr::KEY_KEY_W] = !keydown[irr::KEY_KEY_W];\r
776                         }\r
777                 }\r
778                 {\r
779                         static float counter1 = 0;\r
780                         counter1 -= dtime;\r
781                         if(counter1 < 0.0)\r
782                         {\r
783                                 counter1 = 0.1*Rand(1, 40);\r
784                                 keydown[irr::KEY_KEY_A] = !keydown[irr::KEY_KEY_A];\r
785                         }\r
786                 }\r
787                 {\r
788                         static float counter1 = 0;\r
789                         counter1 -= dtime;\r
790                         if(counter1 < 0.0)\r
791                         {\r
792                                 counter1 = 0.1*Rand(1, 20);\r
793                                 mousespeed = v2s32(Rand(-20,20), Rand(-15,20));\r
794                         }\r
795                 }\r
796                 {\r
797                         static float counter1 = 0;\r
798                         counter1 -= dtime;\r
799                         if(counter1 < 0.0)\r
800                         {\r
801                                 counter1 = 0.1*Rand(1, 30);\r
802                                 leftclicked = true;\r
803                         }\r
804                 }\r
805                 {\r
806                         static float counter1 = 0;\r
807                         counter1 -= dtime;\r
808                         if(counter1 < 0.0)\r
809                         {\r
810                                 counter1 = 0.1*Rand(1, 20);\r
811                                 rightclicked = true;\r
812                         }\r
813                 }\r
814                 mousepos += mousespeed;\r
815         }\r
816 \r
817         s32 Rand(s32 min, s32 max)\r
818         {\r
819                 return (myrand()%(max-min+1))+min;\r
820         }\r
821 private:\r
822         bool keydown[KEY_KEY_CODES_COUNT];\r
823         v2s32 mousepos;\r
824         v2s32 mousespeed;\r
825         bool leftclicked;\r
826         bool rightclicked;\r
827 };\r
828 \r
829 void updateViewingRange(f32 frametime_in, Client *client)\r
830 {\r
831         if(draw_control.range_all == true)\r
832                 return;\r
833         \r
834         static f32 added_frametime = 0;\r
835         static s16 added_frames = 0;\r
836 \r
837         added_frametime += frametime_in;\r
838         added_frames += 1;\r
839 \r
840         // Actually this counter kind of sucks because frametime is busytime\r
841         static f32 counter = 0;\r
842         counter -= frametime_in;\r
843         if(counter > 0)\r
844                 return;\r
845         //counter = 0.1;\r
846         counter = 0.2;\r
847 \r
848         /*dstream<<__FUNCTION_NAME\r
849                         <<": Collected "<<added_frames<<" frames, total of "\r
850                         <<added_frametime<<"s."<<std::endl;*/\r
851         \r
852         /*dstream<<"draw_control.blocks_drawn="\r
853                         <<draw_control.blocks_drawn\r
854                         <<", draw_control.blocks_would_have_drawn="\r
855                         <<draw_control.blocks_would_have_drawn\r
856                         <<std::endl;*/\r
857         \r
858         float range_min = g_settings.getS16("viewing_range_nodes_min");\r
859         float range_max = g_settings.getS16("viewing_range_nodes_max");\r
860         \r
861         draw_control.wanted_min_range = range_min;\r
862         draw_control.wanted_max_blocks = (1.2*draw_control.blocks_drawn)+1;\r
863         \r
864         float block_draw_ratio = 1.0;\r
865         if(draw_control.blocks_would_have_drawn != 0)\r
866         {\r
867                 block_draw_ratio = (float)draw_control.blocks_drawn\r
868                         / (float)draw_control.blocks_would_have_drawn;\r
869         }\r
870 \r
871         // Calculate the average frametime in the case that all wanted\r
872         // blocks had been drawn\r
873         f32 frametime = added_frametime / added_frames / block_draw_ratio;\r
874         \r
875         added_frametime = 0.0;\r
876         added_frames = 0;\r
877         \r
878         float wanted_fps = g_settings.getFloat("wanted_fps");\r
879         float wanted_frametime = 1.0 / wanted_fps;\r
880         \r
881         f32 wanted_frametime_change = wanted_frametime - frametime;\r
882         //dstream<<"wanted_frametime_change="<<wanted_frametime_change<<std::endl;\r
883         \r
884         // If needed frametime change is very small, just return\r
885         if(fabs(wanted_frametime_change) < wanted_frametime*0.2)\r
886         {\r
887                 //dstream<<"ignoring small wanted_frametime_change"<<std::endl;\r
888                 return;\r
889         }\r
890 \r
891         float range = draw_control.wanted_range;\r
892         float new_range = range;\r
893 \r
894         static s16 range_old = 0;\r
895         static f32 frametime_old = 0;\r
896         \r
897         float d_range = range - range_old;\r
898         f32 d_frametime = frametime - frametime_old;\r
899         // A sane default of 30ms per 50 nodes of range\r
900         static f32 time_per_range = 30. / 50;\r
901         if(d_range != 0)\r
902         {\r
903                 time_per_range = d_frametime / d_range;\r
904         }\r
905         \r
906         // The minimum allowed calculated frametime-range derivative:\r
907         // Practically this sets the maximum speed of changing the range.\r
908         // The lower this value, the higher the maximum changing speed.\r
909         // A low value here results in wobbly range (0.001)\r
910         // A high value here results in slow changing range (0.0025)\r
911         // SUGG: This could be dynamically adjusted so that when\r
912         //       the camera is turning, this is lower\r
913         //float min_time_per_range = 0.0015;\r
914         float min_time_per_range = 0.0010;\r
915         //float min_time_per_range = 0.05 / range;\r
916         if(time_per_range < min_time_per_range)\r
917         {\r
918                 time_per_range = min_time_per_range;\r
919                 //dstream<<"time_per_range="<<time_per_range<<" (min)"<<std::endl;\r
920         }\r
921         else\r
922         {\r
923                 //dstream<<"time_per_range="<<time_per_range<<std::endl;\r
924         }\r
925 \r
926         f32 wanted_range_change = wanted_frametime_change / time_per_range;\r
927         // Dampen the change a bit to kill oscillations\r
928         //wanted_range_change *= 0.9;\r
929         //wanted_range_change *= 0.75;\r
930         wanted_range_change *= 0.5;\r
931         //dstream<<"wanted_range_change="<<wanted_range_change<<std::endl;\r
932 \r
933         // If needed range change is very small, just return\r
934         if(fabs(wanted_range_change) < 0.001)\r
935         {\r
936                 //dstream<<"ignoring small wanted_range_change"<<std::endl;\r
937                 return;\r
938         }\r
939 \r
940         new_range += wanted_range_change;\r
941         //dstream<<"new_range="<<new_range/*<<std::endl*/;\r
942         \r
943         //float new_range_unclamped = new_range;\r
944         if(new_range < range_min)\r
945                 new_range = range_min;\r
946         if(new_range > range_max)\r
947                 new_range = range_max;\r
948         \r
949         /*if(new_range != new_range_unclamped)\r
950                 dstream<<", clamped to "<<new_range<<std::endl;\r
951         else\r
952                 dstream<<std::endl;*/\r
953 \r
954         draw_control.wanted_range = new_range;\r
955 \r
956         range_old = new_range;\r
957         frametime_old = frametime;\r
958 }\r
959 \r
960 class GUIQuickInventory : public IEventReceiver\r
961 {\r
962 public:\r
963         GUIQuickInventory(\r
964                         gui::IGUIEnvironment* env,\r
965                         gui::IGUIElement* parent,\r
966                         v2s32 pos,\r
967                         s32 itemcount,\r
968                         Inventory *inventory):\r
969                 m_itemcount(itemcount),\r
970                 m_inventory(inventory)\r
971         {\r
972                 core::rect<s32> imgsize(0,0,48,48);\r
973                 core::rect<s32> textsize(0,0,48,16);\r
974                 v2s32 spacing(0, 64);\r
975                 for(s32 i=0; i<m_itemcount; i++)\r
976                 {\r
977                         m_images.push_back(env->addImage(\r
978                                 imgsize + pos + spacing*i\r
979                         ));\r
980                         m_images[i]->setScaleImage(true);\r
981                         m_texts.push_back(env->addStaticText(\r
982                                 L"",\r
983                                 textsize + pos + spacing*i,\r
984                                 false, false\r
985                         ));\r
986                         m_texts[i]->setBackgroundColor(\r
987                                         video::SColor(128,0,0,0));\r
988                         m_texts[i]->setTextAlignment(\r
989                                         gui::EGUIA_CENTER,\r
990                                         gui::EGUIA_UPPERLEFT);\r
991                 }\r
992         }\r
993 \r
994         virtual bool OnEvent(const SEvent& event)\r
995         {\r
996                 return false;\r
997         }\r
998 \r
999         void setSelection(s32 i)\r
1000         {\r
1001                 m_selection = i;\r
1002         }\r
1003 \r
1004         void update()\r
1005         {\r
1006                 s32 start = 0;\r
1007 \r
1008                 start = m_selection - m_itemcount / 2;\r
1009 \r
1010                 InventoryList *mainlist = m_inventory->getList("main");\r
1011 \r
1012                 for(s32 i=0; i<m_itemcount; i++)\r
1013                 {\r
1014                         s32 j = i + start;\r
1015 \r
1016                         if(j > (s32)mainlist->getSize() - 1)\r
1017                                 j -= mainlist->getSize();\r
1018                         if(j < 0)\r
1019                                 j += mainlist->getSize();\r
1020                         \r
1021                         InventoryItem *item = mainlist->getItem(j);\r
1022                         // Null items\r
1023                         if(item == NULL)\r
1024                         {\r
1025                                 m_images[i]->setImage(NULL);\r
1026 \r
1027                                 wchar_t t[10];\r
1028                                 if(m_selection == j)\r
1029                                         swprintf(t, 10, L"<-");\r
1030                                 else\r
1031                                         swprintf(t, 10, L"");\r
1032                                 m_texts[i]->setText(t);\r
1033 \r
1034                                 // The next ifs will segfault with a NULL pointer\r
1035                                 continue;\r
1036                         }\r
1037                         \r
1038                         \r
1039                         m_images[i]->setImage(item->getImage());\r
1040                         \r
1041                         wchar_t t[10];\r
1042                         if(m_selection == j)\r
1043                                 swprintf(t, 10, SWPRINTF_CHARSTRING L" <-", item->getText().c_str());\r
1044                         else\r
1045                                 swprintf(t, 10, SWPRINTF_CHARSTRING, item->getText().c_str());\r
1046                         m_texts[i]->setText(t);\r
1047                 }\r
1048         }\r
1049 \r
1050 private:\r
1051         s32 m_itemcount;\r
1052         core::array<gui::IGUIStaticText*> m_texts;\r
1053         core::array<gui::IGUIImage*> m_images;\r
1054         Inventory *m_inventory;\r
1055         s32 m_selection;\r
1056 };\r
1057 \r
1058 // Chat data\r
1059 struct ChatLine\r
1060 {\r
1061         ChatLine():\r
1062                 age(0.0)\r
1063         {\r
1064         }\r
1065         ChatLine(const std::wstring &a_text):\r
1066                 age(0.0),\r
1067                 text(a_text)\r
1068         {\r
1069         }\r
1070         float age;\r
1071         std::wstring text;\r
1072 };\r
1073 \r
1074 int main(int argc, char *argv[])\r
1075 {\r
1076         /*\r
1077                 Low-level initialization\r
1078         */\r
1079 \r
1080         bool disable_stderr = false;\r
1081 #ifdef _WIN32\r
1082         disable_stderr = true;\r
1083 #endif\r
1084 \r
1085         // Initialize debug streams\r
1086         debugstreams_init(disable_stderr, DEBUGFILE);\r
1087         // Initialize debug stacks\r
1088         debug_stacks_init();\r
1089 \r
1090         DSTACK(__FUNCTION_NAME);\r
1091         \r
1092         initializeMaterialProperties();\r
1093 \r
1094         BEGIN_DEBUG_EXCEPTION_HANDLER\r
1095 \r
1096         try\r
1097         {\r
1098         \r
1099         /*\r
1100                 Parse command line\r
1101         */\r
1102         \r
1103         // List all allowed options\r
1104         core::map<std::string, ValueSpec> allowed_options;\r
1105         allowed_options.insert("help", ValueSpec(VALUETYPE_FLAG));\r
1106         allowed_options.insert("server", ValueSpec(VALUETYPE_FLAG,\r
1107                         "Run server directly"));\r
1108         allowed_options.insert("config", ValueSpec(VALUETYPE_STRING,\r
1109                         "Load configuration from specified file"));\r
1110         allowed_options.insert("port", ValueSpec(VALUETYPE_STRING));\r
1111         allowed_options.insert("address", ValueSpec(VALUETYPE_STRING));\r
1112         allowed_options.insert("random-input", ValueSpec(VALUETYPE_FLAG));\r
1113         allowed_options.insert("disable-unittests", ValueSpec(VALUETYPE_FLAG));\r
1114         allowed_options.insert("enable-unittests", ValueSpec(VALUETYPE_FLAG));\r
1115 \r
1116         Settings cmd_args;\r
1117         \r
1118         bool ret = cmd_args.parseCommandLine(argc, argv, allowed_options);\r
1119 \r
1120         if(ret == false || cmd_args.getFlag("help"))\r
1121         {\r
1122                 dstream<<"Allowed options:"<<std::endl;\r
1123                 for(core::map<std::string, ValueSpec>::Iterator\r
1124                                 i = allowed_options.getIterator();\r
1125                                 i.atEnd() == false; i++)\r
1126                 {\r
1127                         dstream<<"  --"<<i.getNode()->getKey();\r
1128                         if(i.getNode()->getValue().type == VALUETYPE_FLAG)\r
1129                         {\r
1130                         }\r
1131                         else\r
1132                         {\r
1133                                 dstream<<" <value>";\r
1134                         }\r
1135                         dstream<<std::endl;\r
1136 \r
1137                         if(i.getNode()->getValue().help != NULL)\r
1138                         {\r
1139                                 dstream<<"      "<<i.getNode()->getValue().help\r
1140                                                 <<std::endl;\r
1141                         }\r
1142                 }\r
1143 \r
1144                 return cmd_args.getFlag("help") ? 0 : 1;\r
1145         }\r
1146 \r
1147 \r
1148         /*\r
1149                 Basic initialization\r
1150         */\r
1151 \r
1152         // Initialize default settings\r
1153         set_default_settings();\r
1154         \r
1155         // Print startup message\r
1156         dstream<<DTIME<<"minetest-c55"\r
1157                         " with SER_FMT_VER_HIGHEST="<<(int)SER_FMT_VER_HIGHEST\r
1158                         <<", ENABLE_TESTS="<<ENABLE_TESTS\r
1159                         <<std::endl;\r
1160         \r
1161         // Set locale. This is for forcing '.' as the decimal point.\r
1162         std::locale::global(std::locale("C"));\r
1163         // This enables printing all characters in bitmap font\r
1164         setlocale(LC_CTYPE, "en_US");\r
1165 \r
1166         // Initialize sockets\r
1167         sockets_init();\r
1168         atexit(sockets_cleanup);\r
1169         \r
1170         /*\r
1171                 Initialization\r
1172         */\r
1173 \r
1174         /*\r
1175                 Read config file\r
1176         */\r
1177         \r
1178         // Path of configuration file in use\r
1179         std::string configpath = "";\r
1180         \r
1181         if(cmd_args.exists("config"))\r
1182         {\r
1183                 bool r = g_settings.readConfigFile(cmd_args.get("config").c_str());\r
1184                 if(r == false)\r
1185                 {\r
1186                         dstream<<"Could not read configuration from \""\r
1187                                         <<cmd_args.get("config")<<"\""<<std::endl;\r
1188                         return 1;\r
1189                 }\r
1190                 configpath = cmd_args.get("config");\r
1191         }\r
1192         else\r
1193         {\r
1194                 const char *filenames[2] =\r
1195                 {\r
1196                         "../minetest.conf",\r
1197                         "../../minetest.conf"\r
1198                 };\r
1199 \r
1200                 for(u32 i=0; i<2; i++)\r
1201                 {\r
1202                         bool r = g_settings.readConfigFile(filenames[i]);\r
1203                         if(r)\r
1204                         {\r
1205                                 configpath = filenames[i];\r
1206                                 break;\r
1207                         }\r
1208                 }\r
1209         }\r
1210 \r
1211         // Initialize random seed\r
1212         srand(time(0));\r
1213         mysrand(time(0));\r
1214 \r
1215         /*\r
1216                 Run unit tests\r
1217         */\r
1218         if((ENABLE_TESTS && cmd_args.getFlag("disable-unittests") == false)\r
1219                         || cmd_args.getFlag("enable-unittests") == true)\r
1220         {\r
1221                 run_tests();\r
1222         }\r
1223         \r
1224         // Read map parameters from settings\r
1225 \r
1226         HMParams hm_params;\r
1227         hm_params.blocksize = g_settings.getU16("heightmap_blocksize");\r
1228         hm_params.randmax = g_settings.get("height_randmax");\r
1229         hm_params.randfactor = g_settings.get("height_randfactor");\r
1230         hm_params.base = g_settings.get("height_base");\r
1231 \r
1232         MapParams map_params;\r
1233         map_params.plants_amount = g_settings.getFloat("plants_amount");\r
1234         map_params.ravines_amount = g_settings.getFloat("ravines_amount");\r
1235 \r
1236         /*\r
1237                 Ask some stuff\r
1238         */\r
1239 \r
1240         std::cout<<std::endl<<std::endl;\r
1241         \r
1242         std::cout\r
1243         <<"        .__               __                   __   "<<std::endl\r
1244         <<"  _____ |__| ____   _____/  |_  ____   _______/  |_ "<<std::endl\r
1245         <<" /     \\|  |/    \\_/ __ \\   __\\/ __ \\ /  ___/\\   __\\"<<std::endl\r
1246         <<"|  Y Y  \\  |   |  \\  ___/|  | \\  ___/ \\___ \\  |  |  "<<std::endl\r
1247         <<"|__|_|  /__|___|  /\\___  >__|  \\___  >____  > |__|  "<<std::endl\r
1248         <<"      \\/        \\/     \\/          \\/     \\/        "<<std::endl\r
1249         <<std::endl;\r
1250 \r
1251         std::cout<<std::endl;\r
1252         //char templine[100];\r
1253         \r
1254         // Port?\r
1255         u16 port = 30000;\r
1256         if(cmd_args.exists("port"))\r
1257         {\r
1258                 port = cmd_args.getU16("port");\r
1259         }\r
1260         else\r
1261         {\r
1262                 port = g_settings.getU16Ask("port", "Port", 30000);\r
1263                 std::cout<<"-> "<<port<<std::endl;\r
1264         }\r
1265         \r
1266         if(cmd_args.getFlag("server"))\r
1267         {\r
1268                 DSTACK("Dedicated server branch");\r
1269                 \r
1270                 std::cout<<std::endl;\r
1271                 std::cout<<"========================"<<std::endl;\r
1272                 std::cout<<"Running dedicated server"<<std::endl;\r
1273                 std::cout<<"========================"<<std::endl;\r
1274                 std::cout<<std::endl;\r
1275 \r
1276                 Server server("../map", hm_params, map_params);\r
1277                 server.start(port);\r
1278         \r
1279                 for(;;)\r
1280                 {\r
1281                         // This is kind of a hack but can be done like this\r
1282                         // because server.step() is very light\r
1283                         sleep_ms(30);\r
1284                         server.step(0.030);\r
1285 \r
1286                         static int counter = 0;\r
1287                         counter--;\r
1288                         if(counter <= 0)\r
1289                         {\r
1290                                 counter = 10;\r
1291 \r
1292                                 core::list<PlayerInfo> list = server.getPlayerInfo();\r
1293                                 core::list<PlayerInfo>::Iterator i;\r
1294                                 static u32 sum_old = 0;\r
1295                                 u32 sum = PIChecksum(list);\r
1296                                 if(sum != sum_old)\r
1297                                 {\r
1298                                         std::cout<<DTIME<<"Player info:"<<std::endl;\r
1299                                         for(i=list.begin(); i!=list.end(); i++)\r
1300                                         {\r
1301                                                 i->PrintLine(&std::cout);\r
1302                                         }\r
1303                                 }\r
1304                                 sum_old = sum;\r
1305                         }\r
1306                 }\r
1307 \r
1308                 return 0;\r
1309         }\r
1310 \r
1311         bool hosting = false;\r
1312         char connect_name[100] = "";\r
1313 \r
1314         if(cmd_args.exists("address"))\r
1315         {\r
1316                 snprintf(connect_name, 100, "%s", cmd_args.get("address").c_str());\r
1317         }\r
1318         else if(is_yes(g_settings.get("host_game")) == false)\r
1319         {\r
1320                 if(g_settings.get("address") != "")\r
1321                 {\r
1322                         std::cout<<g_settings.get("address")<<std::endl;\r
1323                         snprintf(connect_name, 100, "%s", g_settings.get("address").c_str());\r
1324                 }\r
1325                 else\r
1326                 {\r
1327                         std::cout<<"Address to connect to [empty = host a game]: ";\r
1328                         std::cin.getline(connect_name, 100);\r
1329                 }\r
1330         }\r
1331         \r
1332         if(connect_name[0] == 0){\r
1333                 snprintf(connect_name, 100, "127.0.0.1");\r
1334                 hosting = true;\r
1335         }\r
1336         \r
1337         if(hosting)\r
1338                 std::cout<<"> Hosting game"<<std::endl;\r
1339         else\r
1340                 std::cout<<"> Connecting to "<<connect_name<<std::endl;\r
1341         \r
1342         char playername[PLAYERNAME_SIZE] = "";\r
1343         if(g_settings.get("name") != "")\r
1344         {\r
1345                 snprintf(playername, PLAYERNAME_SIZE, "%s", g_settings.get("name").c_str());\r
1346         }\r
1347         else\r
1348         {\r
1349                 std::cout<<"Name of player: ";\r
1350                 std::cin.getline(playername, PLAYERNAME_SIZE);\r
1351         }\r
1352         std::cout<<"-> \""<<playername<<"\""<<std::endl;\r
1353 \r
1354         /*\r
1355                 Resolution selection\r
1356         */\r
1357         \r
1358         bool fullscreen = false;\r
1359         u16 screenW = atoi(g_settings.get("screenW").c_str());\r
1360         u16 screenH = atoi(g_settings.get("screenH").c_str());\r
1361 \r
1362         //\r
1363 \r
1364         MyEventReceiver receiver;\r
1365 \r
1366         video::E_DRIVER_TYPE driverType;\r
1367 \r
1368 #ifdef _WIN32\r
1369         //driverType = video::EDT_DIRECT3D9; // Doesn't seem to work\r
1370         driverType = video::EDT_OPENGL;\r
1371 #else\r
1372         driverType = video::EDT_OPENGL;\r
1373 #endif\r
1374 \r
1375         // create device and exit if creation failed\r
1376 \r
1377         IrrlichtDevice *device;\r
1378         device = createDevice(driverType,\r
1379                         core::dimension2d<u32>(screenW, screenH),\r
1380                         16, fullscreen, false, false, &receiver);\r
1381 \r
1382         if (device == 0)\r
1383                 return 1; // could not create selected driver.\r
1384         \r
1385         g_device = device;\r
1386         g_irrlicht = new IrrlichtWrapper(device);\r
1387 \r
1388         //g_device = device;\r
1389         \r
1390         device->setResizable(true);\r
1391 \r
1392         bool random_input = g_settings.getBool("random_input")\r
1393                         || cmd_args.getFlag("random-input");\r
1394         if(random_input)\r
1395                 g_input = new RandomInputHandler();\r
1396         else\r
1397                 g_input = new RealInputHandler(device, &receiver);\r
1398         \r
1399         /*\r
1400                 Continue initialization\r
1401         */\r
1402 \r
1403         video::IVideoDriver* driver = device->getVideoDriver();\r
1404 \r
1405         /*\r
1406                 This changes the minimum allowed number of vertices in a VBO\r
1407         */\r
1408         //driver->setMinHardwareBufferVertexCount(50);\r
1409 \r
1410         scene::ISceneManager* smgr = device->getSceneManager();\r
1411         \r
1412         guienv = device->getGUIEnvironment();\r
1413         gui::IGUISkin* skin = guienv->getSkin();\r
1414         gui::IGUIFont* font = guienv->getFont("../data/fontlucida.png");\r
1415         if(font)\r
1416                 skin->setFont(font);\r
1417         \r
1418         u32 text_height = font->getDimension(L"Hello, world!").Height;\r
1419         dstream<<"text_height="<<text_height<<std::endl;\r
1420 \r
1421         //skin->setColor(gui::EGDC_BUTTON_TEXT, video::SColor(255,0,0,0));\r
1422         skin->setColor(gui::EGDC_BUTTON_TEXT, video::SColor(255,255,255,255));\r
1423         //skin->setColor(gui::EGDC_3D_HIGH_LIGHT, video::SColor(0,0,0,0));\r
1424         //skin->setColor(gui::EGDC_3D_SHADOW, video::SColor(0,0,0,0));\r
1425         skin->setColor(gui::EGDC_3D_HIGH_LIGHT, video::SColor(255,0,0,0));\r
1426         skin->setColor(gui::EGDC_3D_SHADOW, video::SColor(255,0,0,0));\r
1427         \r
1428         const wchar_t *text = L"Loading and connecting...";\r
1429         core::vector2d<s32> center(screenW/2, screenH/2);\r
1430         core::vector2d<s32> textsize(300, text_height);\r
1431         core::rect<s32> textrect(center - textsize/2, center + textsize/2);\r
1432 \r
1433         gui::IGUIStaticText *gui_loadingtext = guienv->addStaticText(\r
1434                         text, textrect, false, false);\r
1435         gui_loadingtext->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);\r
1436 \r
1437         driver->beginScene(true, true, video::SColor(255,0,0,0));\r
1438         guienv->drawAll();\r
1439         driver->endScene();\r
1440 \r
1441         /*\r
1442                 Preload some textures\r
1443         */\r
1444 \r
1445         tile_materials_preload(g_irrlicht);\r
1446 \r
1447         /*\r
1448                 Make a scope here for the client so that it gets removed\r
1449                 before the irrlicht device\r
1450         */\r
1451         {\r
1452 \r
1453         std::cout<<DTIME<<"Creating server and client"<<std::endl;\r
1454         \r
1455         /*\r
1456                 Create server\r
1457         */\r
1458         SharedPtr<Server> server;\r
1459         if(hosting){\r
1460                 server = new Server("../map", hm_params, map_params);\r
1461                 server->start(port);\r
1462         }\r
1463         \r
1464         /*\r
1465                 Create client\r
1466         */\r
1467 \r
1468         Client client(device, playername, draw_control);\r
1469                         \r
1470         g_client = &client;\r
1471         \r
1472         Address connect_address(0,0,0,0, port);\r
1473         try{\r
1474                 connect_address.Resolve(connect_name);\r
1475         }\r
1476         catch(ResolveError &e)\r
1477         {\r
1478                 std::cout<<DTIME<<"Couldn't resolve address"<<std::endl;\r
1479                 return 0;\r
1480         }\r
1481         \r
1482         std::cout<<DTIME<<"Connecting to server..."<<std::endl;\r
1483         client.connect(connect_address);\r
1484         \r
1485         try{\r
1486                 while(client.connectedAndInitialized() == false)\r
1487                 {\r
1488                         client.step(0.1);\r
1489                         if(server != NULL){\r
1490                                 server->step(0.1);\r
1491                         }\r
1492                         sleep_ms(100);\r
1493                 }\r
1494         }\r
1495         catch(con::PeerNotFoundException &e)\r
1496         {\r
1497                 std::cout<<DTIME<<"Timed out."<<std::endl;\r
1498                 return 0;\r
1499         }\r
1500 \r
1501         /*\r
1502                 Create skybox\r
1503         */\r
1504         /*scene::ISceneNode* skybox;\r
1505         skybox = smgr->addSkyBoxSceneNode(\r
1506                 driver->getTexture("../data/skybox2.png"),\r
1507                 driver->getTexture("../data/skybox3.png"),\r
1508                 driver->getTexture("../data/skybox1.png"),\r
1509                 driver->getTexture("../data/skybox1.png"),\r
1510                 driver->getTexture("../data/skybox1.png"),\r
1511                 driver->getTexture("../data/skybox1.png"));*/\r
1512         \r
1513         /*\r
1514                 Create the camera node\r
1515         */\r
1516 \r
1517         scene::ICameraSceneNode* camera = smgr->addCameraSceneNode(\r
1518                 0, // Camera parent\r
1519                 v3f(BS*100, BS*2, BS*100), // Look from\r
1520                 v3f(BS*100+1, BS*2, BS*100), // Look to\r
1521                 -1 // Camera ID\r
1522         );\r
1523 \r
1524         if(camera == NULL)\r
1525                 return 1;\r
1526         \r
1527         video::SColor skycolor = video::SColor(255,90,140,200);\r
1528 \r
1529         camera->setFOV(FOV_ANGLE);\r
1530 \r
1531         // Just so big a value that everything rendered is visible\r
1532         camera->setFarValue(100000*BS);\r
1533 \r
1534         f32 camera_yaw = 0; // "right/left"\r
1535         f32 camera_pitch = 0; // "up/down"\r
1536 \r
1537         /*\r
1538                 Move into game\r
1539         */\r
1540         \r
1541         gui_loadingtext->remove();\r
1542 \r
1543         /*\r
1544                 Add some gui stuff\r
1545         */\r
1546 \r
1547         GUIQuickInventory *quick_inventory = new GUIQuickInventory\r
1548                         (guienv, NULL, v2s32(10, 70), 5, &local_inventory);\r
1549         \r
1550         /*\r
1551                 We need some kind of a root node to be able to add\r
1552                 custom elements directly on the screen.\r
1553                 Otherwise they won't be automatically drawn.\r
1554         */\r
1555         guiroot = guienv->addStaticText(L"",\r
1556                         core::rect<s32>(0, 0, 10000, 10000));\r
1557         \r
1558         // Test the text input system\r
1559         /*(new GUITextInputMenu(guienv, guiroot, -1, &g_active_menu_count,\r
1560                         NULL))->drop();*/\r
1561         /*GUIMessageMenu *menu =\r
1562                         new GUIMessageMenu(guienv, guiroot, -1, \r
1563                                 &g_active_menu_count,\r
1564                                 L"Asd");\r
1565         menu->drop();*/\r
1566         \r
1567         // Launch pause menu\r
1568         (new GUIPauseMenu(guienv, guiroot, -1, g_device,\r
1569                         &g_active_menu_count))->drop();\r
1570 \r
1571         // First line of debug text\r
1572         gui::IGUIStaticText *guitext = guienv->addStaticText(\r
1573                         L"Minetest-c55",\r
1574                         core::rect<s32>(5, 5, 795, 5+textsize.Y),\r
1575                         false, false);\r
1576         // Second line of debug text\r
1577         gui::IGUIStaticText *guitext2 = guienv->addStaticText(\r
1578                         L"",\r
1579                         core::rect<s32>(5, 5+(textsize.Y+5)*1, 795, (5+textsize.Y)*2),\r
1580                         false, false);\r
1581         \r
1582         // At the middle of the screen\r
1583         // Object infos are shown in this\r
1584         gui::IGUIStaticText *guitext_info = guienv->addStaticText(\r
1585                         L"test",\r
1586                         core::rect<s32>(100, 70, 100+400, 70+(textsize.Y+5)),\r
1587                         false, false);\r
1588         \r
1589         // Chat text\r
1590         gui::IGUIStaticText *chat_guitext = guienv->addStaticText(\r
1591                         L"Chat here\nOther line\nOther line\nOther line\nOther line",\r
1592                         core::rect<s32>(70, 60, 795, 150),\r
1593                         false, true);\r
1594         chat_guitext->setBackgroundColor(video::SColor(96,0,0,0));\r
1595         core::list<ChatLine> chat_lines;\r
1596         \r
1597         /*\r
1598                 Some statistics are collected in these\r
1599         */\r
1600         u32 drawtime = 0;\r
1601         u32 beginscenetime = 0;\r
1602         u32 scenetime = 0;\r
1603         u32 endscenetime = 0;\r
1604         \r
1605         // A test\r
1606         //throw con::PeerNotFoundException("lol");\r
1607 \r
1608         /*\r
1609                 Main loop\r
1610         */\r
1611 \r
1612         bool first_loop_after_window_activation = true;\r
1613 \r
1614         // Time is in milliseconds\r
1615         // NOTE: getRealTime() without run()s causes strange problems in wine\r
1616         // NOTE: Have to call run() between calls of this to update the timer\r
1617         u32 lasttime = device->getTimer()->getTime();\r
1618 \r
1619         while(device->run())\r
1620         {\r
1621                 /*\r
1622                         Run global IrrlichtWrapper's main thread processing stuff\r
1623                 */\r
1624                 g_irrlicht->Run();\r
1625 \r
1626                 /*\r
1627                         Random calculations\r
1628                 */\r
1629                 v2u32 screensize = driver->getScreenSize();\r
1630                 core::vector2d<s32> displaycenter(screensize.X/2,screensize.Y/2);\r
1631                 \r
1632                 // Hilight boxes collected during the loop and displayed\r
1633                 core::list< core::aabbox3d<f32> > hilightboxes;\r
1634                 \r
1635                 // Info text\r
1636                 std::wstring infotext;\r
1637 \r
1638                 //TimeTaker //timer1("//timer1");\r
1639                 \r
1640                 // Time of frame without fps limit\r
1641                 float busytime;\r
1642                 u32 busytime_u32;\r
1643                 {\r
1644                         // not using getRealTime is necessary for wine\r
1645                         u32 time = device->getTimer()->getTime();\r
1646                         if(time > lasttime)\r
1647                                 busytime_u32 = time - lasttime;\r
1648                         else\r
1649                                 busytime_u32 = 0;\r
1650                         busytime = busytime_u32 / 1000.0;\r
1651                 }\r
1652 \r
1653                 //std::cout<<"busytime_u32="<<busytime_u32<<std::endl;\r
1654         \r
1655                 // Absolutelu necessary for wine!\r
1656                 device->run();\r
1657 \r
1658                 /*\r
1659                         Viewing range\r
1660                 */\r
1661                 \r
1662                 updateViewingRange(busytime, &client);\r
1663                 \r
1664                 /*\r
1665                         FPS limiter\r
1666                 */\r
1667 \r
1668                 {\r
1669                         float fps_max = g_settings.getFloat("fps_max");\r
1670                         u32 frametime_min = 1000./fps_max;\r
1671                         \r
1672                         if(busytime_u32 < frametime_min)\r
1673                         {\r
1674                                 u32 sleeptime = frametime_min - busytime_u32;\r
1675                                 device->sleep(sleeptime);\r
1676                         }\r
1677                 }\r
1678 \r
1679                 // Absolutelu necessary for wine!\r
1680                 device->run();\r
1681 \r
1682                 /*\r
1683                         Time difference calculation\r
1684                 */\r
1685                 f32 dtime; // in seconds\r
1686                 \r
1687                 u32 time = device->getTimer()->getTime();\r
1688                 if(time > lasttime)\r
1689                         dtime = (time - lasttime) / 1000.0;\r
1690                 else\r
1691                         dtime = 0;\r
1692                 lasttime = time;\r
1693 \r
1694                 /*\r
1695                         Time average and jitter calculation\r
1696                 */\r
1697 \r
1698                 static f32 dtime_avg1 = 0.0;\r
1699                 dtime_avg1 = dtime_avg1 * 0.98 + dtime * 0.02;\r
1700                 f32 dtime_jitter1 = dtime - dtime_avg1;\r
1701 \r
1702                 static f32 dtime_jitter1_max_sample = 0.0;\r
1703                 static f32 dtime_jitter1_max_fraction = 0.0;\r
1704                 {\r
1705                         static f32 jitter1_max = 0.0;\r
1706                         static f32 counter = 0.0;\r
1707                         if(dtime_jitter1 > jitter1_max)\r
1708                                 jitter1_max = dtime_jitter1;\r
1709                         counter += dtime;\r
1710                         if(counter > 0.0)\r
1711                         {\r
1712                                 counter -= 3.0;\r
1713                                 dtime_jitter1_max_sample = jitter1_max;\r
1714                                 dtime_jitter1_max_fraction\r
1715                                                 = dtime_jitter1_max_sample / (dtime_avg1+0.001);\r
1716                                 jitter1_max = 0.0;\r
1717                                 \r
1718                                 /*\r
1719                                         Control freetime ratio\r
1720                                 */\r
1721                                 /*if(dtime_jitter1_max_fraction > DTIME_JITTER_MAX_FRACTION)\r
1722                                 {\r
1723                                         if(g_freetime_ratio < FREETIME_RATIO_MAX)\r
1724                                                 g_freetime_ratio += 0.01;\r
1725                                 }\r
1726                                 else\r
1727                                 {\r
1728                                         if(g_freetime_ratio > FREETIME_RATIO_MIN)\r
1729                                                 g_freetime_ratio -= 0.01;\r
1730                                 }*/\r
1731                         }\r
1732                 }\r
1733                 \r
1734                 /*\r
1735                         Busytime average and jitter calculation\r
1736                 */\r
1737 \r
1738                 static f32 busytime_avg1 = 0.0;\r
1739                 busytime_avg1 = busytime_avg1 * 0.98 + busytime * 0.02;\r
1740                 f32 busytime_jitter1 = busytime - busytime_avg1;\r
1741                 \r
1742                 static f32 busytime_jitter1_max_sample = 0.0;\r
1743                 static f32 busytime_jitter1_min_sample = 0.0;\r
1744                 {\r
1745                         static f32 jitter1_max = 0.0;\r
1746                         static f32 jitter1_min = 0.0;\r
1747                         static f32 counter = 0.0;\r
1748                         if(busytime_jitter1 > jitter1_max)\r
1749                                 jitter1_max = busytime_jitter1;\r
1750                         if(busytime_jitter1 < jitter1_min)\r
1751                                 jitter1_min = busytime_jitter1;\r
1752                         counter += dtime;\r
1753                         if(counter > 0.0){\r
1754                                 counter -= 3.0;\r
1755                                 busytime_jitter1_max_sample = jitter1_max;\r
1756                                 busytime_jitter1_min_sample = jitter1_min;\r
1757                                 jitter1_max = 0.0;\r
1758                                 jitter1_min = 0.0;\r
1759                         }\r
1760                 }\r
1761                 \r
1762                 /*\r
1763                         Debug info for client\r
1764                 */\r
1765                 {\r
1766                         static float counter = 0.0;\r
1767                         counter -= dtime;\r
1768                         if(counter < 0)\r
1769                         {\r
1770                                 counter = 30.0;\r
1771                                 client.printDebugInfo(std::cout);\r
1772                         }\r
1773                 }\r
1774 \r
1775                 /*\r
1776                         Input handler step()\r
1777                 */\r
1778                 g_input->step(dtime);\r
1779 \r
1780                 /*\r
1781                         Player speed control\r
1782                 */\r
1783                 \r
1784                 {\r
1785                         /*bool a_up,\r
1786                         bool a_down,\r
1787                         bool a_left,\r
1788                         bool a_right,\r
1789                         bool a_jump,\r
1790                         bool a_superspeed,\r
1791                         float a_pitch,\r
1792                         float a_yaw*/\r
1793                         PlayerControl control(\r
1794                                 g_input->isKeyDown(irr::KEY_KEY_W),\r
1795                                 g_input->isKeyDown(irr::KEY_KEY_S),\r
1796                                 g_input->isKeyDown(irr::KEY_KEY_A),\r
1797                                 g_input->isKeyDown(irr::KEY_KEY_D),\r
1798                                 g_input->isKeyDown(irr::KEY_SPACE),\r
1799                                 g_input->isKeyDown(irr::KEY_KEY_2),\r
1800                                 camera_pitch,\r
1801                                 camera_yaw\r
1802                         );\r
1803                         client.setPlayerControl(control);\r
1804                 }\r
1805 \r
1806                 /*\r
1807                         Process environment\r
1808                 */\r
1809                 \r
1810                 {\r
1811                         //TimeTaker timer("client.step(dtime)");\r
1812                         client.step(dtime);\r
1813                         //client.step(dtime_avg1);\r
1814                 }\r
1815 \r
1816                 if(server != NULL)\r
1817                 {\r
1818                         //TimeTaker timer("server->step(dtime)");\r
1819                         server->step(dtime);\r
1820                 }\r
1821 \r
1822                 v3f player_position = client.getPlayerPosition();\r
1823                 \r
1824                 //TimeTaker //timer2("//timer2");\r
1825 \r
1826                 /*\r
1827                         Mouse and camera control\r
1828                 */\r
1829                 \r
1830                 if((device->isWindowActive() && noMenuActive()) || random_input)\r
1831                 {\r
1832                         if(!random_input)\r
1833                                 device->getCursorControl()->setVisible(false);\r
1834 \r
1835                         if(first_loop_after_window_activation){\r
1836                                 //std::cout<<"window active, first loop"<<std::endl;\r
1837                                 first_loop_after_window_activation = false;\r
1838                         }\r
1839                         else{\r
1840                                 s32 dx = g_input->getMousePos().X - displaycenter.X;\r
1841                                 s32 dy = g_input->getMousePos().Y - displaycenter.Y;\r
1842                                 //std::cout<<"window active, pos difference "<<dx<<","<<dy<<std::endl;\r
1843                                 camera_yaw -= dx*0.2;\r
1844                                 camera_pitch += dy*0.2;\r
1845                                 if(camera_pitch < -89.5) camera_pitch = -89.5;\r
1846                                 if(camera_pitch > 89.5) camera_pitch = 89.5;\r
1847                         }\r
1848                         g_input->setMousePos(displaycenter.X, displaycenter.Y);\r
1849                 }\r
1850                 else{\r
1851                         device->getCursorControl()->setVisible(true);\r
1852 \r
1853                         //std::cout<<"window inactive"<<std::endl;\r
1854                         first_loop_after_window_activation = true;\r
1855                 }\r
1856 \r
1857                 camera_yaw = wrapDegrees(camera_yaw);\r
1858                 camera_pitch = wrapDegrees(camera_pitch);\r
1859                 \r
1860                 v3f camera_direction = v3f(0,0,1);\r
1861                 camera_direction.rotateYZBy(camera_pitch);\r
1862                 camera_direction.rotateXZBy(camera_yaw);\r
1863 \r
1864                 v3f camera_position =\r
1865                                 player_position + v3f(0, BS+BS/2, 0);\r
1866 \r
1867                 camera->setPosition(camera_position);\r
1868                 // *100.0 helps in large map coordinates\r
1869                 camera->setTarget(camera_position + camera_direction * 100.0);\r
1870 \r
1871                 if(FIELD_OF_VIEW_TEST){\r
1872                         //client.m_env.getMap().updateCamera(v3f(0,0,0), v3f(0,0,1));\r
1873                         client.updateCamera(v3f(0,0,0), v3f(0,0,1));\r
1874                 }\r
1875                 else{\r
1876                         //client.m_env.getMap().updateCamera(camera_position, camera_direction);\r
1877                         //TimeTaker timer("client.updateCamera");\r
1878                         client.updateCamera(camera_position, camera_direction);\r
1879                 }\r
1880                 \r
1881                 //timer2.stop();\r
1882                 //TimeTaker //timer3("//timer3");\r
1883 \r
1884                 /*\r
1885                         Calculate what block is the crosshair pointing to\r
1886                 */\r
1887                 \r
1888                 //u32 t1 = device->getTimer()->getRealTime();\r
1889                 \r
1890                 //f32 d = 4; // max. distance\r
1891                 f32 d = 4; // max. distance\r
1892                 core::line3d<f32> shootline(camera_position,\r
1893                                 camera_position + camera_direction * BS * (d+1));\r
1894 \r
1895                 MapBlockObject *selected_object = client.getSelectedObject\r
1896                                 (d*BS, camera_position, shootline);\r
1897 \r
1898                 /*\r
1899                         If it's pointing to a MapBlockObject\r
1900                 */\r
1901 \r
1902                 if(selected_object != NULL)\r
1903                 {\r
1904                         //dstream<<"Client returned selected_object != NULL"<<std::endl;\r
1905 \r
1906                         core::aabbox3d<f32> box_on_map\r
1907                                         = selected_object->getSelectionBoxOnMap();\r
1908 \r
1909                         hilightboxes.push_back(box_on_map);\r
1910 \r
1911                         infotext = narrow_to_wide(selected_object->infoText());\r
1912 \r
1913                         if(g_input->getLeftClicked())\r
1914                         {\r
1915                                 std::cout<<DTIME<<"Left-clicked object"<<std::endl;\r
1916                                 client.clickObject(0, selected_object->getBlock()->getPos(),\r
1917                                                 selected_object->getId(), g_selected_item);\r
1918                         }\r
1919                         else if(g_input->getRightClicked())\r
1920                         {\r
1921                                 std::cout<<DTIME<<"Right-clicked object"<<std::endl;\r
1922                                 /*\r
1923                                         Check if we want to modify the object ourselves\r
1924                                 */\r
1925                                 if(selected_object->getTypeId() == MAPBLOCKOBJECT_TYPE_SIGN)\r
1926                                 {\r
1927                                         dstream<<"Sign object right-clicked"<<std::endl;\r
1928                                         \r
1929                                         if(random_input == false)\r
1930                                         {\r
1931                                                 // Get a new text for it\r
1932 \r
1933                                                 TextDest *dest = new TextDestSign(\r
1934                                                                 selected_object->getBlock()->getPos(),\r
1935                                                                 selected_object->getId(),\r
1936                                                                 &client);\r
1937 \r
1938                                                 SignObject *sign_object = (SignObject*)selected_object;\r
1939 \r
1940                                                 std::wstring wtext =\r
1941                                                                 narrow_to_wide(sign_object->getText());\r
1942 \r
1943                                                 (new GUITextInputMenu(guienv, guiroot, -1,\r
1944                                                                 &g_active_menu_count, dest,\r
1945                                                                 wtext))->drop();\r
1946                                         }\r
1947                                 }\r
1948                                 /*\r
1949                                         Otherwise pass the event to the server as-is\r
1950                                 */\r
1951                                 else\r
1952                                 {\r
1953                                         client.clickObject(1, selected_object->getBlock()->getPos(),\r
1954                                                         selected_object->getId(), g_selected_item);\r
1955                                 }\r
1956                         }\r
1957                 }\r
1958                 else // selected_object == NULL\r
1959                 {\r
1960 \r
1961                 /*\r
1962                         Find out which node we are pointing at\r
1963                 */\r
1964                 \r
1965                 bool nodefound = false;\r
1966                 v3s16 nodepos;\r
1967                 v3s16 neighbourpos;\r
1968                 core::aabbox3d<f32> nodefacebox;\r
1969                 f32 mindistance = BS * 1001;\r
1970                 \r
1971                 v3s16 pos_i = floatToInt(player_position);\r
1972 \r
1973                 /*std::cout<<"pos_i=("<<pos_i.X<<","<<pos_i.Y<<","<<pos_i.Z<<")"\r
1974                                 <<std::endl;*/\r
1975 \r
1976                 s16 a = d;\r
1977                 s16 ystart = pos_i.Y + 0 - (camera_direction.Y<0 ? a : 1);\r
1978                 s16 zstart = pos_i.Z - (camera_direction.Z<0 ? a : 1);\r
1979                 s16 xstart = pos_i.X - (camera_direction.X<0 ? a : 1);\r
1980                 s16 yend = pos_i.Y + 1 + (camera_direction.Y>0 ? a : 1);\r
1981                 s16 zend = pos_i.Z + (camera_direction.Z>0 ? a : 1);\r
1982                 s16 xend = pos_i.X + (camera_direction.X>0 ? a : 1);\r
1983                 \r
1984                 for(s16 y = ystart; y <= yend; y++)\r
1985                 for(s16 z = zstart; z <= zend; z++)\r
1986                 for(s16 x = xstart; x <= xend; x++)\r
1987                 {\r
1988                         MapNode n;\r
1989                         try\r
1990                         {\r
1991                                 n = client.getNode(v3s16(x,y,z));\r
1992                                 if(content_pointable(n.d) == false)\r
1993                                         continue;\r
1994                         }\r
1995                         catch(InvalidPositionException &e)\r
1996                         {\r
1997                                 continue;\r
1998                         }\r
1999 \r
2000                         v3s16 np(x,y,z);\r
2001                         v3f npf = intToFloat(np);\r
2002                         \r
2003                         f32 d = 0.01;\r
2004                         \r
2005                         v3s16 dirs[6] = {\r
2006                                 v3s16(0,0,1), // back\r
2007                                 v3s16(0,1,0), // top\r
2008                                 v3s16(1,0,0), // right\r
2009                                 v3s16(0,0,-1), // front\r
2010                                 v3s16(0,-1,0), // bottom\r
2011                                 v3s16(-1,0,0), // left\r
2012                         };\r
2013                         \r
2014                         /*\r
2015                                 Meta-objects\r
2016                         */\r
2017                         if(n.d == CONTENT_TORCH)\r
2018                         {\r
2019                                 v3s16 dir = unpackDir(n.dir);\r
2020                                 v3f dir_f = v3f(dir.X, dir.Y, dir.Z);\r
2021                                 dir_f *= BS/2 - BS/6 - BS/20;\r
2022                                 v3f cpf = npf + dir_f;\r
2023                                 f32 distance = (cpf - camera_position).getLength();\r
2024 \r
2025                                 core::aabbox3d<f32> box;\r
2026                                 \r
2027                                 // bottom\r
2028                                 if(dir == v3s16(0,-1,0))\r
2029                                 {\r
2030                                         box = core::aabbox3d<f32>(\r
2031                                                 npf - v3f(BS/6, BS/2, BS/6),\r
2032                                                 npf + v3f(BS/6, -BS/2+BS/3*2, BS/6)\r
2033                                         );\r
2034                                 }\r
2035                                 // top\r
2036                                 else if(dir == v3s16(0,1,0))\r
2037                                 {\r
2038                                         box = core::aabbox3d<f32>(\r
2039                                                 npf - v3f(BS/6, -BS/2+BS/3*2, BS/6),\r
2040                                                 npf + v3f(BS/6, BS/2, BS/6)\r
2041                                         );\r
2042                                 }\r
2043                                 // side\r
2044                                 else\r
2045                                 {\r
2046                                         box = core::aabbox3d<f32>(\r
2047                                                 cpf - v3f(BS/6, BS/3, BS/6),\r
2048                                                 cpf + v3f(BS/6, BS/3, BS/6)\r
2049                                         );\r
2050                                 }\r
2051 \r
2052                                 if(distance < mindistance)\r
2053                                 {\r
2054                                         if(box.intersectsWithLine(shootline))\r
2055                                         {\r
2056                                                 nodefound = true;\r
2057                                                 nodepos = np;\r
2058                                                 neighbourpos = np;\r
2059                                                 mindistance = distance;\r
2060                                                 nodefacebox = box;\r
2061                                         }\r
2062                                 }\r
2063                         }\r
2064                         /*\r
2065                                 Regular blocks\r
2066                         */\r
2067                         else\r
2068                         {\r
2069                                 for(u16 i=0; i<6; i++)\r
2070                                 {\r
2071                                         v3f dir_f = v3f(dirs[i].X,\r
2072                                                         dirs[i].Y, dirs[i].Z);\r
2073                                         v3f centerpoint = npf + dir_f * BS/2;\r
2074                                         f32 distance =\r
2075                                                         (centerpoint - camera_position).getLength();\r
2076                                         \r
2077                                         if(distance < mindistance)\r
2078                                         {\r
2079                                                 core::CMatrix4<f32> m;\r
2080                                                 m.buildRotateFromTo(v3f(0,0,1), dir_f);\r
2081 \r
2082                                                 // This is the back face\r
2083                                                 v3f corners[2] = {\r
2084                                                         v3f(BS/2, BS/2, BS/2),\r
2085                                                         v3f(-BS/2, -BS/2, BS/2+d)\r
2086                                                 };\r
2087                                                 \r
2088                                                 for(u16 j=0; j<2; j++)\r
2089                                                 {\r
2090                                                         m.rotateVect(corners[j]);\r
2091                                                         corners[j] += npf;\r
2092                                                 }\r
2093 \r
2094                                                 core::aabbox3d<f32> facebox(corners[0]);\r
2095                                                 facebox.addInternalPoint(corners[1]);\r
2096 \r
2097                                                 if(facebox.intersectsWithLine(shootline))\r
2098                                                 {\r
2099                                                         nodefound = true;\r
2100                                                         nodepos = np;\r
2101                                                         neighbourpos = np + dirs[i];\r
2102                                                         mindistance = distance;\r
2103                                                         nodefacebox = facebox;\r
2104                                                 }\r
2105                                         } // if distance < mindistance\r
2106                                 } // for dirs\r
2107                         } // regular block\r
2108                 } // for coords\r
2109 \r
2110                 static float nodig_delay_counter = 0.0;\r
2111 \r
2112                 if(nodefound)\r
2113                 {\r
2114                         static v3s16 nodepos_old(-32768,-32768,-32768);\r
2115 \r
2116                         static float dig_time = 0.0;\r
2117                         static u16 dig_index = 0;\r
2118 \r
2119                         hilightboxes.push_back(nodefacebox);\r
2120                         \r
2121                         if(g_input->getLeftReleased())\r
2122                         {\r
2123                                 client.clearTempMod(nodepos);\r
2124                                 dig_time = 0.0;\r
2125                         }\r
2126                         \r
2127                         if(nodig_delay_counter > 0.0)\r
2128                         {\r
2129                                 nodig_delay_counter -= dtime;\r
2130                         }\r
2131                         else\r
2132                         {\r
2133                                 if(nodepos != nodepos_old)\r
2134                                 {\r
2135                                         std::cout<<DTIME<<"Pointing at ("<<nodepos.X<<","\r
2136                                                         <<nodepos.Y<<","<<nodepos.Z<<")"<<std::endl;\r
2137 \r
2138                                         if(nodepos_old != v3s16(-32768,-32768,-32768))\r
2139                                         {\r
2140                                                 client.clearTempMod(nodepos_old);\r
2141                                                 dig_time = 0.0;\r
2142                                         }\r
2143                                 }\r
2144 \r
2145                                 if(g_input->getLeftClicked() ||\r
2146                                                 (g_input->getLeftState() && nodepos != nodepos_old))\r
2147                                 {\r
2148                                         dstream<<DTIME<<"Started digging"<<std::endl;\r
2149                                         client.groundAction(0, nodepos, neighbourpos, g_selected_item);\r
2150                                 }\r
2151                                 if(g_input->getLeftClicked())\r
2152                                 {\r
2153                                         client.setTempMod(nodepos, NodeMod(NODEMOD_CRACK, 0));\r
2154                                 }\r
2155                                 if(g_input->getLeftState())\r
2156                                 {\r
2157                                         MapNode n = client.getNode(nodepos);\r
2158                                 \r
2159                                         // Get tool name. Default is "" = bare hands\r
2160                                         std::string toolname = "";\r
2161                                         InventoryList *mlist = local_inventory.getList("main");\r
2162                                         if(mlist != NULL)\r
2163                                         {\r
2164                                                 InventoryItem *item = mlist->getItem(g_selected_item);\r
2165                                                 if(item && (std::string)item->getName() == "ToolItem")\r
2166                                                 {\r
2167                                                         ToolItem *titem = (ToolItem*)item;\r
2168                                                         toolname = titem->getToolName();\r
2169                                                 }\r
2170                                         }\r
2171 \r
2172                                         // Get digging properties for material and tool\r
2173                                         u8 material = n.d;\r
2174                                         DiggingProperties prop =\r
2175                                                         getDiggingProperties(material, toolname);\r
2176                                         \r
2177                                         float dig_time_complete = 0.0;\r
2178 \r
2179                                         if(prop.diggable == false)\r
2180                                         {\r
2181                                                 /*dstream<<"Material "<<(int)material\r
2182                                                                 <<" not diggable with \""\r
2183                                                                 <<toolname<<"\""<<std::endl;*/\r
2184                                                 // I guess nobody will wait for this long\r
2185                                                 dig_time_complete = 10000000.0;\r
2186                                         }\r
2187                                         else\r
2188                                         {\r
2189                                                 dig_time_complete = prop.time;\r
2190                                         }\r
2191                                         \r
2192                                         if(dig_time_complete >= 0.001)\r
2193                                         {\r
2194                                                 dig_index = (u16)((float)CRACK_ANIMATION_LENGTH\r
2195                                                                 * dig_time/dig_time_complete);\r
2196                                         }\r
2197                                         // This is for torches\r
2198                                         else\r
2199                                         {\r
2200                                                 dig_index = CRACK_ANIMATION_LENGTH;\r
2201                                         }\r
2202 \r
2203                                         if(dig_index < CRACK_ANIMATION_LENGTH)\r
2204                                         {\r
2205                                                 //dstream<<"dig_index="<<dig_index<<std::endl;\r
2206                                                 client.setTempMod(nodepos, NodeMod(NODEMOD_CRACK, dig_index));\r
2207                                         }\r
2208                                         else\r
2209                                         {\r
2210                                                 dstream<<DTIME<<"Digging completed"<<std::endl;\r
2211                                                 client.groundAction(3, nodepos, neighbourpos, g_selected_item);\r
2212                                                 client.clearTempMod(nodepos);\r
2213                                                 client.removeNode(nodepos);\r
2214 \r
2215                                                 dig_time = 0;\r
2216 \r
2217                                                 nodig_delay_counter = dig_time_complete\r
2218                                                                 / (float)CRACK_ANIMATION_LENGTH;\r
2219 \r
2220                                                 // We don't want a corresponding delay to\r
2221                                                 // very time consuming nodes\r
2222                                                 if(nodig_delay_counter > 0.5)\r
2223                                                 {\r
2224                                                         nodig_delay_counter = 0.5;\r
2225                                                 }\r
2226                                                 // We want a slight delay to very little\r
2227                                                 // time consuming nodes\r
2228                                                 //float mindelay = 0.15;\r
2229                                                 float mindelay = 0.20;\r
2230                                                 if(nodig_delay_counter < mindelay)\r
2231                                                 {\r
2232                                                         nodig_delay_counter = mindelay;\r
2233                                                 }\r
2234                                         }\r
2235 \r
2236                                         dig_time += dtime;\r
2237                                 }\r
2238                         }\r
2239                         \r
2240                         if(g_input->getRightClicked())\r
2241                         {\r
2242                                 std::cout<<DTIME<<"Ground right-clicked"<<std::endl;\r
2243                                 client.groundAction(1, nodepos, neighbourpos, g_selected_item);\r
2244                         }\r
2245                         \r
2246                         nodepos_old = nodepos;\r
2247                 }\r
2248                 else{\r
2249                 }\r
2250 \r
2251                 } // selected_object == NULL\r
2252                 \r
2253                 g_input->resetLeftClicked();\r
2254                 g_input->resetRightClicked();\r
2255                 \r
2256                 if(g_input->getLeftReleased())\r
2257                 {\r
2258                         std::cout<<DTIME<<"Left button released (stopped digging)"\r
2259                                         <<std::endl;\r
2260                         client.groundAction(2, v3s16(0,0,0), v3s16(0,0,0), 0);\r
2261                 }\r
2262                 if(g_input->getRightReleased())\r
2263                 {\r
2264                         //std::cout<<DTIME<<"Right released"<<std::endl;\r
2265                         // Nothing here\r
2266                 }\r
2267                 \r
2268                 g_input->resetLeftReleased();\r
2269                 g_input->resetRightReleased();\r
2270                 \r
2271                 /*\r
2272                         Calculate stuff for drawing\r
2273                 */\r
2274 \r
2275                 camera->setAspectRatio((f32)screensize.X / (f32)screensize.Y);\r
2276                 \r
2277                 u32 daynight_ratio = client.getDayNightRatio();\r
2278                 video::SColor bgcolor = video::SColor(\r
2279                                 255,\r
2280                                 skycolor.getRed() * daynight_ratio / 1000,\r
2281                                 skycolor.getGreen() * daynight_ratio / 1000,\r
2282                                 skycolor.getBlue() * daynight_ratio / 1000);\r
2283 \r
2284                 /*\r
2285                         Fog\r
2286                 */\r
2287                 \r
2288                 if(g_settings.getBool("enable_fog") == true)\r
2289                 {\r
2290                         f32 range = draw_control.wanted_range * BS;\r
2291                         if(draw_control.range_all)\r
2292                                 range = 100000*BS;\r
2293 \r
2294                         driver->setFog(\r
2295                                 bgcolor,\r
2296                                 video::EFT_FOG_LINEAR,\r
2297                                 range*0.6,\r
2298                                 range,\r
2299                                 0.01,\r
2300                                 false, // pixel fog\r
2301                                 false // range fog\r
2302                                 );\r
2303                 }\r
2304 \r
2305 \r
2306                 /*\r
2307                         Update gui stuff (0ms)\r
2308                 */\r
2309 \r
2310                 //TimeTaker guiupdatetimer("Gui updating");\r
2311                 \r
2312                 {\r
2313                         wchar_t temptext[150];\r
2314 \r
2315                         static float drawtime_avg = 0;\r
2316                         drawtime_avg = drawtime_avg * 0.95 + (float)drawtime*0.05;\r
2317                         static float beginscenetime_avg = 0;\r
2318                         beginscenetime_avg = beginscenetime_avg * 0.95 + (float)beginscenetime*0.05;\r
2319                         static float scenetime_avg = 0;\r
2320                         scenetime_avg = scenetime_avg * 0.95 + (float)scenetime*0.05;\r
2321                         static float endscenetime_avg = 0;\r
2322                         endscenetime_avg = endscenetime_avg * 0.95 + (float)endscenetime*0.05;\r
2323                         \r
2324                         swprintf(temptext, 150, L"Minetest-c55 ("\r
2325                                         L"F: item=%i"\r
2326                                         L", R: range_all=%i"\r
2327                                         L")"\r
2328                                         L" drawtime=%.0f, beginscenetime=%.0f, scenetime=%.0f, endscenetime=%.0f",\r
2329                                         g_selected_item,\r
2330                                         draw_control.range_all,\r
2331                                         drawtime_avg,\r
2332                                         beginscenetime_avg,\r
2333                                         scenetime_avg,\r
2334                                         endscenetime_avg\r
2335                                         );\r
2336                         \r
2337                         guitext->setText(temptext);\r
2338                 }\r
2339                 \r
2340                 {\r
2341                         wchar_t temptext[150];\r
2342                         swprintf(temptext, 150,\r
2343                                         L"(% .1f, % .1f, % .1f)"\r
2344                                         L" (% .3f < btime_jitter < % .3f"\r
2345                                         L", dtime_jitter = % .1f %%"\r
2346                                         L", v_range = %.1f)",\r
2347                                         player_position.X/BS,\r
2348                                         player_position.Y/BS,\r
2349                                         player_position.Z/BS,\r
2350                                         busytime_jitter1_min_sample,\r
2351                                         busytime_jitter1_max_sample,\r
2352                                         dtime_jitter1_max_fraction * 100.0,\r
2353                                         draw_control.wanted_range\r
2354                                         );\r
2355 \r
2356                         guitext2->setText(temptext);\r
2357                 }\r
2358                 \r
2359                 {\r
2360                         guitext_info->setText(infotext.c_str());\r
2361                 }\r
2362                 \r
2363                 /*\r
2364                         Get chat messages from client\r
2365                 */\r
2366                 {\r
2367                         // Get new messages\r
2368                         std::wstring message;\r
2369                         while(client.getChatMessage(message))\r
2370                         {\r
2371                                 chat_lines.push_back(ChatLine(message));\r
2372                                 /*if(chat_lines.size() > 6)\r
2373                                 {\r
2374                                         core::list<ChatLine>::Iterator\r
2375                                                         i = chat_lines.begin();\r
2376                                         chat_lines.erase(i);\r
2377                                 }*/\r
2378                         }\r
2379                         // Append them to form the whole static text and throw\r
2380                         // it to the gui element\r
2381                         std::wstring whole;\r
2382                         // This will correspond to the line number counted from\r
2383                         // top to bottom, from size-1 to 0\r
2384                         s16 line_number = chat_lines.size();\r
2385                         // Count of messages to be removed from the top\r
2386                         u16 to_be_removed_count = 0;\r
2387                         for(core::list<ChatLine>::Iterator\r
2388                                         i = chat_lines.begin();\r
2389                                         i != chat_lines.end(); i++)\r
2390                         {\r
2391                                 // After this, line number is valid for this loop\r
2392                                 line_number--;\r
2393                                 // Increment age\r
2394                                 (*i).age += dtime;\r
2395                                 /*\r
2396                                         This results in a maximum age of 60*6 to the\r
2397                                         lowermost line and a maximum of 6 lines\r
2398                                 */\r
2399                                 float allowed_age = (6-line_number) * 60.0;\r
2400 \r
2401                                 if((*i).age > allowed_age)\r
2402                                 {\r
2403                                         to_be_removed_count++;\r
2404                                         continue;\r
2405                                 }\r
2406                                 whole += (*i).text + L'\n';\r
2407                         }\r
2408                         for(u16 i=0; i<to_be_removed_count; i++)\r
2409                         {\r
2410                                 core::list<ChatLine>::Iterator\r
2411                                                 it = chat_lines.begin();\r
2412                                 chat_lines.erase(it);\r
2413                         }\r
2414                         chat_guitext->setText(whole.c_str());\r
2415                         // Update gui element size and position\r
2416                         core::rect<s32> rect(\r
2417                                         10,\r
2418                                         screensize.Y - 10 - text_height*chat_lines.size(),\r
2419                                         screensize.X - 10,\r
2420                                         screensize.Y - 10\r
2421                         );\r
2422                         chat_guitext->setRelativePosition(rect);\r
2423 \r
2424                         if(chat_lines.size() == 0)\r
2425                                 chat_guitext->setVisible(false);\r
2426                         else\r
2427                                 chat_guitext->setVisible(true);\r
2428                 }\r
2429 \r
2430                 /*\r
2431                         Inventory\r
2432                 */\r
2433                 \r
2434                 static u16 old_selected_item = 65535;\r
2435                 if(client.getLocalInventoryUpdated()\r
2436                                 || g_selected_item != old_selected_item)\r
2437                 {\r
2438                         old_selected_item = g_selected_item;\r
2439                         //std::cout<<"Updating local inventory"<<std::endl;\r
2440                         client.getLocalInventory(local_inventory);\r
2441                         quick_inventory->setSelection(g_selected_item);\r
2442                         quick_inventory->update();\r
2443                 }\r
2444                 \r
2445                 /*\r
2446                         Send actions returned by the inventory menu\r
2447                 */\r
2448                 while(inventory_action_queue.size() != 0)\r
2449                 {\r
2450                         InventoryAction *a = inventory_action_queue.pop_front();\r
2451 \r
2452                         client.sendInventoryAction(a);\r
2453                         // Eat it\r
2454                         delete a;\r
2455                 }\r
2456 \r
2457                 /*\r
2458                         Drawing begins\r
2459                 */\r
2460 \r
2461                 TimeTaker drawtimer("Drawing");\r
2462 \r
2463                 \r
2464                 {\r
2465                         TimeTaker timer("beginScene");\r
2466                         driver->beginScene(true, true, bgcolor);\r
2467                         //driver->beginScene(false, true, bgcolor);\r
2468                         beginscenetime = timer.stop(true);\r
2469                 }\r
2470 \r
2471                 //timer3.stop();\r
2472                 \r
2473                 //std::cout<<DTIME<<"smgr->drawAll()"<<std::endl;\r
2474                 \r
2475                 {\r
2476                         TimeTaker timer("smgr");\r
2477                         smgr->drawAll();\r
2478                         scenetime = timer.stop(true);\r
2479                 }\r
2480                 \r
2481                 {\r
2482                 //TimeTaker timer9("auxiliary drawings");\r
2483                 // 0ms\r
2484                 \r
2485                 //timer9.stop();\r
2486                 //TimeTaker //timer10("//timer10");\r
2487                 \r
2488                 video::SMaterial m;\r
2489                 m.Thickness = 10;\r
2490                 m.Lighting = false;\r
2491                 driver->setMaterial(m);\r
2492 \r
2493                 driver->setTransform(video::ETS_WORLD, core::IdentityMatrix);\r
2494 \r
2495                 for(core::list< core::aabbox3d<f32> >::Iterator i=hilightboxes.begin();\r
2496                                 i != hilightboxes.end(); i++)\r
2497                 {\r
2498                         /*std::cout<<"hilightbox min="\r
2499                                         <<"("<<i->MinEdge.X<<","<<i->MinEdge.Y<<","<<i->MinEdge.Z<<")"\r
2500                                         <<" max="\r
2501                                         <<"("<<i->MaxEdge.X<<","<<i->MaxEdge.Y<<","<<i->MaxEdge.Z<<")"\r
2502                                         <<std::endl;*/\r
2503                         driver->draw3DBox(*i, video::SColor(255,0,0,0));\r
2504                 }\r
2505 \r
2506                 /*\r
2507                         Draw crosshair\r
2508                 */\r
2509                 driver->draw2DLine(displaycenter - core::vector2d<s32>(10,0),\r
2510                                 displaycenter + core::vector2d<s32>(10,0),\r
2511                                 video::SColor(255,255,255,255));\r
2512                 driver->draw2DLine(displaycenter - core::vector2d<s32>(0,10),\r
2513                                 displaycenter + core::vector2d<s32>(0,10),\r
2514                                 video::SColor(255,255,255,255));\r
2515 \r
2516                 }\r
2517 \r
2518                 //timer10.stop();\r
2519                 //TimeTaker //timer11("//timer11");\r
2520 \r
2521                 /*\r
2522                         Draw gui\r
2523                 */\r
2524                 // 0-1ms\r
2525                 guienv->drawAll();\r
2526                 \r
2527                 // End drawing\r
2528                 {\r
2529                         TimeTaker timer("endScene");\r
2530                         driver->endScene();\r
2531                         endscenetime = timer.stop(true);\r
2532                 }\r
2533 \r
2534                 drawtime = drawtimer.stop(true);\r
2535 \r
2536                 /*\r
2537                         Drawing ends\r
2538                 */\r
2539                 \r
2540                 static s16 lastFPS = 0;\r
2541                 //u16 fps = driver->getFPS();\r
2542                 u16 fps = (1.0/dtime_avg1);\r
2543 \r
2544                 if (lastFPS != fps)\r
2545                 {\r
2546                         core::stringw str = L"Minetest [";\r
2547                         str += driver->getName();\r
2548                         str += "] FPS:";\r
2549                         str += fps;\r
2550 \r
2551                         device->setWindowCaption(str.c_str());\r
2552                         lastFPS = fps;\r
2553                 }\r
2554                 \r
2555                 /*}\r
2556                 else\r
2557                         device->yield();*/\r
2558         }\r
2559 \r
2560         delete quick_inventory;\r
2561 \r
2562         } // client is deleted at this point\r
2563         \r
2564         delete g_input;\r
2565 \r
2566         /*\r
2567                 In the end, delete the Irrlicht device.\r
2568         */\r
2569         device->drop();\r
2570         \r
2571         /*\r
2572                 Update configuration file\r
2573         */\r
2574         /*if(configpath != "")\r
2575         {\r
2576                 g_settings.updateConfigFile(configpath.c_str());\r
2577         }*/\r
2578 \r
2579         } //try\r
2580         catch(con::PeerNotFoundException &e)\r
2581         {\r
2582                 dstream<<DTIME<<"Connection timed out."<<std::endl;\r
2583                 \r
2584                 /*if(g_device)\r
2585                 {\r
2586                         GUIMessageMenu *menu =\r
2587                                         new GUIMessageMenu(guienv, guiroot, -1, \r
2588                                                 &g_active_menu_count,\r
2589                                                 L"Connection timed out");\r
2590 \r
2591                         video::IVideoDriver* driver = g_device->getVideoDriver();\r
2592                         \r
2593                         dstream<<"Created menu"<<std::endl;\r
2594 \r
2595                         while(g_device->run() && menu->getStatus() == false)\r
2596                         {\r
2597                                 driver->beginScene(true, true, video::SColor(255,0,0,0));\r
2598                                 guienv->drawAll();\r
2599                                 driver->endScene();\r
2600                         }\r
2601                         \r
2602                         dstream<<"Dropping menu"<<std::endl;\r
2603 \r
2604                         menu->drop();\r
2605                 }*/\r
2606         }\r
2607 \r
2608         END_DEBUG_EXCEPTION_HANDLER\r
2609         \r
2610         debugstreams_deinit();\r
2611         \r
2612         return 0;\r
2613 }\r
2614 \r
2615 //END\r