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