]> git.lizzy.rs Git - dragonfireclient.git/blob - src/main.cpp
cleaning up main.cpp a bit
[dragonfireclient.git] / src / main.cpp
1 /*\r
2 Minetest-c55\r
3 Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>\r
4 \r
5 This program is free software; you can redistribute it and/or modify\r
6 it under the terms of the GNU General Public License as published by\r
7 the Free Software Foundation; either version 2 of the License, or\r
8 (at your option) any later version.\r
9 \r
10 This program is distributed in the hope that it will be useful,\r
11 but WITHOUT ANY WARRANTY; without even the implied warranty of\r
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
13 GNU General Public License for more details.\r
14 \r
15 You should have received a copy of the GNU General Public License along\r
16 with this program; if not, write to the Free Software Foundation, Inc.,\r
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
18 */\r
19 \r
20 /*\r
21 =============================== NOTES ==============================\r
22 NOTE: Things starting with TODO are sometimes only suggestions.\r
23 \r
24 NOTE: iostream.imbue(std::locale("C")) is very slow\r
25 NOTE: Global locale is now set at initialization\r
26 \r
27 NOTE: If VBO (EHM_STATIC) is used, remember to explicitly free the\r
28       hardware buffer (it is not freed automatically)\r
29 \r
30 Random suggeestions (AKA very old suggestions that haven't been done):\r
31 ----------------------------------------------------------------------\r
32 \r
33 SUGG: Fix address to be ipv6 compatible\r
34 \r
35 SUGG: If player is on ground, mainly fetch ground-level blocks\r
36 \r
37 SUGG: Expose Connection's seqnums and ACKs to server and client.\r
38       - This enables saving many packets and making a faster connection\r
39           - This also enables server to check if client has received the\r
40             most recent block sent, for example.\r
41 SUGG: Add a sane bandwidth throttling system to Connection\r
42 \r
43 SUGG: More fine-grained control of client's dumping of blocks from\r
44       memory\r
45           - ...What does this mean in the first place?\r
46 \r
47 SUGG: A map editing mode (similar to dedicated server mode)\r
48 \r
49 SUGG: Transfer more blocks in a single packet\r
50 SUGG: A blockdata combiner class, to which blocks are added and at\r
51       destruction it sends all the stuff in as few packets as possible.\r
52 SUGG: Make a PACKET_COMBINED which contains many subpackets. Utilize\r
53       it by sending more stuff in a single packet.\r
54           - Add a packet queue to RemoteClient, from which packets will be\r
55             combined with object data packets\r
56                 - This is not exactly trivial: the object data packets are\r
57                   sometimes very big by themselves\r
58           - This might not give much network performance gain though.\r
59 \r
60 SUGG: Precalculate lighting translation table at runtime (at startup)\r
61       - This is not doable because it is currently hand-made and not\r
62             based on some mathematical function.\r
63                 - Note: This has been changing lately\r
64 \r
65 SUGG: A version number to blocks, which increments when the block is\r
66       modified (node add/remove, water update, lighting update)\r
67           - This can then be used to make sure the most recent version of\r
68             a block has been sent to client, for example\r
69 \r
70 SUGG: Make the amount of blocks sending to client and the total\r
71           amount of blocks dynamically limited. Transferring blocks is the\r
72           main network eater of this system, so it is the one that has\r
73           to be throttled so that RTTs stay low.\r
74 \r
75 SUGG: Meshes of blocks could be split into 6 meshes facing into\r
76       different directions and then only those drawn that need to be\r
77 \r
78 SUGG: Calculate lighting per vertex to get a lighting effect like in\r
79       bartwe's game\r
80 \r
81 SUGG: Background music based on cellular automata?\r
82       http://www.earslap.com/projectslab/otomata\r
83 \r
84 \r
85 Gaming ideas:\r
86 -------------\r
87 \r
88 - Aim for something like controlling a single dwarf in Dwarf Fortress\r
89 \r
90 - The player could go faster by a crafting a boat, or riding an animal\r
91 \r
92 - Random NPC traders. what else?\r
93 \r
94 Game content:\r
95 -------------\r
96 - When furnace is destroyed, move items to player's inventory\r
97 - Add lots of stuff\r
98 - Glass blocks\r
99 - Growing grass, decaying leaves\r
100         - This can be done in the active blocks I guess.\r
101         - Lots of stuff can be done in the active blocks.\r
102         - Uh, is there an active block list somewhere? I think not. Add it.\r
103 - Breaking weak structures\r
104         - This can probably be accomplished in the same way as grass\r
105 - Player health points\r
106         - When player dies, throw items on map (needs better item-on-map\r
107           implementation)\r
108 - Cobble to get mossy if near water\r
109 - More slots in furnace source list, so that multiple ingredients\r
110   are possible.\r
111 - Keys to chests?\r
112 \r
113 - The Treasure Guard; a big monster with a hammer\r
114         - The hammer does great damage, shakes the ground and removes a block\r
115         - You can drop on top of it, and have some time to attack there\r
116           before he shakes you off\r
117 \r
118 - Maybe the difficulty could come from monsters getting tougher in\r
119   far-away places, and the player starting to need something from\r
120   there when time goes by.\r
121   - The player would have some of that stuff at the beginning, and\r
122     would need new supplies of it when it runs out\r
123 \r
124 - A bomb\r
125 - A spread-items-on-map routine for the bomb, and for dying players\r
126 \r
127 Documentation:\r
128 --------------\r
129 \r
130 Build system / running:\r
131 -----------------------\r
132 \r
133 Networking and serialization:\r
134 -----------------------------\r
135 \r
136 TODO: Get rid of GotSplitPacketException\r
137 \r
138 GUI:\r
139 ----\r
140 \r
141 TODO: Configuration menu, at least for keys\r
142 \r
143 Graphics:\r
144 ---------\r
145 \r
146 SUGG: Combine MapBlock's face caches to so big pieces that VBO\r
147       can be used\r
148       - That is >500 vertices\r
149           - This is not easy; all the MapBlocks close to the player would\r
150             still need to be drawn separately and combining the blocks\r
151                 would have to happen in a background thread\r
152 \r
153 SUGG: Make fetching sector's blocks more efficient when rendering\r
154       sectors that have very large amounts of blocks (on client)\r
155           - Is this necessary at all?\r
156 \r
157 TODO: Flowing water animation\r
158 \r
159 SUGG: Draw cubes in inventory directly with 3D drawing commands, so that\r
160       animating them is easier.\r
161 \r
162 SUGG: Option for enabling proper alpha channel for textures\r
163 TODO: A setting for enabling bilinear filtering for textures\r
164 \r
165 Configuration:\r
166 --------------\r
167 \r
168 Client:\r
169 -------\r
170 \r
171 TODO: Untie client network operations from framerate\r
172       - Needs some input queues or something\r
173           - This won't give much performance boost because calculating block\r
174             meshes takes so long\r
175 \r
176 SUGG: Make morning and evening transition more smooth and maybe shorter\r
177 \r
178 TODO: Don't update all meshes always on single node changes, but\r
179       check which ones should be updated\r
180           - implement Map::updateNodeMeshes() and the usage of it\r
181           - It will give almost always a 4x boost in mesh update performance.\r
182 \r
183 - A weapon engine\r
184 \r
185 - Tool/weapon visualization\r
186 \r
187 Server:\r
188 -------\r
189 \r
190 SUGG: Make an option to the server to disable building and digging near\r
191       the starting position\r
192 \r
193 FIXME: Server sometimes goes into some infinite PeerNotFoundException loop\r
194 \r
195 * Fix the problem with the server constantly saving one or a few\r
196   blocks? List the first saved block, maybe it explains.\r
197   - It is probably caused by oscillating water\r
198 * Make a small history check to transformLiquids to detect and log\r
199   continuous oscillations, in such detail that they can be fixed.\r
200 \r
201 Objects:\r
202 --------\r
203 \r
204 TODO: Get rid of MapBlockObjects and use ActiveObjects\r
205 \r
206 SUGG: MovingObject::move and Player::move are basically the same.\r
207       combine them.\r
208           - NOTE: Player::move is more up-to-date.\r
209           - NOTE: There is a simple move implementation now in collision.{h,cpp}\r
210 \r
211 Map:\r
212 ----\r
213 \r
214 TODO: Mineral and ground material properties\r
215       - This way mineral ground toughness can be calculated with just\r
216             some formula, as well as tool strengths\r
217 \r
218 TODO: Flowing water to actually contain flow direction information\r
219       - There is a space for this - it just has to be implemented.\r
220 \r
221 SUGG: Erosion simulation at map generation time\r
222         - Simulate water flows, which would carve out dirt fast and\r
223           then turn stone into gravel and sand and relocate it.\r
224         - How about relocating minerals, too? Coal and gold in\r
225           downstream sand and gravel would be kind of cool\r
226           - This would need a better way of handling minerals, mainly\r
227                 to have mineral content as a separate field. the first\r
228                 parameter field is free for this.\r
229         - Simulate rock falling from cliffs when water has removed\r
230           enough solid rock from the bottom\r
231 \r
232 SUGG: Try out the notch way of generating maps, that is, make bunches\r
233       of low-res 3d noise and interpolate linearly.\r
234 \r
235 Mapgen v2:\r
236 * Possibly add some kind of erosion and other stuff\r
237 * Better water generation (spread it to underwater caverns but don't\r
238   fill dungeons that don't touch big water masses)\r
239 * When generating a chunk and the neighboring chunk doesn't have mud\r
240   and stuff yet and the ground is fairly flat, the mud will flow to\r
241   the other chunk making nasty straight walls when the other chunk\r
242   is generated. Fix it. Maybe just a special case if the ground is\r
243   flat?\r
244 \r
245 Misc. stuff:\r
246 ------------\r
247 * Make an "environment metafile" to store at least time of day\r
248 * Move digging property stuff from material.{h,cpp} to mapnode.cpp...\r
249   - Or maybe move content_features to material.{h,cpp}?\r
250 * Maybe:\r
251   Make a system for pregenerating quick information for mapblocks, so\r
252   that the client can show them as cubes before they are actually sent\r
253   or even generated.\r
254 \r
255 Making it more portable:\r
256 ------------------------\r
257 * Some MSVC: std::sto* are defined without a namespace and collide\r
258   with the ones in utility.h\r
259 \r
260 ======================================================================\r
261 \r
262 */\r
263 \r
264 /*\r
265         Setting this to 1 enables a special camera mode that forces\r
266         the renderers to think that the camera statically points from\r
267         the starting place to a static direction.\r
268 \r
269         This allows one to move around with the player and see what\r
270         is actually drawn behind solid things and behind the player.\r
271 */\r
272 #define FIELD_OF_VIEW_TEST 0\r
273 \r
274 #ifdef NDEBUG\r
275         #ifdef _WIN32\r
276                 #pragma message ("Disabling unit tests")\r
277         #else\r
278                 #warning "Disabling unit tests"\r
279         #endif\r
280         // Disable unit tests\r
281         #define ENABLE_TESTS 0\r
282 #else\r
283         // Enable unit tests\r
284         #define ENABLE_TESTS 1\r
285 #endif\r
286 \r
287 #ifdef _MSC_VER\r
288         #pragma comment(lib, "Irrlicht.lib")\r
289         //#pragma comment(lib, "jthread.lib")\r
290         #pragma comment(lib, "zlibwapi.lib")\r
291         #pragma comment(lib, "Shell32.lib")\r
292         // This would get rid of the console window\r
293         //#pragma comment(linker, "/subsystem:windows /ENTRY:mainCRTStartup")\r
294 #endif\r
295 \r
296 #include <iostream>\r
297 #include <fstream>\r
298 #include <jmutexautolock.h>\r
299 #include <locale.h>\r
300 #include "main.h"\r
301 #include "common_irrlicht.h"\r
302 #include "debug.h"\r
303 #include "map.h"\r
304 #include "player.h"\r
305 #include "test.h"\r
306 //#include "environment.h"\r
307 #include "server.h"\r
308 #include "client.h"\r
309 //#include "serialization.h"\r
310 #include "constants.h"\r
311 //#include "strfnd.h"\r
312 #include "porting.h"\r
313 #include "gettime.h"\r
314 #include "porting.h"\r
315 #include "guiPauseMenu.h"\r
316 #include "guiInventoryMenu.h"\r
317 #include "guiTextInputMenu.h"\r
318 #include "materials.h"\r
319 #include "guiMessageMenu.h"\r
320 #include "filesys.h"\r
321 #include "config.h"\r
322 #include "guiMainMenu.h"\r
323 #include "mineral.h"\r
324 #include "noise.h"\r
325 #include "tile.h"\r
326 #include "guiFurnaceMenu.h"\r
327 \r
328 // This makes textures\r
329 ITextureSource *g_texturesource = NULL;\r
330 \r
331 MapDrawControl draw_control;\r
332 \r
333 /*\r
334         Settings.\r
335         These are loaded from the config file.\r
336 */\r
337 \r
338 Settings g_settings;\r
339 // This is located in defaultsettings.cpp\r
340 extern void set_default_settings();\r
341 \r
342 /*\r
343         Random stuff\r
344 */\r
345 \r
346 IrrlichtDevice *g_device = NULL;\r
347 Client *g_client = NULL;\r
348 \r
349 const s32 hotbar_itemcount = 8;\r
350 const s32 hotbar_imagesize = 36;\r
351 \r
352 /*\r
353         GUI Stuff\r
354 */\r
355 \r
356 gui::IGUIEnvironment* guienv = NULL;\r
357 gui::IGUIStaticText *guiroot = NULL;\r
358 \r
359 // Handler for the modal menus\r
360 \r
361 class MainMenuManager : public IMenuManager\r
362 {\r
363 public:\r
364         virtual void createdMenu(GUIModalMenu *menu)\r
365         {\r
366                 for(core::list<GUIModalMenu*>::Iterator\r
367                                 i = m_stack.begin();\r
368                                 i != m_stack.end(); i++)\r
369                 {\r
370                         assert(*i != menu);\r
371                 }\r
372 \r
373                 if(m_stack.size() != 0)\r
374                         (*m_stack.getLast())->setVisible(false);\r
375                 m_stack.push_back(menu);\r
376         }\r
377 \r
378         virtual void deletingMenu(GUIModalMenu *menu)\r
379         {\r
380                 // Remove all entries if there are duplicates\r
381                 bool removed_entry;\r
382                 do{\r
383                         removed_entry = false;\r
384                         for(core::list<GUIModalMenu*>::Iterator\r
385                                         i = m_stack.begin();\r
386                                         i != m_stack.end(); i++)\r
387                         {\r
388                                 if(*i == menu)\r
389                                 {\r
390                                         m_stack.erase(i);\r
391                                         removed_entry = true;\r
392                                         break;\r
393                                 }\r
394                         }\r
395                 }while(removed_entry);\r
396 \r
397                 /*core::list<GUIModalMenu*>::Iterator i = m_stack.getLast();\r
398                 assert(*i == menu);\r
399                 m_stack.erase(i);*/\r
400                 \r
401                 if(m_stack.size() != 0)\r
402                         (*m_stack.getLast())->setVisible(true);\r
403         }\r
404 \r
405         u32 menuCount()\r
406         {\r
407                 return m_stack.size();\r
408         }\r
409 \r
410         core::list<GUIModalMenu*> m_stack;\r
411 };\r
412 \r
413 MainMenuManager g_menumgr;\r
414 \r
415 bool noMenuActive()\r
416 {\r
417         return (g_menumgr.menuCount() == 0);\r
418 }\r
419 \r
420 // Passed to menus to allow disconnecting and exiting\r
421 \r
422 class MainGameCallback : public IGameCallback\r
423 {\r
424 public:\r
425         MainGameCallback():\r
426                 disconnect_requested(false)\r
427         {\r
428         }\r
429 \r
430         virtual void exitToOS()\r
431         {\r
432                 g_device->closeDevice();\r
433         }\r
434 \r
435         virtual void disconnect()\r
436         {\r
437                 disconnect_requested = true;\r
438         }\r
439 \r
440         bool disconnect_requested;\r
441 };\r
442 \r
443 MainGameCallback g_gamecallback;\r
444 \r
445 /*\r
446         Inventory stuff\r
447 */\r
448 \r
449 // Inventory actions from the menu are buffered here before sending\r
450 Queue<InventoryAction*> inventory_action_queue;\r
451 // This is a copy of the inventory that the client's environment has\r
452 Inventory local_inventory;\r
453 \r
454 u16 g_selected_item = 0;\r
455 \r
456 /*\r
457         Debug streams\r
458 */\r
459 \r
460 // Connection\r
461 std::ostream *dout_con_ptr = &dummyout;\r
462 std::ostream *derr_con_ptr = &dstream_no_stderr;\r
463 //std::ostream *dout_con_ptr = &dstream_no_stderr;\r
464 //std::ostream *derr_con_ptr = &dstream_no_stderr;\r
465 //std::ostream *dout_con_ptr = &dstream;\r
466 //std::ostream *derr_con_ptr = &dstream;\r
467 \r
468 // Server\r
469 std::ostream *dout_server_ptr = &dstream;\r
470 std::ostream *derr_server_ptr = &dstream;\r
471 \r
472 // Client\r
473 std::ostream *dout_client_ptr = &dstream;\r
474 std::ostream *derr_client_ptr = &dstream;\r
475 \r
476 /*\r
477         gettime.h implementation\r
478 */\r
479 \r
480 u32 getTimeMs()\r
481 {\r
482         /*\r
483                 Use irrlicht because it is more precise than porting.h's\r
484                 getTimeMs()\r
485         */\r
486         if(g_device == NULL)\r
487                 return 0;\r
488         return g_device->getTimer()->getRealTime();\r
489 }\r
490 \r
491 /*\r
492         Text input system\r
493 */\r
494 \r
495 struct TextDestSign : public TextDest\r
496 {\r
497         TextDestSign(v3s16 blockpos, s16 id, Client *client)\r
498         {\r
499                 m_blockpos = blockpos;\r
500                 m_id = id;\r
501                 m_client = client;\r
502         }\r
503         void gotText(std::wstring text)\r
504         {\r
505                 std::string ntext = wide_to_narrow(text);\r
506                 dstream<<"Changing text of a sign object: "\r
507                                 <<ntext<<std::endl;\r
508                 m_client->sendSignText(m_blockpos, m_id, ntext);\r
509         }\r
510 \r
511         v3s16 m_blockpos;\r
512         s16 m_id;\r
513         Client *m_client;\r
514 };\r
515 \r
516 struct TextDestChat : public TextDest\r
517 {\r
518         TextDestChat(Client *client)\r
519         {\r
520                 m_client = client;\r
521         }\r
522         void gotText(std::wstring text)\r
523         {\r
524                 // Discard empty line\r
525                 if(text == L"")\r
526                         return;\r
527                 \r
528                 // Parse command (server command starts with "/#")\r
529                 if(text[0] == L'/' && text[1] != L'#')\r
530                 {\r
531                         std::wstring reply = L"Local: ";\r
532 \r
533                         reply += L"Local commands not yet supported. "\r
534                                         L"Server prefix is \"/#\".";\r
535                         \r
536                         m_client->addChatMessage(reply);\r
537                         return;\r
538                 }\r
539 \r
540                 // Send to others\r
541                 m_client->sendChatMessage(text);\r
542                 // Show locally\r
543                 m_client->addChatMessage(text);\r
544         }\r
545 \r
546         Client *m_client;\r
547 };\r
548 \r
549 struct TextDestSignNode : public TextDest\r
550 {\r
551         TextDestSignNode(v3s16 p, Client *client)\r
552         {\r
553                 m_p = p;\r
554                 m_client = client;\r
555         }\r
556         void gotText(std::wstring text)\r
557         {\r
558                 std::string ntext = wide_to_narrow(text);\r
559                 dstream<<"Changing text of a sign node: "\r
560                                 <<ntext<<std::endl;\r
561                 m_client->sendSignNodeText(m_p, ntext);\r
562         }\r
563 \r
564         v3s16 m_p;\r
565         Client *m_client;\r
566 };\r
567 \r
568 /*\r
569         Event handler for Irrlicht\r
570 */\r
571 \r
572 class MyEventReceiver : public IEventReceiver\r
573 {\r
574 public:\r
575         // This is the one method that we have to implement\r
576         virtual bool OnEvent(const SEvent& event)\r
577         {\r
578                 /*\r
579                         React to nothing here if a menu is active\r
580                 */\r
581                 if(noMenuActive() == false)\r
582                 {\r
583                         clearInput();\r
584                         return false;\r
585                 }\r
586 \r
587                 // Remember whether each key is down or up\r
588                 if(event.EventType == irr::EET_KEY_INPUT_EVENT)\r
589                 {\r
590                         keyIsDown[event.KeyInput.Key] = event.KeyInput.PressedDown;\r
591 \r
592                         if(event.KeyInput.PressedDown)\r
593                         {\r
594                                 //dstream<<"Pressed key: "<<(char)event.KeyInput.Key<<std::endl;\r
595                                 /*if(g_show_map_plot)\r
596                                 {\r
597                                         if(event.KeyInput.Key == irr::KEY_ESCAPE\r
598                                                 || event.KeyInput.Key == irr::KEY_KEY_M)\r
599                                         {\r
600                                                 g_show_map_plot = false;\r
601                                         }\r
602                                         return true;\r
603                                 }*/\r
604                                 \r
605                                 /*\r
606                                         Launch menus\r
607                                 */\r
608 \r
609                                 if(guienv != NULL && guiroot != NULL && g_device != NULL)\r
610                                 {\r
611                                         if(event.KeyInput.Key == irr::KEY_ESCAPE)\r
612                                         {\r
613                                                 dstream<<DTIME<<"MyEventReceiver: "\r
614                                                                 <<"Launching pause menu"<<std::endl;\r
615                                                 // It will delete itself by itself\r
616                                                 (new GUIPauseMenu(guienv, guiroot, -1, &g_gamecallback,\r
617                                                                 &g_menumgr))->drop();\r
618                                                 return true;\r
619                                         }\r
620                                         if(event.KeyInput.Key == irr::KEY_KEY_I)\r
621                                         {\r
622                                                 dstream<<DTIME<<"MyEventReceiver: "\r
623                                                                 <<"Launching inventory"<<std::endl;\r
624                                                 \r
625                                                 GUIInventoryMenu *menu =\r
626                                                         new GUIInventoryMenu(guienv, guiroot, -1,\r
627                                                                 &g_menumgr, v2s16(8,7),\r
628                                                                 g_client->getInventoryContext(),\r
629                                                                 g_client);\r
630 \r
631                                                 core::array<GUIInventoryMenu::DrawSpec> draw_spec;\r
632                                                 draw_spec.push_back(GUIInventoryMenu::DrawSpec(\r
633                                                                 "list", "current_player", "main",\r
634                                                                 v2s32(0, 3), v2s32(8, 4)));\r
635                                                 draw_spec.push_back(GUIInventoryMenu::DrawSpec(\r
636                                                                 "list", "current_player", "craft",\r
637                                                                 v2s32(3, 0), v2s32(3, 3)));\r
638                                                 draw_spec.push_back(GUIInventoryMenu::DrawSpec(\r
639                                                                 "list", "current_player", "craftresult",\r
640                                                                 v2s32(7, 1), v2s32(1, 1)));\r
641 \r
642                                                 menu->setDrawSpec(draw_spec);\r
643 \r
644                                                 menu->drop();\r
645 \r
646                                                 return true;\r
647                                         }\r
648                                         if(event.KeyInput.Key == irr::KEY_KEY_T)\r
649                                         {\r
650                                                 TextDest *dest = new TextDestChat(g_client);\r
651 \r
652                                                 (new GUITextInputMenu(guienv, guiroot, -1,\r
653                                                                 &g_menumgr, dest,\r
654                                                                 L""))->drop();\r
655                                         }\r
656                                 }\r
657 \r
658                                 // Item selection\r
659                                 if(event.KeyInput.Key >= irr::KEY_KEY_0\r
660                                                 && event.KeyInput.Key <= irr::KEY_KEY_9)\r
661                                 {\r
662                                         u16 s1 = event.KeyInput.Key - irr::KEY_KEY_0;\r
663                                         if(event.KeyInput.Key == irr::KEY_KEY_0)\r
664                                                 s1 = 10;\r
665                                         if(s1 < PLAYER_INVENTORY_SIZE && s1 < hotbar_itemcount)\r
666                                                 g_selected_item = s1-1;\r
667                                         dstream<<DTIME<<"Selected item: "\r
668                                                         <<g_selected_item<<std::endl;\r
669                                 }\r
670 \r
671                                 // Viewing range selection\r
672                                 if(event.KeyInput.Key == irr::KEY_KEY_R)\r
673                                 {\r
674                                         if(draw_control.range_all)\r
675                                         {\r
676                                                 draw_control.range_all = false;\r
677                                                 dstream<<DTIME<<"Disabled full viewing range"<<std::endl;\r
678                                         }\r
679                                         else\r
680                                         {\r
681                                                 draw_control.range_all = true;\r
682                                                 dstream<<DTIME<<"Enabled full viewing range"<<std::endl;\r
683                                         }\r
684                                 }\r
685 \r
686                                 // Print debug stacks\r
687                                 if(event.KeyInput.Key == irr::KEY_KEY_P)\r
688                                 {\r
689                                         dstream<<"-----------------------------------------"\r
690                                                         <<std::endl;\r
691                                         dstream<<DTIME<<"Printing debug stacks:"<<std::endl;\r
692                                         dstream<<"-----------------------------------------"\r
693                                                         <<std::endl;\r
694                                         debug_stacks_print();\r
695                                 }\r
696 \r
697                                 // Map plot\r
698                                 /*if(event.KeyInput.Key == irr::KEY_KEY_M)\r
699                                 {\r
700                                         dstream<<"Map plot requested"<<std::endl;\r
701                                         g_show_map_plot = !g_show_map_plot;\r
702                                         if(g_show_map_plot)\r
703                                                 g_refresh_map_plot = true;\r
704                                 }*/\r
705                                 \r
706                         }\r
707                 }\r
708 \r
709                 if(event.EventType == irr::EET_MOUSE_INPUT_EVENT)\r
710                 {\r
711                         if(noMenuActive() == false)\r
712                         {\r
713                                 left_active = false;\r
714                                 middle_active = false;\r
715                                 right_active = false;\r
716                         }\r
717                         else\r
718                         {\r
719                                 //dstream<<"MyEventReceiver: mouse input"<<std::endl;\r
720                                 left_active = event.MouseInput.isLeftPressed();\r
721                                 middle_active = event.MouseInput.isMiddlePressed();\r
722                                 right_active = event.MouseInput.isRightPressed();\r
723 \r
724                                 if(event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN)\r
725                                 {\r
726                                         leftclicked = true;\r
727                                 }\r
728                                 if(event.MouseInput.Event == EMIE_RMOUSE_PRESSED_DOWN)\r
729                                 {\r
730                                         rightclicked = true;\r
731                                 }\r
732                                 if(event.MouseInput.Event == EMIE_LMOUSE_LEFT_UP)\r
733                                 {\r
734                                         leftreleased = true;\r
735                                 }\r
736                                 if(event.MouseInput.Event == EMIE_RMOUSE_LEFT_UP)\r
737                                 {\r
738                                         rightreleased = true;\r
739                                 }\r
740                                 if(event.MouseInput.Event == EMIE_MOUSE_WHEEL)\r
741                                 {\r
742                                         /*dstream<<"event.MouseInput.Wheel="\r
743                                                         <<event.MouseInput.Wheel<<std::endl;*/\r
744                                         \r
745                                         u16 max_item = MYMIN(PLAYER_INVENTORY_SIZE-1,\r
746                                                         hotbar_itemcount-1);\r
747                                         if(event.MouseInput.Wheel < 0)\r
748                                         {\r
749                                                 if(g_selected_item < max_item)\r
750                                                         g_selected_item++;\r
751                                                 else\r
752                                                         g_selected_item = 0;\r
753                                         }\r
754                                         else if(event.MouseInput.Wheel > 0)\r
755                                         {\r
756                                                 if(g_selected_item > 0)\r
757                                                         g_selected_item--;\r
758                                                 else\r
759                                                         g_selected_item = max_item;\r
760                                         }\r
761                                 }\r
762                         }\r
763                 }\r
764 \r
765                 return false;\r
766         }\r
767 \r
768         // This is used to check whether a key is being held down\r
769         virtual bool IsKeyDown(EKEY_CODE keyCode) const\r
770         {\r
771                 return keyIsDown[keyCode];\r
772         }\r
773 \r
774         void clearInput()\r
775         {\r
776                 for (u32 i=0; i<KEY_KEY_CODES_COUNT; ++i)\r
777                                 keyIsDown[i] = false;\r
778                 \r
779                 leftclicked = false;\r
780                 rightclicked = false;\r
781                 leftreleased = false;\r
782                 rightreleased = false;\r
783 \r
784                 left_active = false;\r
785                 middle_active = false;\r
786                 right_active = false;\r
787         }\r
788 \r
789         MyEventReceiver()\r
790         {\r
791                 clearInput();\r
792         }\r
793 \r
794         bool leftclicked;\r
795         bool rightclicked;\r
796         bool leftreleased;\r
797         bool rightreleased;\r
798 \r
799         bool left_active;\r
800         bool middle_active;\r
801         bool right_active;\r
802 \r
803 private:\r
804         // We use this array to store the current state of each key\r
805         bool keyIsDown[KEY_KEY_CODES_COUNT];\r
806         //s32 mouseX;\r
807         //s32 mouseY;\r
808         IrrlichtDevice *m_device;\r
809 };\r
810 \r
811 /*\r
812         Separated input handler\r
813 */\r
814 \r
815 class InputHandler\r
816 {\r
817 public:\r
818         InputHandler()\r
819         {\r
820         }\r
821         virtual ~InputHandler()\r
822         {\r
823         }\r
824 \r
825         virtual bool isKeyDown(EKEY_CODE keyCode) = 0;\r
826 \r
827         virtual v2s32 getMousePos() = 0;\r
828         virtual void setMousePos(s32 x, s32 y) = 0;\r
829 \r
830         virtual bool getLeftState() = 0;\r
831         virtual bool getRightState() = 0;\r
832 \r
833         virtual bool getLeftClicked() = 0;\r
834         virtual bool getRightClicked() = 0;\r
835         virtual void resetLeftClicked() = 0;\r
836         virtual void resetRightClicked() = 0;\r
837 \r
838         virtual bool getLeftReleased() = 0;\r
839         virtual bool getRightReleased() = 0;\r
840         virtual void resetLeftReleased() = 0;\r
841         virtual void resetRightReleased() = 0;\r
842         \r
843         virtual void step(float dtime) {};\r
844 \r
845         virtual void clear() {};\r
846 };\r
847 \r
848 InputHandler *g_input = NULL;\r
849 \r
850 class RealInputHandler : public InputHandler\r
851 {\r
852 public:\r
853         RealInputHandler(IrrlichtDevice *device, MyEventReceiver *receiver):\r
854                 m_device(device),\r
855                 m_receiver(receiver)\r
856         {\r
857         }\r
858         virtual bool isKeyDown(EKEY_CODE keyCode)\r
859         {\r
860                 return m_receiver->IsKeyDown(keyCode);\r
861         }\r
862         virtual v2s32 getMousePos()\r
863         {\r
864                 return m_device->getCursorControl()->getPosition();\r
865         }\r
866         virtual void setMousePos(s32 x, s32 y)\r
867         {\r
868                 m_device->getCursorControl()->setPosition(x, y);\r
869         }\r
870 \r
871         virtual bool getLeftState()\r
872         {\r
873                 return m_receiver->left_active;\r
874         }\r
875         virtual bool getRightState()\r
876         {\r
877                 return m_receiver->right_active;\r
878         }\r
879         \r
880         virtual bool getLeftClicked()\r
881         {\r
882                 return m_receiver->leftclicked;\r
883         }\r
884         virtual bool getRightClicked()\r
885         {\r
886                 return m_receiver->rightclicked;\r
887         }\r
888         virtual void resetLeftClicked()\r
889         {\r
890                 m_receiver->leftclicked = false;\r
891         }\r
892         virtual void resetRightClicked()\r
893         {\r
894                 m_receiver->rightclicked = false;\r
895         }\r
896 \r
897         virtual bool getLeftReleased()\r
898         {\r
899                 return m_receiver->leftreleased;\r
900         }\r
901         virtual bool getRightReleased()\r
902         {\r
903                 return m_receiver->rightreleased;\r
904         }\r
905         virtual void resetLeftReleased()\r
906         {\r
907                 m_receiver->leftreleased = false;\r
908         }\r
909         virtual void resetRightReleased()\r
910         {\r
911                 m_receiver->rightreleased = false;\r
912         }\r
913 \r
914         void clear()\r
915         {\r
916                 resetRightClicked();\r
917                 resetLeftClicked();\r
918         }\r
919 private:\r
920         IrrlichtDevice *m_device;\r
921         MyEventReceiver *m_receiver;\r
922 };\r
923 \r
924 class RandomInputHandler : public InputHandler\r
925 {\r
926 public:\r
927         RandomInputHandler()\r
928         {\r
929                 leftdown = false;\r
930                 rightdown = false;\r
931                 leftclicked = false;\r
932                 rightclicked = false;\r
933                 leftreleased = false;\r
934                 rightreleased = false;\r
935                 for(u32 i=0; i<KEY_KEY_CODES_COUNT; ++i)\r
936                         keydown[i] = false;\r
937         }\r
938         virtual bool isKeyDown(EKEY_CODE keyCode)\r
939         {\r
940                 return keydown[keyCode];\r
941         }\r
942         virtual v2s32 getMousePos()\r
943         {\r
944                 return mousepos;\r
945         }\r
946         virtual void setMousePos(s32 x, s32 y)\r
947         {\r
948                 mousepos = v2s32(x,y);\r
949         }\r
950 \r
951         virtual bool getLeftState()\r
952         {\r
953                 return leftdown;\r
954         }\r
955         virtual bool getRightState()\r
956         {\r
957                 return rightdown;\r
958         }\r
959 \r
960         virtual bool getLeftClicked()\r
961         {\r
962                 return leftclicked;\r
963         }\r
964         virtual bool getRightClicked()\r
965         {\r
966                 return rightclicked;\r
967         }\r
968         virtual void resetLeftClicked()\r
969         {\r
970                 leftclicked = false;\r
971         }\r
972         virtual void resetRightClicked()\r
973         {\r
974                 rightclicked = false;\r
975         }\r
976 \r
977         virtual bool getLeftReleased()\r
978         {\r
979                 return leftreleased;\r
980         }\r
981         virtual bool getRightReleased()\r
982         {\r
983                 return rightreleased;\r
984         }\r
985         virtual void resetLeftReleased()\r
986         {\r
987                 leftreleased = false;\r
988         }\r
989         virtual void resetRightReleased()\r
990         {\r
991                 rightreleased = false;\r
992         }\r
993 \r
994         virtual void step(float dtime)\r
995         {\r
996                 {\r
997                         static float counter1 = 0;\r
998                         counter1 -= dtime;\r
999                         if(counter1 < 0.0)\r
1000                         {\r
1001                                 counter1 = 0.1*Rand(1, 40);\r
1002                                 keydown[irr::KEY_SPACE] = !keydown[irr::KEY_SPACE];\r
1003                         }\r
1004                 }\r
1005                 {\r
1006                         static float counter1 = 0;\r
1007                         counter1 -= dtime;\r
1008                         if(counter1 < 0.0)\r
1009                         {\r
1010                                 counter1 = 0.1*Rand(1, 40);\r
1011                                 keydown[irr::KEY_KEY_E] = !keydown[irr::KEY_KEY_E];\r
1012                         }\r
1013                 }\r
1014                 {\r
1015                         static float counter1 = 0;\r
1016                         counter1 -= dtime;\r
1017                         if(counter1 < 0.0)\r
1018                         {\r
1019                                 counter1 = 0.1*Rand(1, 40);\r
1020                                 keydown[irr::KEY_KEY_W] = !keydown[irr::KEY_KEY_W];\r
1021                         }\r
1022                 }\r
1023                 {\r
1024                         static float counter1 = 0;\r
1025                         counter1 -= dtime;\r
1026                         if(counter1 < 0.0)\r
1027                         {\r
1028                                 counter1 = 0.1*Rand(1, 40);\r
1029                                 keydown[irr::KEY_KEY_A] = !keydown[irr::KEY_KEY_A];\r
1030                         }\r
1031                 }\r
1032                 {\r
1033                         static float counter1 = 0;\r
1034                         counter1 -= dtime;\r
1035                         if(counter1 < 0.0)\r
1036                         {\r
1037                                 counter1 = 0.1*Rand(1, 20);\r
1038                                 mousespeed = v2s32(Rand(-20,20), Rand(-15,20));\r
1039                         }\r
1040                 }\r
1041                 {\r
1042                         static float counter1 = 0;\r
1043                         counter1 -= dtime;\r
1044                         if(counter1 < 0.0)\r
1045                         {\r
1046                                 counter1 = 0.1*Rand(1, 30);\r
1047                                 leftdown = !leftdown;\r
1048                                 if(leftdown)\r
1049                                         leftclicked = true;\r
1050                                 if(!leftdown)\r
1051                                         leftreleased = true;\r
1052                         }\r
1053                 }\r
1054                 {\r
1055                         static float counter1 = 0;\r
1056                         counter1 -= dtime;\r
1057                         if(counter1 < 0.0)\r
1058                         {\r
1059                                 counter1 = 0.1*Rand(1, 15);\r
1060                                 rightdown = !rightdown;\r
1061                                 if(rightdown)\r
1062                                         rightclicked = true;\r
1063                                 if(!rightdown)\r
1064                                         rightreleased = true;\r
1065                         }\r
1066                 }\r
1067                 mousepos += mousespeed;\r
1068         }\r
1069 \r
1070         s32 Rand(s32 min, s32 max)\r
1071         {\r
1072                 return (myrand()%(max-min+1))+min;\r
1073         }\r
1074 private:\r
1075         bool keydown[KEY_KEY_CODES_COUNT];\r
1076         v2s32 mousepos;\r
1077         v2s32 mousespeed;\r
1078         bool leftdown;\r
1079         bool rightdown;\r
1080         bool leftclicked;\r
1081         bool rightclicked;\r
1082         bool leftreleased;\r
1083         bool rightreleased;\r
1084 };\r
1085 \r
1086 /*\r
1087         Render distance feedback loop\r
1088 */\r
1089 \r
1090 void updateViewingRange(f32 frametime_in, Client *client)\r
1091 {\r
1092         if(draw_control.range_all == true)\r
1093                 return;\r
1094         \r
1095         static f32 added_frametime = 0;\r
1096         static s16 added_frames = 0;\r
1097 \r
1098         added_frametime += frametime_in;\r
1099         added_frames += 1;\r
1100 \r
1101         // Actually this counter kind of sucks because frametime is busytime\r
1102         static f32 counter = 0;\r
1103         counter -= frametime_in;\r
1104         if(counter > 0)\r
1105                 return;\r
1106         //counter = 0.1;\r
1107         counter = 0.2;\r
1108 \r
1109         /*dstream<<__FUNCTION_NAME\r
1110                         <<": Collected "<<added_frames<<" frames, total of "\r
1111                         <<added_frametime<<"s."<<std::endl;*/\r
1112         \r
1113         /*dstream<<"draw_control.blocks_drawn="\r
1114                         <<draw_control.blocks_drawn\r
1115                         <<", draw_control.blocks_would_have_drawn="\r
1116                         <<draw_control.blocks_would_have_drawn\r
1117                         <<std::endl;*/\r
1118         \r
1119         float range_min = g_settings.getS16("viewing_range_nodes_min");\r
1120         float range_max = g_settings.getS16("viewing_range_nodes_max");\r
1121         \r
1122         draw_control.wanted_min_range = range_min;\r
1123         draw_control.wanted_max_blocks = (1.2*draw_control.blocks_drawn)+1;\r
1124         \r
1125         float block_draw_ratio = 1.0;\r
1126         if(draw_control.blocks_would_have_drawn != 0)\r
1127         {\r
1128                 block_draw_ratio = (float)draw_control.blocks_drawn\r
1129                         / (float)draw_control.blocks_would_have_drawn;\r
1130         }\r
1131 \r
1132         // Calculate the average frametime in the case that all wanted\r
1133         // blocks had been drawn\r
1134         f32 frametime = added_frametime / added_frames / block_draw_ratio;\r
1135         \r
1136         added_frametime = 0.0;\r
1137         added_frames = 0;\r
1138         \r
1139         float wanted_fps = g_settings.getFloat("wanted_fps");\r
1140         float wanted_frametime = 1.0 / wanted_fps;\r
1141         \r
1142         f32 wanted_frametime_change = wanted_frametime - frametime;\r
1143         //dstream<<"wanted_frametime_change="<<wanted_frametime_change<<std::endl;\r
1144         \r
1145         // If needed frametime change is small, just return\r
1146         if(fabs(wanted_frametime_change) < wanted_frametime*0.4)\r
1147         {\r
1148                 //dstream<<"ignoring small wanted_frametime_change"<<std::endl;\r
1149                 return;\r
1150         }\r
1151 \r
1152         float range = draw_control.wanted_range;\r
1153         float new_range = range;\r
1154 \r
1155         static s16 range_old = 0;\r
1156         static f32 frametime_old = 0;\r
1157         \r
1158         float d_range = range - range_old;\r
1159         f32 d_frametime = frametime - frametime_old;\r
1160         // A sane default of 30ms per 50 nodes of range\r
1161         static f32 time_per_range = 30. / 50;\r
1162         if(d_range != 0)\r
1163         {\r
1164                 time_per_range = d_frametime / d_range;\r
1165         }\r
1166         \r
1167         // The minimum allowed calculated frametime-range derivative:\r
1168         // Practically this sets the maximum speed of changing the range.\r
1169         // The lower this value, the higher the maximum changing speed.\r
1170         // A low value here results in wobbly range (0.001)\r
1171         // A high value here results in slow changing range (0.0025)\r
1172         // SUGG: This could be dynamically adjusted so that when\r
1173         //       the camera is turning, this is lower\r
1174         //float min_time_per_range = 0.0015;\r
1175         float min_time_per_range = 0.0010;\r
1176         //float min_time_per_range = 0.05 / range;\r
1177         if(time_per_range < min_time_per_range)\r
1178         {\r
1179                 time_per_range = min_time_per_range;\r
1180                 //dstream<<"time_per_range="<<time_per_range<<" (min)"<<std::endl;\r
1181         }\r
1182         else\r
1183         {\r
1184                 //dstream<<"time_per_range="<<time_per_range<<std::endl;\r
1185         }\r
1186 \r
1187         f32 wanted_range_change = wanted_frametime_change / time_per_range;\r
1188         // Dampen the change a bit to kill oscillations\r
1189         //wanted_range_change *= 0.9;\r
1190         //wanted_range_change *= 0.75;\r
1191         wanted_range_change *= 0.5;\r
1192         //dstream<<"wanted_range_change="<<wanted_range_change<<std::endl;\r
1193 \r
1194         // If needed range change is very small, just return\r
1195         if(fabs(wanted_range_change) < 0.001)\r
1196         {\r
1197                 //dstream<<"ignoring small wanted_range_change"<<std::endl;\r
1198                 return;\r
1199         }\r
1200 \r
1201         new_range += wanted_range_change;\r
1202         //dstream<<"new_range="<<new_range/*<<std::endl*/;\r
1203         \r
1204         //float new_range_unclamped = new_range;\r
1205         if(new_range < range_min)\r
1206                 new_range = range_min;\r
1207         if(new_range > range_max)\r
1208                 new_range = range_max;\r
1209         \r
1210         /*if(new_range != new_range_unclamped)\r
1211                 dstream<<", clamped to "<<new_range<<std::endl;\r
1212         else\r
1213                 dstream<<std::endl;*/\r
1214 \r
1215         draw_control.wanted_range = new_range;\r
1216 \r
1217         range_old = new_range;\r
1218         frametime_old = frametime;\r
1219 }\r
1220 \r
1221 /*\r
1222         Hotbar draw routine\r
1223 */\r
1224 \r
1225 void draw_hotbar(video::IVideoDriver *driver, gui::IGUIFont *font,\r
1226                 v2s32 centerlowerpos, s32 imgsize, s32 itemcount,\r
1227                 Inventory *inventory, s32 halfheartcount)\r
1228 {\r
1229         InventoryList *mainlist = inventory->getList("main");\r
1230         if(mainlist == NULL)\r
1231         {\r
1232                 dstream<<"WARNING: draw_hotbar(): mainlist == NULL"<<std::endl;\r
1233                 return;\r
1234         }\r
1235         \r
1236         s32 padding = imgsize/12;\r
1237         //s32 height = imgsize + padding*2;\r
1238         s32 width = itemcount*(imgsize+padding*2);\r
1239         \r
1240         // Position of upper left corner of bar\r
1241         v2s32 pos = centerlowerpos - v2s32(width/2, imgsize+padding*2);\r
1242         \r
1243         // Draw background color\r
1244         /*core::rect<s32> barrect(0,0,width,height);\r
1245         barrect += pos;\r
1246         video::SColor bgcolor(255,128,128,128);\r
1247         driver->draw2DRectangle(bgcolor, barrect, NULL);*/\r
1248 \r
1249         core::rect<s32> imgrect(0,0,imgsize,imgsize);\r
1250 \r
1251         for(s32 i=0; i<itemcount; i++)\r
1252         {\r
1253                 InventoryItem *item = mainlist->getItem(i);\r
1254                 \r
1255                 core::rect<s32> rect = imgrect + pos\r
1256                                 + v2s32(padding+i*(imgsize+padding*2), padding);\r
1257                 \r
1258                 if(g_selected_item == i)\r
1259                 {\r
1260                         driver->draw2DRectangle(video::SColor(255,255,0,0),\r
1261                                         core::rect<s32>(rect.UpperLeftCorner - v2s32(1,1)*padding,\r
1262                                                         rect.LowerRightCorner + v2s32(1,1)*padding),\r
1263                                         NULL);\r
1264                 }\r
1265                 else\r
1266                 {\r
1267                         video::SColor bgcolor2(128,0,0,0);\r
1268                         driver->draw2DRectangle(bgcolor2, rect, NULL);\r
1269                 }\r
1270 \r
1271                 if(item != NULL)\r
1272                 {\r
1273                         drawInventoryItem(driver, font, item, rect, NULL);\r
1274                 }\r
1275         }\r
1276         \r
1277         /*\r
1278                 Draw hearts\r
1279         */\r
1280         {\r
1281                 video::ITexture *heart_texture =\r
1282                                 driver->getTexture(porting::getDataPath("heart.png").c_str());\r
1283                 v2s32 p = pos + v2s32(0, -20);\r
1284                 for(s32 i=0; i<halfheartcount/2; i++)\r
1285                 {\r
1286                         const video::SColor color(255,255,255,255);\r
1287                         const video::SColor colors[] = {color,color,color,color};\r
1288                         core::rect<s32> rect(0,0,16,16);\r
1289                         rect += p;\r
1290                         driver->draw2DImage(heart_texture, rect,\r
1291                                 core::rect<s32>(core::position2d<s32>(0,0),\r
1292                                 core::dimension2di(heart_texture->getOriginalSize())),\r
1293                                 NULL, colors, true);\r
1294                         p += v2s32(20,0);\r
1295                 }\r
1296                 if(halfheartcount % 2 == 1)\r
1297                 {\r
1298                         const video::SColor color(255,255,255,255);\r
1299                         const video::SColor colors[] = {color,color,color,color};\r
1300                         core::rect<s32> rect(0,0,16/2,16);\r
1301                         rect += p;\r
1302                         core::dimension2di srcd(heart_texture->getOriginalSize());\r
1303                         srcd.Width /= 2;\r
1304                         driver->draw2DImage(heart_texture, rect,\r
1305                                 core::rect<s32>(core::position2d<s32>(0,0), srcd),\r
1306                                 NULL, colors, true);\r
1307                         p += v2s32(20,0);\r
1308                 }\r
1309         }\r
1310 }\r
1311 \r
1312 // Chat data\r
1313 struct ChatLine\r
1314 {\r
1315         ChatLine():\r
1316                 age(0.0)\r
1317         {\r
1318         }\r
1319         ChatLine(const std::wstring &a_text):\r
1320                 age(0.0),\r
1321                 text(a_text)\r
1322         {\r
1323         }\r
1324         float age;\r
1325         std::wstring text;\r
1326 };\r
1327 \r
1328 // These are defined global so that they're not optimized too much.\r
1329 // Can't change them to volatile.\r
1330 s16 temp16;\r
1331 f32 tempf;\r
1332 v3f tempv3f1;\r
1333 v3f tempv3f2;\r
1334 std::string tempstring;\r
1335 std::string tempstring2;\r
1336 \r
1337 void SpeedTests()\r
1338 {\r
1339         {\r
1340                 dstream<<"The following test should take around 20ms."<<std::endl;\r
1341                 TimeTaker timer("Testing std::string speed");\r
1342                 const u32 jj = 10000;\r
1343                 for(u32 j=0; j<jj; j++)\r
1344                 {\r
1345                         tempstring = "";\r
1346                         tempstring2 = "";\r
1347                         const u32 ii = 10;\r
1348                         for(u32 i=0; i<ii; i++){\r
1349                                 tempstring2 += "asd";\r
1350                         }\r
1351                         for(u32 i=0; i<ii+1; i++){\r
1352                                 tempstring += "asd";\r
1353                                 if(tempstring == tempstring2)\r
1354                                         break;\r
1355                         }\r
1356                 }\r
1357         }\r
1358         \r
1359         dstream<<"All of the following tests should take around 100ms each."\r
1360                         <<std::endl;\r
1361 \r
1362         {\r
1363                 TimeTaker timer("Testing floating-point conversion speed");\r
1364                 tempf = 0.001;\r
1365                 for(u32 i=0; i<4000000; i++){\r
1366                         temp16 += tempf;\r
1367                         tempf += 0.001;\r
1368                 }\r
1369         }\r
1370         \r
1371         {\r
1372                 TimeTaker timer("Testing floating-point vector speed");\r
1373 \r
1374                 tempv3f1 = v3f(1,2,3);\r
1375                 tempv3f2 = v3f(4,5,6);\r
1376                 for(u32 i=0; i<10000000; i++){\r
1377                         tempf += tempv3f1.dotProduct(tempv3f2);\r
1378                         tempv3f2 += v3f(7,8,9);\r
1379                 }\r
1380         }\r
1381 \r
1382         {\r
1383                 TimeTaker timer("Testing core::map speed");\r
1384                 \r
1385                 core::map<v2s16, f32> map1;\r
1386                 tempf = -324;\r
1387                 const s16 ii=300;\r
1388                 for(s16 y=0; y<ii; y++){\r
1389                         for(s16 x=0; x<ii; x++){\r
1390                                 map1.insert(v2s16(x,y), tempf);\r
1391                                 tempf += 1;\r
1392                         }\r
1393                 }\r
1394                 for(s16 y=ii-1; y>=0; y--){\r
1395                         for(s16 x=0; x<ii; x++){\r
1396                                 tempf = map1[v2s16(x,y)];\r
1397                         }\r
1398                 }\r
1399         }\r
1400 \r
1401         {\r
1402                 dstream<<"Around 5000/ms should do well here."<<std::endl;\r
1403                 TimeTaker timer("Testing mutex speed");\r
1404                 \r
1405                 JMutex m;\r
1406                 m.Init();\r
1407                 u32 n = 0;\r
1408                 u32 i = 0;\r
1409                 do{\r
1410                         n += 10000;\r
1411                         for(; i<n; i++){\r
1412                                 m.Lock();\r
1413                                 m.Unlock();\r
1414                         }\r
1415                 }\r
1416                 // Do at least 10ms\r
1417                 while(timer.getTime() < 10);\r
1418 \r
1419                 u32 dtime = timer.stop();\r
1420                 u32 per_ms = n / dtime;\r
1421                 std::cout<<"Done. "<<dtime<<"ms, "\r
1422                                 <<per_ms<<"/ms"<<std::endl;\r
1423         }\r
1424 }\r
1425 \r
1426 void getPointedNode(v3f player_position,\r
1427                 v3f camera_direction, v3f camera_position,\r
1428                 bool &nodefound, core::line3d<f32> shootline,\r
1429                 v3s16 &nodepos, v3s16 &neighbourpos,\r
1430                 core::aabbox3d<f32> &nodehilightbox,\r
1431                 f32 d)\r
1432 {\r
1433         assert(g_client);\r
1434 \r
1435         f32 mindistance = BS * 1001;\r
1436         \r
1437         v3s16 pos_i = floatToInt(player_position, BS);\r
1438 \r
1439         /*std::cout<<"pos_i=("<<pos_i.X<<","<<pos_i.Y<<","<<pos_i.Z<<")"\r
1440                         <<std::endl;*/\r
1441 \r
1442         s16 a = d;\r
1443         s16 ystart = pos_i.Y + 0 - (camera_direction.Y<0 ? a : 1);\r
1444         s16 zstart = pos_i.Z - (camera_direction.Z<0 ? a : 1);\r
1445         s16 xstart = pos_i.X - (camera_direction.X<0 ? a : 1);\r
1446         s16 yend = pos_i.Y + 1 + (camera_direction.Y>0 ? a : 1);\r
1447         s16 zend = pos_i.Z + (camera_direction.Z>0 ? a : 1);\r
1448         s16 xend = pos_i.X + (camera_direction.X>0 ? a : 1);\r
1449         \r
1450         for(s16 y = ystart; y <= yend; y++)\r
1451         for(s16 z = zstart; z <= zend; z++)\r
1452         for(s16 x = xstart; x <= xend; x++)\r
1453         {\r
1454                 MapNode n;\r
1455                 try\r
1456                 {\r
1457                         n = g_client->getNode(v3s16(x,y,z));\r
1458                         if(content_pointable(n.d) == false)\r
1459                                 continue;\r
1460                 }\r
1461                 catch(InvalidPositionException &e)\r
1462                 {\r
1463                         continue;\r
1464                 }\r
1465 \r
1466                 v3s16 np(x,y,z);\r
1467                 v3f npf = intToFloat(np, BS);\r
1468                 \r
1469                 f32 d = 0.01;\r
1470                 \r
1471                 v3s16 dirs[6] = {\r
1472                         v3s16(0,0,1), // back\r
1473                         v3s16(0,1,0), // top\r
1474                         v3s16(1,0,0), // right\r
1475                         v3s16(0,0,-1), // front\r
1476                         v3s16(0,-1,0), // bottom\r
1477                         v3s16(-1,0,0), // left\r
1478                 };\r
1479                 \r
1480                 /*\r
1481                         Meta-objects\r
1482                 */\r
1483                 if(n.d == CONTENT_TORCH)\r
1484                 {\r
1485                         v3s16 dir = unpackDir(n.dir);\r
1486                         v3f dir_f = v3f(dir.X, dir.Y, dir.Z);\r
1487                         dir_f *= BS/2 - BS/6 - BS/20;\r
1488                         v3f cpf = npf + dir_f;\r
1489                         f32 distance = (cpf - camera_position).getLength();\r
1490 \r
1491                         core::aabbox3d<f32> box;\r
1492                         \r
1493                         // bottom\r
1494                         if(dir == v3s16(0,-1,0))\r
1495                         {\r
1496                                 box = core::aabbox3d<f32>(\r
1497                                         npf - v3f(BS/6, BS/2, BS/6),\r
1498                                         npf + v3f(BS/6, -BS/2+BS/3*2, BS/6)\r
1499                                 );\r
1500                         }\r
1501                         // top\r
1502                         else if(dir == v3s16(0,1,0))\r
1503                         {\r
1504                                 box = core::aabbox3d<f32>(\r
1505                                         npf - v3f(BS/6, -BS/2+BS/3*2, BS/6),\r
1506                                         npf + v3f(BS/6, BS/2, BS/6)\r
1507                                 );\r
1508                         }\r
1509                         // side\r
1510                         else\r
1511                         {\r
1512                                 box = core::aabbox3d<f32>(\r
1513                                         cpf - v3f(BS/6, BS/3, BS/6),\r
1514                                         cpf + v3f(BS/6, BS/3, BS/6)\r
1515                                 );\r
1516                         }\r
1517 \r
1518                         if(distance < mindistance)\r
1519                         {\r
1520                                 if(box.intersectsWithLine(shootline))\r
1521                                 {\r
1522                                         nodefound = true;\r
1523                                         nodepos = np;\r
1524                                         neighbourpos = np;\r
1525                                         mindistance = distance;\r
1526                                         nodehilightbox = box;\r
1527                                 }\r
1528                         }\r
1529                 }\r
1530                 else if(n.d == CONTENT_SIGN_WALL)\r
1531                 {\r
1532                         v3s16 dir = unpackDir(n.dir);\r
1533                         v3f dir_f = v3f(dir.X, dir.Y, dir.Z);\r
1534                         dir_f *= BS/2 - BS/6 - BS/20;\r
1535                         v3f cpf = npf + dir_f;\r
1536                         f32 distance = (cpf - camera_position).getLength();\r
1537 \r
1538                         v3f vertices[4] =\r
1539                         {\r
1540                                 v3f(BS*0.42,-BS*0.35,-BS*0.4),\r
1541                                 v3f(BS*0.49, BS*0.35, BS*0.4),\r
1542                         };\r
1543 \r
1544                         for(s32 i=0; i<2; i++)\r
1545                         {\r
1546                                 if(dir == v3s16(1,0,0))\r
1547                                         vertices[i].rotateXZBy(0);\r
1548                                 if(dir == v3s16(-1,0,0))\r
1549                                         vertices[i].rotateXZBy(180);\r
1550                                 if(dir == v3s16(0,0,1))\r
1551                                         vertices[i].rotateXZBy(90);\r
1552                                 if(dir == v3s16(0,0,-1))\r
1553                                         vertices[i].rotateXZBy(-90);\r
1554                                 if(dir == v3s16(0,-1,0))\r
1555                                         vertices[i].rotateXYBy(-90);\r
1556                                 if(dir == v3s16(0,1,0))\r
1557                                         vertices[i].rotateXYBy(90);\r
1558 \r
1559                                 vertices[i] += npf;\r
1560                         }\r
1561 \r
1562                         core::aabbox3d<f32> box;\r
1563 \r
1564                         box = core::aabbox3d<f32>(vertices[0]);\r
1565                         box.addInternalPoint(vertices[1]);\r
1566 \r
1567                         if(distance < mindistance)\r
1568                         {\r
1569                                 if(box.intersectsWithLine(shootline))\r
1570                                 {\r
1571                                         nodefound = true;\r
1572                                         nodepos = np;\r
1573                                         neighbourpos = np;\r
1574                                         mindistance = distance;\r
1575                                         nodehilightbox = box;\r
1576                                 }\r
1577                         }\r
1578                 }\r
1579                 /*\r
1580                         Regular blocks\r
1581                 */\r
1582                 else\r
1583                 {\r
1584                         for(u16 i=0; i<6; i++)\r
1585                         {\r
1586                                 v3f dir_f = v3f(dirs[i].X,\r
1587                                                 dirs[i].Y, dirs[i].Z);\r
1588                                 v3f centerpoint = npf + dir_f * BS/2;\r
1589                                 f32 distance =\r
1590                                                 (centerpoint - camera_position).getLength();\r
1591                                 \r
1592                                 if(distance < mindistance)\r
1593                                 {\r
1594                                         core::CMatrix4<f32> m;\r
1595                                         m.buildRotateFromTo(v3f(0,0,1), dir_f);\r
1596 \r
1597                                         // This is the back face\r
1598                                         v3f corners[2] = {\r
1599                                                 v3f(BS/2, BS/2, BS/2),\r
1600                                                 v3f(-BS/2, -BS/2, BS/2+d)\r
1601                                         };\r
1602                                         \r
1603                                         for(u16 j=0; j<2; j++)\r
1604                                         {\r
1605                                                 m.rotateVect(corners[j]);\r
1606                                                 corners[j] += npf;\r
1607                                         }\r
1608 \r
1609                                         core::aabbox3d<f32> facebox(corners[0]);\r
1610                                         facebox.addInternalPoint(corners[1]);\r
1611 \r
1612                                         if(facebox.intersectsWithLine(shootline))\r
1613                                         {\r
1614                                                 nodefound = true;\r
1615                                                 nodepos = np;\r
1616                                                 neighbourpos = np + dirs[i];\r
1617                                                 mindistance = distance;\r
1618 \r
1619                                                 //nodehilightbox = facebox;\r
1620 \r
1621                                                 const float d = 0.502;\r
1622                                                 core::aabbox3d<f32> nodebox\r
1623                                                                 (-BS*d, -BS*d, -BS*d, BS*d, BS*d, BS*d);\r
1624                                                 v3f nodepos_f = intToFloat(nodepos, BS);\r
1625                                                 nodebox.MinEdge += nodepos_f;\r
1626                                                 nodebox.MaxEdge += nodepos_f;\r
1627                                                 nodehilightbox = nodebox;\r
1628                                         }\r
1629                                 } // if distance < mindistance\r
1630                         } // for dirs\r
1631                 } // regular block\r
1632         } // for coords\r
1633 }\r
1634 \r
1635 int main(int argc, char *argv[])\r
1636 {\r
1637         /*\r
1638                 Parse command line\r
1639         */\r
1640         \r
1641         // List all allowed options\r
1642         core::map<std::string, ValueSpec> allowed_options;\r
1643         allowed_options.insert("help", ValueSpec(VALUETYPE_FLAG));\r
1644         allowed_options.insert("server", ValueSpec(VALUETYPE_FLAG,\r
1645                         "Run server directly"));\r
1646         allowed_options.insert("config", ValueSpec(VALUETYPE_STRING,\r
1647                         "Load configuration from specified file"));\r
1648         allowed_options.insert("port", ValueSpec(VALUETYPE_STRING));\r
1649         allowed_options.insert("address", ValueSpec(VALUETYPE_STRING));\r
1650         allowed_options.insert("random-input", ValueSpec(VALUETYPE_FLAG));\r
1651         allowed_options.insert("disable-unittests", ValueSpec(VALUETYPE_FLAG));\r
1652         allowed_options.insert("enable-unittests", ValueSpec(VALUETYPE_FLAG));\r
1653         allowed_options.insert("map-dir", ValueSpec(VALUETYPE_STRING));\r
1654 #ifdef _WIN32\r
1655         allowed_options.insert("dstream-on-stderr", ValueSpec(VALUETYPE_FLAG));\r
1656 #endif\r
1657         allowed_options.insert("speedtests", ValueSpec(VALUETYPE_FLAG));\r
1658 \r
1659         Settings cmd_args;\r
1660         \r
1661         bool ret = cmd_args.parseCommandLine(argc, argv, allowed_options);\r
1662 \r
1663         if(ret == false || cmd_args.getFlag("help"))\r
1664         {\r
1665                 dstream<<"Allowed options:"<<std::endl;\r
1666                 for(core::map<std::string, ValueSpec>::Iterator\r
1667                                 i = allowed_options.getIterator();\r
1668                                 i.atEnd() == false; i++)\r
1669                 {\r
1670                         dstream<<"  --"<<i.getNode()->getKey();\r
1671                         if(i.getNode()->getValue().type == VALUETYPE_FLAG)\r
1672                         {\r
1673                         }\r
1674                         else\r
1675                         {\r
1676                                 dstream<<" <value>";\r
1677                         }\r
1678                         dstream<<std::endl;\r
1679 \r
1680                         if(i.getNode()->getValue().help != NULL)\r
1681                         {\r
1682                                 dstream<<"      "<<i.getNode()->getValue().help\r
1683                                                 <<std::endl;\r
1684                         }\r
1685                 }\r
1686 \r
1687                 return cmd_args.getFlag("help") ? 0 : 1;\r
1688         }\r
1689         \r
1690         /*\r
1691                 Low-level initialization\r
1692         */\r
1693 \r
1694         bool disable_stderr = false;\r
1695 #ifdef _WIN32\r
1696         if(cmd_args.getFlag("dstream-on-stderr") == false)\r
1697                 disable_stderr = true;\r
1698 #endif\r
1699 \r
1700         // Initialize debug streams\r
1701         debugstreams_init(disable_stderr, DEBUGFILE);\r
1702         // Initialize debug stacks\r
1703         debug_stacks_init();\r
1704 \r
1705         DSTACK(__FUNCTION_NAME);\r
1706 \r
1707         porting::signal_handler_init();\r
1708         bool &kill = *porting::signal_handler_killstatus();\r
1709         \r
1710         porting::initializePaths();\r
1711         // Create user data directory\r
1712         fs::CreateDir(porting::path_userdata);\r
1713         \r
1714         // C-style stuff initialization\r
1715         initializeMaterialProperties();\r
1716 \r
1717         // Debug handler\r
1718         BEGIN_DEBUG_EXCEPTION_HANDLER\r
1719 \r
1720         // Print startup message\r
1721         dstream<<DTIME<<"minetest-c55"\r
1722                         " with SER_FMT_VER_HIGHEST="<<(int)SER_FMT_VER_HIGHEST\r
1723                         <<", "<<BUILD_INFO\r
1724                         <<std::endl;\r
1725         \r
1726         /*\r
1727                 Basic initialization\r
1728         */\r
1729 \r
1730         // Initialize default settings\r
1731         set_default_settings();\r
1732         \r
1733         // Set locale. This is for forcing '.' as the decimal point.\r
1734         std::locale::global(std::locale("C"));\r
1735         // This enables printing all characters in bitmap font\r
1736         setlocale(LC_CTYPE, "en_US");\r
1737 \r
1738         // Initialize sockets\r
1739         sockets_init();\r
1740         atexit(sockets_cleanup);\r
1741         \r
1742         /*\r
1743                 Initialization\r
1744         */\r
1745 \r
1746         /*\r
1747                 Read config file\r
1748         */\r
1749         \r
1750         // Path of configuration file in use\r
1751         std::string configpath = "";\r
1752         \r
1753         if(cmd_args.exists("config"))\r
1754         {\r
1755                 bool r = g_settings.readConfigFile(cmd_args.get("config").c_str());\r
1756                 if(r == false)\r
1757                 {\r
1758                         dstream<<"Could not read configuration from \""\r
1759                                         <<cmd_args.get("config")<<"\""<<std::endl;\r
1760                         return 1;\r
1761                 }\r
1762                 configpath = cmd_args.get("config");\r
1763         }\r
1764         else\r
1765         {\r
1766                 core::array<std::string> filenames;\r
1767                 filenames.push_back(porting::path_userdata + "/minetest.conf");\r
1768 #ifdef RUN_IN_PLACE\r
1769                 filenames.push_back(porting::path_userdata + "/../minetest.conf");\r
1770 #endif\r
1771 \r
1772                 for(u32 i=0; i<filenames.size(); i++)\r
1773                 {\r
1774                         bool r = g_settings.readConfigFile(filenames[i].c_str());\r
1775                         if(r)\r
1776                         {\r
1777                                 configpath = filenames[i];\r
1778                                 break;\r
1779                         }\r
1780                 }\r
1781                 \r
1782                 // If no path found, use the first one (menu creates the file)\r
1783                 if(configpath == "")\r
1784                         configpath = filenames[0];\r
1785         }\r
1786 \r
1787         // Initialize random seed\r
1788         srand(time(0));\r
1789         mysrand(time(0));\r
1790 \r
1791         /*\r
1792                 Pre-initialize some stuff with a dummy irrlicht wrapper.\r
1793 \r
1794                 These are needed for unit tests at least.\r
1795         */\r
1796         \r
1797         // Initial call with g_texturesource not set.\r
1798         init_mapnode();\r
1799 \r
1800         /*\r
1801                 Run unit tests\r
1802         */\r
1803 \r
1804         if((ENABLE_TESTS && cmd_args.getFlag("disable-unittests") == false)\r
1805                         || cmd_args.getFlag("enable-unittests") == true)\r
1806         {\r
1807                 run_tests();\r
1808         }\r
1809         \r
1810         /*for(s16 y=-100; y<100; y++)\r
1811         for(s16 x=-100; x<100; x++)\r
1812         {\r
1813                 std::cout<<noise2d_gradient((double)x/10,(double)y/10, 32415)<<std::endl;\r
1814         }\r
1815         return 0;*/\r
1816         \r
1817         /*\r
1818                 Some parameters\r
1819         */\r
1820 \r
1821         // Port\r
1822         u16 port = 30000;\r
1823         if(cmd_args.exists("port"))\r
1824                 port = cmd_args.getU16("port");\r
1825         else if(g_settings.exists("port"))\r
1826                 port = g_settings.getU16("port");\r
1827         \r
1828         // Map directory\r
1829         std::string map_dir = porting::path_userdata+"/map";\r
1830         if(cmd_args.exists("map-dir"))\r
1831                 map_dir = cmd_args.get("map-dir");\r
1832         else if(g_settings.exists("map-dir"))\r
1833                 map_dir = g_settings.get("map-dir");\r
1834         \r
1835         // Run dedicated server if asked to\r
1836         if(cmd_args.getFlag("server"))\r
1837         {\r
1838                 DSTACK("Dedicated server branch");\r
1839 \r
1840                 // Create server\r
1841                 Server server(map_dir.c_str());\r
1842                 server.start(port);\r
1843                 \r
1844                 // Run server\r
1845                 dedicated_server_loop(server, kill);\r
1846 \r
1847                 return 0;\r
1848         }\r
1849 \r
1850         /*\r
1851                 More parameters\r
1852         */\r
1853         \r
1854         // Address to connect to\r
1855         std::string address = "";\r
1856         \r
1857         if(cmd_args.exists("address"))\r
1858         {\r
1859                 address = cmd_args.get("address");\r
1860         }\r
1861         else\r
1862         {\r
1863                 address = g_settings.get("address");\r
1864         }\r
1865         \r
1866         std::string playername = g_settings.get("name");\r
1867 \r
1868         // Resolution selection\r
1869         \r
1870         bool fullscreen = false;\r
1871         u16 screenW = g_settings.getU16("screenW");\r
1872         u16 screenH = g_settings.getU16("screenH");\r
1873 \r
1874         // Determine driver\r
1875 \r
1876         video::E_DRIVER_TYPE driverType;\r
1877         \r
1878         std::string driverstring = g_settings.get("video_driver");\r
1879 \r
1880         if(driverstring == "null")\r
1881                 driverType = video::EDT_NULL;\r
1882         else if(driverstring == "software")\r
1883                 driverType = video::EDT_SOFTWARE;\r
1884         else if(driverstring == "burningsvideo")\r
1885                 driverType = video::EDT_BURNINGSVIDEO;\r
1886         else if(driverstring == "direct3d8")\r
1887                 driverType = video::EDT_DIRECT3D8;\r
1888         else if(driverstring == "direct3d9")\r
1889                 driverType = video::EDT_DIRECT3D9;\r
1890         else if(driverstring == "opengl")\r
1891                 driverType = video::EDT_OPENGL;\r
1892         else\r
1893         {\r
1894                 dstream<<"WARNING: Invalid video_driver specified; defaulting "\r
1895                                 "to opengl"<<std::endl;\r
1896                 driverType = video::EDT_OPENGL;\r
1897         }\r
1898 \r
1899         // create device and exit if creation failed\r
1900 \r
1901         MyEventReceiver receiver;\r
1902 \r
1903         IrrlichtDevice *device;\r
1904         device = createDevice(driverType,\r
1905                         core::dimension2d<u32>(screenW, screenH),\r
1906                         16, fullscreen, false, false, &receiver);\r
1907 \r
1908         if (device == 0)\r
1909                 return 1; // could not create selected driver.\r
1910         \r
1911         g_device = device;\r
1912         TextureSource *texturesource = new TextureSource(device);\r
1913         g_texturesource = texturesource;\r
1914 \r
1915         /*\r
1916                 Speed tests (done after irrlicht is loaded to get timer)\r
1917         */\r
1918         if(cmd_args.getFlag("speedtests"))\r
1919         {\r
1920                 dstream<<"Running speed tests"<<std::endl;\r
1921                 SpeedTests();\r
1922                 return 0;\r
1923         }\r
1924         \r
1925         device->setResizable(true);\r
1926 \r
1927         bool random_input = g_settings.getBool("random_input")\r
1928                         || cmd_args.getFlag("random-input");\r
1929         if(random_input)\r
1930                 g_input = new RandomInputHandler();\r
1931         else\r
1932                 g_input = new RealInputHandler(device, &receiver);\r
1933         \r
1934         /*\r
1935                 Continue initialization\r
1936         */\r
1937 \r
1938         video::IVideoDriver* driver = device->getVideoDriver();\r
1939 \r
1940         /*\r
1941                 This changes the minimum allowed number of vertices in a VBO.\r
1942                 Default is 500.\r
1943         */\r
1944         //driver->setMinHardwareBufferVertexCount(50);\r
1945 \r
1946         scene::ISceneManager* smgr = device->getSceneManager();\r
1947 \r
1948         guienv = device->getGUIEnvironment();\r
1949         gui::IGUISkin* skin = guienv->getSkin();\r
1950         gui::IGUIFont* font = guienv->getFont(porting::getDataPath("fontlucida.png").c_str());\r
1951         if(font)\r
1952                 skin->setFont(font);\r
1953         else\r
1954                 dstream<<"WARNING: Font file was not found."\r
1955                                 " Using default font."<<std::endl;\r
1956         // If font was not found, this will get us one\r
1957         font = skin->getFont();\r
1958         assert(font);\r
1959 \r
1960         u32 text_height = font->getDimension(L"Hello, world!").Height;\r
1961         dstream<<"text_height="<<text_height<<std::endl;\r
1962 \r
1963         //skin->setColor(gui::EGDC_BUTTON_TEXT, video::SColor(255,0,0,0));\r
1964         skin->setColor(gui::EGDC_BUTTON_TEXT, video::SColor(255,255,255,255));\r
1965         //skin->setColor(gui::EGDC_3D_HIGH_LIGHT, video::SColor(0,0,0,0));\r
1966         //skin->setColor(gui::EGDC_3D_SHADOW, video::SColor(0,0,0,0));\r
1967         skin->setColor(gui::EGDC_3D_HIGH_LIGHT, video::SColor(255,0,0,0));\r
1968         skin->setColor(gui::EGDC_3D_SHADOW, video::SColor(255,0,0,0));\r
1969         \r
1970         /*\r
1971                 Preload some textures and stuff\r
1972         */\r
1973 \r
1974         init_content_inventory_texture_paths();\r
1975         init_mapnode(); // Second call with g_texturesource set\r
1976         init_mineral();\r
1977 \r
1978         /*\r
1979                 GUI stuff\r
1980         */\r
1981 \r
1982         /*\r
1983                 We need some kind of a root node to be able to add\r
1984                 custom gui elements directly on the screen.\r
1985                 Otherwise they won't be automatically drawn.\r
1986         */\r
1987         guiroot = guienv->addStaticText(L"",\r
1988                         core::rect<s32>(0, 0, 10000, 10000));\r
1989         \r
1990         // First line of debug text\r
1991         gui::IGUIStaticText *guitext = guienv->addStaticText(\r
1992                         L"",\r
1993                         core::rect<s32>(5, 5, 795, 5+text_height),\r
1994                         false, false);\r
1995         // Second line of debug text\r
1996         gui::IGUIStaticText *guitext2 = guienv->addStaticText(\r
1997                         L"",\r
1998                         core::rect<s32>(5, 5+(text_height+5)*1, 795, (5+text_height)*2),\r
1999                         false, false);\r
2000         \r
2001         // At the middle of the screen\r
2002         // Object infos are shown in this\r
2003         gui::IGUIStaticText *guitext_info = guienv->addStaticText(\r
2004                         L"",\r
2005                         core::rect<s32>(0,0,400,text_height+5) + v2s32(100,200),\r
2006                         false, false);\r
2007         \r
2008         // Chat text\r
2009         gui::IGUIStaticText *guitext_chat = guienv->addStaticText(\r
2010                         L"",\r
2011                         core::rect<s32>(0,0,0,0),\r
2012                         false, false); // Disable word wrap as of now\r
2013                         //false, true);\r
2014         //guitext_chat->setBackgroundColor(video::SColor(96,0,0,0));\r
2015         core::list<ChatLine> chat_lines;\r
2016         \r
2017         /*\r
2018                 If an error occurs, this is set to something and the\r
2019                 menu-game loop is restarted. It is then displayed before\r
2020                 the menu.\r
2021         */\r
2022         std::wstring error_message = L"";\r
2023         \r
2024         /*\r
2025                 Menu-game loop\r
2026         */\r
2027         while(g_device->run() && kill == false)\r
2028         {\r
2029         \r
2030         // This is used for catching disconnects\r
2031         try\r
2032         {\r
2033         \r
2034         /*\r
2035                 Out-of-game menu loop.\r
2036 \r
2037                 Loop quits when menu returns proper parameters.\r
2038         */\r
2039         while(kill == false)\r
2040         {\r
2041                 // Cursor can be non-visible when coming from the game\r
2042                 device->getCursorControl()->setVisible(true);\r
2043                 // Some stuff are left to scene manager when coming from the game\r
2044                 // (map at least?)\r
2045                 smgr->clear();\r
2046                 // Reset or hide the debug gui texts\r
2047                 guitext->setText(L"Minetest-c55");\r
2048                 guitext2->setVisible(false);\r
2049                 guitext_info->setVisible(false);\r
2050                 guitext_chat->setVisible(false);\r
2051                 \r
2052                 // Initialize menu data\r
2053                 MainMenuData menudata;\r
2054                 menudata.address = narrow_to_wide(address);\r
2055                 menudata.name = narrow_to_wide(playername);\r
2056                 menudata.port = narrow_to_wide(itos(port));\r
2057                 menudata.creative_mode = g_settings.getBool("creative_mode");\r
2058 \r
2059                 GUIMainMenu *menu =\r
2060                                 new GUIMainMenu(guienv, guiroot, -1, \r
2061                                         &g_menumgr, &menudata, &g_gamecallback);\r
2062                 menu->allowFocusRemoval(true);\r
2063 \r
2064                 if(error_message != L"")\r
2065                 {\r
2066                         GUIMessageMenu *menu2 =\r
2067                                         new GUIMessageMenu(guienv, guiroot, -1, \r
2068                                                 &g_menumgr, error_message.c_str());\r
2069                         menu2->drop();\r
2070                         error_message = L"";\r
2071                 }\r
2072 \r
2073                 video::IVideoDriver* driver = g_device->getVideoDriver();\r
2074                 \r
2075                 dstream<<"Created main menu"<<std::endl;\r
2076 \r
2077                 while(g_device->run() && kill == false)\r
2078                 {\r
2079                         if(menu->getStatus() == true)\r
2080                                 break;\r
2081 \r
2082                         //driver->beginScene(true, true, video::SColor(255,0,0,0));\r
2083                         driver->beginScene(true, true, video::SColor(255,128,128,128));\r
2084                         guienv->drawAll();\r
2085                         driver->endScene();\r
2086                 }\r
2087                 \r
2088                 // Break out of menu-game loop to shut down cleanly\r
2089                 if(g_device->run() == false || kill == true)\r
2090                         break;\r
2091                 \r
2092                 dstream<<"Dropping main menu"<<std::endl;\r
2093 \r
2094                 menu->drop();\r
2095                 \r
2096                 // Delete map if requested\r
2097                 if(menudata.delete_map)\r
2098                 {\r
2099                         bool r = fs::RecursiveDeleteContent(map_dir);\r
2100                         if(r == false)\r
2101                                 error_message = L"Delete failed";\r
2102                         continue;\r
2103                 }\r
2104 \r
2105                 playername = wide_to_narrow(menudata.name);\r
2106                 address = wide_to_narrow(menudata.address);\r
2107                 int newport = stoi(wide_to_narrow(menudata.port));\r
2108                 if(newport != 0)\r
2109                         port = newport;\r
2110                 //port = stoi(wide_to_narrow(menudata.port));\r
2111                 g_settings.set("creative_mode", itos(menudata.creative_mode));\r
2112                 \r
2113                 // Check for valid parameters, restart menu if invalid.\r
2114                 if(playername == "")\r
2115                 {\r
2116                         error_message = L"Name required.";\r
2117                         continue;\r
2118                 }\r
2119                 \r
2120                 // Save settings\r
2121                 g_settings.set("name", playername);\r
2122                 g_settings.set("address", address);\r
2123                 g_settings.set("port", itos(port));\r
2124                 // Update configuration file\r
2125                 if(configpath != "")\r
2126                         g_settings.updateConfigFile(configpath.c_str());\r
2127         \r
2128                 // Continue to game\r
2129                 break;\r
2130         }\r
2131         \r
2132         // Break out of menu-game loop to shut down cleanly\r
2133         if(g_device->run() == false)\r
2134                 break;\r
2135 \r
2136         /*\r
2137                 Make a scope here so that the client and the server and other\r
2138                 stuff gets removed when disconnected or the irrlicht device\r
2139                 is removed.\r
2140         */\r
2141         {\r
2142 \r
2143         /*\r
2144                 Draw "Loading" screen\r
2145         */\r
2146         const wchar_t *text = L"Loading and connecting...";\r
2147         core::vector2d<s32> center(screenW/2, screenH/2);\r
2148         core::vector2d<s32> textsize(300, text_height);\r
2149         core::rect<s32> textrect(center - textsize/2, center + textsize/2);\r
2150 \r
2151         gui::IGUIStaticText *gui_loadingtext = guienv->addStaticText(\r
2152                         text, textrect, false, false);\r
2153         gui_loadingtext->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);\r
2154 \r
2155         driver->beginScene(true, true, video::SColor(255,0,0,0));\r
2156         guienv->drawAll();\r
2157         driver->endScene();\r
2158 \r
2159         std::cout<<DTIME<<"Creating server and client"<<std::endl;\r
2160         \r
2161         /*\r
2162                 Create server.\r
2163                 SharedPtr will delete it when it goes out of scope.\r
2164         */\r
2165         SharedPtr<Server> server;\r
2166         if(address == ""){\r
2167                 server = new Server(map_dir);\r
2168                 server->start(port);\r
2169         }\r
2170         \r
2171         /*\r
2172                 Create client\r
2173         */\r
2174 \r
2175         Client client(device, playername.c_str(), draw_control);\r
2176                         \r
2177         g_client = &client;\r
2178         \r
2179         Address connect_address(0,0,0,0, port);\r
2180         try{\r
2181                 if(address == "")\r
2182                         //connect_address.Resolve("localhost");\r
2183                         connect_address.setAddress(127,0,0,1);\r
2184                 else\r
2185                         connect_address.Resolve(address.c_str());\r
2186         }\r
2187         catch(ResolveError &e)\r
2188         {\r
2189                 std::cout<<DTIME<<"Couldn't resolve address"<<std::endl;\r
2190                 //return 0;\r
2191                 error_message = L"Couldn't resolve address";\r
2192                 gui_loadingtext->remove();\r
2193                 continue;\r
2194         }\r
2195         \r
2196         dstream<<DTIME<<"Connecting to server at ";\r
2197         connect_address.print(&dstream);\r
2198         dstream<<std::endl;\r
2199         client.connect(connect_address);\r
2200         \r
2201         try{\r
2202                 while(client.connectedAndInitialized() == false)\r
2203                 {\r
2204                         // Update screen\r
2205                         driver->beginScene(true, true, video::SColor(255,0,0,0));\r
2206                         guienv->drawAll();\r
2207                         driver->endScene();\r
2208 \r
2209                         // Update client and server\r
2210 \r
2211                         client.step(0.1);\r
2212 \r
2213                         if(server != NULL)\r
2214                                 server->step(0.1);\r
2215                         \r
2216                         // Delay a bit\r
2217                         sleep_ms(100);\r
2218                 }\r
2219         }\r
2220         catch(con::PeerNotFoundException &e)\r
2221         {\r
2222                 std::cout<<DTIME<<"Timed out."<<std::endl;\r
2223                 //return 0;\r
2224                 error_message = L"Connection timed out.";\r
2225                 gui_loadingtext->remove();\r
2226                 continue;\r
2227         }\r
2228 \r
2229         /*\r
2230                 Create skybox\r
2231         */\r
2232         /*scene::ISceneNode* skybox;\r
2233         skybox = smgr->addSkyBoxSceneNode(\r
2234                 driver->getTexture(porting::getDataPath("skybox2.png").c_str()),\r
2235                 driver->getTexture(porting::getDataPath("skybox3.png").c_str()),\r
2236                 driver->getTexture(porting::getDataPath("skybox1.png").c_str()),\r
2237                 driver->getTexture(porting::getDataPath("skybox1.png").c_str()),\r
2238                 driver->getTexture(porting::getDataPath("skybox1.png").c_str()),\r
2239                 driver->getTexture(porting::getDataPath("skybox1.png").c_str()));*/\r
2240         \r
2241         /*\r
2242                 Create the camera node\r
2243         */\r
2244 \r
2245         scene::ICameraSceneNode* camera = smgr->addCameraSceneNode(\r
2246                 0, // Camera parent\r
2247                 v3f(BS*100, BS*2, BS*100), // Look from\r
2248                 v3f(BS*100+1, BS*2, BS*100), // Look to\r
2249                 -1 // Camera ID\r
2250         );\r
2251 \r
2252         if(camera == NULL)\r
2253                 return 1;\r
2254 \r
2255         //video::SColor skycolor = video::SColor(255,90,140,200);\r
2256         //video::SColor skycolor = video::SColor(255,166,202,244);\r
2257         //video::SColor skycolor = video::SColor(255,120,185,244);\r
2258         video::SColor skycolor = video::SColor(255,140,186,250);\r
2259 \r
2260         camera->setFOV(FOV_ANGLE);\r
2261 \r
2262         // Just so big a value that everything rendered is visible\r
2263         camera->setFarValue(100000*BS);\r
2264         \r
2265         f32 camera_yaw = 0; // "right/left"\r
2266         f32 camera_pitch = 0; // "up/down"\r
2267 \r
2268         /*\r
2269                 Move into game\r
2270         */\r
2271         \r
2272         gui_loadingtext->remove();\r
2273 \r
2274         /*\r
2275                 Add some gui stuff\r
2276         */\r
2277 \r
2278         /*GUIQuickInventory *quick_inventory = new GUIQuickInventory\r
2279                         (guienv, NULL, v2s32(10, 70), 5, &local_inventory);*/\r
2280         /*GUIQuickInventory *quick_inventory = new GUIQuickInventory\r
2281                         (guienv, NULL, v2s32(0, 0), quickinv_itemcount, &local_inventory);*/\r
2282         \r
2283         // Test the text input system\r
2284         /*(new GUITextInputMenu(guienv, guiroot, -1, &g_menumgr,\r
2285                         NULL))->drop();*/\r
2286         /*GUIMessageMenu *menu =\r
2287                         new GUIMessageMenu(guienv, guiroot, -1, \r
2288                                 &g_menumgr,\r
2289                                 L"Asd");\r
2290         menu->drop();*/\r
2291         \r
2292         // Launch pause menu\r
2293         (new GUIPauseMenu(guienv, guiroot, -1, &g_gamecallback,\r
2294                         &g_menumgr))->drop();\r
2295         \r
2296         // Enable texts\r
2297         guitext2->setVisible(true);\r
2298         guitext_info->setVisible(true);\r
2299         guitext_chat->setVisible(true);\r
2300 \r
2301         //s32 guitext_chat_pad_bottom = 70;\r
2302 \r
2303         v2u32 screensize(0,0);\r
2304         v2u32 last_screensize(0,0);\r
2305         \r
2306         /*\r
2307                 Some statistics are collected in these\r
2308         */\r
2309         u32 drawtime = 0;\r
2310         u32 beginscenetime = 0;\r
2311         u32 scenetime = 0;\r
2312         u32 endscenetime = 0;\r
2313         \r
2314         // A test\r
2315         //throw con::PeerNotFoundException("lol");\r
2316 \r
2317         core::list<float> frametime_log;\r
2318 \r
2319         float damage_flash_timer = 0;\r
2320 \r
2321         /*\r
2322                 Main loop\r
2323         */\r
2324 \r
2325         bool first_loop_after_window_activation = true;\r
2326 \r
2327         // Time is in milliseconds\r
2328         // NOTE: getRealTime() causes strange problems in wine (imprecision?)\r
2329         // NOTE: So we have to use getTime() and call run()s between them\r
2330         u32 lasttime = device->getTimer()->getTime();\r
2331 \r
2332         while(device->run() && kill == false)\r
2333         {\r
2334                 if(g_gamecallback.disconnect_requested)\r
2335                 {\r
2336                         g_gamecallback.disconnect_requested = false;\r
2337                         break;\r
2338                 }\r
2339 \r
2340                 /*\r
2341                         Process TextureSource's queue\r
2342                 */\r
2343                 texturesource->processQueue();\r
2344 \r
2345                 /*\r
2346                         Random calculations\r
2347                 */\r
2348                 last_screensize = screensize;\r
2349                 screensize = driver->getScreenSize();\r
2350                 v2s32 displaycenter(screensize.X/2,screensize.Y/2);\r
2351                 //bool screensize_changed = screensize != last_screensize;\r
2352                 \r
2353                 // Hilight boxes collected during the loop and displayed\r
2354                 core::list< core::aabbox3d<f32> > hilightboxes;\r
2355                 \r
2356                 // Info text\r
2357                 std::wstring infotext;\r
2358 \r
2359                 // When screen size changes, update positions and sizes of stuff\r
2360                 /*if(screensize_changed)\r
2361                 {\r
2362                         v2s32 pos(displaycenter.X-((quickinv_itemcount-1)*quickinv_spacing+quickinv_size)/2, screensize.Y-quickinv_spacing);\r
2363                         quick_inventory->updatePosition(pos);\r
2364                 }*/\r
2365 \r
2366                 //TimeTaker //timer1("//timer1");\r
2367                 \r
2368                 // Time of frame without fps limit\r
2369                 float busytime;\r
2370                 u32 busytime_u32;\r
2371                 {\r
2372                         // not using getRealTime is necessary for wine\r
2373                         u32 time = device->getTimer()->getTime();\r
2374                         if(time > lasttime)\r
2375                                 busytime_u32 = time - lasttime;\r
2376                         else\r
2377                                 busytime_u32 = 0;\r
2378                         busytime = busytime_u32 / 1000.0;\r
2379                 }\r
2380 \r
2381                 //std::cout<<"busytime_u32="<<busytime_u32<<std::endl;\r
2382         \r
2383                 // Necessary for device->getTimer()->getTime()\r
2384                 device->run();\r
2385 \r
2386                 /*\r
2387                         Viewing range\r
2388                 */\r
2389                 \r
2390                 updateViewingRange(busytime, &client);\r
2391                 \r
2392                 /*\r
2393                         FPS limiter\r
2394                 */\r
2395 \r
2396                 {\r
2397                         float fps_max = g_settings.getFloat("fps_max");\r
2398                         u32 frametime_min = 1000./fps_max;\r
2399                         \r
2400                         if(busytime_u32 < frametime_min)\r
2401                         {\r
2402                                 u32 sleeptime = frametime_min - busytime_u32;\r
2403                                 device->sleep(sleeptime);\r
2404                         }\r
2405                 }\r
2406 \r
2407                 // Necessary for device->getTimer()->getTime()\r
2408                 device->run();\r
2409 \r
2410                 /*\r
2411                         Time difference calculation\r
2412                 */\r
2413                 f32 dtime; // in seconds\r
2414                 \r
2415                 u32 time = device->getTimer()->getTime();\r
2416                 if(time > lasttime)\r
2417                         dtime = (time - lasttime) / 1000.0;\r
2418                 else\r
2419                         dtime = 0;\r
2420                 lasttime = time;\r
2421 \r
2422                 /*\r
2423                         Log frametime for visualization\r
2424                 */\r
2425                 frametime_log.push_back(dtime);\r
2426                 if(frametime_log.size() > 100)\r
2427                 {\r
2428                         core::list<float>::Iterator i = frametime_log.begin();\r
2429                         frametime_log.erase(i);\r
2430                 }\r
2431 \r
2432                 /*\r
2433                         Visualize frametime in terminal\r
2434                 */\r
2435                 /*for(u32 i=0; i<dtime*400; i++)\r
2436                         std::cout<<"X";\r
2437                 std::cout<<std::endl;*/\r
2438 \r
2439                 /*\r
2440                         Time average and jitter calculation\r
2441                 */\r
2442 \r
2443                 static f32 dtime_avg1 = 0.0;\r
2444                 dtime_avg1 = dtime_avg1 * 0.98 + dtime * 0.02;\r
2445                 f32 dtime_jitter1 = dtime - dtime_avg1;\r
2446 \r
2447                 static f32 dtime_jitter1_max_sample = 0.0;\r
2448                 static f32 dtime_jitter1_max_fraction = 0.0;\r
2449                 {\r
2450                         static f32 jitter1_max = 0.0;\r
2451                         static f32 counter = 0.0;\r
2452                         if(dtime_jitter1 > jitter1_max)\r
2453                                 jitter1_max = dtime_jitter1;\r
2454                         counter += dtime;\r
2455                         if(counter > 0.0)\r
2456                         {\r
2457                                 counter -= 3.0;\r
2458                                 dtime_jitter1_max_sample = jitter1_max;\r
2459                                 dtime_jitter1_max_fraction\r
2460                                                 = dtime_jitter1_max_sample / (dtime_avg1+0.001);\r
2461                                 jitter1_max = 0.0;\r
2462                         }\r
2463                 }\r
2464                 \r
2465                 /*\r
2466                         Busytime average and jitter calculation\r
2467                 */\r
2468 \r
2469                 static f32 busytime_avg1 = 0.0;\r
2470                 busytime_avg1 = busytime_avg1 * 0.98 + busytime * 0.02;\r
2471                 f32 busytime_jitter1 = busytime - busytime_avg1;\r
2472                 \r
2473                 static f32 busytime_jitter1_max_sample = 0.0;\r
2474                 static f32 busytime_jitter1_min_sample = 0.0;\r
2475                 {\r
2476                         static f32 jitter1_max = 0.0;\r
2477                         static f32 jitter1_min = 0.0;\r
2478                         static f32 counter = 0.0;\r
2479                         if(busytime_jitter1 > jitter1_max)\r
2480                                 jitter1_max = busytime_jitter1;\r
2481                         if(busytime_jitter1 < jitter1_min)\r
2482                                 jitter1_min = busytime_jitter1;\r
2483                         counter += dtime;\r
2484                         if(counter > 0.0){\r
2485                                 counter -= 3.0;\r
2486                                 busytime_jitter1_max_sample = jitter1_max;\r
2487                                 busytime_jitter1_min_sample = jitter1_min;\r
2488                                 jitter1_max = 0.0;\r
2489                                 jitter1_min = 0.0;\r
2490                         }\r
2491                 }\r
2492                 \r
2493                 /*\r
2494                         Debug info for client\r
2495                 */\r
2496                 {\r
2497                         static float counter = 0.0;\r
2498                         counter -= dtime;\r
2499                         if(counter < 0)\r
2500                         {\r
2501                                 counter = 30.0;\r
2502                                 client.printDebugInfo(std::cout);\r
2503                         }\r
2504                 }\r
2505 \r
2506                 /*\r
2507                         Input handler step()\r
2508                 */\r
2509                 g_input->step(dtime);\r
2510 \r
2511                 /*\r
2512                         Misc. stuff\r
2513                 */\r
2514 \r
2515                 /*\r
2516                         Player speed control\r
2517                 */\r
2518                 \r
2519                 {\r
2520                         /*bool a_up,\r
2521                         bool a_down,\r
2522                         bool a_left,\r
2523                         bool a_right,\r
2524                         bool a_jump,\r
2525                         bool a_superspeed,\r
2526                         bool a_sneak,\r
2527                         float a_pitch,\r
2528                         float a_yaw*/\r
2529                         PlayerControl control(\r
2530                                 g_input->isKeyDown(irr::KEY_KEY_W),\r
2531                                 g_input->isKeyDown(irr::KEY_KEY_S),\r
2532                                 g_input->isKeyDown(irr::KEY_KEY_A),\r
2533                                 g_input->isKeyDown(irr::KEY_KEY_D),\r
2534                                 g_input->isKeyDown(irr::KEY_SPACE),\r
2535                                 g_input->isKeyDown(irr::KEY_KEY_E),\r
2536                                 g_input->isKeyDown(irr::KEY_LSHIFT)\r
2537                                                 || g_input->isKeyDown(irr::KEY_RSHIFT),\r
2538                                 camera_pitch,\r
2539                                 camera_yaw\r
2540                         );\r
2541                         client.setPlayerControl(control);\r
2542                 }\r
2543                 \r
2544                 /*\r
2545                         Run server\r
2546                 */\r
2547 \r
2548                 if(server != NULL)\r
2549                 {\r
2550                         //TimeTaker timer("server->step(dtime)");\r
2551                         server->step(dtime);\r
2552                 }\r
2553 \r
2554                 /*\r
2555                         Process environment\r
2556                 */\r
2557                 \r
2558                 {\r
2559                         //TimeTaker timer("client.step(dtime)");\r
2560                         client.step(dtime);\r
2561                         //client.step(dtime_avg1);\r
2562                 }\r
2563 \r
2564                 // Read client events\r
2565                 for(;;)\r
2566                 {\r
2567                         ClientEvent event = client.getClientEvent();\r
2568                         if(event.type == CE_NONE)\r
2569                         {\r
2570                                 break;\r
2571                         }\r
2572                         else if(event.type == CE_PLAYER_DAMAGE)\r
2573                         {\r
2574                                 //u16 damage = event.player_damage.amount;\r
2575                                 //dstream<<"Player damage: "<<damage<<std::endl;\r
2576                                 damage_flash_timer = 0.05;\r
2577                         }\r
2578                         else if(event.type == CE_PLAYER_FORCE_MOVE)\r
2579                         {\r
2580                                 camera_yaw = event.player_force_move.yaw;\r
2581                                 camera_pitch = event.player_force_move.pitch;\r
2582                         }\r
2583                 }\r
2584                 \r
2585                 // Get player position\r
2586                 v3f player_position = client.getPlayerPosition();\r
2587                 \r
2588                 //TimeTaker //timer2("//timer2");\r
2589 \r
2590                 /*\r
2591                         Mouse and camera control\r
2592                 */\r
2593                 \r
2594                 if((device->isWindowActive() && noMenuActive()) || random_input)\r
2595                 {\r
2596                         if(!random_input)\r
2597                                 device->getCursorControl()->setVisible(false);\r
2598 \r
2599                         if(first_loop_after_window_activation){\r
2600                                 //std::cout<<"window active, first loop"<<std::endl;\r
2601                                 first_loop_after_window_activation = false;\r
2602                         }\r
2603                         else{\r
2604                                 s32 dx = g_input->getMousePos().X - displaycenter.X;\r
2605                                 s32 dy = g_input->getMousePos().Y - displaycenter.Y;\r
2606                                 //std::cout<<"window active, pos difference "<<dx<<","<<dy<<std::endl;\r
2607                                 camera_yaw -= dx*0.2;\r
2608                                 camera_pitch += dy*0.2;\r
2609                                 if(camera_pitch < -89.5) camera_pitch = -89.5;\r
2610                                 if(camera_pitch > 89.5) camera_pitch = 89.5;\r
2611                         }\r
2612                         g_input->setMousePos(displaycenter.X, displaycenter.Y);\r
2613                 }\r
2614                 else{\r
2615                         device->getCursorControl()->setVisible(true);\r
2616 \r
2617                         //std::cout<<"window inactive"<<std::endl;\r
2618                         first_loop_after_window_activation = true;\r
2619                 }\r
2620 \r
2621                 camera_yaw = wrapDegrees(camera_yaw);\r
2622                 camera_pitch = wrapDegrees(camera_pitch);\r
2623                 \r
2624                 v3f camera_direction = v3f(0,0,1);\r
2625                 camera_direction.rotateYZBy(camera_pitch);\r
2626                 camera_direction.rotateXZBy(camera_yaw);\r
2627                 \r
2628                 // This is at the height of the eyes of the current figure\r
2629                 //v3f camera_position = player_position + v3f(0, BS+BS/2, 0);\r
2630                 // This is more like in minecraft\r
2631                 v3f camera_position = player_position + v3f(0, BS+BS*0.625, 0);\r
2632 \r
2633                 camera->setPosition(camera_position);\r
2634                 // *100.0 helps in large map coordinates\r
2635                 camera->setTarget(camera_position + camera_direction * 100.0);\r
2636 \r
2637                 if(FIELD_OF_VIEW_TEST){\r
2638                         client.updateCamera(v3f(0,0,0), v3f(0,0,1));\r
2639                 }\r
2640                 else{\r
2641                         //TimeTaker timer("client.updateCamera");\r
2642                         client.updateCamera(camera_position, camera_direction);\r
2643                 }\r
2644                 \r
2645                 //timer2.stop();\r
2646                 //TimeTaker //timer3("//timer3");\r
2647 \r
2648                 /*\r
2649                         Calculate what block is the crosshair pointing to\r
2650                 */\r
2651                 \r
2652                 //u32 t1 = device->getTimer()->getRealTime();\r
2653                 \r
2654                 //f32 d = 4; // max. distance\r
2655                 f32 d = 4; // max. distance\r
2656                 core::line3d<f32> shootline(camera_position,\r
2657                                 camera_position + camera_direction * BS * (d+1));\r
2658 \r
2659                 MapBlockObject *selected_object = client.getSelectedObject\r
2660                                 (d*BS, camera_position, shootline);\r
2661 \r
2662                 ClientActiveObject *selected_active_object\r
2663                                 = client.getSelectedActiveObject\r
2664                                         (d*BS, camera_position, shootline);\r
2665 \r
2666                 if(selected_object != NULL)\r
2667                 {\r
2668                         //dstream<<"Client returned selected_object != NULL"<<std::endl;\r
2669 \r
2670                         core::aabbox3d<f32> box_on_map\r
2671                                         = selected_object->getSelectionBoxOnMap();\r
2672 \r
2673                         hilightboxes.push_back(box_on_map);\r
2674 \r
2675                         infotext = narrow_to_wide(selected_object->infoText());\r
2676 \r
2677                         if(g_input->getLeftClicked())\r
2678                         {\r
2679                                 std::cout<<DTIME<<"Left-clicked object"<<std::endl;\r
2680                                 client.clickObject(0, selected_object->getBlock()->getPos(),\r
2681                                                 selected_object->getId(), g_selected_item);\r
2682                         }\r
2683                         else if(g_input->getRightClicked())\r
2684                         {\r
2685                                 std::cout<<DTIME<<"Right-clicked object"<<std::endl;\r
2686                                 /*\r
2687                                         Check if we want to modify the object ourselves\r
2688                                 */\r
2689                                 if(selected_object->getTypeId() == MAPBLOCKOBJECT_TYPE_SIGN)\r
2690                                 {\r
2691                                         dstream<<"Sign object right-clicked"<<std::endl;\r
2692                                         \r
2693                                         if(random_input == false)\r
2694                                         {\r
2695                                                 // Get a new text for it\r
2696 \r
2697                                                 TextDest *dest = new TextDestSign(\r
2698                                                                 selected_object->getBlock()->getPos(),\r
2699                                                                 selected_object->getId(),\r
2700                                                                 &client);\r
2701 \r
2702                                                 SignObject *sign_object = (SignObject*)selected_object;\r
2703 \r
2704                                                 std::wstring wtext =\r
2705                                                                 narrow_to_wide(sign_object->getText());\r
2706 \r
2707                                                 (new GUITextInputMenu(guienv, guiroot, -1,\r
2708                                                                 &g_menumgr, dest,\r
2709                                                                 wtext))->drop();\r
2710                                         }\r
2711                                 }\r
2712                                 /*\r
2713                                         Otherwise pass the event to the server as-is\r
2714                                 */\r
2715                                 else\r
2716                                 {\r
2717                                         client.clickObject(1, selected_object->getBlock()->getPos(),\r
2718                                                         selected_object->getId(), g_selected_item);\r
2719                                 }\r
2720                         }\r
2721                 }\r
2722                 else if(selected_active_object != NULL)\r
2723                 {\r
2724                         //dstream<<"Client returned selected_active_object != NULL"<<std::endl;\r
2725                         \r
2726                         core::aabbox3d<f32> *selection_box\r
2727                                         = selected_active_object->getSelectionBox();\r
2728                         // Box should exist because object was returned in the\r
2729                         // first place\r
2730                         assert(selection_box);\r
2731 \r
2732                         v3f pos = selected_active_object->getPosition();\r
2733 \r
2734                         core::aabbox3d<f32> box_on_map(\r
2735                                         selection_box->MinEdge + pos,\r
2736                                         selection_box->MaxEdge + pos\r
2737                         );\r
2738 \r
2739                         hilightboxes.push_back(box_on_map);\r
2740 \r
2741                         //infotext = narrow_to_wide("A ClientActiveObject");\r
2742                         infotext = narrow_to_wide(selected_active_object->infoText());\r
2743 \r
2744                         if(g_input->getLeftClicked())\r
2745                         {\r
2746                                 std::cout<<DTIME<<"Left-clicked object"<<std::endl;\r
2747                                 client.clickActiveObject(0,\r
2748                                                 selected_active_object->getId(), g_selected_item);\r
2749                         }\r
2750                         else if(g_input->getRightClicked())\r
2751                         {\r
2752                                 std::cout<<DTIME<<"Right-clicked object"<<std::endl;\r
2753                         }\r
2754                 }\r
2755                 else // selected_object == NULL\r
2756                 {\r
2757 \r
2758                 /*\r
2759                         Find out which node we are pointing at\r
2760                 */\r
2761                 \r
2762                 bool nodefound = false;\r
2763                 v3s16 nodepos;\r
2764                 v3s16 neighbourpos;\r
2765                 core::aabbox3d<f32> nodehilightbox;\r
2766 \r
2767                 getPointedNode(player_position,\r
2768                                 camera_direction, camera_position,\r
2769                                 nodefound, shootline,\r
2770                                 nodepos, neighbourpos,\r
2771                                 nodehilightbox, d);\r
2772         \r
2773                 static float nodig_delay_counter = 0.0;\r
2774 \r
2775                 if(nodefound)\r
2776                 {\r
2777                         static v3s16 nodepos_old(-32768,-32768,-32768);\r
2778 \r
2779                         static float dig_time = 0.0;\r
2780                         static u16 dig_index = 0;\r
2781                         \r
2782                         /*\r
2783                                 Visualize selection\r
2784                         */\r
2785 \r
2786                         hilightboxes.push_back(nodehilightbox);\r
2787 \r
2788                         /*\r
2789                                 Check information text of node\r
2790                         */\r
2791 \r
2792                         NodeMetadata *meta = client.getNodeMetadata(nodepos);\r
2793                         if(meta)\r
2794                         {\r
2795                                 infotext = narrow_to_wide(meta->infoText());\r
2796                         }\r
2797                         \r
2798                         //MapNode node = client.getNode(nodepos);\r
2799 \r
2800                         /*\r
2801                                 Handle digging\r
2802                         */\r
2803                         \r
2804                         if(g_input->getLeftReleased())\r
2805                         {\r
2806                                 client.clearTempMod(nodepos);\r
2807                                 dig_time = 0.0;\r
2808                         }\r
2809                         \r
2810                         if(nodig_delay_counter > 0.0)\r
2811                         {\r
2812                                 nodig_delay_counter -= dtime;\r
2813                         }\r
2814                         else\r
2815                         {\r
2816                                 if(nodepos != nodepos_old)\r
2817                                 {\r
2818                                         std::cout<<DTIME<<"Pointing at ("<<nodepos.X<<","\r
2819                                                         <<nodepos.Y<<","<<nodepos.Z<<")"<<std::endl;\r
2820 \r
2821                                         if(nodepos_old != v3s16(-32768,-32768,-32768))\r
2822                                         {\r
2823                                                 client.clearTempMod(nodepos_old);\r
2824                                                 dig_time = 0.0;\r
2825                                         }\r
2826                                 }\r
2827 \r
2828                                 if(g_input->getLeftClicked() ||\r
2829                                                 (g_input->getLeftState() && nodepos != nodepos_old))\r
2830                                 {\r
2831                                         dstream<<DTIME<<"Started digging"<<std::endl;\r
2832                                         client.groundAction(0, nodepos, neighbourpos, g_selected_item);\r
2833                                 }\r
2834                                 if(g_input->getLeftClicked())\r
2835                                 {\r
2836                                         client.setTempMod(nodepos, NodeMod(NODEMOD_CRACK, 0));\r
2837                                 }\r
2838                                 if(g_input->getLeftState())\r
2839                                 {\r
2840                                         MapNode n = client.getNode(nodepos);\r
2841                                 \r
2842                                         // Get tool name. Default is "" = bare hands\r
2843                                         std::string toolname = "";\r
2844                                         InventoryList *mlist = local_inventory.getList("main");\r
2845                                         if(mlist != NULL)\r
2846                                         {\r
2847                                                 InventoryItem *item = mlist->getItem(g_selected_item);\r
2848                                                 if(item && (std::string)item->getName() == "ToolItem")\r
2849                                                 {\r
2850                                                         ToolItem *titem = (ToolItem*)item;\r
2851                                                         toolname = titem->getToolName();\r
2852                                                 }\r
2853                                         }\r
2854 \r
2855                                         // Get digging properties for material and tool\r
2856                                         u8 material = n.d;\r
2857                                         DiggingProperties prop =\r
2858                                                         getDiggingProperties(material, toolname);\r
2859                                         \r
2860                                         float dig_time_complete = 0.0;\r
2861 \r
2862                                         if(prop.diggable == false)\r
2863                                         {\r
2864                                                 /*dstream<<"Material "<<(int)material\r
2865                                                                 <<" not diggable with \""\r
2866                                                                 <<toolname<<"\""<<std::endl;*/\r
2867                                                 // I guess nobody will wait for this long\r
2868                                                 dig_time_complete = 10000000.0;\r
2869                                         }\r
2870                                         else\r
2871                                         {\r
2872                                                 dig_time_complete = prop.time;\r
2873                                         }\r
2874                                         \r
2875                                         if(dig_time_complete >= 0.001)\r
2876                                         {\r
2877                                                 dig_index = (u16)((float)CRACK_ANIMATION_LENGTH\r
2878                                                                 * dig_time/dig_time_complete);\r
2879                                         }\r
2880                                         // This is for torches\r
2881                                         else\r
2882                                         {\r
2883                                                 dig_index = CRACK_ANIMATION_LENGTH;\r
2884                                         }\r
2885 \r
2886                                         if(dig_index < CRACK_ANIMATION_LENGTH)\r
2887                                         {\r
2888                                                 //TimeTaker timer("client.setTempMod");\r
2889                                                 //dstream<<"dig_index="<<dig_index<<std::endl;\r
2890                                                 client.setTempMod(nodepos, NodeMod(NODEMOD_CRACK, dig_index));\r
2891                                         }\r
2892                                         else\r
2893                                         {\r
2894                                                 dstream<<DTIME<<"Digging completed"<<std::endl;\r
2895                                                 client.groundAction(3, nodepos, neighbourpos, g_selected_item);\r
2896                                                 client.clearTempMod(nodepos);\r
2897                                                 client.removeNode(nodepos);\r
2898 \r
2899                                                 dig_time = 0;\r
2900 \r
2901                                                 nodig_delay_counter = dig_time_complete\r
2902                                                                 / (float)CRACK_ANIMATION_LENGTH;\r
2903 \r
2904                                                 // We don't want a corresponding delay to\r
2905                                                 // very time consuming nodes\r
2906                                                 if(nodig_delay_counter > 0.5)\r
2907                                                 {\r
2908                                                         nodig_delay_counter = 0.5;\r
2909                                                 }\r
2910                                                 // We want a slight delay to very little\r
2911                                                 // time consuming nodes\r
2912                                                 float mindelay = 0.15;\r
2913                                                 if(nodig_delay_counter < mindelay)\r
2914                                                 {\r
2915                                                         nodig_delay_counter = mindelay;\r
2916                                                 }\r
2917                                         }\r
2918 \r
2919                                         dig_time += dtime;\r
2920                                 }\r
2921                         }\r
2922                         \r
2923                         if(g_input->getRightClicked())\r
2924                         {\r
2925                                 std::cout<<DTIME<<"Ground right-clicked"<<std::endl;\r
2926                                 \r
2927                                 if(meta && meta->typeId() == CONTENT_SIGN_WALL && !random_input)\r
2928                                 {\r
2929                                         dstream<<"Sign node right-clicked"<<std::endl;\r
2930                                         \r
2931                                         SignNodeMetadata *signmeta = (SignNodeMetadata*)meta;\r
2932                                         \r
2933                                         // Get a new text for it\r
2934 \r
2935                                         TextDest *dest = new TextDestSignNode(nodepos, &client);\r
2936 \r
2937                                         std::wstring wtext =\r
2938                                                         narrow_to_wide(signmeta->getText());\r
2939 \r
2940                                         (new GUITextInputMenu(guienv, guiroot, -1,\r
2941                                                         &g_menumgr, dest,\r
2942                                                         wtext))->drop();\r
2943                                 }\r
2944                                 else if(meta && meta->typeId() == CONTENT_CHEST && !random_input)\r
2945                                 {\r
2946                                         dstream<<"Chest node right-clicked"<<std::endl;\r
2947                                         \r
2948                                         //ChestNodeMetadata *chestmeta = (ChestNodeMetadata*)meta;\r
2949 \r
2950                                         std::string chest_inv_id;\r
2951                                         chest_inv_id += "nodemeta:";\r
2952                                         chest_inv_id += itos(nodepos.X);\r
2953                                         chest_inv_id += ",";\r
2954                                         chest_inv_id += itos(nodepos.Y);\r
2955                                         chest_inv_id += ",";\r
2956                                         chest_inv_id += itos(nodepos.Z);\r
2957                                         \r
2958                                         GUIInventoryMenu *menu =\r
2959                                                 new GUIInventoryMenu(guienv, guiroot, -1,\r
2960                                                         &g_menumgr, v2s16(8,9),\r
2961                                                         g_client->getInventoryContext(),\r
2962                                                         g_client);\r
2963 \r
2964                                         core::array<GUIInventoryMenu::DrawSpec> draw_spec;\r
2965                                         \r
2966                                         draw_spec.push_back(GUIInventoryMenu::DrawSpec(\r
2967                                                         "list", chest_inv_id, "0",\r
2968                                                         v2s32(0, 0), v2s32(8, 4)));\r
2969                                         draw_spec.push_back(GUIInventoryMenu::DrawSpec(\r
2970                                                         "list", "current_player", "main",\r
2971                                                         v2s32(0, 5), v2s32(8, 4)));\r
2972 \r
2973                                         menu->setDrawSpec(draw_spec);\r
2974 \r
2975                                         menu->drop();\r
2976 \r
2977                                 }\r
2978                                 else if(meta && meta->typeId() == CONTENT_FURNACE && !random_input)\r
2979                                 {\r
2980                                         dstream<<"Furnace node right-clicked"<<std::endl;\r
2981                                         \r
2982                                         GUIFurnaceMenu *menu =\r
2983                                                 new GUIFurnaceMenu(guienv, guiroot, -1,\r
2984                                                         &g_menumgr, nodepos, g_client);\r
2985 \r
2986                                         menu->drop();\r
2987 \r
2988                                 }\r
2989                                 else\r
2990                                 {\r
2991                                         client.groundAction(1, nodepos, neighbourpos, g_selected_item);\r
2992                                 }\r
2993                         }\r
2994                         \r
2995                         nodepos_old = nodepos;\r
2996                 }\r
2997                 else{\r
2998                 }\r
2999 \r
3000                 } // selected_object == NULL\r
3001                 \r
3002                 g_input->resetLeftClicked();\r
3003                 g_input->resetRightClicked();\r
3004                 \r
3005                 if(g_input->getLeftReleased())\r
3006                 {\r
3007                         std::cout<<DTIME<<"Left button released (stopped digging)"\r
3008                                         <<std::endl;\r
3009                         client.groundAction(2, v3s16(0,0,0), v3s16(0,0,0), 0);\r
3010                 }\r
3011                 if(g_input->getRightReleased())\r
3012                 {\r
3013                         //std::cout<<DTIME<<"Right released"<<std::endl;\r
3014                         // Nothing here\r
3015                 }\r
3016                 \r
3017                 g_input->resetLeftReleased();\r
3018                 g_input->resetRightReleased();\r
3019                 \r
3020                 /*\r
3021                         Calculate stuff for drawing\r
3022                 */\r
3023 \r
3024                 camera->setAspectRatio((f32)screensize.X / (f32)screensize.Y);\r
3025                 \r
3026                 u32 daynight_ratio = client.getDayNightRatio();\r
3027                 u8 l = decode_light((daynight_ratio * LIGHT_SUN) / 1000);\r
3028                 video::SColor bgcolor = video::SColor(\r
3029                                 255,\r
3030                                 skycolor.getRed() * l / 255,\r
3031                                 skycolor.getGreen() * l / 255,\r
3032                                 skycolor.getBlue() * l / 255);\r
3033 \r
3034                 /*\r
3035                         Fog\r
3036                 */\r
3037                 \r
3038                 if(g_settings.getBool("enable_fog") == true)\r
3039                 {\r
3040                         //f32 range = draw_control.wanted_range * BS + MAP_BLOCKSIZE/2*BS;\r
3041                         f32 range = draw_control.wanted_range * BS + 0.8*MAP_BLOCKSIZE*BS;\r
3042                         //f32 range = draw_control.wanted_range * BS + 0.0*MAP_BLOCKSIZE*BS;\r
3043                         if(draw_control.range_all)\r
3044                                 range = 100000*BS;\r
3045 \r
3046                         driver->setFog(\r
3047                                 bgcolor,\r
3048                                 video::EFT_FOG_LINEAR,\r
3049                                 range*0.4,\r
3050                                 range*1.0,\r
3051                                 0.01,\r
3052                                 false, // pixel fog\r
3053                                 false // range fog\r
3054                         );\r
3055                 }\r
3056                 else\r
3057                 {\r
3058                         driver->setFog(\r
3059                                 bgcolor,\r
3060                                 video::EFT_FOG_LINEAR,\r
3061                                 100000*BS,\r
3062                                 110000*BS,\r
3063                                 0.01,\r
3064                                 false, // pixel fog\r
3065                                 false // range fog\r
3066                         );\r
3067                 }\r
3068 \r
3069 \r
3070                 /*\r
3071                         Update gui stuff (0ms)\r
3072                 */\r
3073 \r
3074                 //TimeTaker guiupdatetimer("Gui updating");\r
3075                 \r
3076                 {\r
3077                         static float drawtime_avg = 0;\r
3078                         drawtime_avg = drawtime_avg * 0.95 + (float)drawtime*0.05;\r
3079                         static float beginscenetime_avg = 0;\r
3080                         beginscenetime_avg = beginscenetime_avg * 0.95 + (float)beginscenetime*0.05;\r
3081                         static float scenetime_avg = 0;\r
3082                         scenetime_avg = scenetime_avg * 0.95 + (float)scenetime*0.05;\r
3083                         static float endscenetime_avg = 0;\r
3084                         endscenetime_avg = endscenetime_avg * 0.95 + (float)endscenetime*0.05;\r
3085                         \r
3086                         char temptext[300];\r
3087                         snprintf(temptext, 300, "Minetest-c55 ("\r
3088                                         "F: item=%i"\r
3089                                         ", R: range_all=%i"\r
3090                                         ")"\r
3091                                         " drawtime=%.0f, beginscenetime=%.0f"\r
3092                                         ", scenetime=%.0f, endscenetime=%.0f",\r
3093                                         g_selected_item,\r
3094                                         draw_control.range_all,\r
3095                                         drawtime_avg,\r
3096                                         beginscenetime_avg,\r
3097                                         scenetime_avg,\r
3098                                         endscenetime_avg\r
3099                                         );\r
3100                         \r
3101                         guitext->setText(narrow_to_wide(temptext).c_str());\r
3102                 }\r
3103                 \r
3104                 {\r
3105                         char temptext[300];\r
3106                         snprintf(temptext, 300,\r
3107                                         "(% .1f, % .1f, % .1f)"\r
3108                                         " (% .3f < btime_jitter < % .3f"\r
3109                                         ", dtime_jitter = % .1f %%"\r
3110                                         ", v_range = %.1f)",\r
3111                                         player_position.X/BS,\r
3112                                         player_position.Y/BS,\r
3113                                         player_position.Z/BS,\r
3114                                         busytime_jitter1_min_sample,\r
3115                                         busytime_jitter1_max_sample,\r
3116                                         dtime_jitter1_max_fraction * 100.0,\r
3117                                         draw_control.wanted_range\r
3118                                         );\r
3119 \r
3120                         guitext2->setText(narrow_to_wide(temptext).c_str());\r
3121                 }\r
3122                 \r
3123                 {\r
3124                         guitext_info->setText(infotext.c_str());\r
3125                 }\r
3126                 \r
3127                 /*\r
3128                         Get chat messages from client\r
3129                 */\r
3130                 {\r
3131                         // Get new messages\r
3132                         std::wstring message;\r
3133                         while(client.getChatMessage(message))\r
3134                         {\r
3135                                 chat_lines.push_back(ChatLine(message));\r
3136                                 /*if(chat_lines.size() > 6)\r
3137                                 {\r
3138                                         core::list<ChatLine>::Iterator\r
3139                                                         i = chat_lines.begin();\r
3140                                         chat_lines.erase(i);\r
3141                                 }*/\r
3142                         }\r
3143                         // Append them to form the whole static text and throw\r
3144                         // it to the gui element\r
3145                         std::wstring whole;\r
3146                         // This will correspond to the line number counted from\r
3147                         // top to bottom, from size-1 to 0\r
3148                         s16 line_number = chat_lines.size();\r
3149                         // Count of messages to be removed from the top\r
3150                         u16 to_be_removed_count = 0;\r
3151                         for(core::list<ChatLine>::Iterator\r
3152                                         i = chat_lines.begin();\r
3153                                         i != chat_lines.end(); i++)\r
3154                         {\r
3155                                 // After this, line number is valid for this loop\r
3156                                 line_number--;\r
3157                                 // Increment age\r
3158                                 (*i).age += dtime;\r
3159                                 /*\r
3160                                         This results in a maximum age of 60*6 to the\r
3161                                         lowermost line and a maximum of 6 lines\r
3162                                 */\r
3163                                 float allowed_age = (6-line_number) * 60.0;\r
3164 \r
3165                                 if((*i).age > allowed_age)\r
3166                                 {\r
3167                                         to_be_removed_count++;\r
3168                                         continue;\r
3169                                 }\r
3170                                 whole += (*i).text + L'\n';\r
3171                         }\r
3172                         for(u16 i=0; i<to_be_removed_count; i++)\r
3173                         {\r
3174                                 core::list<ChatLine>::Iterator\r
3175                                                 it = chat_lines.begin();\r
3176                                 chat_lines.erase(it);\r
3177                         }\r
3178                         guitext_chat->setText(whole.c_str());\r
3179 \r
3180                         // Update gui element size and position\r
3181 \r
3182                         /*core::rect<s32> rect(\r
3183                                         10,\r
3184                                         screensize.Y - guitext_chat_pad_bottom\r
3185                                                         - text_height*chat_lines.size(),\r
3186                                         screensize.X - 10,\r
3187                                         screensize.Y - guitext_chat_pad_bottom\r
3188                         );*/\r
3189                         core::rect<s32> rect(\r
3190                                         10,\r
3191                                         50,\r
3192                                         screensize.X - 10,\r
3193                                         50 + text_height*chat_lines.size()\r
3194                         );\r
3195 \r
3196                         guitext_chat->setRelativePosition(rect);\r
3197 \r
3198                         if(chat_lines.size() == 0)\r
3199                                 guitext_chat->setVisible(false);\r
3200                         else\r
3201                                 guitext_chat->setVisible(true);\r
3202                 }\r
3203 \r
3204                 /*\r
3205                         Inventory\r
3206                 */\r
3207                 \r
3208                 static u16 old_selected_item = 65535;\r
3209                 if(client.getLocalInventoryUpdated()\r
3210                                 || g_selected_item != old_selected_item)\r
3211                 {\r
3212                         old_selected_item = g_selected_item;\r
3213                         //std::cout<<"Updating local inventory"<<std::endl;\r
3214                         client.getLocalInventory(local_inventory);\r
3215                 }\r
3216                 \r
3217                 /*\r
3218                         Send actions returned by the inventory menu\r
3219                 */\r
3220                 while(inventory_action_queue.size() != 0)\r
3221                 {\r
3222                         InventoryAction *a = inventory_action_queue.pop_front();\r
3223 \r
3224                         client.sendInventoryAction(a);\r
3225                         // Eat it\r
3226                         delete a;\r
3227                 }\r
3228 \r
3229                 /*\r
3230                         Drawing begins\r
3231                 */\r
3232 \r
3233                 TimeTaker drawtimer("Drawing");\r
3234 \r
3235                 \r
3236                 {\r
3237                         TimeTaker timer("beginScene");\r
3238                         driver->beginScene(true, true, bgcolor);\r
3239                         //driver->beginScene(false, true, bgcolor);\r
3240                         beginscenetime = timer.stop(true);\r
3241                 }\r
3242 \r
3243                 //timer3.stop();\r
3244                 \r
3245                 //std::cout<<DTIME<<"smgr->drawAll()"<<std::endl;\r
3246                 \r
3247                 {\r
3248                         TimeTaker timer("smgr");\r
3249                         smgr->drawAll();\r
3250                         scenetime = timer.stop(true);\r
3251                 }\r
3252                 \r
3253                 {\r
3254                 //TimeTaker timer9("auxiliary drawings");\r
3255                 // 0ms\r
3256                 \r
3257                 //timer9.stop();\r
3258                 //TimeTaker //timer10("//timer10");\r
3259                 \r
3260                 video::SMaterial m;\r
3261                 //m.Thickness = 10;\r
3262                 m.Thickness = 3;\r
3263                 m.Lighting = false;\r
3264                 driver->setMaterial(m);\r
3265 \r
3266                 driver->setTransform(video::ETS_WORLD, core::IdentityMatrix);\r
3267 \r
3268                 for(core::list< core::aabbox3d<f32> >::Iterator i=hilightboxes.begin();\r
3269                                 i != hilightboxes.end(); i++)\r
3270                 {\r
3271                         /*std::cout<<"hilightbox min="\r
3272                                         <<"("<<i->MinEdge.X<<","<<i->MinEdge.Y<<","<<i->MinEdge.Z<<")"\r
3273                                         <<" max="\r
3274                                         <<"("<<i->MaxEdge.X<<","<<i->MaxEdge.Y<<","<<i->MaxEdge.Z<<")"\r
3275                                         <<std::endl;*/\r
3276                         driver->draw3DBox(*i, video::SColor(255,0,0,0));\r
3277                 }\r
3278 \r
3279                 /*\r
3280                         Frametime log\r
3281                 */\r
3282                 if(g_settings.getBool("frametime_graph") == true)\r
3283                 {\r
3284                         s32 x = 10;\r
3285                         for(core::list<float>::Iterator\r
3286                                         i = frametime_log.begin();\r
3287                                         i != frametime_log.end();\r
3288                                         i++)\r
3289                         {\r
3290                                 driver->draw2DLine(v2s32(x,50),\r
3291                                                 v2s32(x,50+(*i)*1000),\r
3292                                                 video::SColor(255,255,255,255));\r
3293                                 x++;\r
3294                         }\r
3295                 }\r
3296 #if 0\r
3297                 /*\r
3298                         Draw map plot\r
3299                 */\r
3300                 if(g_show_map_plot && g_map_plot_texture)\r
3301                 {\r
3302                         core::dimension2d<u32> drawdim(640,480);\r
3303                         core::rect<s32> dest(v2s32(0,0), drawdim);\r
3304                         dest += v2s32(\r
3305                                 (screensize.X-drawdim.Width)/2,\r
3306                                 (screensize.Y-drawdim.Height)/2\r
3307                         );\r
3308                         core::rect<s32> source(v2s32(0,0), g_map_plot_texture->getSize());\r
3309                         driver->draw2DImage(g_map_plot_texture, dest, source);\r
3310                 }\r
3311 #endif\r
3312                 /*\r
3313                         Draw crosshair\r
3314                 */\r
3315                 driver->draw2DLine(displaycenter - core::vector2d<s32>(10,0),\r
3316                                 displaycenter + core::vector2d<s32>(10,0),\r
3317                                 video::SColor(255,255,255,255));\r
3318                 driver->draw2DLine(displaycenter - core::vector2d<s32>(0,10),\r
3319                                 displaycenter + core::vector2d<s32>(0,10),\r
3320                                 video::SColor(255,255,255,255));\r
3321 \r
3322                 } // timer\r
3323 \r
3324                 //timer10.stop();\r
3325                 //TimeTaker //timer11("//timer11");\r
3326 \r
3327                 /*\r
3328                         Draw gui\r
3329                 */\r
3330                 // 0-1ms\r
3331                 guienv->drawAll();\r
3332 \r
3333                 /*\r
3334                         Draw hotbar\r
3335                 */\r
3336                 {\r
3337                         draw_hotbar(driver, font, v2s32(displaycenter.X, screensize.Y),\r
3338                                         hotbar_imagesize, hotbar_itemcount, &local_inventory,\r
3339                                         client.getHP());\r
3340                 }\r
3341 \r
3342                 /*\r
3343                         Damage flash\r
3344                 */\r
3345                 if(damage_flash_timer > 0.0)\r
3346                 {\r
3347                         damage_flash_timer -= dtime;\r
3348                         \r
3349                         video::SColor color(128,255,0,0);\r
3350                         driver->draw2DRectangle(color,\r
3351                                         core::rect<s32>(0,0,screensize.X,screensize.Y),\r
3352                                         NULL);\r
3353                 }\r
3354                 \r
3355                 /*\r
3356                         End scene\r
3357                 */\r
3358                 {\r
3359                         TimeTaker timer("endScene");\r
3360                         driver->endScene();\r
3361                         endscenetime = timer.stop(true);\r
3362                 }\r
3363 \r
3364                 drawtime = drawtimer.stop(true);\r
3365 \r
3366                 /*\r
3367                         End of drawing\r
3368                 */\r
3369 \r
3370 #if 0\r
3371                 /*\r
3372                         Refresh map plot if player has moved considerably\r
3373                 */\r
3374                 if(g_refresh_map_plot)\r
3375                 {\r
3376                         static v3f old_player_pos = v3f(1,1,1) * 10000000;\r
3377                         v3f p = client.getPlayerPosition() / BS;\r
3378                         if(old_player_pos.getDistanceFrom(p) > 4 * g_map_plot_texture_scale)\r
3379                         {\r
3380                                 updateMapPlotTexture(v2f(p.X,p.Z), driver, &client);\r
3381                                 old_player_pos = p;\r
3382                         }\r
3383                         g_refresh_map_plot = false;\r
3384                 }\r
3385 #endif\r
3386                 \r
3387                 static s16 lastFPS = 0;\r
3388                 //u16 fps = driver->getFPS();\r
3389                 u16 fps = (1.0/dtime_avg1);\r
3390 \r
3391                 if (lastFPS != fps)\r
3392                 {\r
3393                         core::stringw str = L"Minetest [";\r
3394                         str += driver->getName();\r
3395                         str += "] FPS:";\r
3396                         str += fps;\r
3397 \r
3398                         device->setWindowCaption(str.c_str());\r
3399                         lastFPS = fps;\r
3400                 }\r
3401         }\r
3402 \r
3403         } // client and server are deleted at this point\r
3404 \r
3405         } //try\r
3406         catch(con::PeerNotFoundException &e)\r
3407         {\r
3408                 dstream<<DTIME<<"Connection timed out."<<std::endl;\r
3409                 error_message = L"Connection timed out.";\r
3410         }\r
3411 \r
3412         } // Menu-game loop\r
3413         \r
3414         delete g_input;\r
3415 \r
3416         /*\r
3417                 In the end, delete the Irrlicht device.\r
3418         */\r
3419         device->drop();\r
3420         \r
3421         /*\r
3422                 Update configuration file\r
3423         */\r
3424         /*if(configpath != "")\r
3425         {\r
3426                 g_settings.updateConfigFile(configpath.c_str());\r
3427         }*/\r
3428 \r
3429         END_DEBUG_EXCEPTION_HANDLER\r
3430         \r
3431         debugstreams_deinit();\r
3432         \r
3433         return 0;\r
3434 }\r
3435 \r
3436 //END\r