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