3 Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
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.
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.
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.
21 #include "common_irrlicht.h"
22 #include <IGUICheckBox.h>
23 #include <IGUIEditBox.h>
24 #include <IGUIButton.h>
25 #include <IGUIStaticText.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"
42 #include "mainmenumanager.h"
46 // Needed for determining pointing to nodes
47 #include "mapnode_contentfeatures.h"
50 Setting this to 1 enables a special camera mode that forces
51 the renderers to think that the camera statically points from
52 the starting place to a static direction.
54 This allows one to move around with the player and see what
55 is actually drawn behind solid things and behind the player.
57 #define FIELD_OF_VIEW_TEST 0
67 ChatLine(const std::wstring &a_text):
80 // Inventory actions from the menu are buffered here before sending
81 Queue<InventoryAction*> inventory_action_queue;
82 // This is a copy of the inventory that the client's environment has
83 Inventory local_inventory;
85 u16 g_selected_item = 0;
91 struct TextDestChat : public TextDest
93 TextDestChat(Client *client)
97 void gotText(std::wstring text)
104 m_client->sendChatMessage(text);
106 m_client->addChatMessage(text);
112 struct TextDestNodeMetadata : public TextDest
114 TextDestNodeMetadata(v3s16 p, Client *client)
119 void gotText(std::wstring text)
121 std::string ntext = wide_to_narrow(text);
122 infostream<<"Changing text of a sign node: "
124 m_client->sendSignNodeText(m_p, ntext);
131 /* Respawn menu callback */
133 class MainRespawnInitiator: public IRespawnInitiator
136 MainRespawnInitiator(bool *active, Client *client):
137 m_active(active), m_client(client)
144 m_client->sendRespawn();
154 void draw_hotbar(video::IVideoDriver *driver, gui::IGUIFont *font,
155 v2s32 centerlowerpos, s32 imgsize, s32 itemcount,
156 Inventory *inventory, s32 halfheartcount)
158 InventoryList *mainlist = inventory->getList("main");
161 errorstream<<"draw_hotbar(): mainlist == NULL"<<std::endl;
165 s32 padding = imgsize/12;
166 //s32 height = imgsize + padding*2;
167 s32 width = itemcount*(imgsize+padding*2);
169 // Position of upper left corner of bar
170 v2s32 pos = centerlowerpos - v2s32(width/2, imgsize+padding*2);
172 // Draw background color
173 /*core::rect<s32> barrect(0,0,width,height);
175 video::SColor bgcolor(255,128,128,128);
176 driver->draw2DRectangle(bgcolor, barrect, NULL);*/
178 core::rect<s32> imgrect(0,0,imgsize,imgsize);
180 for(s32 i=0; i<itemcount; i++)
182 InventoryItem *item = mainlist->getItem(i);
184 core::rect<s32> rect = imgrect + pos
185 + v2s32(padding+i*(imgsize+padding*2), padding);
187 if(g_selected_item == i)
189 video::SColor c_outside(255,255,0,0);
190 //video::SColor c_outside(255,0,0,0);
191 //video::SColor c_inside(255,192,192,192);
192 s32 x1 = rect.UpperLeftCorner.X;
193 s32 y1 = rect.UpperLeftCorner.Y;
194 s32 x2 = rect.LowerRightCorner.X;
195 s32 y2 = rect.LowerRightCorner.Y;
196 // Black base borders
197 driver->draw2DRectangle(c_outside,
199 v2s32(x1 - padding, y1 - padding),
200 v2s32(x2 + padding, y1)
202 driver->draw2DRectangle(c_outside,
204 v2s32(x1 - padding, y2),
205 v2s32(x2 + padding, y2 + padding)
207 driver->draw2DRectangle(c_outside,
209 v2s32(x1 - padding, y1),
212 driver->draw2DRectangle(c_outside,
215 v2s32(x2 + padding, y2)
217 /*// Light inside borders
218 driver->draw2DRectangle(c_inside,
220 v2s32(x1 - padding/2, y1 - padding/2),
221 v2s32(x2 + padding/2, y1)
223 driver->draw2DRectangle(c_inside,
225 v2s32(x1 - padding/2, y2),
226 v2s32(x2 + padding/2, y2 + padding/2)
228 driver->draw2DRectangle(c_inside,
230 v2s32(x1 - padding/2, y1),
233 driver->draw2DRectangle(c_inside,
236 v2s32(x2 + padding/2, y2)
241 video::SColor bgcolor2(128,0,0,0);
242 driver->draw2DRectangle(bgcolor2, rect, NULL);
246 drawInventoryItem(driver, font, item, rect, NULL);
254 video::ITexture *heart_texture =
255 driver->getTexture(getTexturePath("heart.png").c_str());
256 v2s32 p = pos + v2s32(0, -20);
257 for(s32 i=0; i<halfheartcount/2; i++)
259 const video::SColor color(255,255,255,255);
260 const video::SColor colors[] = {color,color,color,color};
261 core::rect<s32> rect(0,0,16,16);
263 driver->draw2DImage(heart_texture, rect,
264 core::rect<s32>(core::position2d<s32>(0,0),
265 core::dimension2di(heart_texture->getOriginalSize())),
269 if(halfheartcount % 2 == 1)
271 const video::SColor color(255,255,255,255);
272 const video::SColor colors[] = {color,color,color,color};
273 core::rect<s32> rect(0,0,16/2,16);
275 core::dimension2di srcd(heart_texture->getOriginalSize());
277 driver->draw2DImage(heart_texture, rect,
278 core::rect<s32>(core::position2d<s32>(0,0), srcd),
286 Find what the player is pointing at
288 void getPointedNode(Client *client, v3f player_position,
289 v3f camera_direction, v3f camera_position,
290 bool &nodefound, core::line3d<f32> shootline,
291 v3s16 &nodepos, v3s16 &neighbourpos,
292 core::aabbox3d<f32> &nodehilightbox,
295 f32 mindistance = BS * 1001;
297 v3s16 pos_i = floatToInt(player_position, BS);
299 /*infostream<<"pos_i=("<<pos_i.X<<","<<pos_i.Y<<","<<pos_i.Z<<")"
303 s16 ystart = pos_i.Y + 0 - (camera_direction.Y<0 ? a : 1);
304 s16 zstart = pos_i.Z - (camera_direction.Z<0 ? a : 1);
305 s16 xstart = pos_i.X - (camera_direction.X<0 ? a : 1);
306 s16 yend = pos_i.Y + 1 + (camera_direction.Y>0 ? a : 1);
307 s16 zend = pos_i.Z + (camera_direction.Z>0 ? a : 1);
308 s16 xend = pos_i.X + (camera_direction.X>0 ? a : 1);
310 for(s16 y = ystart; y <= yend; y++)
311 for(s16 z = zstart; z <= zend; z++)
312 for(s16 x = xstart; x <= xend; x++)
317 n = client->getNode(v3s16(x,y,z));
318 if(content_pointable(n.getContent()) == false)
321 catch(InvalidPositionException &e)
327 v3f npf = intToFloat(np, BS);
332 v3s16(0,0,1), // back
334 v3s16(1,0,0), // right
335 v3s16(0,0,-1), // front
336 v3s16(0,-1,0), // bottom
337 v3s16(-1,0,0), // left
340 ContentFeatures &f = content_features(n);
342 if(f.selection_box.type == NODEBOX_FIXED)
344 f32 distance = (npf - camera_position).getLength();
346 core::aabbox3d<f32> box = f.selection_box.fixed;
350 if(distance < mindistance)
352 if(box.intersectsWithLine(shootline))
357 mindistance = distance;
358 nodehilightbox = box;
362 else if(f.selection_box.type == NODEBOX_WALLMOUNTED)
364 v3s16 dir = unpackDir(n.param2);
365 v3f dir_f = v3f(dir.X, dir.Y, dir.Z);
366 dir_f *= BS/2 - BS/6 - BS/20;
367 v3f cpf = npf + dir_f;
368 f32 distance = (cpf - camera_position).getLength();
370 core::aabbox3d<f32> box;
373 if(dir == v3s16(0,1,0)){
374 box = f.selection_box.wall_top;
377 else if(dir == v3s16(0,-1,0)){
378 box = f.selection_box.wall_bottom;
384 f.selection_box.wall_side.MinEdge,
385 f.selection_box.wall_side.MaxEdge
388 for(s32 i=0; i<2; i++)
390 if(dir == v3s16(-1,0,0))
391 vertices[i].rotateXZBy(0);
392 if(dir == v3s16(1,0,0))
393 vertices[i].rotateXZBy(180);
394 if(dir == v3s16(0,0,-1))
395 vertices[i].rotateXZBy(90);
396 if(dir == v3s16(0,0,1))
397 vertices[i].rotateXZBy(-90);
400 box = core::aabbox3d<f32>(vertices[0]);
401 box.addInternalPoint(vertices[1]);
407 if(distance < mindistance)
409 if(box.intersectsWithLine(shootline))
414 mindistance = distance;
415 nodehilightbox = box;
419 else // NODEBOX_REGULAR
421 for(u16 i=0; i<6; i++)
423 v3f dir_f = v3f(dirs[i].X,
424 dirs[i].Y, dirs[i].Z);
425 v3f centerpoint = npf + dir_f * BS/2;
427 (centerpoint - camera_position).getLength();
429 if(distance < mindistance)
431 core::CMatrix4<f32> m;
432 m.buildRotateFromTo(v3f(0,0,1), dir_f);
434 // This is the back face
436 v3f(BS/2, BS/2, BS/2),
437 v3f(-BS/2, -BS/2, BS/2+d)
440 for(u16 j=0; j<2; j++)
442 m.rotateVect(corners[j]);
446 core::aabbox3d<f32> facebox(corners[0]);
447 facebox.addInternalPoint(corners[1]);
449 if(facebox.intersectsWithLine(shootline))
453 neighbourpos = np + dirs[i];
454 mindistance = distance;
456 //nodehilightbox = facebox;
458 const float d = 0.502;
459 core::aabbox3d<f32> nodebox
460 (-BS*d, -BS*d, -BS*d, BS*d, BS*d, BS*d);
461 v3f nodepos_f = intToFloat(nodepos, BS);
462 nodebox.MinEdge += nodepos_f;
463 nodebox.MaxEdge += nodepos_f;
464 nodehilightbox = nodebox;
466 } // if distance < mindistance
472 void update_skybox(video::IVideoDriver* driver,
473 scene::ISceneManager* smgr, scene::ISceneNode* &skybox,
481 /*// Disable skybox if FarMesh is enabled
482 if(g_settings->getBool("enable_farmesh"))
485 if(brightness >= 0.5)
487 skybox = smgr->addSkyBoxSceneNode(
488 driver->getTexture(getTexturePath("skybox2.png").c_str()),
489 driver->getTexture(getTexturePath("skybox3.png").c_str()),
490 driver->getTexture(getTexturePath("skybox1.png").c_str()),
491 driver->getTexture(getTexturePath("skybox1.png").c_str()),
492 driver->getTexture(getTexturePath("skybox1.png").c_str()),
493 driver->getTexture(getTexturePath("skybox1.png").c_str()));
495 else if(brightness >= 0.2)
497 skybox = smgr->addSkyBoxSceneNode(
498 driver->getTexture(getTexturePath("skybox2_dawn.png").c_str()),
499 driver->getTexture(getTexturePath("skybox3_dawn.png").c_str()),
500 driver->getTexture(getTexturePath("skybox1_dawn.png").c_str()),
501 driver->getTexture(getTexturePath("skybox1_dawn.png").c_str()),
502 driver->getTexture(getTexturePath("skybox1_dawn.png").c_str()),
503 driver->getTexture(getTexturePath("skybox1_dawn.png").c_str()));
507 skybox = smgr->addSkyBoxSceneNode(
508 driver->getTexture(getTexturePath("skybox2_night.png").c_str()),
509 driver->getTexture(getTexturePath("skybox3_night.png").c_str()),
510 driver->getTexture(getTexturePath("skybox1_night.png").c_str()),
511 driver->getTexture(getTexturePath("skybox1_night.png").c_str()),
512 driver->getTexture(getTexturePath("skybox1_night.png").c_str()),
513 driver->getTexture(getTexturePath("skybox1_night.png").c_str()));
518 Draws a screen with a single text on it.
519 Text will be removed when the screen is drawn the next time.
521 /*gui::IGUIStaticText **/
522 void draw_load_screen(const std::wstring &text,
523 video::IVideoDriver* driver, gui::IGUIFont* font)
525 v2u32 screensize = driver->getScreenSize();
526 const wchar_t *loadingtext = text.c_str();
527 core::vector2d<u32> textsize_u = font->getDimension(loadingtext);
528 core::vector2d<s32> textsize(textsize_u.X,textsize_u.Y);
529 core::vector2d<s32> center(screensize.X/2, screensize.Y/2);
530 core::rect<s32> textrect(center - textsize/2, center + textsize/2);
532 gui::IGUIStaticText *guitext = guienv->addStaticText(
533 loadingtext, textrect, false, false);
534 guitext->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);
536 driver->beginScene(true, true, video::SColor(255,0,0,0));
549 IrrlichtDevice *device,
552 std::string playername,
553 std::string password,
556 std::wstring &error_message,
557 std::string configpath
560 video::IVideoDriver* driver = device->getVideoDriver();
561 scene::ISceneManager* smgr = device->getSceneManager();
563 // Calculate text height using the font
564 u32 text_height = font->getDimension(L"Random test string").Height;
566 v2u32 screensize(0,0);
567 v2u32 last_screensize(0,0);
568 screensize = driver->getScreenSize();
570 const s32 hotbar_itemcount = 8;
571 //const s32 hotbar_imagesize = 36;
572 //const s32 hotbar_imagesize = 64;
573 s32 hotbar_imagesize = 48;
575 // The color of the sky
577 //video::SColor skycolor = video::SColor(255,140,186,250);
579 video::SColor bgcolor_bright = video::SColor(255,170,200,230);
582 Draw "Loading" screen
584 /*gui::IGUIStaticText *gui_loadingtext = */
585 //draw_load_screen(L"Loading and connecting...", driver, font);
587 draw_load_screen(L"Loading...", driver, font);
591 SharedPtr will delete it when it goes out of scope.
593 SharedPtr<Server> server;
595 draw_load_screen(L"Creating server...", driver, font);
596 infostream<<"Creating server"<<std::endl;
597 server = new Server(map_dir, configpath);
605 draw_load_screen(L"Creating client...", driver, font);
606 infostream<<"Creating client"<<std::endl;
607 MapDrawControl draw_control;
608 Client client(device, playername.c_str(), password, draw_control);
610 draw_load_screen(L"Resolving address...", driver, font);
611 Address connect_address(0,0,0,0, port);
614 //connect_address.Resolve("localhost");
615 connect_address.setAddress(127,0,0,1);
617 connect_address.Resolve(address.c_str());
619 catch(ResolveError &e)
621 errorstream<<"Couldn't resolve address"<<std::endl;
623 error_message = L"Couldn't resolve address";
624 //gui_loadingtext->remove();
629 Attempt to connect to the server
632 infostream<<"Connecting to server at ";
633 connect_address.print(&infostream);
634 infostream<<std::endl;
635 client.connect(connect_address);
637 bool could_connect = false;
640 float time_counter = 0.0;
643 if(client.connectedAndInitialized())
645 could_connect = true;
648 if(client.accessDenied())
652 // Wait for 10 seconds
653 if(time_counter >= 10.0)
658 std::wostringstream ss;
659 ss<<L"Connecting to server... (timeout in ";
660 ss<<(int)(10.0 - time_counter + 1.0);
662 draw_load_screen(ss.str(), driver, font);
665 driver->beginScene(true, true, video::SColor(255,0,0,0));
667 driver->endScene();*/
669 // Update client and server
681 catch(con::PeerNotFoundException &e)
684 if(could_connect == false)
686 if(client.accessDenied())
688 error_message = L"Access denied. Reason: "
689 +client.accessDeniedReason();
690 errorstream<<wide_to_narrow(error_message)<<std::endl;
694 error_message = L"Connection timed out.";
695 errorstream<<"Timed out."<<std::endl;
697 //gui_loadingtext->remove();
704 float old_brightness = 1.0;
705 scene::ISceneNode* skybox = NULL;
706 update_skybox(driver, smgr, skybox, 1.0);
709 Create the camera node
711 Camera camera(smgr, draw_control);
712 if (!camera.successfullyCreated(error_message))
715 f32 camera_yaw = 0; // "right/left"
716 f32 camera_pitch = 0; // "up/down"
722 float cloud_height = BS*100;
723 Clouds *clouds = NULL;
724 if(g_settings->getBool("enable_clouds"))
726 clouds = new Clouds(smgr->getRootSceneNode(), smgr, -1,
727 cloud_height, time(0));
734 FarMesh *farmesh = NULL;
735 if(g_settings->getBool("enable_farmesh"))
737 farmesh = new FarMesh(smgr->getRootSceneNode(), smgr, -1, client.getMapSeed(), &client);
744 //gui_loadingtext->remove();
750 // First line of debug text
751 gui::IGUIStaticText *guitext = guienv->addStaticText(
753 core::rect<s32>(5, 5, 795, 5+text_height),
755 // Second line of debug text
756 gui::IGUIStaticText *guitext2 = guienv->addStaticText(
758 core::rect<s32>(5, 5+(text_height+5)*1, 795, (5+text_height)*2),
760 // At the middle of the screen
761 // Object infos are shown in this
762 gui::IGUIStaticText *guitext_info = guienv->addStaticText(
764 core::rect<s32>(0,0,400,text_height+5) + v2s32(100,200),
768 gui::IGUIStaticText *guitext_chat = guienv->addStaticText(
770 core::rect<s32>(0,0,0,0),
771 //false, false); // Disable word wrap as of now
773 //guitext_chat->setBackgroundColor(video::SColor(96,0,0,0));
774 core::list<ChatLine> chat_lines;
776 // Profiler text (size is updated when text is updated)
777 gui::IGUIStaticText *guitext_profiler = guienv->addStaticText(
779 core::rect<s32>(6, 4+(text_height+5)*2, 400,
780 (text_height+5)*2 + text_height*35),
782 guitext_profiler->setBackgroundColor(video::SColor(80,0,0,0));
783 guitext_profiler->setVisible(false);
785 /*GUIQuickInventory *quick_inventory = new GUIQuickInventory
786 (guienv, NULL, v2s32(10, 70), 5, &local_inventory);*/
787 /*GUIQuickInventory *quick_inventory = new GUIQuickInventory
788 (guienv, NULL, v2s32(0, 0), quickinv_itemcount, &local_inventory);*/
790 // Test the text input system
791 /*(new GUITextInputMenu(guienv, guiroot, -1, &g_menumgr,
793 /*GUIMessageMenu *menu =
794 new GUIMessageMenu(guienv, guiroot, -1,
800 (new GUIPauseMenu(guienv, guiroot, -1, g_gamecallback,
801 &g_menumgr))->drop();
804 /*guitext2->setVisible(true);
805 guitext_info->setVisible(true);
806 guitext_chat->setVisible(true);*/
808 //s32 guitext_chat_pad_bottom = 70;
811 Some statistics are collected in these
814 u32 beginscenetime = 0;
816 u32 endscenetime = 0;
819 //throw con::PeerNotFoundException("lol");
821 core::list<float> frametime_log;
823 float nodig_delay_counter = 0.0;
824 float dig_time = 0.0;
826 v3s16 nodepos_old(-32768,-32768,-32768);
828 float damage_flash_timer = 0;
829 s16 farmesh_range = 20*MAP_BLOCKSIZE;
831 const float object_hit_delay = 0.5;
832 float object_hit_delay_timer = 0.0;
834 bool invert_mouse = g_settings->getBool("invert_mouse");
836 bool respawn_menu_active = false;
838 bool show_profiler = false;
839 bool force_fog_off = false;
840 bool disable_camera_update = false;
846 bool first_loop_after_window_activation = true;
848 // TODO: Convert the static interval timers to these
849 // Interval limiter for profiler
850 IntervalLimiter m_profiler_interval;
852 // Time is in milliseconds
853 // NOTE: getRealTime() causes strange problems in wine (imprecision?)
854 // NOTE: So we have to use getTime() and call run()s between them
855 u32 lasttime = device->getTimer()->getTime();
857 while(device->run() && kill == false)
859 //std::cerr<<"frame"<<std::endl;
861 if(client.accessDenied())
863 error_message = L"Access denied. Reason: "
864 +client.accessDeniedReason();
865 errorstream<<wide_to_narrow(error_message)<<std::endl;
869 if(g_gamecallback->disconnect_requested)
871 g_gamecallback->disconnect_requested = false;
875 if(g_gamecallback->changepassword_requested)
877 (new GUIPasswordChange(guienv, guiroot, -1,
878 &g_menumgr, &client))->drop();
879 g_gamecallback->changepassword_requested = false;
883 Process TextureSource's queue
885 ((TextureSource*)g_texturesource)->processQueue();
890 last_screensize = screensize;
891 screensize = driver->getScreenSize();
892 v2s32 displaycenter(screensize.X/2,screensize.Y/2);
893 //bool screensize_changed = screensize != last_screensize;
896 if(screensize.Y <= 800)
897 hotbar_imagesize = 32;
898 else if(screensize.Y <= 1280)
899 hotbar_imagesize = 48;
901 hotbar_imagesize = 64;
903 // Hilight boxes collected during the loop and displayed
904 core::list< core::aabbox3d<f32> > hilightboxes;
907 std::wstring infotext;
909 // When screen size changes, update positions and sizes of stuff
910 /*if(screensize_changed)
912 v2s32 pos(displaycenter.X-((quickinv_itemcount-1)*quickinv_spacing+quickinv_size)/2, screensize.Y-quickinv_spacing);
913 quick_inventory->updatePosition(pos);
916 //TimeTaker //timer1("//timer1");
918 // Time of frame without fps limit
922 // not using getRealTime is necessary for wine
923 u32 time = device->getTimer()->getTime();
925 busytime_u32 = time - lasttime;
928 busytime = busytime_u32 / 1000.0;
931 //infostream<<"busytime_u32="<<busytime_u32<<std::endl;
933 // Necessary for device->getTimer()->getTime()
941 float fps_max = g_settings->getFloat("fps_max");
942 u32 frametime_min = 1000./fps_max;
944 if(busytime_u32 < frametime_min)
946 u32 sleeptime = frametime_min - busytime_u32;
947 device->sleep(sleeptime);
951 // Necessary for device->getTimer()->getTime()
955 Time difference calculation
957 f32 dtime; // in seconds
959 u32 time = device->getTimer()->getTime();
961 dtime = (time - lasttime) / 1000.0;
968 object_hit_delay_timer -= dtime;
970 g_profiler->add("Elapsed time", dtime);
971 g_profiler->avg("FPS", 1./dtime);
974 Log frametime for visualization
976 frametime_log.push_back(dtime);
977 if(frametime_log.size() > 100)
979 core::list<float>::Iterator i = frametime_log.begin();
980 frametime_log.erase(i);
984 Visualize frametime in terminal
986 /*for(u32 i=0; i<dtime*400; i++)
988 infostream<<std::endl;*/
991 Time average and jitter calculation
994 static f32 dtime_avg1 = 0.0;
995 dtime_avg1 = dtime_avg1 * 0.96 + dtime * 0.04;
996 f32 dtime_jitter1 = dtime - dtime_avg1;
998 static f32 dtime_jitter1_max_sample = 0.0;
999 static f32 dtime_jitter1_max_fraction = 0.0;
1001 static f32 jitter1_max = 0.0;
1002 static f32 counter = 0.0;
1003 if(dtime_jitter1 > jitter1_max)
1004 jitter1_max = dtime_jitter1;
1009 dtime_jitter1_max_sample = jitter1_max;
1010 dtime_jitter1_max_fraction
1011 = dtime_jitter1_max_sample / (dtime_avg1+0.001);
1017 Busytime average and jitter calculation
1020 static f32 busytime_avg1 = 0.0;
1021 busytime_avg1 = busytime_avg1 * 0.98 + busytime * 0.02;
1022 f32 busytime_jitter1 = busytime - busytime_avg1;
1024 static f32 busytime_jitter1_max_sample = 0.0;
1025 static f32 busytime_jitter1_min_sample = 0.0;
1027 static f32 jitter1_max = 0.0;
1028 static f32 jitter1_min = 0.0;
1029 static f32 counter = 0.0;
1030 if(busytime_jitter1 > jitter1_max)
1031 jitter1_max = busytime_jitter1;
1032 if(busytime_jitter1 < jitter1_min)
1033 jitter1_min = busytime_jitter1;
1037 busytime_jitter1_max_sample = jitter1_max;
1038 busytime_jitter1_min_sample = jitter1_min;
1045 Debug info for client
1048 static float counter = 0.0;
1053 client.printDebugInfo(infostream);
1060 float profiler_print_interval =
1061 g_settings->getFloat("profiler_print_interval");
1062 bool print_to_log = true;
1063 if(profiler_print_interval == 0){
1064 print_to_log = false;
1065 profiler_print_interval = 5;
1067 if(m_profiler_interval.step(dtime, profiler_print_interval))
1070 infostream<<"Profiler:"<<std::endl;
1071 g_profiler->print(infostream);
1074 std::ostringstream os(std::ios_base::binary);
1075 g_profiler->print(os);
1076 std::wstring text = narrow_to_wide(os.str());
1077 guitext_profiler->setText(text.c_str());
1079 g_profiler->clear();
1081 s32 w = font->getDimension(text.c_str()).Width;
1084 core::rect<s32> rect(6, 4+(text_height+5)*2, 12+w,
1085 8+(text_height+5)*2 +
1086 font->getDimension(text.c_str()).Height);
1087 guitext_profiler->setRelativePosition(rect);
1091 Direct handling of user input
1094 // Reset input if window not active or some menu is active
1095 if(device->isWindowActive() == false || noMenuActive() == false)
1100 // Input handler step() (used by the random input generator)
1104 Launch menus according to keys
1106 if(input->wasKeyDown(getKeySetting("keymap_inventory")))
1108 infostream<<"the_game: "
1109 <<"Launching inventory"<<std::endl;
1111 GUIInventoryMenu *menu =
1112 new GUIInventoryMenu(guienv, guiroot, -1,
1113 &g_menumgr, v2s16(8,7),
1114 client.getInventoryContext(),
1117 core::array<GUIInventoryMenu::DrawSpec> draw_spec;
1118 draw_spec.push_back(GUIInventoryMenu::DrawSpec(
1119 "list", "current_player", "main",
1120 v2s32(0, 3), v2s32(8, 4)));
1121 draw_spec.push_back(GUIInventoryMenu::DrawSpec(
1122 "list", "current_player", "craft",
1123 v2s32(3, 0), v2s32(3, 3)));
1124 draw_spec.push_back(GUIInventoryMenu::DrawSpec(
1125 "list", "current_player", "craftresult",
1126 v2s32(7, 1), v2s32(1, 1)));
1128 menu->setDrawSpec(draw_spec);
1132 else if(input->wasKeyDown(EscapeKey))
1134 infostream<<"the_game: "
1135 <<"Launching pause menu"<<std::endl;
1136 // It will delete itself by itself
1137 (new GUIPauseMenu(guienv, guiroot, -1, g_gamecallback,
1138 &g_menumgr))->drop();
1140 // Move mouse cursor on top of the disconnect button
1141 input->setMousePos(displaycenter.X, displaycenter.Y+25);
1143 else if(input->wasKeyDown(getKeySetting("keymap_chat")))
1145 TextDest *dest = new TextDestChat(&client);
1147 (new GUITextInputMenu(guienv, guiroot, -1,
1151 else if(input->wasKeyDown(getKeySetting("keymap_cmd")))
1153 TextDest *dest = new TextDestChat(&client);
1155 (new GUITextInputMenu(guienv, guiroot, -1,
1159 else if(input->wasKeyDown(getKeySetting("keymap_freemove")))
1161 if(g_settings->getBool("free_move"))
1163 g_settings->set("free_move","false");
1164 chat_lines.push_back(ChatLine(L"free_move disabled"));
1168 g_settings->set("free_move","true");
1169 chat_lines.push_back(ChatLine(L"free_move enabled"));
1172 else if(input->wasKeyDown(getKeySetting("keymap_fastmove")))
1174 if(g_settings->getBool("fast_move"))
1176 g_settings->set("fast_move","false");
1177 chat_lines.push_back(ChatLine(L"fast_move disabled"));
1181 g_settings->set("fast_move","true");
1182 chat_lines.push_back(ChatLine(L"fast_move enabled"));
1185 else if(input->wasKeyDown(getKeySetting("keymap_frametime_graph")))
1187 if(g_settings->getBool("frametime_graph"))
1189 g_settings->set("frametime_graph","false");
1190 chat_lines.push_back(ChatLine(L"frametime_graph disabled"));
1194 g_settings->set("frametime_graph","true");
1195 chat_lines.push_back(ChatLine(L"frametime_graph enabled"));
1198 else if(input->wasKeyDown(getKeySetting("keymap_screenshot")))
1200 irr::video::IImage* const image = driver->createScreenShot();
1202 irr::c8 filename[256];
1203 snprintf(filename, 256, "%s" DIR_DELIM "screenshot_%u.png",
1204 g_settings->get("screenshot_path").c_str(),
1205 device->getTimer()->getRealTime());
1206 if (driver->writeImageToFile(image, filename)) {
1207 std::wstringstream sstr;
1208 sstr<<"Saved screenshot to '"<<filename<<"'";
1209 infostream<<"Saved screenshot to '"<<filename<<"'"<<std::endl;
1210 chat_lines.push_back(ChatLine(sstr.str()));
1212 infostream<<"Failed to save screenshot '"<<filename<<"'"<<std::endl;
1217 else if(input->wasKeyDown(getKeySetting("keymap_toggle_profiler")))
1219 show_profiler = !show_profiler;
1220 guitext_profiler->setVisible(show_profiler);
1222 chat_lines.push_back(ChatLine(L"Profiler disabled"));
1224 chat_lines.push_back(ChatLine(L"Profiler enabled"));
1226 else if(input->wasKeyDown(getKeySetting("keymap_toggle_force_fog_off")))
1228 force_fog_off = !force_fog_off;
1230 chat_lines.push_back(ChatLine(L"Fog disabled"));
1232 chat_lines.push_back(ChatLine(L"Fog enabled"));
1234 else if(input->wasKeyDown(getKeySetting("keymap_toggle_update_camera")))
1236 disable_camera_update = !disable_camera_update;
1237 if(disable_camera_update)
1238 chat_lines.push_back(ChatLine(L"Camera update disabled"));
1240 chat_lines.push_back(ChatLine(L"Camera update enabled"));
1243 // Item selection with mouse wheel
1245 s32 wheel = input->getMouseWheel();
1246 u16 max_item = MYMIN(PLAYER_INVENTORY_SIZE-1,
1247 hotbar_itemcount-1);
1251 if(g_selected_item < max_item)
1254 g_selected_item = 0;
1258 if(g_selected_item > 0)
1261 g_selected_item = max_item;
1266 for(u16 i=0; i<10; i++)
1268 const KeyPress *kp = NumberKey + (i + 1) % 10;
1269 if(input->wasKeyDown(*kp))
1271 if(i < PLAYER_INVENTORY_SIZE && i < hotbar_itemcount)
1273 g_selected_item = i;
1275 infostream<<"Selected item: "
1276 <<g_selected_item<<std::endl;
1281 // Viewing range selection
1282 if(input->wasKeyDown(getKeySetting("keymap_rangeselect")))
1284 if(draw_control.range_all)
1286 draw_control.range_all = false;
1287 infostream<<"Disabled full viewing range"<<std::endl;
1291 draw_control.range_all = true;
1292 infostream<<"Enabled full viewing range"<<std::endl;
1296 // Print debug stacks
1297 if(input->wasKeyDown(getKeySetting("keymap_print_debug_stacks")))
1299 dstream<<"-----------------------------------------"
1301 dstream<<DTIME<<"Printing debug stacks:"<<std::endl;
1302 dstream<<"-----------------------------------------"
1304 debug_stacks_print();
1308 Mouse and camera control
1309 NOTE: Do this before client.setPlayerControl() to not cause a camera lag of one frame
1312 if((device->isWindowActive() && noMenuActive()) || random_input)
1316 // Mac OSX gets upset if this is set every frame
1317 if(device->getCursorControl()->isVisible())
1318 device->getCursorControl()->setVisible(false);
1321 if(first_loop_after_window_activation){
1322 //infostream<<"window active, first loop"<<std::endl;
1323 first_loop_after_window_activation = false;
1326 s32 dx = input->getMousePos().X - displaycenter.X;
1327 s32 dy = input->getMousePos().Y - displaycenter.Y;
1330 //infostream<<"window active, pos difference "<<dx<<","<<dy<<std::endl;
1332 /*const float keyspeed = 500;
1333 if(input->isKeyDown(irr::KEY_UP))
1334 dy -= dtime * keyspeed;
1335 if(input->isKeyDown(irr::KEY_DOWN))
1336 dy += dtime * keyspeed;
1337 if(input->isKeyDown(irr::KEY_LEFT))
1338 dx -= dtime * keyspeed;
1339 if(input->isKeyDown(irr::KEY_RIGHT))
1340 dx += dtime * keyspeed;*/
1342 camera_yaw -= dx*0.2;
1343 camera_pitch += dy*0.2;
1344 if(camera_pitch < -89.5) camera_pitch = -89.5;
1345 if(camera_pitch > 89.5) camera_pitch = 89.5;
1347 input->setMousePos(displaycenter.X, displaycenter.Y);
1350 // Mac OSX gets upset if this is set every frame
1351 if(device->getCursorControl()->isVisible() == false)
1352 device->getCursorControl()->setVisible(true);
1354 //infostream<<"window inactive"<<std::endl;
1355 first_loop_after_window_activation = true;
1359 Player speed control
1362 if(!noMenuActive() || !device->isWindowActive())
1364 PlayerControl control(
1375 client.setPlayerControl(control);
1388 PlayerControl control(
1389 input->isKeyDown(getKeySetting("keymap_forward")),
1390 input->isKeyDown(getKeySetting("keymap_backward")),
1391 input->isKeyDown(getKeySetting("keymap_left")),
1392 input->isKeyDown(getKeySetting("keymap_right")),
1393 input->isKeyDown(getKeySetting("keymap_jump")),
1394 input->isKeyDown(getKeySetting("keymap_special1")),
1395 input->isKeyDown(getKeySetting("keymap_sneak")),
1399 client.setPlayerControl(control);
1408 //TimeTaker timer("server->step(dtime)");
1409 server->step(dtime);
1417 //TimeTaker timer("client.step(dtime)");
1419 //client.step(dtime_avg1);
1423 // Read client events
1426 ClientEvent event = client.getClientEvent();
1427 if(event.type == CE_NONE)
1431 else if(event.type == CE_PLAYER_DAMAGE)
1433 //u16 damage = event.player_damage.amount;
1434 //infostream<<"Player damage: "<<damage<<std::endl;
1435 damage_flash_timer = 0.05;
1436 if(event.player_damage.amount >= 2){
1437 damage_flash_timer += 0.05 * event.player_damage.amount;
1440 else if(event.type == CE_PLAYER_FORCE_MOVE)
1442 camera_yaw = event.player_force_move.yaw;
1443 camera_pitch = event.player_force_move.pitch;
1445 else if(event.type == CE_DEATHSCREEN)
1447 if(respawn_menu_active)
1450 /*bool set_camera_point_target =
1451 event.deathscreen.set_camera_point_target;
1452 v3f camera_point_target;
1453 camera_point_target.X = event.deathscreen.camera_point_target_x;
1454 camera_point_target.Y = event.deathscreen.camera_point_target_y;
1455 camera_point_target.Z = event.deathscreen.camera_point_target_z;*/
1456 MainRespawnInitiator *respawner =
1457 new MainRespawnInitiator(
1458 &respawn_menu_active, &client);
1459 GUIDeathScreen *menu =
1460 new GUIDeathScreen(guienv, guiroot, -1,
1461 &g_menumgr, respawner);
1464 /* Handle visualization */
1466 damage_flash_timer = 0;
1468 /*LocalPlayer* player = client.getLocalPlayer();
1469 player->setPosition(player->getPosition() + v3f(0,-BS,0));
1470 camera.update(player, busytime, screensize);*/
1475 //TimeTaker //timer2("//timer2");
1477 LocalPlayer* player = client.getLocalPlayer();
1478 camera.update(player, busytime, screensize);
1481 v3f player_position = player->getPosition();
1482 v3f camera_position = camera.getPosition();
1483 v3f camera_direction = camera.getDirection();
1484 f32 camera_fov = camera.getFovMax();
1486 if(!disable_camera_update){
1487 client.updateCamera(camera_position,
1488 camera_direction, camera_fov);
1492 //TimeTaker //timer3("//timer3");
1495 Calculate what block is the crosshair pointing to
1498 //u32 t1 = device->getTimer()->getRealTime();
1500 //f32 d = 4; // max. distance
1501 f32 d = 4; // max. distance
1502 core::line3d<f32> shootline(camera_position,
1503 camera_position + camera_direction * BS * (d+1));
1505 ClientActiveObject *selected_active_object
1506 = client.getSelectedActiveObject
1507 (d*BS, camera_position, shootline);
1509 bool left_punch = false;
1510 bool left_punch_muted = false;
1512 if(selected_active_object != NULL)
1514 /* Clear possible cracking animation */
1515 if(nodepos_old != v3s16(-32768,-32768,-32768))
1517 client.clearTempMod(nodepos_old);
1519 nodepos_old = v3s16(-32768,-32768,-32768);
1522 //infostream<<"Client returned selected_active_object != NULL"<<std::endl;
1524 core::aabbox3d<f32> *selection_box
1525 = selected_active_object->getSelectionBox();
1526 // Box should exist because object was returned in the
1528 assert(selection_box);
1530 v3f pos = selected_active_object->getPosition();
1532 core::aabbox3d<f32> box_on_map(
1533 selection_box->MinEdge + pos,
1534 selection_box->MaxEdge + pos
1537 if(selected_active_object->doShowSelectionBox())
1538 hilightboxes.push_back(box_on_map);
1540 //infotext = narrow_to_wide("A ClientActiveObject");
1541 infotext = narrow_to_wide(selected_active_object->infoText());
1543 //if(input->getLeftClicked())
1544 if(input->getLeftState())
1546 bool do_punch = false;
1547 bool do_punch_damage = false;
1548 if(object_hit_delay_timer <= 0.0){
1550 do_punch_damage = true;
1551 object_hit_delay_timer = object_hit_delay;
1553 if(input->getLeftClicked()){
1557 infostream<<"Left-clicked object"<<std::endl;
1560 if(do_punch_damage){
1561 client.clickActiveObject(0,
1562 selected_active_object->getId(), g_selected_item);
1565 else if(input->getRightClicked())
1567 infostream<<"Right-clicked object"<<std::endl;
1568 client.clickActiveObject(1,
1569 selected_active_object->getId(), g_selected_item);
1572 else // selected_object == NULL
1576 Find out which node we are pointing at
1579 bool nodefound = false;
1582 core::aabbox3d<f32> nodehilightbox;
1584 getPointedNode(&client, player_position,
1585 camera_direction, camera_position,
1586 nodefound, shootline,
1587 nodepos, neighbourpos,
1591 if(nodepos_old != v3s16(-32768,-32768,-32768))
1593 client.clearTempMod(nodepos_old);
1595 nodepos_old = v3s16(-32768,-32768,-32768);
1602 hilightboxes.push_back(nodehilightbox);
1605 Check information text of node
1608 NodeMetadata *meta = client.getNodeMetadata(nodepos);
1611 infotext = narrow_to_wide(meta->infoText());
1614 //MapNode node = client.getNode(nodepos);
1620 if(input->getLeftReleased())
1622 client.clearTempMod(nodepos);
1626 if(nodig_delay_counter > 0.0)
1628 nodig_delay_counter -= dtime;
1632 if(nodepos != nodepos_old)
1634 infostream<<"Pointing at ("<<nodepos.X<<","
1635 <<nodepos.Y<<","<<nodepos.Z<<")"<<std::endl;
1637 if(nodepos_old != v3s16(-32768,-32768,-32768))
1639 client.clearTempMod(nodepos_old);
1641 nodepos_old = v3s16(-32768,-32768,-32768);
1645 if(input->getLeftClicked() ||
1646 (input->getLeftState() && nodepos != nodepos_old))
1648 infostream<<"Started digging"<<std::endl;
1649 client.groundAction(0, nodepos, neighbourpos, g_selected_item);
1651 if(input->getLeftClicked())
1653 client.setTempMod(nodepos, NodeMod(NODEMOD_CRACK, 0));
1655 if(input->getLeftState())
1657 MapNode n = client.getNode(nodepos);
1659 // Get tool name. Default is "" = bare hands
1660 std::string toolname = "";
1661 InventoryList *mlist = local_inventory.getList("main");
1664 InventoryItem *item = mlist->getItem(g_selected_item);
1665 if(item && (std::string)item->getName() == "ToolItem")
1667 ToolItem *titem = (ToolItem*)item;
1668 toolname = titem->getToolName();
1672 // Get digging properties for material and tool
1673 content_t material = n.getContent();
1674 DiggingProperties prop =
1675 getDiggingProperties(material, toolname);
1677 float dig_time_complete = 0.0;
1679 if(prop.diggable == false)
1681 /*infostream<<"Material "<<(int)material
1682 <<" not diggable with \""
1683 <<toolname<<"\""<<std::endl;*/
1684 // I guess nobody will wait for this long
1685 dig_time_complete = 10000000.0;
1689 dig_time_complete = prop.time;
1692 if(dig_time_complete >= 0.001)
1694 dig_index = (u16)((float)CRACK_ANIMATION_LENGTH
1695 * dig_time/dig_time_complete);
1697 // This is for torches
1700 dig_index = CRACK_ANIMATION_LENGTH;
1703 if(dig_index < CRACK_ANIMATION_LENGTH)
1705 //TimeTaker timer("client.setTempMod");
1706 //infostream<<"dig_index="<<dig_index<<std::endl;
1707 client.setTempMod(nodepos, NodeMod(NODEMOD_CRACK, dig_index));
1711 infostream<<"Digging completed"<<std::endl;
1712 client.groundAction(3, nodepos, neighbourpos, g_selected_item);
1713 client.clearTempMod(nodepos);
1714 client.removeNode(nodepos);
1718 nodig_delay_counter = dig_time_complete
1719 / (float)CRACK_ANIMATION_LENGTH;
1721 // We don't want a corresponding delay to
1722 // very time consuming nodes
1723 if(nodig_delay_counter > 0.5)
1725 nodig_delay_counter = 0.5;
1727 // We want a slight delay to very little
1728 // time consuming nodes
1729 float mindelay = 0.15;
1730 if(nodig_delay_counter < mindelay)
1732 nodig_delay_counter = mindelay;
1738 camera.setDigging(0); // left click animation
1743 if(input->getRightClicked())
1745 infostream<<"Ground right-clicked"<<std::endl;
1747 // If metadata provides an inventory view, activate it
1748 if(meta && meta->getInventoryDrawSpecString() != "" && !random_input)
1750 infostream<<"Launching custom inventory view"<<std::endl;
1752 Construct the unique identification string of the node
1754 std::string current_name;
1755 current_name += "nodemeta:";
1756 current_name += itos(nodepos.X);
1757 current_name += ",";
1758 current_name += itos(nodepos.Y);
1759 current_name += ",";
1760 current_name += itos(nodepos.Z);
1766 core::array<GUIInventoryMenu::DrawSpec> draw_spec;
1768 GUIInventoryMenu::makeDrawSpecArrayFromString(
1770 meta->getInventoryDrawSpecString(),
1773 GUIInventoryMenu *menu =
1774 new GUIInventoryMenu(guienv, guiroot, -1,
1775 &g_menumgr, invsize,
1776 client.getInventoryContext(),
1778 menu->setDrawSpec(draw_spec);
1781 // If metadata provides text input, activate text input
1782 else if(meta && meta->allowsTextInput() && !random_input)
1784 infostream<<"Launching metadata text input"<<std::endl;
1786 // Get a new text for it
1788 TextDest *dest = new TextDestNodeMetadata(nodepos, &client);
1790 std::wstring wtext = narrow_to_wide(meta->getText());
1792 (new GUITextInputMenu(guienv, guiroot, -1,
1796 // Otherwise report right click to server
1799 client.groundAction(1, nodepos, neighbourpos, g_selected_item);
1800 camera.setDigging(1); // right click animation
1804 nodepos_old = nodepos;
1807 } // selected_object == NULL
1809 if(left_punch || (input->getLeftClicked() && !left_punch_muted))
1811 camera.setDigging(0); // left click animation
1814 input->resetLeftClicked();
1815 input->resetRightClicked();
1817 if(input->getLeftReleased())
1819 infostream<<"Left button released (stopped digging)"
1821 client.groundAction(2, v3s16(0,0,0), v3s16(0,0,0), 0);
1823 if(input->getRightReleased())
1825 //inostream<<DTIME<<"Right released"<<std::endl;
1829 input->resetLeftReleased();
1830 input->resetRightReleased();
1833 Calculate stuff for drawing
1836 u32 daynight_ratio = client.getDayNightRatio();
1837 u8 l = decode_light((daynight_ratio * LIGHT_SUN) / 1000);
1838 video::SColor bgcolor = video::SColor(
1840 bgcolor_bright.getRed() * l / 255,
1841 bgcolor_bright.getGreen() * l / 255,
1842 bgcolor_bright.getBlue() * l / 255);
1843 /*skycolor.getRed() * l / 255,
1844 skycolor.getGreen() * l / 255,
1845 skycolor.getBlue() * l / 255);*/
1847 float brightness = (float)l/255.0;
1852 if(fabs(brightness - old_brightness) > 0.01)
1853 update_skybox(driver, smgr, skybox, brightness);
1860 clouds->step(dtime);
1861 clouds->update(v2f(player_position.X, player_position.Z),
1862 0.05+brightness*0.95);
1870 farmesh_range = draw_control.wanted_range * 10;
1871 if(draw_control.range_all && farmesh_range < 500)
1872 farmesh_range = 500;
1873 if(farmesh_range > 1000)
1874 farmesh_range = 1000;
1876 farmesh->step(dtime);
1877 farmesh->update(v2f(player_position.X, player_position.Z),
1878 0.05+brightness*0.95, farmesh_range);
1881 // Store brightness value
1882 old_brightness = brightness;
1888 if(g_settings->getBool("enable_fog") == true && !force_fog_off)
1893 range = BS*farmesh_range;
1897 range = draw_control.wanted_range*BS + MAP_BLOCKSIZE*BS*1.5;
1899 if(draw_control.range_all)
1902 range = range * 0.5 + 25*BS;*/
1907 video::EFT_FOG_LINEAR,
1919 video::EFT_FOG_LINEAR,
1929 Update gui stuff (0ms)
1932 //TimeTaker guiupdatetimer("Gui updating");
1935 static float drawtime_avg = 0;
1936 drawtime_avg = drawtime_avg * 0.95 + (float)drawtime*0.05;
1937 static float beginscenetime_avg = 0;
1938 beginscenetime_avg = beginscenetime_avg * 0.95 + (float)beginscenetime*0.05;
1939 static float scenetime_avg = 0;
1940 scenetime_avg = scenetime_avg * 0.95 + (float)scenetime*0.05;
1941 static float endscenetime_avg = 0;
1942 endscenetime_avg = endscenetime_avg * 0.95 + (float)endscenetime*0.05;
1945 snprintf(temptext, 300, "Minetest-c55 %s ("
1948 " drawtime=%.0f, beginscenetime=%.0f"
1949 ", scenetime=%.0f, endscenetime=%.0f",
1951 draw_control.range_all,
1958 guitext->setText(narrow_to_wide(temptext).c_str());
1963 snprintf(temptext, 300,
1964 "(% .1f, % .1f, % .1f)"
1965 " (% .3f < btime_jitter < % .3f"
1966 ", dtime_jitter = % .1f %%"
1967 ", v_range = %.1f, RTT = %.3f)",
1968 player_position.X/BS,
1969 player_position.Y/BS,
1970 player_position.Z/BS,
1971 busytime_jitter1_min_sample,
1972 busytime_jitter1_max_sample,
1973 dtime_jitter1_max_fraction * 100.0,
1974 draw_control.wanted_range,
1978 guitext2->setText(narrow_to_wide(temptext).c_str());
1982 guitext_info->setText(infotext.c_str());
1986 Get chat messages from client
1990 std::wstring message;
1991 while(client.getChatMessage(message))
1993 chat_lines.push_back(ChatLine(message));
1994 /*if(chat_lines.size() > 6)
1996 core::list<ChatLine>::Iterator
1997 i = chat_lines.begin();
1998 chat_lines.erase(i);
2001 // Append them to form the whole static text and throw
2002 // it to the gui element
2004 // This will correspond to the line number counted from
2005 // top to bottom, from size-1 to 0
2006 s16 line_number = chat_lines.size();
2007 // Count of messages to be removed from the top
2008 u16 to_be_removed_count = 0;
2009 for(core::list<ChatLine>::Iterator
2010 i = chat_lines.begin();
2011 i != chat_lines.end(); i++)
2013 // After this, line number is valid for this loop
2018 This results in a maximum age of 60*6 to the
2019 lowermost line and a maximum of 6 lines
2021 float allowed_age = (6-line_number) * 60.0;
2023 if((*i).age > allowed_age)
2025 to_be_removed_count++;
2028 whole += (*i).text + L'\n';
2030 for(u16 i=0; i<to_be_removed_count; i++)
2032 core::list<ChatLine>::Iterator
2033 it = chat_lines.begin();
2034 chat_lines.erase(it);
2036 guitext_chat->setText(whole.c_str());
2038 // Update gui element size and position
2040 /*core::rect<s32> rect(
2042 screensize.Y - guitext_chat_pad_bottom
2043 - text_height*chat_lines.size(),
2045 screensize.Y - guitext_chat_pad_bottom
2047 core::rect<s32> rect(
2051 50 + guitext_chat->getTextHeight()
2054 guitext_chat->setRelativePosition(rect);
2056 // Don't show chat if empty or profiler is enabled
2057 if(chat_lines.size() == 0 || show_profiler)
2058 guitext_chat->setVisible(false);
2060 guitext_chat->setVisible(true);
2067 static u16 old_selected_item = 65535;
2068 if(client.getLocalInventoryUpdated()
2069 || g_selected_item != old_selected_item)
2071 client.selectPlayerItem(g_selected_item);
2072 old_selected_item = g_selected_item;
2073 //infostream<<"Updating local inventory"<<std::endl;
2074 client.getLocalInventory(local_inventory);
2076 // Update wielded tool
2077 InventoryList *mlist = local_inventory.getList("main");
2078 InventoryItem *item = NULL;
2080 item = mlist->getItem(g_selected_item);
2085 Send actions returned by the inventory menu
2087 while(inventory_action_queue.size() != 0)
2089 InventoryAction *a = inventory_action_queue.pop_front();
2091 client.sendInventoryAction(a);
2100 TimeTaker drawtimer("Drawing");
2104 TimeTaker timer("beginScene");
2105 driver->beginScene(true, true, bgcolor);
2106 //driver->beginScene(false, true, bgcolor);
2107 beginscenetime = timer.stop(true);
2112 //infostream<<"smgr->drawAll()"<<std::endl;
2115 TimeTaker timer("smgr");
2117 scenetime = timer.stop(true);
2121 //TimeTaker timer9("auxiliary drawings");
2125 //TimeTaker //timer10("//timer10");
2131 driver->setMaterial(m);
2133 driver->setTransform(video::ETS_WORLD, core::IdentityMatrix);
2135 for(core::list< core::aabbox3d<f32> >::Iterator i=hilightboxes.begin();
2136 i != hilightboxes.end(); i++)
2138 /*infostream<<"hilightbox min="
2139 <<"("<<i->MinEdge.X<<","<<i->MinEdge.Y<<","<<i->MinEdge.Z<<")"
2141 <<"("<<i->MaxEdge.X<<","<<i->MaxEdge.Y<<","<<i->MaxEdge.Z<<")"
2143 driver->draw3DBox(*i, video::SColor(255,0,0,0));
2150 // Warning: This clears the Z buffer.
2151 camera.drawWieldedTool();
2158 client.renderPostFx();
2164 if(g_settings->getBool("frametime_graph") == true)
2167 for(core::list<float>::Iterator
2168 i = frametime_log.begin();
2169 i != frametime_log.end();
2172 driver->draw2DLine(v2s32(x,50),
2173 v2s32(x,50+(*i)*1000),
2174 video::SColor(255,255,255,255));
2182 driver->draw2DLine(displaycenter - core::vector2d<s32>(10,0),
2183 displaycenter + core::vector2d<s32>(10,0),
2184 video::SColor(255,255,255,255));
2185 driver->draw2DLine(displaycenter - core::vector2d<s32>(0,10),
2186 displaycenter + core::vector2d<s32>(0,10),
2187 video::SColor(255,255,255,255));
2192 //TimeTaker //timer11("//timer11");
2204 draw_hotbar(driver, font, v2s32(displaycenter.X, screensize.Y),
2205 hotbar_imagesize, hotbar_itemcount, &local_inventory,
2212 if(damage_flash_timer > 0.0)
2214 damage_flash_timer -= dtime;
2216 video::SColor color(128,255,0,0);
2217 driver->draw2DRectangle(color,
2218 core::rect<s32>(0,0,screensize.X,screensize.Y),
2226 TimeTaker timer("endScene");
2228 endscenetime = timer.stop(true);
2231 drawtime = drawtimer.stop(true);
2237 static s16 lastFPS = 0;
2238 //u16 fps = driver->getFPS();
2239 u16 fps = (1.0/dtime_avg1);
2243 core::stringw str = L"Minetest [";
2244 str += driver->getName();
2248 device->setWindowCaption(str.c_str());
2260 Draw a "shutting down" screen, which will be shown while the map
2261 generator and other stuff quits
2264 /*gui::IGUIStaticText *gui_shuttingdowntext = */
2265 draw_load_screen(L"Shutting down stuff...", driver, font);
2266 /*driver->beginScene(true, true, video::SColor(255,0,0,0));
2269 gui_shuttingdowntext->remove();*/