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