Update inventory texture too
[oweals/minetest.git] / src / client.cpp
index 816ab39caeecb2088ada746e4389d7d70dd3371b..7093a5190a2c40d176bf8279bb1437c2ba9cdba5 100644 (file)
@@ -31,6 +31,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "settings.h"
 #include "profiler.h"
 #include "log.h"
+#include "nodemetadata.h"
+#include "nodedef.h"
+#include "tooldef.h"
+#include <IFileSystem.h>
 
 /*
        QueuedMeshUpdate
@@ -156,10 +160,10 @@ void * MeshUpdateThread::Thread()
                        continue;
                }
 
-               ScopeProfiler sp(g_profiler, "mesh make");
+               ScopeProfiler sp(g_profiler, "Client: Mesh making");
 
                scene::SMesh *mesh_new = NULL;
-               mesh_new = makeMapBlockMesh(q->data);
+               mesh_new = makeMapBlockMesh(q->data, m_gamedef);
 
                MeshUpdateResult r;
                r.p = q->p;
@@ -184,13 +188,21 @@ Client::Client(
                IrrlichtDevice *device,
                const char *playername,
                std::string password,
-               MapDrawControl &control):
-       m_mesh_update_thread(),
+               MapDrawControl &control,
+               IWritableTextureSource *tsrc,
+               IWritableToolDefManager *tooldef,
+               IWritableNodeDefManager *nodedef
+):
+       m_tsrc(tsrc),
+       m_tooldef(tooldef),
+       m_nodedef(nodedef),
+       m_mesh_update_thread(this),
        m_env(
-               new ClientMap(this, control,
+               new ClientMap(this, this, control,
                        device->getSceneManager()->getRootSceneNode(),
                        device->getSceneManager(), 666),
-               device->getSceneManager()
+               device->getSceneManager(),
+               tsrc, this
        ),
        m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
        m_device(device),
@@ -208,18 +220,23 @@ Client::Client(
        m_playerpos_send_timer = 0.0;
        m_ignore_damage_timer = 0.0;
 
-       //m_env_mutex.Init();
-       //m_con_mutex.Init();
+       // Build main texture atlas, now that the GameDef exists (that is, us)
+       if(g_settings->getBool("enable_texture_atlas"))
+               m_tsrc->buildMainAtlas(this);
+       else
+               infostream<<"Not building texture atlas."<<std::endl;
+       
+       // Update node textures
+       m_nodedef->updateTextures(m_tsrc);
 
+       // Start threads after setting up content definitions
        m_mesh_update_thread.Start();
 
        /*
                Add local player
        */
        {
-               //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
-
-               Player *player = new LocalPlayer();
+               Player *player = new LocalPlayer(this);
 
                player->updateName(playername);
 
@@ -246,7 +263,7 @@ void Client::connect(Address address)
 {
        DSTACK(__FUNCTION_NAME);
        //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
-       m_con.setTimeoutMs(0);
+       m_con.SetTimeoutMs(0);
        m_con.Connect(address);
 }
 
@@ -434,7 +451,7 @@ void Client::step(float dtime)
                        snprintf((char*)&data[23], PASSWORD_SIZE, "%s", m_password.c_str());
                        
                        // This should be incremented in each version
-                       writeU16(&data[51], 3);
+                       writeU16(&data[51], PROTOCOL_VERSION);
 
                        // Send as unreliable
                        Send(0, data, false);
@@ -563,8 +580,8 @@ void Client::step(float dtime)
                        counter = 0.0;
                        //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
                        // connectedAndInitialized() is true, peer exists.
-                       con::Peer *peer = m_con.GetPeer(PEER_ID_SERVER);
-                       infostream<<"Client: avg_rtt="<<peer->avg_rtt<<std::endl;
+                       float avg_rtt = m_con.GetPeerAvgRTT(PEER_ID_SERVER);
+                       infostream<<"Client: avg_rtt="<<avg_rtt<<std::endl;
                }
        }
 
@@ -665,14 +682,13 @@ void Client::ReceiveAll()
 void Client::Receive()
 {
        DSTACK(__FUNCTION_NAME);
-       u32 data_maxsize = 200000;
-       Buffer<u8> data(data_maxsize);
+       SharedBuffer<u8> data;
        u16 sender_peer_id;
        u32 datasize;
        {
                //TimeTaker t1("con mutex and receive", m_device);
                //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
-               datasize = m_con.Receive(sender_peer_id, *data, data_maxsize);
+               datasize = m_con.Receive(sender_peer_id, data);
        }
        //TimeTaker t1("ProcessData", m_device);
        ProcessData(*data, datasize, sender_peer_id);
@@ -709,14 +725,6 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
                return;
        }
 
-       con::Peer *peer;
-       {
-               //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
-               // All data is coming from the server
-               // PeerNotFoundException is handled by caller.
-               peer = m_con.GetPeer(PEER_ID_SERVER);
-       }
-
        u8 ser_version = m_server_ser_ver;
 
        //infostream<<"Client received command="<<(int)command<<std::endl;
@@ -830,7 +838,7 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
                //TimeTaker t1("TOCLIENT_ADDNODE");
 
                MapNode n;
-               n.deSerialize(&data[8], ser_version);
+               n.deSerialize(&data[8], ser_version, m_nodedef);
                
                addNode(p, n);
        }
