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