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