]> git.lizzy.rs Git - dragonfireclient.git/blobdiff - src/client.cpp
Fix gettext on MSVC
[dragonfireclient.git] / src / client.cpp
index 89bb053aeac4ef9ce483e2a5817620918d124a0c..107e16f1487f377cb8d84051800e8cf31bfc4a6c 100644 (file)
@@ -28,7 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "util/string.h"
 #include "strfnd.h"
 #include "client.h"
-#include "clientserver.h"
+#include "network/clientopcodes.h"
 #include "main.h"
 #include "filesys.h"
 #include "porting.h"
@@ -52,6 +52,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "config.h"
 #include "version.h"
 #include "drawscene.h"
+#include "subgame.h"
+#include "server.h"
+#include "database.h"
+#include "database-sqlite3.h"
 
 extern gui::IGUIEnvironment* guienv;
 
@@ -75,7 +79,7 @@ QueuedMeshUpdate::~QueuedMeshUpdate()
 /*
        MeshUpdateQueue
 */
-       
+
 MeshUpdateQueue::MeshUpdateQueue()
 {
 }
@@ -126,7 +130,7 @@ void MeshUpdateQueue::addBlock(v3s16 p, MeshMakeData *data, bool ack_block_to_se
                        return;
                }
        }
-       
+
        /*
                Add the block
        */
@@ -169,7 +173,7 @@ void * MeshUpdateThread::Thread()
        log_register_thread("MeshUpdateThread");
 
        DSTACK(__FUNCTION_NAME);
-       
+
        BEGIN_DEBUG_EXCEPTION_HANDLER
 
        porting::setThreadName("MeshUpdateThread");
@@ -243,6 +247,7 @@ Client::Client(
                device->getSceneManager(),
                tsrc, this, device
        ),
+       m_particle_manager(&m_env),
        m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, ipv6, this),
        m_device(device),
        m_server_ser_ver(SER_FMT_VER_INVALID),
@@ -250,10 +255,11 @@ Client::Client(
        m_inventory_updated(false),
        m_inventory_from_server(NULL),
        m_inventory_from_server_age(0.0),
-       m_show_hud(true),
+       m_show_highlighted(false),
        m_animation_time(0),
        m_crack_level(-1),
        m_crack_pos(0,0,0),
+       m_highlighted_pos(0,0,0),
        m_map_seed(0),
        m_password(password),
        m_access_denied(false),
@@ -275,12 +281,20 @@ Client::Client(
 
                m_env.addPlayer(player);
        }
+
+       m_cache_smooth_lighting = g_settings->getBool("smooth_lighting");
+       m_cache_enable_shaders  = g_settings->getBool("enable_shaders");
 }
 
 void Client::Stop()
 {
        //request all client managed threads to stop
        m_mesh_update_thread.Stop();
+       if (localdb != NULL) {
+               actionstream << "Local map saving ended" << std::endl;
+               localdb->endSave();
+               delete localserver;
+       }
 }
 
 bool Client::isShutdown()
@@ -322,9 +336,14 @@ Client::~Client()
        }
 }
 
-void Client::connect(Address address)
+void Client::connect(Address address,
+               const std::string &address_name,
+               bool is_local_server)
 {
        DSTACK(__FUNCTION_NAME);
+
+       initLocalMapSaving(address, address_name, is_local_server);
+
        m_con.SetTimeoutMs(0);
        m_con.Connect(address);
 }
@@ -341,7 +360,7 @@ void Client::step(float dtime)
                m_ignore_damage_timer -= dtime;
        else
                m_ignore_damage_timer = 0.0;
-       
+
        m_animation_time += dtime;
        if(m_animation_time > 60.0)
                m_animation_time -= 60.0;
@@ -359,7 +378,7 @@ void Client::step(float dtime)
                if(counter <= 0.0)
                {
                        counter = 20.0;
-                       
+
                        infostream << "Client packetcounter (" << m_packetcounter_timer
                                        << "):"<<std::endl;
                        m_packetcounter.print(infostream);
@@ -375,7 +394,7 @@ void Client::step(float dtime)
                        NOTE: This jams the game for a while because deleting sectors
                              clear caches
                */
-               
+
                float &counter = m_delete_unused_sectors_timer;
                counter -= dtime;
                if(counter <= 0.0)
@@ -390,12 +409,12 @@ void Client::step(float dtime)
 
                        float delete_unused_sectors_timeout =
                                g_settings->getFloat("client_delete_unused_sectors_timeout");
-       
+
                        // Delete sector blocks
                        /*u32 num = m_env.getMap().unloadUnusedData
                                        (delete_unused_sectors_timeout,
                                        true, &deleted_blocks);*/
-                       
+
                        // Delete whole sectors
                        m_env.getMap().unloadUnusedData
                                        (delete_unused_sectors_timeout,
@@ -407,14 +426,14 @@ void Client::step(float dtime)
                                                <<" unused sectors"<<std::endl;*/
                                /*infostream<<"Client: Deleted "<<num
                                                <<" unused sectors"<<std::endl;*/
-                               
+
                                /*
                                        Send info to server
                                */
 
                                // Env is locked so con can be locked.
                                //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
-                               
+
                                core::list<v3s16>::Iterator i = deleted_blocks.begin();
                                core::list<v3s16> sendlist;
                                for(;;)
@@ -472,7 +491,7 @@ void Client::step(float dtime)
                        counter = 2.0;
 
                        //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
-                       
+
                        Player *myplayer = m_env.getLocalPlayer();
                        assert(myplayer != NULL);
                        // Send TOSERVER_INIT
@@ -494,7 +513,7 @@ void Client::step(float dtime)
 
                        memset((char*)&data[23], 0, PASSWORD_SIZE);
                        snprintf((char*)&data[23], PASSWORD_SIZE, "%s", m_password.c_str());
-                       
+
                        writeU16(&data[51], CLIENT_PROTOCOL_VERSION_MIN);
                        writeU16(&data[53], CLIENT_PROTOCOL_VERSION_MAX);
 
@@ -509,7 +528,7 @@ void Client::step(float dtime)
        /*
                Do stuff if connected
        */
-       
+
        /*
                Run Map's timers and unload unused data
        */
@@ -521,11 +540,11 @@ void Client::step(float dtime)
                m_env.getMap().timerUpdate(map_timer_and_unload_dtime,
                                g_settings->getFloat("client_unload_unused_data_timeout"),
                                &deleted_blocks);
-                               
+
                /*if(deleted_blocks.size() > 0)
                        infostream<<"Client: Unloaded "<<deleted_blocks.size()
                                        <<" unused blocks"<<std::endl;*/
-                       
+
                /*
                        Send info to server
                        NOTE: This loop is intentionally iterated the way it is.
@@ -537,7 +556,7 @@ void Client::step(float dtime)
                {
                        if(sendlist.size() == 255 || i == deleted_blocks.end())
                        {
-                               if(sendlist.size() == 0)
+                               if(sendlist.empty())
                                        break;
                                /*
                                        [0] u16 command
@@ -582,7 +601,7 @@ void Client::step(float dtime)
 
                // Step environment
                m_env.step(dtime);
-               
+
                /*
                        Get events
                */
@@ -598,7 +617,7 @@ void Client::step(float dtime)
                                if(m_ignore_damage_timer <= 0)
                                {
                                        u8 damage = event.player_damage.amount;
-                                       
+
                                        if(event.player_damage.send_to_server)
                                                sendDamage(damage);
 
@@ -748,7 +767,7 @@ void Client::step(float dtime)
                        m_sound->updateSoundPosition(client_id, pos);
                }
        }
-       
+
        /*
                Handle removed remotely initiated sounds
        */
@@ -773,7 +792,7 @@ void Client::step(float dtime)
                        }
                }
                // Sync to server
