]> git.lizzy.rs Git - dragonfireclient.git/blob - src/game.cpp
Tool progress bar tweaking
[dragonfireclient.git] / src / game.cpp
1 /*
2 Minetest-c55
3 Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "game.h"
21 #include "common_irrlicht.h"
22 #include <IGUICheckBox.h>
23 #include <IGUIEditBox.h>
24 #include <IGUIButton.h>
25 #include <IGUIStaticText.h>
26 #include <IGUIFont.h>
27 #include "client.h"
28 #include "server.h"
29 #include "guiPauseMenu.h"
30 #include "guiPasswordChange.h"
31 #include "guiInventoryMenu.h"
32 #include "guiTextInputMenu.h"
33 #include "guiDeathScreen.h"
34 #include "materials.h"
35 #include "config.h"
36 #include "clouds.h"
37 #include "camera.h"
38 #include "farmesh.h"
39 #include "mapblock.h"
40 #include "settings.h"
41 #include "profiler.h"
42 #include "mainmenumanager.h"
43 #include "gettext.h"
44 #include "log.h"
45 #include "filesys.h"
46 // Needed for determining pointing to nodes
47 #include "nodedef.h"
48 #include "nodemetadata.h"
49 #include "main.h" // For g_settings
50 #include "itemdef.h"
51 #include "tile.h" // For TextureSource
52 #include "logoutputbuffer.h"
53
54 /*
55         Setting this to 1 enables a special camera mode that forces
56         the renderers to think that the camera statically points from
57         the starting place to a static direction.
58
59         This allows one to move around with the player and see what
60         is actually drawn behind solid things and behind the player.
61 */
62 #define FIELD_OF_VIEW_TEST 0
63
64
65 // Chat data
66 struct ChatLine
67 {
68         ChatLine():
69                 age(0.0)
70         {
71         }
72         ChatLine(const std::wstring &a_text):
73                 age(0.0),
74                 text(a_text)
75         {
76         }
77         float age;
78         std::wstring text;
79 };
80
81 /*
82         Text input system
83 */
84
85 struct TextDestChat : public TextDest
86 {
87         TextDestChat(Client *client)
88         {
89                 m_client = client;
90         }
91         void gotText(std::wstring text)
92         {
93                 // Discard empty line
94                 if(text == L"")
95                         return;
96
97                 // Send to others
98                 m_client->sendChatMessage(text);
99                 // Show locally
100                 m_client->addChatMessage(text);
101         }
102
103         Client *m_client;
104 };
105
106 struct TextDestNodeMetadata : public TextDest
107 {
108         TextDestNodeMetadata(v3s16 p, Client *client)
109         {
110                 m_p = p;
111                 m_client = client;
112         }
113         void gotText(std::wstring text)
114         {
115                 std::string ntext = wide_to_narrow(text);
116                 infostream<<"Changing text of a sign node: "
117                                 <<ntext<<std::endl;
118                 m_client->sendSignNodeText(m_p, ntext);
119         }
120
121         v3s16 m_p;
122         Client *m_client;
123 };
124
125 /* Respawn menu callback */
126
127 class MainRespawnInitiator: public IRespawnInitiator
128 {
129 public:
130         MainRespawnInitiator(bool *active, Client *client):
131                 m_active(active), m_client(client)
132         {
133                 *m_active = true;
134         }
135         void respawn()
136         {
137                 *m_active = false;
138                 m_client->sendRespawn();
139         }
140 private:
141         bool *m_active;
142         Client *m_client;
143 };
144
145 /*
146         Hotbar draw routine
147 */
148 void draw_hotbar(video::IVideoDriver *driver, gui::IGUIFont *font,
149                 IGameDef *gamedef,
150                 v2s32 centerlowerpos, s32 imgsize, s32 itemcount,
151                 Inventory *inventory, s32 halfheartcount, u16 playeritem)
152 {
153         InventoryList *mainlist = inventory->getList("main");
154         if(mainlist == NULL)
155         {
156                 errorstream<<"draw_hotbar(): mainlist == NULL"<<std::endl;
157                 return;
158         }
159         
160         s32 padding = imgsize/12;
161         //s32 height = imgsize + padding*2;
162         s32 width = itemcount*(imgsize+padding*2);
163         
164         // Position of upper left corner of bar
165         v2s32 pos = centerlowerpos - v2s32(width/2, imgsize+padding*2);
166         
167         // Draw background color
168         /*core::rect<s32> barrect(0,0,width,height);
169         barrect += pos;
170         video::SColor bgcolor(255,128,128,128);
171         driver->draw2DRectangle(bgcolor, barrect, NULL);*/
172
173         core::rect<s32> imgrect(0,0,imgsize,imgsize);
174
175         for(s32 i=0; i<itemcount; i++)
176         {
177                 const ItemStack &item = mainlist->getItem(i);
178                 
179                 core::rect<s32> rect = imgrect + pos
180                                 + v2s32(padding+i*(imgsize+padding*2), padding);
181                 
182                 if(playeritem == i)
183                 {
184                         video::SColor c_outside(255,255,0,0);
185                         //video::SColor c_outside(255,0,0,0);
186                         //video::SColor c_inside(255,192,192,192);
187                         s32 x1 = rect.UpperLeftCorner.X;
188                         s32 y1 = rect.UpperLeftCorner.Y;
189                         s32 x2 = rect.LowerRightCorner.X;
190                         s32 y2 = rect.LowerRightCorner.Y;
191                         // Black base borders
192                         driver->draw2DRectangle(c_outside,
193                                         core::rect<s32>(
194                                                 v2s32(x1 - padding, y1 - padding),
195                                                 v2s32(x2 + padding, y1)
196                                         ), NULL);
197                         driver->draw2DRectangle(c_outside,
198                                         core::rect<s32>(
199                                                 v2s32(x1 - padding, y2),
200                                                 v2s32(x2 + padding, y2 + padding)
201                                         ), NULL);
202                         driver->draw2DRectangle(c_outside,
203                                         core::rect<s32>(
204                                                 v2s32(x1 - padding, y1),
205                                                 v2s32(x1, y2)
206                                         ), NULL);
207                         driver->draw2DRectangle(c_outside,
208                                         core::rect<s32>(
209                                                 v2s32(x2, y1),
210                                                 v2s32(x2 + padding, y2)
211                                         ), NULL);
212                         /*// Light inside borders
213                         driver->draw2DRectangle(c_inside,
214                                         core::rect<s32>(
215                                                 v2s32(x1 - padding/2, y1 - padding/2),
216                                                 v2s32(x2 + padding/2, y1)
217                                         ), NULL);
218                         driver->draw2DRectangle(c_inside,
219                                         core::rect<s32>(
220                                                 v2s32(x1 - padding/2, y2),
221                                                 v2s32(x2 + padding/2, y2 + padding/2)
222                                         ), NULL);
223                         driver->draw2DRectangle(c_inside,
224                                         core::rect<s32>(
225                                                 v2s32(x1 - padding/2, y1),
226                                                 v2s32(x1, y2)
227                                         ), NULL);
228                         driver->draw2DRectangle(c_inside,
229                                         core::rect<s32>(
230                                                 v2s32(x2, y1),
231                                                 v2s32(x2 + padding/2, y2)
232                                         ), NULL);
233                         */
234                 }
235
236                 video::SColor bgcolor2(128,0,0,0);
237                 driver->draw2DRectangle(bgcolor2, rect, NULL);
238                 drawItemStack(driver, font, item, rect, NULL, gamedef);
239         }
240         
241         /*
242                 Draw hearts
243         */
244         video::ITexture *heart_texture =
245                 gamedef->getTextureSource()->getTextureRaw("heart.png");
246         if(heart_texture)
247         {
248                 v2s32 p = pos + v2s32(0, -20);
249                 for(s32 i=0; i<halfheartcount/2; i++)
250                 {
251                         const video::SColor color(255,255,255,255);
252                         const video::SColor colors[] = {color,color,color,color};
253                         core::rect<s32> rect(0,0,16,16);
254                         rect += p;
255                         driver->draw2DImage(heart_texture, rect,
256                                 core::rect<s32>(core::position2d<s32>(0,0),
257                                 core::dimension2di(heart_texture->getOriginalSize())),
258                                 NULL, colors, true);
259                         p += v2s32(16,0);
260                 }
261                 if(halfheartcount % 2 == 1)
262                 {
263                         const video::SColor color(255,255,255,255);
264                         const video::SColor colors[] = {color,color,color,color};
265                         core::rect<s32> rect(0,0,16/2,16);
266                         rect += p;
267                         core::dimension2di srcd(heart_texture->getOriginalSize());
268                         srcd.Width /= 2;
269                         driver->draw2DImage(heart_texture, rect,
270                                 core::rect<s32>(core::position2d<s32>(0,0), srcd),
271                                 NULL, colors, true);
272                         p += v2s32(16,0);
273                 }
274         }
275 }
276
277 /*
278         Check if a node is pointable
279 */
280 inline bool isPointableNode(const MapNode& n,
281                 Client *client, bool liquids_pointable)
282 {
283         const ContentFeatures &features = client->getNodeDefManager()->get(n);
284         return features.pointable ||
285                 (liquids_pointable && features.isLiquid());
286 }
287
288 /*
289         Find what the player is pointing at
290 */
291 PointedThing getPointedThing(Client *client, v3f player_position,
292                 v3f camera_direction, v3f camera_position,
293                 core::line3d<f32> shootline, f32 d,
294                 bool liquids_pointable,
295                 bool look_for_object,
296                 core::aabbox3d<f32> &hilightbox,
297                 bool &should_show_hilightbox,
298                 ClientActiveObject *&selected_object)
299 {
300         PointedThing result;
301
302         hilightbox = core::aabbox3d<f32>(0,0,0,0,0,0);
303         should_show_hilightbox = false;
304         selected_object = NULL;
305
306         // First try to find a pointed at active object
307         if(look_for_object)
308         {
309                 selected_object = client->getSelectedActiveObject(d*BS,
310                                 camera_position, shootline);
311         }
312         if(selected_object != NULL)
313         {
314                 core::aabbox3d<f32> *selection_box
315                         = selected_object->getSelectionBox();
316                 // Box should exist because object was returned in the
317                 // first place
318                 assert(selection_box);
319
320                 v3f pos = selected_object->getPosition();
321
322                 hilightbox = core::aabbox3d<f32>(
323                                 selection_box->MinEdge + pos,
324                                 selection_box->MaxEdge + pos
325                 );
326
327                 should_show_hilightbox = selected_object->doShowSelectionBox();
328
329                 result.type = POINTEDTHING_OBJECT;
330                 result.object_id = selected_object->getId();
331                 return result;
332         }
333
334         // That didn't work, try to find a pointed at node
335
336         f32 mindistance = BS * 1001;
337         
338         v3s16 pos_i = floatToInt(player_position, BS);
339
340         /*infostream<<"pos_i=("<<pos_i.X<<","<<pos_i.Y<<","<<pos_i.Z<<")"
341                         <<std::endl;*/
342
343         s16 a = d;
344         s16 ystart = pos_i.Y + 0 - (camera_direction.Y<0 ? a : 1);
345         s16 zstart = pos_i.Z - (camera_direction.Z<0 ? a : 1);
346         s16 xstart = pos_i.X - (camera_direction.X<0 ? a : 1);
347         s16 yend = pos_i.Y + 1 + (camera_direction.Y>0 ? a : 1);
348         s16 zend = pos_i.Z + (camera_direction.Z>0 ? a : 1);
349         s16 xend = pos_i.X + (camera_direction.X>0 ? a : 1);
350         
351         for(s16 y = ystart; y <= yend; y++)
352         for(s16 z = zstart; z <= zend; z++)
353         for(s16 x = xstart; x <= xend; x++)
354         {
355                 MapNode n;
356                 try
357                 {
358                         n = client->getNode(v3s16(x,y,z));
359                 }
360                 catch(InvalidPositionException &e)
361                 {
362                         continue;
363                 }
364                 if(!isPointableNode(n, client, liquids_pointable))
365                         continue;
366
367                 v3s16 np(x,y,z);
368                 v3f npf = intToFloat(np, BS);
369                 
370                 f32 d = 0.01;
371                 
372                 v3s16 dirs[6] = {
373                         v3s16(0,0,1), // back
374                         v3s16(0,1,0), // top
375                         v3s16(1,0,0), // right
376                         v3s16(0,0,-1), // front
377                         v3s16(0,-1,0), // bottom
378                         v3s16(-1,0,0), // left
379                 };
380                 
381                 const ContentFeatures &f = client->getNodeDefManager()->get(n);
382                 
383                 if(f.selection_box.type == NODEBOX_FIXED)
384                 {
385                         core::aabbox3d<f32> box = f.selection_box.fixed;
386                         box.MinEdge += npf;
387                         box.MaxEdge += npf;
388
389                         v3s16 facedirs[6] = {
390                                 v3s16(-1,0,0),
391                                 v3s16(1,0,0),
392                                 v3s16(0,-1,0),
393                                 v3s16(0,1,0),
394                                 v3s16(0,0,-1),
395                                 v3s16(0,0,1),
396                         };
397
398                         core::aabbox3d<f32> faceboxes[6] = {
399                                 // X-
400                                 core::aabbox3d<f32>(
401                                         box.MinEdge.X, box.MinEdge.Y, box.MinEdge.Z,
402                                         box.MinEdge.X+d, box.MaxEdge.Y, box.MaxEdge.Z
403                                 ),
404                                 // X+
405                                 core::aabbox3d<f32>(
406                                         box.MaxEdge.X-d, box.MinEdge.Y, box.MinEdge.Z,
407                                         box.MaxEdge.X, box.MaxEdge.Y, box.MaxEdge.Z
408                                 ),
409                                 // Y-
410                                 core::aabbox3d<f32>(
411                                         box.MinEdge.X, box.MinEdge.Y, box.MinEdge.Z,
412                                         box.MaxEdge.X, box.MinEdge.Y+d, box.MaxEdge.Z
413                                 ),
414                                 // Y+
415                                 core::aabbox3d<f32>(
416                                         box.MinEdge.X, box.MaxEdge.Y-d, box.MinEdge.Z,
417                                         box.MaxEdge.X, box.MaxEdge.Y, box.MaxEdge.Z
418                                 ),
419                                 // Z-
420                                 core::aabbox3d<f32>(
421                                         box.MinEdge.X, box.MinEdge.Y, box.MinEdge.Z,
422                                         box.MaxEdge.X, box.MaxEdge.Y, box.MinEdge.Z+d
423                                 ),
424                                 // Z+
425                                 core::aabbox3d<f32>(
426                                         box.MinEdge.X, box.MinEdge.Y, box.MaxEdge.Z-d,
427                                         box.MaxEdge.X, box.MaxEdge.Y, box.MaxEdge.Z
428                                 ),
429                         };
430
431                         for(u16 i=0; i<6; i++)
432                         {
433                                 v3f facedir_f(facedirs[i].X, facedirs[i].Y, facedirs[i].Z);
434                                 v3f centerpoint = npf + facedir_f * BS/2;
435                                 f32 distance = (centerpoint - camera_position).getLength();
436                                 if(distance >= mindistance)
437                                         continue;
438                                 if(!faceboxes[i].intersectsWithLine(shootline))
439                                         continue;
440                                 result.type = POINTEDTHING_NODE;
441                                 result.node_undersurface = np;
442                                 result.node_abovesurface = np+facedirs[i];
443                                 mindistance = distance;
444                                 hilightbox = box;
445                                 should_show_hilightbox = true;
446                         }
447                 }
448                 else if(f.selection_box.type == NODEBOX_WALLMOUNTED)
449                 {
450                         v3s16 dir = unpackDir(n.param2);
451                         v3f dir_f = v3f(dir.X, dir.Y, dir.Z);
452                         dir_f *= BS/2 - BS/6 - BS/20;
453                         v3f cpf = npf + dir_f;
454                         f32 distance = (cpf - camera_position).getLength();
455
456                         core::aabbox3d<f32> box;
457                         
458                         // top
459                         if(dir == v3s16(0,1,0)){
460                                 box = f.selection_box.wall_top;
461                         }
462                         // bottom
463                         else if(dir == v3s16(0,-1,0)){
464                                 box = f.selection_box.wall_bottom;
465                         }
466                         // side
467                         else{
468                                 v3f vertices[2] =
469                                 {
470                                         f.selection_box.wall_side.MinEdge,
471                                         f.selection_box.wall_side.MaxEdge
472                                 };
473
474                                 for(s32 i=0; i<2; i++)
475                                 {
476                                         if(dir == v3s16(-1,0,0))
477                                                 vertices[i].rotateXZBy(0);
478                                         if(dir == v3s16(1,0,0))
479                                                 vertices[i].rotateXZBy(180);
480                                         if(dir == v3s16(0,0,-1))
481                                                 vertices[i].rotateXZBy(90);
482                                         if(dir == v3s16(0,0,1))
483                                                 vertices[i].rotateXZBy(-90);
484                                 }
485
486                                 box = core::aabbox3d<f32>(vertices[0]);
487                                 box.addInternalPoint(vertices[1]);
488                         }
489
490                         box.MinEdge += npf;
491                         box.MaxEdge += npf;
492                         
493                         if(distance < mindistance)
494                         {
495                                 if(box.intersectsWithLine(shootline))
496                                 {
497                                         result.type = POINTEDTHING_NODE;
498                                         result.node_undersurface = np;
499                                         result.node_abovesurface = np;
500                                         mindistance = distance;
501                                         hilightbox = box;
502                                         should_show_hilightbox = true;
503                                 }
504                         }
505                 }
506                 else // NODEBOX_REGULAR
507                 {
508                         for(u16 i=0; i<6; i++)
509                         {
510                                 v3f dir_f = v3f(dirs[i].X,
511                                                 dirs[i].Y, dirs[i].Z);
512                                 v3f centerpoint = npf + dir_f * BS/2;
513                                 f32 distance =
514                                                 (centerpoint - camera_position).getLength();
515                                 
516                                 if(distance < mindistance)
517                                 {
518                                         core::CMatrix4<f32> m;
519                                         m.buildRotateFromTo(v3f(0,0,1), dir_f);
520
521                                         // This is the back face
522                                         v3f corners[2] = {
523                                                 v3f(BS/2, BS/2, BS/2),
524                                                 v3f(-BS/2, -BS/2, BS/2+d)
525                                         };
526                                         
527                                         for(u16 j=0; j<2; j++)
528                                         {
529                                                 m.rotateVect(corners[j]);
530                                                 corners[j] += npf;
531                                         }
532
533                                         core::aabbox3d<f32> facebox(corners[0]);
534                                         facebox.addInternalPoint(corners[1]);
535
536                                         if(facebox.intersectsWithLine(shootline))
537                                         {
538                                                 result.type = POINTEDTHING_NODE;
539                                                 result.node_undersurface = np;
540                                                 result.node_abovesurface = np + dirs[i];
541                                                 mindistance = distance;
542
543                                                 //hilightbox = facebox;
544
545                                                 const float d = 0.502;
546                                                 core::aabbox3d<f32> nodebox
547                                                                 (-BS*d, -BS*d, -BS*d, BS*d, BS*d, BS*d);
548                                                 v3f nodepos_f = intToFloat(np, BS);
549                                                 nodebox.MinEdge += nodepos_f;
550                                                 nodebox.MaxEdge += nodepos_f;
551                                                 hilightbox = nodebox;
552                                                 should_show_hilightbox = true;
553                                         }
554                                 } // if distance < mindistance
555                         } // for dirs
556                 } // regular block
557         } // for coords
558
559         return result;
560 }
561
562 void update_skybox(video::IVideoDriver* driver, ITextureSource *tsrc,
563                 scene::ISceneManager* smgr, scene::ISceneNode* &skybox,
564                 float brightness)
565 {
566         if(skybox)
567         {
568                 skybox->remove();
569         }
570         
571         /*// Disable skybox if FarMesh is enabled
572         if(g_settings->getBool("enable_farmesh"))
573                 return;*/
574         
575         if(brightness >= 0.5)
576         {
577                 skybox = smgr->addSkyBoxSceneNode(
578                         tsrc->getTextureRaw("skybox2.png"),
579                         tsrc->getTextureRaw("skybox3.png"),
580                         tsrc->getTextureRaw("skybox1.png"),
581                         tsrc->getTextureRaw("skybox1.png"),
582                         tsrc->getTextureRaw("skybox1.png"),
583                         tsrc->getTextureRaw("skybox1.png"));
584         }
585         else if(brightness >= 0.2)
586         {
587                 skybox = smgr->addSkyBoxSceneNode(
588                         tsrc->getTextureRaw("skybox2_dawn.png"),
589                         tsrc->getTextureRaw("skybox3_dawn.png"),
590                         tsrc->getTextureRaw("skybox1_dawn.png"),
591                         tsrc->getTextureRaw("skybox1_dawn.png"),
592                         tsrc->getTextureRaw("skybox1_dawn.png"),
593                         tsrc->getTextureRaw("skybox1_dawn.png"));
594         }
595         else
596         {
597                 skybox = smgr->addSkyBoxSceneNode(
598                         tsrc->getTextureRaw("skybox2_night.png"),
599                         tsrc->getTextureRaw("skybox3_night.png"),
600                         tsrc->getTextureRaw("skybox1_night.png"),
601                         tsrc->getTextureRaw("skybox1_night.png"),
602                         tsrc->getTextureRaw("skybox1_night.png"),
603                         tsrc->getTextureRaw("skybox1_night.png"));
604         }
605 }
606
607 /*
608         Draws a screen with a single text on it.
609         Text will be removed when the screen is drawn the next time.
610 */
611 /*gui::IGUIStaticText **/
612 void draw_load_screen(const std::wstring &text,
613                 video::IVideoDriver* driver, gui::IGUIFont* font)
614 {
615         v2u32 screensize = driver->getScreenSize();
616         const wchar_t *loadingtext = text.c_str();
617         core::vector2d<u32> textsize_u = font->getDimension(loadingtext);
618         core::vector2d<s32> textsize(textsize_u.X,textsize_u.Y);
619         core::vector2d<s32> center(screensize.X/2, screensize.Y/2);
620         core::rect<s32> textrect(center - textsize/2, center + textsize/2);
621
622         gui::IGUIStaticText *guitext = guienv->addStaticText(
623                         loadingtext, textrect, false, false);
624         guitext->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);
625
626         driver->beginScene(true, true, video::SColor(255,0,0,0));
627         guienv->drawAll();
628         driver->endScene();
629         
630         guitext->remove();
631         
632         //return guitext;
633 }
634
635 void the_game(
636         bool &kill,
637         bool random_input,
638         InputHandler *input,
639         IrrlichtDevice *device,
640         gui::IGUIFont* font,
641         std::string map_dir,
642         std::string playername,
643         std::string password,
644         std::string address,
645         u16 port,
646         std::wstring &error_message,
647     std::string configpath
648 )
649 {
650         video::IVideoDriver* driver = device->getVideoDriver();
651         scene::ISceneManager* smgr = device->getSceneManager();
652         
653         // Calculate text height using the font
654         u32 text_height = font->getDimension(L"Random test string").Height;
655
656         v2u32 screensize(0,0);
657         v2u32 last_screensize(0,0);
658         screensize = driver->getScreenSize();
659
660         const s32 hotbar_itemcount = 8;
661         //const s32 hotbar_imagesize = 36;
662         //const s32 hotbar_imagesize = 64;
663         s32 hotbar_imagesize = 48;
664         
665         // The color of the sky
666
667         //video::SColor skycolor = video::SColor(255,140,186,250);
668
669         video::SColor bgcolor_bright = video::SColor(255,170,200,230);
670
671         /*
672                 Draw "Loading" screen
673         */
674
675         draw_load_screen(L"Loading...", driver, font);
676         
677         // Create texture source
678         IWritableTextureSource *tsrc = createTextureSource(device);
679         
680         // These will be filled by data received from the server
681         // Create item definition manager
682         IWritableItemDefManager *itemdef = createItemDefManager();
683         // Create node definition manager
684         IWritableNodeDefManager *nodedef = createNodeDefManager();
685
686         // Add chat log output for errors to be shown in chat
687         LogOutputBuffer chat_log_error_buf(LMT_ERROR);
688
689         /*
690                 Create server.
691                 SharedPtr will delete it when it goes out of scope.
692         */
693         SharedPtr<Server> server;
694         if(address == ""){
695                 draw_load_screen(L"Creating server...", driver, font);
696                 infostream<<"Creating server"<<std::endl;
697                 server = new Server(map_dir, configpath);
698                 server->start(port);
699         }
700
701         { // Client scope
702         
703         /*
704                 Create client
705         */
706
707         draw_load_screen(L"Creating client...", driver, font);
708         infostream<<"Creating client"<<std::endl;
709         
710         MapDrawControl draw_control;
711
712         Client client(device, playername.c_str(), password, draw_control,
713                         tsrc, itemdef, nodedef);
714         
715         // Client acts as our GameDef
716         IGameDef *gamedef = &client;
717                         
718         draw_load_screen(L"Resolving address...", driver, font);
719         Address connect_address(0,0,0,0, port);
720         try{
721                 if(address == "")
722                         //connect_address.Resolve("localhost");
723                         connect_address.setAddress(127,0,0,1);
724                 else
725                         connect_address.Resolve(address.c_str());
726         }
727         catch(ResolveError &e)
728         {
729                 errorstream<<"Couldn't resolve address"<<std::endl;
730                 //return 0;
731                 error_message = L"Couldn't resolve address";
732                 //gui_loadingtext->remove();
733                 return;
734         }
735
736         /*
737                 Attempt to connect to the server
738         */
739         
740         infostream<<"Connecting to server at ";
741         connect_address.print(&infostream);
742         infostream<<std::endl;
743         client.connect(connect_address);
744         
745         /*
746                 Wait for server to accept connection
747         */
748         bool could_connect = false;
749         try{
750                 float frametime = 0.033;
751                 const float timeout = 10.0;
752                 float time_counter = 0.0;
753                 for(;;)
754                 {
755                         // Update client and server
756                         client.step(frametime);
757                         if(server != NULL)
758                                 server->step(frametime);
759                         
760                         // End condition
761                         if(client.connectedAndInitialized()){
762                                 could_connect = true;
763                                 break;
764                         }
765                         // Break conditions
766                         if(client.accessDenied())
767                                 break;
768                         if(time_counter >= timeout)
769                                 break;
770                         
771                         // Display status
772                         std::wostringstream ss;
773                         ss<<L"Connecting to server... (timeout in ";
774                         ss<<(int)(timeout - time_counter + 1.0);
775                         ss<<L" seconds)";
776                         draw_load_screen(ss.str(), driver, font);
777                         
778                         // Delay a bit
779                         sleep_ms(1000*frametime);
780                         time_counter += frametime;
781                 }
782         }
783         catch(con::PeerNotFoundException &e)
784         {}
785         
786         /*
787                 Handle failure to connect
788         */
789         if(could_connect == false)
790         {
791                 if(client.accessDenied())
792                 {
793                         error_message = L"Access denied. Reason: "
794                                         +client.accessDeniedReason();
795                         errorstream<<wide_to_narrow(error_message)<<std::endl;
796                 }
797                 else
798                 {
799                         error_message = L"Connection timed out.";
800                         errorstream<<"Timed out."<<std::endl;
801                 }
802                 //gui_loadingtext->remove();
803                 return;
804         }
805         
806         /*
807                 Wait until content has been received
808         */
809         bool got_content = false;
810         {
811                 float frametime = 0.033;
812                 const float timeout = 30.0;
813                 float time_counter = 0.0;
814                 for(;;)
815                 {
816                         // Update client and server
817                         client.step(frametime);
818                         if(server != NULL)
819                                 server->step(frametime);
820                         
821                         // End condition
822                         if(client.texturesReceived() &&
823                                         client.itemdefReceived() &&
824                                         client.nodedefReceived()){
825                                 got_content = true;
826                                 break;
827                         }
828                         // Break conditions
829                         if(!client.connectedAndInitialized())
830                                 break;
831                         if(time_counter >= timeout)
832                                 break;
833                         
834                         // Display status
835                         std::wostringstream ss;
836                         ss<<L"Waiting content... (continuing anyway in ";
837                         ss<<(int)(timeout - time_counter + 1.0);
838                         ss<<L" seconds)\n";
839
840                         ss<<(client.itemdefReceived()?L"[X]":L"[  ]");
841                         ss<<L" Item definitions\n";
842                         ss<<(client.nodedefReceived()?L"[X]":L"[  ]");
843                         ss<<L" Node definitions\n";
844                         //ss<<(client.texturesReceived()?L"[X]":L"[  ]");
845                         ss<<L"["<<(int)(client.textureReceiveProgress()*100+0.5)<<L"%] ";
846                         ss<<L" Textures\n";
847
848                         draw_load_screen(ss.str(), driver, font);
849                         
850                         // Delay a bit
851                         sleep_ms(1000*frametime);
852                         time_counter += frametime;
853                 }
854         }
855
856         /*
857                 After all content has been received:
858                 Update cached textures, meshes and materials
859         */
860         client.afterContentReceived();
861
862         /*
863                 Create skybox
864         */
865         float old_brightness = 1.0;
866         scene::ISceneNode* skybox = NULL;
867         update_skybox(driver, tsrc, smgr, skybox, 1.0);
868         
869         /*
870                 Create the camera node
871         */
872         Camera camera(smgr, draw_control);
873         if (!camera.successfullyCreated(error_message))
874                 return;
875
876         f32 camera_yaw = 0; // "right/left"
877         f32 camera_pitch = 0; // "up/down"
878
879         /*
880                 Clouds
881         */
882         
883         float cloud_height = BS*100;
884         Clouds *clouds = NULL;
885         if(g_settings->getBool("enable_clouds"))
886         {
887                 clouds = new Clouds(smgr->getRootSceneNode(), smgr, -1,
888                                 cloud_height, time(0));
889         }
890         
891         /*
892                 FarMesh
893         */
894
895         FarMesh *farmesh = NULL;
896         if(g_settings->getBool("enable_farmesh"))
897         {
898                 farmesh = new FarMesh(smgr->getRootSceneNode(), smgr, -1, client.getMapSeed(), &client);
899         }
900
901         /*
902                 A copy of the local inventory
903         */
904         Inventory local_inventory(itemdef);
905
906         /*
907                 Move into game
908         */
909         
910         //gui_loadingtext->remove();
911
912         /*
913                 Add some gui stuff
914         */
915
916         // First line of debug text
917         gui::IGUIStaticText *guitext = guienv->addStaticText(
918                         L"Minetest-c55",
919                         core::rect<s32>(5, 5, 795, 5+text_height),
920                         false, false);
921         // Second line of debug text
922         gui::IGUIStaticText *guitext2 = guienv->addStaticText(
923                         L"",
924                         core::rect<s32>(5, 5+(text_height+5)*1, 795, (5+text_height)*2),
925                         false, false);
926         // At the middle of the screen
927         // Object infos are shown in this
928         gui::IGUIStaticText *guitext_info = guienv->addStaticText(
929                         L"",
930                         core::rect<s32>(0,0,400,text_height+5) + v2s32(100,200),
931                         false, false);
932         
933         // Chat text
934         gui::IGUIStaticText *guitext_chat = guienv->addStaticText(
935                         L"",
936                         core::rect<s32>(0,0,0,0),
937                         //false, false); // Disable word wrap as of now
938                         false, true);
939         //guitext_chat->setBackgroundColor(video::SColor(96,0,0,0));
940         core::list<ChatLine> chat_lines;
941         
942         // Profiler text (size is updated when text is updated)
943         gui::IGUIStaticText *guitext_profiler = guienv->addStaticText(
944                         L"<Profiler>",
945                         core::rect<s32>(6, 4+(text_height+5)*2, 400,
946                         (text_height+5)*2 + text_height*35),
947                         false, false);
948         guitext_profiler->setBackgroundColor(video::SColor(80,0,0,0));
949         guitext_profiler->setVisible(false);
950         
951         /*GUIQuickInventory *quick_inventory = new GUIQuickInventory
952                         (guienv, NULL, v2s32(10, 70), 5, &local_inventory);*/
953         /*GUIQuickInventory *quick_inventory = new GUIQuickInventory
954                         (guienv, NULL, v2s32(0, 0), quickinv_itemcount, &local_inventory);*/
955         
956         // Test the text input system
957         /*(new GUITextInputMenu(guienv, guiroot, -1, &g_menumgr,
958                         NULL))->drop();*/
959         /*GUIMessageMenu *menu =
960                         new GUIMessageMenu(guienv, guiroot, -1, 
961                                 &g_menumgr,
962                                 L"Asd");
963         menu->drop();*/
964         
965         // Launch pause menu
966         (new GUIPauseMenu(guienv, guiroot, -1, g_gamecallback,
967                         &g_menumgr))->drop();
968         
969         // Enable texts
970         /*guitext2->setVisible(true);
971         guitext_info->setVisible(true);
972         guitext_chat->setVisible(true);*/
973
974         //s32 guitext_chat_pad_bottom = 70;
975
976         /*
977                 Some statistics are collected in these
978         */
979         u32 drawtime = 0;
980         u32 beginscenetime = 0;
981         u32 scenetime = 0;
982         u32 endscenetime = 0;
983         
984         // A test
985         //throw con::PeerNotFoundException("lol");
986
987         float brightness = 1.0;
988
989         core::list<float> frametime_log;
990
991         float nodig_delay_timer = 0.0;
992         float dig_time = 0.0;
993         u16 dig_index = 0;
994         PointedThing pointed_old;
995         bool digging = false;
996         bool ldown_for_dig = false;
997
998         float damage_flash_timer = 0;
999         s16 farmesh_range = 20*MAP_BLOCKSIZE;
1000
1001         const float object_hit_delay = 0.2;
1002         float object_hit_delay_timer = 0.0;
1003         
1004         bool invert_mouse = g_settings->getBool("invert_mouse");
1005
1006         bool respawn_menu_active = false;
1007         bool update_wielded_item_trigger = false;
1008
1009         bool show_profiler = false;
1010         bool force_fog_off = false;
1011         bool disable_camera_update = false;
1012
1013         /*
1014                 Main loop
1015         */
1016
1017         bool first_loop_after_window_activation = true;
1018
1019         // TODO: Convert the static interval timers to these
1020         // Interval limiter for profiler
1021         IntervalLimiter m_profiler_interval;
1022
1023         // Time is in milliseconds
1024         // NOTE: getRealTime() causes strange problems in wine (imprecision?)
1025         // NOTE: So we have to use getTime() and call run()s between them
1026         u32 lasttime = device->getTimer()->getTime();
1027
1028         while(device->run() && kill == false)
1029         {
1030                 //std::cerr<<"frame"<<std::endl;
1031
1032                 if(client.accessDenied())
1033                 {
1034                         error_message = L"Access denied. Reason: "
1035                                         +client.accessDeniedReason();
1036                         errorstream<<wide_to_narrow(error_message)<<std::endl;
1037                         break;
1038                 }
1039
1040                 if(g_gamecallback->disconnect_requested)
1041                 {
1042                         g_gamecallback->disconnect_requested = false;
1043                         break;
1044                 }
1045
1046                 if(g_gamecallback->changepassword_requested)
1047                 {
1048                         (new GUIPasswordChange(guienv, guiroot, -1,
1049                                 &g_menumgr, &client))->drop();
1050                         g_gamecallback->changepassword_requested = false;
1051                 }
1052
1053                 /*
1054                         Process TextureSource's queue
1055                 */
1056                 tsrc->processQueue();
1057
1058                 /*
1059                         Random calculations
1060                 */
1061                 last_screensize = screensize;
1062                 screensize = driver->getScreenSize();
1063                 v2s32 displaycenter(screensize.X/2,screensize.Y/2);
1064                 //bool screensize_changed = screensize != last_screensize;
1065
1066                 // Resize hotbar
1067                 if(screensize.Y <= 800)
1068                         hotbar_imagesize = 32;
1069                 else if(screensize.Y <= 1280)
1070                         hotbar_imagesize = 48;
1071                 else
1072                         hotbar_imagesize = 64;
1073                 
1074                 // Hilight boxes collected during the loop and displayed
1075                 core::list< core::aabbox3d<f32> > hilightboxes;
1076                 
1077                 // Info text
1078                 std::wstring infotext;
1079
1080                 // When screen size changes, update positions and sizes of stuff
1081                 /*if(screensize_changed)
1082                 {
1083                         v2s32 pos(displaycenter.X-((quickinv_itemcount-1)*quickinv_spacing+quickinv_size)/2, screensize.Y-quickinv_spacing);
1084                         quick_inventory->updatePosition(pos);
1085                 }*/
1086
1087                 //TimeTaker //timer1("//timer1");
1088                 
1089                 // Time of frame without fps limit
1090                 float busytime;
1091                 u32 busytime_u32;
1092                 {
1093                         // not using getRealTime is necessary for wine
1094                         u32 time = device->getTimer()->getTime();
1095                         if(time > lasttime)
1096                                 busytime_u32 = time - lasttime;
1097                         else
1098                                 busytime_u32 = 0;
1099                         busytime = busytime_u32 / 1000.0;
1100                 }
1101
1102                 //infostream<<"busytime_u32="<<busytime_u32<<std::endl;
1103         
1104                 // Necessary for device->getTimer()->getTime()
1105                 device->run();
1106
1107                 /*
1108                         FPS limiter
1109                 */
1110
1111                 {
1112                         float fps_max = g_settings->getFloat("fps_max");
1113                         u32 frametime_min = 1000./fps_max;
1114                         
1115                         if(busytime_u32 < frametime_min)
1116                         {
1117                                 u32 sleeptime = frametime_min - busytime_u32;
1118                                 device->sleep(sleeptime);
1119                         }
1120                 }
1121
1122                 // Necessary for device->getTimer()->getTime()
1123                 device->run();
1124
1125                 /*
1126                         Time difference calculation
1127                 */
1128                 f32 dtime; // in seconds
1129                 
1130                 u32 time = device->getTimer()->getTime();
1131                 if(time > lasttime)
1132                         dtime = (time - lasttime) / 1000.0;
1133                 else
1134                         dtime = 0;
1135                 lasttime = time;
1136
1137                 /* Run timers */
1138
1139                 if(nodig_delay_timer >= 0)
1140                         nodig_delay_timer -= dtime;
1141                 if(object_hit_delay_timer >= 0)
1142                         object_hit_delay_timer -= dtime;
1143
1144                 g_profiler->add("Elapsed time", dtime);
1145                 g_profiler->avg("FPS", 1./dtime);
1146
1147                 /*
1148                         Log frametime for visualization
1149                 */
1150                 frametime_log.push_back(dtime);
1151                 if(frametime_log.size() > 100)
1152                 {
1153                         core::list<float>::Iterator i = frametime_log.begin();
1154                         frametime_log.erase(i);
1155                 }
1156
1157                 /*
1158                         Visualize frametime in terminal
1159                 */
1160                 /*for(u32 i=0; i<dtime*400; i++)
1161                         infostream<<"X";
1162                 infostream<<std::endl;*/
1163
1164                 /*
1165                         Time average and jitter calculation
1166                 */
1167
1168                 static f32 dtime_avg1 = 0.0;
1169                 dtime_avg1 = dtime_avg1 * 0.96 + dtime * 0.04;
1170                 f32 dtime_jitter1 = dtime - dtime_avg1;
1171
1172                 static f32 dtime_jitter1_max_sample = 0.0;
1173                 static f32 dtime_jitter1_max_fraction = 0.0;
1174                 {
1175                         static f32 jitter1_max = 0.0;
1176                         static f32 counter = 0.0;
1177                         if(dtime_jitter1 > jitter1_max)
1178                                 jitter1_max = dtime_jitter1;
1179                         counter += dtime;
1180                         if(counter > 0.0)
1181                         {
1182                                 counter -= 3.0;
1183                                 dtime_jitter1_max_sample = jitter1_max;
1184                                 dtime_jitter1_max_fraction
1185                                                 = dtime_jitter1_max_sample / (dtime_avg1+0.001);
1186                                 jitter1_max = 0.0;
1187                         }
1188                 }
1189                 
1190                 /*
1191                         Busytime average and jitter calculation
1192                 */
1193
1194                 static f32 busytime_avg1 = 0.0;
1195                 busytime_avg1 = busytime_avg1 * 0.98 + busytime * 0.02;
1196                 f32 busytime_jitter1 = busytime - busytime_avg1;
1197                 
1198                 static f32 busytime_jitter1_max_sample = 0.0;
1199                 static f32 busytime_jitter1_min_sample = 0.0;
1200                 {
1201                         static f32 jitter1_max = 0.0;
1202                         static f32 jitter1_min = 0.0;
1203                         static f32 counter = 0.0;
1204                         if(busytime_jitter1 > jitter1_max)
1205                                 jitter1_max = busytime_jitter1;
1206                         if(busytime_jitter1 < jitter1_min)
1207                                 jitter1_min = busytime_jitter1;
1208                         counter += dtime;
1209                         if(counter > 0.0){
1210                                 counter -= 3.0;
1211                                 busytime_jitter1_max_sample = jitter1_max;
1212                                 busytime_jitter1_min_sample = jitter1_min;
1213                                 jitter1_max = 0.0;
1214                                 jitter1_min = 0.0;
1215                         }
1216                 }
1217                 
1218                 /*
1219                         Debug info for client
1220                 */
1221                 {
1222                         static float counter = 0.0;
1223                         counter -= dtime;
1224                         if(counter < 0)
1225                         {
1226                                 counter = 30.0;
1227                                 client.printDebugInfo(infostream);
1228                         }
1229                 }
1230
1231                 /*
1232                         Profiler
1233                 */
1234                 float profiler_print_interval =
1235                                 g_settings->getFloat("profiler_print_interval");
1236                 bool print_to_log = true;
1237                 if(profiler_print_interval == 0){
1238                         print_to_log = false;
1239                         profiler_print_interval = 5;
1240                 }
1241                 if(m_profiler_interval.step(dtime, profiler_print_interval))
1242                 {
1243                         if(print_to_log){
1244                                 infostream<<"Profiler:"<<std::endl;
1245                                 g_profiler->print(infostream);
1246                         }
1247
1248                         std::ostringstream os(std::ios_base::binary);
1249                         g_profiler->print(os);
1250                         std::wstring text = narrow_to_wide(os.str());
1251                         guitext_profiler->setText(text.c_str());
1252
1253                         g_profiler->clear();
1254                         
1255                         s32 w = font->getDimension(text.c_str()).Width;
1256                         if(w < 400)
1257                                 w = 400;
1258                         core::rect<s32> rect(6, 4+(text_height+5)*2, 12+w,
1259                                         8+(text_height+5)*2 +
1260                                         font->getDimension(text.c_str()).Height);
1261                         guitext_profiler->setRelativePosition(rect);
1262                 }
1263
1264                 /*
1265                         Direct handling of user input
1266                 */
1267                 
1268                 // Reset input if window not active or some menu is active
1269                 if(device->isWindowActive() == false || noMenuActive() == false)
1270                 {
1271                         input->clear();
1272                 }
1273
1274                 // Input handler step() (used by the random input generator)
1275                 input->step(dtime);
1276
1277                 /*
1278                         Launch menus and trigger stuff according to keys
1279                 */
1280                 if(input->wasKeyDown(getKeySetting("keymap_drop")))
1281                 {
1282                         // drop selected item
1283                         IDropAction *a = new IDropAction();
1284                         a->count = 0;
1285                         a->from_inv.setCurrentPlayer();
1286                         a->from_list = "main";
1287                         a->from_i = client.getPlayerItem();
1288                         client.inventoryAction(a);
1289                 }
1290                 else if(input->wasKeyDown(getKeySetting("keymap_inventory")))
1291                 {
1292                         infostream<<"the_game: "
1293                                         <<"Launching inventory"<<std::endl;
1294                         
1295                         GUIInventoryMenu *menu =
1296                                 new GUIInventoryMenu(guienv, guiroot, -1,
1297                                         &g_menumgr, v2s16(8,7),
1298                                         &client, gamedef);
1299
1300                         InventoryLocation inventoryloc;
1301                         inventoryloc.setCurrentPlayer();
1302
1303                         core::array<GUIInventoryMenu::DrawSpec> draw_spec;
1304                         draw_spec.push_back(GUIInventoryMenu::DrawSpec(
1305                                         "list", inventoryloc, "main",
1306                                         v2s32(0, 3), v2s32(8, 4)));
1307                         draw_spec.push_back(GUIInventoryMenu::DrawSpec(
1308                                         "list", inventoryloc, "craft",
1309                                         v2s32(3, 0), v2s32(3, 3)));
1310                         draw_spec.push_back(GUIInventoryMenu::DrawSpec(
1311                                         "list", inventoryloc, "craftresult",
1312                                         v2s32(7, 1), v2s32(1, 1)));
1313
1314                         menu->setDrawSpec(draw_spec);
1315
1316                         menu->drop();
1317                 }
1318                 else if(input->wasKeyDown(EscapeKey))
1319                 {
1320                         infostream<<"the_game: "
1321                                         <<"Launching pause menu"<<std::endl;
1322                         // It will delete itself by itself
1323                         (new GUIPauseMenu(guienv, guiroot, -1, g_gamecallback,
1324                                         &g_menumgr))->drop();
1325
1326                         // Move mouse cursor on top of the disconnect button
1327                         input->setMousePos(displaycenter.X, displaycenter.Y+25);
1328                 }
1329                 else if(input->wasKeyDown(getKeySetting("keymap_chat")))
1330                 {
1331                         TextDest *dest = new TextDestChat(&client);
1332
1333                         (new GUITextInputMenu(guienv, guiroot, -1,
1334                                         &g_menumgr, dest,
1335                                         L""))->drop();
1336                 }
1337                 else if(input->wasKeyDown(getKeySetting("keymap_cmd")))
1338                 {
1339                         TextDest *dest = new TextDestChat(&client);
1340
1341                         (new GUITextInputMenu(guienv, guiroot, -1,
1342                                         &g_menumgr, dest,
1343                                         L"/"))->drop();
1344                 }
1345                 else if(input->wasKeyDown(getKeySetting("keymap_freemove")))
1346                 {
1347                         if(g_settings->getBool("free_move"))
1348                         {
1349                                 g_settings->set("free_move","false");
1350                                 chat_lines.push_back(ChatLine(L"free_move disabled"));
1351                         }
1352                         else
1353                         {
1354                                 g_settings->set("free_move","true");
1355                                 chat_lines.push_back(ChatLine(L"free_move enabled"));
1356                         }
1357                 }
1358                 else if(input->wasKeyDown(getKeySetting("keymap_fastmove")))
1359                 {
1360                         if(g_settings->getBool("fast_move"))
1361                         {
1362                                 g_settings->set("fast_move","false");
1363                                 chat_lines.push_back(ChatLine(L"fast_move disabled"));
1364                         }
1365                         else
1366                         {
1367                                 g_settings->set("fast_move","true");
1368                                 chat_lines.push_back(ChatLine(L"fast_move enabled"));
1369                         }
1370                 }
1371                 else if(input->wasKeyDown(getKeySetting("keymap_frametime_graph")))
1372                 {
1373                         if(g_settings->getBool("frametime_graph"))
1374                         {
1375                                 g_settings->set("frametime_graph","false");
1376                                 chat_lines.push_back(ChatLine(L"frametime_graph disabled"));
1377                         }
1378                         else
1379                         {
1380                                 g_settings->set("frametime_graph","true");
1381                                 chat_lines.push_back(ChatLine(L"frametime_graph enabled"));
1382                         }
1383                 }
1384                 else if(input->wasKeyDown(getKeySetting("keymap_screenshot")))
1385                 {
1386                         irr::video::IImage* const image = driver->createScreenShot(); 
1387                         if (image) { 
1388                                 irr::c8 filename[256]; 
1389                                 snprintf(filename, 256, "%s" DIR_DELIM "screenshot_%u.png", 
1390                                                  g_settings->get("screenshot_path").c_str(),
1391                                                  device->getTimer()->getRealTime()); 
1392                                 if (driver->writeImageToFile(image, filename)) {
1393                                         std::wstringstream sstr;
1394                                         sstr<<"Saved screenshot to '"<<filename<<"'";
1395                                         infostream<<"Saved screenshot to '"<<filename<<"'"<<std::endl;
1396                                         chat_lines.push_back(ChatLine(sstr.str()));
1397                                 } else{
1398                                         infostream<<"Failed to save screenshot '"<<filename<<"'"<<std::endl;
1399                                 }
1400                                 image->drop(); 
1401                         }                        
1402                 }
1403                 else if(input->wasKeyDown(getKeySetting("keymap_toggle_profiler")))
1404                 {
1405                         show_profiler = !show_profiler;
1406                         guitext_profiler->setVisible(show_profiler);
1407                         if(show_profiler)
1408                                 chat_lines.push_back(ChatLine(L"Profiler disabled"));
1409                         else
1410                                 chat_lines.push_back(ChatLine(L"Profiler enabled"));
1411                 }
1412                 else if(input->wasKeyDown(getKeySetting("keymap_toggle_force_fog_off")))
1413                 {
1414                         force_fog_off = !force_fog_off;
1415                         if(force_fog_off)
1416                                 chat_lines.push_back(ChatLine(L"Fog disabled"));
1417                         else
1418                                 chat_lines.push_back(ChatLine(L"Fog enabled"));
1419                 }
1420                 else if(input->wasKeyDown(getKeySetting("keymap_toggle_update_camera")))
1421                 {
1422                         disable_camera_update = !disable_camera_update;
1423                         if(disable_camera_update)
1424                                 chat_lines.push_back(ChatLine(L"Camera update disabled"));
1425                         else
1426                                 chat_lines.push_back(ChatLine(L"Camera update enabled"));
1427                 }
1428
1429                 // Item selection with mouse wheel
1430                 u16 new_playeritem = client.getPlayerItem();
1431                 {
1432                         s32 wheel = input->getMouseWheel();
1433                         u16 max_item = MYMIN(PLAYER_INVENTORY_SIZE-1,
1434                                         hotbar_itemcount-1);
1435
1436                         if(wheel < 0)
1437                         {
1438                                 if(new_playeritem < max_item)
1439                                         new_playeritem++;
1440                                 else
1441                                         new_playeritem = 0;
1442                         }
1443                         else if(wheel > 0)
1444                         {
1445                                 if(new_playeritem > 0)
1446                                         new_playeritem--;
1447                                 else
1448                                         new_playeritem = max_item;
1449                         }
1450                 }
1451                 
1452                 // Item selection
1453                 for(u16 i=0; i<10; i++)
1454                 {
1455                         const KeyPress *kp = NumberKey + (i + 1) % 10;
1456                         if(input->wasKeyDown(*kp))
1457                         {
1458                                 if(i < PLAYER_INVENTORY_SIZE && i < hotbar_itemcount)
1459                                 {
1460                                         new_playeritem = i;
1461
1462                                         infostream<<"Selected item: "
1463                                                         <<new_playeritem<<std::endl;
1464                                 }
1465                         }
1466                 }
1467
1468                 // Viewing range selection
1469                 if(input->wasKeyDown(getKeySetting("keymap_rangeselect")))
1470                 {
1471                         if(draw_control.range_all)
1472                         {
1473                                 draw_control.range_all = false;
1474                                 infostream<<"Disabled full viewing range"<<std::endl;
1475                         }
1476                         else
1477                         {
1478                                 draw_control.range_all = true;
1479                                 infostream<<"Enabled full viewing range"<<std::endl;
1480                         }
1481                 }
1482
1483                 // Print debug stacks
1484                 if(input->wasKeyDown(getKeySetting("keymap_print_debug_stacks")))
1485                 {
1486                         dstream<<"-----------------------------------------"
1487                                         <<std::endl;
1488                         dstream<<DTIME<<"Printing debug stacks:"<<std::endl;
1489                         dstream<<"-----------------------------------------"
1490                                         <<std::endl;
1491                         debug_stacks_print();
1492                 }
1493
1494                 /*
1495                         Mouse and camera control
1496                         NOTE: Do this before client.setPlayerControl() to not cause a camera lag of one frame
1497                 */
1498                 
1499                 if((device->isWindowActive() && noMenuActive()) || random_input)
1500                 {
1501                         if(!random_input)
1502                         {
1503                                 // Mac OSX gets upset if this is set every frame
1504                                 if(device->getCursorControl()->isVisible())
1505                                         device->getCursorControl()->setVisible(false);
1506                         }
1507
1508                         if(first_loop_after_window_activation){
1509                                 //infostream<<"window active, first loop"<<std::endl;
1510                                 first_loop_after_window_activation = false;
1511                         }
1512                         else{
1513                                 s32 dx = input->getMousePos().X - displaycenter.X;
1514                                 s32 dy = input->getMousePos().Y - displaycenter.Y;
1515                                 if(invert_mouse)
1516                                         dy = -dy;
1517                                 //infostream<<"window active, pos difference "<<dx<<","<<dy<<std::endl;
1518                                 
1519                                 /*const float keyspeed = 500;
1520                                 if(input->isKeyDown(irr::KEY_UP))
1521                                         dy -= dtime * keyspeed;
1522                                 if(input->isKeyDown(irr::KEY_DOWN))
1523                                         dy += dtime * keyspeed;
1524                                 if(input->isKeyDown(irr::KEY_LEFT))
1525                                         dx -= dtime * keyspeed;
1526                                 if(input->isKeyDown(irr::KEY_RIGHT))
1527                                         dx += dtime * keyspeed;*/
1528
1529                                 camera_yaw -= dx*0.2;
1530                                 camera_pitch += dy*0.2;
1531                                 if(camera_pitch < -89.5) camera_pitch = -89.5;
1532                                 if(camera_pitch > 89.5) camera_pitch = 89.5;
1533                         }
1534                         input->setMousePos(displaycenter.X, displaycenter.Y);
1535                 }
1536                 else{
1537                         // Mac OSX gets upset if this is set every frame
1538                         if(device->getCursorControl()->isVisible() == false)
1539                                 device->getCursorControl()->setVisible(true);
1540
1541                         //infostream<<"window inactive"<<std::endl;
1542                         first_loop_after_window_activation = true;
1543                 }
1544
1545                 /*
1546                         Player speed control
1547                 */
1548                 
1549                 if(!noMenuActive() || !device->isWindowActive())
1550                 {
1551                         PlayerControl control(
1552                                 false,
1553                                 false,
1554                                 false,
1555                                 false,
1556                                 false,
1557                                 false,
1558                                 false,
1559                                 camera_pitch,
1560                                 camera_yaw
1561                         );
1562                         client.setPlayerControl(control);
1563                 }
1564                 else
1565                 {
1566                         /*bool a_up,
1567                         bool a_down,
1568                         bool a_left,
1569                         bool a_right,
1570                         bool a_jump,
1571                         bool a_superspeed,
1572                         bool a_sneak,
1573                         float a_pitch,
1574                         float a_yaw*/
1575                         PlayerControl control(
1576                                 input->isKeyDown(getKeySetting("keymap_forward")),
1577                                 input->isKeyDown(getKeySetting("keymap_backward")),
1578                                 input->isKeyDown(getKeySetting("keymap_left")),
1579                                 input->isKeyDown(getKeySetting("keymap_right")),
1580                                 input->isKeyDown(getKeySetting("keymap_jump")),
1581                                 input->isKeyDown(getKeySetting("keymap_special1")),
1582                                 input->isKeyDown(getKeySetting("keymap_sneak")),
1583                                 camera_pitch,
1584                                 camera_yaw
1585                         );
1586                         client.setPlayerControl(control);
1587                 }
1588                 
1589                 /*
1590                         Run server
1591                 */
1592
1593                 if(server != NULL)
1594                 {
1595                         //TimeTaker timer("server->step(dtime)");
1596                         server->step(dtime);
1597                 }
1598
1599                 /*
1600                         Process environment
1601                 */
1602                 
1603                 {
1604                         //TimeTaker timer("client.step(dtime)");
1605                         client.step(dtime);
1606                         //client.step(dtime_avg1);
1607                 }
1608
1609                 {
1610                         // Read client events
1611                         for(;;)
1612                         {
1613                                 ClientEvent event = client.getClientEvent();
1614                                 if(event.type == CE_NONE)
1615                                 {
1616                                         break;
1617                                 }
1618                                 else if(event.type == CE_PLAYER_DAMAGE)
1619                                 {
1620                                         //u16 damage = event.player_damage.amount;
1621                                         //infostream<<"Player damage: "<<damage<<std::endl;
1622                                         damage_flash_timer = 0.05;
1623                                         if(event.player_damage.amount >= 2){
1624                                                 damage_flash_timer += 0.05 * event.player_damage.amount;
1625                                         }
1626                                 }
1627                                 else if(event.type == CE_PLAYER_FORCE_MOVE)
1628                                 {
1629                                         camera_yaw = event.player_force_move.yaw;
1630                                         camera_pitch = event.player_force_move.pitch;
1631                                 }
1632                                 else if(event.type == CE_DEATHSCREEN)
1633                                 {
1634                                         if(respawn_menu_active)
1635                                                 continue;
1636
1637                                         /*bool set_camera_point_target =
1638                                                         event.deathscreen.set_camera_point_target;
1639                                         v3f camera_point_target;
1640                                         camera_point_target.X = event.deathscreen.camera_point_target_x;
1641                                         camera_point_target.Y = event.deathscreen.camera_point_target_y;
1642                                         camera_point_target.Z = event.deathscreen.camera_point_target_z;*/
1643                                         MainRespawnInitiator *respawner =
1644                                                         new MainRespawnInitiator(
1645                                                                         &respawn_menu_active, &client);
1646                                         GUIDeathScreen *menu =
1647                                                         new GUIDeathScreen(guienv, guiroot, -1, 
1648                                                                 &g_menumgr, respawner);
1649                                         menu->drop();
1650                                         
1651                                         /* Handle visualization */
1652
1653                                         damage_flash_timer = 0;
1654
1655                                         /*LocalPlayer* player = client.getLocalPlayer();
1656                                         player->setPosition(player->getPosition() + v3f(0,-BS,0));
1657                                         camera.update(player, busytime, screensize);*/
1658                                 }
1659                                 else if(event.type == CE_TEXTURES_UPDATED)
1660                                 {
1661                                         update_skybox(driver, tsrc, smgr, skybox, brightness);
1662                                         
1663                                         update_wielded_item_trigger = true;
1664                                 }
1665                         }
1666                 }
1667                 
1668                 //TimeTaker //timer2("//timer2");
1669
1670                 LocalPlayer* player = client.getLocalPlayer();
1671                 camera.update(player, busytime, screensize);
1672                 camera.step(dtime);
1673
1674                 v3f player_position = player->getPosition();
1675                 v3f camera_position = camera.getPosition();
1676                 v3f camera_direction = camera.getDirection();
1677                 f32 camera_fov = camera.getFovMax();
1678                 
1679                 if(!disable_camera_update){
1680                         client.updateCamera(camera_position,
1681                                 camera_direction, camera_fov);
1682                 }
1683
1684                 //timer2.stop();
1685                 //TimeTaker //timer3("//timer3");
1686
1687                 /*
1688                         For interaction purposes, get info about the held item
1689                         - What item is it?
1690                         - Is it a usable item?
1691                         - Can it point to liquids?
1692                 */
1693                 ItemStack playeritem;
1694                 bool playeritem_usable = false;
1695                 bool playeritem_liquids_pointable = false;
1696                 {
1697                         InventoryList *mlist = local_inventory.getList("main");
1698                         if(mlist != NULL)
1699                         {
1700                                 playeritem = mlist->getItem(client.getPlayerItem());
1701                                 playeritem_usable = playeritem.getDefinition(itemdef).usable;
1702                                 playeritem_liquids_pointable = playeritem.getDefinition(itemdef).liquids_pointable;
1703                         }
1704                 }
1705
1706                 /*
1707                         Calculate what block is the crosshair pointing to
1708                 */
1709                 
1710                 //u32 t1 = device->getTimer()->getRealTime();
1711                 
1712                 f32 d = 4; // max. distance
1713                 core::line3d<f32> shootline(camera_position,
1714                                 camera_position + camera_direction * BS * (d+1));
1715
1716                 core::aabbox3d<f32> hilightbox;
1717                 bool should_show_hilightbox = false;
1718                 ClientActiveObject *selected_object = NULL;
1719
1720                 PointedThing pointed = getPointedThing(
1721                                 // input
1722                                 &client, player_position, camera_direction,
1723                                 camera_position, shootline, d,
1724                                 playeritem_liquids_pointable, !ldown_for_dig,
1725                                 // output
1726                                 hilightbox, should_show_hilightbox,
1727                                 selected_object);
1728
1729                 if(pointed != pointed_old)
1730                 {
1731                         infostream<<"Pointing at "<<pointed.dump()<<std::endl;
1732                         //dstream<<"Pointing at "<<pointed.dump()<<std::endl;
1733                 }
1734
1735                 /*
1736                         Visualize selection
1737                 */
1738                 if(should_show_hilightbox)
1739                         hilightboxes.push_back(hilightbox);
1740
1741                 /*
1742                         Stop digging when
1743                         - releasing left mouse button
1744                         - pointing away from node
1745                 */
1746                 if(digging)
1747                 {
1748                         if(input->getLeftReleased())
1749                         {
1750                                 infostream<<"Left button released"
1751                                         <<" (stopped digging)"<<std::endl;
1752                                 digging = false;
1753                         }
1754                         else if(pointed != pointed_old)
1755                         {
1756                                 if (pointed.type == POINTEDTHING_NODE
1757                                         && pointed_old.type == POINTEDTHING_NODE
1758                                         && pointed.node_undersurface == pointed_old.node_undersurface)
1759                                 {
1760                                         // Still pointing to the same node,
1761                                         // but a different face. Don't reset.
1762                                 }
1763                                 else
1764                                 {
1765                                         infostream<<"Pointing away from node"
1766                                                 <<" (stopped digging)"<<std::endl;
1767                                         digging = false;
1768                                 }
1769                         }
1770                         if(!digging)
1771                         {
1772                                 client.interact(1, pointed_old);
1773                                 client.clearTempMod(pointed_old.node_undersurface);
1774                                 dig_time = 0.0;
1775                         }
1776                 }
1777                 if(!digging && ldown_for_dig && !input->getLeftState())
1778                 {
1779                         ldown_for_dig = false;
1780                 }
1781
1782                 bool left_punch = false;
1783                 bool left_punch_muted = false;
1784
1785                 if(playeritem_usable && input->getLeftState())
1786                 {
1787                         if(input->getLeftClicked())
1788                                 client.interact(4, pointed);
1789                 }
1790                 else if(pointed.type == POINTEDTHING_NODE)
1791                 {
1792                         v3s16 nodepos = pointed.node_undersurface;
1793                         v3s16 neighbourpos = pointed.node_abovesurface;
1794
1795                         /*
1796                                 Check information text of node
1797                         */
1798
1799                         NodeMetadata *meta = client.getNodeMetadata(nodepos);
1800                         if(meta)
1801                         {
1802                                 infotext = narrow_to_wide(meta->infoText());
1803                         }
1804                         else
1805                         {
1806                                 MapNode n = client.getNode(nodepos);
1807                                 if(nodedef->get(n).tname_tiles[0] == "unknown_block.png"){
1808                                         infotext = L"Unknown node: ";
1809                                         infotext += narrow_to_wide(nodedef->get(n).name);
1810                                 }
1811                         }
1812                         
1813                         /*
1814                                 Handle digging
1815                         */
1816                         
1817                         
1818                         if(nodig_delay_timer <= 0.0 && input->getLeftState())
1819                         {
1820                                 if(!digging)
1821                                 {
1822                                         infostream<<"Started digging"<<std::endl;
1823                                         client.interact(0, pointed);
1824                                         digging = true;
1825                                         ldown_for_dig = true;
1826                                 }
1827                                 MapNode n = client.getNode(nodepos);
1828
1829                                 // Get digging properties for material and tool
1830                                 content_t material = n.getContent();
1831                                 ToolDiggingProperties tp =
1832                                                 playeritem.getToolDiggingProperties(itemdef);
1833                                 DiggingProperties prop =
1834                                                 getDiggingProperties(material, &tp, nodedef);
1835
1836                                 float dig_time_complete = 0.0;
1837
1838                                 if(prop.diggable == false)
1839                                 {
1840                                         // I guess nobody will wait for this long
1841                                         dig_time_complete = 10000000.0;
1842                                 }
1843                                 else
1844                                 {
1845                                         dig_time_complete = prop.time;
1846                                 }
1847
1848                                 if(dig_time_complete >= 0.001)
1849                                 {
1850                                         dig_index = (u16)((float)CRACK_ANIMATION_LENGTH
1851                                                         * dig_time/dig_time_complete);
1852                                 }
1853                                 // This is for torches
1854                                 else
1855                                 {
1856                                         dig_index = CRACK_ANIMATION_LENGTH;
1857                                 }
1858
1859                                 if(dig_index < CRACK_ANIMATION_LENGTH)
1860                                 {
1861                                         //TimeTaker timer("client.setTempMod");
1862                                         //infostream<<"dig_index="<<dig_index<<std::endl;
1863                                         client.setTempMod(nodepos, NodeMod(NODEMOD_CRACK, dig_index));
1864                                 }
1865                                 else
1866                                 {
1867                                         infostream<<"Digging completed"<<std::endl;
1868                                         client.interact(2, pointed);
1869                                         client.clearTempMod(nodepos);
1870                                         client.removeNode(nodepos);
1871
1872                                         dig_time = 0;
1873                                         digging = false;
1874
1875                                         nodig_delay_timer = dig_time_complete
1876                                                         / (float)CRACK_ANIMATION_LENGTH;
1877
1878                                         // We don't want a corresponding delay to
1879                                         // very time consuming nodes
1880                                         if(nodig_delay_timer > 0.5)
1881                                         {
1882                                                 nodig_delay_timer = 0.5;
1883                                         }
1884                                         // We want a slight delay to very little
1885                                         // time consuming nodes
1886                                         float mindelay = 0.15;
1887                                         if(nodig_delay_timer < mindelay)
1888                                         {
1889                                                 nodig_delay_timer = mindelay;
1890                                         }
1891                                 }
1892
1893                                 dig_time += dtime;
1894
1895                                 camera.setDigging(0);  // left click animation
1896                         }
1897
1898                         if(input->getRightClicked())
1899                         {
1900                                 infostream<<"Ground right-clicked"<<std::endl;
1901                                 
1902                                 // If metadata provides an inventory view, activate it
1903                                 if(meta && meta->getInventoryDrawSpecString() != "" && !random_input)
1904                                 {
1905                                         infostream<<"Launching custom inventory view"<<std::endl;
1906
1907                                         InventoryLocation inventoryloc;
1908                                         inventoryloc.setNodeMeta(nodepos);
1909                                         
1910
1911                                         /*
1912                                                 Create menu
1913                                         */
1914
1915                                         core::array<GUIInventoryMenu::DrawSpec> draw_spec;
1916                                         v2s16 invsize =
1917                                                 GUIInventoryMenu::makeDrawSpecArrayFromString(
1918                                                         draw_spec,
1919                                                         meta->getInventoryDrawSpecString(),
1920                                                         inventoryloc);
1921
1922                                         GUIInventoryMenu *menu =
1923                                                 new GUIInventoryMenu(guienv, guiroot, -1,
1924                                                         &g_menumgr, invsize,
1925                                                         &client, gamedef);
1926                                         menu->setDrawSpec(draw_spec);
1927                                         menu->drop();
1928                                 }
1929                                 // If metadata provides text input, activate text input
1930                                 else if(meta && meta->allowsTextInput() && !random_input)
1931                                 {
1932                                         infostream<<"Launching metadata text input"<<std::endl;
1933                                         
1934                                         // Get a new text for it
1935
1936                                         TextDest *dest = new TextDestNodeMetadata(nodepos, &client);
1937
1938                                         std::wstring wtext = narrow_to_wide(meta->getText());
1939
1940                                         (new GUITextInputMenu(guienv, guiroot, -1,
1941                                                         &g_menumgr, dest,
1942                                                         wtext))->drop();
1943                                 }
1944                                 // Otherwise report right click to server
1945                                 else
1946                                 {
1947                                         client.interact(3, pointed);
1948                                         camera.setDigging(1);  // right click animation
1949                                 }
1950                         }
1951                 }
1952                 else if(pointed.type == POINTEDTHING_OBJECT)
1953                 {
1954                         infotext = narrow_to_wide(selected_object->infoText());
1955
1956                         //if(input->getLeftClicked())
1957                         if(input->getLeftState())
1958                         {
1959                                 bool do_punch = false;
1960                                 bool do_punch_damage = false;
1961                                 if(object_hit_delay_timer <= 0.0){
1962                                         do_punch = true;
1963                                         do_punch_damage = true;
1964                                         object_hit_delay_timer = object_hit_delay;
1965                                 }
1966                                 if(input->getLeftClicked()){
1967                                         do_punch = true;
1968                                 }
1969                                 if(do_punch){
1970                                         infostream<<"Left-clicked object"<<std::endl;
1971                                         left_punch = true;
1972                                 }
1973                                 if(do_punch_damage){
1974                                         // Report direct punch
1975                                         v3f objpos = selected_object->getPosition();
1976                                         v3f dir = (objpos - player_position).normalize();
1977
1978                                         bool disable_send = selected_object->directReportPunch(playeritem.name, dir);
1979                                         if(!disable_send)
1980                                                 client.interact(0, pointed);
1981                                 }
1982                         }
1983                         else if(input->getRightClicked())
1984                         {
1985                                 infostream<<"Right-clicked object"<<std::endl;
1986                                 client.interact(3, pointed);  // place
1987                         }
1988                 }
1989
1990                 pointed_old = pointed;
1991                 
1992                 if(left_punch || (input->getLeftClicked() && !left_punch_muted))
1993                 {
1994                         camera.setDigging(0); // left click animation
1995                 }
1996
1997                 input->resetLeftClicked();
1998                 input->resetRightClicked();
1999
2000                 input->resetLeftReleased();
2001                 input->resetRightReleased();
2002                 
2003                 /*
2004                         Calculate stuff for drawing
2005                 */
2006                 
2007                 /*
2008                         Calculate general brightness
2009                 */
2010                 u32 daynight_ratio = client.getDayNightRatio();
2011                 u8 light8 = decode_light((daynight_ratio * LIGHT_SUN) / 1000);
2012                 brightness = (float)light8/255.0;
2013                 video::SColor bgcolor = video::SColor(
2014                                 255,
2015                                 bgcolor_bright.getRed() * brightness,
2016                                 bgcolor_bright.getGreen() * brightness,
2017                                 bgcolor_bright.getBlue() * brightness);
2018                                 /*skycolor.getRed() * brightness,
2019                                 skycolor.getGreen() * brightness,
2020                                 skycolor.getBlue() * brightness);*/
2021
2022                 /*
2023                         Update skybox
2024                 */
2025                 if(fabs(brightness - old_brightness) > 0.01)
2026                         update_skybox(driver, tsrc, smgr, skybox, brightness);
2027
2028                 /*
2029                         Update clouds
2030                 */
2031                 if(clouds)
2032                 {
2033                         clouds->step(dtime);
2034                         clouds->update(v2f(player_position.X, player_position.Z),
2035                                         0.05+brightness*0.95);
2036                 }
2037                 
2038                 /*
2039                         Update farmesh
2040                 */
2041                 if(farmesh)
2042                 {
2043                         farmesh_range = draw_control.wanted_range * 10;
2044                         if(draw_control.range_all && farmesh_range < 500)
2045                                 farmesh_range = 500;
2046                         if(farmesh_range > 1000)
2047                                 farmesh_range = 1000;
2048
2049                         farmesh->step(dtime);
2050                         farmesh->update(v2f(player_position.X, player_position.Z),
2051                                         0.05+brightness*0.95, farmesh_range);
2052                 }
2053                 
2054                 // Store brightness value
2055                 old_brightness = brightness;
2056
2057                 /*
2058                         Fog
2059                 */
2060                 
2061                 if(g_settings->getBool("enable_fog") == true && !force_fog_off)
2062                 {
2063                         f32 range;
2064                         if(farmesh)
2065                         {
2066                                 range = BS*farmesh_range;
2067                         }
2068                         else
2069                         {
2070                                 range = draw_control.wanted_range*BS + MAP_BLOCKSIZE*BS*1.5;
2071                                 range *= 0.9;
2072                                 if(draw_control.range_all)
2073                                         range = 100000*BS;
2074                                 /*if(range < 50*BS)
2075                                         range = range * 0.5 + 25*BS;*/
2076                         }
2077
2078                         driver->setFog(
2079                                 bgcolor,
2080                                 video::EFT_FOG_LINEAR,
2081                                 range*0.4,
2082                                 range*1.0,
2083                                 0.01,
2084                                 false, // pixel fog
2085                                 false // range fog
2086                         );
2087                 }
2088                 else
2089                 {
2090                         driver->setFog(
2091                                 bgcolor,
2092                                 video::EFT_FOG_LINEAR,
2093                                 100000*BS,
2094                                 110000*BS,
2095                                 0.01,
2096                                 false, // pixel fog
2097                                 false // range fog
2098                         );
2099                 }
2100
2101                 /*
2102                         Update gui stuff (0ms)
2103                 */
2104
2105                 //TimeTaker guiupdatetimer("Gui updating");
2106                 
2107                 {
2108                         static float drawtime_avg = 0;
2109                         drawtime_avg = drawtime_avg * 0.95 + (float)drawtime*0.05;
2110                         static float beginscenetime_avg = 0;
2111                         beginscenetime_avg = beginscenetime_avg * 0.95 + (float)beginscenetime*0.05;
2112                         static float scenetime_avg = 0;
2113                         scenetime_avg = scenetime_avg * 0.95 + (float)scenetime*0.05;
2114                         static float endscenetime_avg = 0;
2115                         endscenetime_avg = endscenetime_avg * 0.95 + (float)endscenetime*0.05;
2116                         
2117                         char temptext[300];
2118                         snprintf(temptext, 300, "Minetest-c55 %s ("
2119                                         "R: range_all=%i"
2120                                         ")"
2121                                         " drawtime=%.0f, beginscenetime=%.0f"
2122                                         ", scenetime=%.0f, endscenetime=%.0f",
2123                                         VERSION_STRING,
2124                                         draw_control.range_all,
2125                                         drawtime_avg,
2126                                         beginscenetime_avg,
2127                                         scenetime_avg,
2128                                         endscenetime_avg
2129                                         );
2130                         
2131                         guitext->setText(narrow_to_wide(temptext).c_str());
2132                 }
2133                 
2134                 {
2135                         char temptext[300];
2136                         snprintf(temptext, 300,
2137                                         "(% .1f, % .1f, % .1f)"
2138                                         " (% .3f < btime_jitter < % .3f"
2139                                         ", dtime_jitter = % .1f %%"
2140                                         ", v_range = %.1f, RTT = %.3f)",
2141                                         player_position.X/BS,
2142                                         player_position.Y/BS,
2143                                         player_position.Z/BS,
2144                                         busytime_jitter1_min_sample,
2145                                         busytime_jitter1_max_sample,
2146                                         dtime_jitter1_max_fraction * 100.0,
2147                                         draw_control.wanted_range,
2148                                         client.getRTT()
2149                                         );
2150
2151                         guitext2->setText(narrow_to_wide(temptext).c_str());
2152                 }
2153                 
2154                 {
2155                         guitext_info->setText(infotext.c_str());
2156                 }
2157                 
2158                 /*
2159                         Get chat messages from client
2160                 */
2161                 {
2162                         // Get new messages from error log buffer
2163                         while(!chat_log_error_buf.empty())
2164                         {
2165                                 chat_lines.push_back(ChatLine(narrow_to_wide(
2166                                                 chat_log_error_buf.get())));
2167                         }
2168                         // Get new messages from client
2169                         std::wstring message;
2170                         while(client.getChatMessage(message))
2171                         {
2172                                 chat_lines.push_back(ChatLine(message));
2173                                 /*if(chat_lines.size() > 6)
2174                                 {
2175                                         core::list<ChatLine>::Iterator
2176                                                         i = chat_lines.begin();
2177                                         chat_lines.erase(i);
2178                                 }*/
2179                         }
2180                         // Append them to form the whole static text and throw
2181                         // it to the gui element
2182                         std::wstring whole;
2183                         // This will correspond to the line number counted from
2184                         // top to bottom, from size-1 to 0
2185                         s16 line_number = chat_lines.size();
2186                         // Count of messages to be removed from the top
2187                         u16 to_be_removed_count = 0;
2188                         for(core::list<ChatLine>::Iterator
2189                                         i = chat_lines.begin();
2190                                         i != chat_lines.end(); i++)
2191                         {
2192                                 // After this, line number is valid for this loop
2193                                 line_number--;
2194                                 // Increment age
2195                                 (*i).age += dtime;
2196                                 /*
2197                                         This results in a maximum age of 60*6 to the
2198                                         lowermost line and a maximum of 6 lines
2199                                 */
2200                                 float allowed_age = (6-line_number) * 60.0;
2201
2202                                 if((*i).age > allowed_age)
2203                                 {
2204                                         to_be_removed_count++;
2205                                         continue;
2206                                 }
2207                                 whole += (*i).text + L'\n';
2208                         }
2209                         for(u16 i=0; i<to_be_removed_count; i++)
2210                         {
2211                                 core::list<ChatLine>::Iterator
2212                                                 it = chat_lines.begin();
2213                                 chat_lines.erase(it);
2214                         }
2215                         guitext_chat->setText(whole.c_str());
2216
2217                         // Update gui element size and position
2218
2219                         /*core::rect<s32> rect(
2220                                         10,
2221                                         screensize.Y - guitext_chat_pad_bottom
2222                                                         - text_height*chat_lines.size(),
2223                                         screensize.X - 10,
2224                                         screensize.Y - guitext_chat_pad_bottom
2225                         );*/
2226                         core::rect<s32> rect(
2227                                         10,
2228                                         50,
2229                                         screensize.X - 10,
2230                                         50 + guitext_chat->getTextHeight()
2231                         );
2232
2233                         guitext_chat->setRelativePosition(rect);
2234
2235                         // Don't show chat if empty or profiler is enabled
2236                         if(chat_lines.size() == 0 || show_profiler)
2237                                 guitext_chat->setVisible(false);
2238                         else
2239                                 guitext_chat->setVisible(true);
2240                 }
2241
2242                 /*
2243                         Inventory
2244                 */
2245                 
2246                 if(client.getPlayerItem() != new_playeritem)
2247                 {
2248                         client.selectPlayerItem(new_playeritem);
2249                 }
2250                 if(client.getLocalInventoryUpdated())
2251                 {
2252                         //infostream<<"Updating local inventory"<<std::endl;
2253                         client.getLocalInventory(local_inventory);
2254                         
2255                         update_wielded_item_trigger = true;
2256                 }
2257                 if(update_wielded_item_trigger)
2258                 {
2259                         update_wielded_item_trigger = false;
2260                         // Update wielded tool
2261                         InventoryList *mlist = local_inventory.getList("main");
2262                         ItemStack item;
2263                         if(mlist != NULL)
2264                                 item = mlist->getItem(client.getPlayerItem());
2265                         camera.wield(item, gamedef);
2266                 }
2267                 
2268                 /*
2269                         Drawing begins
2270                 */
2271
2272                 TimeTaker drawtimer("Drawing");
2273
2274                 
2275                 {
2276                         TimeTaker timer("beginScene");
2277                         driver->beginScene(true, true, bgcolor);
2278                         //driver->beginScene(false, true, bgcolor);
2279                         beginscenetime = timer.stop(true);
2280                 }
2281                 
2282                 //timer3.stop();
2283                 
2284                 //infostream<<"smgr->drawAll()"<<std::endl;
2285                 
2286                 {
2287                         TimeTaker timer("smgr");
2288                         smgr->drawAll();
2289                         scenetime = timer.stop(true);
2290                 }
2291                 
2292                 {
2293                 //TimeTaker timer9("auxiliary drawings");
2294                 // 0ms
2295                 
2296                 //timer9.stop();
2297                 //TimeTaker //timer10("//timer10");
2298                 
2299                 video::SMaterial m;
2300                 //m.Thickness = 10;
2301                 m.Thickness = 3;
2302                 m.Lighting = false;
2303                 driver->setMaterial(m);
2304
2305                 driver->setTransform(video::ETS_WORLD, core::IdentityMatrix);
2306
2307                 for(core::list< core::aabbox3d<f32> >::Iterator i=hilightboxes.begin();
2308                                 i != hilightboxes.end(); i++)
2309                 {
2310                         /*infostream<<"hilightbox min="
2311                                         <<"("<<i->MinEdge.X<<","<<i->MinEdge.Y<<","<<i->MinEdge.Z<<")"
2312                                         <<" max="
2313                                         <<"("<<i->MaxEdge.X<<","<<i->MaxEdge.Y<<","<<i->MaxEdge.Z<<")"
2314                                         <<std::endl;*/
2315                         driver->draw3DBox(*i, video::SColor(255,0,0,0));
2316                 }
2317
2318                 /*
2319                         Wielded tool
2320                 */
2321                 {
2322                         // Warning: This clears the Z buffer.
2323                         camera.drawWieldedTool();
2324                 }
2325
2326                 /*
2327                         Post effects
2328                 */
2329                 {
2330                         client.renderPostFx();
2331                 }
2332
2333                 /*
2334                         Frametime log
2335                 */
2336                 if(g_settings->getBool("frametime_graph") == true)
2337                 {
2338                         s32 x = 10;
2339                         for(core::list<float>::Iterator
2340                                         i = frametime_log.begin();
2341                                         i != frametime_log.end();
2342                                         i++)
2343                         {
2344                                 driver->draw2DLine(v2s32(x,50),
2345                                                 v2s32(x,50+(*i)*1000),
2346                                                 video::SColor(255,255,255,255));
2347                                 x++;
2348                         }
2349                 }
2350
2351                 /*
2352                         Draw crosshair
2353                 */
2354                 driver->draw2DLine(displaycenter - core::vector2d<s32>(10,0),
2355                                 displaycenter + core::vector2d<s32>(10,0),
2356                                 video::SColor(255,255,255,255));
2357                 driver->draw2DLine(displaycenter - core::vector2d<s32>(0,10),
2358                                 displaycenter + core::vector2d<s32>(0,10),
2359                                 video::SColor(255,255,255,255));
2360
2361                 } // timer
2362
2363                 //timer10.stop();
2364                 //TimeTaker //timer11("//timer11");
2365
2366                 /*
2367                         Draw gui
2368                 */
2369                 // 0-1ms
2370                 guienv->drawAll();
2371
2372                 /*
2373                         Draw hotbar
2374                 */
2375                 {
2376                         draw_hotbar(driver, font, gamedef,
2377                                         v2s32(displaycenter.X, screensize.Y),
2378                                         hotbar_imagesize, hotbar_itemcount, &local_inventory,
2379                                         client.getHP(), client.getPlayerItem());
2380                 }
2381
2382                 /*
2383                         Damage flash
2384                 */
2385                 if(damage_flash_timer > 0.0)
2386                 {
2387                         damage_flash_timer -= dtime;
2388                         
2389                         video::SColor color(128,255,0,0);
2390                         driver->draw2DRectangle(color,
2391                                         core::rect<s32>(0,0,screensize.X,screensize.Y),
2392                                         NULL);
2393                 }
2394
2395                 /*
2396                         End scene
2397                 */
2398                 {
2399                         TimeTaker timer("endScene");
2400                         endSceneX(driver);
2401                         endscenetime = timer.stop(true);
2402                 }
2403
2404                 drawtime = drawtimer.stop(true);
2405
2406                 /*
2407                         End of drawing
2408                 */
2409
2410                 static s16 lastFPS = 0;
2411                 //u16 fps = driver->getFPS();
2412                 u16 fps = (1.0/dtime_avg1);
2413
2414                 if (lastFPS != fps)
2415                 {
2416                         core::stringw str = L"Minetest [";
2417                         str += driver->getName();
2418                         str += "] FPS=";
2419                         str += fps;
2420
2421                         device->setWindowCaption(str.c_str());
2422                         lastFPS = fps;
2423                 }
2424         }
2425
2426         /*
2427                 Drop stuff
2428         */
2429         if(clouds)
2430                 clouds->drop();
2431         
2432         /*
2433                 Draw a "shutting down" screen, which will be shown while the map
2434                 generator and other stuff quits
2435         */
2436         {
2437                 /*gui::IGUIStaticText *gui_shuttingdowntext = */
2438                 draw_load_screen(L"Shutting down stuff...", driver, font);
2439                 /*driver->beginScene(true, true, video::SColor(255,0,0,0));
2440                 guienv->drawAll();
2441                 driver->endScene();
2442                 gui_shuttingdowntext->remove();*/
2443         }
2444
2445         } // Client scope (must be destructed before destructing *def and tsrc
2446
2447         delete tsrc;
2448         delete nodedef;
2449         delete itemdef;
2450 }
2451
2452