Code refactoring; split half of main.cpp to game.cpp.
authorPerttu Ahola <celeron55@gmail.com>
Sat, 23 Apr 2011 15:31:31 +0000 (18:31 +0300)
committerPerttu Ahola <celeron55@gmail.com>
Sat, 23 Apr 2011 15:31:31 +0000 (18:31 +0300)
src/CMakeLists.txt
src/client.cpp
src/environment.cpp
src/game.cpp [new file with mode: 0644]
src/game.h [new file with mode: 0644]
src/main.cpp
src/main.h
src/player.cpp
src/player.h

index aea98e19d0790d1b225efa55d79e5f7f7453beb0..9d9524eab3b7e6b38e1ab44f4da42460e0c59e95 100644 (file)
@@ -90,6 +90,7 @@ set(minetest_SRCS
        guiPauseMenu.cpp
        client.cpp
        tile.cpp
+       game.cpp
        main.cpp
 )
 
index 702247f66364aace840cc3bf12ba6ae417903caa..ec2504bc823f45920f9d82335eb7181696e47e58 100644 (file)
@@ -621,7 +621,7 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
                p.Y = readS16(&data[4]);
                p.Z = readS16(&data[6]);
                
-               //TimeTaker t1("TOCLIENT_REMOVENODE", g_device);
+               //TimeTaker t1("TOCLIENT_REMOVENODE");
                
                // This will clear the cracking animation after digging
                ((ClientMap&)m_env.getMap()).clearTempMod(p);
@@ -638,7 +638,7 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
                p.Y = readS16(&data[4]);
                p.Z = readS16(&data[6]);
                
-               //TimeTaker t1("TOCLIENT_ADDNODE", g_device);
+               //TimeTaker t1("TOCLIENT_ADDNODE");
 
                MapNode n;
                n.deSerialize(&data[8], ser_version);
index b3055ca6f7b88b3d83a8daec93407f830db446c7..2b781126b5f1c9bed7ff3bd99bb97b2afd5684e6 100644 (file)
@@ -438,7 +438,7 @@ void ServerEnvironment::step(float dtime)
        bool footprints = g_settings.getBool("footprints");
 
        {
-               //TimeTaker timer("Server m_map->timerUpdate()", g_device);
+               //TimeTaker timer("Server m_map->timerUpdate()");
                m_map->timerUpdate(dtime);
        }
 
@@ -1027,7 +1027,7 @@ void ClientEnvironment::step(float dtime)
        bool footprints = g_settings.getBool("footprints");
 
        {
-               //TimeTaker timer("Client m_map->timerUpdate()", g_device);
+               //TimeTaker timer("Client m_map->timerUpdate()");
                m_map->timerUpdate(dtime);
        }
        
