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