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
48 #include "nodemetadata.h"
49 #include "main.h" // For g_settings
50 #include "content_mapnode.h" // For content_mapnode_init
52 #include "content_tool.h" // Default tools
53 #include "content_mapnode.h" // Default nodes
56 Setting this to 1 enables a special camera mode that forces
57 the renderers to think that the camera statically points from
58 the starting place to a static direction.
60 This allows one to move around with the player and see what
61 is actually drawn behind solid things and behind the player.
63 #define FIELD_OF_VIEW_TEST 0
73 ChatLine(const std::wstring &a_text):
86 // Inventory actions from the menu are buffered here before sending
87 Queue<InventoryAction*> inventory_action_queue;
88 // This is a copy of the inventory that the client's environment has
89 Inventory local_inventory;
91 u16 g_selected_item = 0;
97 struct TextDestChat : public TextDest
99 TextDestChat(Client *client)
103 void gotText(std::wstring text)
105 // Discard empty line
110 m_client->sendChatMessage(text);
112 m_client->addChatMessage(text);
118 struct TextDestNodeMetadata : public TextDest
120 TextDestNodeMetadata(v3s16 p, Client *client)
125 void gotText(std::wstring text)
127 std::string ntext = wide_to_narrow(text);
128 infostream<<"Changing text of a sign node: "
130 m_client->sendSignNodeText(m_p, ntext);
137 /* Respawn menu callback */
139 class MainRespawnInitiator: public IRespawnInitiator
142 MainRespawnInitiator(bool *active, Client *client):
143 m_active(active), m_client(client)
150 m_client->sendRespawn();
160 void draw_hotbar(video::IVideoDriver *driver, gui::IGUIFont *font,
161 ITextureSource *tsrc,
162 v2s32 centerlowerpos, s32 imgsize, s32 itemcount,
163 Inventory *inventory, s32 halfheartcount)
165 InventoryList *mainlist = inventory->getList("main");
168 errorstream<<"draw_hotbar(): mainlist == NULL"<<std::endl;
172 s32 padding = imgsize/12;
173 //s32 height = imgsize + padding*2;
174 s32 width = itemcount*(imgsize+padding*2);
176 // Position of upper left corner of bar
177 v2s32 pos = centerlowerpos - v2s32(width/2, imgsize+padding*2);
179 // Draw background color
180 /*core::rect<s32> barrect(0,0,width,height);
182 video::SColor bgcolor(255,128,128,128);
183 driver->draw2DRectangle(bgcolor, barrect, NULL);*/
185 core::rect<s32> imgrect(0,0,imgsize,imgsize);
187 for(s32 i=0; i<itemcount; i++)
189 InventoryItem *item = mainlist->getItem(i);
191 core::rect<s32> rect = imgrect + pos
192 + v2s32(padding+i*(imgsize+padding*2), padding);
194 if(g_selected_item == i)
196 video::SColor c_outside(255,255,0,0);
197 //video::SColor c_outside(255,0,0,0);
198 //video::SColor c_inside(255,192,192,192);
199 s32 x1 = rect.UpperLeftCorner.X;
200 s32 y1 = rect.UpperLeftCorner.Y;
201 s32 x2 = rect.LowerRightCorner.X;
202 s32 y2 = rect.LowerRightCorner.Y;
203 // Black base borders
204 driver->draw2DRectangle(c_outside,
206 v2s32(x1 - padding, y1 - padding),
207 v2s32(x2 + padding, y1)
209 driver->draw2DRectangle(c_outside,
211 v2s32(x1 - padding, y2),
212 v2s32(x2 + padding, y2 + padding)
214 driver->draw2DRectangle(c_outside,
216 v2s32(x1 - padding, y1),
219 driver->draw2DRectangle(c_outside,
222 v2s32(x2 + padding, y2)
224 /*// Light inside borders
225 driver->draw2DRectangle(c_inside,
227 v2s32(x1 - padding/2, y1 - padding/2),
228 v2s32(x2 + padding/2, y1)
230 driver->draw2DRectangle(c_inside,
232 v2s32(x1 - padding/2, y2),
233 v2s32(x2 + padding/2, y2 + padding/2)
235 driver->draw2DRectangle(c_inside,
237 v2s32(x1 - padding/2, y1),
240 driver->draw2DRectangle(c_inside,
243 v2s32(x2 + padding/2, y2)
248 video::SColor bgcolor2(128,0,0,0);
249 driver->draw2DRectangle(bgcolor2, rect, NULL);
253 drawInventoryItem(driver, font, item, rect, NULL, tsrc);
261 video::ITexture *heart_texture =
262 driver->getTexture(getTexturePath("heart.png").c_str());
263 v2s32 p = pos + v2s32(0, -20);
264 for(s32 i=0; i<halfheartcount/2; i++)
266 const video::SColor color(255,255,255,255);
267 const video::SColor colors[] = {color,color,color,color};
268 core::rect<s32> rect(0,0,16,16);
270 driver->draw2DImage(heart_texture, rect,
271 core::rect<s32>(core::position2d<s32>(0,0),
272 core::dimension2di(heart_texture->getOriginalSize())),
276 if(halfheartcount % 2 == 1)
278 const video::SColor color(255,255,255,255);
279 const video::SColor colors[] = {color,color,color,color};
280 core::rect<s32> rect(0,0,16/2,16);
282 core::dimension2di srcd(heart_texture->getOriginalSize());
284 driver->draw2DImage(heart_texture, rect,
285 core::rect<s32>(core::position2d<s32>(0,0), srcd),
293 Find what the player is pointing at
295 void getPointedNode(Client *client, v3f player_position,
296 v3f camera_direction, v3f camera_position,
297 bool &nodefound, core::line3d<f32> shootline,
298 v3s16 &nodepos, v3s16 &neighbourpos,
299 core::aabbox3d<f32> &nodehilightbox,
302 f32 mindistance = BS * 1001;
304 v3s16 pos_i = floatToInt(player_position, BS);
306 /*infostream<<"pos_i=("<<pos_i.X<<","<<pos_i.Y<<","<<pos_i.Z<<")"
310 s16 ystart = pos_i.Y + 0 - (camera_direction.Y<0 ? a : 1);
311 s16 zstart = pos_i.Z - (camera_direction.Z<0 ? a : 1);
312 s16 xstart = pos_i.X - (camera_direction.X<0 ? a : 1);
313 s16 yend = pos_i.Y + 1 + (camera_direction.Y>0 ? a : 1);
314 s16 zend = pos_i.Z + (camera_direction.Z>0 ? a : 1);
315 s16 xend = pos_i.X + (camera_direction.X>0 ? a : 1);
317 for(s16 y = ystart; y <= yend; y++)
318 for(s16 z = zstart; z <= zend; z++)
319 for(s16 x = xstart; x <= xend; x++)
324 n = client->getNode(v3s16(x,y,z));
325 if(client->getNodeDefManager()->get(n).pointable == false)
328 catch(InvalidPositionException &e)
334 v3f npf = intToFloat(np, BS);
339 v3s16(0,0,1), // back
341 v3s16(1,0,0), // right
342 v3s16(0,0,-1), // front
343 v3s16(0,-1,0), // bottom
344 v3s16(-1,0,0), // left
347 const ContentFeatures &f = client->getNodeDefManager()->get(n);
349 if(f.selection_box.type == NODEBOX_FIXED)
351 f32 distance = (npf - camera_position).getLength();
353 core::aabbox3d<f32> box = f.selection_box.fixed;
357 if(distance < mindistance)
359 if(box.intersectsWithLine(shootline))
364 mindistance = distance;
365 nodehilightbox = box;
369 else if(f.selection_box.type == NODEBOX_WALLMOUNTED)
371 v3s16 dir = unpackDir(n.param2);
372 v3f dir_f = v3f(dir.X, dir.Y, dir.Z);
373 dir_f *= BS/2 - BS/6 - BS/20;
374 v3f cpf = npf + dir_f;
375 f32 distance = (cpf - camera_position).getLength();
377 core::aabbox3d<f32> box;
380 if(dir == v3s16(0,1,0)){
381 box = f.selection_box.wall_top;
384 else if(dir == v3s16(0,-1,0)){
385 box = f.selection_box.wall_bottom;
391 f.selection_box.wall_side.MinEdge,
392 f.selection_box.wall_side.MaxEdge
395 for(s32 i=0; i<2; i++)
397 if(dir == v3s16(-1,0,0))
398 vertices[i].rotateXZBy(0);
399 if(dir == v3s16(1,0,0))
400 vertices[i].rotateXZBy(180);
401 if(dir == v3s16(0,0,-1))
402 vertices[i].rotateXZBy(90);
403 if(dir == v3s16(0,0,1))
404 vertices[i].rotateXZBy(-90);
407 box = core::aabbox3d<f32>(vertices[0]);
408 box.addInternalPoint(vertices[1]);
414 if(distance < mindistance)
416 if(box.intersectsWithLine(shootline))
421 mindistance = distance;
422 nodehilightbox = box;
426 else // NODEBOX_REGULAR
428 for(u16 i=0; i<6; i++)
430 v3f dir_f = v3f(dirs[i].X,
431 dirs[i].Y, dirs[i].Z);
432 v3f centerpoint = npf + dir_f * BS/2;
434 (centerpoint - camera_position).getLength();
436 if(distance < mindistance)
438 core::CMatrix4<f32> m;
439 m.buildRotateFromTo(v3f(0,0,1), dir_f);
441 // This is the back face
443 v3f(BS/2, BS/2, BS/2),
444 v3f(-BS/2, -BS/2, BS/2+d)
447 for(u16 j=0; j<2; j++)
449 m.rotateVect(corners[j]);
453 core::aabbox3d<f32> facebox(corners[0]);
454 facebox.addInternalPoint(corners[1]);
456 if(facebox.intersectsWithLine(shootline))
460 neighbourpos = np + dirs[i];
461 mindistance = distance;
463 //nodehilightbox = facebox;
465 const float d = 0.502;
466 core::aabbox3d<f32> nodebox
467 (-BS*d, -BS*d, -BS*d, BS*d, BS*d, BS*d);
468 v3f nodepos_f = intToFloat(nodepos, BS);
469 nodebox.MinEdge += nodepos_f;
470 nodebox.MaxEdge += nodepos_f;
471 nodehilightbox = nodebox;
473 } // if distance < mindistance
479 void update_skybox(video::IVideoDriver* driver,
480 scene::ISceneManager* smgr, scene::ISceneNode* &skybox,
488 /*// Disable skybox if FarMesh is enabled
489 if(g_settings->getBool("enable_farmesh"))
492 if(brightness >= 0.5)
494 skybox = smgr->addSkyBoxSceneNode(
495 driver->getTexture(getTexturePath("skybox2.png").c_str()),
496 driver->getTexture(getTexturePath("skybox3.png").c_str()),
497 driver->getTexture(getTexturePath("skybox1.png").c_str()),
498 driver->getTexture(getTexturePath("skybox1.png").c_str()),
499 driver->getTexture(getTexturePath("skybox1.png").c_str()),
500 driver->getTexture(getTexturePath("skybox1.png").c_str()));
502 else if(brightness >= 0.2)
504 skybox = smgr->addSkyBoxSceneNode(
505 driver->getTexture(getTexturePath("skybox2_dawn.png").c_str()),
506 driver->getTexture(getTexturePath("skybox3_dawn.png").c_str()),
507 driver->getTexture(getTexturePath("skybox1_dawn.png").c_str()),
508 driver->getTexture(getTexturePath("skybox1_dawn.png").c_str()),
509 driver->getTexture(getTexturePath("skybox1_dawn.png").c_str()),
510 driver->getTexture(getTexturePath("skybox1_dawn.png").c_str()));
514 skybox = smgr->addSkyBoxSceneNode(
515 driver->getTexture(getTexturePath("skybox2_night.png").c_str()),
516 driver->getTexture(getTexturePath("skybox3_night.png").c_str()),
517 driver->getTexture(getTexturePath("skybox1_night.png").c_str()),
518 driver->getTexture(getTexturePath("skybox1_night.png").c_str()),
519 driver->getTexture(getTexturePath("skybox1_night.png").c_str()),
520 driver->getTexture(getTexturePath("skybox1_night.png").c_str()));
525 Draws a screen with a single text on it.
526 Text will be removed when the screen is drawn the next time.
528 /*gui::IGUIStaticText **/
529 void draw_load_screen(const std::wstring &text,
530 video::IVideoDriver* driver, gui::IGUIFont* font)
532 v2u32 screensize = driver->getScreenSize();
533 const wchar_t *loadingtext = text.c_str();
534 core::vector2d<u32> textsize_u = font->getDimension(loadingtext);
535 core::vector2d<s32> textsize(textsize_u.X,textsize_u.Y);
536 core::vector2d<s32> center(screensize.X/2, screensize.Y/2);
537 core::rect<s32> textrect(center - textsize/2, center + textsize/2);
539 gui::IGUIStaticText *guitext = guienv->addStaticText(
540 loadingtext, textrect, false, false);
541 guitext->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);
543 driver->beginScene(true, true, video::SColor(255,0,0,0));
556 IrrlichtDevice *device,
559 std::string playername,
560 std::string password,
563 std::wstring &error_message,
564 std::string configpath
567 video::IVideoDriver* driver = device->getVideoDriver();
568 scene::ISceneManager* smgr = device->getSceneManager();
570 // Calculate text height using the font
571 u32 text_height = font->getDimension(L"Random test string").Height;
573 v2u32 screensize(0,0);
574 v2u32 last_screensize(0,0);
575 screensize = driver->getScreenSize();
577 const s32 hotbar_itemcount = 8;
578 //const s32 hotbar_imagesize = 36;
579 //const s32 hotbar_imagesize = 64;
580 s32 hotbar_imagesize = 48;
582 // The color of the sky
584 //video::SColor skycolor = video::SColor(255,140,186,250);
586 video::SColor bgcolor_bright = video::SColor(255,170,200,230);
589 Draw "Loading" screen
591 /*gui::IGUIStaticText *gui_loadingtext = */
592 //draw_load_screen(L"Loading and connecting...", driver, font);
594 draw_load_screen(L"Loading...", driver, font);
596 // Create tool definition manager
597 IWritableToolDefManager *tooldef = createToolDefManager();
598 // Create texture source
599 IWritableTextureSource *tsrc = createTextureSource(device);
600 // Create node definition manager
601 IWritableNodeDefManager *nodedef = createNodeDefManager(tsrc);
603 // Fill node feature table with default definitions
604 content_mapnode_init(tsrc, nodedef);
605 // Set default tool definitions
606 content_tool_init(tooldef);
610 SharedPtr will delete it when it goes out of scope.
612 SharedPtr<Server> server;
614 draw_load_screen(L"Creating server...", driver, font);
615 infostream<<"Creating server"<<std::endl;
616 server = new Server(map_dir, configpath);
624 draw_load_screen(L"Creating client...", driver, font);
625 infostream<<"Creating client"<<std::endl;
627 MapDrawControl draw_control;
629 Client client(device, playername.c_str(), password, draw_control,
630 tsrc, tooldef, nodedef);
632 // Client acts as our GameDef
633 IGameDef *gamedef = &client;
635 draw_load_screen(L"Resolving address...", driver, font);
636 Address connect_address(0,0,0,0, port);
639 //connect_address.Resolve("localhost");
640 connect_address.setAddress(127,0,0,1);
642 connect_address.Resolve(address.c_str());
644 catch(ResolveError &e)
646 errorstream<<"Couldn't resolve address"<<std::endl;
648 error_message = L"Couldn't resolve address";
649 //gui_loadingtext->remove();
654 Attempt to connect to the server
657 infostream<<"Connecting to server at ";
658 connect_address.print(&infostream);
659 infostream<<std::endl;
660 client.connect(connect_address);
662 bool could_connect = false;
665 float time_counter = 0.0;
668 if(client.connectedAndInitialized())
670 could_connect = true;
673 if(client.accessDenied())
677 // Wait for 10 seconds
678 if(time_counter >= 10.0)
683 std::wostringstream ss;
684 ss<<L"Connecting to server... (timeout in ";
685 ss<<(int)(10.0 - time_counter + 1.0);
687 draw_load_screen(ss.str(), driver, font);
690 driver->beginScene(true, true, video::SColor(255,0,0,0));
692 driver->endScene();*/
694 // Update client and server
706 catch(con::PeerNotFoundException &e)
709 if(could_connect == false)
711 if(client.accessDenied())
713 error_message = L"Access denied. Reason: "
714 +client.accessDeniedReason();
715 errorstream<<wide_to_narrow(error_message)<<std::endl;
719 error_message = L"Connection timed out.";
720 errorstream<<"Timed out."<<std::endl;
722 //gui_loadingtext->remove();
729 float old_brightness = 1.0;
730 scene::ISceneNode* skybox = NULL;
731 update_skybox(driver, smgr, skybox, 1.0);
734 Create the camera node
736 Camera camera(smgr, draw_control);
737 if (!camera.successfullyCreated(error_message))
740 f32 camera_yaw = 0; // "right/left"
741 f32 camera_pitch = 0; // "up/down"
747 float cloud_height = BS*100;
748 Clouds *clouds = NULL;
749 if(g_settings->getBool("enable_clouds"))
751 clouds = new Clouds(smgr->getRootSceneNode(), smgr, -1,
752 cloud_height, time(0));
759 FarMesh *farmesh = NULL;
760 if(g_settings->getBool("enable_farmesh"))
762 farmesh = new FarMesh(smgr->getRootSceneNode(), smgr, -1, client.getMapSeed(), &client);
769 //gui_loadingtext->remove();
775 // First line of debug text
776 gui::IGUIStaticText *guitext = guienv->addStaticText(
778 core::rect<s32>(5, 5, 795, 5+text_height),
780 // Second line of debug text
781 gui::IGUIStaticText *guitext2 = guienv->addStaticText(
783 core::rect<s32>(5, 5+(text_height+5)*1, 795, (5+text_height)*2),
785 // At the middle of the screen
786 // Object infos are shown in this
787 gui::IGUIStaticText *guitext_info = guienv->addStaticText(
789 core::rect<s32>(0,0,400,text_height+5) + v2s32(100,200),
793 gui::IGUIStaticText *guitext_chat = guienv->addStaticText(
795 core::rect<s32>(0,0,0,0),
796 //false, false); // Disable word wrap as of now
798 //guitext_chat->setBackgroundColor(video::SColor(96,0,0,0));
799 core::list<ChatLine> chat_lines;
801 // Profiler text (size is updated when text is updated)
802 gui::IGUIStaticText *guitext_profiler = guienv->addStaticText(
804 core::rect<s32>(6, 4+(text_height+5)*2, 400,
805 (text_height+5)*2 + text_height*35),
807 guitext_profiler->setBackgroundColor(video::SColor(80,0,0,0));
808 guitext_profiler->setVisible(false);
810 /*GUIQuickInventory *quick_inventory = new GUIQuickInventory
811 (guienv, NULL, v2s32(10, 70), 5, &local_inventory);*/
812 /*GUIQuickInventory *quick_inventory = new GUIQuickInventory
813 (guienv, NULL, v2s32(0, 0), quickinv_itemcount, &local_inventory);*/
815 // Test the text input system
816 /*(new GUITextInputMenu(guienv, guiroot, -1, &g_menumgr,
818 /*GUIMessageMenu *menu =
819 new GUIMessageMenu(guienv, guiroot, -1,
825 (new GUIPauseMenu(guienv, guiroot, -1, g_gamecallback,
826 &g_menumgr))->drop();
829 /*guitext2->setVisible(true);
830 guitext_info->setVisible(true);
831 guitext_chat->setVisible(true);*/
833 //s32 guitext_chat_pad_bottom = 70;
836 Some statistics are collected in these
839 u32 beginscenetime = 0;
841 u32 endscenetime = 0;
844 //throw con::PeerNotFoundException("lol");
846 core::list<float> frametime_log;
848 float nodig_delay_counter = 0.0;
849 float dig_time = 0.0;
851 v3s16 nodepos_old(-32768,-32768,-32768);
853 float damage_flash_timer = 0;
854 s16 farmesh_range = 20*MAP_BLOCKSIZE;
856 const float object_hit_delay = 0.5;
857 float object_hit_delay_timer = 0.0;
859 bool invert_mouse = g_settings->getBool("invert_mouse");
861 bool respawn_menu_active = false;
863 bool show_profiler = false;
864 bool force_fog_off = false;
865 bool disable_camera_update = false;
871 bool first_loop_after_window_activation = true;
873 // TODO: Convert the static interval timers to these
874 // Interval limiter for profiler
875 IntervalLimiter m_profiler_interval;
877 // Time is in milliseconds
878 // NOTE: getRealTime() causes strange problems in wine (imprecision?)
879 // NOTE: So we have to use getTime() and call run()s between them
880 u32 lasttime = device->getTimer()->getTime();
882 while(device->run() && kill == false)
884 //std::cerr<<"frame"<<std::endl;
886 if(client.accessDenied())
888 error_message = L"Access denied. Reason: "
889 +client.accessDeniedReason();
890 errorstream<<wide_to_narrow(error_message)<<std::endl;
894 if(g_gamecallback->disconnect_requested)
896 g_gamecallback->disconnect_requested = false;
900 if(g_gamecallback->changepassword_requested)
902 (new GUIPasswordChange(guienv, guiroot, -1,
903 &g_menumgr, &client))->drop();
904 g_gamecallback->changepassword_requested = false;
908 Process TextureSource's queue
910 tsrc->processQueue();
915 last_screensize = screensize;
916 screensize = driver->getScreenSize();
917 v2s32 displaycenter(screensize.X/2,screensize.Y/2);
918 //bool screensize_changed = screensize != last_screensize;
921 if(screensize.Y <= 800)
922 hotbar_imagesize = 32;
923 else if(screensize.Y <= 1280)
924 hotbar_imagesize = 48;
926 hotbar_imagesize = 64;
928 // Hilight boxes collected during the loop and displayed
929 core::list< core::aabbox3d<f32> > hilightboxes;
932 std::wstring infotext;
934 // When screen size changes, update positions and sizes of stuff
935 /*if(screensize_changed)
937 v2s32 pos(displaycenter.X-((quickinv_itemcount-1)*quickinv_spacing+quickinv_size)/2, screensize.Y-quickinv_spacing);
938 quick_inventory->updatePosition(pos);
941 //TimeTaker //timer1("//timer1");
943 // Time of frame without fps limit
947 // not using getRealTime is necessary for wine
948 u32 time = device->getTimer()->getTime();
950 busytime_u32 = time - lasttime;
953 busytime = busytime_u32 / 1000.0;
956 //infostream<<"busytime_u32="<<busytime_u32<<std::endl;
958 // Necessary for device->getTimer()->getTime()
966 float fps_max = g_settings->getFloat("fps_max");
967 u32 frametime_min = 1000./fps_max;
969 if(busytime_u32 < frametime_min)
971 u32 sleeptime = frametime_min - busytime_u32;
972 device->sleep(sleeptime);
976 // Necessary for device->getTimer()->getTime()
980 Time difference calculation
982 f32 dtime; // in seconds
984 u32 time = device->getTimer()->getTime();
986 dtime = (time - lasttime) / 1000.0;
993 object_hit_delay_timer -= dtime;
995 g_profiler->add("Elapsed time", dtime);
996 g_profiler->avg("FPS", 1./dtime);
999 Log frametime for visualization
1001 frametime_log.push_back(dtime);
1002 if(frametime_log.size() > 100)
1004 core::list<float>::Iterator i = frametime_log.begin();
1005 frametime_log.erase(i);
1009 Visualize frametime in terminal
1011 /*for(u32 i=0; i<dtime*400; i++)
1013 infostream<<std::endl;*/
1016 Time average and jitter calculation
1019 static f32 dtime_avg1 = 0.0;
1020 dtime_avg1 = dtime_avg1 * 0.96 + dtime * 0.04;
1021 f32 dtime_jitter1 = dtime - dtime_avg1;
1023 static f32 dtime_jitter1_max_sample = 0.0;
1024 static f32 dtime_jitter1_max_fraction = 0.0;
1026 static f32 jitter1_max = 0.0;
1027 static f32 counter = 0.0;
1028 if(dtime_jitter1 > jitter1_max)
1029 jitter1_max = dtime_jitter1;
1034 dtime_jitter1_max_sample = jitter1_max;
1035 dtime_jitter1_max_fraction
1036 = dtime_jitter1_max_sample / (dtime_avg1+0.001);
1042 Busytime average and jitter calculation
1045 static f32 busytime_avg1 = 0.0;
1046 busytime_avg1 = busytime_avg1 * 0.98 + busytime * 0.02;
1047 f32 busytime_jitter1 = busytime - busytime_avg1;
1049 static f32 busytime_jitter1_max_sample = 0.0;
1050 static f32 busytime_jitter1_min_sample = 0.0;
1052 static f32 jitter1_max = 0.0;
1053 static f32 jitter1_min = 0.0;
1054 static f32 counter = 0.0;
1055 if(busytime_jitter1 > jitter1_max)
1056 jitter1_max = busytime_jitter1;
1057 if(busytime_jitter1 < jitter1_min)
1058 jitter1_min = busytime_jitter1;
1062 busytime_jitter1_max_sample = jitter1_max;
1063 busytime_jitter1_min_sample = jitter1_min;
1070 Debug info for client
1073 static float counter = 0.0;
1078 client.printDebugInfo(infostream);
1085 float profiler_print_interval =
1086 g_settings->getFloat("profiler_print_interval");
1087 bool print_to_log = true;
1088 if(profiler_print_interval == 0){
1089 print_to_log = false;
1090 profiler_print_interval = 5;
1092 if(m_profiler_interval.step(dtime, profiler_print_interval))
1095 infostream<<"Profiler:"<<std::endl;
1096 g_profiler->print(infostream);
1099 std::ostringstream os(std::ios_base::binary);
1100 g_profiler->print(os);
1101 std::wstring text = narrow_to_wide(os.str());
1102 guitext_profiler->setText(text.c_str());
1104 g_profiler->clear();
1106 s32 w = font->getDimension(text.c_str()).Width;
1109 core::rect<s32> rect(6, 4+(text_height+5)*2, 12+w,
1110 8+(text_height+5)*2 +
1111 font->getDimension(text.c_str()).Height);
1112 guitext_profiler->setRelativePosition(rect);
1116 Direct handling of user input
1119 // Reset input if window not active or some menu is active
1120 if(device->isWindowActive() == false || noMenuActive() == false)
1125 // Input handler step() (used by the random input generator)
1129 Launch menus according to keys
1131 if(input->wasKeyDown(getKeySetting("keymap_inventory")))
1133 infostream<<"the_game: "
1134 <<"Launching inventory"<<std::endl;
1136 GUIInventoryMenu *menu =
1137 new GUIInventoryMenu(guienv, guiroot, -1,
1138 &g_menumgr, v2s16(8,7),
1139 client.getInventoryContext(),
1142 core::array<GUIInventoryMenu::DrawSpec> draw_spec;
1143 draw_spec.push_back(GUIInventoryMenu::DrawSpec(
1144 "list", "current_player", "main",
1145 v2s32(0, 3), v2s32(8, 4)));
1146 draw_spec.push_back(GUIInventoryMenu::DrawSpec(
1147 "list", "current_player", "craft",
1148 v2s32(3, 0), v2s32(3, 3)));
1149 draw_spec.push_back(GUIInventoryMenu::DrawSpec(
1150 "list", "current_player", "craftresult",
1151 v2s32(7, 1), v2s32(1, 1)));
1153 menu->setDrawSpec(draw_spec);
1157 else if(input->wasKeyDown(EscapeKey))
1159 infostream<<"the_game: "
1160 <<"Launching pause menu"<<std::endl;
1161 // It will delete itself by itself
1162 (new GUIPauseMenu(guienv, guiroot, -1, g_gamecallback,
1163 &g_menumgr))->drop();
1165 // Move mouse cursor on top of the disconnect button
1166 input->setMousePos(displaycenter.X, displaycenter.Y+25);
1168 else if(input->wasKeyDown(getKeySetting("keymap_chat")))
1170 TextDest *dest = new TextDestChat(&client);
1172 (new GUITextInputMenu(guienv, guiroot, -1,
1176 else if(input->wasKeyDown(getKeySetting("keymap_cmd")))
1178 TextDest *dest = new TextDestChat(&client);
1180 (new GUITextInputMenu(guienv, guiroot, -1,
1184 else if(input->wasKeyDown(getKeySetting("keymap_freemove")))
1186 if(g_settings->getBool("free_move"))
1188 g_settings->set("free_move","false");
1189 chat_lines.push_back(ChatLine(L"free_move disabled"));
1193 g_settings->set("free_move","true");
1194 chat_lines.push_back(ChatLine(L"free_move enabled"));
1197 else if(input->wasKeyDown(getKeySetting("keymap_fastmove")))
1199 if(g_settings->getBool("fast_move"))
1201 g_settings->set("fast_move","false");
1202 chat_lines.push_back(ChatLine(L"fast_move disabled"));
1206 g_settings->set("fast_move","true");
1207 chat_lines.push_back(ChatLine(L"fast_move enabled"));
1210 else if(input->wasKeyDown(getKeySetting("keymap_frametime_graph")))
1212 if(g_settings->getBool("frametime_graph"))
1214 g_settings->set("frametime_graph","false");
1215 chat_lines.push_back(ChatLine(L"frametime_graph disabled"));
1219 g_settings->set("frametime_graph","true");
1220 chat_lines.push_back(ChatLine(L"frametime_graph enabled"));
1223 else if(input->wasKeyDown(getKeySetting("keymap_screenshot")))
1225 irr::video::IImage* const image = driver->createScreenShot();
1227 irr::c8 filename[256];
1228 snprintf(filename, 256, "%s" DIR_DELIM "screenshot_%u.png",
1229 g_settings->get("screenshot_path").c_str(),
1230 device->getTimer()->getRealTime());
1231 if (driver->writeImageToFile(image, filename)) {
1232 std::wstringstream sstr;
1233 sstr<<"Saved screenshot to '"<<filename<<"'";
1234 infostream<<"Saved screenshot to '"<<filename<<"'"<<std::endl;
1235 chat_lines.push_back(ChatLine(sstr.str()));
1237 infostream<<"Failed to save screenshot '"<<filename<<"'"<<std::endl;
1242 else if(input->wasKeyDown(getKeySetting("keymap_toggle_profiler")))
1244 show_profiler = !show_profiler;
1245 guitext_profiler->setVisible(show_profiler);
1247 chat_lines.push_back(ChatLine(L"Profiler disabled"));
1249 chat_lines.push_back(ChatLine(L"Profiler enabled"));
1251 else if(input->wasKeyDown(getKeySetting("keymap_toggle_force_fog_off")))
1253 force_fog_off = !force_fog_off;
1255 chat_lines.push_back(ChatLine(L"Fog disabled"));
1257 chat_lines.push_back(ChatLine(L"Fog enabled"));
1259 else if(input->wasKeyDown(getKeySetting("keymap_toggle_update_camera")))
1261 disable_camera_update = !disable_camera_update;
1262 if(disable_camera_update)
1263 chat_lines.push_back(ChatLine(L"Camera update disabled"));
1265 chat_lines.push_back(ChatLine(L"Camera update enabled"));
1268 // Item selection with mouse wheel
1270 s32 wheel = input->getMouseWheel();
1271 u16 max_item = MYMIN(PLAYER_INVENTORY_SIZE-1,
1272 hotbar_itemcount-1);
1276 if(g_selected_item < max_item)
1279 g_selected_item = 0;
1283 if(g_selected_item > 0)
1286 g_selected_item = max_item;
1291 for(u16 i=0; i<10; i++)
1293 const KeyPress *kp = NumberKey + (i + 1) % 10;
1294 if(input->wasKeyDown(*kp))
1296 if(i < PLAYER_INVENTORY_SIZE && i < hotbar_itemcount)
1298 g_selected_item = i;
1300 infostream<<"Selected item: "
1301 <<g_selected_item<<std::endl;
1306 // Viewing range selection
1307 if(input->wasKeyDown(getKeySetting("keymap_rangeselect")))
1309 if(draw_control.range_all)
1311 draw_control.range_all = false;
1312 infostream<<"Disabled full viewing range"<<std::endl;
1316 draw_control.range_all = true;
1317 infostream<<"Enabled full viewing range"<<std::endl;
1321 // Print debug stacks
1322 if(input->wasKeyDown(getKeySetting("keymap_print_debug_stacks")))
1324 dstream<<"-----------------------------------------"
1326 dstream<<DTIME<<"Printing debug stacks:"<<std::endl;
1327 dstream<<"-----------------------------------------"
1329 debug_stacks_print();
1333 Mouse and camera control
1334 NOTE: Do this before client.setPlayerControl() to not cause a camera lag of one frame
1337 if((device->isWindowActive() && noMenuActive()) || random_input)
1341 // Mac OSX gets upset if this is set every frame
1342 if(device->getCursorControl()->isVisible())
1343 device->getCursorControl()->setVisible(false);
1346 if(first_loop_after_window_activation){
1347 //infostream<<"window active, first loop"<<std::endl;
1348 first_loop_after_window_activation = false;
1351 s32 dx = input->getMousePos().X - displaycenter.X;
1352 s32 dy = input->getMousePos().Y - displaycenter.Y;
1355 //infostream<<"window active, pos difference "<<dx<<","<<dy<<std::endl;
1357 /*const float keyspeed = 500;
1358 if(input->isKeyDown(irr::KEY_UP))
1359 dy -= dtime * keyspeed;
1360 if(input->isKeyDown(irr::KEY_DOWN))
1361 dy += dtime * keyspeed;
1362 if(input->isKeyDown(irr::KEY_LEFT))
1363 dx -= dtime * keyspeed;
1364 if(input->isKeyDown(irr::KEY_RIGHT))
1365 dx += dtime * keyspeed;*/
1367 camera_yaw -= dx*0.2;
1368 camera_pitch += dy*0.2;
1369 if(camera_pitch < -89.5) camera_pitch = -89.5;
1370 if(camera_pitch > 89.5) camera_pitch = 89.5;
1372 input->setMousePos(displaycenter.X, displaycenter.Y);
1375 // Mac OSX gets upset if this is set every frame
1376 if(device->getCursorControl()->isVisible() == false)
1377 device->getCursorControl()->setVisible(true);
1379 //infostream<<"window inactive"<<std::endl;
1380 first_loop_after_window_activation = true;
1384 Player speed control
1387 if(!noMenuActive() || !device->isWindowActive())
1389 PlayerControl control(
1400 client.setPlayerControl(control);
1413 PlayerControl control(
1414 input->isKeyDown(getKeySetting("keymap_forward")),
1415 input->isKeyDown(getKeySetting("keymap_backward")),
1416 input->isKeyDown(getKeySetting("keymap_left")),
1417 input->isKeyDown(getKeySetting("keymap_right")),
1418 input->isKeyDown(getKeySetting("keymap_jump")),
1419 input->isKeyDown(getKeySetting("keymap_special1")),
1420 input->isKeyDown(getKeySetting("keymap_sneak")),
1424 client.setPlayerControl(control);
1433 //TimeTaker timer("server->step(dtime)");
1434 server->step(dtime);
1442 //TimeTaker timer("client.step(dtime)");
1444 //client.step(dtime_avg1);
1448 // Read client events
1451 ClientEvent event = client.getClientEvent();
1452 if(event.type == CE_NONE)
1456 else if(event.type == CE_PLAYER_DAMAGE)
1458 //u16 damage = event.player_damage.amount;
1459 //infostream<<"Player damage: "<<damage<<std::endl;
1460 damage_flash_timer = 0.05;
1461 if(event.player_damage.amount >= 2){
1462 damage_flash_timer += 0.05 * event.player_damage.amount;
1465 else if(event.type == CE_PLAYER_FORCE_MOVE)
1467 camera_yaw = event.player_force_move.yaw;
1468 camera_pitch = event.player_force_move.pitch;
1470 else if(event.type == CE_DEATHSCREEN)
1472 if(respawn_menu_active)
1475 /*bool set_camera_point_target =
1476 event.deathscreen.set_camera_point_target;
1477 v3f camera_point_target;
1478 camera_point_target.X = event.deathscreen.camera_point_target_x;
1479 camera_point_target.Y = event.deathscreen.camera_point_target_y;
1480 camera_point_target.Z = event.deathscreen.camera_point_target_z;*/
1481 MainRespawnInitiator *respawner =
1482 new MainRespawnInitiator(
1483 &respawn_menu_active, &client);
1484 GUIDeathScreen *menu =
1485 new GUIDeathScreen(guienv, guiroot, -1,
1486 &g_menumgr, respawner);
1489 /* Handle visualization */
1491 damage_flash_timer = 0;
1493 /*LocalPlayer* player = client.getLocalPlayer();
1494 player->setPosition(player->getPosition() + v3f(0,-BS,0));
1495 camera.update(player, busytime, screensize);*/
1500 //TimeTaker //timer2("//timer2");
1502 LocalPlayer* player = client.getLocalPlayer();
1503 camera.update(player, busytime, screensize);
1506 v3f player_position = player->getPosition();
1507 v3f camera_position = camera.getPosition();
1508 v3f camera_direction = camera.getDirection();
1509 f32 camera_fov = camera.getFovMax();
1511 if(!disable_camera_update){
1512 client.updateCamera(camera_position,
1513 camera_direction, camera_fov);
1517 //TimeTaker //timer3("//timer3");
1520 Calculate what block is the crosshair pointing to
1523 //u32 t1 = device->getTimer()->getRealTime();
1525 //f32 d = 4; // max. distance
1526 f32 d = 4; // max. distance
1527 core::line3d<f32> shootline(camera_position,
1528 camera_position + camera_direction * BS * (d+1));
1530 ClientActiveObject *selected_active_object
1531 = client.getSelectedActiveObject
1532 (d*BS, camera_position, shootline);
1534 bool left_punch = false;
1535 bool left_punch_muted = false;
1537 if(selected_active_object != NULL)
1539 /* Clear possible cracking animation */
1540 if(nodepos_old != v3s16(-32768,-32768,-32768))
1542 client.clearTempMod(nodepos_old);
1544 nodepos_old = v3s16(-32768,-32768,-32768);
1547 //infostream<<"Client returned selected_active_object != NULL"<<std::endl;
1549 core::aabbox3d<f32> *selection_box
1550 = selected_active_object->getSelectionBox();
1551 // Box should exist because object was returned in the
1553 assert(selection_box);
1555 v3f pos = selected_active_object->getPosition();
1557 core::aabbox3d<f32> box_on_map(
1558 selection_box->MinEdge + pos,
1559 selection_box->MaxEdge + pos
1562 if(selected_active_object->doShowSelectionBox())
1563 hilightboxes.push_back(box_on_map);
1565 //infotext = narrow_to_wide("A ClientActiveObject");
1566 infotext = narrow_to_wide(selected_active_object->infoText());
1568 //if(input->getLeftClicked())
1569 if(input->getLeftState())
1571 bool do_punch = false;
1572 bool do_punch_damage = false;
1573 if(object_hit_delay_timer <= 0.0){
1575 do_punch_damage = true;
1576 object_hit_delay_timer = object_hit_delay;
1578 if(input->getLeftClicked()){
1582 infostream<<"Left-clicked object"<<std::endl;
1585 if(do_punch_damage){
1586 client.clickActiveObject(0,
1587 selected_active_object->getId(), g_selected_item);
1590 else if(input->getRightClicked())
1592 infostream<<"Right-clicked object"<<std::endl;
1593 client.clickActiveObject(1,
1594 selected_active_object->getId(), g_selected_item);
1597 else // selected_object == NULL
1601 Find out which node we are pointing at
1604 bool nodefound = false;
1607 core::aabbox3d<f32> nodehilightbox;
1609 getPointedNode(&client, player_position,
1610 camera_direction, camera_position,
1611 nodefound, shootline,
1612 nodepos, neighbourpos,
1616 if(nodepos_old != v3s16(-32768,-32768,-32768))
1618 client.clearTempMod(nodepos_old);
1620 nodepos_old = v3s16(-32768,-32768,-32768);
1627 hilightboxes.push_back(nodehilightbox);
1630 Check information text of node
1633 NodeMetadata *meta = client.getNodeMetadata(nodepos);
1636 infotext = narrow_to_wide(meta->infoText());
1639 //MapNode node = client.getNode(nodepos);
1645 if(input->getLeftReleased())
1647 client.clearTempMod(nodepos);
1651 if(nodig_delay_counter > 0.0)
1653 nodig_delay_counter -= dtime;
1657 if(nodepos != nodepos_old)
1659 infostream<<"Pointing at ("<<nodepos.X<<","
1660 <<nodepos.Y<<","<<nodepos.Z<<")"<<std::endl;
1662 if(nodepos_old != v3s16(-32768,-32768,-32768))
1664 client.clearTempMod(nodepos_old);
1666 nodepos_old = v3s16(-32768,-32768,-32768);
1670 if(input->getLeftClicked() ||
1671 (input->getLeftState() && nodepos != nodepos_old))
1673 infostream<<"Started digging"<<std::endl;
1674 client.groundAction(0, nodepos, neighbourpos, g_selected_item);
1676 if(input->getLeftClicked())
1678 client.setTempMod(nodepos, NodeMod(NODEMOD_CRACK, 0));
1680 if(input->getLeftState())
1682 MapNode n = client.getNode(nodepos);
1684 // Get tool name. Default is "" = bare hands
1685 std::string toolname = "";
1686 InventoryList *mlist = local_inventory.getList("main");
1689 InventoryItem *item = mlist->getItem(g_selected_item);
1690 if(item && (std::string)item->getName() == "ToolItem")
1692 ToolItem *titem = (ToolItem*)item;
1693 toolname = titem->getToolName();
1697 // Get digging properties for material and tool
1698 content_t material = n.getContent();
1699 ToolDiggingProperties tp =
1700 tooldef->getDiggingProperties(toolname);
1701 DiggingProperties prop =
1702 getDiggingProperties(material, &tp, nodedef);
1704 float dig_time_complete = 0.0;
1706 if(prop.diggable == false)
1708 /*infostream<<"Material "<<(int)material
1709 <<" not diggable with \""
1710 <<toolname<<"\""<<std::endl;*/
1711 // I guess nobody will wait for this long
1712 dig_time_complete = 10000000.0;
1716 dig_time_complete = prop.time;
1719 if(dig_time_complete >= 0.001)
1721 dig_index = (u16)((float)CRACK_ANIMATION_LENGTH
1722 * dig_time/dig_time_complete);
1724 // This is for torches
1727 dig_index = CRACK_ANIMATION_LENGTH;
1730 if(dig_index < CRACK_ANIMATION_LENGTH)
1732 //TimeTaker timer("client.setTempMod");
1733 //infostream<<"dig_index="<<dig_index<<std::endl;
1734 client.setTempMod(nodepos, NodeMod(NODEMOD_CRACK, dig_index));
1738 infostream<<"Digging completed"<<std::endl;
1739 client.groundAction(3, nodepos, neighbourpos, g_selected_item);
1740 client.clearTempMod(nodepos);
1741 client.removeNode(nodepos);
1745 nodig_delay_counter = dig_time_complete
1746 / (float)CRACK_ANIMATION_LENGTH;
1748 // We don't want a corresponding delay to
1749 // very time consuming nodes
1750 if(nodig_delay_counter > 0.5)
1752 nodig_delay_counter = 0.5;
1754 // We want a slight delay to very little
1755 // time consuming nodes
1756 float mindelay = 0.15;
1757 if(nodig_delay_counter < mindelay)
1759 nodig_delay_counter = mindelay;
1765 camera.setDigging(0); // left click animation
1770 if(input->getRightClicked())
1772 infostream<<"Ground right-clicked"<<std::endl;
1774 // If metadata provides an inventory view, activate it
1775 if(meta && meta->getInventoryDrawSpecString() != "" && !random_input)
1777 infostream<<"Launching custom inventory view"<<std::endl;
1779 Construct the unique identification string of the node
1781 std::string current_name;
1782 current_name += "nodemeta:";
1783 current_name += itos(nodepos.X);
1784 current_name += ",";
1785 current_name += itos(nodepos.Y);
1786 current_name += ",";
1787 current_name += itos(nodepos.Z);
1793 core::array<GUIInventoryMenu::DrawSpec> draw_spec;
1795 GUIInventoryMenu::makeDrawSpecArrayFromString(
1797 meta->getInventoryDrawSpecString(),
1800 GUIInventoryMenu *menu =
1801 new GUIInventoryMenu(guienv, guiroot, -1,
1802 &g_menumgr, invsize,
1803 client.getInventoryContext(),
1805 menu->setDrawSpec(draw_spec);
1808 // If metadata provides text input, activate text input
1809 else if(meta && meta->allowsTextInput() && !random_input)
1811 infostream<<"Launching metadata text input"<<std::endl;
1813 // Get a new text for it
1815 TextDest *dest = new TextDestNodeMetadata(nodepos, &client);
1817 std::wstring wtext = narrow_to_wide(meta->getText());
1819 (new GUITextInputMenu(guienv, guiroot, -1,
1823 // Otherwise report right click to server
1826 client.groundAction(1, nodepos, neighbourpos, g_selected_item);
1827 camera.setDigging(1); // right click animation
1831 nodepos_old = nodepos;
1834 } // selected_object == NULL
1836 if(left_punch || (input->getLeftClicked() && !left_punch_muted))
1838 camera.setDigging(0); // left click animation
1841 input->resetLeftClicked();
1842 input->resetRightClicked();
1844 if(input->getLeftReleased())
1846 infostream<<"Left button released (stopped digging)"
1848 client.groundAction(2, v3s16(0,0,0), v3s16(0,0,0), 0);
1850 if(input->getRightReleased())
1852 //inostream<<DTIME<<"Right released"<<std::endl;
1856 input->resetLeftReleased();
1857 input->resetRightReleased();
1860 Calculate stuff for drawing
1863 u32 daynight_ratio = client.getDayNightRatio();
1864 u8 l = decode_light((daynight_ratio * LIGHT_SUN) / 1000);
1865 video::SColor bgcolor = video::SColor(
1867 bgcolor_bright.getRed() * l / 255,
1868 bgcolor_bright.getGreen() * l / 255,
1869 bgcolor_bright.getBlue() * l / 255);
1870 /*skycolor.getRed() * l / 255,
1871 skycolor.getGreen() * l / 255,
1872 skycolor.getBlue() * l / 255);*/
1874 float brightness = (float)l/255.0;
1879 if(fabs(brightness - old_brightness) > 0.01)
1880 update_skybox(driver, smgr, skybox, brightness);
1887 clouds->step(dtime);
1888 clouds->update(v2f(player_position.X, player_position.Z),
1889 0.05+brightness*0.95);
1897 farmesh_range = draw_control.wanted_range * 10;
1898 if(draw_control.range_all && farmesh_range < 500)
1899 farmesh_range = 500;
1900 if(farmesh_range > 1000)
1901 farmesh_range = 1000;
1903 farmesh->step(dtime);
1904 farmesh->update(v2f(player_position.X, player_position.Z),
1905 0.05+brightness*0.95, farmesh_range);
1908 // Store brightness value
1909 old_brightness = brightness;
1915 if(g_settings->getBool("enable_fog") == true && !force_fog_off)
1920 range = BS*farmesh_range;
1924 range = draw_control.wanted_range*BS + MAP_BLOCKSIZE*BS*1.5;
1926 if(draw_control.range_all)
1929 range = range * 0.5 + 25*BS;*/
1934 video::EFT_FOG_LINEAR,
1946 video::EFT_FOG_LINEAR,
1956 Update gui stuff (0ms)
1959 //TimeTaker guiupdatetimer("Gui updating");
1962 static float drawtime_avg = 0;
1963 drawtime_avg = drawtime_avg * 0.95 + (float)drawtime*0.05;
1964 static float beginscenetime_avg = 0;
1965 beginscenetime_avg = beginscenetime_avg * 0.95 + (float)beginscenetime*0.05;
1966 static float scenetime_avg = 0;
1967 scenetime_avg = scenetime_avg * 0.95 + (float)scenetime*0.05;
1968 static float endscenetime_avg = 0;
1969 endscenetime_avg = endscenetime_avg * 0.95 + (float)endscenetime*0.05;
1972 snprintf(temptext, 300, "Minetest-c55 %s ("
1975 " drawtime=%.0f, beginscenetime=%.0f"
1976 ", scenetime=%.0f, endscenetime=%.0f",
1978 draw_control.range_all,
1985 guitext->setText(narrow_to_wide(temptext).c_str());
1990 snprintf(temptext, 300,
1991 "(% .1f, % .1f, % .1f)"
1992 " (% .3f < btime_jitter < % .3f"
1993 ", dtime_jitter = % .1f %%"
1994 ", v_range = %.1f, RTT = %.3f)",
1995 player_position.X/BS,
1996 player_position.Y/BS,
1997 player_position.Z/BS,
1998 busytime_jitter1_min_sample,
1999 busytime_jitter1_max_sample,
2000 dtime_jitter1_max_fraction * 100.0,
2001 draw_control.wanted_range,
2005 guitext2->setText(narrow_to_wide(temptext).c_str());
2009 guitext_info->setText(infotext.c_str());
2013 Get chat messages from client
2017 std::wstring message;
2018 while(client.getChatMessage(message))
2020 chat_lines.push_back(ChatLine(message));
2021 /*if(chat_lines.size() > 6)
2023 core::list<ChatLine>::Iterator
2024 i = chat_lines.begin();
2025 chat_lines.erase(i);
2028 // Append them to form the whole static text and throw
2029 // it to the gui element
2031 // This will correspond to the line number counted from
2032 // top to bottom, from size-1 to 0
2033 s16 line_number = chat_lines.size();
2034 // Count of messages to be removed from the top
2035 u16 to_be_removed_count = 0;
2036 for(core::list<ChatLine>::Iterator
2037 i = chat_lines.begin();
2038 i != chat_lines.end(); i++)
2040 // After this, line number is valid for this loop
2045 This results in a maximum age of 60*6 to the
2046 lowermost line and a maximum of 6 lines
2048 float allowed_age = (6-line_number) * 60.0;
2050 if((*i).age > allowed_age)
2052 to_be_removed_count++;
2055 whole += (*i).text + L'\n';
2057 for(u16 i=0; i<to_be_removed_count; i++)
2059 core::list<ChatLine>::Iterator
2060 it = chat_lines.begin();
2061 chat_lines.erase(it);
2063 guitext_chat->setText(whole.c_str());
2065 // Update gui element size and position
2067 /*core::rect<s32> rect(
2069 screensize.Y - guitext_chat_pad_bottom
2070 - text_height*chat_lines.size(),
2072 screensize.Y - guitext_chat_pad_bottom
2074 core::rect<s32> rect(
2078 50 + guitext_chat->getTextHeight()
2081 guitext_chat->setRelativePosition(rect);
2083 // Don't show chat if empty or profiler is enabled
2084 if(chat_lines.size() == 0 || show_profiler)
2085 guitext_chat->setVisible(false);
2087 guitext_chat->setVisible(true);
2094 static u16 old_selected_item = 65535;
2095 if(client.getLocalInventoryUpdated()
2096 || g_selected_item != old_selected_item)
2098 client.selectPlayerItem(g_selected_item);
2099 old_selected_item = g_selected_item;
2100 //infostream<<"Updating local inventory"<<std::endl;
2101 client.getLocalInventory(local_inventory);
2103 // Update wielded tool
2104 InventoryList *mlist = local_inventory.getList("main");
2105 InventoryItem *item = NULL;
2107 item = mlist->getItem(g_selected_item);
2108 camera.wield(item, gamedef);
2112 Send actions returned by the inventory menu
2114 while(inventory_action_queue.size() != 0)
2116 InventoryAction *a = inventory_action_queue.pop_front();
2118 client.sendInventoryAction(a);
2127 TimeTaker drawtimer("Drawing");
2131 TimeTaker timer("beginScene");
2132 driver->beginScene(true, true, bgcolor);
2133 //driver->beginScene(false, true, bgcolor);
2134 beginscenetime = timer.stop(true);
2139 //infostream<<"smgr->drawAll()"<<std::endl;
2142 TimeTaker timer("smgr");
2144 scenetime = timer.stop(true);
2148 //TimeTaker timer9("auxiliary drawings");
2152 //TimeTaker //timer10("//timer10");
2158 driver->setMaterial(m);
2160 driver->setTransform(video::ETS_WORLD, core::IdentityMatrix);
2162 for(core::list< core::aabbox3d<f32> >::Iterator i=hilightboxes.begin();
2163 i != hilightboxes.end(); i++)
2165 /*infostream<<"hilightbox min="
2166 <<"("<<i->MinEdge.X<<","<<i->MinEdge.Y<<","<<i->MinEdge.Z<<")"
2168 <<"("<<i->MaxEdge.X<<","<<i->MaxEdge.Y<<","<<i->MaxEdge.Z<<")"
2170 driver->draw3DBox(*i, video::SColor(255,0,0,0));
2177 // Warning: This clears the Z buffer.
2178 camera.drawWieldedTool();
2185 client.renderPostFx();
2191 if(g_settings->getBool("frametime_graph") == true)
2194 for(core::list<float>::Iterator
2195 i = frametime_log.begin();
2196 i != frametime_log.end();
2199 driver->draw2DLine(v2s32(x,50),
2200 v2s32(x,50+(*i)*1000),
2201 video::SColor(255,255,255,255));
2209 driver->draw2DLine(displaycenter - core::vector2d<s32>(10,0),
2210 displaycenter + core::vector2d<s32>(10,0),
2211 video::SColor(255,255,255,255));
2212 driver->draw2DLine(displaycenter - core::vector2d<s32>(0,10),
2213 displaycenter + core::vector2d<s32>(0,10),
2214 video::SColor(255,255,255,255));
2219 //TimeTaker //timer11("//timer11");
2231 draw_hotbar(driver, font, tsrc,
2232 v2s32(displaycenter.X, screensize.Y),
2233 hotbar_imagesize, hotbar_itemcount, &local_inventory,
2240 if(damage_flash_timer > 0.0)
2242 damage_flash_timer -= dtime;
2244 video::SColor color(128,255,0,0);
2245 driver->draw2DRectangle(color,
2246 core::rect<s32>(0,0,screensize.X,screensize.Y),
2254 TimeTaker timer("endScene");
2256 endscenetime = timer.stop(true);
2259 drawtime = drawtimer.stop(true);
2265 static s16 lastFPS = 0;
2266 //u16 fps = driver->getFPS();
2267 u16 fps = (1.0/dtime_avg1);
2271 core::stringw str = L"Minetest [";
2272 str += driver->getName();
2276 device->setWindowCaption(str.c_str());
2288 Draw a "shutting down" screen, which will be shown while the map
2289 generator and other stuff quits
2292 /*gui::IGUIStaticText *gui_shuttingdowntext = */
2293 draw_load_screen(L"Shutting down stuff...", driver, font);
2294 /*driver->beginScene(true, true, video::SColor(255,0,0,0));
2297 gui_shuttingdowntext->remove();*/