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