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