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