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