diff --git a/src/game.cpp b/src/game.cpp
new file mode 100644 (file)
index 0000000..9a0fd31
--- /dev/null
@@ -0,0 +1,1975 @@
+/*
+Minetest-c55
+Copyright (C) 2011 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "common_irrlicht.h"
+#include "game.h"
+#include "client.h"
+#include "server.h"
+#include "guiPauseMenu.h"
+#include "guiInventoryMenu.h"
+#include "guiTextInputMenu.h"
+#include "guiFurnaceMenu.h"
+#include "materials.h"
+
+/*
+       Setting this to 1 enables a special camera mode that forces
+       the renderers to think that the camera statically points from
+       the starting place to a static direction.
+
+       This allows one to move around with the player and see what
+       is actually drawn behind solid things and behind the player.
+*/
+#define FIELD_OF_VIEW_TEST 0
+
+
+MapDrawControl draw_control;
+
+// Chat data
+struct ChatLine
+{
+       ChatLine():
+               age(0.0)
+       {
+       }
+       ChatLine(const std::wstring &a_text):
+               age(0.0),
+               text(a_text)
+       {
+       }
+       float age;
+       std::wstring text;
+};
+
+/*
+       Inventory stuff
+*/
+
+// Inventory actions from the menu are buffered here before sending
+Queue<InventoryAction*> inventory_action_queue;
+// This is a copy of the inventory that the client's environment has
+Inventory local_inventory;
+
+u16 g_selected_item = 0;
+
+/*
+       Text input system
+*/
+
+struct TextDestSign : public TextDest
+{
+       TextDestSign(v3s16 blockpos, s16 id, Client *client)
+       {
+               m_blockpos = blockpos;
+               m_id = id;
+               m_client = client;
+       }
+       void gotText(std::wstring text)
+       {
+               std::string ntext = wide_to_narrow(text);
+               dstream<<"Changing text of a sign object: "
+                               <<ntext<<std::endl;
+               m_client->sendSignText(m_blockpos, m_id, ntext);
+       }
+
+       v3s16 m_blockpos;
+       s16 m_id;
+       Client *m_client;
+};
+
+struct TextDestChat : public TextDest
+{
+       TextDestChat(Client *client)
+       {
+               m_client = client;
+       }
+       void gotText(std::wstring text)
+       {
+               // Discard empty line
+               if(text == L"")
+                       return;
+               
+               // Parse command (server command starts with "/#")
+               if(text[0] == L'/' && text[1] != L'#')
+               {
+                       std::wstring reply = L"Local: ";
+
+                       reply += L"Local commands not yet supported. "
+                                       L"Server prefix is \"/#\".";
+                       
+                       m_client->addChatMessage(reply);
+                       return;
+               }
+
+               // Send to others
+               m_client->sendChatMessage(text);
+               // Show locally
+               m_client->addChatMessage(text);
+       }
+
+       Client *m_client;
+};
+
+struct TextDestSignNode : public TextDest
+{
+       TextDestSignNode(v3s16 p, Client *client)
+       {
+               m_p = p;
+               m_client = client;
+       }
+       void gotText(std::wstring text)
+       {
+               std::string ntext = wide_to_narrow(text);
+               dstream<<"Changing text of a sign node: "
+                               <<ntext<<std::endl;
+               m_client->sendSignNodeText(m_p, ntext);
+       }
+
+       v3s16 m_p;
+       Client *m_client;
+};
+
+/*
+       Render distance feedback loop
+*/
+void updateViewingRange(f32 frametime_in, Client *client)
+{
+       if(draw_control.range_all == true)
+               return;
+       
+       static f32 added_frametime = 0;
+       static s16 added_frames = 0;
+
+       added_frametime += frametime_in;
+       added_frames += 1;
+
+       // Actually this counter kind of sucks because frametime is busytime
+       static f32 counter = 0;
+       counter -= frametime_in;
+       if(counter > 0)
+               return;
+       //counter = 0.1;
+       counter = 0.2;
+
+       /*dstream<<__FUNCTION_NAME
+                       <<": Collected "<<added_frames<<" frames, total of "
+                       <<added_frametime<<"s."<<std::endl;*/
+       
+       /*dstream<<"draw_control.blocks_drawn="
+                       <<draw_control.blocks_drawn
+                       <<", draw_control.blocks_would_have_drawn="
+                       <<draw_control.blocks_would_have_drawn
+                       <<std::endl;*/
+       
+       float range_min = g_settings.getS16("viewing_range_nodes_min");
+       float range_max = g_settings.getS16("viewing_range_nodes_max");
+       
+       draw_control.wanted_min_range = range_min;
+       draw_control.wanted_max_blocks = (1.2*draw_control.blocks_drawn)+1;
+       
+       float block_draw_ratio = 1.0;
+       if(draw_control.blocks_would_have_drawn != 0)
+       {
+               block_draw_ratio = (float)draw_control.blocks_drawn
+                       / (float)draw_control.blocks_would_have_drawn;
+       }
+
+       // Calculate the average frametime in the case that all wanted
+       // blocks had been drawn
+       f32 frametime = added_frametime / added_frames / block_draw_ratio;
+       
+       added_frametime = 0.0;
+       added_frames = 0;
+       
+       float wanted_fps = g_settings.getFloat("wanted_fps");
+       float wanted_frametime = 1.0 / wanted_fps;
+       
+       f32 wanted_frametime_change = wanted_frametime - frametime;
+       //dstream<<"wanted_frametime_change="<<wanted_frametime_change<<std::endl;
+       
+       // If needed frametime change is small, just return
+       if(fabs(wanted_frametime_change) < wanted_frametime*0.4)
+       {
+               //dstream<<"ignoring small wanted_frametime_change"<<std::endl;
+               return;
+       }
+
+       float range = draw_control.wanted_range;
+       float new_range = range;
+
+       static s16 range_old = 0;
+       static f32 frametime_old = 0;
+       
+       float d_range = range - range_old;
+       f32 d_frametime = frametime - frametime_old;
+       // A sane default of 30ms per 50 nodes of range
+       static f32 time_per_range = 30. / 50;
+       if(d_range != 0)
+       {
+               time_per_range = d_frametime / d_range;
+       }
+       
+       // The minimum allowed calculated frametime-range derivative:
+       // Practically this sets the maximum speed of changing the range.
+       // The lower this value, the higher the maximum changing speed.
+       // A low value here results in wobbly range (0.001)
+       // A high value here results in slow changing range (0.0025)
+       // SUGG: This could be dynamically adjusted so that when
+       //       the camera is turning, this is lower
+       //float min_time_per_range = 0.0015;
+       float min_time_per_range = 0.0010;
+       //float min_time_per_range = 0.05 / range;
+       if(time_per_range < min_time_per_range)
+       {
+               time_per_range = min_time_per_range;
+               //dstream<<"time_per_range="<<time_per_range<<" (min)"<<std::endl;
+       }
+       else
+       {
+               //dstream<<"time_per_range="<<time_per_range<<std::endl;
+       }
+
+       f32 wanted_range_change = wanted_frametime_change / time_per_range;
+       // Dampen the change a bit to kill oscillations
+       //wanted_range_change *= 0.9;
+       //wanted_range_change *= 0.75;
+       wanted_range_change *= 0.5;
+       //dstream<<"wanted_range_change="<<wanted_range_change<<std::endl;
+
+       // If needed range change is very small, just return
+       if(fabs(wanted_range_change) < 0.001)
+       {
+               //dstream<<"ignoring small wanted_range_change"<<std::endl;
+               return;
+       }
+
+       new_range += wanted_range_change;
+       //dstream<<"new_range="<<new_range/*<<std::endl*/;
+       
+       //float new_range_unclamped = new_range;
+       if(new_range < range_min)
+               new_range = range_min;
+       if(new_range > range_max)
+               new_range = range_max;
+       
+       /*if(new_range != new_range_unclamped)
+               dstream<<", clamped to "<<new_range<<std::endl;
+       else
+               dstream<<std::endl;*/
+
+       draw_control.wanted_range = new_range;
+
+       range_old = new_range;
+       frametime_old = frametime;
+}
+
+/*
+       Hotbar draw routine
+*/
+void draw_hotbar(video::IVideoDriver *driver, gui::IGUIFont *font,
+               v2s32 centerlowerpos, s32 imgsize, s32 itemcount,
+               Inventory *inventory, s32 halfheartcount)
+{
+       InventoryList *mainlist = inventory->getList("main");
+       if(mainlist == NULL)
+       {
+               dstream<<"WARNING: draw_hotbar(): mainlist == NULL"<<std::endl;
+               return;
+       }
+       
+       s32 padding = imgsize/12;
+       //s32 height = imgsize + padding*2;
+       s32 width = itemcount*(imgsize+padding*2);
+       
+       // Position of upper left corner of bar
+       v2s32 pos = centerlowerpos - v2s32(width/2, imgsize+padding*2);
+       
+       // Draw background color
+       /*core::rect<s32> barrect(0,0,width,height);
+       barrect += pos;
+       video::SColor bgcolor(255,128,128,128);
+       driver->draw2DRectangle(bgcolor, barrect, NULL);*/
+
+       core::rect<s32> imgrect(0,0,imgsize,imgsize);
+
+       for(s32 i=0; i<itemcount; i++)
+       {
+               InventoryItem *item = mainlist->getItem(i);
+               
+               core::rect<s32> rect = imgrect + pos
+                               + v2s32(padding+i*(imgsize+padding*2), padding);
+               
+               if(g_selected_item == i)
+               {
+                       driver->draw2DRectangle(video::SColor(255,255,0,0),
+                                       core::rect<s32>(rect.UpperLeftCorner - v2s32(1,1)*padding,
+                                                       rect.LowerRightCorner + v2s32(1,1)*padding),
+                                       NULL);
+               }
+               else
+               {
+                       video::SColor bgcolor2(128,0,0,0);
+                       driver->draw2DRectangle(bgcolor2, rect, NULL);
+               }
+
+               if(item != NULL)
+               {
+                       drawInventoryItem(driver, font, item, rect, NULL);
+               }
+       }
+       
+       /*
+               Draw hearts
+       */
+       {
+               video::ITexture *heart_texture =
+                               driver->getTexture(porting::getDataPath("heart.png").c_str());
+               v2s32 p = pos + v2s32(0, -20);
+               for(s32 i=0; i<halfheartcount/2; i++)
+               {
+                       const video::SColor color(255,255,255,255);
+                       const video::SColor colors[] = {color,color,color,color};
+                       core::rect<s32> rect(0,0,16,16);
+                       rect += p;
+                       driver->draw2DImage(heart_texture, rect,
+                               core::rect<s32>(core::position2d<s32>(0,0),
+                               core::dimension2di(heart_texture->getOriginalSize())),
+                               NULL, colors, true);
+                       p += v2s32(20,0);
+               }
+               if(halfheartcount % 2 == 1)
+               {
+                       const video::SColor color(255,255,255,255);
+                       const video::SColor colors[] = {color,color,color,color};
+                       core::rect<s32> rect(0,0,16/2,16);
+                       rect += p;
+                       core::dimension2di srcd(heart_texture->getOriginalSize());
+                       srcd.Width /= 2;
+                       driver->draw2DImage(heart_texture, rect,
+                               core::rect<s32>(core::position2d<s32>(0,0), srcd),
+                               NULL, colors, true);
+                       p += v2s32(20,0);
+               }
+       }
+}
+
+/*
+       Find what the player is pointing at
+*/
+void getPointedNode(Client *client, v3f player_position,
+               v3f camera_direction, v3f camera_position,
+               bool &nodefound, core::line3d<f32> shootline,
+               v3s16 &nodepos, v3s16 &neighbourpos,
+               core::aabbox3d<f32> &nodehilightbox,
+               f32 d)
+{
+       f32 mindistance = BS * 1001;
+       
+       v3s16 pos_i = floatToInt(player_position, BS);
+
+       /*std::cout<<"pos_i=("<<pos_i.X<<","<<pos_i.Y<<","<<pos_i.Z<<")"
+                       <<std::endl;*/
+
+       s16 a = d;
+       s16 ystart = pos_i.Y + 0 - (camera_direction.Y<0 ? a : 1);
+       s16 zstart = pos_i.Z - (camera_direction.Z<0 ? a : 1);
+       s16 xstart = pos_i.X - (camera_direction.X<0 ? a : 1);
+       s16 yend = pos_i.Y + 1 + (camera_direction.Y>0 ? a : 1);
+       s16 zend = pos_i.Z + (camera_direction.Z>0 ? a : 1);
+       s16 xend = pos_i.X + (camera_direction.X>0 ? a : 1);
+       
+       for(s16 y = ystart; y <= yend; y++)
+       for(s16 z = zstart; z <= zend; z++)
+       for(s16 x = xstart; x <= xend; x++)
+       {
+               MapNode n;
+               try
+               {
+                       n = client->getNode(v3s16(x,y,z));
+                       if(content_pointable(n.d) == false)
+                               continue;
+               }
+               catch(InvalidPositionException &e)
+               {
+                       continue;
+               }
+
+               v3s16 np(x,y,z);
+               v3f npf = intToFloat(np, BS);
+               
+               f32 d = 0.01;
+               
+               v3s16 dirs[6] = {
+                       v3s16(0,0,1), // back
+                       v3s16(0,1,0), // top
+                       v3s16(1,0,0), // right
+                       v3s16(0,0,-1), // front
+                       v3s16(0,-1,0), // bottom
+                       v3s16(-1,0,0), // left
+               };
+               
+               /*
+                       Meta-objects
+               */
+               if(n.d == CONTENT_TORCH)
+               {
+                       v3s16 dir = unpackDir(n.dir);
+                       v3f dir_f = v3f(dir.X, dir.Y, dir.Z);
+                       dir_f *= BS/2 - BS/6 - BS/20;
+                       v3f cpf = npf + dir_f;
+                       f32 distance = (cpf - camera_position).getLength();
+
+                       core::aabbox3d<f32> box;
+                       
+                       // bottom
+                       if(dir == v3s16(0,-1,0))
+                       {
+                               box = core::aabbox3d<f32>(
+                                       npf - v3f(BS/6, BS/2, BS/6),
+                                       npf + v3f(BS/6, -BS/2+BS/3*2, BS/6)
+                               );
+                       }
+                       // top
+                       else if(dir == v3s16(0,1,0))
+                       {
+                               box = core::aabbox3d<f32>(
+                                       npf - v3f(BS/6, -BS/2+BS/3*2, BS/6),
+                                       npf + v3f(BS/6, BS/2, BS/6)
+                               );
+                       }
+                       // side
+                       else
+                       {
+                               box = core::aabbox3d<f32>(
+                                       cpf - v3f(BS/6, BS/3, BS/6),
+                                       cpf + v3f(BS/6, BS/3, BS/6)
+                               );
+                       }
+
+                       if(distance < mindistance)
+                       {
+                               if(box.intersectsWithLine(shootline))
+                               {
+                                       nodefound = true;
+                                       nodepos = np;
+                                       neighbourpos = np;
+                                       mindistance = distance;
+                                       nodehilightbox = box;
+                               }
+                       }
+               }
+               else if(n.d == CONTENT_SIGN_WALL)
+               {
+                       v3s16 dir = unpackDir(n.dir);
+                       v3f dir_f = v3f(dir.X, dir.Y, dir.Z);
+                       dir_f *= BS/2 - BS/6 - BS/20;
+                       v3f cpf = npf + dir_f;
+                       f32 distance = (cpf - camera_position).getLength();
+
+                       v3f vertices[4] =
+                       {
+                               v3f(BS*0.42,-BS*0.35,-BS*0.4),
+                               v3f(BS*0.49, BS*0.35, BS*0.4),
+                       };
+
+                       for(s32 i=0; i<2; i++)
+                       {
+                               if(dir == v3s16(1,0,0))
+                                       vertices[i].rotateXZBy(0);
+                               if(dir == v3s16(-1,0,0))
+                                       vertices[i].rotateXZBy(180);
+                               if(dir == v3s16(0,0,1))
+                                       vertices[i].rotateXZBy(90);
+                               if(dir == v3s16(0,0,-1))
+                                       vertices[i].rotateXZBy(-90);
+                               if(dir == v3s16(0,-1,0))
+                                       vertices[i].rotateXYBy(-90);
+                               if(dir == v3s16(0,1,0))
+                                       vertices[i].rotateXYBy(90);
+
+                               vertices[i] += npf;
+                       }
+
+                       core::aabbox3d<f32> box;
+
+                       box = core::aabbox3d<f32>(vertices[0]);
+                       box.addInternalPoint(vertices[1]);
+
+                       if(distance < mindistance)
+                       {
+                               if(box.intersectsWithLine(shootline))
+                               {
+                                       nodefound = true;
+                                       nodepos = np;
+                                       neighbourpos = np;
+                                       mindistance = distance;
+                                       nodehilightbox = box;
+                               }
+                       }
+               }
+               /*
+                       Regular blocks
+               */
+               else
+               {
+                       for(u16 i=0; i<6; i++)
+                       {
+                               v3f dir_f = v3f(dirs[i].X,
+                                               dirs[i].Y, dirs[i].Z);
+                               v3f centerpoint = npf + dir_f * BS/2;
+                               f32 distance =
+                                               (centerpoint - camera_position).getLength();
+                               
+                               if(distance < mindistance)
+                               {
+                                       core::CMatrix4<f32> m;
+                                       m.buildRotateFromTo(v3f(0,0,1), dir_f);
+
+                                       // This is the back face
+                                       v3f corners[2] = {
+                                               v3f(BS/2, BS/2, BS/2),
+                                               v3f(-BS/2, -BS/2, BS/2+d)
+                                       };
+                                       
+                                       for(u16 j=0; j<2; j++)
+                                       {
+                                               m.rotateVect(corners[j]);
+                                               corners[j] += npf;
+                                       }
+
+                                       core::aabbox3d<f32> facebox(corners[0]);
+                                       facebox.addInternalPoint(corners[1]);
+
+                                       if(facebox.intersectsWithLine(shootline))
+                                       {
+                                               nodefound = true;
+                                               nodepos = np;
+                                               neighbourpos = np + dirs[i];
+                                               mindistance = distance;
+
+                                               //nodehilightbox = facebox;
+
+                                               const float d = 0.502;
+                                               core::aabbox3d<f32> nodebox
+                                                               (-BS*d, -BS*d, -BS*d, BS*d, BS*d, BS*d);
+                                               v3f nodepos_f = intToFloat(nodepos, BS);
+                                               nodebox.MinEdge += nodepos_f;
+                                               nodebox.MaxEdge += nodepos_f;
+                                               nodehilightbox = nodebox;
+                                       }
+                               } // if distance < mindistance
+                       } // for dirs
+               } // regular block
+       } // for coords
+}
+
+void the_game(
+       bool &kill,
+       bool random_input,
+       InputHandler *input,
+       IrrlichtDevice *device,
+       gui::IGUIFont* font,
+       std::string map_dir,
+       std::string playername,
+       std::string address,
+       u16 port,
+       std::wstring &error_message
+)
+{
+       video::IVideoDriver* driver = device->getVideoDriver();
+       scene::ISceneManager* smgr = device->getSceneManager();
+
+       v2u32 screensize(0,0);
+       v2u32 last_screensize(0,0);
+       screensize = driver->getScreenSize();
+
+       const s32 hotbar_itemcount = 8;
+       const s32 hotbar_imagesize = 36;
+       
+       /*
+               Draw "Loading" screen
+       */
+       const wchar_t *text = L"Loading and connecting...";
+       u32 text_height = font->getDimension(text).Height;
+       core::vector2d<s32> center(screensize.X/2, screensize.Y/2);
+       core::vector2d<s32> textsize(300, text_height);
+       core::rect<s32> textrect(center - textsize/2, center + textsize/2);
+
+       gui::IGUIStaticText *gui_loadingtext = guienv->addStaticText(
+                       text, textrect, false, false);
+       gui_loadingtext->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);
+
+       driver->beginScene(true, true, video::SColor(255,0,0,0));
+       guienv->drawAll();
+       driver->endScene();
+
+       std::cout<<DTIME<<"Creating server and client"<<std::endl;
+       
+       /*
+               Create server.
+               SharedPtr will delete it when it goes out of scope.
+       */
+       SharedPtr<Server> server;
+       if(address == ""){
+               server = new Server(map_dir);
+               server->start(port);
+       }
+       
+       /*
+               Create client
+       */
+
+       Client client(device, playername.c_str(), draw_control);
+                       
+       Address connect_address(0,0,0,0, port);
+       try{
+               if(address == "")
+                       //connect_address.Resolve("localhost");
+                       connect_address.setAddress(127,0,0,1);
+               else
+                       connect_address.Resolve(address.c_str());
+       }
+       catch(ResolveError &e)
+       {
+               std::cout<<DTIME<<"Couldn't resolve address"<<std::endl;
+               //return 0;
+               error_message = L"Couldn't resolve address";
+               gui_loadingtext->remove();
+               return;
+       }
+       
+       dstream<<DTIME<<"Connecting to server at ";
+       connect_address.print(&dstream);
+       dstream<<std::endl;
+       client.connect(connect_address);
+       
+       try{
+               while(client.connectedAndInitialized() == false)
+               {
+                       // Update screen
+                       driver->beginScene(true, true, video::SColor(255,0,0,0));
+                       guienv->drawAll();
+                       driver->endScene();
+
+                       // Update client and server
+
+                       client.step(0.1);
+
+                       if(server != NULL)
+                               server->step(0.1);
+                       
+                       // Delay a bit
+                       sleep_ms(100);
+               }
+       }
+       catch(con::PeerNotFoundException &e)
+       {
+               std::cout<<DTIME<<"Timed out."<<std::endl;
+               //return 0;
+               error_message = L"Connection timed out.";
+               gui_loadingtext->remove();
+               return;
+       }
+
+       /*
+               Create skybox
+       */
+       /*scene::ISceneNode* skybox;
+       skybox = smgr->addSkyBoxSceneNode(
+               driver->getTexture(porting::getDataPath("skybox2.png").c_str()),
+               driver->getTexture(porting::getDataPath("skybox3.png").c_str()),
+               driver->getTexture(porting::getDataPath("skybox1.png").c_str()),
+               driver->getTexture(porting::getDataPath("skybox1.png").c_str()),
+               driver->getTexture(porting::getDataPath("skybox1.png").c_str()),
+               driver->getTexture(porting::getDataPath("skybox1.png").c_str()));*/
+       
+       /*
+               Create the camera node
+       */
+
+       scene::ICameraSceneNode* camera = smgr->addCameraSceneNode(
+               0, // Camera parent
+               v3f(BS*100, BS*2, BS*100), // Look from
+               v3f(BS*100+1, BS*2, BS*100), // Look to
+               -1 // Camera ID
+       );
+
+       if(camera == NULL)
+       {
+               error_message = L"Failed to create the camera node";
+               return;
+       }
+
+       //video::SColor skycolor = video::SColor(255,90,140,200);
+       //video::SColor skycolor = video::SColor(255,166,202,244);
+       //video::SColor skycolor = video::SColor(255,120,185,244);
+       video::SColor skycolor = video::SColor(255,140,186,250);
+
+       camera->setFOV(FOV_ANGLE);
+
+       // Just so big a value that everything rendered is visible
+       camera->setFarValue(100000*BS);
+       
+       f32 camera_yaw = 0; // "right/left"
+       f32 camera_pitch = 0; // "up/down"
+
+       /*
+               Move into game
+       */
+       
+       gui_loadingtext->remove();
+
+       /*
+               Add some gui stuff
+       */
+
+       // First line of debug text
+       gui::IGUIStaticText *guitext = guienv->addStaticText(
+                       L"Minetest-c55",
+                       core::rect<s32>(5, 5, 795, 5+text_height),
+                       false, false);
+       // Second line of debug text
+       gui::IGUIStaticText *guitext2 = guienv->addStaticText(
+                       L"",
+                       core::rect<s32>(5, 5+(text_height+5)*1, 795, (5+text_height)*2),
+                       false, false);
+       
+       // At the middle of the screen
+       // Object infos are shown in this
+       gui::IGUIStaticText *guitext_info = guienv->addStaticText(
+                       L"",
+                       core::rect<s32>(0,0,400,text_height+5) + v2s32(100,200),
+                       false, false);
+       
+       // Chat text
+       gui::IGUIStaticText *guitext_chat = guienv->addStaticText(
+                       L"",
+                       core::rect<s32>(0,0,0,0),
+                       false, false); // Disable word wrap as of now
+                       //false, true);
+       //guitext_chat->setBackgroundColor(video::SColor(96,0,0,0));
+       core::list<ChatLine> chat_lines;
+       
+       /*GUIQuickInventory *quick_inventory = new GUIQuickInventory
+                       (guienv, NULL, v2s32(10, 70), 5, &local_inventory);*/
+       /*GUIQuickInventory *quick_inventory = new GUIQuickInventory
+                       (guienv, NULL, v2s32(0, 0), quickinv_itemcount, &local_inventory);*/
+       
+       // Test the text input system
+       /*(new GUITextInputMenu(guienv, guiroot, -1, &g_menumgr,
+                       NULL))->drop();*/
+       /*GUIMessageMenu *menu =
+                       new GUIMessageMenu(guienv, guiroot, -1, 
+                               &g_menumgr,
+                               L"Asd");
+       menu->drop();*/
+       
+       // Launch pause menu
+       (new GUIPauseMenu(guienv, guiroot, -1, g_gamecallback,
+                       &g_menumgr))->drop();
+       
+       // Enable texts
+       /*guitext2->setVisible(true);
+       guitext_info->setVisible(true);
+       guitext_chat->setVisible(true);*/
+
+       //s32 guitext_chat_pad_bottom = 70;
+
+       /*
+               Some statistics are collected in these
+       */
+       u32 drawtime = 0;
+       u32 beginscenetime = 0;
+       u32 scenetime = 0;
+       u32 endscenetime = 0;
+       
+       // A test
+       //throw con::PeerNotFoundException("lol");
+
+       core::list<float> frametime_log;
+
+       float damage_flash_timer = 0;
+
+       /*
+               Main loop
+       */
+
+       bool first_loop_after_window_activation = true;
+
+       // Time is in milliseconds
+       // NOTE: getRealTime() causes strange problems in wine (imprecision?)
+       // NOTE: So we have to use getTime() and call run()s between them
+       u32 lasttime = device->getTimer()->getTime();
+
+       while(device->run() && kill == false)
+       {
+               if(g_gamecallback->disconnect_requested)
+               {
+                       g_gamecallback->disconnect_requested = false;
+                       break;
+               }
+
+               /*
+                       Process TextureSource's queue
+               */
+               ((TextureSource*)g_texturesource)->processQueue();
+
+               /*
+                       Random calculations
+               */
+               last_screensize = screensize;
+               screensize = driver->getScreenSize();
+               v2s32 displaycenter(screensize.X/2,screensize.Y/2);
+               //bool screensize_changed = screensize != last_screensize;
+               
+               // Hilight boxes collected during the loop and displayed
+               core::list< core::aabbox3d<f32> > hilightboxes;
+               
+               // Info text
+               std::wstring infotext;
+
+               // When screen size changes, update positions and sizes of stuff
+               /*if(screensize_changed)
+               {
+                       v2s32 pos(displaycenter.X-((quickinv_itemcount-1)*quickinv_spacing+quickinv_size)/2, screensize.Y-quickinv_spacing);
+                       quick_inventory->updatePosition(pos);
+               }*/
+
+               //TimeTaker //timer1("//timer1");
+               
+               // Time of frame without fps limit
+               float busytime;
+               u32 busytime_u32;
+               {
+                       // not using getRealTime is necessary for wine
+                       u32 time = device->getTimer()->getTime();
+                       if(time > lasttime)
+                               busytime_u32 = time - lasttime;
+                       else
+                               busytime_u32 = 0;
+                       busytime = busytime_u32 / 1000.0;
+               }
+
+               //std::cout<<"busytime_u32="<<busytime_u32<<std::endl;
+       
+               // Necessary for device->getTimer()->getTime()
+               device->run();
+
+               /*
+                       Viewing range
+               */
+               
+               updateViewingRange(busytime, &client);
+               
+               /*
+                       FPS limiter
+               */
+
+               {
+                       float fps_max = g_settings.getFloat("fps_max");
+                       u32 frametime_min = 1000./fps_max;
+                       
+                       if(busytime_u32 < frametime_min)
+                       {
+                               u32 sleeptime = frametime_min - busytime_u32;
+                               device->sleep(sleeptime);
+                       }
+               }
+
+               // Necessary for device->getTimer()->getTime()
+               device->run();
+
+               /*
+                       Time difference calculation
+               */
+               f32 dtime; // in seconds
+               
+               u32 time = device->getTimer()->getTime();
+               if(time > lasttime)
+                       dtime = (time - lasttime) / 1000.0;
+               else
+                       dtime = 0;
+               lasttime = time;
+
+               /*
+                       Log frametime for visualization
+               */
+               frametime_log.push_back(dtime);
+               if(frametime_log.size() > 100)
+               {
+                       core::list<float>::Iterator i = frametime_log.begin();
+                       frametime_log.erase(i);
+               }
+
+               /*
+                       Visualize frametime in terminal
+               */
+               /*for(u32 i=0; i<dtime*400; i++)
+                       std::cout<<"X";
+               std::cout<<std::endl;*/
+
+               /*
+                       Time average and jitter calculation
+               */
+
+               static f32 dtime_avg1 = 0.0;
+               dtime_avg1 = dtime_avg1 * 0.98 + dtime * 0.02;
+               f32 dtime_jitter1 = dtime - dtime_avg1;
+
+               static f32 dtime_jitter1_max_sample = 0.0;
+               static f32 dtime_jitter1_max_fraction = 0.0;
+               {
+                       static f32 jitter1_max = 0.0;
+                       static f32 counter = 0.0;
+                       if(dtime_jitter1 > jitter1_max)
+                               jitter1_max = dtime_jitter1;
+                       counter += dtime;
+                       if(counter > 0.0)
+                       {
+                               counter -= 3.0;
+                               dtime_jitter1_max_sample = jitter1_max;
+                               dtime_jitter1_max_fraction
+                                               = dtime_jitter1_max_sample / (dtime_avg1+0.001);
+                               jitter1_max = 0.0;
+                       }
+               }
+               
+               /*
+                       Busytime average and jitter calculation
+               */
+
+               static f32 busytime_avg1 = 0.0;
+               busytime_avg1 = busytime_avg1 * 0.98 + busytime * 0.02;
+               f32 busytime_jitter1 = busytime - busytime_avg1;
+               
+               static f32 busytime_jitter1_max_sample = 0.0;
+               static f32 busytime_jitter1_min_sample = 0.0;
+               {
+                       static f32 jitter1_max = 0.0;
+                       static f32 jitter1_min = 0.0;
+                       static f32 counter = 0.0;
+                       if(busytime_jitter1 > jitter1_max)
+                               jitter1_max = busytime_jitter1;
+                       if(busytime_jitter1 < jitter1_min)
+                               jitter1_min = busytime_jitter1;
+                       counter += dtime;
+                       if(counter > 0.0){
+                               counter -= 3.0;
+                               busytime_jitter1_max_sample = jitter1_max;
+                               busytime_jitter1_min_sample = jitter1_min;
+                               jitter1_max = 0.0;
+                               jitter1_min = 0.0;
+                       }
+               }
+               
+               /*
+                       Debug info for client
+               */
+               {
+                       static float counter = 0.0;
+                       counter -= dtime;
+                       if(counter < 0)
+                       {
+                               counter = 30.0;
+                               client.printDebugInfo(std::cout);
+                       }
+               }
+
+               /*
+                       Direct handling of user input
+               */
+               
+               // Reset input if window not active or some menu is active
+               if(device->isWindowActive() == false || noMenuActive() == false)
+               {
+                       input->clear();
+               }
+
+               // Input handler step() (used by the random input generator)
+               input->step(dtime);
+
+               /*
+                       Launch menus according to keys
+               */
+               if(input->wasKeyDown(irr::KEY_KEY_I))
+               {
+                       dstream<<DTIME<<"the_game: "
+                                       <<"Launching inventory"<<std::endl;
+                       
+                       GUIInventoryMenu *menu =
+                               new GUIInventoryMenu(guienv, guiroot, -1,
+                                       &g_menumgr, v2s16(8,7),
+                                       client.getInventoryContext(),
+                                       &client);
+
+                       core::array<GUIInventoryMenu::DrawSpec> draw_spec;
+                       draw_spec.push_back(GUIInventoryMenu::DrawSpec(
+                                       "list", "current_player", "main",
+                                       v2s32(0, 3), v2s32(8, 4)));
+                       draw_spec.push_back(GUIInventoryMenu::DrawSpec(
+                                       "list", "current_player", "craft",
+                                       v2s32(3, 0), v2s32(3, 3)));
+                       draw_spec.push_back(GUIInventoryMenu::DrawSpec(
+                                       "list", "current_player", "craftresult",
+                                       v2s32(7, 1), v2s32(1, 1)));
+
+                       menu->setDrawSpec(draw_spec);
+
+                       menu->drop();
+               }
+               else if(input->wasKeyDown(irr::KEY_ESCAPE))
+               {
+                       dstream<<DTIME<<"the_game: "
+                                       <<"Launching pause menu"<<std::endl;
+                       // It will delete itself by itself
+                       (new GUIPauseMenu(guienv, guiroot, -1, g_gamecallback,
+                                       &g_menumgr))->drop();
+               }
+               else if(input->wasKeyDown(irr::KEY_KEY_T))
+               {
+                       TextDest *dest = new TextDestChat(&client);
+
+                       (new GUITextInputMenu(guienv, guiroot, -1,
+                                       &g_menumgr, dest,
+                                       L""))->drop();
+               }
+
+               // Item selection with mouse wheel
+               {
+                       s32 wheel = input->getMouseWheel();
+                       u16 max_item = MYMIN(PLAYER_INVENTORY_SIZE-1,
+                                       hotbar_itemcount-1);
+
+                       if(wheel < 0)
+                       {
+                               if(g_selected_item < max_item)
+                                       g_selected_item++;
+                               else
+                                       g_selected_item = 0;
+                       }
+                       else if(wheel > 0)
+                       {
+                               if(g_selected_item > 0)
+                                       g_selected_item--;
+                               else
+                                       g_selected_item = max_item;
+                       }
+               }
+               
+               // Item selection
+               for(u16 i=0; i<10; i++)
+               {
+                       s32 keycode = irr::KEY_KEY_1 + i;
+                       if(i == 9)
+                               keycode = irr::KEY_KEY_0;
+                       if(input->wasKeyDown((irr::EKEY_CODE)keycode))
+                       {
+                               if(i < PLAYER_INVENTORY_SIZE && i < hotbar_itemcount)
+                               {
+                                       g_selected_item = i;
+
+                                       dstream<<DTIME<<"Selected item: "
+                                                       <<g_selected_item<<std::endl;
+                               }
+                       }
+               }
+
+               // Viewing range selection
+               if(input->wasKeyDown(irr::KEY_KEY_R))
+               {
+                       if(draw_control.range_all)
+                       {
+                               draw_control.range_all = false;
+                               dstream<<DTIME<<"Disabled full viewing range"<<std::endl;
+                       }
+                       else
+                       {
+                               draw_control.range_all = true;
+                               dstream<<DTIME<<"Enabled full viewing range"<<std::endl;
+                       }
+               }
+
+               // Print debug stacks
+               if(input->wasKeyDown(irr::KEY_KEY_P))
+               {
+                       dstream<<"-----------------------------------------"
+                                       <<std::endl;
+                       dstream<<DTIME<<"Printing debug stacks:"<<std::endl;
+                       dstream<<"-----------------------------------------"
+                                       <<std::endl;
+                       debug_stacks_print();
+               }
+
+               /*
+                       Player speed control
+               */
+               
+               {
+                       /*bool a_up,
+                       bool a_down,
+                       bool a_left,
+                       bool a_right,
+                       bool a_jump,
+                       bool a_superspeed,
+                       bool a_sneak,
+                       float a_pitch,
+                       float a_yaw*/
+                       PlayerControl control(
+                               input->isKeyDown(irr::KEY_KEY_W),
+                               input->isKeyDown(irr::KEY_KEY_S),
+                               input->isKeyDown(irr::KEY_KEY_A),
+                               input->isKeyDown(irr::KEY_KEY_D),
+                               input->isKeyDown(irr::KEY_SPACE),
+                               input->isKeyDown(irr::KEY_KEY_E),
+                               input->isKeyDown(irr::KEY_LSHIFT)
+                                               || input->isKeyDown(irr::KEY_RSHIFT),
+                               camera_pitch,
+                               camera_yaw
+                       );
+                       client.setPlayerControl(control);
+               }
+               
+               /*
+                       Run server
+               */
+
+               if(server != NULL)
+               {
+                       //TimeTaker timer("server->step(dtime)");
+                       server->step(dtime);
+               }
+
+               /*
+                       Process environment
+               */
+               
+               {
+                       //TimeTaker timer("client.step(dtime)");
+                       client.step(dtime);
+                       //client.step(dtime_avg1);
+               }
+
+               // Read client events
+               for(;;)
+               {
+                       ClientEvent event = client.getClientEvent();
+                       if(event.type == CE_NONE)
+                       {
+                               break;
+                       }
+                       else if(event.type == CE_PLAYER_DAMAGE)
+                       {
+                               //u16 damage = event.player_damage.amount;
+                               //dstream<<"Player damage: "<<damage<<std::endl;
+                               damage_flash_timer = 0.05;
+                       }
+                       else if(event.type == CE_PLAYER_FORCE_MOVE)
+                       {
+                               camera_yaw = event.player_force_move.yaw;
+                               camera_pitch = event.player_force_move.pitch;
+                       }
+               }
+               
+               // Get player position
+               v3f player_position = client.getPlayerPosition();
+               
+               //TimeTaker //timer2("//timer2");
+
+               /*
+                       Mouse and camera control
+               */
+               
+               if((device->isWindowActive() && noMenuActive()) || random_input)
+               {
+                       if(!random_input)
+                               device->getCursorControl()->setVisible(false);
+
+                       if(first_loop_after_window_activation){
+                               //std::cout<<"window active, first loop"<<std::endl;
+                               first_loop_after_window_activation = false;
+                       }
+                       else{
+                               s32 dx = input->getMousePos().X - displaycenter.X;
+                               s32 dy = input->getMousePos().Y - displaycenter.Y;
+                               //std::cout<<"window active, pos difference "<<dx<<","<<dy<<std::endl;
+                               camera_yaw -= dx*0.2;
+                               camera_pitch += dy*0.2;
+                               if(camera_pitch < -89.5) camera_pitch = -89.5;
+                               if(camera_pitch > 89.5) camera_pitch = 89.5;
+                       }
+                       input->setMousePos(displaycenter.X, displaycenter.Y);
+               }
+               else{
+                       device->getCursorControl()->setVisible(true);
+
+                       //std::cout<<"window inactive"<<std::endl;
+                       first_loop_after_window_activation = true;
+               }
+
+               camera_yaw = wrapDegrees(camera_yaw);
+               camera_pitch = wrapDegrees(camera_pitch);
+               
+               v3f camera_direction = v3f(0,0,1);
+               camera_direction.rotateYZBy(camera_pitch);
+               camera_direction.rotateXZBy(camera_yaw);
+               
+               // This is at the height of the eyes of the current figure
+               //v3f camera_position = player_position + v3f(0, BS+BS/2, 0);
+               // This is more like in minecraft
+               v3f camera_position = player_position + v3f(0, BS+BS*0.625, 0);
+
+               camera->setPosition(camera_position);
+               // *100.0 helps in large map coordinates
+               camera->setTarget(camera_position + camera_direction * 100.0);
+
+               if(FIELD_OF_VIEW_TEST){
+                       client.updateCamera(v3f(0,0,0), v3f(0,0,1));
+               }
+               else{
+                       //TimeTaker timer("client.updateCamera");
+                       client.updateCamera(camera_position, camera_direction);
+               }
+               
+               //timer2.stop();
+               //TimeTaker //timer3("//timer3");
+
+               /*
+                       Calculate what block is the crosshair pointing to
+               */
+               
+               //u32 t1 = device->getTimer()->getRealTime();
+               
+               //f32 d = 4; // max. distance
+               f32 d = 4; // max. distance
+               core::line3d<f32> shootline(camera_position,
+                               camera_position + camera_direction * BS * (d+1));
+
+               MapBlockObject *selected_object = client.getSelectedObject
+                               (d*BS, camera_position, shootline);
+
+               ClientActiveObject *selected_active_object
+                               = client.getSelectedActiveObject
+                                       (d*BS, camera_position, shootline);
+
+               if(selected_object != NULL)
+               {
+                       //dstream<<"Client returned selected_object != NULL"<<std::endl;
+
+                       core::aabbox3d<f32> box_on_map
+                                       = selected_object->getSelectionBoxOnMap();
+
+                       hilightboxes.push_back(box_on_map);
+
+                       infotext = narrow_to_wide(selected_object->infoText());
+
+                       if(input->getLeftClicked())
+                       {
+                               std::cout<<DTIME<<"Left-clicked object"<<std::endl;
+                               client.clickObject(0, selected_object->getBlock()->getPos(),
+                                               selected_object->getId(), g_selected_item);
+                       }
+                       else if(input->getRightClicked())
+                       {
+                               std::cout<<DTIME<<"Right-clicked object"<<std::endl;
+                               /*
+                                       Check if we want to modify the object ourselves
+                               */
+                               if(selected_object->getTypeId() == MAPBLOCKOBJECT_TYPE_SIGN)
+                               {
+                                       dstream<<"Sign object right-clicked"<<std::endl;
+                                       
+                                       if(random_input == false)
+                                       {
+                                               // Get a new text for it
+
+                                               TextDest *dest = new TextDestSign(
+                                                               selected_object->getBlock()->getPos(),
+                                                               selected_object->getId(),
+                                                               &client);
+
+                                               SignObject *sign_object = (SignObject*)selected_object;
+
+                                               std::wstring wtext =
+                                                               narrow_to_wide(sign_object->getText());
+
+                                               (new GUITextInputMenu(guienv, guiroot, -1,
+                                                               &g_menumgr, dest,
+                                                               wtext))->drop();
+                                       }
+                               }
+                               /*
+                                       Otherwise pass the event to the server as-is
+                               */
+                               else
+                               {
+                                       client.clickObject(1, selected_object->getBlock()->getPos(),
+                                                       selected_object->getId(), g_selected_item);
+                               }
+                       }
+               }
+               else if(selected_active_object != NULL)
+               {
+                       //dstream<<"Client returned selected_active_object != NULL"<<std::endl;
+                       
+                       core::aabbox3d<f32> *selection_box
+                                       = selected_active_object->getSelectionBox();
+                       // Box should exist because object was returned in the
+                       // first place
+                       assert(selection_box);
+
+                       v3f pos = selected_active_object->getPosition();
+
+                       core::aabbox3d<f32> box_on_map(
+                                       selection_box->MinEdge + pos,
+                                       selection_box->MaxEdge + pos
+                       );
+
+                       hilightboxes.push_back(box_on_map);
+
+                       //infotext = narrow_to_wide("A ClientActiveObject");
+                       infotext = narrow_to_wide(selected_active_object->infoText());
+
+                       if(input->getLeftClicked())
+                       {
+                               std::cout<<DTIME<<"Left-clicked object"<<std::endl;
+                               client.clickActiveObject(0,
+                                               selected_active_object->getId(), g_selected_item);
+                       }
+                       else if(input->getRightClicked())
+                       {
+                               std::cout<<DTIME<<"Right-clicked object"<<std::endl;
+                       }
+               }
+               else // selected_object == NULL
+               {
+
+               /*
+                       Find out which node we are pointing at
+               */
+               
+               bool nodefound = false;
+               v3s16 nodepos;
+               v3s16 neighbourpos;
+               core::aabbox3d<f32> nodehilightbox;
+
+               getPointedNode(&client, player_position,
+                               camera_direction, camera_position,
+                               nodefound, shootline,
+                               nodepos, neighbourpos,
+                               nodehilightbox, d);
+       
+               static float nodig_delay_counter = 0.0;
+
+               if(nodefound)
+               {
+                       static v3s16 nodepos_old(-32768,-32768,-32768);
+
+                       static float dig_time = 0.0;
+                       static u16 dig_index = 0;
+                       
+                       /*
+                               Visualize selection
+                       */
+
+                       hilightboxes.push_back(nodehilightbox);
+
+                       /*
+                               Check information text of node
+                       */
+
+                       NodeMetadata *meta = client.getNodeMetadata(nodepos);
+                       if(meta)
+                       {
+                               infotext = narrow_to_wide(meta->infoText());
+                       }
+                       
+                       //MapNode node = client.getNode(nodepos);
+
+                       /*
+                               Handle digging
+                       */
+                       
+                       if(input->getLeftReleased())
+                       {
+                               client.clearTempMod(nodepos);
+                               dig_time = 0.0;
+                       }
+                       
+                       if(nodig_delay_counter > 0.0)
+                       {
+                               nodig_delay_counter -= dtime;
+                       }
+                       else
+                       {
+                               if(nodepos != nodepos_old)
+                               {
+                                       std::cout<<DTIME<<"Pointing at ("<<nodepos.X<<","
+                                                       <<nodepos.Y<<","<<nodepos.Z<<")"<<std::endl;
+
+                                       if(nodepos_old != v3s16(-32768,-32768,-32768))
+                                       {
+                                               client.clearTempMod(nodepos_old);
+                                               dig_time = 0.0;
+                                       }
+                               }
+
+                               if(input->getLeftClicked() ||
+                                               (input->getLeftState() && nodepos != nodepos_old))
+                               {
+                                       dstream<<DTIME<<"Started digging"<<std::endl;
+                                       client.groundAction(0, nodepos, neighbourpos, g_selected_item);
+                               }
+                               if(input->getLeftClicked())
+                               {
+                                       client.setTempMod(nodepos, NodeMod(NODEMOD_CRACK, 0));
+                               }
+                               if(input->getLeftState())
+                               {
+                                       MapNode n = client.getNode(nodepos);
+                               
+                                       // Get tool name. Default is "" = bare hands
+                                       std::string toolname = "";
+                                       InventoryList *mlist = local_inventory.getList("main");
+                                       if(mlist != NULL)
+                                       {
+                                               InventoryItem *item = mlist->getItem(g_selected_item);
+                                               if(item && (std::string)item->getName() == "ToolItem")
+                                               {
+                                                       ToolItem *titem = (ToolItem*)item;
+                                                       toolname = titem->getToolName();
+                                               }
+                                       }
+
+                                       // Get digging properties for material and tool
+                                       u8 material = n.d;
+                                       DiggingProperties prop =
+                                                       getDiggingProperties(material, toolname);
+                                       
+                                       float dig_time_complete = 0.0;
+
+                                       if(prop.diggable == false)
+                                       {
+                                               /*dstream<<"Material "<<(int)material
+                                                               <<" not diggable with \""
+                                                               <<toolname<<"\""<<std::endl;*/
+                                               // I guess nobody will wait for this long
+                                               dig_time_complete = 10000000.0;
+                                       }
+                                       else
+                                       {
+                                               dig_time_complete = prop.time;
+                                       }
+                                       
+                                       if(dig_time_complete >= 0.001)
+                                       {
+                                               dig_index = (u16)((float)CRACK_ANIMATION_LENGTH
+                                                               * dig_time/dig_time_complete);
+                                       }
+                                       // This is for torches
+                                       else
+                                       {
+                                               dig_index = CRACK_ANIMATION_LENGTH;
+                                       }
+
+                                       if(dig_index < CRACK_ANIMATION_LENGTH)
+                                       {
+                                               //TimeTaker timer("client.setTempMod");
+                                               //dstream<<"dig_index="<<dig_index<<std::endl;
+                                               client.setTempMod(nodepos, NodeMod(NODEMOD_CRACK, dig_index));
+                                       }
+                                       else
+                                       {
+                                               dstream<<DTIME<<"Digging completed"<<std::endl;
+                                               client.groundAction(3, nodepos, neighbourpos, g_selected_item);
+                                               client.clearTempMod(nodepos);
+                                               client.removeNode(nodepos);
+
+                                               dig_time = 0;
+
+                                               nodig_delay_counter = dig_time_complete
+                                                               / (float)CRACK_ANIMATION_LENGTH;
+
+                                               // We don't want a corresponding delay to
+                                               // very time consuming nodes
+                                               if(nodig_delay_counter > 0.5)
+                                               {
+                                                       nodig_delay_counter = 0.5;
+                                               }
+                                               // We want a slight delay to very little
+                                               // time consuming nodes
+                                               float mindelay = 0.15;
+                                               if(nodig_delay_counter < mindelay)
+                                               {
+                                                       nodig_delay_counter = mindelay;
+                                               }
+                                       }
+
+                                       dig_time += dtime;
+                               }
+                       }
+                       
+                       if(input->getRightClicked())
+                       {
+                               std::cout<<DTIME<<"Ground right-clicked"<<std::endl;
+                               
+                               if(meta && meta->typeId() == CONTENT_SIGN_WALL && !random_input)
+                               {
+                                       dstream<<"Sign node right-clicked"<<std::endl;
+                                       
+                                       SignNodeMetadata *signmeta = (SignNodeMetadata*)meta;
+                                       
+                                       // Get a new text for it
+
+                                       TextDest *dest = new TextDestSignNode(nodepos, &client);
+
+                                       std::wstring wtext =
+                                                       narrow_to_wide(signmeta->getText());
+
+                                       (new GUITextInputMenu(guienv, guiroot, -1,
+                                                       &g_menumgr, dest,
+                                                       wtext))->drop();
+                               }
+                               else if(meta && meta->typeId() == CONTENT_CHEST && !random_input)
+                               {
+                                       dstream<<"Chest node right-clicked"<<std::endl;
+                                       
+                                       //ChestNodeMetadata *chestmeta = (ChestNodeMetadata*)meta;
+
+                                       std::string chest_inv_id;
+                                       chest_inv_id += "nodemeta:";
+                                       chest_inv_id += itos(nodepos.X);
+                                       chest_inv_id += ",";
+                                       chest_inv_id += itos(nodepos.Y);
+                                       chest_inv_id += ",";
+                                       chest_inv_id += itos(nodepos.Z);
+                                       
+                                       GUIInventoryMenu *menu =
+                                               new GUIInventoryMenu(guienv, guiroot, -1,
+                                                       &g_menumgr, v2s16(8,9),
+                                                       client.getInventoryContext(),
+                                                       &client);
+
+                                       core::array<GUIInventoryMenu::DrawSpec> draw_spec;
+                                       
+                                       draw_spec.push_back(GUIInventoryMenu::DrawSpec(
+                                                       "list", chest_inv_id, "0",
+                                                       v2s32(0, 0), v2s32(8, 4)));
+                                       draw_spec.push_back(GUIInventoryMenu::DrawSpec(
+                                                       "list", "current_player", "main",
+                                                       v2s32(0, 5), v2s32(8, 4)));
+
+                                       menu->setDrawSpec(draw_spec);
+
+                                       menu->drop();
+
+                               }
+                               else if(meta && meta->typeId() == CONTENT_FURNACE && !random_input)
+                               {
+                                       dstream<<"Furnace node right-clicked"<<std::endl;
+                                       
+                                       GUIFurnaceMenu *menu =
+                                               new GUIFurnaceMenu(guienv, guiroot, -1,
+                                                       &g_menumgr, nodepos, &client);
+
+                                       menu->drop();
+
+                               }
+                               else
+                               {
+                                       client.groundAction(1, nodepos, neighbourpos, g_selected_item);
+                               }
+                       }
+                       
+                       nodepos_old = nodepos;
+               }
+               else{
+               }
+
+               } // selected_object == NULL
+               
+               input->resetLeftClicked();
+               input->resetRightClicked();
+               
+               if(input->getLeftReleased())
+               {
+                       std::cout<<DTIME<<"Left button released (stopped digging)"
+                                       <<std::endl;
+                       client.groundAction(2, v3s16(0,0,0), v3s16(0,0,0), 0);
+               }
+               if(input->getRightReleased())
+               {
+                       //std::cout<<DTIME<<"Right released"<<std::endl;
+                       // Nothing here
+               }
+               
+               input->resetLeftReleased();
+               input->resetRightReleased();
+               
+               /*
+                       Calculate stuff for drawing
+               */
+
+               camera->setAspectRatio((f32)screensize.X / (f32)screensize.Y);
+               
+               u32 daynight_ratio = client.getDayNightRatio();
+               u8 l = decode_light((daynight_ratio * LIGHT_SUN) / 1000);
+               video::SColor bgcolor = video::SColor(
+                               255,
+                               skycolor.getRed() * l / 255,
+                               skycolor.getGreen() * l / 255,
+                               skycolor.getBlue() * l / 255);
+
+               /*
+                       Fog
+               */
+               
+               if(g_settings.getBool("enable_fog") == true)
+               {
+                       //f32 range = draw_control.wanted_range * BS + MAP_BLOCKSIZE/2*BS;
+                       f32 range = draw_control.wanted_range * BS + 0.8*MAP_BLOCKSIZE*BS;
+                       //f32 range = draw_control.wanted_range * BS + 0.0*MAP_BLOCKSIZE*BS;
+                       if(draw_control.range_all)
+                               range = 100000*BS;
+
+                       driver->setFog(
+                               bgcolor,
+                               video::EFT_FOG_LINEAR,
+                               range*0.4,
+                               range*1.0,
+                               0.01,
+                               false, // pixel fog
+                               false // range fog
+                       );
+               }
+               else
+               {
+                       driver->setFog(
+                               bgcolor,
+                               video::EFT_FOG_LINEAR,
+                               100000*BS,
+                               110000*BS,
+                               0.01,
+                               false, // pixel fog
+                               false // range fog
+                       );
+               }
+
+
+               /*
+                       Update gui stuff (0ms)
+               */
+
+               //TimeTaker guiupdatetimer("Gui updating");
+               
+               {
+                       static float drawtime_avg = 0;
+                       drawtime_avg = drawtime_avg * 0.95 + (float)drawtime*0.05;
+                       static float beginscenetime_avg = 0;
+                       beginscenetime_avg = beginscenetime_avg * 0.95 + (float)beginscenetime*0.05;
+                       static float scenetime_avg = 0;
+                       scenetime_avg = scenetime_avg * 0.95 + (float)scenetime*0.05;
+                       static float endscenetime_avg = 0;
+                       endscenetime_avg = endscenetime_avg * 0.95 + (float)endscenetime*0.05;
+                       
+                       char temptext[300];
+                       snprintf(temptext, 300, "Minetest-c55 ("
+                                       "F: item=%i"
+                                       ", R: range_all=%i"
+                                       ")"
+                                       " drawtime=%.0f, beginscenetime=%.0f"
+                                       ", scenetime=%.0f, endscenetime=%.0f",
+                                       g_selected_item,
+                                       draw_control.range_all,
+                                       drawtime_avg,
+                                       beginscenetime_avg,
+                                       scenetime_avg,
+                                       endscenetime_avg
+                                       );
+                       
+                       guitext->setText(narrow_to_wide(temptext).c_str());
+               }
+               
+               {
+                       char temptext[300];
+                       snprintf(temptext, 300,
+                                       "(% .1f, % .1f, % .1f)"
+                                       " (% .3f < btime_jitter < % .3f"
+                                       ", dtime_jitter = % .1f %%"
+                                       ", v_range = %.1f)",
+                                       player_position.X/BS,
+                                       player_position.Y/BS,
+                                       player_position.Z/BS,
+                                       busytime_jitter1_min_sample,
+                                       busytime_jitter1_max_sample,
+                                       dtime_jitter1_max_fraction * 100.0,
+                                       draw_control.wanted_range
+                                       );
+
+                       guitext2->setText(narrow_to_wide(temptext).c_str());
+               }
+               
+               {
+                       guitext_info->setText(infotext.c_str());
+               }
+               
+               /*
+                       Get chat messages from client
+               */
+               {
+                       // Get new messages
+                       std::wstring message;
+                       while(client.getChatMessage(message))
+                       {
+                               chat_lines.push_back(ChatLine(message));
+                               /*if(chat_lines.size() > 6)
+                               {
+                                       core::list<ChatLine>::Iterator
+                                                       i = chat_lines.begin();
+                                       chat_lines.erase(i);
+                               }*/
+                       }
+                       // Append them to form the whole static text and throw
+                       // it to the gui element
+                       std::wstring whole;
+                       // This will correspond to the line number counted from
+                       // top to bottom, from size-1 to 0
+                       s16 line_number = chat_lines.size();
+                       // Count of messages to be removed from the top
+                       u16 to_be_removed_count = 0;
+                       for(core::list<ChatLine>::Iterator
+                                       i = chat_lines.begin();
+                                       i != chat_lines.end(); i++)
+                       {
+                               // After this, line number is valid for this loop
+                               line_number--;
+                               // Increment age
+                               (*i).age += dtime;
+                               /*
+                                       This results in a maximum age of 60*6 to the
+                                       lowermost line and a maximum of 6 lines
+                               */
+                               float allowed_age = (6-line_number) * 60.0;
+
+                               if((*i).age > allowed_age)
+                               {
+                                       to_be_removed_count++;
+                                       continue;
+                               }
+                               whole += (*i).text + L'\n';
+                       }
+                       for(u16 i=0; i<to_be_removed_count; i++)
+                       {
+                               core::list<ChatLine>::Iterator
+                                               it = chat_lines.begin();
+                               chat_lines.erase(it);
+                       }
+                       guitext_chat->setText(whole.c_str());
+
+                       // Update gui element size and position
+
+                       /*core::rect<s32> rect(
+                                       10,
+                                       screensize.Y - guitext_chat_pad_bottom
+                                                       - text_height*chat_lines.size(),
+                                       screensize.X - 10,
+                                       screensize.Y - guitext_chat_pad_bottom
+                       );*/
+                       core::rect<s32> rect(
+                                       10,
+                                       50,
+                                       screensize.X - 10,
+                                       50 + text_height*chat_lines.size()
+                       );
+
+                       guitext_chat->setRelativePosition(rect);
+
+                       if(chat_lines.size() == 0)
+                               guitext_chat->setVisible(false);
+                       else
+                               guitext_chat->setVisible(true);
+               }
+
+               /*
+                       Inventory
+               */
+               
+               static u16 old_selected_item = 65535;
+               if(client.getLocalInventoryUpdated()
+                               || g_selected_item != old_selected_item)
+               {
+                       old_selected_item = g_selected_item;
+                       //std::cout<<"Updating local inventory"<<std::endl;
+                       client.getLocalInventory(local_inventory);
+               }
+               
+               /*
+                       Send actions returned by the inventory menu
+               */
+               while(inventory_action_queue.size() != 0)
+               {
+                       InventoryAction *a = inventory_action_queue.pop_front();
+
+                       client.sendInventoryAction(a);
+                       // Eat it
+                       delete a;
+               }
+
+               /*
+                       Drawing begins
+               */
+
+               TimeTaker drawtimer("Drawing");
+
+               
+               {
+                       TimeTaker timer("beginScene");
+                       driver->beginScene(true, true, bgcolor);
+                       //driver->beginScene(false, true, bgcolor);
+                       beginscenetime = timer.stop(true);
+               }
+
+               //timer3.stop();
+               
+               //std::cout<<DTIME<<"smgr->drawAll()"<<std::endl;
+               
+               {
+                       TimeTaker timer("smgr");
+                       smgr->drawAll();
+                       scenetime = timer.stop(true);
+               }
+               
+               {
+               //TimeTaker timer9("auxiliary drawings");
+               // 0ms
+               
+               //timer9.stop();
+               //TimeTaker //timer10("//timer10");
+               
+               video::SMaterial m;
+               //m.Thickness = 10;
+               m.Thickness = 3;
+               m.Lighting = false;
+               driver->setMaterial(m);
+
+               driver->setTransform(video::ETS_WORLD, core::IdentityMatrix);
+
+               for(core::list< core::aabbox3d<f32> >::Iterator i=hilightboxes.begin();
+                               i != hilightboxes.end(); i++)
+               {
+                       /*std::cout<<"hilightbox min="
+                                       <<"("<<i->MinEdge.X<<","<<i->MinEdge.Y<<","<<i->MinEdge.Z<<")"
+                                       <<" max="
+                                       <<"("<<i->MaxEdge.X<<","<<i->MaxEdge.Y<<","<<i->MaxEdge.Z<<")"
+                                       <<std::endl;*/
+                       driver->draw3DBox(*i, video::SColor(255,0,0,0));
+               }
+
+               /*
+                       Frametime log
+               */
+               if(g_settings.getBool("frametime_graph") == true)
+               {
+                       s32 x = 10;
+                       for(core::list<float>::Iterator
+                                       i = frametime_log.begin();
+                                       i != frametime_log.end();
+                                       i++)
+                       {
+                               driver->draw2DLine(v2s32(x,50),
+                                               v2s32(x,50+(*i)*1000),
+                                               video::SColor(255,255,255,255));
+                               x++;
+                       }
+               }
+
+               /*
+                       Draw crosshair
+               */
+               driver->draw2DLine(displaycenter - core::vector2d<s32>(10,0),
+                               displaycenter + core::vector2d<s32>(10,0),
+                               video::SColor(255,255,255,255));
+               driver->draw2DLine(displaycenter - core::vector2d<s32>(0,10),
+                               displaycenter + core::vector2d<s32>(0,10),
+                               video::SColor(255,255,255,255));
+
+               } // timer
+
+               //timer10.stop();
+               //TimeTaker //timer11("//timer11");
+
+               /*
+                       Draw gui
+               */
+               // 0-1ms
+               guienv->drawAll();
+
+               /*
+                       Draw hotbar
+               */
+               {
+                       draw_hotbar(driver, font, v2s32(displaycenter.X, screensize.Y),
+                                       hotbar_imagesize, hotbar_itemcount, &local_inventory,
+                                       client.getHP());
+               }
+
+               /*
+                       Damage flash
+               */
+               if(damage_flash_timer > 0.0)
+               {
+                       damage_flash_timer -= dtime;
+                       
+                       video::SColor color(128,255,0,0);
+                       driver->draw2DRectangle(color,
+                                       core::rect<s32>(0,0,screensize.X,screensize.Y),
+                                       NULL);
+               }
+               
+               /*
+                       End scene
+               */
+               {
+                       TimeTaker timer("endScene");
+                       driver->endScene();
+                       endscenetime = timer.stop(true);
+               }
+
+               drawtime = drawtimer.stop(true);
+
+               /*
+                       End of drawing
+               */
+
+               static s16 lastFPS = 0;
+               //u16 fps = driver->getFPS();
+               u16 fps = (1.0/dtime_avg1);
+
+               if (lastFPS != fps)
+               {
+                       core::stringw str = L"Minetest [";
+                       str += driver->getName();
+                       str += "] FPS:";
+                       str += fps;
+
+                       device->setWindowCaption(str.c_str());
+                       lastFPS = fps;
+               }
+       }
+}
+
+
diff --git a/src/game.h b/src/game.h
new file mode 100644 (file)
index 0000000..7cba129
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+Minetest-c55
+Copyright (C) 2011 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#ifndef GAME_HEADER
+#define GAME_HEADER
+
+#include "common_irrlicht.h"
+#include <string>
+
+class InputHandler
+{
+public:
+       InputHandler()
+       {
+       }
+       virtual ~InputHandler()
+       {
+       }
+
+       virtual bool isKeyDown(EKEY_CODE keyCode) = 0;
+       virtual bool wasKeyDown(EKEY_CODE keyCode) = 0;
+       
+       virtual v2s32 getMousePos() = 0;
+       virtual void setMousePos(s32 x, s32 y) = 0;
+
+       virtual bool getLeftState() = 0;
+       virtual bool getRightState() = 0;
+
+       virtual bool getLeftClicked() = 0;
+       virtual bool getRightClicked() = 0;
+       virtual void resetLeftClicked() = 0;
+       virtual void resetRightClicked() = 0;
+
+       virtual bool getLeftReleased() = 0;
+       virtual bool getRightReleased() = 0;
+       virtual void resetLeftReleased() = 0;
+       virtual void resetRightReleased() = 0;
+       
+       virtual s32 getMouseWheel() = 0;
+
+       virtual void step(float dtime) {};
+
+       virtual void clear() {};
+};
+
+void the_game(
+       bool &kill,
+       bool random_input,
+       InputHandler *input,
+       IrrlichtDevice *device,
+       gui::IGUIFont* font,
+       std::string map_dir,
+       std::string playername,
+       std::string address,
+       u16 port,
+       std::wstring &error_message
+);
+
+#endif
+
index af94387f678aba1b2ee386c2a76928d084b7ed75..ffe877ebdfa4330e7a40d74406a1771606b6d9a9 100644 (file)
@@ -261,16 +261,6 @@ Making it more portable:
 \r
 */\r
 \r
