diff options
author | Perttu Ahola <celeron55@gmail.com> | 2012-01-02 13:31:50 +0200 |
---|---|---|
committer | Perttu Ahola <celeron55@gmail.com> | 2012-01-02 13:31:50 +0200 |
commit | 0e1f448b619de6651205692806c6f137f481dc43 (patch) | |
tree | 18f3a224dff6f1c2d37c392a2cc7651664d69970 /src/server.cpp | |
parent | ff82b95800b13d156a59d4936970dc3c8797b14e (diff) | |
download | minetest-0e1f448b619de6651205692806c6f137f481dc43.tar.gz minetest-0e1f448b619de6651205692806c6f137f481dc43.tar.bz2 minetest-0e1f448b619de6651205692806c6f137f481dc43.zip |
Texture cache on client (mostly made by sapier) (breaks network compatibility)
Diffstat (limited to 'src/server.cpp')
-rw-r--r-- | src/server.cpp | 324 |
1 files changed, 232 insertions, 92 deletions
diff --git a/src/server.cpp b/src/server.cpp index 3679195f3..5bd072d02 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -48,6 +48,8 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "mapgen.h" #include "content_abm.h" #include "mods.h" +#include "sha1.h" +#include "base64.h" #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")" @@ -929,6 +931,9 @@ Server::Server( } } + // Read Textures and calculate sha1 sums + PrepareTextures(); + // Initialize Environment m_env = new ServerEnvironment(new ServerMap(mapsavedir, this), m_lua, @@ -2110,8 +2115,8 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) // Send CraftItem definitions SendCraftItemDef(m_con, peer_id, m_craftitemdef); - // Send textures - SendTextures(peer_id); + // Send texture announcement + SendTextureAnnouncement(peer_id); // Send player info to all players //SendPlayerInfos(); @@ -2825,6 +2830,26 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) // ActiveObject is added to environment in AsyncRunStep after // the previous addition has been succesfully removed } + else if(command == TOSERVER_REQUEST_TEXTURES) { + std::string datastring((char*)&data[2], datasize-2); + std::istringstream is(datastring, std::ios_base::binary); + + infostream<<"TOSERVER_REQUEST_TEXTURES: "<<std::endl; + + core::list<TextureRequest> tosend; + + u16 numtextures = readU16(is); + + for(int i = 0; i < numtextures; i++) { + + std::string name = deSerializeString(is); + + tosend.push_back(TextureRequest(name)); + infostream<<"TOSERVER_REQUEST_TEXTURES: requested texture " << name <<std::endl; + } + + SendTexturesRequested(peer_id, tosend); + } else if(command == TOSERVER_INTERACT) { std::string datastring((char*)&data[2], datasize-2); @@ -4233,6 +4258,124 @@ void Server::SendBlocks(float dtime) } } +void Server::PrepareTextures() { + DSTACK(__FUNCTION_NAME); + + infostream<<"Server::PrepareTextures(): Calculate sha1 sums of textures"<<std::endl; + + for(core::list<ModSpec>::Iterator i = m_mods.begin(); + i != m_mods.end(); i++){ + const ModSpec &mod = *i; + std::string texturepath = mod.path + DIR_DELIM + "textures"; + std::vector<fs::DirListNode> dirlist = fs::GetDirListing(texturepath); + for(u32 j=0; j<dirlist.size(); j++){ + if(dirlist[j].dir) // Ignode dirs + continue; + std::string tname = dirlist[j].name; + std::string tpath = texturepath + DIR_DELIM + tname; + // Read data + std::ifstream fis(tpath.c_str(), std::ios_base::binary); + if(fis.good() == false){ + errorstream<<"Server::PrepareTextures(): Could not open \"" + <<tname<<"\" for reading"<<std::endl; + continue; + } + std::ostringstream tmp_os(std::ios_base::binary); + bool bad = false; + for(;;){ + char buf[1024]; + fis.read(buf, 1024); + std::streamsize len = fis.gcount(); + tmp_os.write(buf, len); + if(fis.eof()) + break; + if(!fis.good()){ + bad = true; + break; + } + } + if(bad){ + errorstream<<"Server::PrepareTextures(): Failed to read \"" + <<tname<<"\""<<std::endl; + continue; + } + + SHA1 sha1; + sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length()); + + unsigned char *digest = sha1.getDigest(); + std::string digest_string = base64_encode(digest, 20); + + delete(digest); + + // Put in list + this->m_Textures[tname] = TextureInformation(tpath,digest_string); + infostream<<"Server::PrepareTextures(): added sha1 for "<< tname <<std::endl; + } + } +} + +struct SendableTextureAnnouncement + { + std::string name; + std::string sha1_digest; + + SendableTextureAnnouncement(const std::string name_="", + const std::string sha1_digest_=""): + name(name_), + sha1_digest(sha1_digest_) + { + } + }; + +void Server::SendTextureAnnouncement(u16 peer_id){ + DSTACK(__FUNCTION_NAME); + + infostream<<"Server::SendTextureAnnouncement(): Calculate sha1 sums of textures and send to client"<<std::endl; + + core::list<SendableTextureAnnouncement> texture_announcements; + + for (std::map<std::string,TextureInformation>::iterator i = m_Textures.begin();i != m_Textures.end(); i++ ) { + + // Put in list + texture_announcements.push_back( + SendableTextureAnnouncement(i->first, i->second.sha1_digest)); + } + + //send announcements + + /* + u16 command + u32 number of textures + for each texture { + u16 length of name + string name + u16 length of digest string + string sha1_digest + } + */ + std::ostringstream os(std::ios_base::binary); + + writeU16(os, TOCLIENT_ANNOUNCE_TEXTURES); + writeU16(os, texture_announcements.size()); + + for(core::list<SendableTextureAnnouncement>::Iterator + j = texture_announcements.begin(); + j != texture_announcements.end(); j++){ + os<<serializeString(j->name); + os<<serializeString(j->sha1_digest); + } + + // Make data buffer + std::string s = os.str(); + infostream<<"Server::SendTextureAnnouncement(): Send to client"<<std::endl; + SharedBuffer<u8> data((u8*)s.c_str(), s.size()); + + // Send as reliable + m_con.Send(peer_id, 0, data, true); + +} + struct SendableTexture { std::string name; @@ -4247,112 +4390,109 @@ struct SendableTexture {} }; -void Server::SendTextures(u16 peer_id) -{ +void Server::SendTexturesRequested(u16 peer_id,core::list<TextureRequest> tosend) { DSTACK(__FUNCTION_NAME); - infostream<<"Server::SendTextures(): Sending textures to client"<<std::endl; - + infostream<<"Server::SendTexturesRequested(): Sending textures to client"<<std::endl; + /* Read textures */ - + // Put 5kB in one bunch (this is not accurate) u32 bytes_per_bunch = 5000; - + core::array< core::list<SendableTexture> > texture_bunches; texture_bunches.push_back(core::list<SendableTexture>()); - + u32 texture_size_bunch_total = 0; - for(core::list<ModSpec>::Iterator i = m_mods.begin(); - i != m_mods.end(); i++){ - const ModSpec &mod = *i; - std::string texturepath = mod.path + DIR_DELIM + "textures"; - std::vector<fs::DirListNode> dirlist = fs::GetDirListing(texturepath); - for(u32 j=0; j<dirlist.size(); j++){ - if(dirlist[j].dir) // Ignode dirs - continue; - std::string tname = dirlist[j].name; - std::string tpath = texturepath + DIR_DELIM + tname; - // Read data - std::ifstream fis(tpath.c_str(), std::ios_base::binary); - if(fis.good() == false){ - errorstream<<"Server::SendTextures(): Could not open \"" - <<tname<<"\" for reading"<<std::endl; - continue; - } - std::ostringstream tmp_os(std::ios_base::binary); - bool bad = false; - for(;;){ - char buf[1024]; - fis.read(buf, 1024); - std::streamsize len = fis.gcount(); - tmp_os.write(buf, len); - texture_size_bunch_total += len; - if(fis.eof()) - break; - if(!fis.good()){ - bad = true; - break; - } - } - if(bad){ - errorstream<<"Server::SendTextures(): Failed to read \"" - <<tname<<"\""<<std::endl; - continue; - } - /*infostream<<"Server::SendTextures(): Loaded \"" - <<tname<<"\""<<std::endl;*/ - // Put in list - texture_bunches[texture_bunches.size()-1].push_back( - SendableTexture(tname, tpath, tmp_os.str())); - - // Start next bunch if got enough data - if(texture_size_bunch_total >= bytes_per_bunch){ - texture_bunches.push_back(core::list<SendableTexture>()); - texture_size_bunch_total = 0; + + for(core::list<TextureRequest>::Iterator i = tosend.begin(); i != tosend.end(); i++) { + + //TODO get path + name + std::string tpath = m_Textures[(*i).name].path; + + // Read data + std::ifstream fis(tpath.c_str(), std::ios_base::binary); + if(fis.good() == false){ + errorstream<<"Server::SendTexturesRequested(): Could not open \"" + <<tpath<<"\" for reading"<<std::endl; + continue; + } + std::ostringstream tmp_os(std::ios_base::binary); + bool bad = false; + for(;;){ + char buf[1024]; + fis.read(buf, 1024); + std::streamsize len = fis.gcount(); + tmp_os.write(buf, len); + texture_size_bunch_total += len; + if(fis.eof()) + break; + if(!fis.good()){ + bad = true; + break; } } + if(bad){ + errorstream<<"Server::SendTexturesRequested(): Failed to read \"" + <<(*i).name<<"\""<<std::endl; + continue; + } + /*infostream<<"Server::SendTexturesRequested(): Loaded \"" + <<tname<<"\""<<std::endl;*/ + // Put in list + texture_bunches[texture_bunches.size()-1].push_back( + SendableTexture((*i).name, tpath, tmp_os.str())); + + // Start next bunch if got enough data + if(texture_size_bunch_total >= bytes_per_bunch){ + texture_bunches.push_back(core::list<SendableTexture>()); + texture_size_bunch_total = 0; + } + } /* Create and send packets */ - - u32 num_bunches = texture_bunches.size(); - for(u32 i=0; i<num_bunches; i++) - { - /* - 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 + + u32 num_bunches = texture_bunches.size(); + for(u32 i=0; i<num_bunches; i++) + { + /* + 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 + } + */ + std::ostringstream os(std::ios_base::binary); + + writeU16(os, TOCLIENT_TEXTURES); + writeU16(os, num_bunches); + writeU16(os, i); + writeU32(os, texture_bunches[i].size()); + + for(core::list<SendableTexture>::Iterator + j = texture_bunches[i].begin(); + j != texture_bunches[i].end(); j++){ + os<<serializeString(j->name); + os<<serializeLongString(j->data); } - */ - std::ostringstream os(std::ios_base::binary); - writeU16(os, TOCLIENT_TEXTURES); - writeU16(os, num_bunches); - writeU16(os, i); - writeU32(os, texture_bunches[i].size()); - - for(core::list<SendableTexture>::Iterator - j = texture_bunches[i].begin(); - j != texture_bunches[i].end(); j++){ - os<<serializeString(j->name); - os<<serializeLongString(j->data); + // Make data buffer + std::string s = os.str(); + infostream<<"Server::SendTexturesRequested(): bunch "<<i<<"/"<<num_bunches + <<" textures="<<texture_bunches[i].size() + <<" size=" <<s.size()<<std::endl; + SharedBuffer<u8> data((u8*)s.c_str(), s.size()); + // Send as reliable + m_con.Send(peer_id, 0, data, true); } - - // Make data buffer - std::string s = os.str(); - infostream<<"Server::SendTextures(): bunch "<<i<<"/"<<num_bunches - <<" textures="<<texture_bunches[i].size() - <<" size=" <<s.size()<<std::endl; - SharedBuffer<u8> data((u8*)s.c_str(), s.size()); - // Send as reliable - m_con.Send(peer_id, 0, data, true); - } + + } /* |