diff --git a/src/client.cpp b/src/client.cpp index 1daeeba36..c89273a80 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -34,6 +34,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "nodemetadata.h" #include "nodedef.h" #include "tooldef.h" +#include /* QueuedMeshUpdate @@ -1523,6 +1524,62 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id) m_mesh_update_thread.setRun(true); m_mesh_update_thread.Start(); } + else if(command == TOCLIENT_TEXTURES) + { + infostream<<"Client: Received textures: packet size: "<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: "< 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 \""<drop(); + continue; + } + m_tsrc->insertImage(name, img); + rfile->drop(); + } + + // Update texture atlas + if(g_settings->getBool("enable_texture_atlas")) + m_tsrc->buildMainAtlas(this); + + // Resume threads + m_mesh_update_thread.setRun(true); + m_mesh_update_thread.Start(); + } else { infostream<<"Client: Ignoring unknown command " diff --git a/src/clientserver.h b/src/clientserver.h index ef8188b2a..0d553f769 100644 --- a/src/clientserver.h +++ b/src/clientserver.h @@ -29,6 +29,7 @@ with this program; if not, write to the Free Software Foundation, Inc., Base for writing changes here PROTOCOL_VERSION 4: Add TOCLIENT_TOOLDEF + Add TOCLIENT_TEXTURES */ #define PROTOCOL_VERSION 4 @@ -198,6 +199,18 @@ enum ToClientCommand serialized ToolDefManager */ + TOCLIENT_TEXTURES = 0x39, + /* + u16 command + u32 number of textures + for each texture { + u16 length of name + string name + u32 length of data + data + } + */ + //TOCLIENT_CONTENT_SENDING_MODE = 0x38, /* u16 command diff --git a/src/server.cpp b/src/server.cpp index 9a7f1e972..44c66447c 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -944,6 +944,35 @@ u32 PIChecksum(core::list &l) return checksum; } +struct ModSpec +{ + std::string name; + std::string path; + + ModSpec(const std::string &name_="", const std::string path_=""): + name(name_), + path(path_) + {} +}; + +static core::list getMods(core::list &modspaths) +{ + core::list mods; + for(core::list::Iterator i = modspaths.begin(); + i != modspaths.end(); i++){ + std::string modspath = *i; + std::vector dirlist = fs::GetDirListing(modspath); + for(u32 j=0; j modspaths; - modspaths.push_back(porting::path_data + DIR_DELIM + "mods"); - for(core::list::Iterator i = modspaths.begin(); - i != modspaths.end(); i++){ - std::string modspath = *i; - std::vector dirlist = fs::GetDirListing(modspath); - for(u32 j=0; j mods = getMods(m_modspaths); + for(core::list::Iterator i = mods.begin(); + i != mods.end(); i++){ + ModSpec mod = *i; + infostream<<"Server: Loading mod \""< textures; + core::list mods = getMods(m_modspaths); + for(core::list::Iterator i = mods.begin(); + i != mods.end(); i++){ + ModSpec mod = *i; + std::string texturepath = mod.path + DIR_DELIM + "textures"; + std::vector dirlist = fs::GetDirListing(texturepath); + for(u32 j=0; j::Iterator i = textures.begin(); + i != textures.end(); i++){ + os<name); + os<data); + } + + // Make data buffer + std::string s = os.str(); + infostream<<"Server::SendTextures(): number of textures: " + < data((u8*)s.c_str(), s.size()); + // Send as reliable + m_con.Send(peer_id, 0, data, true); +} + /* Something random */ diff --git a/src/server.h b/src/server.h index 0354abbd9..e53bf9c9a 100644 --- a/src/server.h +++ b/src/server.h @@ -515,7 +515,10 @@ private: IToolDefManager *tooldef); /* - Non-static send methods + Non-static send methods. + Conlock should be always used. + Envlock usage is documented badly but it's easy to figure out + which ones access the environment. */ // Envlock and conlock should be locked when calling these @@ -546,6 +549,8 @@ private: // Sends blocks to clients (locks env and con on its own) void SendBlocks(float dtime); + + void SendTextures(u16 peer_id); /* Something random @@ -682,6 +687,9 @@ private: // Configuration path ("" = no configuration file) std::string m_configpath; + + // Mod parent directory paths + core::list m_modspaths; bool m_shutdown_requested; diff --git a/src/tile.cpp b/src/tile.cpp index eb3616f02..8ab92d105 100644 --- a/src/tile.cpp +++ b/src/tile.cpp @@ -242,14 +242,6 @@ public: */ void updateAP(AtlasPointer &ap); - /* - Build the main texture atlas which contains most of the - textures. - - This is called by the constructor. - */ - void buildMainAtlas(class IGameDef *gamedef); - /* Processes queued texture requests from other threads. @@ -257,6 +249,17 @@ public: */ void processQueue(); + /* + Build the main texture atlas which contains most of the + textures. + */ + void buildMainAtlas(class IGameDef *gamedef); + + /* + Insert an image into the cache without touching the filesystem. + */ + void insertImage(const std::string &name, video::IImage *img); + private: // The id of the thread that is allowed to use irrlicht directly @@ -305,31 +308,6 @@ TextureSource::~TextureSource() { } -void TextureSource::processQueue() -{ - /* - Fetch textures - */ - if(m_get_texture_queue.size() > 0) - { - GetRequest - request = m_get_texture_queue.pop(); - - infostream<<"TextureSource::processQueue(): " - <<"got texture request with " - <<"name=\""< - result; - result.key = request.key; - result.callers = request.callers; - result.item = getTextureIdDirect(request.key); - - request.dest->push_back(result); - } -} - u32 TextureSource::getTextureId(const std::string &name) { //infostream<<"getTextureId(): \""< 0) + { + GetRequest + request = m_get_texture_queue.pop(); + + infostream<<"TextureSource::processQueue(): " + <<"got texture request with " + <<"name=\""< + result; + result.key = request.key; + result.callers = request.callers; + result.item = getTextureIdDirect(request.key); + + request.dest->push_back(result); + } +} + void TextureSource::buildMainAtlas(class IGameDef *gamedef) { assert(gamedef->tsrc() == this); @@ -864,6 +867,46 @@ void TextureSource::buildMainAtlas(class IGameDef *gamedef) driver->writeImageToFile(atlas_img, atlaspath.c_str());*/ } +void TextureSource::insertImage(const std::string &name, video::IImage *img) +{ + infostream<<"TextureSource::insertImage(): name="<getVideoDriver(); + assert(driver); + + // Create texture + video::ITexture *t = driver->addTexture(name.c_str(), img); + + bool reuse_old_id = false; + u32 id = m_atlaspointer_cache.size(); + // Check old id without fetching a texture + core::map::Node *n; + n = m_name_to_id.find(name); + // If it exists, we will replace the old definition + if(n){ + id = n->getValue(); + reuse_old_id = true; + } + + // Create AtlasPointer + AtlasPointer ap(id); + ap.atlas = t; + ap.pos = v2f(0,0); + ap.size = v2f(1,1); + ap.tiled = 0; + core::dimension2d dim = img->getDimension(); + + // Create SourceAtlasPointer and add to containers + SourceAtlasPointer nap(name, ap, img, v2s32(0,0), dim); + if(reuse_old_id) + m_atlaspointer_cache[id] = nap; + else + m_atlaspointer_cache.push_back(nap); + m_name_to_id[name] = id; +} + video::IImage* generate_image_from_scratch(std::string name, IrrlichtDevice *device) { diff --git a/src/tile.h b/src/tile.h index 105692c10..17ba74e33 100644 --- a/src/tile.h +++ b/src/tile.h @@ -156,8 +156,10 @@ public: {return NULL;} virtual void updateAP(AtlasPointer &ap){}; - virtual void buildMainAtlas(class IGameDef *gamedef)=0; virtual void processQueue()=0; + virtual void buildMainAtlas(class IGameDef *gamedef)=0; + // img is eaten, do not drop it + virtual void insertImage(const std::string &name, video::IImage *img)=0; }; IWritableTextureSource* createTextureSource(IrrlichtDevice *device);