-/*\r
-       Setting this to 1 enables a special camera mode that forces\r
-       the renderers to think that the camera statically points from\r
-       the starting place to a static direction.\r
-\r
-       This allows one to move around with the player and see what\r
-       is actually drawn behind solid things and behind the player.\r
-*/\r
-#define FIELD_OF_VIEW_TEST 0\r
-\r
 #ifdef NDEBUG\r
        #ifdef _WIN32\r
                #pragma message ("Disabling unit tests")\r
@@ -295,41 +285,32 @@ Making it more portable:
 \r
 #include <iostream>\r
 #include <fstream>\r
-#include <jmutexautolock.h>\r
+//#include <jmutexautolock.h>\r
 #include <locale.h>\r
 #include "main.h"\r
 #include "common_irrlicht.h"\r
 #include "debug.h"\r
-#include "map.h"\r
-#include "player.h"\r
+//#include "map.h"\r
+//#include "player.h"\r
 #include "test.h"\r
-//#include "environment.h"\r
 #include "server.h"\r
-#include "client.h"\r
-//#include "serialization.h"\r
+//#include "client.h"\r
 #include "constants.h"\r
-//#include "strfnd.h"\r
 #include "porting.h"\r
 #include "gettime.h"\r
-#include "porting.h"\r
-#include "guiPauseMenu.h"\r
-#include "guiInventoryMenu.h"\r
-#include "guiTextInputMenu.h"\r
-#include "materials.h"\r
 #include "guiMessageMenu.h"\r
 #include "filesys.h"\r
 #include "config.h"\r
 #include "guiMainMenu.h"\r
 #include "mineral.h"\r
