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