summaryrefslogtreecommitdiff
path: root/src/client.cpp
diff options
context:
space:
mode:
authorPerttu Ahola <celeron55@gmail.com>2012-01-02 13:31:50 +0200
committerPerttu Ahola <celeron55@gmail.com>2012-01-02 13:31:50 +0200
commit0e1f448b619de6651205692806c6f137f481dc43 (patch)
tree18f3a224dff6f1c2d37c392a2cc7651664d69970 /src/client.cpp
parentff82b95800b13d156a59d4936970dc3c8797b14e (diff)
downloadminetest-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/client.cpp')
-rw-r--r--src/client.cpp181
1 files changed, 181 insertions, 0 deletions
diff --git a/src/client.cpp b/src/client.cpp
index cfdc713db..e3b250b32 100644
--- a/src/client.cpp
+++ b/src/client.cpp
@@ -36,6 +36,22 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "tooldef.h"
#include "craftitemdef.h"
#include <IFileSystem.h>
+#include "sha1.h"
+#include "base64.h"
+
+static std::string getTextureCacheDir()
+{
+ return porting::path_userdata + DIR_DELIM + "cache" + DIR_DELIM + "texture";
+}
+
+struct TextureRequest
+{
+ std::string name;
+
+ TextureRequest(const std::string &name_=""):
+ name(name_)
+ {}
+};
/*
QueuedMeshUpdate
@@ -1232,6 +1248,157 @@ 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_ANNOUNCE_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.setRun(false);
+ // Process the remaining TextureSource queue to let MeshUpdateThread
+ // get it's remaining textures and thus let it stop
+ while(m_mesh_update_thread.IsRunning()){
+ m_tsrc->processQueue();
+ }
+
+ int num_textures = readU16(is);
+
+ core::list<TextureRequest> texture_requests;
+
+ for(int i=0; i<num_textures; i++){
+
+ bool texture_found = false;
+
+ //read texture from cache
+ std::string name = deSerializeString(is);
+ std::string sha1_texture = deSerializeString(is);
+
+ std::string tpath = getTextureCacheDir() + DIR_DELIM + name;
+ // Read data
+ std::ifstream fis(tpath.c_str(), std::ios_base::binary);
+
+
+ if(fis.good() == false){
+ infostream<<"Client::Texture not found in cache: "
+ <<name << " expected it at: "<<tpath<<std::endl;
+ }
+ else
+ {
+ 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){
+ infostream<<"Client: Failed to read texture from cache\""
+ <<name<<"\""<<std::endl;
+ }
+ else {
+
+ 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);
+
+ if (digest_string == sha1_texture) {
+ // Silly irrlicht's const-incorrectness
+ Buffer<char> data_rw(tmp_os.str().c_str(), tmp_os.str().size());
+
+ // Create an irrlicht memory file
+ io::IReadFile *rfile = irrfs->createMemoryReadFile(
+ *data_rw, tmp_os.str().size(), "_tempreadfile");
+ assert(rfile);
+ // Read image
+ video::IImage *img = vdrv->createImageFromFile(rfile);
+ if(!img){
+ infostream<<"Client: Cannot create image from data of "
+ <<"received texture \""<<name<<"\""<<std::endl;
+ rfile->drop();
+ }
+ else {
+ m_tsrc->insertSourceImage(name, img);
+ img->drop();
+ rfile->drop();
+
+ texture_found = true;
+ }
+ }
+ else {
+ infostream<<"Client::Texture cached sha1 hash not matching server hash: "
+ <<name << ": server ->"<<sha1_texture <<" client -> "<<digest_string<<std::endl;
+ }
+
+ delete(digest);
+ }
+ }
+
+ //add texture request
+ if (!texture_found) {
+ infostream<<"Client: Adding texture to request list: \""
+ <<name<<"\""<<std::endl;
+ texture_requests.push_back(TextureRequest(name));
+ }
+
+ }
+ // 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);
+
+
+ //send Texture request
+ /*
+ u16 command
+ u16 number of textures requested
+ for each texture {
+ u16 length of name
+ string name
+ u16 length of path
+ string path
+ }
+ */
+ std::ostringstream os(std::ios_base::binary);
+ u8 buf[12];
+
+
+ // Write command
+ writeU16(buf, TOSERVER_REQUEST_TEXTURES);
+ os.write((char*)buf, 2);
+
+ writeU16(buf,texture_requests.size());
+ os.write((char*)buf, 2);
+
+
+ for(core::list<TextureRequest>::Iterator i = texture_requests.begin();
+ i != texture_requests.end(); i++) {
+ os<<serializeString(i->name);
+ }
+
+ // Make data buffer
+ std::string s = os.str();
+ SharedBuffer<u8> data((u8*)s.c_str(), s.size());
+ // Send as reliable
+ Send(0, data, true);
+ infostream<<"Client: Sending request list to server " <<std::endl;
+ }
else if(command == TOCLIENT_TEXTURES)
{
io::IFileSystem *irrfs = m_device->getFileSystem();
@@ -1286,6 +1453,20 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
rfile->drop();
continue;
}
+
+ fs::CreateAllDirs(getTextureCacheDir());
+
+ std::string filename = getTextureCacheDir() + DIR_DELIM + name;
+ std::ofstream outfile(filename.c_str(), std::ios_base::binary | std::ios_base::trunc);
+
+ if (outfile.good()) {
+ outfile.write(data.c_str(),data.length());
+ outfile.close();
+ }
+ else {
+ errorstream<<"Client: Unable to open cached texture file "<< filename <<std::endl;
+ }
+
m_tsrc->insertSourceImage(name, img);
img->drop();
rfile->drop();