-#include "noise.h"\r
-#include "tile.h"\r
-#include "guiFurnaceMenu.h"\r
+//#include "noise.h"\r
+//#include "tile.h"\r
+#include "materials.h"\r
+#include "game.h"\r
 \r
 // This makes textures\r
 ITextureSource *g_texturesource = NULL;\r
 \r
-MapDrawControl draw_control;\r
-\r
 /*\r
        Settings.\r
        These are loaded from the config file.\r
@@ -343,12 +324,6 @@ extern void set_default_settings();
        Random stuff\r
 */\r
 \r
-IrrlichtDevice *g_device = NULL;\r
-Client *g_client = NULL;\r
-\r
-const s32 hotbar_itemcount = 8;\r
-const s32 hotbar_imagesize = 36;\r
-\r
 /*\r
        GUI Stuff\r
 */\r
@@ -356,60 +331,6 @@ const s32 hotbar_imagesize = 36;
 gui::IGUIEnvironment* guienv = NULL;\r
 gui::IGUIStaticText *guiroot = NULL;\r
 \r
-// Handler for the modal menus\r
-\r
-class MainMenuManager : public IMenuManager\r
-{\r
-public:\r
-       virtual void createdMenu(GUIModalMenu *menu)\r
-       {\r
-               for(core::list<GUIModalMenu*>::Iterator\r
-                               i = m_stack.begin();\r
-                               i != m_stack.end(); i++)\r
-               {\r
-                       assert(*i != menu);\r
-               }\r
-\r
-               if(m_stack.size() != 0)\r
-                       (*m_stack.getLast())->setVisible(false);\r
-               m_stack.push_back(menu);\r
-       }\r
-\r
-       virtual void deletingMenu(GUIModalMenu *menu)\r
-       {\r
-               // Remove all entries if there are duplicates\r
-               bool removed_entry;\r
-               do{\r
-                       removed_entry = false;\r
-                       for(core::list<GUIModalMenu*>::Iterator\r
-                                       i = m_stack.begin();\r
-                                       i != m_stack.end(); i++)\r
-                       {\r
-                               if(*i == menu)\r
-                               {\r
-                                       m_stack.erase(i);\r
-                                       removed_entry = true;\r
-                                       break;\r
-                               }\r
-                       }\r
-               }while(removed_entry);\r
-\r
-               /*core::list<GUIModalMenu*>::Iterator i = m_stack.getLast();\r
-               assert(*i == menu);\r
-               m_stack.erase(i);*/\r
-               \r
-               if(m_stack.size() != 0)\r
-                       (*m_stack.getLast())->setVisible(true);\r
-       }\r
-\r
-       u32 menuCount()\r
-       {\r
-               return m_stack.size();\r
-       }\r
-\r
-       core::list<GUIModalMenu*> m_stack;\r
-};\r
-\r
 MainMenuManager g_menumgr;\r
 \r
 bool noMenuActive()\r
@@ -419,39 +340,7 @@ bool noMenuActive()
 \r
 // Passed to menus to allow disconnecting and exiting\r
 \r
-class MainGameCallback : public IGameCallback\r
-{\r
-public:\r
-       MainGameCallback():\r
-               disconnect_requested(false)\r
-       {\r
-       }\r
-\r
-       virtual void exitToOS()\r
-       {\r
-               g_device->closeDevice();\r
-       }\r
-\r
-       virtual void disconnect()\r
-       {\r
-               disconnect_requested = true;\r
-       }\r
-\r
-       bool disconnect_requested;\r
-};\r
-\r
-MainGameCallback g_gamecallback;\r
-\r
-/*\r
-       Inventory stuff\r
-*/\r
-\r
-// Inventory actions from the menu are buffered here before sending\r
-Queue<InventoryAction*> inventory_action_queue;\r
-// This is a copy of the inventory that the client's environment has\r
-Inventory local_inventory;\r
-\r
-u16 g_selected_item = 0;\r
+MainGameCallback *g_gamecallback = NULL;\r
 \r
 /*\r
        Debug streams\r
@@ -477,96 +366,38 @@ std::ostream *derr_client_ptr = &dstream;
        gettime.h implementation\r
 */\r
 \r
-u32 getTimeMs()\r
-{\r
-       /*\r
-               Use irrlicht because it is more precise than porting.h's\r
-               getTimeMs()\r
-       */\r
-       if(g_device == NULL)\r
-               return 0;\r
-       return g_device->getTimer()->getRealTime();\r
-}\r
-\r
-/*\r
-       Text input system\r
-*/\r
-\r
-struct TextDestSign : public TextDest\r
+// A small helper class\r
+class TimeGetter\r
 {\r
-       TextDestSign(v3s16 blockpos, s16 id, Client *client)\r
-       {\r
-               m_blockpos = blockpos;\r
-               m_id = id;\r
-               m_client = client;\r
-       }\r
-       void gotText(std::wstring text)\r
+public:\r
+       TimeGetter(IrrlichtDevice *device):\r
+               m_device(device)\r
+       {}\r
+       u32 getTime()\r
        {\r
-               std::string ntext = wide_to_narrow(text);\r
-               dstream<<"Changing text of a sign object: "\r
-                               <<ntext<<std::endl;\r
-               m_client->sendSignText(m_blockpos, m_id, ntext);\r
+               if(m_device == NULL)\r
+                       return 0;\r
+               return m_device->getTimer()->getRealTime();\r
        }\r
-\r
-       v3s16 m_blockpos;\r
-       s16 m_id;\r
-       Client *m_client;\r
+private:\r
+       IrrlichtDevice *m_device;\r
 };\r
 \r
-struct TextDestChat : public TextDest\r
-{\r
-       TextDestChat(Client *client)\r
-       {\r
-               m_client = client;\r
-       }\r
-       void gotText(std::wstring text)\r
-       {\r
-               // Discard empty line\r
-               if(text == L"")\r
-                       return;\r
-               \r
-               // Parse command (server command starts with "/#")\r
-               if(text[0] == L'/' && text[1] != L'#')\r
-               {\r
-                       std::wstring reply = L"Local: ";\r
-\r
-                       reply += L"Local commands not yet supported. "\r
-                                       L"Server prefix is \"/#\".";\r
-                       \r
-                       m_client->addChatMessage(reply);\r
-                       return;\r
-               }\r
-\r
-               // Send to others\r
-               m_client->sendChatMessage(text);\r
-               // Show locally\r
-               m_client->addChatMessage(text);\r
-       }\r
-\r
-       Client *m_client;\r
-};\r
+// A pointer to a global instance of the time getter\r
+TimeGetter *g_timegetter = NULL;\r
 \r
-struct TextDestSignNode : public TextDest\r
+u32 getTimeMs()\r
 {\r
-       TextDestSignNode(v3s16 p, Client *client)\r
-       {\r
-               m_p = p;\r
-               m_client = client;\r
-       }\r
-       void gotText(std::wstring text)\r
-       {\r
-               std::string ntext = wide_to_narrow(text);\r
-               dstream<<"Changing text of a sign node: "\r
-                               <<ntext<<std::endl;\r
-               m_client->sendSignNodeText(m_p, ntext);\r
-       }\r
-\r
-       v3s16 m_p;\r
-       Client *m_client;\r
-};\r
+       if(g_timegetter == NULL)\r
+               return 0;\r
+       return g_timegetter->getTime();\r
+}\r
 \r
 /*\r
        Event handler for Irrlicht\r
+\r
+       NOTE: Everything possible should be moved out from here,\r
+             probably to InputHandler and the_game\r
 */\r
 \r
 class MyEventReceiver : public IEventReceiver\r
@@ -580,7 +411,6 @@ public:
                */\r
                if(noMenuActive() == false)\r
                {\r
-                       clearInput();\r
                        return false;\r
                }\r
 \r
@@ -590,120 +420,7 @@ public:
                        keyIsDown[event.KeyInput.Key] = event.KeyInput.PressedDown;\r
 \r
                        if(event.KeyInput.PressedDown)\r
-                       {\r
-                               //dstream<<"Pressed key: "<<(char)event.KeyInput.Key<<std::endl;\r
-                               /*if(g_show_map_plot)\r
-                               {\r
-                                       if(event.KeyInput.Key == irr::KEY_ESCAPE\r
-                                               || event.KeyInput.Key == irr::KEY_KEY_M)\r
-                                       {\r
-                                               g_show_map_plot = false;\r
-                                       }\r
-                                       return true;\r
-                               }*/\r
-                               \r
-                               /*\r
-                                       Launch menus\r
-                               */\r
-\r
-                               if(guienv != NULL && guiroot != NULL && g_device != NULL)\r
-                               {\r
-                                       if(event.KeyInput.Key == irr::KEY_ESCAPE)\r
-                                       {\r
-                                               dstream<<DTIME<<"MyEventReceiver: "\r
-                                                               <<"Launching pause menu"<<std::endl;\r
-                                               // It will delete itself by itself\r
-                                               (new GUIPauseMenu(guienv, guiroot, -1, &g_gamecallback,\r
-                                                               &g_menumgr))->drop();\r
-                                               return true;\r
-                                       }\r
-                                       if(event.KeyInput.Key == irr::KEY_KEY_I)\r
-                                       {\r
-                                               dstream<<DTIME<<"MyEventReceiver: "\r
-                                                               <<"Launching inventory"<<std::endl;\r
-                                               \r
-                                               GUIInventoryMenu *menu =\r
-                                                       new GUIInventoryMenu(guienv, guiroot, -1,\r
-                                                               &g_menumgr, v2s16(8,7),\r
-                                                               g_client->getInventoryContext(),\r
-                                                               g_client);\r
-\r
-                                               core::array<GUIInventoryMenu::DrawSpec> draw_spec;\r
-                                               draw_spec.push_back(GUIInventoryMenu::DrawSpec(\r
-                                                               "list", "current_player", "main",\r
-                                                               v2s32(0, 3), v2s32(8, 4)));\r
-                                               draw_spec.push_back(GUIInventoryMenu::DrawSpec(\r
-                                                               "list", "current_player", "craft",\r
-                                                               v2s32(3, 0), v2s32(3, 3)));\r
-                                               draw_spec.push_back(GUIInventoryMenu::DrawSpec(\r
-                                                               "list", "current_player", "craftresult",\r
-                                                               v2s32(7, 1), v2s32(1, 1)));\r
-\r
-                                               menu->setDrawSpec(draw_spec);\r
-\r
-                                               menu->drop();\r
-\r
-                                               return true;\r
-                                       }\r
-                                       if(event.KeyInput.Key == irr::KEY_KEY_T)\r
-                                       {\r
-                                               TextDest *dest = new TextDestChat(g_client);\r
-\r
-                                               (new GUITextInputMenu(guienv, guiroot, -1,\r
-                                                               &g_menumgr, dest,\r
-                                                               L""))->drop();\r
-                                       }\r
-                               }\r
-\r
-                               // Item selection\r
-                               if(event.KeyInput.Key >= irr::KEY_KEY_0\r
-                                               && event.KeyInput.Key <= irr::KEY_KEY_9)\r
-                               {\r
-                                       u16 s1 = event.KeyInput.Key - irr::KEY_KEY_0;\r
-                                       if(event.KeyInput.Key == irr::KEY_KEY_0)\r
-                                               s1 = 10;\r
-                                       if(s1 < PLAYER_INVENTORY_SIZE && s1 < hotbar_itemcount)\r
-                                               g_selected_item = s1-1;\r
-                                       dstream<<DTIME<<"Selected item: "\r
-                                                       <<g_selected_item<<std::endl;\r
-                               }\r
-\r
-                               // Viewing range selection\r
-                               if(event.KeyInput.Key == irr::KEY_KEY_R)\r
-                               {\r
-                                       if(draw_control.range_all)\r
-                                       {\r
-                                               draw_control.range_all = false;\r
-                                               dstream<<DTIME<<"Disabled full viewing range"<<std::endl;\r
-                                       }\r
-                                       else\r
-                                       {\r
-                                               draw_control.range_all = true;\r
-                                               dstream<<DTIME<<"Enabled full viewing range"<<std::endl;\r
-                                       }\r
-                               }\r
-\r
-                               // Print debug stacks\r
-                               if(event.KeyInput.Key == irr::KEY_KEY_P)\r
-                               {\r
-                                       dstream<<"-----------------------------------------"\r
-                                                       <<std::endl;\r
-                                       dstream<<DTIME<<"Printing debug stacks:"<<std::endl;\r
-                                       dstream<<"-----------------------------------------"\r
-                                                       <<std::endl;\r
-                                       debug_stacks_print();\r
-                               }\r
-\r
-                               // Map plot\r
-                               /*if(event.KeyInput.Key == irr::KEY_KEY_M)\r
-                               {\r
-                                       dstream<<"Map plot requested"<<std::endl;\r
-                                       g_show_map_plot = !g_show_map_plot;\r
-                                       if(g_show_map_plot)\r
-                                               g_refresh_map_plot = true;\r
-                               }*/\r
-                               \r
-                       }\r
+                               keyWasDown[event.KeyInput.Key] = true;\r
                }\r
 \r
                if(event.EventType == irr::EET_MOUSE_INPUT_EVENT)\r
@@ -739,25 +456,7 @@ public:
                                }\r
                                if(event.MouseInput.Event == EMIE_MOUSE_WHEEL)\r
                                {\r
-                                       /*dstream<<"event.MouseInput.Wheel="\r
-                                                       <<event.MouseInput.Wheel<<std::endl;*/\r
-                                       \r
-                                       u16 max_item = MYMIN(PLAYER_INVENTORY_SIZE-1,\r
-                                                       hotbar_itemcount-1);\r
-                                       if(event.MouseInput.Wheel < 0)\r
-                                       {\r
-                                               if(g_selected_item < max_item)\r
-                                                       g_selected_item++;\r
-                                               else\r
-                                                       g_selected_item = 0;\r
-                                       }\r
-                                       else if(event.MouseInput.Wheel > 0)\r
-                                       {\r
-                                               if(g_selected_item > 0)\r
-                                                       g_selected_item--;\r
-                                               else\r
-                                                       g_selected_item = max_item;\r
-                                       }\r
+                                       mouse_wheel += event.MouseInput.Wheel;\r
                                }\r
                        }\r
                }\r
@@ -765,16 +464,33 @@ public:
                return false;\r
        }\r
 \r
-       // This is used to check whether a key is being held down\r
-       virtual bool IsKeyDown(EKEY_CODE keyCode) const\r
+       bool IsKeyDown(EKEY_CODE keyCode) const\r
        {\r
                return keyIsDown[keyCode];\r
        }\r
+       \r
+       // Checks whether a key was down and resets the state\r
+       bool WasKeyDown(EKEY_CODE keyCode)\r
+       {\r
+               bool b = keyWasDown[keyCode];\r
+               keyWasDown[keyCode] = false;\r
+               return b;\r
+       }\r
+\r
+       s32 getMouseWheel()\r
+       {\r
+               s32 a = mouse_wheel;\r
+               mouse_wheel = 0;\r
+               return a;\r
+       }\r
 \r
        void clearInput()\r
        {\r
-               for (u32 i=0; i<KEY_KEY_CODES_COUNT; ++i)\r
-                               keyIsDown[i] = false;\r
+               for(u32 i=0; i<KEY_KEY_CODES_COUNT; i++)\r
+               {\r
+                       keyIsDown[i] = false;\r
+                       keyWasDown[i] = false;\r
+               }\r
                \r
                leftclicked = false;\r
                rightclicked = false;\r
@@ -784,6 +500,8 @@ public:
                left_active = false;\r
                middle_active = false;\r
                right_active = false;\r
+\r
+               mouse_wheel = 0;\r
        }\r
 \r
        MyEventReceiver()\r
@@ -800,53 +518,21 @@ public:
        bool middle_active;\r
        bool right_active;\r
 \r
+       s32 mouse_wheel;\r
+\r
 private:\r
-       // We use this array to store the current state of each key\r
-       bool keyIsDown[KEY_KEY_CODES_COUNT];\r
-       //s32 mouseX;\r
-       //s32 mouseY;\r
        IrrlichtDevice *m_device;\r
+       \r
+       // The current state of keys\r
+       bool keyIsDown[KEY_KEY_CODES_COUNT];\r
+       // Whether a key has been pressed or not\r
+       bool keyWasDown[KEY_KEY_CODES_COUNT];\r
 };\r
 \r
 /*\r
        Separated input handler\r
 */\r
 \r
