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