#include "nodemetadata.h"
#include "nodedef.h"
#include "tooldef.h"
+#include <IFileSystem.h>
/*
QueuedMeshUpdate
m_time_of_day(0),
m_map_seed(0),
m_password(password),
- m_access_denied(false)
+ m_access_denied(false),
+ m_texture_receive_progress(0),
+ m_textures_received(false),
+ m_tooldef_received(false),
+ m_nodedef_received(false)
{
m_packetcounter_timer = 0.0;
//m_delete_unused_sectors_timer = 0.0;
// Build main texture atlas, now that the GameDef exists (that is, us)
if(g_settings->getBool("enable_texture_atlas"))
- tsrc->buildMainAtlas(this);
+ m_tsrc->buildMainAtlas(this);
else
infostream<<"Not building texture atlas."<<std::endl;
+
+ // Update node textures
+ m_nodedef->updateTextures(m_tsrc);
- // NOTE: This should be done only after getting possible dynamic
- // game definitions from the server, or at least shut down and
- // restarted when doing so
+ // Start threads after setting up content definitions
m_mesh_update_thread.Start();
/*
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);
void Client::ReceiveAll()
{
DSTACK(__FUNCTION_NAME);
+ u32 start_ms = porting::getTimeMs();
for(;;)
{
+ // Limit time even if there would be huge amounts of data to
+ // process
+ if(porting::getTimeMs() > start_ms + 100)
+ break;
+
try{
Receive();
}
//TimeTaker t1("TOCLIENT_ADDNODE");
MapNode n;
- n.deSerialize(&data[8], ser_version, m_nodedef);
+ n.deSerialize(&data[8], ser_version);
addNode(p, n);
}
block = new MapBlock(&m_env.getMap(), p, this);
block->deSerialize(istr, ser_version);
sector->insertBlock(block);
-
- //DEBUG
- /*NodeMod mod;
- mod.type = NODEMOD_CHANGECONTENT;
- mod.param = CONTENT_MESE;
- block->setTempMod(v3s16(8,10,8), mod);
- block->setTempMod(v3s16(8,9,8), mod);
- block->setTempMod(v3s16(8,8,8), mod);
- block->setTempMod(v3s16(8,7,8), mod);
- block->setTempMod(v3s16(8,6,8), mod);*/
}
#if 0
event.deathscreen.camera_point_target_z = camera_point_target.Z;
m_client_event_queue.push_back(event);
}
+ else if(command == TOCLIENT_TEXTURES)
+ {
+ 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
+ u16 total number of texture bunches
+ u16 index of this bunch
+ u32 number of textures in this bunch
+ for each texture {
+ u16 length of name
+ string name
+ u32 length of data
+ data
+ }
+ */
+ int num_bunches = readU16(is);
+ int bunch_i = readU16(is);
+ m_texture_receive_progress = (float)bunch_i / (float)(num_bunches - 1);
+ if(bunch_i == num_bunches - 1)
+ m_textures_received = true;
+ int num_textures = readU32(is);
+ infostream<<"Client: Received textures: bunch "<<bunch_i<<"/"
+ <<num_bunches<<" textures="<<num_textures
+ <<" size="<<datasize<<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();
+ }
+
+ if(m_nodedef_received && m_textures_received){
+ // 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 if(command == TOCLIENT_TOOLDEF)
+ {
+ infostream<<"Client: Received tool definitions: packet size: "
+ <<datasize<<std::endl;
+
+ std::string datastring((char*)&data[2], datasize-2);
+ std::istringstream is(datastring, std::ios_base::binary);
+
+ m_tooldef_received = true;
+
+ // 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_NODEDEF)
+ {
+ infostream<<"Client: Received node definitions: packet size: "
+ <<datasize<<std::endl;
+
+ std::string datastring((char*)&data[2], datasize-2);
+ std::istringstream is(datastring, std::ios_base::binary);
+
+ m_nodedef_received = true;
+
+ // Stop threads while updating content definitions
+ m_mesh_update_thread.stop();
+
+ std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
+ m_nodedef->deSerialize(tmp_is, this);
+
+ if(m_textures_received){
+ // 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();
+ }
else
{
infostream<<"Client: Ignoring unknown command "
{
return m_nodedef;
}
+ICraftDefManager* Client::getCraftDefManager()
+{
+ return NULL;
+ //return m_craftdef;
+}
ITextureSource* Client::getTextureSource()
{
return m_tsrc;
}
+u16 Client::allocateUnknownNodeId(const std::string &name)
+{
+ errorstream<<"Client::allocateUnknownNodeId(): "
+ <<"Client cannot allocate node IDs"<<std::endl;
+ assert(0);
+ return CONTENT_IGNORE;
+}