-class InputHandler\r
-{\r
-public:\r
-       InputHandler()\r
-       {\r
-       }\r
-       virtual ~InputHandler()\r
-       {\r
-       }\r
-\r
-       virtual bool isKeyDown(EKEY_CODE keyCode) = 0;\r
-\r
-       virtual v2s32 getMousePos() = 0;\r
-       virtual void setMousePos(s32 x, s32 y) = 0;\r
-\r
-       virtual bool getLeftState() = 0;\r
-       virtual bool getRightState() = 0;\r
-\r
-       virtual bool getLeftClicked() = 0;\r
-       virtual bool getRightClicked() = 0;\r
-       virtual void resetLeftClicked() = 0;\r
-       virtual void resetRightClicked() = 0;\r
-\r
-       virtual bool getLeftReleased() = 0;\r
-       virtual bool getRightReleased() = 0;\r
-       virtual void resetLeftReleased() = 0;\r
-       virtual void resetRightReleased() = 0;\r
-       \r
-       virtual void step(float dtime) {};\r
-\r
-       virtual void clear() {};\r
-};\r
-\r
-InputHandler *g_input = NULL;\r
-\r
 class RealInputHandler : public InputHandler\r
 {\r
 public:\r
@@ -859,6 +545,10 @@ public:
        {\r
                return m_receiver->IsKeyDown(keyCode);\r
        }\r
+       virtual bool wasKeyDown(EKEY_CODE keyCode)\r
+       {\r
+               return m_receiver->WasKeyDown(keyCode);\r
+       }\r
        virtual v2s32 getMousePos()\r
        {\r
                return m_device->getCursorControl()->getPosition();\r
@@ -911,10 +601,14 @@ public:
                m_receiver->rightreleased = false;\r
        }\r
 \r
+       virtual s32 getMouseWheel()\r
+       {\r
+               return m_receiver->getMouseWheel();\r
+       }\r
+\r
        void clear()\r
        {\r
-               resetRightClicked();\r
-               resetLeftClicked();\r
+               m_receiver->clearInput();\r
        }\r
 private:\r
        IrrlichtDevice *m_device;\r
@@ -939,6 +633,10 @@ public:
        {\r
                return keydown[keyCode];\r
        }\r
+       virtual bool wasKeyDown(EKEY_CODE keyCode)\r
+       {\r
+               return false;\r
+       }\r
        virtual v2s32 getMousePos()\r
        {\r
                return mousepos;\r
@@ -991,6 +689,11 @@ public:
                rightreleased = false;\r
        }\r
 \r
+       virtual s32 getMouseWheel()\r
+       {\r
+               return 0;\r
+       }\r
+\r
        virtual void step(float dtime)\r
        {\r
                {\r
@@ -1083,248 +786,6 @@ private:
        bool rightreleased;\r
 };\r
 \r
-/*\r
-       Render distance feedback loop\r
-*/\r
-\r
-void updateViewingRange(f32 frametime_in, Client *client)\r
-{\r
-       if(draw_control.range_all == true)\r
-               return;\r
-       \r
-       static f32 added_frametime = 0;\r
-       static s16 added_frames = 0;\r
-\r
-       added_frametime += frametime_in;\r
-       added_frames += 1;\r
-\r
-       // Actually this counter kind of sucks because frametime is busytime\r
-       static f32 counter = 0;\r
-       counter -= frametime_in;\r
-       if(counter > 0)\r
-               return;\r
-       //counter = 0.1;\r
-       counter = 0.2;\r
-\r
-       /*dstream<<__FUNCTION_NAME\r
-                       <<": Collected "<<added_frames<<" frames, total of "\r
-                       <<added_frametime<<"s."<<std::endl;*/\r
-       \r
-       /*dstream<<"draw_control.blocks_drawn="\r
-                       <<draw_control.blocks_drawn\r
-                       <<", draw_control.blocks_would_have_drawn="\r
-                       <<draw_control.blocks_would_have_drawn\r
-                       <<std::endl;*/\r
-       \r
-       float range_min = g_settings.getS16("viewing_range_nodes_min");\r
-       float range_max = g_settings.getS16("viewing_range_nodes_max");\r
-       \r
-       draw_control.wanted_min_range = range_min;\r
-       draw_control.wanted_max_blocks = (1.2*draw_control.blocks_drawn)+1;\r
-       \r
-       float block_draw_ratio = 1.0;\r
-       if(draw_control.blocks_would_have_drawn != 0)\r
-       {\r
-               block_draw_ratio = (float)draw_control.blocks_drawn\r
-                       / (float)draw_control.blocks_would_have_drawn;\r
-       }\r
-\r
-       // Calculate the average frametime in the case that all wanted\r
-       // blocks had been drawn\r
-       f32 frametime = added_frametime / added_frames / block_draw_ratio;\r
-       \r
-       added_frametime = 0.0;\r
-       added_frames = 0;\r
-       \r
-       float wanted_fps = g_settings.getFloat("wanted_fps");\r
-       float wanted_frametime = 1.0 / wanted_fps;\r
-       \r
-       f32 wanted_frametime_change = wanted_frametime - frametime;\r
-       //dstream<<"wanted_frametime_change="<<wanted_frametime_change<<std::endl;\r
-       \r
-       // If needed frametime change is small, just return\r
-       if(fabs(wanted_frametime_change) < wanted_frametime*0.4)\r
-       {\r
-               //dstream<<"ignoring small wanted_frametime_change"<<std::endl;\r
-               return;\r
-       }\r
-\r
-       float range = draw_control.wanted_range;\r
-       float new_range = range;\r
-\r
-       static s16 range_old = 0;\r
-       static f32 frametime_old = 0;\r
-       \r
-       float d_range = range - range_old;\r
-       f32 d_frametime = frametime - frametime_old;\r
-       // A sane default of 30ms per 50 nodes of range\r
-       static f32 time_per_range = 30. / 50;\r
-       if(d_range != 0)\r
-       {\r
-               time_per_range = d_frametime / d_range;\r
-       }\r
-       \r
-       // The minimum allowed calculated frametime-range derivative:\r
-       // Practically this sets the maximum speed of changing the range.\r
-       // The lower this value, the higher the maximum changing speed.\r
-       // A low value here results in wobbly range (0.001)\r
-       // A high value here results in slow changing range (0.0025)\r
-       // SUGG: This could be dynamically adjusted so that when\r
-       //       the camera is turning, this is lower\r
-       //float min_time_per_range = 0.0015;\r
-       float min_time_per_range = 0.0010;\r
-       //float min_time_per_range = 0.05 / range;\r
-       if(time_per_range < min_time_per_range)\r
-       {\r
-               time_per_range = min_time_per_range;\r
-               //dstream<<"time_per_range="<<time_per_range<<" (min)"<<std::endl;\r
-       }\r
-       else\r
-       {\r
-               //dstream<<"time_per_range="<<time_per_range<<std::endl;\r
-       }\r
-\r
-       f32 wanted_range_change = wanted_frametime_change / time_per_range;\r
-       // Dampen the change a bit to kill oscillations\r
-       //wanted_range_change *= 0.9;\r
-       //wanted_range_change *= 0.75;\r
-       wanted_range_change *= 0.5;\r
-       //dstream<<"wanted_range_change="<<wanted_range_change<<std::endl;\r
-\r
-       // If needed range change is very small, just return\r
-       if(fabs(wanted_range_change) < 0.001)\r
-       {\r
-               //dstream<<"ignoring small wanted_range_change"<<std::endl;\r
-               return;\r
-       }\r
-\r
-       new_range += wanted_range_change;\r
-       //dstream<<"new_range="<<new_range/*<<std::endl*/;\r
-       \r
-       //float new_range_unclamped = new_range;\r
-       if(new_range < range_min)\r
-               new_range = range_min;\r
-       if(new_range > range_max)\r
-               new_range = range_max;\r
-       \r
-       /*if(new_range != new_range_unclamped)\r
-               dstream<<", clamped to "<<new_range<<std::endl;\r
-       else\r
-               dstream<<std::endl;*/\r
-\r
-       draw_control.wanted_range = new_range;\r
-\r
-       range_old = new_range;\r
-       frametime_old = frametime;\r
-}\r
-\r
-/*\r
-       Hotbar draw routine\r
-*/\r
-\r
-void draw_hotbar(video::IVideoDriver *driver, gui::IGUIFont *font,\r
-               v2s32 centerlowerpos, s32 imgsize, s32 itemcount,\r
-               Inventory *inventory, s32 halfheartcount)\r
-{\r
-       InventoryList *mainlist = inventory->getList("main");\r
-       if(mainlist == NULL)\r
-       {\r
-               dstream<<"WARNING: draw_hotbar(): mainlist == NULL"<<std::endl;\r
-               return;\r
-       }\r
-       \r
-       s32 padding = imgsize/12;\r
-       //s32 height = imgsize + padding*2;\r
-       s32 width = itemcount*(imgsize+padding*2);\r
-       \r
-       // Position of upper left corner of bar\r
-       v2s32 pos = centerlowerpos - v2s32(width/2, imgsize+padding*2);\r
-       \r
-       // Draw background color\r
-       /*core::rect<s32> barrect(0,0,width,height);\r
-       barrect += pos;\r
-       video::SColor bgcolor(255,128,128,128);\r
-       driver->draw2DRectangle(bgcolor, barrect, NULL);*/\r
-\r
-       core::rect<s32> imgrect(0,0,imgsize,imgsize);\r
-\r
-       for(s32 i=0; i<itemcount; i++)\r
-       {\r
-               InventoryItem *item = mainlist->getItem(i);\r
-               \r
-               core::rect<s32> rect = imgrect + pos\r
-                               + v2s32(padding+i*(imgsize+padding*2), padding);\r
-               \r
-               if(g_selected_item == i)\r
-               {\r
-                       driver->draw2DRectangle(video::SColor(255,255,0,0),\r
-                                       core::rect<s32>(rect.UpperLeftCorner - v2s32(1,1)*padding,\r
-                                                       rect.LowerRightCorner + v2s32(1,1)*padding),\r
-                                       NULL);\r
-               }\r
-               else\r
-               {\r
-                       video::SColor bgcolor2(128,0,0,0);\r
-                       driver->draw2DRectangle(bgcolor2, rect, NULL);\r
-               }\r
-\r
-               if(item != NULL)\r
-               {\r
-                       drawInventoryItem(driver, font, item, rect, NULL);\r
-               }\r
-       }\r
-       \r
-       /*\r
-               Draw hearts\r
-       */\r
-       {\r
-               video::ITexture *heart_texture =\r
-                               driver->getTexture(porting::getDataPath("heart.png").c_str());\r
-               v2s32 p = pos + v2s32(0, -20);\r
-               for(s32 i=0; i<halfheartcount/2; i++)\r
-               {\r
-                       const video::SColor color(255,255,255,255);\r
-                       const video::SColor colors[] = {color,color,color,color};\r
-                       core::rect<s32> rect(0,0,16,16);\r
-                       rect += p;\r
-                       driver->draw2DImage(heart_texture, rect,\r
-                               core::rect<s32>(core::position2d<s32>(0,0),\r
-                               core::dimension2di(heart_texture->getOriginalSize())),\r
-                               NULL, colors, true);\r
-                       p += v2s32(20,0);\r
-               }\r
-               if(halfheartcount % 2 == 1)\r
-               {\r
-                       const video::SColor color(255,255,255,255);\r
-                       const video::SColor colors[] = {color,color,color,color};\r
-                       core::rect<s32> rect(0,0,16/2,16);\r
-                       rect += p;\r
-                       core::dimension2di srcd(heart_texture->getOriginalSize());\r
-                       srcd.Width /= 2;\r
-                       driver->draw2DImage(heart_texture, rect,\r
-                               core::rect<s32>(core::position2d<s32>(0,0), srcd),\r
-                               NULL, colors, true);\r
-                       p += v2s32(20,0);\r
-               }\r
-       }\r
-}\r
-\r
-// Chat data\r
-struct ChatLine\r
-{\r
-       ChatLine():\r
-               age(0.0)\r
-       {\r
-       }\r
-       ChatLine(const std::wstring &a_text):\r
-               age(0.0),\r
-               text(a_text)\r
-       {\r
-       }\r
-       float age;\r
-       std::wstring text;\r
-};\r
-\r
 // These are defined global so that they're not optimized too much.\r
 // Can't change them to volatile.\r
 s16 temp16;\r
@@ -1423,240 +884,31 @@ void SpeedTests()
        }\r
 }\r
 \r
-void getPointedNode(v3f player_position,\r
-               v3f camera_direction, v3f camera_position,\r
-               bool &nodefound, core::line3d<f32> shootline,\r
-               v3s16 &nodepos, v3s16 &neighbourpos,\r
-               core::aabbox3d<f32> &nodehilightbox,\r
-               f32 d)\r
+int main(int argc, char *argv[])\r
 {\r
-       assert(g_client);\r
+       /*\r
+               Parse command line\r
+       */\r
+       \r
+       // List all allowed options\r
+       core::map<std::string, ValueSpec> allowed_options;\r
+       allowed_options.insert("help", ValueSpec(VALUETYPE_FLAG));\r
+       allowed_options.insert("server", ValueSpec(VALUETYPE_FLAG,\r
+                       "Run server directly"));\r
+       allowed_options.insert("config", ValueSpec(VALUETYPE_STRING,\r
+                       "Load configuration from specified file"));\r
+       allowed_options.insert("port", ValueSpec(VALUETYPE_STRING));\r
+       allowed_options.insert("address", ValueSpec(VALUETYPE_STRING));\r
+       allowed_options.insert("random-input", ValueSpec(VALUETYPE_FLAG));\r
+       allowed_options.insert("disable-unittests", ValueSpec(VALUETYPE_FLAG));\r
+       allowed_options.insert("enable-unittests", ValueSpec(VALUETYPE_FLAG));\r
+       allowed_options.insert("map-dir", ValueSpec(VALUETYPE_STRING));\r
+#ifdef _WIN32\r
+       allowed_options.insert("dstream-on-stderr", ValueSpec(VALUETYPE_FLAG));\r
+#endif\r
+       allowed_options.insert("speedtests", ValueSpec(VALUETYPE_FLAG));\r
 \r
-       f32 mindistance = BS * 1001;\r
-       \r
-       v3s16 pos_i = floatToInt(player_position, BS);\r
-\r
-       /*std::cout<<"pos_i=("<<pos_i.X<<","<<pos_i.Y<<","<<pos_i.Z<<")"\r
-                       <<std::endl;*/\r
-\r
-       s16 a = d;\r
-       s16 ystart = pos_i.Y + 0 - (camera_direction.Y<0 ? a : 1);\r
-       s16 zstart = pos_i.Z - (camera_direction.Z<0 ? a : 1);\r
-       s16 xstart = pos_i.X - (camera_direction.X<0 ? a : 1);\r
-       s16 yend = pos_i.Y + 1 + (camera_direction.Y>0 ? a : 1);\r
-       s16 zend = pos_i.Z + (camera_direction.Z>0 ? a : 1);\r
-       s16 xend = pos_i.X + (camera_direction.X>0 ? a : 1);\r
-       \r
-       for(s16 y = ystart; y <= yend; y++)\r
-       for(s16 z = zstart; z <= zend; z++)\r
-       for(s16 x = xstart; x <= xend; x++)\r
-       {\r
-               MapNode n;\r
-               try\r
-               {\r
-                       n = g_client->getNode(v3s16(x,y,z));\r
-                       if(content_pointable(n.d) == false)\r
-                               continue;\r
-               }\r
-               catch(InvalidPositionException &e)\r
-               {\r
-                       continue;\r
-               }\r
-\r
-               v3s16 np(x,y,z);\r
-               v3f npf = intToFloat(np, BS);\r
-               \r
-               f32 d = 0.01;\r
-               \r
-               v3s16 dirs[6] = {\r
-                       v3s16(0,0,1), // back\r
-                       v3s16(0,1,0), // top\r
-                       v3s16(1,0,0), // right\r
-                       v3s16(0,0,-1), // front\r
-                       v3s16(0,-1,0), // bottom\r
-                       v3s16(-1,0,0), // left\r
-               };\r
-               \r
-               /*\r
-                       Meta-objects\r
-               */\r
-               if(n.d == CONTENT_TORCH)\r
-               {\r
-                       v3s16 dir = unpackDir(n.dir);\r
-                       v3f dir_f = v3f(dir.X, dir.Y, dir.Z);\r
-                       dir_f *= BS/2 - BS/6 - BS/20;\r
-                       v3f cpf = npf + dir_f;\r
-                       f32 distance = (cpf - camera_position).getLength();\r
-\r
-                       core::aabbox3d<f32> box;\r
-                       \r
-                       // bottom\r
-                       if(dir == v3s16(0,-1,0))\r
-                       {\r
-                               box = core::aabbox3d<f32>(\r
-                                       npf - v3f(BS/6, BS/2, BS/6),\r
-                                       npf + v3f(BS/6, -BS/2+BS/3*2, BS/6)\r
-                               );\r
-                       }\r
-                       // top\r
-                       else if(dir == v3s16(0,1,0))\r
-                       {\r
-                               box = core::aabbox3d<f32>(\r
-                                       npf - v3f(BS/6, -BS/2+BS/3*2, BS/6),\r
-                                       npf + v3f(BS/6, BS/2, BS/6)\r
-                               );\r
-                       }\r
-                       // side\r
-                       else\r
-                       {\r
-                               box = core::aabbox3d<f32>(\r
-                                       cpf - v3f(BS/6, BS/3, BS/6),\r
-                                       cpf + v3f(BS/6, BS/3, BS/6)\r
-                               );\r
-                       }\r
-\r
-                       if(distance < mindistance)\r
-                       {\r
-                               if(box.intersectsWithLine(shootline))\r
-                               {\r
-                                       nodefound = true;\r
-                                       nodepos = np;\r
-                                       neighbourpos = np;\r
-                                       mindistance = distance;\r
-                                       nodehilightbox = box;\r
-                               }\r
-                       }\r
-               }\r
-               else if(n.d == CONTENT_SIGN_WALL)\r
-               {\r
-                       v3s16 dir = unpackDir(n.dir);\r
-                       v3f dir_f = v3f(dir.X, dir.Y, dir.Z);\r
-                       dir_f *= BS/2 - BS/6 - BS/20;\r
-                       v3f cpf = npf + dir_f;\r
-                       f32 distance = (cpf - camera_position).getLength();\r
-\r
-                       v3f vertices[4] =\r
-                       {\r
-                               v3f(BS*0.42,-BS*0.35,-BS*0.4),\r
-                               v3f(BS*0.49, BS*0.35, BS*0.4),\r
-                       };\r
-\r
-                       for(s32 i=0; i<2; i++)\r
-                       {\r
-                               if(dir == v3s16(1,0,0))\r
-                                       vertices[i].rotateXZBy(0);\r
-                               if(dir == v3s16(-1,0,0))\r
-                                       vertices[i].rotateXZBy(180);\r
-                               if(dir == v3s16(0,0,1))\r
-                                       vertices[i].rotateXZBy(90);\r
-                               if(dir == v3s16(0,0,-1))\r
-                                       vertices[i].rotateXZBy(-90);\r
-                               if(dir == v3s16(0,-1,0))\r
-                                       vertices[i].rotateXYBy(-90);\r
-                               if(dir == v3s16(0,1,0))\r
-                                       vertices[i].rotateXYBy(90);\r
-\r
-                               vertices[i] += npf;\r
-                       }\r
-\r
-                       core::aabbox3d<f32> box;\r
-\r
-                       box = core::aabbox3d<f32>(vertices[0]);\r
-                       box.addInternalPoint(vertices[1]);\r
-\r
-                       if(distance < mindistance)\r
-                       {\r
-                               if(box.intersectsWithLine(shootline))\r
-                               {\r
-                                       nodefound = true;\r
-                                       nodepos = np;\r
-                                       neighbourpos = np;\r
-                                       mindistance = distance;\r
-                                       nodehilightbox = box;\r
-                               }\r
-                       }\r
-               }\r
-               /*\r
-                       Regular blocks\r
-               */\r
-               else\r
-               {\r
-                       for(u16 i=0; i<6; i++)\r
-                       {\r
-                               v3f dir_f = v3f(dirs[i].X,\r
-                                               dirs[i].Y, dirs[i].Z);\r
-                               v3f centerpoint = npf + dir_f * BS/2;\r
-                               f32 distance =\r
-                                               (centerpoint - camera_position).getLength();\r
-                               \r
-                               if(distance < mindistance)\r
-                               {\r
-                                       core::CMatrix4<f32> m;\r
-                                       m.buildRotateFromTo(v3f(0,0,1), dir_f);\r
-\r
-                                       // This is the back face\r
-                                       v3f corners[2] = {\r
-                                               v3f(BS/2, BS/2, BS/2),\r
-                                               v3f(-BS/2, -BS/2, BS/2+d)\r
-                                       };\r
-                                       \r
-                                       for(u16 j=0; j<2; j++)\r
-                                       {\r
-                                               m.rotateVect(corners[j]);\r
-                                               corners[j] += npf;\r
-                                       }\r
-\r
-                                       core::aabbox3d<f32> facebox(corners[0]);\r
-                                       facebox.addInternalPoint(corners[1]);\r
-\r
-                                       if(facebox.intersectsWithLine(shootline))\r
-                                       {\r
-                                               nodefound = true;\r
-                                               nodepos = np;\r
-                                               neighbourpos = np + dirs[i];\r
-                                               mindistance = distance;\r
-\r
-                                               //nodehilightbox = facebox;\r
-\r
-                                               const float d = 0.502;\r
-                                               core::aabbox3d<f32> nodebox\r
-                                                               (-BS*d, -BS*d, -BS*d, BS*d, BS*d, BS*d);\r
-                                               v3f nodepos_f = intToFloat(nodepos, BS);\r
-                                               nodebox.MinEdge += nodepos_f;\r
-                                               nodebox.MaxEdge += nodepos_f;\r
-                                               nodehilightbox = nodebox;\r
-                                       }\r
-                               } // if distance < mindistance\r
-                       } // for dirs\r
-               } // regular block\r
-       } // for coords\r
-}\r
-\r
-int main(int argc, char *argv[])\r
-{\r
-       /*\r
-               Parse command line\r
-       */\r
-       \r
-       // List all allowed options\r
-       core::map<std::string, ValueSpec> allowed_options;\r
-       allowed_options.insert("help", ValueSpec(VALUETYPE_FLAG));\r
-       allowed_options.insert("server", ValueSpec(VALUETYPE_FLAG,\r
-                       "Run server directly"));\r
-       allowed_options.insert("config", ValueSpec(VALUETYPE_STRING,\r
-                       "Load configuration from specified file"));\r
-       allowed_options.insert("port", ValueSpec(VALUETYPE_STRING));\r
-       allowed_options.insert("address", ValueSpec(VALUETYPE_STRING));\r
-       allowed_options.insert("random-input", ValueSpec(VALUETYPE_FLAG));\r
-       allowed_options.insert("disable-unittests", ValueSpec(VALUETYPE_FLAG));\r
-       allowed_options.insert("enable-unittests", ValueSpec(VALUETYPE_FLAG));\r
-       allowed_options.insert("map-dir", ValueSpec(VALUETYPE_STRING));\r
-#ifdef _WIN32\r
-       allowed_options.insert("dstream-on-stderr", ValueSpec(VALUETYPE_FLAG));\r
-#endif\r
-       allowed_options.insert("speedtests", ValueSpec(VALUETYPE_FLAG));\r
-\r
-       Settings cmd_args;\r
+       Settings cmd_args;\r
        \r
        bool ret = cmd_args.parseCommandLine(argc, argv, allowed_options);\r
 \r
@@ -1815,7 +1067,7 @@ int main(int argc, char *argv[])
        return 0;*/\r
        \r
        /*\r
-               Some parameters\r
+               Game parameters\r
        */\r
 \r
        // Port\r
@@ -1865,6 +1117,10 @@ int main(int argc, char *argv[])
        \r
        std::string playername = g_settings.get("name");\r
 \r
+       /*\r
+               Device initialization\r
+       */\r
+\r
        // Resolution selection\r
        \r
        bool fullscreen = false;\r
@@ -1896,7 +1152,9 @@ int main(int argc, char *argv[])
                driverType = video::EDT_OPENGL;\r
        }\r
 \r