-               if(removed_server_ids.size() != 0)
+               if(!removed_server_ids.empty())
                {
                        std::ostringstream os(std::ios_base::binary);
                        writeU16(os, TOSERVER_REMOVED_SOUNDS);
@@ -795,7 +814,7 @@ bool Client::loadMedia(const std::string &data, const std::string &filename)
 {
        // Silly irrlicht's const-incorrectness
        Buffer<char> data_rw(data.c_str(), data.size());
-       
+
        std::string name;
 
        const char *image_ext[] = {
@@ -923,6 +942,41 @@ void Client::received_media()
                        <<std::endl;
 }
 
+void Client::initLocalMapSaving(const Address &address,
+               const std::string &hostname,
+               bool is_local_server)
+{
+       localdb = NULL;
+
+       if (!g_settings->getBool("enable_local_map_saving") || is_local_server)
+               return;
+
+       const std::string world_path = porting::path_user
+               + DIR_DELIM + "worlds"
+               + DIR_DELIM + "server_"
+               + hostname + "_" + to_string(address.getPort());
+
+       SubgameSpec gamespec;
+
+       if (!getWorldExists(world_path)) {
+               gamespec = findSubgame(g_settings->get("default_game"));
+               if (!gamespec.isValid())
+                       gamespec = findSubgame("minimal");
+       } else {
+               gamespec = findWorldSubgame(world_path);
+       }
+
+       if (!gamespec.isValid()) {
+               errorstream << "Couldn't find subgame for local map saving." << std::endl;
+               return;
+       }
+
+       localserver = new Server(world_path, gamespec, false, false);
+       localdb = new Database_SQLite3(&(ServerMap&)localserver->getMap(), world_path);
+       localdb->beginSave();
+       actionstream << "Local map saving started, map will be saved at '" << world_path << "'" << std::endl;
+}
+
 void Client::ReceiveAll()
 {
        DSTACK(__FUNCTION_NAME);
@@ -933,7 +987,7 @@ void Client::ReceiveAll()
                // process
                if(porting::getTimeMs() > start_ms + 100)
                        break;
-               
+
                try{
                        Receive();
                        g_profiler->graphAdd("client_received_packets", 1);
@@ -960,1004 +1014,1076 @@ void Client::Receive()
        ProcessData(*data, datasize, sender_peer_id);
 }
 
-/*
-       sender_peer_id given to this shall be quaranteed to be a valid peer
-*/
-void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
+void Client::handleCommand_Deprecated(ToClientPacket* pkt)
 {
-       DSTACK(__FUNCTION_NAME);
+       infostream << "Got deprecated command "
+                       << toClientCommandTable[pkt->getCommand()].name << " from peer "
+                       << pkt->getPeerId() << "!" << std::endl;
+}
 
-       // Ignore packets that don't even fit a command
-       if(datasize < 2)
-       {
-               m_packetcounter.add(60000);
+void Client::handleCommand_Init(ToClientPacket* pkt)
+{
+       if(pkt->getSize() < 1)
                return;
-       }
 
-       ToClientCommand command = (ToClientCommand)readU16(&data[0]);
+       u8 deployed;
+       *pkt >> deployed;
 
-       //infostream<<"Client: received command="<<command<<std::endl;
-       m_packetcounter.add((u16)command);
-       
-       /*
-               If this check is removed, be sure to change the queue
-               system to know the ids
-       */
-       if(sender_peer_id != PEER_ID_SERVER)
-       {
-               infostream<<"Client::ProcessData(): Discarding data not "
-                               "coming from server: peer_id="<<sender_peer_id
-                               <<std::endl;
+       infostream << "Client: TOCLIENT_INIT received with "
+                       "deployed=" << ((int)deployed & 0xff) << std::endl;
+
+       if(!ser_ver_supported(deployed)) {
+               infostream << "Client: TOCLIENT_INIT: Server sent "
+                               << "unsupported ser_fmt_ver"<< std::endl;
                return;
        }
 
-       u8 ser_version = m_server_ser_ver;
+       m_server_ser_ver = deployed;
 
-       if(command == TOCLIENT_INIT)
-       {
-               if(datasize < 3)
-                       return;
+       // Get player position
+       v3s16 playerpos_s16(0, BS * 2 + BS * 20, 0);
+       if(pkt->getSize() >= 1 + 6) {
+               *pkt >> playerpos_s16;
+       }
+       v3f playerpos_f = intToFloat(playerpos_s16, BS) - v3f(0, BS / 2, 0);
 
-               u8 deployed = data[2];
 
-               infostream<<"Client: TOCLIENT_INIT received with "
-                               "deployed="<<((int)deployed&0xff)<<std::endl;
+       // Set player position
+       Player *player = m_env.getLocalPlayer();
+       assert(player != NULL);
+       player->setPosition(playerpos_f);
 
-               if(!ser_ver_supported(deployed))
-               {
-                       infostream<<"Client: TOCLIENT_INIT: Server sent "
-                                       <<"unsupported ser_fmt_ver"<<std::endl;
-                       return;
-               }
-               
-               m_server_ser_ver = deployed;
+       if(pkt->getSize() >= 1 + 6 + 8) {
+               // Get map seed
+               *pkt >> m_map_seed;
+               infostream << "Client: received map seed: " << m_map_seed << std::endl;
+       }
 
-               // Get player position
-               v3s16 playerpos_s16(0, BS*2+BS*20, 0);
-               if(datasize >= 2+1+6)
-                       playerpos_s16 = readV3S16(&data[2+1]);
-               v3f playerpos_f = intToFloat(playerpos_s16, BS) - v3f(0, BS/2, 0);
+       if(pkt->getSize() >= 1 + 6 + 8 + 4) {
+               *pkt >> m_recommended_send_interval;
+               infostream << "Client: received recommended send interval "
+                               << m_recommended_send_interval<<std::endl;
+       }
 
-                       
-               // Set player position
-               Player *player = m_env.getLocalPlayer();
-               assert(player != NULL);
-               player->setPosition(playerpos_f);
-               
-               if(datasize >= 2+1+6+8)
-               {
-                       // Get map seed
-                       m_map_seed = readU64(&data[2+1+6]);
-                       infostream<<"Client: received map seed: "<<m_map_seed<<std::endl;
-               }
+       // Reply to server
+       u32 replysize = 2;
+       SharedBuffer<u8> reply(replysize);
+       writeU16(&reply[0], TOSERVER_INIT2);
+       // Send as reliable
+       m_con.Send(PEER_ID_SERVER, 1, reply, true);
 
-               if(datasize >= 2+1+6+8+4)
-               {
-                       // Get map seed
-                       m_recommended_send_interval = readF1000(&data[2+1+6+8]);
-                       infostream<<"Client: received recommended send interval "
-                                       <<m_recommended_send_interval<<std::endl;
-               }
-               
-               // Reply to server
-               u32 replysize = 2;
-               SharedBuffer<u8> reply(replysize);
-               writeU16(&reply[0], TOSERVER_INIT2);
-               // Send as reliable
-               m_con.Send(PEER_ID_SERVER, 1, reply, true);
+       m_state = LC_Init;
+}
 
-               m_state = LC_Init;
+void Client::handleCommand_AccessDenied(ToClientPacket* pkt)
+{
+       // The server didn't like our password. Note, this needs
+       // to be processed even if the serialisation format has
+       // not been agreed yet, the same as TOCLIENT_INIT.
+       m_access_denied = true;
+       m_access_denied_reason = L"Unknown";
+       if(pkt->getSize() >= 2) {
+               *pkt >> m_access_denied_reason;
+       }
+}
 
+void Client::handleCommand_RemoveNode(ToClientPacket* pkt)
+{
+       if(pkt->getSize() < 6)
                return;
-       }
 
-       if(command == TOCLIENT_ACCESS_DENIED)
-       {
-               // The server didn't like our password. Note, this needs
-               // to be processed even if the serialisation format has
-               // not been agreed yet, the same as TOCLIENT_INIT.
-               m_access_denied = true;
-               m_access_denied_reason = L"Unknown";
-               if(datasize >= 4)
-               {
-                       std::string datastring((char*)&data[2], datasize-2);
-                       std::istringstream is(datastring, std::ios_base::binary);
-                       m_access_denied_reason = deSerializeWideString(is);
-               }
+       v3s16 p;
+       *pkt >> p.X;
+       *pkt >> p.Y;
+       *pkt >> p.Z;
+       removeNode(p);
+}
+
+void Client::handleCommand_AddNode(ToClientPacket* pkt)
+{
+       if(pkt->getSize() < 6 + MapNode::serializedLength(m_server_ser_ver))
                return;
+
+       v3s16 p;
+       *pkt >> p.X;
+       *pkt >> p.Y;
+       *pkt >> p.Z;
+
+       MapNode n;
+       n.deSerialize(pkt->getU8Ptr(6), m_server_ser_ver);
+
+       bool remove_metadata = true;
+       u32 index = 6 + MapNode::serializedLength(m_server_ser_ver);
+       if ((pkt->getSize() >= index + 1) && pkt->getU8(index)) {
+               remove_metadata = false;
        }
 
-       if(ser_version == SER_FMT_VER_INVALID)
-       {
-               infostream<<"Client: Server serialization"
-                               " format invalid or not initialized."
-                               " Skipping incoming command="<<command<<std::endl;
+       addNode(p, n, remove_metadata);
+}
+void Client::handleCommand_BlockData(ToClientPacket* pkt)
+{
+       // Ignore too small packet
+       if(pkt->getSize() < 6)
                return;
+
+       v3s16 p;
+       *pkt >> p.X;
+       *pkt >> p.Y;
+       *pkt >> p.Z;
+
+       std::string datastring(pkt->getString(6), pkt->getSize() - 6);
+       std::istringstream istr(datastring, std::ios_base::binary);
+
+       MapSector *sector;
+       MapBlock *block;
+
+       v2s16 p2d(p.X, p.Z);
+       sector = m_env.getMap().emergeSector(p2d);
+
+       assert(sector->getPos() == p2d);
+
+       block = sector->getBlockNoCreateNoEx(p.Y);
+       if(block) {
+               /*
+                       Update an existing block
+               */
+               block->deSerialize(istr, m_server_ser_ver, false);
+               block->deSerializeNetworkSpecific(istr);
+       }
+       else {
+               /*
+                       Create a new block
+               */
+               block = new MapBlock(&m_env.getMap(), p, this);
+               block->deSerialize(istr, m_server_ser_ver, false);
+               block->deSerializeNetworkSpecific(istr);
+               sector->insertBlock(block);
        }
-       
+
+       if (localdb != NULL) {
+               ((ServerMap&) localserver->getMap()).saveBlock(block, localdb);
+       }
+
        /*
-         Handle runtime commands
+               Add it to mesh update queue and set it to be acknowledged after update.
        */
-       // there's no sane reason why we shouldn't have a player and
-       // almost everyone needs a player reference
+       addUpdateMeshTaskWithEdge(p, true);
+}
+
+void Client::handleCommand_Inventory(ToClientPacket* pkt)
+{
+       if(pkt->getSize() < 1)
+               return;
+
+       std::string datastring(pkt->getString(0), pkt->getSize());
+       std::istringstream is(datastring, std::ios_base::binary);
+
        Player *player = m_env.getLocalPlayer();
        assert(player != NULL);
 
-       if(command == TOCLIENT_REMOVENODE)
-       {
-               if(datasize < 8)
-                       return;
-               v3s16 p;
-               p.X = readS16(&data[2]);
-               p.Y = readS16(&data[4]);
-               p.Z = readS16(&data[6]);
-               removeNode(p);
-       }
-       else if(command == TOCLIENT_ADDNODE)
-       {
-               if(datasize < 8 + MapNode::serializedLength(ser_version))
-                       return;
+       player->inventory.deSerialize(is);
 
-               v3s16 p;
-               p.X = readS16(&data[2]);
-               p.Y = readS16(&data[4]);
-               p.Z = readS16(&data[6]);
-
-               MapNode n;
-               n.deSerialize(&data[8], ser_version);
-               
-               bool remove_metadata = true;
-               u32 index = 8 + MapNode::serializedLength(ser_version);
-               if ((datasize >= index+1) && data[index]){
-                       remove_metadata = false;
-               }
-               
-               addNode(p, n, remove_metadata);
+       m_inventory_updated = true;
+
+       delete m_inventory_from_server;
+       m_inventory_from_server = new Inventory(player->inventory);
+       m_inventory_from_server_age = 0.0;
+}
+
+void Client::handleCommand_TimeOfDay(ToClientPacket* pkt)
+{
+       if(pkt->getSize() < 2)
+               return;
+
+       u16 time_of_day;
+
+       *pkt >> time_of_day;
+
+       time_of_day      = time_of_day % 24000;
+       float time_speed = 0;
+
+       if(pkt->getSize() >= 2 + 4) {
+               *pkt >> time_speed;
        }
-       else if(command == TOCLIENT_BLOCKDATA)
-       {
-               // Ignore too small packet
-               if(datasize < 8)
-                       return;
-                       
-               v3s16 p;
-               p.X = readS16(&data[2]);
-               p.Y = readS16(&data[4]);
-               p.Z = readS16(&data[6]);
-               
-               std::string datastring((char*)&data[8], datasize-8);
-               std::istringstream istr(datastring, std::ios_base::binary);
-               
-               MapSector *sector;
-               MapBlock *block;
-               
-               v2s16 p2d(p.X, p.Z);
-               sector = m_env.getMap().emergeSector(p2d);
-               
-               assert(sector->getPos() == p2d);
-               
-               block = sector->getBlockNoCreateNoEx(p.Y);
-               if(block)
-               {
-                       /*
-                               Update an existing block
-                       */
-                       block->deSerialize(istr, ser_version, false);
-                       block->deSerializeNetworkSpecific(istr);
-               }
+       else {
+               // Old message; try to approximate speed of time by ourselves
+               float time_of_day_f = (float)time_of_day / 24000.0;
+               float tod_diff_f = 0;
+
+               if(time_of_day_f < 0.2 && m_last_time_of_day_f > 0.8)
+                       tod_diff_f = time_of_day_f - m_last_time_of_day_f + 1.0;
                else
-               {
-                       /*
-                               Create a new block
-                       */
-                       block = new MapBlock(&m_env.getMap(), p, this);
-                       block->deSerialize(istr, ser_version, false);
-                       block->deSerializeNetworkSpecific(istr);
-                       sector->insertBlock(block);
-               }
+                       tod_diff_f = time_of_day_f - m_last_time_of_day_f;
 
-               /*
-                       Add it to mesh update queue and set it to be acknowledged after update.
-               */
-               addUpdateMeshTaskWithEdge(p, true);
+               m_last_time_of_day_f       = time_of_day_f;
+               float time_diff            = m_time_of_day_update_timer;
+               m_time_of_day_update_timer = 0;
+
+               if(m_time_of_day_set){
+                       time_speed = (3600.0 * 24.0) * tod_diff_f / time_diff;
+                       infostream << "Client: Measured time_of_day speed (old format): "
+                                       << time_speed << " tod_diff_f=" << tod_diff_f
+                                       << " time_diff=" << time_diff << std::endl;
+               }
        }
-       else if(command == TOCLIENT_INVENTORY)
-       {
-               if(datasize < 3)
-                       return;
 
-               std::string datastring((char*)&data[2], datasize-2);
-               std::istringstream is(datastring, std::ios_base::binary);
+       // Update environment
+       m_env.setTimeOfDay(time_of_day);
+       m_env.setTimeOfDaySpeed(time_speed);
+       m_time_of_day_set = true;
 
-               player->inventory.deSerialize(is);
+       u32 dr = m_env.getDayNightRatio();
+       infostream << "Client: time_of_day=" << time_of_day
+                       << " time_speed=" << time_speed
+                       << " dr=" << dr << std::endl;
+}
 
-               m_inventory_updated = true;
+void Client::handleCommand_ChatMessage(ToClientPacket* pkt)
+{
+       /*
+               u16 command
+               u16 length
+               wstring message
+       */
+       u16 len, read_wchar;
 
-               delete m_inventory_from_server;
-               m_inventory_from_server = new Inventory(player->inventory);
-               m_inventory_from_server_age = 0.0;
+       *pkt >> len;
 
+       std::wstring message;
+       for(unsigned int i=0; i<len; i++) {
+               *pkt >> read_wchar;
+               message += (wchar_t)read_wchar;
        }
-       else if(command == TOCLIENT_TIME_OF_DAY)
-       {
-               if(datasize < 4)
-                       return;
-               
-               u16 time_of_day  = readU16(&data[2]);
-               time_of_day      = time_of_day % 24000;
-               float time_speed = 0;
 
-               if(datasize >= 2 + 2 + 4)
-               {
-                       time_speed = readF1000(&data[4]);
-               }
-               else {
-                       // Old message; try to approximate speed of time by ourselves
-                       float time_of_day_f = (float)time_of_day / 24000.0;
-                       float tod_diff_f = 0;
-
-                       if(time_of_day_f < 0.2 && m_last_time_of_day_f > 0.8)
-                               tod_diff_f = time_of_day_f - m_last_time_of_day_f + 1.0;
-                       else
-                               tod_diff_f = time_of_day_f - m_last_time_of_day_f;
-
-                       m_last_time_of_day_f         = time_of_day_f;
-                       float time_diff            = m_time_of_day_update_timer;
-                       m_time_of_day_update_timer = 0;
-
-                       if(m_time_of_day_set){
-                               time_speed = (3600.0*24.0) * tod_diff_f / time_diff;
-                               infostream<<"Client: Measured time_of_day speed (old format): "
-                                               <<time_speed<<" tod_diff_f="<<tod_diff_f
-                                               <<" time_diff="<<time_diff<<std::endl;
-                       }
+       m_chat_queue.push_back(message);
+}
+
+void Client::handleCommand_ActiveObjectRemoveAdd(ToClientPacket* pkt)
+{
+       /*
+               u16 command
+               u16 count of removed objects
+               for all removed objects {
+                       u16 id
                }
-               
-               // Update environment
-               m_env.setTimeOfDay(time_of_day);
-               m_env.setTimeOfDaySpeed(time_speed);
-               m_time_of_day_set = true;
-
-               u32 dr = m_env.getDayNightRatio();
-               infostream<<"Client: time_of_day="<<time_of_day
-                               <<" time_speed="<<time_speed
-                               <<" dr="<<dr<<std::endl;
-       }
-       else if(command == TOCLIENT_CHAT_MESSAGE)
-       {
-               /*
-                       u16 command
-                       u16 length
-                       wstring message
-               */
-               u8 buf[6];
-               std::string datastring((char*)&data[2], datasize-2);
-               std::istringstream is(datastring, std::ios_base::binary);
-               
-               // Read stuff
-               is.read((char*) buf, 2);
-               u16 len = readU16(buf);
-               
-               std::wstring message;
-               for(unsigned int i=0; i<len; i++)
-               {
-                       is.read((char*)buf, 2);
-                       message += (wchar_t)readU16(buf);
+               u16 count of added objects
+               for all added objects {
+                       u16 id
+                       u8 type
+                       u32 initialization data length
+                       string initialization data
                }
-               
-               m_chat_queue.push_back(message);
+       */
+
+       // Read removed objects
+       u8 type;
+       u16 removed_count, added_count, id;
+
+       *pkt >> removed_count;
+
+       for(u16 i=0; i<removed_count; i++) {
+               *pkt >> id;
+               m_env.removeActiveObject(id);
        }
-       else if(command == TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD)
-       {
-               /*
-                       u16 command
-                       u16 count of removed objects
-                       for all removed objects {
-                               u16 id
-                       }
-                       u16 count of added objects
-                       for all added objects {
-                               u16 id
-                               u8 type
-                               u32 initialization data length
-                               string initialization data
-                       }
-               */
 
-               char buf[6];
-               // Get all data except the command number
-               std::string datastring((char*)&data[2], datasize-2);
-               // Throw them in an istringstream
-               std::istringstream is(datastring, std::ios_base::binary);
+       // Read added objects
+       *pkt >> added_count;
 
-               // Read removed objects
-               is.read(buf, 2);
-               u16 removed_count = readU16((u8*)buf);
-               for(unsigned int i=0; i<removed_count; i++)
+       for(u16 i=0; i<added_count; i++) {
+               *pkt >> id >> type;
+               m_env.addActiveObject(id, type, pkt->readLongString());
+       }
+}
+
+void Client::handleCommand_ActiveObjectMessages(ToClientPacket* pkt)
+{
+       /*
+               u16 command
+               for all objects
                {
-                       is.read(buf, 2);
-                       u16 id = readU16((u8*)buf);
-                       m_env.removeActiveObject(id);
+                       u16 id
+                       u16 message length
+                       string message
                }
+       */
+       char buf[6];
+       // Get all data except the command number
+       std::string datastring(pkt->getString(0), pkt->getSize());
+       // Throw them in an istringstream
+       std::istringstream is(datastring, std::ios_base::binary);
 
-               // Read added objects
+       while(is.eof() == false) {
+               is.read(buf, 2);
+               u16 id = readU16((u8*)buf);
+               if(is.eof())
+                       break;
                is.read(buf, 2);
-               u16 added_count = readU16((u8*)buf);
-               for(unsigned int i=0; i<added_count; i++)
+               size_t message_size = readU16((u8*)buf);
+               std::string message;
+               message.reserve(message_size);
+               for(unsigned int i=0; i<message_size; i++)
                {
-                       is.read(buf, 2);
-                       u16 id = readU16((u8*)buf);
                        is.read(buf, 1);
-                       u8 type = readU8((u8*)buf);
-                       std::string data = deSerializeLongString(is);
-                       // Add it
-                       m_env.addActiveObject(id, type, data);
+                       message.append(buf, 1);
                }
+               // Pass on to the environment
+               m_env.processActiveObjectMessage(id, message);
        }
-       else if(command == TOCLIENT_ACTIVE_OBJECT_MESSAGES)
-       {
-               /*
-                       u16 command
-                       for all objects
-                       {
-                               u16 id
-                               u16 message length
-                               string message
-                       }
-               */
-               char buf[6];
-               // Get all data except the command number
-               std::string datastring((char*)&data[2], datasize-2);
-               // Throw them in an istringstream
-               std::istringstream is(datastring, std::ios_base::binary);
+}
 
-               while(is.eof() == false)
-               {
-                       is.read(buf, 2);
-                       u16 id = readU16((u8*)buf);
-                       if(is.eof())
-                               break;
-                       is.read(buf, 2);
-                       size_t message_size = readU16((u8*)buf);
-                       std::string message;
-                       message.reserve(message_size);
-                       for(unsigned int i=0; i<message_size; i++)
-                       {
-                               is.read(buf, 1);
-                               message.append(buf, 1);
-                       }
-                       // Pass on to the environment
-                       m_env.processActiveObjectMessage(id, message);
-               }
-       }
-       else if(command == TOCLIENT_MOVEMENT)
-       {
-               std::string datastring((char*)&data[2], datasize-2);
-               std::istringstream is(datastring, std::ios_base::binary);
-
-               player->movement_acceleration_default   = readF1000(is) * BS;
-               player->movement_acceleration_air       = readF1000(is) * BS;
-               player->movement_acceleration_fast      = readF1000(is) * BS;
-               player->movement_speed_walk             = readF1000(is) * BS;
-               player->movement_speed_crouch           = readF1000(is) * BS;
-               player->movement_speed_fast             = readF1000(is) * BS;
-               player->movement_speed_climb            = readF1000(is) * BS;
-               player->movement_speed_jump             = readF1000(is) * BS;
-               player->movement_liquid_fluidity        = readF1000(is) * BS;
-               player->movement_liquid_fluidity_smooth = readF1000(is) * BS;
-               player->movement_liquid_sink            = readF1000(is) * BS;
-               player->movement_gravity                = readF1000(is) * BS;
-       }
-       else if(command == TOCLIENT_HP)
-       {
-               std::string datastring((char*)&data[2], datasize-2);
-               std::istringstream is(datastring, std::ios_base::binary);
+void Client::handleCommand_Movement(ToClientPacket* pkt)
+{
+       Player *player = m_env.getLocalPlayer();
+       assert(player != NULL);
 
-               u8 oldhp   = player->hp;
-               u8 hp      = readU8(is);
-               player->hp = hp;
+       float mad, maa, maf, msw, mscr, msf, mscl, msj, lf, lfs, ls, g;
 
-               if(hp < oldhp)
-               {
-                       // Add to ClientEvent queue
-                       ClientEvent event;
-                       event.type = CE_PLAYER_DAMAGE;
-                       event.player_damage.amount = oldhp - hp;
-                       m_client_event_queue.push_back(event);
-               }
-       }
-       else if(command == TOCLIENT_BREATH)
-       {
-               std::string datastring((char*)&data[2], datasize-2);
-               std::istringstream is(datastring, std::ios_base::binary);
+       *pkt >> mad >> maa >> maf >> msw >> mscr >> msf >> mscl >> msj
+               >> lf >> lfs >> ls >> g;
 
-               player->setBreath(readU16(is));
-       }
-       else if(command == TOCLIENT_MOVE_PLAYER)
-       {
-               std::string datastring((char*)&data[2], datasize-2);
-               std::istringstream is(datastring, std::ios_base::binary);
-
-               v3f pos = readV3F1000(is);
-               f32 pitch = readF1000(is);
-               f32 yaw = readF1000(is);
-               player->setPosition(pos);
-
-               infostream<<"Client got TOCLIENT_MOVE_PLAYER"
-                               <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
-                               <<" pitch="<<pitch
-                               <<" yaw="<<yaw
-                               <<std::endl;
+       player->movement_acceleration_default   = mad * BS;
+       player->movement_acceleration_air       = maa * BS;
+       player->movement_acceleration_fast      = maf * BS;
+       player->movement_speed_walk             = msw * BS;
+       player->movement_speed_crouch           = mscr * BS;
+       player->movement_speed_fast             = msf * BS;
+       player->movement_speed_climb            = mscl * BS;
+       player->movement_speed_jump             = msj * BS;
+       player->movement_liquid_fluidity        = lf * BS;
+       player->movement_liquid_fluidity_smooth = lfs * BS;
+       player->movement_liquid_sink            = ls * BS;
+       player->movement_gravity                = g * BS;
+}
 
-               /*
-                       Add to ClientEvent queue.
-                       This has to be sent to the main program because otherwise
-                       it would just force the pitch and yaw values to whatever
-                       the camera points to.
-               */
-               ClientEvent event;
-               event.type = CE_PLAYER_FORCE_MOVE;
-               event.player_force_move.pitch = pitch;
-               event.player_force_move.yaw = yaw;
-               m_client_event_queue.push_back(event);
+void Client::handleCommand_HP(ToClientPacket* pkt)
+{
 
-               // Ignore damage for a few seconds, so that the player doesn't
-               // get damage from falling on ground
-               m_ignore_damage_timer = 3.0;
-       }
-       else if(command == TOCLIENT_PLAYERITEM)
-       {
-               infostream<<"Client: WARNING: Ignoring TOCLIENT_PLAYERITEM"<<std::endl;
-       }
-       else if(command == TOCLIENT_DEATHSCREEN)
-       {
-               std::string datastring((char*)&data[2], datasize-2);
-               std::istringstream is(datastring, std::ios_base::binary);
-               
-               bool set_camera_point_target = readU8(is);
-               v3f camera_point_target = readV3F1000(is);
-               
+       Player *player = m_env.getLocalPlayer();
+       assert(player != NULL);
+
+       u8 oldhp   = player->hp;
+
+       u8 hp;
+       *pkt >> hp;
+
+       player->hp = hp;
+
+       if(hp < oldhp) {
+               // Add to ClientEvent queue
                ClientEvent event;
-               event.type                                = CE_DEATHSCREEN;
-               event.deathscreen.set_camera_point_target = set_camera_point_target;
-               event.deathscreen.camera_point_target_x   = camera_point_target.X;
-               event.deathscreen.camera_point_target_y   = camera_point_target.Y;
-               event.deathscreen.camera_point_target_z   = camera_point_target.Z;
+               event.type = CE_PLAYER_DAMAGE;
+               event.player_damage.amount = oldhp - hp;
                m_client_event_queue.push_back(event);
        }
-       else if(command == TOCLIENT_ANNOUNCE_MEDIA)
-       {
-               std::string datastring((char*)&data[2], datasize-2);
-               std::istringstream is(datastring, std::ios_base::binary);
-
-               int num_files = readU16(is);
-               
-               infostream<<"Client: Received media announcement: packet size: "
-                               <<datasize<<std::endl;
-
-               if (m_media_downloader == NULL ||
-                               m_media_downloader->isStarted()) {
-                       const char *problem = m_media_downloader ?
-                               "we already saw another announcement" :
-                               "all media has been received already";
-                       errorstream<<"Client: Received media announcement but "
-                               <<problem<<"! "
-                               <<" files="<<num_files
-                               <<" size="<<datasize<<std::endl;
-                       return;
-               }
+}
 
-               // Mesh update thread must be stopped while
-               // updating content definitions
-               assert(!m_mesh_update_thread.IsRunning());
+void Client::handleCommand_Breath(ToClientPacket* pkt)
+{
+       Player *player = m_env.getLocalPlayer();
+       assert(player != NULL);
 
-               for(int i=0; i<num_files; i++)
-               {
-                       std::string name = deSerializeString(is);
-                       std::string sha1_base64 = deSerializeString(is);
-                       std::string sha1_raw = base64_decode(sha1_base64);
-                       m_media_downloader->addFile(name, sha1_raw);
-               }
+       u16 breath;
 
-               std::vector<std::string> remote_media;
-               try {
-                       Strfnd sf(deSerializeString(is));
-                       while(!sf.atend()) {
-                               std::string baseurl = trim(sf.next(","));
-                               if(baseurl != "")
-                                       m_media_downloader->addRemoteServer(baseurl);
-                       }
-               }
-               catch(SerializationError& e) {
-                       // not supported by server or turned off
-               }
+       *pkt >> breath;
 
-               m_media_downloader->step(this);
+       player->setBreath(breath);
+}
+
+void Client::handleCommand_MovePlayer(ToClientPacket* pkt)
+{
+       Player *player = m_env.getLocalPlayer();
+       assert(player != NULL);
+
+       v3f pos;
+       f32 pitch, yaw;
+
+       *pkt >> pos >> pitch >> yaw;
+
+       player->setPosition(pos);
+
+       infostream << "Client got TOCLIENT_MOVE_PLAYER"
+                       << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
+                       << " pitch=" << pitch
+                       << " yaw=" << yaw
+                       << std::endl;
+
+       /*
+               Add to ClientEvent queue.
+               This has to be sent to the main program because otherwise
+               it would just force the pitch and yaw values to whatever
+               the camera points to.
+       */
+       ClientEvent event;
+       event.type = CE_PLAYER_FORCE_MOVE;
+       event.player_force_move.pitch = pitch;
+       event.player_force_move.yaw = yaw;
+       m_client_event_queue.push_back(event);
+
+       // Ignore damage for a few seconds, so that the player doesn't
+       // get damage from falling on ground
+       m_ignore_damage_timer = 3.0;
+}
+
+void Client::handleCommand_PlayerItem(ToClientPacket* pkt)
+{
+       infostream << "Client: WARNING: Ignoring TOCLIENT_PLAYERITEM" << std::endl;
+}
+
+void Client::handleCommand_DeathScreen(ToClientPacket* pkt)
+{
+       bool set_camera_point_target;
+       v3f camera_point_target;
+
+       *pkt >> set_camera_point_target;
+       *pkt >> camera_point_target;
+
+       ClientEvent event;
+       event.type                                = CE_DEATHSCREEN;
+       event.deathscreen.set_camera_point_target = set_camera_point_target;
+       event.deathscreen.camera_point_target_x   = camera_point_target.X;
+       event.deathscreen.camera_point_target_y   = camera_point_target.Y;
+       event.deathscreen.camera_point_target_z   = camera_point_target.Z;
+       m_client_event_queue.push_back(event);
+}
+
+void Client::handleCommand_AnnounceMedia(ToClientPacket* pkt)
+{
+       u16 num_files;
+
+       *pkt >> num_files;
+
+       infostream << "Client: Received media announcement: packet size: "
+                       << pkt->getSize() << std::endl;
+
+       if (m_media_downloader == NULL ||
+                       m_media_downloader->isStarted()) {
+               const char *problem = m_media_downloader ?
+                       "we already saw another announcement" :
+                       "all media has been received already";
+               errorstream << "Client: Received media announcement but "
+                       << problem << "! "
+                       << " files=" << num_files
+                       << " size=" << pkt->getSize() << std::endl;
+               return;
        }
-       else if(command == TOCLIENT_MEDIA)
-       {
-               std::string datastring((char*)&data[2], datasize-2);
-               std::istringstream is(datastring, std::ios_base::binary);
 
-               /*
-                       u16 command
-                       u16 total number of file bunches
-                       u16 index of this bunch
-                       u32 number of files in this bunch
-                       for each file {
-                               u16 length of name
-                               string name
-                               u32 length of data
-                               data
-                       }
-               */
-               int num_bunches = readU16(is);
-               int bunch_i = readU16(is);
-               u32 num_files = readU32(is);
-               infostream<<"Client: Received files: bunch "<<bunch_i<<"/"
-                               <<num_bunches<<" files="<<num_files
-                               <<" size="<<datasize<<std::endl;
-
-               if (num_files == 0)
-                       return;
+       // Mesh update thread must be stopped while
+       // updating content definitions
+       assert(!m_mesh_update_thread.IsRunning());
 
-               if (m_media_downloader == NULL ||
-                               !m_media_downloader->isStarted()) {
-                       const char *problem = m_media_downloader ?
-                               "media has not been requested" :
-                               "all media has been received already";
-                       errorstream<<"Client: Received media but "
-                               <<problem<<"! "
-                               <<" bunch "<<bunch_i<<"/"<<num_bunches
-                               <<" files="<<num_files
-                               <<" size="<<datasize<<std::endl;
-                       return;
-               }
+       for(int i=0; i<num_files; i++) {
+               std::string name, sha1_base64;
+
+               *pkt >> name >> sha1_base64;
+
+               std::string sha1_raw = base64_decode(sha1_base64);
+               m_media_downloader->addFile(name, sha1_raw);
+       }
+
+       std::vector<std::string> remote_media;
+       try {
+               std::string str;
 
-               // Mesh update thread must be stopped while
-               // updating content definitions
-               assert(!m_mesh_update_thread.IsRunning());
+               *pkt >> str;
 
-               for(unsigned int i=0; i<num_files; i++){
-                       std::string name = deSerializeString(is);
-                       std::string data = deSerializeLongString(is);
-                       m_media_downloader->conventionalTransferDone(
-                                       name, data, this);
+               Strfnd sf(str);
+               while(!sf.atend()) {
+                       std::string baseurl = trim(sf.next(","));
+                       if(baseurl != "")
+                               m_media_downloader->addRemoteServer(baseurl);
                }
        }
-       else if(command == TOCLIENT_TOOLDEF)
-       {
-               infostream<<"Client: WARNING: Ignoring TOCLIENT_TOOLDEF"<<std::endl;
+       catch(SerializationError& e) {
+               // not supported by server or turned off
        }
-       else if(command == TOCLIENT_NODEDEF)
-       {
-               infostream<<"Client: Received node definitions: packet size: "
-                               <<datasize<<std::endl;
-
-               // Mesh update thread must be stopped while
-               // updating content definitions
-               assert(!m_mesh_update_thread.IsRunning());
-
-               // Decompress node definitions
-               std::string datastring((char*)&data[2], datasize-2);
-               std::istringstream is(datastring, std::ios_base::binary);
-               std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
-               std::ostringstream tmp_os;
-               decompressZlib(tmp_is, tmp_os);
-
-               // Deserialize node definitions
-               std::istringstream tmp_is2(tmp_os.str());
-               m_nodedef->deSerialize(tmp_is2);
-               m_nodedef_received = true;
-       }
-       else if(command == TOCLIENT_CRAFTITEMDEF)
-       {
-               infostream<<"Client: WARNING: Ignoring TOCLIENT_CRAFTITEMDEF"<<std::endl;
+
+       m_media_downloader->step(this);
+}
+
+void Client::handleCommand_Media(ToClientPacket* pkt)
+{
+       /*
+               u16 command
+               u16 total number of file bunches
+               u16 index of this bunch
+               u32 number of files in this bunch
+               for each file {
+                       u16 length of name
+                       string name
+                       u32 length of data
+                       data
+               }
+       */
+       u16 num_bunches;
+       u16 bunch_i;
+       u32 num_files;
+
+       *pkt >> num_bunches >> bunch_i >> num_files;
+
+       infostream << "Client: Received files: bunch " << bunch_i << "/"
+                       << num_bunches << " files=" << num_files
+                       << " size=" << pkt->getSize() << std::endl;
+
+       if (num_files == 0)
+               return;
+
+       if (m_media_downloader == NULL ||
+                       !m_media_downloader->isStarted()) {
+               const char *problem = m_media_downloader ?
+                       "media has not been requested" :
+                       "all media has been received already";
+               errorstream << "Client: Received media but "
+                       << problem << "! "
+                       << " bunch " << bunch_i << "/" << num_bunches
+                       << " files=" << num_files
+                       << " size=" << pkt->getSize() << std::endl;
+               return;
        }
-       else if(command == TOCLIENT_ITEMDEF)
-       {
-               infostream<<"Client: Received item definitions: packet size: "
-                               <<datasize<<std::endl;
-
-               // Mesh update thread must be stopped while
-               // updating content definitions
-               assert(!m_mesh_update_thread.IsRunning());
-
-               // Decompress item definitions
-               std::string datastring((char*)&data[2], datasize-2);
-               std::istringstream is(datastring, std::ios_base::binary);
-               std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
-               std::ostringstream tmp_os;
-               decompressZlib(tmp_is, tmp_os);
-
-               // Deserialize node definitions
-               std::istringstream tmp_is2(tmp_os.str());
-               m_itemdef->deSerialize(tmp_is2);
-               m_itemdef_received = true;
-       }
-       else if(command == TOCLIENT_PLAY_SOUND)
-       {
-               std::string datastring((char*)&data[2], datasize-2);
-               std::istringstream is(datastring, std::ios_base::binary);
-
-               s32 server_id = readS32(is);
-               std::string name = deSerializeString(is);
-               float gain = readF1000(is);
-               int type = readU8(is); // 0=local, 1=positional, 2=object
-               v3f pos = readV3F1000(is);
-               u16 object_id = readU16(is);
-               bool loop = readU8(is);
-               // Start playing
-               int client_id = -1;
-               switch(type){
+
+       // Mesh update thread must be stopped while
+       // updating content definitions
+       assert(!m_mesh_update_thread.IsRunning());
+
+       for(unsigned int i=0; i<num_files; i++) {
+               std::string name;
+
+               *pkt >> name;
+
+               std::string data = pkt->readLongString();
+
+               m_media_downloader->conventionalTransferDone(
+                               name, data, this);
+       }
+}
+
+void Client::handleCommand_ToolDef(ToClientPacket* pkt)
+{
+       infostream << "Client: WARNING: Ignoring TOCLIENT_TOOLDEF" << std::endl;
+}
+
+void Client::handleCommand_NodeDef(ToClientPacket* pkt)
+{
+       infostream << "Client: Received node definitions: packet size: "
+                       << pkt->getSize() << std::endl;
+
+       // Mesh update thread must be stopped while
+       // updating content definitions
+       assert(!m_mesh_update_thread.IsRunning());
+
+       // Decompress node definitions
+       std::string datastring(pkt->getString(0), pkt->getSize());
+       std::istringstream is(datastring, std::ios_base::binary);
+       std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
+       std::ostringstream tmp_os;
+       decompressZlib(tmp_is, tmp_os);
+
+       // Deserialize node definitions
+       std::istringstream tmp_is2(tmp_os.str());
+       m_nodedef->deSerialize(tmp_is2);
+       m_nodedef_received = true;
+}
+
+void Client::handleCommand_CraftItemDef(ToClientPacket* pkt)
+{
+       infostream << "Client: WARNING: Ignoring TOCLIENT_CRAFTITEMDEF" << std::endl;
+}
+
+void Client::handleCommand_ItemDef(ToClientPacket* pkt)
+{
+       infostream << "Client: Received item definitions: packet size: "
+                       << pkt->getSize() << std::endl;
+
+       // Mesh update thread must be stopped while
+       // updating content definitions
+       assert(!m_mesh_update_thread.IsRunning());
+
+       // Decompress item definitions
+       std::string datastring(pkt->getString(0), pkt->getSize());
+       std::istringstream is(datastring, std::ios_base::binary);
+       std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
+       std::ostringstream tmp_os;
+       decompressZlib(tmp_is, tmp_os);
+
+       // Deserialize node definitions
+       std::istringstream tmp_is2(tmp_os.str());
+       m_itemdef->deSerialize(tmp_is2);
+       m_itemdef_received = true;
+}
+
+void Client::handleCommand_PlaySound(ToClientPacket* pkt)
+{
+       s32 server_id;
+       std::string name;
+       float gain;
+       u8 type; // 0=local, 1=positional, 2=object
+       v3f pos;
+       u16 object_id;
+       bool loop;
+
+       *pkt >> server_id >> name >> gain >> type >> pos >> object_id >> loop;
+
+       // Start playing
+       int client_id = -1;
+       switch(type) {
                case 0: // local
                        client_id = m_sound->playSound(name, loop, gain);
                        break;
                case 1: // positional
                        client_id = m_sound->playSoundAt(name, loop, gain, pos);
                        break;
-               case 2: { // object
+               case 2:
+               { // object
                        ClientActiveObject *cao = m_env.getActiveObject(object_id);
                        if(cao)
                                pos = cao->getPosition();
                        client_id = m_sound->playSoundAt(name, loop, gain, pos);
                        // TODO: Set up sound to move with object
-                       break; }
-               default:
                        break;
                }
-               if(client_id != -1){
-                       m_sounds_server_to_client[server_id] = client_id;
-                       m_sounds_client_to_server[client_id] = server_id;
-                       if(object_id != 0)
-                               m_sounds_to_objects[client_id] = object_id;
-               }
+               default:
+                       break;
        }
-       else if(command == TOCLIENT_STOP_SOUND)
-       {
-               std::string datastring((char*)&data[2], datasize-2);
-               std::istringstream is(datastring, std::ios_base::binary);
 
-               s32 server_id = readS32(is);
-               std::map<s32, int>::iterator i =
-                               m_sounds_server_to_client.find(server_id);
-               if(i != m_sounds_server_to_client.end()){
-                       int client_id = i->second;
-                       m_sound->stopSound(client_id);
-               }
-       }
-       else if(command == TOCLIENT_PRIVILEGES)
-       {
-               std::string datastring((char*)&data[2], datasize-2);
-               std::istringstream is(datastring, std::ios_base::binary);
-               
-               m_privileges.clear();
-               infostream<<"Client: Privileges updated: ";
-               u16 num_privileges = readU16(is);
-               for(unsigned int i=0; i<num_privileges; i++){
-                       std::string priv = deSerializeString(is);
-                       m_privileges.insert(priv);
-                       infostream<<priv<<" ";
-               }
-               infostream<<std::endl;
+       if(client_id != -1) {
+               m_sounds_server_to_client[server_id] = client_id;
+               m_sounds_client_to_server[client_id] = server_id;
+               if(object_id != 0)
+                       m_sounds_to_objects[client_id] = object_id;
        }
-       else if(command == TOCLIENT_INVENTORY_FORMSPEC)
-       {
-               std::string datastring((char*)&data[2], datasize-2);
-               std::istringstream is(datastring, std::ios_base::binary);
+}
 
-               // Store formspec in LocalPlayer
-               player->inventory_formspec = deSerializeLongString(is);
-       }
-       else if(command == TOCLIENT_DETACHED_INVENTORY)
-       {
-               std::string datastring((char*)&data[2], datasize-2);
-               std::istringstream is(datastring, std::ios_base::binary);
-
-               std::string name = deSerializeString(is);
-               
-               infostream<<"Client: Detached inventory update: \""<<name<<"\""<<std::endl;
-
-               Inventory *inv = NULL;
-               if(m_detached_inventories.count(name) > 0)
-                       inv = m_detached_inventories[name];
-               else{
-                       inv = new Inventory(m_itemdef);
-                       m_detached_inventories[name] = inv;
-               }
-               inv->deSerialize(is);
-       }
-       else if(command == TOCLIENT_SHOW_FORMSPEC)
-       {
-               std::string datastring((char*)&data[2], datasize-2);
-               std::istringstream is(datastring, std::ios_base::binary);
+void Client::handleCommand_StopSound(ToClientPacket* pkt)
+{
+       s32 server_id;
 
-               std::string formspec = deSerializeLongString(is);
-               std::string formname = deSerializeString(is);
+       *pkt >> server_id;
 
-               ClientEvent event;
-               event.type = CE_SHOW_FORMSPEC;
-               // pointer is required as event is a struct only!
-               // adding a std:string to a struct isn't possible
-               event.show_formspec.formspec = new std::string(formspec);
-               event.show_formspec.formname = new std::string(formname);
-               m_client_event_queue.push_back(event);
+       std::map<s32, int>::iterator i =
+               m_sounds_server_to_client.find(server_id);
+
+       if(i != m_sounds_server_to_client.end()) {
+               int client_id = i->second;
+               m_sound->stopSound(client_id);
        }
-       else if(command == TOCLIENT_SPAWN_PARTICLE)
-       {
-               std::string datastring((char*)&data[2], datasize-2);
-               std::istringstream is(datastring, std::ios_base::binary);
-
-               v3f pos                 = readV3F1000(is);
-               v3f vel                 = readV3F1000(is);
-               v3f acc                 = readV3F1000(is);
-               float expirationtime    = readF1000(is);
-               float size              = readF1000(is);
-               bool collisiondetection = readU8(is);
-               std::string texture     = deSerializeLongString(is);
-               bool vertical           = false;
-               try {
-                       vertical = readU8(is);
-               } catch (...) {}
+}
 
-               ClientEvent event;
-               event.type                              = CE_SPAWN_PARTICLE;
-               event.spawn_particle.pos                = new v3f (pos);
-               event.spawn_particle.vel                = new v3f (vel);
-               event.spawn_particle.acc                = new v3f (acc);
-               event.spawn_particle.expirationtime     = expirationtime;
-               event.spawn_particle.size               = size;
-               event.spawn_particle.collisiondetection = collisiondetection;
-               event.spawn_particle.vertical           = vertical;
-               event.spawn_particle.texture            = new std::string(texture);
+void Client::handleCommand_Privileges(ToClientPacket* pkt)
+{
+       m_privileges.clear();
+       infostream << "Client: Privileges updated: ";
+       u16 num_privileges;
 
-               m_client_event_queue.push_back(event);
-       }
-       else if(command == TOCLIENT_ADD_PARTICLESPAWNER)
-       {
-               std::string datastring((char*)&data[2], datasize-2);
-               std::istringstream is(datastring, std::ios_base::binary);
-
-               u16 amount              = readU16(is);
-               float spawntime         = readF1000(is);
-               v3f minpos              = readV3F1000(is);
-               v3f maxpos              = readV3F1000(is);
-               v3f minvel              = readV3F1000(is);
-               v3f maxvel              = readV3F1000(is);
-               v3f minacc              = readV3F1000(is);
-               v3f maxacc              = readV3F1000(is);
-               float minexptime        = readF1000(is);
-               float maxexptime        = readF1000(is);
-               float minsize           = readF1000(is);
-               float maxsize           = readF1000(is);
-               bool collisiondetection = readU8(is);
-               std::string texture     = deSerializeLongString(is);
-               u32 id                  = readU32(is);
-               bool vertical = false;
-               try {
-                       vertical = readU8(is);
-               } catch (...) {}
+       *pkt >> num_privileges;
 
-               ClientEvent event;
-               event.type                                   = CE_ADD_PARTICLESPAWNER;
-               event.add_particlespawner.amount             = amount;
-               event.add_particlespawner.spawntime          = spawntime;
-               event.add_particlespawner.minpos             = new v3f (minpos);
-               event.add_particlespawner.maxpos             = new v3f (maxpos);
-               event.add_particlespawner.minvel             = new v3f (minvel);
-               event.add_particlespawner.maxvel             = new v3f (maxvel);
-               event.add_particlespawner.minacc             = new v3f (minacc);
-               event.add_particlespawner.maxacc             = new v3f (maxacc);
-               event.add_particlespawner.minexptime         = minexptime;
-               event.add_particlespawner.maxexptime         = maxexptime;
-               event.add_particlespawner.minsize            = minsize;
-               event.add_particlespawner.maxsize            = maxsize;
-               event.add_particlespawner.collisiondetection = collisiondetection;
-               event.add_particlespawner.vertical           = vertical;
-               event.add_particlespawner.texture            = new std::string(texture);
-               event.add_particlespawner.id                 = id;
+       for(unsigned int i=0; i<num_privileges; i++) {
+               std::string priv;
 
-               m_client_event_queue.push_back(event);
+               *pkt >> priv;
+
+               m_privileges.insert(priv);
+               infostream << priv << " ";
        }
-       else if(command == TOCLIENT_DELETE_PARTICLESPAWNER)
-       {
-               std::string datastring((char*)&data[2], datasize-2);
-               std::istringstream is(datastring, std::ios_base::binary);
+       infostream << std::endl;
+}
 
-               u32 id = readU16(is);
+void Client::handleCommand_InventoryFormSpec(ToClientPacket* pkt)
+{
+       Player *player = m_env.getLocalPlayer();
+       assert(player != NULL);
 
-               ClientEvent event;
-               event.type                      = CE_DELETE_PARTICLESPAWNER;
-               event.delete_particlespawner.id = id;
+       // Store formspec in LocalPlayer
+       player->inventory_formspec = pkt->readLongString();
+}
 
-               m_client_event_queue.push_back(event);
-       }
-       else if(command == TOCLIENT_HUDADD)
-       {
-               std::string datastring((char *)&data[2], datasize - 2);
-               std::istringstream is(datastring, std::ios_base::binary);
-
-               u32 id           = readU32(is);
-               u8 type          = readU8(is);
-               v2f pos          = readV2F1000(is);
-               std::string name = deSerializeString(is);
-               v2f scale        = readV2F1000(is);
-               std::string text = deSerializeString(is);
-               u32 number       = readU32(is);
-               u32 item         = readU32(is);
-               u32 dir          = readU32(is);
-               v2f align        = readV2F1000(is);
-               v2f offset       = readV2F1000(is);
-               v3f world_pos;
-               v2s32 size;
-               try{
-                       world_pos    = readV3F1000(is);
-               }catch(SerializationError &e) {};
-               try{
-                       size = readV2S32(is);
-               } catch(SerializationError &e) {};
+void Client::handleCommand_DetachedInventory(ToClientPacket* pkt)
+{
+       std::string datastring(pkt->getString(0), pkt->getSize());
+       std::istringstream is(datastring, std::ios_base::binary);
 
-               ClientEvent event;
-               event.type             = CE_HUDADD;
-               event.hudadd.id        = id;
-               event.hudadd.type      = type;
-               event.hudadd.pos       = new v2f(pos);
-               event.hudadd.name      = new std::string(name);
-               event.hudadd.scale     = new v2f(scale);
-               event.hudadd.text      = new std::string(text);
-               event.hudadd.number    = number;
-               event.hudadd.item      = item;
-               event.hudadd.dir       = dir;
-               event.hudadd.align     = new v2f(align);
-               event.hudadd.offset    = new v2f(offset);
-               event.hudadd.world_pos = new v3f(world_pos);
-               event.hudadd.size      = new v2s32(size);
-               m_client_event_queue.push_back(event);
-       }
-       else if(command == TOCLIENT_HUDRM)
-       {
-               std::string datastring((char *)&data[2], datasize - 2);
-               std::istringstream is(datastring, std::ios_base::binary);
+       std::string name = deSerializeString(is);
+
+       infostream << "Client: Detached inventory update: \"" << name
+                       << "\"" << std::endl;
+
+       Inventory *inv = NULL;
+       if(m_detached_inventories.count(name) > 0)
+               inv = m_detached_inventories[name];
+       else {
+               inv = new Inventory(m_itemdef);
+               m_detached_inventories[name] = inv;
+       }
+       inv->deSerialize(is);
+}
+
+void Client::handleCommand_ShowFormSpec(ToClientPacket* pkt)
+{
+       std::string formspec = pkt->readLongString();
+       std::string formname;
 
-               u32 id = readU32(is);
+       *pkt >> formname;
 
-               ClientEvent event;
-               event.type     = CE_HUDRM;
-               event.hudrm.id = id;
-               m_client_event_queue.push_back(event);
+       ClientEvent event;
+       event.type = CE_SHOW_FORMSPEC;
+       // pointer is required as event is a struct only!
+       // adding a std:string to a struct isn't possible
+       event.show_formspec.formspec = new std::string(formspec);
+       event.show_formspec.formname = new std::string(formname);
+       m_client_event_queue.push_back(event);
+}
+
+void Client::handleCommand_SpawnParticle(ToClientPacket* pkt)
+{
+       std::string datastring(pkt->getString(0), pkt->getSize());
+       std::istringstream is(datastring, std::ios_base::binary);
+
+       v3f pos                 = readV3F1000(is);
+       v3f vel                 = readV3F1000(is);
+       v3f acc                 = readV3F1000(is);
+       float expirationtime    = readF1000(is);
+       float size              = readF1000(is);
+       bool collisiondetection = readU8(is);
+       std::string texture     = deSerializeLongString(is);
+       bool vertical           = false;
+       try {
+               vertical = readU8(is);
+       } catch (...) {}
+
+       ClientEvent event;
+       event.type                              = CE_SPAWN_PARTICLE;
+       event.spawn_particle.pos                = new v3f (pos);
+       event.spawn_particle.vel                = new v3f (vel);
+       event.spawn_particle.acc                = new v3f (acc);
+       event.spawn_particle.expirationtime     = expirationtime;
+       event.spawn_particle.size               = size;
+       event.spawn_particle.collisiondetection = collisiondetection;
+       event.spawn_particle.vertical           = vertical;
+       event.spawn_particle.texture            = new std::string(texture);
+
+       m_client_event_queue.push_back(event);
+}
+
+void Client::handleCommand_AddParticleSpawner(ToClientPacket* pkt)
+{
+       u16 amount;
+       float spawntime;
+       v3f minpos;
+       v3f maxpos;
+       v3f minvel;
+       v3f maxvel;
+       v3f minacc;
+       v3f maxacc;
+       float minexptime;
+       float maxexptime;
+       float minsize;
+       float maxsize;
+       bool collisiondetection;
+       u32 id;
+
+       *pkt >> amount >> spawntime >> minpos >> maxpos >> minvel >> maxvel
+               >> minacc >> maxacc >> minexptime >> maxexptime >> minsize
+               >> maxsize >> collisiondetection;
+
+       std::string texture = pkt->readLongString();
+
+       *pkt >> id;
+
+       bool vertical = false;
+       try {
+               *pkt >> vertical;
+       } catch (...) {}
+
+       ClientEvent event;
+       event.type                                   = CE_ADD_PARTICLESPAWNER;
+       event.add_particlespawner.amount             = amount;
+       event.add_particlespawner.spawntime          = spawntime;
+       event.add_particlespawner.minpos             = new v3f (minpos);
+       event.add_particlespawner.maxpos             = new v3f (maxpos);
+       event.add_particlespawner.minvel             = new v3f (minvel);
+       event.add_particlespawner.maxvel             = new v3f (maxvel);
+       event.add_particlespawner.minacc             = new v3f (minacc);
+       event.add_particlespawner.maxacc             = new v3f (maxacc);
+       event.add_particlespawner.minexptime         = minexptime;
+       event.add_particlespawner.maxexptime         = maxexptime;
+       event.add_particlespawner.minsize            = minsize;
+       event.add_particlespawner.maxsize            = maxsize;
+       event.add_particlespawner.collisiondetection = collisiondetection;
+       event.add_particlespawner.vertical           = vertical;
+       event.add_particlespawner.texture            = new std::string(texture);
+       event.add_particlespawner.id                 = id;
+
+       m_client_event_queue.push_back(event);
+}
+
+void Client::handleCommand_DeleteParticleSpawner(ToClientPacket* pkt)
+{
+       u16 id;
+
+       *pkt >> id;
+
+       ClientEvent event;
+       event.type                      = CE_DELETE_PARTICLESPAWNER;
+       event.delete_particlespawner.id = id;
+
+       m_client_event_queue.push_back(event);
+}
+
+void Client::handleCommand_HudAdd(ToClientPacket* pkt)
+{
+       std::string datastring(pkt->getString(0), pkt->getSize());
+       std::istringstream is(datastring, std::ios_base::binary);
+
+       u32 id;
+       u8 type;
+       v2f pos;
+       std::string name;
+       v2f scale;
+       std::string text;
+       u32 number;
+       u32 item;
+       u32 dir;
+       v2f align;
+       v2f offset;
+       v3f world_pos;
+       v2s32 size;
+
+       *pkt >> id >> type >> pos >> name >> scale >> text >> number >> item
+               >> dir >> align >> offset;
+       try {
+               *pkt >> world_pos;
+       }
+       catch(SerializationError &e) {};
+
+       try {
+               *pkt >> size;
+       } catch(SerializationError &e) {};
+
+       ClientEvent event;
+       event.type             = CE_HUDADD;
+       event.hudadd.id        = id;
+       event.hudadd.type      = type;
+       event.hudadd.pos       = new v2f(pos);
+       event.hudadd.name      = new std::string(name);
+       event.hudadd.scale     = new v2f(scale);
+       event.hudadd.text      = new std::string(text);
+       event.hudadd.number    = number;
+       event.hudadd.item      = item;
+       event.hudadd.dir       = dir;
+       event.hudadd.align     = new v2f(align);
+       event.hudadd.offset    = new v2f(offset);
+       event.hudadd.world_pos = new v3f(world_pos);
+       event.hudadd.size      = new v2s32(size);
+       m_client_event_queue.push_back(event);
+}
+
+void Client::handleCommand_HudRemove(ToClientPacket* pkt)
+{
+       u32 id;
+
+       *pkt >> id;
+
+       ClientEvent event;
+       event.type     = CE_HUDRM;
+       event.hudrm.id = id;
+       m_client_event_queue.push_back(event);
+}
+
+void Client::handleCommand_HudChange(ToClientPacket* pkt)
+{
+       std::string sdata;
+       v2f v2fdata;
+       v3f v3fdata;
+       u32 intdata = 0;
+       v2s32 v2s32data;
+       u32 id;
+       u8 stat;
+
+       *pkt >> id >> stat;
+
+       if (stat == HUD_STAT_POS || stat == HUD_STAT_SCALE ||
+               stat == HUD_STAT_ALIGN || stat == HUD_STAT_OFFSET)
+               *pkt >> v2fdata;
+       else if (stat == HUD_STAT_NAME || stat == HUD_STAT_TEXT)
+               *pkt >> sdata;
+       else if (stat == HUD_STAT_WORLD_POS)
+               *pkt >> v3fdata;
+       else if (stat == HUD_STAT_SIZE )
+               *pkt >> v2s32data;
+       else
+               *pkt >> intdata;
+
+       ClientEvent event;
+       event.type              = CE_HUDCHANGE;
+       event.hudchange.id      = id;
+       event.hudchange.stat    = (HudElementStat)stat;
+       event.hudchange.v2fdata = new v2f(v2fdata);
+       event.hudchange.v3fdata = new v3f(v3fdata);
+       event.hudchange.sdata   = new std::string(sdata);
+       event.hudchange.data    = intdata;
+       event.hudchange.v2s32data = new v2s32(v2s32data);
+       m_client_event_queue.push_back(event);
+}
+
+void Client::handleCommand_HudSetFlags(ToClientPacket* pkt)
+{
+       u32 flags, mask;
+
+       *pkt >> flags >> mask;
+
+       Player *player = m_env.getLocalPlayer();
+       assert(player != NULL);
+
+       player->hud_flags &= ~mask;
+       player->hud_flags |= flags;
+}
+
+void Client::handleCommand_HudSetParam(ToClientPacket* pkt)
+{
+       u16 param; std::string value;
+
+       *pkt >> param >> value;
+
+       Player *player = m_env.getLocalPlayer();
+       assert(player != NULL);
+
+       if(param == HUD_PARAM_HOTBAR_ITEMCOUNT && value.size() == 4) {
+               s32 hotbar_itemcount = readS32((u8*) value.c_str());
+               if(hotbar_itemcount > 0 && hotbar_itemcount <= HUD_HOTBAR_ITEMCOUNT_MAX)
+                       player->hud_hotbar_itemcount = hotbar_itemcount;
        }
-       else if(command == TOCLIENT_HUDCHANGE)
-       {
-               std::string sdata;
-               v2f v2fdata;
-               v3f v3fdata;
-               u32 intdata = 0;
-               v2s32 v2s32data;
-               
-               std::string datastring((char *)&data[2], datasize - 2);
-               std::istringstream is(datastring, std::ios_base::binary);
-
-               u32 id  = readU32(is);
-               u8 stat = (HudElementStat)readU8(is);
-               
-               if (stat == HUD_STAT_POS || stat == HUD_STAT_SCALE ||
-                       stat == HUD_STAT_ALIGN || stat == HUD_STAT_OFFSET)
-                       v2fdata = readV2F1000(is);
-               else if (stat == HUD_STAT_NAME || stat == HUD_STAT_TEXT)
-                       sdata = deSerializeString(is);
-               else if (stat == HUD_STAT_WORLD_POS)
-                       v3fdata = readV3F1000(is);
-               else if (stat == HUD_STAT_SIZE )
-                       v2s32data = readV2S32(is);
-               else
-                       intdata = readU32(is);
-               
-               ClientEvent event;
-               event.type              = CE_HUDCHANGE;
-               event.hudchange.id      = id;
-               event.hudchange.stat    = (HudElementStat)stat;
-               event.hudchange.v2fdata = new v2f(v2fdata);
-               event.hudchange.v3fdata = new v3f(v3fdata);
-               event.hudchange.sdata   = new std::string(sdata);
-               event.hudchange.data    = intdata;
-               event.hudchange.v2s32data = new v2s32(v2s32data);
-               m_client_event_queue.push_back(event);
+       else if (param == HUD_PARAM_HOTBAR_IMAGE) {
+               ((LocalPlayer *) player)->hotbar_image = value;
        }
-       else if(command == TOCLIENT_HUD_SET_FLAGS)
-       {
-               std::string datastring((char *)&data[2], datasize - 2);
-               std::istringstream is(datastring, std::ios_base::binary);
-
-               u32 flags = readU32(is);
-               u32 mask  = readU32(is);
-               
-               player->hud_flags &= ~mask;
-               player->hud_flags |= flags;
+       else if (param == HUD_PARAM_HOTBAR_SELECTED_IMAGE) {
+               ((LocalPlayer *) player)->hotbar_selected_image = value;
        }
-       else if(command == TOCLIENT_HUD_SET_PARAM)
-       {
-               std::string datastring((char *)&data[2], datasize - 2);
-               std::istringstream is(datastring, std::ios_base::binary);
+}
 
-               u16 param         = readU16(is);
-               std::string value = deSerializeString(is);
+void Client::handleCommand_HudSetSky(ToClientPacket* pkt)
+{
+       std::string datastring(pkt->getString(0), pkt->getSize());
+       std::istringstream is(datastring, std::ios_base::binary);
 
-               if(param == HUD_PARAM_HOTBAR_ITEMCOUNT && value.size() == 4) {
-                       s32 hotbar_itemcount = readS32((u8*) value.c_str());
-                       if(hotbar_itemcount > 0 && hotbar_itemcount <= HUD_HOTBAR_ITEMCOUNT_MAX)
-                               player->hud_hotbar_itemcount = hotbar_itemcount;
-               }
-               else if (param == HUD_PARAM_HOTBAR_IMAGE) {
-                       ((LocalPlayer *) player)->hotbar_image = value;
-               }
-               else if (param == HUD_PARAM_HOTBAR_SELECTED_IMAGE) {
-                       ((LocalPlayer *) player)->hotbar_selected_image = value;
-               }
-       }
-       else if(command == TOCLIENT_SET_SKY)
-       {
-               std::string datastring((char *)&data[2], datasize - 2);
-               std::istringstream is(datastring, std::ios_base::binary);
+       video::SColor *bgcolor           = new video::SColor(readARGB8(is));
+       std::string *type                = new std::string(deSerializeString(is));
+       u16 count                        = readU16(is);
+       std::vector<std::string> *params = new std::vector<std::string>;
 
-               video::SColor *bgcolor           = new video::SColor(readARGB8(is));
-               std::string *type                = new std::string(deSerializeString(is));
-               u16 count                        = readU16(is);
-               std::vector<std::string> *params = new std::vector<std::string>;
+       for(size_t i=0; i<count; i++)
+               params->push_back(deSerializeString(is));
 
-               for(size_t i=0; i<count; i++)
-                       params->push_back(deSerializeString(is));
+       ClientEvent event;
+       event.type            = CE_SET_SKY;
+       event.set_sky.bgcolor = bgcolor;
+       event.set_sky.type    = type;
+       event.set_sky.params  = params;
+       m_client_event_queue.push_back(event);
+}
 
-               ClientEvent event;
-               event.type            = CE_SET_SKY;
-               event.set_sky.bgcolor = bgcolor;
-               event.set_sky.type    = type;
-               event.set_sky.params  = params;
-               m_client_event_queue.push_back(event);
-       }
-       else if(command == TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO)
-       {
-               std::string datastring((char *)&data[2], datasize - 2);
-               std::istringstream is(datastring, std::ios_base::binary);
+void Client::handleCommand_OverrideDayNightRatio(ToClientPacket* pkt)
+{
+       bool do_override;
+       u16 day_night_ratio_u;
 
-               bool do_override        = readU8(is);
-               float day_night_ratio_f = (float)readU16(is) / 65536;
+       *pkt >> do_override >> day_night_ratio_u;
 
-               ClientEvent event;
-               event.type                                 = CE_OVERRIDE_DAY_NIGHT_RATIO;
-               event.override_day_night_ratio.do_override = do_override;
-               event.override_day_night_ratio.ratio_f     = day_night_ratio_f;
-               m_client_event_queue.push_back(event);
+       float day_night_ratio_f = (float)day_night_ratio_u / 65536;
+
+       ClientEvent event;
+       event.type                                 = CE_OVERRIDE_DAY_NIGHT_RATIO;
+       event.override_day_night_ratio.do_override = do_override;
+       event.override_day_night_ratio.ratio_f     = day_night_ratio_f;
+       m_client_event_queue.push_back(event);
+}
+
+void Client::handleCommand_LocalPlayerAnimations(ToClientPacket* pkt)
+{
+       LocalPlayer *player = m_env.getLocalPlayer();
+       assert(player != NULL);
+
+       *pkt >> player->local_animations[0];
+       *pkt >> player->local_animations[1];
+       *pkt >> player->local_animations[2];
+       *pkt >> player->local_animations[3];
+       *pkt >> player->local_animation_speed;
+}
+
+void Client::handleCommand_EyeOffset(ToClientPacket* pkt)
+{
+       LocalPlayer *player = m_env.getLocalPlayer();
+       assert(player != NULL);
+
+       *pkt >> player->eye_offset_first >> player->eye_offset_third;
+}
+
+inline void Client::handleCommand(ToClientPacket* pkt)
+{
+       const ToClientCommandHandler& opHandle = toClientCommandTable[pkt->getCommand()];
+       (this->*opHandle.handler)(pkt);
+}
+
+/*
+       sender_peer_id given to this shall be quaranteed to be a valid peer
+*/
+void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
+{
+       DSTACK(__FUNCTION_NAME);
+
+       // Ignore packets that don't even fit a command
+       if(datasize < 2) {
+               m_packetcounter.add(60000);
+               return;
        }
-       else if(command == TOCLIENT_LOCAL_PLAYER_ANIMATIONS)
-       {
-               std::string datastring((char *)&data[2], datasize - 2);
-               std::istringstream is(datastring, std::ios_base::binary);
 
-               LocalPlayer *player = m_env.getLocalPlayer();
-               assert(player != NULL);
+       ToClientPacket* pkt = new ToClientPacket(data, datasize, sender_peer_id);
 
-               player->local_animations[0] = readV2S32(is);
-               player->local_animations[1] = readV2S32(is);
-               player->local_animations[2] = readV2S32(is);
-               player->local_animations[3] = readV2S32(is);
-               player->local_animation_speed = readF1000(is);
+       ToClientCommand command = pkt->getCommand();
+
+       //infostream<<"Client: received command="<<command<<std::endl;
+       m_packetcounter.add((u16)command);
+
+       /*
+               If this check is removed, be sure to change the queue
+               system to know the ids
+       */
+       if(sender_peer_id != PEER_ID_SERVER) {
+               infostream << "Client::ProcessData(): Discarding data not "
+                       "coming from server: peer_id=" << sender_peer_id
+                       << std::endl;
+               delete pkt;
+               return;
        }
-       else if(command == TOCLIENT_EYE_OFFSET)
-       {
-               std::string datastring((char *)&data[2], datasize - 2);
-               std::istringstream is(datastring, std::ios_base::binary);
 
-               LocalPlayer *player = m_env.getLocalPlayer();
-               assert(player != NULL);
+       // Command must be handled into ToClientCommandHandler
+       if (command >= TOCLIENT_NUM_MSG_TYPES) {
+               infostream << "Client: Ignoring unknown command "
+                       << command << std::endl;
+       }
 
-               player->eye_offset_first = readV3F1000(is);
-               player->eye_offset_third = readV3F1000(is);
+       /*
+        * Those packets are handled before m_server_ser_ver is set, it's normal
+        * But we must use the new ToClientConnectionState in the future,
+        * as a byte mask
+        */
+       if(toClientCommandTable[command].state == TOCLIENT_STATE_NOT_CONNECTED) {
+               handleCommand(pkt);
+               delete pkt;
+               return;
        }
-       else
-       {
-               infostream<<"Client: Ignoring unknown command "
-                               <<command<<std::endl;
+
+       if(m_server_ser_ver == SER_FMT_VER_INVALID) {
+               infostream << "Client: Server serialization"
+                               " format invalid or not initialized."
+                               " Skipping incoming command=" << command << std::endl;
+               delete pkt;
+               return;
        }
+
+       /*
+         Handle runtime commands
+       */
+
+       handleCommand(pkt);
+       delete pkt;
 }
 
 void Client::Send(u16 channelnum, SharedBuffer<u8> data, bool reliable)
@@ -2029,7 +2155,7 @@ void Client::sendNodemetaFields(v3s16 p, const std::string &formname,
        // Send as reliable
        Send(0, data, true);
 }
-       
+
 void Client::sendInventoryFields(const std::string &formname,
                const std::map<std::string, std::string> &fields)
 {
@@ -2059,13 +2185,13 @@ void Client::sendInventoryAction(InventoryAction *a)
 {
        std::ostringstream os(std::ios_base::binary);
        u8 buf[12];
-       
+
        // Write command
        writeU16(buf, TOSERVER_INVENTORY_ACTION);
        os.write((char*)buf, 2);
 
        a->serialize(os);
-       
+
        // Make data buffer
        std::string s = os.str();
        SharedBuffer<u8> data((u8*)s.c_str(), s.size());
@@ -2077,11 +2203,11 @@ void Client::sendChatMessage(const std::wstring &message)
 {
        std::ostringstream os(std::ios_base::binary);
        u8 buf[12];
-       
+
        // Write command
        writeU16(buf, TOSERVER_CHAT_MESSAGE);
        os.write((char*)buf, 2);
-       
+
        // Write length
        size_t messagesize = message.size();
        if (messagesize > 0xFFFF) {
@@ -2089,7 +2215,7 @@ void Client::sendChatMessage(const std::wstring &message)
        }
        writeU16(buf, (u16) messagesize);
        os.write((char*)buf, 2);
-       
+
        // Write string
        for(unsigned int i=0; i<message.size(); i++)
        {
@@ -2097,7 +2223,7 @@ void Client::sendChatMessage(const std::wstring &message)
                writeU16(buf, w);
                os.write((char*)buf, 2);
        }
-       
+
        // Make data buffer
        std::string s = os.str();
        SharedBuffer<u8> data((u8*)s.c_str(), s.size());
@@ -2231,13 +2357,13 @@ void Client::sendPlayerPos()
                //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
                our_peer_id = m_con.GetPeerID();
        }
-       
+
        // Set peer id if not set already
        if(myplayer->peer_id == PEER_ID_INEXISTENT)
                myplayer->peer_id = our_peer_id;
        // Check that an existing peer_id is the same as the connection's
        assert(myplayer->peer_id == our_peer_id);
-       
+
        v3f pf         = myplayer->getPosition();
        v3f sf         = myplayer->getSpeed();
        s32 pitch      = myplayer->getPitch() * 100;
@@ -2299,15 +2425,13 @@ void Client::removeNode(v3s16 p)
        catch(InvalidPositionException &e)
        {
        }
-       
+
        for(std::map<v3s16, MapBlock * >::iterator
                        i = modified_blocks.begin();
                        i != modified_blocks.end(); ++i)
        {
-               addUpdateMeshTask(i->first, false, false);
+               addUpdateMeshTaskWithEdge(i->first, false, true);
        }
-       // add urgent task to update the modified node
-       addUpdateMeshTaskForNode(p, false, true);
 }
 
 void Client::addNode(v3s16 p, MapNode n, bool remove_metadata)
@@ -2323,15 +2447,15 @@ void Client::addNode(v3s16 p, MapNode n, bool remove_metadata)
        }
        catch(InvalidPositionException &e)
        {}
-       
+
        for(std::map<v3s16, MapBlock * >::iterator
                        i = modified_blocks.begin();
                        i != modified_blocks.end(); ++i)
        {
-               addUpdateMeshTask(i->first, false, false);
+               addUpdateMeshTaskWithEdge(i->first, false, true);
        }
 }
-       
+
 void Client::setPlayerControl(PlayerControl &control)
 {
        LocalPlayer *player = m_env.getLocalPlayer();
@@ -2430,7 +2554,7 @@ ClientActiveObject * Client::getSelectedActiveObject(
        std::vector<DistanceSortedActiveObject> objects;
 
        m_env.getActiveObjects(from_pos_f_on_map, max_d, objects);
-       
+
        // Sort them.
        // After this, the closest object is the first in the array.
        std::sort(objects.begin(), objects.end());
@@ -2438,7 +2562,7 @@ ClientActiveObject * Client::getSelectedActiveObject(
        for(unsigned int i=0; i<objects.size(); i++)
        {
                ClientActiveObject *obj = objects[i].obj;
-               
+
                core::aabbox3d<f32> *selection_box = obj->getSelectionBox();
                if(selection_box == NULL)
                        continue;
@@ -2474,9 +2598,9 @@ int Client::getCrackLevel()
        return m_crack_level;
 }
 
-void Client::setHighlighted(v3s16 pos, bool show_hud)
+void Client::setHighlighted(v3s16 pos, bool show_highlighted)
 {
-       m_show_hud = show_hud;
+       m_show_highlighted = show_highlighted;
        v3s16 old_highlighted_pos = m_highlighted_pos;
        m_highlighted_pos = pos;
        addUpdateMeshTaskForNode(old_highlighted_pos, false, true);
@@ -2558,7 +2682,7 @@ void Client::addUpdateMeshTask(v3s16 p, bool ack_to_server, bool urgent)
                Create a task to update the mesh of the block
        */
 
-       MeshMakeData *data = new MeshMakeData(this);
+       MeshMakeData *data = new MeshMakeData(this, m_cache_enable_shaders);
 
        {
                //TimeTaker timer("data fill");
@@ -2566,8 +2690,8 @@ void Client::addUpdateMeshTask(v3s16 p, bool ack_to_server, bool urgent)
                // Debug: 1-6ms, avg=2ms
                data->fill(b);
                data->setCrack(m_crack_level, m_crack_pos);
-               data->setHighlighted(m_highlighted_pos, m_show_hud);
-               data->setSmoothLighting(g_settings->getBool("smooth_lighting"));
+               data->setHighlighted(m_highlighted_pos, m_show_highlighted);
+               data->setSmoothLighting(m_cache_smooth_lighting);
        }
 
        // Add task to queue
@@ -2577,9 +2701,7 @@ void Client::addUpdateMeshTask(v3s16 p, bool ack_to_server, bool urgent)
 void Client::addUpdateMeshTaskWithEdge(v3s16 blockpos, bool ack_to_server, bool urgent)
 {
        try{
-               v3s16 p = blockpos + v3s16(0,0,0);
-               //MapBlock *b = m_env.getMap().getBlockNoCreate(p);
-               addUpdateMeshTask(p, ack_to_server, urgent);
+               addUpdateMeshTask(blockpos, ack_to_server, urgent);
        }
        catch(InvalidPositionException &e){}
 
@@ -2607,8 +2729,7 @@ void Client::addUpdateMeshTaskForNode(v3s16 nodepos, bool ack_to_server, bool ur
        v3s16 blockpos_relative = blockpos * MAP_BLOCKSIZE;
 
        try{
-               v3s16 p = blockpos + v3s16(0,0,0);
-               addUpdateMeshTask(p, ack_to_server, urgent);
+               addUpdateMeshTask(blockpos, ack_to_server, urgent);
        }
        catch(InvalidPositionException &e){}
 
@@ -2663,18 +2784,30 @@ void Client::afterContentReceived(IrrlichtDevice *device, gui::IGUIFont* font)
        assert(m_itemdef_received);
        assert(m_nodedef_received);
        assert(mediaReceived());
-       
+
+       const wchar_t* text = wgettext("Loading textures...");
+
        // Rebuild inherited images and recreate textures
        infostream<<"- Rebuilding images and textures"<<std::endl;
+       draw_load_screen(text,device, guienv, 0, 70);
        m_tsrc->rebuildImagesAndTextures();
+       delete[] text;
 
        // Rebuild shaders
        infostream<<"- Rebuilding shaders"<<std::endl;
+       text = wgettext("Rebuilding shaders...");
+       draw_load_screen(text, device, guienv, 0, 75);
        m_shsrc->rebuildShaders();
+       delete[] text;
 
        // Update node aliases
        infostream<<"- Updating node aliases"<<std::endl;
+       text = wgettext("Initializing nodes...");
+       draw_load_screen(text, device, guienv, 0, 80);
        m_nodedef->updateAliases(m_itemdef);
+       m_nodedef->setNodeRegistrationStatus(true);
+       m_nodedef->runNodeResolverCallbacks();
+       delete[] text;
 
        // Update node textures and assign shaders to each tile
        infostream<<"- Updating node textures"<<std::endl;
@@ -2684,21 +2817,21 @@ void Client::afterContentReceived(IrrlichtDevice *device, gui::IGUIFont* font)
        if(g_settings->getBool("preload_item_visuals"))
        {
                verbosestream<<"Updating item textures and meshes"<<std::endl;
-               wchar_t* text = wgettext("Item textures...");
-               draw_load_screen(text, device, guienv, font, 0, 0);
+               text = wgettext("Item textures...");
+               draw_load_screen(text, device, guienv, 0, 0);
                std::set<std::string> names = m_itemdef->getAll();
                size_t size = names.size();
                size_t count = 0;
                int percent = 0;
                for(std::set<std::string>::const_iterator
-                               i = names.begin(); i != names.end(); ++i){
+                               i = names.begin(); i != names.end(); ++i)
+               {
                        // Asking for these caches the result
                        m_itemdef->getInventoryTexture(*i, this);
                        m_itemdef->getWieldMesh(*i, this);
                        count++;
-                       percent = count*100/size;
-                       if (count%50 == 0) // only update every 50 item
-                               draw_load_screen(text, device, guienv, font, 0, percent);
+                       percent = (count * 100 / size * 0.2) + 80;
+                       draw_load_screen(text, device, guienv, 0, percent);
                }
                delete[] text;
        }
@@ -2706,10 +2839,13 @@ void Client::afterContentReceived(IrrlichtDevice *device, gui::IGUIFont* font)
        // Start mesh update thread after setting up content definitions
        infostream<<"- Starting mesh update thread"<<std::endl;
        m_mesh_update_thread.Start();
-       
+
        m_state = LC_Ready;
        sendReady();
+       text = wgettext("Done!");
+       draw_load_screen(text, device, guienv, 0, 100);
        infostream<<"Client::afterContentReceived() done"<<std::endl;
+       delete[] text;
 }
 
 float Client::getRTT(void)
@@ -2734,7 +2870,7 @@ void Client::makeScreenshot(IrrlichtDevice *device)
        irr::video::IVideoDriver *driver = device->getVideoDriver();
        irr::video::IImage* const raw_image = driver->createScreenShot();
        if (raw_image) {
-               irr::video::IImage* const image = driver->createImage(video::ECF_R8G8B8, 
+               irr::video::IImage* const image = driver->createImage(video::ECF_R8G8B8,
                        raw_image->getDimension());
 
                if (image) {
@@ -2743,14 +2879,14 @@ void Client::makeScreenshot(IrrlichtDevice *device)
                        snprintf(filename, sizeof(filename), "%s" DIR_DELIM "screenshot_%u.png",
                                 g_settings->get("screenshot_path").c_str(),
                                 device->getTimer()->getRealTime());
-                       std::stringstream sstr;
+                       std::ostringstream sstr;
                        if (driver->writeImageToFile(image, filename)) {
                                sstr << "Saved screenshot to '" << filename << "'";
                        } else {
                                sstr << "Failed to save screenshot '" << filename << "'";
                        }
                        m_chat_queue.push_back(narrow_to_wide(sstr.str()));
-                       infostream << sstr << std::endl;
+                       infostream << sstr.str() << std::endl;
                        image->drop();
                }
                raw_image->drop();
@@ -2800,6 +2936,11 @@ MtEventManager* Client::getEventManager()
        return m_event;
 }
 
+ParticleManager* Client::getParticleManager()
+{
+       return &m_particle_manager;
+}
+
 scene::IAnimatedMesh* Client::getMesh(const std::string &filename)
 {
        std::map<std::string, std::string>::const_iterator i =
@@ -2828,4 +2969,3 @@ scene::IAnimatedMesh* Client::getMesh(const std::string &filename)
        smgr->getMeshCache()->removeMesh(mesh);
        return mesh;
 }
-