@@ -879,7 +887,7 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
                                Create a new block
                        */
                        //infostream<<"Creating new"<<std::endl;
-                       block = new MapBlock(&m_env.getMap(), p);
+                       block = new MapBlock(&m_env.getMap(), p, this);
                        block->deSerialize(istr, ser_version);
                        sector->insertBlock(block);
 
@@ -1044,7 +1052,7 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
                                // Create a player if it doesn't exist
                                if(player == NULL)
                                {
-                                       player = new RemotePlayer(
+                                       player = new RemotePlayer(this,
                                                        m_device->getSceneManager()->getRootSceneNode(),
                                                        m_device,
                                                        -1);
@@ -1165,7 +1173,7 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
                        //t4.stop();
 
                        //TimeTaker t1("inventory.deSerialize()", m_device);
-                       player->inventory.deSerialize(is);
+                       player->inventory.deSerialize(is, this);
                        //t1.stop();
 
                        m_inventory_updated = true;
@@ -1472,7 +1480,8 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
                                                << peer_id << std::endl;
                                } else {
                                        std::istringstream iss(itemstring);
-                                       delete inv->changeItem(0, InventoryItem::deSerialize(iss));
+                                       delete inv->changeItem(0,
+                                                       InventoryItem::deSerialize(iss, this));
                                        infostream<<"Client: player item for peer " << peer_id << ": ";
                                        player->getWieldItem()->serialize(infostream);
                                        infostream<<std::endl;
@@ -1496,6 +1505,90 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
                event.deathscreen.camera_point_target_z = camera_point_target.Z;
                m_client_event_queue.push_back(event);
        }
+       else if(command == TOCLIENT_TOOLDEF)
+       {
+               infostream<<"Client: Received tool definitions"<<std::endl;
+
+               std::string datastring((char*)&data[2], datasize-2);
+               std::istringstream is(datastring, std::ios_base::binary);
+
+               // Stop threads while updating content definitions
+               m_mesh_update_thread.stop();
+
+               std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
+               m_tooldef->deSerialize(tmp_is);
+               
+               // Resume threads
+               m_mesh_update_thread.setRun(true);
+               m_mesh_update_thread.Start();
+       }
+       else if(command == TOCLIENT_TEXTURES)
+       {
+               infostream<<"Client: Received textures: packet size: "<<datasize
+                               <<std::endl;
+
+               io::IFileSystem *irrfs = m_device->getFileSystem();
+               video::IVideoDriver *vdrv = m_device->getVideoDriver();
+
+               std::string datastring((char*)&data[2], datasize-2);
+               std::istringstream is(datastring, std::ios_base::binary);
+
+               // Stop threads while updating content definitions
+               m_mesh_update_thread.stop();
+               
+               /*
+                       u16 command
+                       u32 number of textures
+                       for each texture {
+                               u16 length of name
+                               string name
+                               u32 length of data
+                               data
+                       }
+               */
+               int num_textures = readU32(is);
+               infostream<<"Client: Received textures: count: "<<num_textures
+                               <<std::endl;
+               for(int i=0; i<num_textures; i++){
+                       std::string name = deSerializeString(is);
+                       std::string data = deSerializeLongString(is);
+                       // Silly irrlicht's const-incorrectness
+                       Buffer<char> data_rw(data.c_str(), data.size());
+                       // Create an irrlicht memory file
+                       io::IReadFile *rfile = irrfs->createMemoryReadFile(
+                                       *data_rw, data.size(), "_tempreadfile");
+                       assert(rfile);
+                       // Read image
+                       video::IImage *img = vdrv->createImageFromFile(rfile);
+                       if(!img){
+                               errorstream<<"Client: Cannot create image from data of "
+                                               <<"received texture \""<<name<<"\""<<std::endl;
+                               rfile->drop();
+                               continue;
+                       }
+                       m_tsrc->insertSourceImage(name, img);
+                       img->drop();
+                       rfile->drop();
+               }
+               
+               // Rebuild inherited images and recreate textures
+               m_tsrc->rebuildImagesAndTextures();
+
+               // Update texture atlas
+               if(g_settings->getBool("enable_texture_atlas"))
+                       m_tsrc->buildMainAtlas(this);
+               
+               // Update node textures
+               m_nodedef->updateTextures(m_tsrc);
+
+               // Resume threads
+               m_mesh_update_thread.setRun(true);
+               m_mesh_update_thread.Start();
+
+               ClientEvent event;
+               event.type = CE_TEXTURES_UPDATED;
+               m_client_event_queue.push_back(event);
+       }
        else
        {
                infostream<<"Client: Ignoring unknown command "
@@ -2168,9 +2261,25 @@ ClientEvent Client::getClientEvent()
 
 float Client::getRTT(void)
 {
-       con::Peer *peer = m_con.GetPeerNoEx(PEER_ID_SERVER);
-       if(!peer)
-               return 0.0;
-       return peer->avg_rtt;
+       try{
+               return m_con.GetPeerAvgRTT(PEER_ID_SERVER);
+       } catch(con::PeerNotFoundException &e){
+               return 1337;
+       }
+}
+
+// IGameDef interface
+// Under envlock
+IToolDefManager* Client::getToolDefManager()
+{
+       return m_tooldef;
+}
+INodeDefManager* Client::getNodeDefManager()
+{
+       return m_nodedef;
+}
+ITextureSource* Client::getTextureSource()
+{
+       return m_tsrc;
 }