-       // create device and exit if creation failed\r
+       /*\r
+               Create device and exit if creation failed\r
+       */\r
 \r
        MyEventReceiver receiver;\r
 \r
@@ -1908,9 +1166,17 @@ int main(int argc, char *argv[])
        if (device == 0)\r
                return 1; // could not create selected driver.\r
        \r
-       g_device = device;\r
-       TextureSource *texturesource = new TextureSource(device);\r
-       g_texturesource = texturesource;\r
+       // Set device in game parameters\r
+       device = device;\r
+       \r
+       // Create time getter\r
+       g_timegetter = new TimeGetter(device);\r
+       \r
+       // Create game callback for menus\r
+       g_gamecallback = new MainGameCallback(device);\r
+       \r
+       // Create texture source\r
+       g_texturesource = new TextureSource(device);\r
 \r
        /*\r
                Speed tests (done after irrlicht is loaded to get timer)\r
@@ -1926,16 +1192,17 @@ int main(int argc, char *argv[])
 \r
        bool random_input = g_settings.getBool("random_input")\r
                        || cmd_args.getFlag("random-input");\r
+       InputHandler *input = NULL;\r
        if(random_input)\r
-               g_input = new RandomInputHandler();\r
+               input = new RandomInputHandler();\r
        else\r
-               g_input = new RealInputHandler(device, &receiver);\r
+               input = new RealInputHandler(device, &receiver);\r
        \r
        /*\r
                Continue initialization\r
        */\r
 \r
-       video::IVideoDriver* driver = device->getVideoDriver();\r
+       //video::IVideoDriver* driver = device->getVideoDriver();\r
 \r
        /*\r
                This changes the minimum allowed number of vertices in a VBO.\r
@@ -1956,7 +1223,7 @@ int main(int argc, char *argv[])
        // If font was not found, this will get us one\r
        font = skin->getFont();\r
        assert(font);\r
-\r
+       \r
        u32 text_height = font->getDimension(L"Hello, world!").Height;\r
        dstream<<"text_height="<<text_height<<std::endl;\r
 \r
@@ -1979,1453 +1246,172 @@ int main(int argc, char *argv[])
                GUI stuff\r
        */\r
 \r
-       /*\r
-               We need some kind of a root node to be able to add\r
-               custom gui elements directly on the screen.\r
-               Otherwise they won't be automatically drawn.\r
-       */\r
-       guiroot = guienv->addStaticText(L"",\r
-                       core::rect<s32>(0, 0, 10000, 10000));\r
-       \r
-       // First line of debug text\r
-       gui::IGUIStaticText *guitext = guienv->addStaticText(\r
-                       L"",\r
-                       core::rect<s32>(5, 5, 795, 5+text_height),\r
-                       false, false);\r
-       // Second line of debug text\r
-       gui::IGUIStaticText *guitext2 = guienv->addStaticText(\r
-                       L"",\r
-                       core::rect<s32>(5, 5+(text_height+5)*1, 795, (5+text_height)*2),\r
-                       false, false);\r
-       \r
-       // At the middle of the screen\r
-       // Object infos are shown in this\r
-       gui::IGUIStaticText *guitext_info = guienv->addStaticText(\r
-                       L"",\r
-                       core::rect<s32>(0,0,400,text_height+5) + v2s32(100,200),\r
-                       false, false);\r
-       \r
-       // Chat text\r
-       gui::IGUIStaticText *guitext_chat = guienv->addStaticText(\r
-                       L"",\r
-                       core::rect<s32>(0,0,0,0),\r
-                       false, false); // Disable word wrap as of now\r
-                       //false, true);\r
-       //guitext_chat->setBackgroundColor(video::SColor(96,0,0,0));\r
-       core::list<ChatLine> chat_lines;\r
-       \r
-       /*\r
-               If an error occurs, this is set to something and the\r
-               menu-game loop is restarted. It is then displayed before\r
-               the menu.\r
-       */\r
-       std::wstring error_message = L"";\r
-       \r
        /*\r
                Menu-game loop\r
        */\r
-       while(g_device->run() && kill == false)\r
-       {\r
-       \r
-       // This is used for catching disconnects\r
-       try\r
-       {\r
-       \r
-       /*\r
-               Out-of-game menu loop.\r
-\r
-               Loop quits when menu returns proper parameters.\r
-       */\r
-       while(kill == false)\r
+       while(device->run() && kill == false)\r
        {\r
-               // Cursor can be non-visible when coming from the game\r
-               device->getCursorControl()->setVisible(true);\r
-               // Some stuff are left to scene manager when coming from the game\r
-               // (map at least?)\r
-               smgr->clear();\r
-               // Reset or hide the debug gui texts\r
-               guitext->setText(L"Minetest-c55");\r
-               guitext2->setVisible(false);\r
-               guitext_info->setVisible(false);\r
-               guitext_chat->setVisible(false);\r
-               \r
-               // Initialize menu data\r
-               MainMenuData menudata;\r
-               menudata.address = narrow_to_wide(address);\r
-               menudata.name = narrow_to_wide(playername);\r
-               menudata.port = narrow_to_wide(itos(port));\r
-               menudata.creative_mode = g_settings.getBool("creative_mode");\r
-\r
-               GUIMainMenu *menu =\r
-                               new GUIMainMenu(guienv, guiroot, -1, \r
-                                       &g_menumgr, &menudata, &g_gamecallback);\r
-               menu->allowFocusRemoval(true);\r
-\r
-               if(error_message != L"")\r
-               {\r
-                       GUIMessageMenu *menu2 =\r
-                                       new GUIMessageMenu(guienv, guiroot, -1, \r
-                                               &g_menumgr, error_message.c_str());\r
-                       menu2->drop();\r
-                       error_message = L"";\r
-               }\r
-\r
-               video::IVideoDriver* driver = g_device->getVideoDriver();\r
-               \r
-               dstream<<"Created main menu"<<std::endl;\r
-\r
-               while(g_device->run() && kill == false)\r
-               {\r
-                       if(menu->getStatus() == true)\r
-                               break;\r
-\r
-                       //driver->beginScene(true, true, video::SColor(255,0,0,0));\r
-                       driver->beginScene(true, true, video::SColor(255,128,128,128));\r
-                       guienv->drawAll();\r
-                       driver->endScene();\r
-               }\r
-               \r
-               // Break out of menu-game loop to shut down cleanly\r
-               if(g_device->run() == false || kill == true)\r
-                       break;\r
-               \r
-               dstream<<"Dropping main menu"<<std::endl;\r
-\r
-               menu->drop();\r
-               \r
-               // Delete map if requested\r
-               if(menudata.delete_map)\r
-               {\r
-                       bool r = fs::RecursiveDeleteContent(map_dir);\r
-                       if(r == false)\r
-                               error_message = L"Delete failed";\r
-                       continue;\r
-               }\r
+               /*\r
+                       If an error occurs, this is set to something and the\r
+                       menu-game loop is restarted. It is then displayed before\r
+                       the menu.\r
+               */\r
+               std::wstring error_message = L"";\r
 \r
-               playername = wide_to_narrow(menudata.name);\r
-               address = wide_to_narrow(menudata.address);\r
-               int newport = stoi(wide_to_narrow(menudata.port));\r
-               if(newport != 0)\r
-                       port = newport;\r
-               //port = stoi(wide_to_narrow(menudata.port));\r
-               g_settings.set("creative_mode", itos(menudata.creative_mode));\r
-               \r
-               // Check for valid parameters, restart menu if invalid.\r
-               if(playername == "")\r
+               // This is used for catching disconnects\r
+               try\r
                {\r
-                       error_message = L"Name required.";\r
-                       continue;\r
-               }\r
-               \r
-               // Save settings\r
-               g_settings.set("name", playername);\r
-               g_settings.set("address", address);\r
-               g_settings.set("port", itos(port));\r
-               // Update configuration file\r
-               if(configpath != "")\r
-                       g_settings.updateConfigFile(configpath.c_str());\r
-       \r
-               // Continue to game\r
-               break;\r
-       }\r
-       \r
-       // Break out of menu-game loop to shut down cleanly\r
-       if(g_device->run() == false)\r
-               break;\r
-\r
-       /*\r
-               Make a scope here so that the client and the server and other\r
-               stuff gets removed when disconnected or the irrlicht device\r
-               is removed.\r
-       */\r
-       {\r
-\r
-       /*\r
-               Draw "Loading" screen\r
-       */\r
-       const wchar_t *text = L"Loading and connecting...";\r
-       core::vector2d<s32> center(screenW/2, screenH/2);\r
-       core::vector2d<s32> textsize(300, text_height);\r
-       core::rect<s32> textrect(center - textsize/2, center + textsize/2);\r
-\r
-       gui::IGUIStaticText *gui_loadingtext = guienv->addStaticText(\r
-                       text, textrect, false, false);\r
-       gui_loadingtext->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);\r
-\r
-       driver->beginScene(true, true, video::SColor(255,0,0,0));\r
-       guienv->drawAll();\r
-       driver->endScene();\r
-\r
-       std::cout<<DTIME<<"Creating server and client"<<std::endl;\r
-       \r
-       /*\r
-               Create server.\r
-               SharedPtr will delete it when it goes out of scope.\r
-       */\r
-       SharedPtr<Server> server;\r
-       if(address == ""){\r
-               server = new Server(map_dir);\r
-               server->start(port);\r
-       }\r
-       \r
-       /*\r
-               Create client\r
-       */\r
 \r
-       Client client(device, playername.c_str(), draw_control);\r
+                       /*\r
+                               Clear everything from the GUIEnvironment\r
+                       */\r
+                       guienv->clear();\r
                        \r
-       g_client = &client;\r
-       \r
-       Address connect_address(0,0,0,0, port);\r
-       try{\r
-               if(address == "")\r
-                       //connect_address.Resolve("localhost");\r
-                       connect_address.setAddress(127,0,0,1);\r
-               else\r
-                       connect_address.Resolve(address.c_str());\r
-       }\r
-       catch(ResolveError &e)\r
-       {\r
-               std::cout<<DTIME<<"Couldn't resolve address"<<std::endl;\r
-               //return 0;\r
-               error_message = L"Couldn't resolve address";\r
-               gui_loadingtext->remove();\r
-               continue;\r
-       }\r
-       \r
-       dstream<<DTIME<<"Connecting to server at ";\r
-       connect_address.print(&dstream);\r
-       dstream<<std::endl;\r
-       client.connect(connect_address);\r
-       \r
-       try{\r
-               while(client.connectedAndInitialized() == false)\r
-               {\r
-                       // Update screen\r
-                       driver->beginScene(true, true, video::SColor(255,0,0,0));\r
-                       guienv->drawAll();\r
-                       driver->endScene();\r
-\r
-                       // Update client and server\r
-\r
-                       client.step(0.1);\r
-\r
-                       if(server != NULL)\r
-                               server->step(0.1);\r
+                       /*\r
+                               We need some kind of a root node to be able to add\r
+                               custom gui elements directly on the screen.\r
+                               Otherwise they won't be automatically drawn.\r
+                       */\r
+                       guiroot = guienv->addStaticText(L"",\r
+                                       core::rect<s32>(0, 0, 10000, 10000));\r
                        \r
-                       // Delay a bit\r
-                       sleep_ms(100);\r
-               }\r
-       }\r
-       catch(con::PeerNotFoundException &e)\r
-       {\r
-               std::cout<<DTIME<<"Timed out."<<std::endl;\r
-               //return 0;\r
-               error_message = L"Connection timed out.";\r
-               gui_loadingtext->remove();\r
-               continue;\r
-       }\r
-\r
-       /*\r
-               Create skybox\r
-       */\r
-       /*scene::ISceneNode* skybox;\r
-       skybox = smgr->addSkyBoxSceneNode(\r
-               driver->getTexture(porting::getDataPath("skybox2.png").c_str()),\r
-               driver->getTexture(porting::getDataPath("skybox3.png").c_str()),\r
-               driver->getTexture(porting::getDataPath("skybox1.png").c_str()),\r
-               driver->getTexture(porting::getDataPath("skybox1.png").c_str()),\r
-               driver->getTexture(porting::getDataPath("skybox1.png").c_str()),\r
-               driver->getTexture(porting::getDataPath("skybox1.png").c_str()));*/\r
-       \r
-       /*\r
-               Create the camera node\r
-       */\r
-\r
-       scene::ICameraSceneNode* camera = smgr->addCameraSceneNode(\r
-               0, // Camera parent\r
-               v3f(BS*100, BS*2, BS*100), // Look from\r
-               v3f(BS*100+1, BS*2, BS*100), // Look to\r
-               -1 // Camera ID\r
-       );\r
-\r
-       if(camera == NULL)\r
-               return 1;\r
+                       /*\r
+                               Out-of-game menu loop.\r
 \r
-       //video::SColor skycolor = video::SColor(255,90,140,200);\r
-       //video::SColor skycolor = video::SColor(255,166,202,244);\r
-       //video::SColor skycolor = video::SColor(255,120,185,244);\r
-       video::SColor skycolor = video::SColor(255,140,186,250);\r
+                               Loop quits when menu returns proper parameters.\r
+                       */\r
+                       while(kill == false)\r
+                       {\r
+                               // Cursor can be non-visible when coming from the game\r
+                               device->getCursorControl()->setVisible(true);\r
+                               // Some stuff are left to scene manager when coming from the game\r
+                               // (map at least?)\r
+                               smgr->clear();\r
+                               // Reset or hide the debug gui texts\r
+                               /*guitext->setText(L"Minetest-c55");\r
+                               guitext2->setVisible(false);\r
+                               guitext_info->setVisible(false);\r
+                               guitext_chat->setVisible(false);*/\r
+                               \r
+                               // Initialize menu data\r
+                               MainMenuData menudata;\r
+                               menudata.address = narrow_to_wide(address);\r
+                               menudata.name = narrow_to_wide(playername);\r
+                               menudata.port = narrow_to_wide(itos(port));\r
+                               menudata.creative_mode = g_settings.getBool("creative_mode");\r
+\r
+                               GUIMainMenu *menu =\r
+                                               new GUIMainMenu(guienv, guiroot, -1, \r
+                                                       &g_menumgr, &menudata, g_gamecallback);\r
+                               menu->allowFocusRemoval(true);\r
+\r
+                               if(error_message != L"")\r
+                               {\r
+                                       dstream<<"WARNING: error_message = "\r
+                                                       <<wide_to_narrow(error_message)<<std::endl;\r
+\r
+                                       GUIMessageMenu *menu2 =\r
+                                                       new GUIMessageMenu(guienv, guiroot, -1, \r
+                                                               &g_menumgr, error_message.c_str());\r
+                                       menu2->drop();\r
+                                       error_message = L"";\r
+                               }\r
 \r
-       camera->setFOV(FOV_ANGLE);\r
+                               video::IVideoDriver* driver = device->getVideoDriver();\r
+                               \r
+                               dstream<<"Created main menu"<<std::endl;\r
 \r
-       // Just so big a value that everything rendered is visible\r
-       camera->setFarValue(100000*BS);\r
-       \r
-       f32 camera_yaw = 0; // "right/left"\r
-       f32 camera_pitch = 0; // "up/down"\r
+                               while(device->run() && kill == false)\r
+                               {\r
+                                       if(menu->getStatus() == true)\r
+                                               break;\r
 \r
-       /*\r
-               Move into game\r
-       */\r
-       \r
-       gui_loadingtext->remove();\r
+                                       //driver->beginScene(true, true, video::SColor(255,0,0,0));\r
+                                       driver->beginScene(true, true, video::SColor(255,128,128,128));\r
+                                       guienv->drawAll();\r
+                                       driver->endScene();\r
+                               }\r
+                               \r
+                               // Break out of menu-game loop to shut down cleanly\r
+                               if(device->run() == false || kill == true)\r
+                                       break;\r
+                               \r
+                               dstream<<"Dropping main menu"<<std::endl;\r
 \r
-       /*\r
-               Add some gui stuff\r
-       */\r
+                               menu->drop();\r
+                               \r
+                               // Delete map if requested\r
+                               if(menudata.delete_map)\r
+                               {\r
+                                       bool r = fs::RecursiveDeleteContent(map_dir);\r
+                                       if(r == false)\r
+                                               error_message = L"Delete failed";\r
+                                       continue;\r
+                               }\r
 \r
-       /*GUIQuickInventory *quick_inventory = new GUIQuickInventory\r
-                       (guienv, NULL, v2s32(10, 70), 5, &local_inventory);*/\r
-       /*GUIQuickInventory *quick_inventory = new GUIQuickInventory\r
-                       (guienv, NULL, v2s32(0, 0), quickinv_itemcount, &local_inventory);*/\r
-       \r
-       // Test the text input system\r
-       /*(new GUITextInputMenu(guienv, guiroot, -1, &g_menumgr,\r
-                       NULL))->drop();*/\r
-       /*GUIMessageMenu *menu =\r
-                       new GUIMessageMenu(guienv, guiroot, -1, \r
-                               &g_menumgr,\r
-                               L"Asd");\r
-       menu->drop();*/\r
-       \r
-       // Launch pause menu\r
-       (new GUIPauseMenu(guienv, guiroot, -1, &g_gamecallback,\r
-                       &g_menumgr))->drop();\r
-       \r
-       // Enable texts\r
-       guitext2->setVisible(true);\r
-       guitext_info->setVisible(true);\r
-       guitext_chat->setVisible(true);\r
+                               playername = wide_to_narrow(menudata.name);\r
+                               address = wide_to_narrow(menudata.address);\r
+                               int newport = stoi(wide_to_narrow(menudata.port));\r
+                               if(newport != 0)\r
+                                       port = newport;\r
+                               //port = stoi(wide_to_narrow(menudata.port));\r
+                               g_settings.set("creative_mode", itos(menudata.creative_mode));\r
+                               \r
+                               // Check for valid parameters, restart menu if invalid.\r
+                               if(playername == "")\r
+                               {\r
+                                       error_message = L"Name required.";\r
+                                       continue;\r
+                               }\r
+                               \r
+                               // Save settings\r
+                               g_settings.set("name", playername);\r
+                               g_settings.set("address", address);\r
+                               g_settings.set("port", itos(port));\r
+                               // Update configuration file\r
+                               if(configpath != "")\r
+                                       g_settings.updateConfigFile(configpath.c_str());\r
+                       \r
+                               // Continue to game\r
+                               break;\r
+                       }\r
+                       \r
+                       // Break out of menu-game loop to shut down cleanly\r
+                       if(device->run() == false)\r
+                               break;\r
+                       \r
+                       /*\r
+                               Run game\r
+                       */\r
+                       the_game(\r
+                               kill,\r
+                               random_input,\r
+                               input,\r
+                               device,\r
+                               font,\r
+                               map_dir,\r
+                               playername,\r
+                               address,\r
+                               port,\r
+                               error_message\r
+                       );\r
 \r
-       //s32 guitext_chat_pad_bottom = 70;\r
+               } //try\r
+               catch(con::PeerNotFoundException &e)\r
+               {\r
+                       dstream<<DTIME<<"Connection error (timed out?)"<<std::endl;\r
+                       error_message = L"Connection error (timed out?)";\r
+               }\r
 \r
-       v2u32 screensize(0,0);\r
-       v2u32 last_screensize(0,0);\r
-       \r
-       /*\r
-               Some statistics are collected in these\r
-       */\r
-       u32 drawtime = 0;\r
-       u32 beginscenetime = 0;\r
-       u32 scenetime = 0;\r
-       u32 endscenetime = 0;\r
+       } // Menu-game loop\r
        \r
-       // A test\r
-       //throw con::PeerNotFoundException("lol");\r
-\r
-       core::list<float> frametime_log;\r
-\r
-       float damage_flash_timer = 0;\r
+       delete input;\r
 \r
        /*\r
-               Main loop\r
+               In the end, delete the Irrlicht device.\r
        */\r
-\r
-       bool first_loop_after_window_activation = true;\r
-\r
-       // Time is in milliseconds\r
-       // NOTE: getRealTime() causes strange problems in wine (imprecision?)\r
-       // NOTE: So we have to use getTime() and call run()s between them\r
-       u32 lasttime = device->getTimer()->getTime();\r
-\r
-       while(device->run() && kill == false)\r
-       {\r
-               if(g_gamecallback.disconnect_requested)\r
-               {\r
-                       g_gamecallback.disconnect_requested = false;\r
-                       break;\r
-               }\r
-\r
-               /*\r
-                       Process TextureSource's queue\r
-               */\r
-               texturesource->processQueue();\r
-\r
-               /*\r
-                       Random calculations\r
-               */\r
-               last_screensize = screensize;\r
-               screensize = driver->getScreenSize();\r
-               v2s32 displaycenter(screensize.X/2,screensize.Y/2);\r
-               //bool screensize_changed = screensize != last_screensize;\r
-               \r
-               // Hilight boxes collected during the loop and displayed\r
-               core::list< core::aabbox3d<f32> > hilightboxes;\r
-               \r
-               // Info text\r
-               std::wstring infotext;\r
-\r
-               // When screen size changes, update positions and sizes of stuff\r
-               /*if(screensize_changed)\r
-               {\r
-                       v2s32 pos(displaycenter.X-((quickinv_itemcount-1)*quickinv_spacing+quickinv_size)/2, screensize.Y-quickinv_spacing);\r
-                       quick_inventory->updatePosition(pos);\r
-               }*/\r
-\r
-               //TimeTaker //timer1("//timer1");\r
-               \r
-               // Time of frame without fps limit\r
-               float busytime;\r
-               u32 busytime_u32;\r
-               {\r
-                       // not using getRealTime is necessary for wine\r
-                       u32 time = device->getTimer()->getTime();\r
-                       if(time > lasttime)\r
-                               busytime_u32 = time - lasttime;\r
-                       else\r
-                               busytime_u32 = 0;\r
-                       busytime = busytime_u32 / 1000.0;\r
-               }\r
-\r
-               //std::cout<<"busytime_u32="<<busytime_u32<<std::endl;\r
+       device->drop();\r
        \r
-               // Necessary for device->getTimer()->getTime()\r
-               device->run();\r
-\r
-               /*\r
-                       Viewing range\r
-               */\r
-               \r
-               updateViewingRange(busytime, &client);\r
-               \r
-               /*\r
-                       FPS limiter\r
-               */\r
-\r
-               {\r
-                       float fps_max = g_settings.getFloat("fps_max");\r
-                       u32 frametime_min = 1000./fps_max;\r
-                       \r
-                       if(busytime_u32 < frametime_min)\r
-                       {\r
-                               u32 sleeptime = frametime_min - busytime_u32;\r
-                               device->sleep(sleeptime);\r
-                       }\r
-               }\r
-\r
-               // Necessary for device->getTimer()->getTime()\r
-               device->run();\r
-\r
-               /*\r
-                       Time difference calculation\r
-               */\r
-               f32 dtime; // in seconds\r
-               \r
-               u32 time = device->getTimer()->getTime();\r
-               if(time > lasttime)\r
-                       dtime = (time - lasttime) / 1000.0;\r
-               else\r
-                       dtime = 0;\r
-               lasttime = time;\r
-\r
-               /*\r
-                       Log frametime for visualization\r
-               */\r
-               frametime_log.push_back(dtime);\r
-               if(frametime_log.size() > 100)\r
-               {\r
-                       core::list<float>::Iterator i = frametime_log.begin();\r
-                       frametime_log.erase(i);\r
-               }\r
-\r
-               /*\r
-                       Visualize frametime in terminal\r
-               */\r
-               /*for(u32 i=0; i<dtime*400; i++)\r
-                       std::cout<<"X";\r
-               std::cout<<std::endl;*/\r
-\r
-               /*\r
-                       Time average and jitter calculation\r
-               */\r
-\r
-               static f32 dtime_avg1 = 0.0;\r
-               dtime_avg1 = dtime_avg1 * 0.98 + dtime * 0.02;\r
-               f32 dtime_jitter1 = dtime - dtime_avg1;\r
-\r
-               static f32 dtime_jitter1_max_sample = 0.0;\r
-               static f32 dtime_jitter1_max_fraction = 0.0;\r
-               {\r
-                       static f32 jitter1_max = 0.0;\r
-                       static f32 counter = 0.0;\r
-                       if(dtime_jitter1 > jitter1_max)\r
-                               jitter1_max = dtime_jitter1;\r
-                       counter += dtime;\r
-                       if(counter > 0.0)\r
-                       {\r
-                               counter -= 3.0;\r
-                               dtime_jitter1_max_sample = jitter1_max;\r
-                               dtime_jitter1_max_fraction\r
-                                               = dtime_jitter1_max_sample / (dtime_avg1+0.001);\r
-                               jitter1_max = 0.0;\r
-                       }\r
-               }\r
-               \r
-               /*\r
-                       Busytime average and jitter calculation\r
-               */\r
-\r
-               static f32 busytime_avg1 = 0.0;\r
-               busytime_avg1 = busytime_avg1 * 0.98 + busytime * 0.02;\r
-               f32 busytime_jitter1 = busytime - busytime_avg1;\r
-               \r
-               static f32 busytime_jitter1_max_sample = 0.0;\r
-               static f32 busytime_jitter1_min_sample = 0.0;\r
-               {\r
-                       static f32 jitter1_max = 0.0;\r
-                       static f32 jitter1_min = 0.0;\r
-                       static f32 counter = 0.0;\r
-                       if(busytime_jitter1 > jitter1_max)\r
-                               jitter1_max = busytime_jitter1;\r
-                       if(busytime_jitter1 < jitter1_min)\r
-                               jitter1_min = busytime_jitter1;\r
-                       counter += dtime;\r
-                       if(counter > 0.0){\r
-                               counter -= 3.0;\r
-                               busytime_jitter1_max_sample = jitter1_max;\r
-                               busytime_jitter1_min_sample = jitter1_min;\r
-                               jitter1_max = 0.0;\r
-                               jitter1_min = 0.0;\r
-                       }\r
-               }\r
-               \r
-               /*\r
-                       Debug info for client\r
-               */\r
-               {\r
-                       static float counter = 0.0;\r
-                       counter -= dtime;\r
-                       if(counter < 0)\r
-                       {\r
-                               counter = 30.0;\r
-                               client.printDebugInfo(std::cout);\r
-                       }\r
-               }\r
-\r
-               /*\r
-                       Input handler step()\r
-               */\r
-               g_input->step(dtime);\r
-\r
-               /*\r
-                       Misc. stuff\r
-               */\r
-\r
-               /*\r
-                       Player speed control\r
-               */\r
-               \r
-               {\r
-                       /*bool a_up,\r
-                       bool a_down,\r
-                       bool a_left,\r
-                       bool a_right,\r
-                       bool a_jump,\r
-                       bool a_superspeed,\r
-                       bool a_sneak,\r
-                       float a_pitch,\r
-                       float a_yaw*/\r
-                       PlayerControl control(\r
-                               g_input->isKeyDown(irr::KEY_KEY_W),\r
-                               g_input->isKeyDown(irr::KEY_KEY_S),\r
-                               g_input->isKeyDown(irr::KEY_KEY_A),\r
-                               g_input->isKeyDown(irr::KEY_KEY_D),\r
-                               g_input->isKeyDown(irr::KEY_SPACE),\r
-                               g_input->isKeyDown(irr::KEY_KEY_E),\r
-                               g_input->isKeyDown(irr::KEY_LSHIFT)\r
-                                               || g_input->isKeyDown(irr::KEY_RSHIFT),\r
-                               camera_pitch,\r
-                               camera_yaw\r
-                       );\r
-                       client.setPlayerControl(control);\r
-               }\r
-               \r
-               /*\r
-                       Run server\r
-               */\r
-\r
-               if(server != NULL)\r
-               {\r
-                       //TimeTaker timer("server->step(dtime)");\r
-                       server->step(dtime);\r
-               }\r
-\r
-               /*\r
-                       Process environment\r
-               */\r
-               \r
-               {\r
-                       //TimeTaker timer("client.step(dtime)");\r
-                       client.step(dtime);\r
-                       //client.step(dtime_avg1);\r
-               }\r
-\r
-               // Read client events\r
-               for(;;)\r
-               {\r
-                       ClientEvent event = client.getClientEvent();\r
-                       if(event.type == CE_NONE)\r
-                       {\r
-                               break;\r
-                       }\r
-                       else if(event.type == CE_PLAYER_DAMAGE)\r
-                       {\r
-                               //u16 damage = event.player_damage.amount;\r
-                               //dstream<<"Player damage: "<<damage<<std::endl;\r
-                               damage_flash_timer = 0.05;\r
-                       }\r
-                       else if(event.type == CE_PLAYER_FORCE_MOVE)\r
-                       {\r
-                               camera_yaw = event.player_force_move.yaw;\r
-                               camera_pitch = event.player_force_move.pitch;\r
-                       }\r
-               }\r
-               \r
-               // Get player position\r
-               v3f player_position = client.getPlayerPosition();\r
-               \r
-               //TimeTaker //timer2("//timer2");\r
-\r
-               /*\r
-                       Mouse and camera control\r
-               */\r
-               \r
-               if((device->isWindowActive() && noMenuActive()) || random_input)\r
-               {\r
-                       if(!random_input)\r
-                               device->getCursorControl()->setVisible(false);\r
-\r
-                       if(first_loop_after_window_activation){\r
-                               //std::cout<<"window active, first loop"<<std::endl;\r
-                               first_loop_after_window_activation = false;\r
-                       }\r
-                       else{\r
-                               s32 dx = g_input->getMousePos().X - displaycenter.X;\r
-                               s32 dy = g_input->getMousePos().Y - displaycenter.Y;\r
-                               //std::cout<<"window active, pos difference "<<dx<<","<<dy<<std::endl;\r
-                               camera_yaw -= dx*0.2;\r
-                               camera_pitch += dy*0.2;\r
-                               if(camera_pitch < -89.5) camera_pitch = -89.5;\r
-                               if(camera_pitch > 89.5) camera_pitch = 89.5;\r
-                       }\r
-                       g_input->setMousePos(displaycenter.X, displaycenter.Y);\r
-               }\r
-               else{\r
-                       device->getCursorControl()->setVisible(true);\r
-\r
-                       //std::cout<<"window inactive"<<std::endl;\r
-                       first_loop_after_window_activation = true;\r
-               }\r
-\r
-               camera_yaw = wrapDegrees(camera_yaw);\r
-               camera_pitch = wrapDegrees(camera_pitch);\r
-               \r
-               v3f camera_direction = v3f(0,0,1);\r
-               camera_direction.rotateYZBy(camera_pitch);\r
-               camera_direction.rotateXZBy(camera_yaw);\r
-               \r
-               // This is at the height of the eyes of the current figure\r
-               //v3f camera_position = player_position + v3f(0, BS+BS/2, 0);\r
-               // This is more like in minecraft\r
-               v3f camera_position = player_position + v3f(0, BS+BS*0.625, 0);\r
-\r
-               camera->setPosition(camera_position);\r
-               // *100.0 helps in large map coordinates\r
-               camera->setTarget(camera_position + camera_direction * 100.0);\r
-\r
-               if(FIELD_OF_VIEW_TEST){\r
-                       client.updateCamera(v3f(0,0,0), v3f(0,0,1));\r
-               }\r
-               else{\r
-                       //TimeTaker timer("client.updateCamera");\r
-                       client.updateCamera(camera_position, camera_direction);\r
-               }\r
-               \r
-               //timer2.stop();\r
-               //TimeTaker //timer3("//timer3");\r
-\r
-               /*\r
-                       Calculate what block is the crosshair pointing to\r
-               */\r
-               \r
-               //u32 t1 = device->getTimer()->getRealTime();\r
-               \r
-               //f32 d = 4; // max. distance\r
-               f32 d = 4; // max. distance\r
-               core::line3d<f32> shootline(camera_position,\r
-                               camera_position + camera_direction * BS * (d+1));\r
-\r
-               MapBlockObject *selected_object = client.getSelectedObject\r
-                               (d*BS, camera_position, shootline);\r
-\r
-               ClientActiveObject *selected_active_object\r
-                               = client.getSelectedActiveObject\r
-                                       (d*BS, camera_position, shootline);\r
-\r
-               if(selected_object != NULL)\r
-               {\r
-                       //dstream<<"Client returned selected_object != NULL"<<std::endl;\r
-\r
-                       core::aabbox3d<f32> box_on_map\r
-                                       = selected_object->getSelectionBoxOnMap();\r
-\r
-                       hilightboxes.push_back(box_on_map);\r
-\r
-                       infotext = narrow_to_wide(selected_object->infoText());\r
-\r
-                       if(g_input->getLeftClicked())\r
-                       {\r
-                               std::cout<<DTIME<<"Left-clicked object"<<std::endl;\r
-                               client.clickObject(0, selected_object->getBlock()->getPos(),\r
-                                               selected_object->getId(), g_selected_item);\r
-                       }\r
-                       else if(g_input->getRightClicked())\r
-                       {\r
-                               std::cout<<DTIME<<"Right-clicked object"<<std::endl;\r
-                               /*\r
-                                       Check if we want to modify the object ourselves\r
-                               */\r
-                               if(selected_object->getTypeId() == MAPBLOCKOBJECT_TYPE_SIGN)\r
-                               {\r
-                                       dstream<<"Sign object right-clicked"<<std::endl;\r
-                                       \r
-                                       if(random_input == false)\r
-                                       {\r
-                                               // Get a new text for it\r
-\r
-                                               TextDest *dest = new TextDestSign(\r
-                                                               selected_object->getBlock()->getPos(),\r
-                                                               selected_object->getId(),\r
-                                                               &client);\r
-\r
-                                               SignObject *sign_object = (SignObject*)selected_object;\r
-\r
-                                               std::wstring wtext =\r
-                                                               narrow_to_wide(sign_object->getText());\r
-\r
-                                               (new GUITextInputMenu(guienv, guiroot, -1,\r
-                                                               &g_menumgr, dest,\r
-                                                               wtext))->drop();\r
-                                       }\r
-                               }\r
-                               /*\r
-                                       Otherwise pass the event to the server as-is\r
-                               */\r
-                               else\r
-                               {\r
-                                       client.clickObject(1, selected_object->getBlock()->getPos(),\r
-                                                       selected_object->getId(), g_selected_item);\r
-                               }\r
-                       }\r
-               }\r
-               else if(selected_active_object != NULL)\r
-               {\r
-                       //dstream<<"Client returned selected_active_object != NULL"<<std::endl;\r
-                       \r
-                       core::aabbox3d<f32> *selection_box\r
-                                       = selected_active_object->getSelectionBox();\r
-                       // Box should exist because object was returned in the\r
-                       // first place\r
-                       assert(selection_box);\r
-\r
-                       v3f pos = selected_active_object->getPosition();\r
-\r
-                       core::aabbox3d<f32> box_on_map(\r
-                                       selection_box->MinEdge + pos,\r
-                                       selection_box->MaxEdge + pos\r
-                       );\r
-\r
-                       hilightboxes.push_back(box_on_map);\r
-\r
-                       //infotext = narrow_to_wide("A ClientActiveObject");\r
-                       infotext = narrow_to_wide(selected_active_object->infoText());\r
-\r
-                       if(g_input->getLeftClicked())\r
-                       {\r
-                               std::cout<<DTIME<<"Left-clicked object"<<std::endl;\r
-                               client.clickActiveObject(0,\r
-                                               selected_active_object->getId(), g_selected_item);\r
-                       }\r
-                       else if(g_input->getRightClicked())\r
-                       {\r
-                               std::cout<<DTIME<<"Right-clicked object"<<std::endl;\r
-                       }\r
-               }\r
-               else // selected_object == NULL\r
-               {\r
-\r
-               /*\r
-                       Find out which node we are pointing at\r
-               */\r
-               \r
-               bool nodefound = false;\r
-               v3s16 nodepos;\r
-               v3s16 neighbourpos;\r
-               core::aabbox3d<f32> nodehilightbox;\r
-\r
-               getPointedNode(player_position,\r
-                               camera_direction, camera_position,\r
-                               nodefound, shootline,\r
-                               nodepos, neighbourpos,\r
-                               nodehilightbox, d);\r
-       \r
-               static float nodig_delay_counter = 0.0;\r
-\r
-               if(nodefound)\r
-               {\r
-                       static v3s16 nodepos_old(-32768,-32768,-32768);\r
-\r
-                       static float dig_time = 0.0;\r
-                       static u16 dig_index = 0;\r
-                       \r
-                       /*\r
-                               Visualize selection\r
-                       */\r
-\r
-                       hilightboxes.push_back(nodehilightbox);\r
-\r
-                       /*\r
-                               Check information text of node\r
-                       */\r
-\r
-                       NodeMetadata *meta = client.getNodeMetadata(nodepos);\r
-                       if(meta)\r
-                       {\r
-                               infotext = narrow_to_wide(meta->infoText());\r
-                       }\r
-                       \r
-                       //MapNode node = client.getNode(nodepos);\r
-\r
-                       /*\r
-                               Handle digging\r
-                       */\r
-                       \r
-                       if(g_input->getLeftReleased())\r
-                       {\r
-                               client.clearTempMod(nodepos);\r
-                               dig_time = 0.0;\r
-                       }\r
-                       \r
-                       if(nodig_delay_counter > 0.0)\r
-                       {\r
-                               nodig_delay_counter -= dtime;\r
-                       }\r
-                       else\r
-                       {\r
-                               if(nodepos != nodepos_old)\r
-                               {\r
-                                       std::cout<<DTIME<<"Pointing at ("<<nodepos.X<<","\r
-                                                       <<nodepos.Y<<","<<nodepos.Z<<")"<<std::endl;\r
-\r
-                                       if(nodepos_old != v3s16(-32768,-32768,-32768))\r
-                                       {\r
-                                               client.clearTempMod(nodepos_old);\r
-                                               dig_time = 0.0;\r
-                                       }\r
-                               }\r
-\r
-                               if(g_input->getLeftClicked() ||\r
-                                               (g_input->getLeftState() && nodepos != nodepos_old))\r
-                               {\r
-                                       dstream<<DTIME<<"Started digging"<<std::endl;\r
-                                       client.groundAction(0, nodepos, neighbourpos, g_selected_item);\r
-                               }\r
-                               if(g_input->getLeftClicked())\r
-                               {\r
-                                       client.setTempMod(nodepos, NodeMod(NODEMOD_CRACK, 0));\r
-                               }\r
-                               if(g_input->getLeftState())\r
-                               {\r
-                                       MapNode n = client.getNode(nodepos);\r
-                               \r
-                                       // Get tool name. Default is "" = bare hands\r
-                                       std::string toolname = "";\r
-                                       InventoryList *mlist = local_inventory.getList("main");\r
-                                       if(mlist != NULL)\r
-                                       {\r
-                                               InventoryItem *item = mlist->getItem(g_selected_item);\r
-                                               if(item && (std::string)item->getName() == "ToolItem")\r
-                                               {\r
-                                                       ToolItem *titem = (ToolItem*)item;\r
-                                                       toolname = titem->getToolName();\r
-                                               }\r
-                                       }\r
-\r
-                                       // Get digging properties for material and tool\r
-                                       u8 material = n.d;\r
-                                       DiggingProperties prop =\r
-                                                       getDiggingProperties(material, toolname);\r
-                                       \r
-                                       float dig_time_complete = 0.0;\r
-\r
-                                       if(prop.diggable == false)\r
-                                       {\r
-                                               /*dstream<<"Material "<<(int)material\r
-                                                               <<" not diggable with \""\r
-                                                               <<toolname<<"\""<<std::endl;*/\r
-                                               // I guess nobody will wait for this long\r
-                                               dig_time_complete = 10000000.0;\r
-                                       }\r
-                                       else\r
-                                       {\r
-                                               dig_time_complete = prop.time;\r
-                                       }\r
-                                       \r
-                                       if(dig_time_complete >= 0.001)\r
-                                       {\r
-                                               dig_index = (u16)((float)CRACK_ANIMATION_LENGTH\r
-                                                               * dig_time/dig_time_complete);\r
-                                       }\r
-                                       // This is for torches\r
-                                       else\r
-                                       {\r
-                                               dig_index = CRACK_ANIMATION_LENGTH;\r
-                                       }\r
-\r
-                                       if(dig_index < CRACK_ANIMATION_LENGTH)\r
-                                       {\r
-                                               //TimeTaker timer("client.setTempMod");\r
-                                               //dstream<<"dig_index="<<dig_index<<std::endl;\r
-                                               client.setTempMod(nodepos, NodeMod(NODEMOD_CRACK, dig_index));\r
-                                       }\r
-                                       else\r
-                                       {\r
-                                               dstream<<DTIME<<"Digging completed"<<std::endl;\r
-                                               client.groundAction(3, nodepos, neighbourpos, g_selected_item);\r
-                                               client.clearTempMod(nodepos);\r
-                                               client.removeNode(nodepos);\r
-\r
-                                               dig_time = 0;\r
-\r
-                                               nodig_delay_counter = dig_time_complete\r
-                                                               / (float)CRACK_ANIMATION_LENGTH;\r
-\r
-                                               // We don't want a corresponding delay to\r
-                                               // very time consuming nodes\r
-                                               if(nodig_delay_counter > 0.5)\r
-                                               {\r
-                                                       nodig_delay_counter = 0.5;\r
-                                               }\r
-                                               // We want a slight delay to very little\r
-                                               // time consuming nodes\r
-                                               float mindelay = 0.15;\r
-                                               if(nodig_delay_counter < mindelay)\r
-                                               {\r
-                                                       nodig_delay_counter = mindelay;\r
-                                               }\r
-                                       }\r
-\r
-                                       dig_time += dtime;\r
-                               }\r
-                       }\r
-                       \r
-                       if(g_input->getRightClicked())\r
-                       {\r
-                               std::cout<<DTIME<<"Ground right-clicked"<<std::endl;\r
-                               \r
-                               if(meta && meta->typeId() == CONTENT_SIGN_WALL && !random_input)\r
-                               {\r
-                                       dstream<<"Sign node right-clicked"<<std::endl;\r
-                                       \r
-                                       SignNodeMetadata *signmeta = (SignNodeMetadata*)meta;\r
-                                       \r
-                                       // Get a new text for it\r
-\r
-                                       TextDest *dest = new TextDestSignNode(nodepos, &client);\r
-\r
-                                       std::wstring wtext =\r
-                                                       narrow_to_wide(signmeta->getText());\r
-\r
-                                       (new GUITextInputMenu(guienv, guiroot, -1,\r
-                                                       &g_menumgr, dest,\r
-                                                       wtext))->drop();\r
-                               }\r
-                               else if(meta && meta->typeId() == CONTENT_CHEST && !random_input)\r
-                               {\r
-                                       dstream<<"Chest node right-clicked"<<std::endl;\r
-                                       \r
-                                       //ChestNodeMetadata *chestmeta = (ChestNodeMetadata*)meta;\r
-\r
-                                       std::string chest_inv_id;\r
-                                       chest_inv_id += "nodemeta:";\r
-                                       chest_inv_id += itos(nodepos.X);\r
-                                       chest_inv_id += ",";\r
-                                       chest_inv_id += itos(nodepos.Y);\r
-                                       chest_inv_id += ",";\r
-                                       chest_inv_id += itos(nodepos.Z);\r
-                                       \r
-                                       GUIInventoryMenu *menu =\r
-                                               new GUIInventoryMenu(guienv, guiroot, -1,\r
-                                                       &g_menumgr, v2s16(8,9),\r
-                                                       g_client->getInventoryContext(),\r
-                                                       g_client);\r
-\r
-                                       core::array<GUIInventoryMenu::DrawSpec> draw_spec;\r
-                                       \r
-                                       draw_spec.push_back(GUIInventoryMenu::DrawSpec(\r
-                                                       "list", chest_inv_id, "0",\r
-                                                       v2s32(0, 0), v2s32(8, 4)));\r
-                                       draw_spec.push_back(GUIInventoryMenu::DrawSpec(\r
-                                                       "list", "current_player", "main",\r
-                                                       v2s32(0, 5), v2s32(8, 4)));\r
-\r
-                                       menu->setDrawSpec(draw_spec);\r
-\r
-                                       menu->drop();\r
-\r
-                               }\r
-                               else if(meta && meta->typeId() == CONTENT_FURNACE && !random_input)\r
-                               {\r
-                                       dstream<<"Furnace node right-clicked"<<std::endl;\r
-                                       \r
-                                       GUIFurnaceMenu *menu =\r
-                                               new GUIFurnaceMenu(guienv, guiroot, -1,\r
-                                                       &g_menumgr, nodepos, g_client);\r
-\r
-                                       menu->drop();\r
-\r
-                               }\r
-                               else\r
-                               {\r
-                                       client.groundAction(1, nodepos, neighbourpos, g_selected_item);\r
-                               }\r
-                       }\r
-                       \r
-                       nodepos_old = nodepos;\r
-               }\r
-               else{\r
-               }\r
-\r
-               } // selected_object == NULL\r
-               \r
-               g_input->resetLeftClicked();\r
-               g_input->resetRightClicked();\r
-               \r
-               if(g_input->getLeftReleased())\r
-               {\r
-                       std::cout<<DTIME<<"Left button released (stopped digging)"\r
-                                       <<std::endl;\r
-                       client.groundAction(2, v3s16(0,0,0), v3s16(0,0,0), 0);\r
-               }\r
-               if(g_input->getRightReleased())\r
-               {\r
-                       //std::cout<<DTIME<<"Right released"<<std::endl;\r
-                       // Nothing here\r
-               }\r
-               \r
-               g_input->resetLeftReleased();\r
-               g_input->resetRightReleased();\r
-               \r
-               /*\r
-                       Calculate stuff for drawing\r
-               */\r
-\r
-               camera->setAspectRatio((f32)screensize.X / (f32)screensize.Y);\r
-               \r
-               u32 daynight_ratio = client.getDayNightRatio();\r
-               u8 l = decode_light((daynight_ratio * LIGHT_SUN) / 1000);\r
-               video::SColor bgcolor = video::SColor(\r
-                               255,\r
-                               skycolor.getRed() * l / 255,\r
-                               skycolor.getGreen() * l / 255,\r
-                               skycolor.getBlue() * l / 255);\r
-\r
-               /*\r
-                       Fog\r
-               */\r
-               \r
-               if(g_settings.getBool("enable_fog") == true)\r
-               {\r
-                       //f32 range = draw_control.wanted_range * BS + MAP_BLOCKSIZE/2*BS;\r
-                       f32 range = draw_control.wanted_range * BS + 0.8*MAP_BLOCKSIZE*BS;\r
-                       //f32 range = draw_control.wanted_range * BS + 0.0*MAP_BLOCKSIZE*BS;\r
-                       if(draw_control.range_all)\r
-                               range = 100000*BS;\r
-\r
-                       driver->setFog(\r
-                               bgcolor,\r
-                               video::EFT_FOG_LINEAR,\r
-                               range*0.4,\r
-                               range*1.0,\r
-                               0.01,\r
-                               false, // pixel fog\r
-                               false // range fog\r
-                       );\r
-               }\r
-               else\r
-               {\r
-                       driver->setFog(\r
-                               bgcolor,\r
-                               video::EFT_FOG_LINEAR,\r
-                               100000*BS,\r
-                               110000*BS,\r
-                               0.01,\r
-                               false, // pixel fog\r
-                               false // range fog\r
-                       );\r
-               }\r
-\r
-\r
-               /*\r
-                       Update gui stuff (0ms)\r
-               */\r
-\r
-               //TimeTaker guiupdatetimer("Gui updating");\r
-               \r
-               {\r
-                       static float drawtime_avg = 0;\r
-                       drawtime_avg = drawtime_avg * 0.95 + (float)drawtime*0.05;\r
-                       static float beginscenetime_avg = 0;\r
-                       beginscenetime_avg = beginscenetime_avg * 0.95 + (float)beginscenetime*0.05;\r
-                       static float scenetime_avg = 0;\r
-                       scenetime_avg = scenetime_avg * 0.95 + (float)scenetime*0.05;\r
-                       static float endscenetime_avg = 0;\r
-                       endscenetime_avg = endscenetime_avg * 0.95 + (float)endscenetime*0.05;\r
-                       \r
-                       char temptext[300];\r
-                       snprintf(temptext, 300, "Minetest-c55 ("\r
-                                       "F: item=%i"\r
-                                       ", R: range_all=%i"\r
-                                       ")"\r
-                                       " drawtime=%.0f, beginscenetime=%.0f"\r
-                                       ", scenetime=%.0f, endscenetime=%.0f",\r
-                                       g_selected_item,\r
-                                       draw_control.range_all,\r
-                                       drawtime_avg,\r
-                                       beginscenetime_avg,\r
-                                       scenetime_avg,\r
-                                       endscenetime_avg\r
-                                       );\r
-                       \r
-                       guitext->setText(narrow_to_wide(temptext).c_str());\r
-               }\r
-               \r
-               {\r
-                       char temptext[300];\r
-                       snprintf(temptext, 300,\r
-                                       "(% .1f, % .1f, % .1f)"\r
-                                       " (% .3f < btime_jitter < % .3f"\r
-                                       ", dtime_jitter = % .1f %%"\r
-                                       ", v_range = %.1f)",\r
-                                       player_position.X/BS,\r
-                                       player_position.Y/BS,\r
-                                       player_position.Z/BS,\r
-                                       busytime_jitter1_min_sample,\r
-                                       busytime_jitter1_max_sample,\r
-                                       dtime_jitter1_max_fraction * 100.0,\r
-                                       draw_control.wanted_range\r
-                                       );\r
-\r
-                       guitext2->setText(narrow_to_wide(temptext).c_str());\r
-               }\r
-               \r
-               {\r
-                       guitext_info->setText(infotext.c_str());\r
-               }\r
-               \r
-               /*\r
-                       Get chat messages from client\r
-               */\r
-               {\r
-                       // Get new messages\r
-                       std::wstring message;\r
-                       while(client.getChatMessage(message))\r
-                       {\r
-                               chat_lines.push_back(ChatLine(message));\r
-                               /*if(chat_lines.size() > 6)\r
-                               {\r
-                                       core::list<ChatLine>::Iterator\r
-                                                       i = chat_lines.begin();\r
-                                       chat_lines.erase(i);\r
-                               }*/\r
-                       }\r
-                       // Append them to form the whole static text and throw\r
-                       // it to the gui element\r
-                       std::wstring whole;\r
-                       // This will correspond to the line number counted from\r
-                       // top to bottom, from size-1 to 0\r
-                       s16 line_number = chat_lines.size();\r
-                       // Count of messages to be removed from the top\r
-                       u16 to_be_removed_count = 0;\r
-                       for(core::list<ChatLine>::Iterator\r
-                                       i = chat_lines.begin();\r
-                                       i != chat_lines.end(); i++)\r
-                       {\r
-                               // After this, line number is valid for this loop\r
-                               line_number--;\r
-                               // Increment age\r
-                               (*i).age += dtime;\r
-                               /*\r
-                                       This results in a maximum age of 60*6 to the\r
-                                       lowermost line and a maximum of 6 lines\r
-                               */\r
-                               float allowed_age = (6-line_number) * 60.0;\r
-\r
-                               if((*i).age > allowed_age)\r
-                               {\r
-                                       to_be_removed_count++;\r
-                                       continue;\r
-                               }\r
-                               whole += (*i).text + L'\n';\r
-                       }\r
-                       for(u16 i=0; i<to_be_removed_count; i++)\r
-                       {\r
-                               core::list<ChatLine>::Iterator\r
-                                               it = chat_lines.begin();\r
-                               chat_lines.erase(it);\r
-                       }\r
-                       guitext_chat->setText(whole.c_str());\r
-\r
-                       // Update gui element size and position\r
-\r
-                       /*core::rect<s32> rect(\r
-                                       10,\r
-                                       screensize.Y - guitext_chat_pad_bottom\r
-                                                       - text_height*chat_lines.size(),\r
-                                       screensize.X - 10,\r
-                                       screensize.Y - guitext_chat_pad_bottom\r
-                       );*/\r
-                       core::rect<s32> rect(\r
-                                       10,\r
-                                       50,\r
-                                       screensize.X - 10,\r
-                                       50 + text_height*chat_lines.size()\r
-                       );\r
-\r
-                       guitext_chat->setRelativePosition(rect);\r
-\r
-                       if(chat_lines.size() == 0)\r
-                               guitext_chat->setVisible(false);\r
-                       else\r
-                               guitext_chat->setVisible(true);\r
-               }\r
-\r
-               /*\r
-                       Inventory\r
-               */\r
-               \r
-               static u16 old_selected_item = 65535;\r
-               if(client.getLocalInventoryUpdated()\r
-                               || g_selected_item != old_selected_item)\r
-               {\r
-                       old_selected_item = g_selected_item;\r
-                       //std::cout<<"Updating local inventory"<<std::endl;\r
-                       client.getLocalInventory(local_inventory);\r
-               }\r
-               \r
-               /*\r
-                       Send actions returned by the inventory menu\r
-               */\r
-               while(inventory_action_queue.size() != 0)\r
-               {\r
-                       InventoryAction *a = inventory_action_queue.pop_front();\r
-\r
-                       client.sendInventoryAction(a);\r
-                       // Eat it\r
-                       delete a;\r
-               }\r
-\r
-               /*\r
-                       Drawing begins\r
-               */\r
-\r
-               TimeTaker drawtimer("Drawing");\r
-\r
-               \r
-               {\r
-                       TimeTaker timer("beginScene");\r
-                       driver->beginScene(true, true, bgcolor);\r
-                       //driver->beginScene(false, true, bgcolor);\r
-                       beginscenetime = timer.stop(true);\r
-               }\r
-\r
-               //timer3.stop();\r
-               \r
-               //std::cout<<DTIME<<"smgr->drawAll()"<<std::endl;\r
-               \r
-               {\r
-                       TimeTaker timer("smgr");\r
-                       smgr->drawAll();\r
-                       scenetime = timer.stop(true);\r
-               }\r
-               \r
-               {\r
-               //TimeTaker timer9("auxiliary drawings");\r
-               // 0ms\r
-               \r
-               //timer9.stop();\r
-               //TimeTaker //timer10("//timer10");\r
-               \r
-               video::SMaterial m;\r
-               //m.Thickness = 10;\r
-               m.Thickness = 3;\r
-               m.Lighting = false;\r
-               driver->setMaterial(m);\r
-\r
-               driver->setTransform(video::ETS_WORLD, core::IdentityMatrix);\r
-\r
-               for(core::list< core::aabbox3d<f32> >::Iterator i=hilightboxes.begin();\r
-                               i != hilightboxes.end(); i++)\r
-               {\r
-                       /*std::cout<<"hilightbox min="\r
-                                       <<"("<<i->MinEdge.X<<","<<i->MinEdge.Y<<","<<i->MinEdge.Z<<")"\r
-                                       <<" max="\r
-                                       <<"("<<i->MaxEdge.X<<","<<i->MaxEdge.Y<<","<<i->MaxEdge.Z<<")"\r
-                                       <<std::endl;*/\r
-                       driver->draw3DBox(*i, video::SColor(255,0,0,0));\r
-               }\r
-\r
-               /*\r
-                       Frametime log\r
-               */\r
-               if(g_settings.getBool("frametime_graph") == true)\r
-               {\r
-                       s32 x = 10;\r
-                       for(core::list<float>::Iterator\r
-                                       i = frametime_log.begin();\r
-                                       i != frametime_log.end();\r
-                                       i++)\r
-                       {\r
-                               driver->draw2DLine(v2s32(x,50),\r
-                                               v2s32(x,50+(*i)*1000),\r
-                                               video::SColor(255,255,255,255));\r
-                               x++;\r
-                       }\r
-               }\r
-#if 0\r
-               /*\r
-                       Draw map plot\r
-               */\r
-               if(g_show_map_plot && g_map_plot_texture)\r
-               {\r
-                       core::dimension2d<u32> drawdim(640,480);\r
-                       core::rect<s32> dest(v2s32(0,0), drawdim);\r
-                       dest += v2s32(\r
-                               (screensize.X-drawdim.Width)/2,\r
-                               (screensize.Y-drawdim.Height)/2\r
-                       );\r
-                       core::rect<s32> source(v2s32(0,0), g_map_plot_texture->getSize());\r
-                       driver->draw2DImage(g_map_plot_texture, dest, source);\r
-               }\r
-#endif\r
-               /*\r
-                       Draw crosshair\r
-               */\r
-               driver->draw2DLine(displaycenter - core::vector2d<s32>(10,0),\r
-                               displaycenter + core::vector2d<s32>(10,0),\r
-                               video::SColor(255,255,255,255));\r
-               driver->draw2DLine(displaycenter - core::vector2d<s32>(0,10),\r
-                               displaycenter + core::vector2d<s32>(0,10),\r
-                               video::SColor(255,255,255,255));\r
-\r
-               } // timer\r
-\r
-               //timer10.stop();\r
-               //TimeTaker //timer11("//timer11");\r
-\r
-               /*\r
-                       Draw gui\r
-               */\r
-               // 0-1ms\r
-               guienv->drawAll();\r
-\r
-               /*\r
-                       Draw hotbar\r
-               */\r
-               {\r
-                       draw_hotbar(driver, font, v2s32(displaycenter.X, screensize.Y),\r
-                                       hotbar_imagesize, hotbar_itemcount, &local_inventory,\r
-                                       client.getHP());\r
-               }\r
-\r
-               /*\r
-                       Damage flash\r
-               */\r
-               if(damage_flash_timer > 0.0)\r
-               {\r
-                       damage_flash_timer -= dtime;\r
-                       \r
-                       video::SColor color(128,255,0,0);\r
-                       driver->draw2DRectangle(color,\r
-                                       core::rect<s32>(0,0,screensize.X,screensize.Y),\r
-                                       NULL);\r
-               }\r
-               \r
-               /*\r
-                       End scene\r
-               */\r
-               {\r
-                       TimeTaker timer("endScene");\r
-                       driver->endScene();\r
-                       endscenetime = timer.stop(true);\r
-               }\r
-\r
-               drawtime = drawtimer.stop(true);\r
-\r
-               /*\r
-                       End of drawing\r
-               */\r
-\r
-#if 0\r
-               /*\r
-                       Refresh map plot if player has moved considerably\r
-               */\r
-               if(g_refresh_map_plot)\r
-               {\r
-                       static v3f old_player_pos = v3f(1,1,1) * 10000000;\r
-                       v3f p = client.getPlayerPosition() / BS;\r
-                       if(old_player_pos.getDistanceFrom(p) > 4 * g_map_plot_texture_scale)\r
-                       {\r
-                               updateMapPlotTexture(v2f(p.X,p.Z), driver, &client);\r
-                               old_player_pos = p;\r
-                       }\r
-                       g_refresh_map_plot = false;\r
-               }\r
-#endif\r
-               \r
-               static s16 lastFPS = 0;\r
-               //u16 fps = driver->getFPS();\r
-               u16 fps = (1.0/dtime_avg1);\r
-\r
-               if (lastFPS != fps)\r
-               {\r
-                       core::stringw str = L"Minetest [";\r
-                       str += driver->getName();\r
-                       str += "] FPS:";\r
-                       str += fps;\r
-\r
-                       device->setWindowCaption(str.c_str());\r
-                       lastFPS = fps;\r
-               }\r
-       }\r
-\r
-       } // client and server are deleted at this point\r
-\r
-       } //try\r
-       catch(con::PeerNotFoundException &e)\r
-       {\r
-               dstream<<DTIME<<"Connection timed out."<<std::endl;\r
-               error_message = L"Connection timed out.";\r
-       }\r
-\r
-       } // Menu-game loop\r
-       \r
-       delete g_input;\r
-\r
-       /*\r
-               In the end, delete the Irrlicht device.\r
-       */\r
-       device->drop();\r
-       \r
-       /*\r
-               Update configuration file\r
-       */\r
-       /*if(configpath != "")\r
-       {\r
-               g_settings.updateConfigFile(configpath.c_str());\r
-       }*/\r
-\r
        END_DEBUG_EXCEPTION_HANDLER\r
        \r
        debugstreams_deinit();\r
index 4248bd3e4041a8c688b4f5b007cf9529321cc235..c8ac7ccf18c7cf228c6319d67fda7a277107d2a5 100644 (file)
@@ -46,5 +46,98 @@ extern std::ostream *derr_server_ptr;
 #define dout_server (*dout_server_ptr)
 #define derr_server (*derr_server_ptr)
 
+/*
+       All kinds of stuff that needs to be exposed from main.cpp
+*/
+
+#include "modalMenu.h"
+#include "guiPauseMenu.h" //For IGameCallback
+
+extern gui::IGUIEnvironment* guienv;
+extern gui::IGUIStaticText *guiroot;
+
+// Handler for the modal menus
+
+class MainMenuManager : public IMenuManager
+{
+public:
+       virtual void createdMenu(GUIModalMenu *menu)
+       {
+               for(core::list<GUIModalMenu*>::Iterator
+                               i = m_stack.begin();
+                               i != m_stack.end(); i++)
+               {
+                       assert(*i != menu);
+               }
+
+               if(m_stack.size() != 0)
+                       (*m_stack.getLast())->setVisible(false);
+               m_stack.push_back(menu);
+       }
+
+       virtual void deletingMenu(GUIModalMenu *menu)
+       {
+               // Remove all entries if there are duplicates
+               bool removed_entry;
+               do{
+                       removed_entry = false;
+                       for(core::list<GUIModalMenu*>::Iterator
+                                       i = m_stack.begin();
+                                       i != m_stack.end(); i++)
+                       {
+                               if(*i == menu)
+                               {
+                                       m_stack.erase(i);
+                                       removed_entry = true;
+                                       break;
+                               }
+                       }
+               }while(removed_entry);
+
+               /*core::list<GUIModalMenu*>::Iterator i = m_stack.getLast();
+               assert(*i == menu);
+               m_stack.erase(i);*/
+               
+               if(m_stack.size() != 0)
+                       (*m_stack.getLast())->setVisible(true);
+       }
+
+       u32 menuCount()
+       {
+               return m_stack.size();
+       }
+
+       core::list<GUIModalMenu*> m_stack;
+};
+
+extern MainMenuManager g_menumgr;
+
+extern bool noMenuActive();
+
+class MainGameCallback : public IGameCallback
+{
+public:
+       MainGameCallback(IrrlichtDevice *a_device):
+               disconnect_requested(false),
+               device(a_device)
+       {
+       }
+
+       virtual void exitToOS()
+       {
+               device->closeDevice();
+       }
+
+       virtual void disconnect()
+       {
+               disconnect_requested = true;
+       }
+
+       bool disconnect_requested;
+       IrrlichtDevice *device;
+};
+
+extern MainGameCallback *g_gamecallback;
+
 #endif
 
index 3d4c9826497c79d15583f60a71e91ef8c76f551d..64780de75d7c2402d185b06b1e9362a0d57a4dbf 100644 (file)
@@ -1,6 +1,6 @@
 /*
 Minetest-c55
-Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
+Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
 
 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -17,10 +17,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
 
-/*
-(c) 2010 Perttu Ahola <celeron55@gmail.com>
-*/
-
 #include "player.h"
 #include "map.h"
 #include "connection.h"
index 03fba1e2c0b252870aa9300efb5fd865d724910d..f70b52fe737453a6741a8ca339de8f2f8148da27 100644 (file)
@@ -1,6 +1,6 @@
 /*
 Minetest-c55
-Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
+Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
 
 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -17,10 +17,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
 
-/*
-(c) 2010 Perttu Ahola <celeron55@gmail.com>
-*/
-
 #ifndef PLAYER_HEADER
 #define PLAYER_HEADER