Fixed compressing, and started work on sending meshes (sorry for the dirty code)
parent
ba121612cf
commit
e970a169d4
407
src/client.cpp
407
src/client.cpp
|
@ -48,6 +48,11 @@ static std::string getMediaCacheDir()
|
|||
return porting::path_user + DIR_DELIM + "cache" + DIR_DELIM + "media";
|
||||
}
|
||||
|
||||
static std::string getMeshCacheDir()
|
||||
{
|
||||
return porting::path_user + DIR_DELIM + "cache" + DIR_DELIM + "meshes";
|
||||
}
|
||||
|
||||
struct MediaRequest
|
||||
{
|
||||
std::string name;
|
||||
|
@ -57,6 +62,15 @@ struct MediaRequest
|
|||
{}
|
||||
};
|
||||
|
||||
struct MeshRequest
|
||||
{
|
||||
std::string name;
|
||||
|
||||
MeshRequest(const std::string &name_=""):
|
||||
name(name_)
|
||||
{}
|
||||
};
|
||||
|
||||
/*
|
||||
QueuedMeshUpdate
|
||||
*/
|
||||
|
@ -259,8 +273,11 @@ Client::Client(
|
|||
m_password(password),
|
||||
m_access_denied(false),
|
||||
m_media_cache(getMediaCacheDir()),
|
||||
m_mesh_cache(getMeshCacheDir()),
|
||||
m_media_receive_progress(0),
|
||||
m_media_received(false),
|
||||
m_mesh_receive_progress(0),
|
||||
m_meshes_received(false),
|
||||
m_itemdef_received(false),
|
||||
m_nodedef_received(false),
|
||||
m_time_of_day_set(false),
|
||||
|
@ -853,18 +870,31 @@ bool Client::loadMedia(const std::string &data, const std::string &filename)
|
|||
m_sound->loadSoundData(name, data);
|
||||
return true;
|
||||
}
|
||||
|
||||
errorstream<<"Client: Don't know how to load file \""
|
||||
<<filename<<"\""<<std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Client::loadMeshes(const std::string &data, const std::string &filename)
|
||||
{
|
||||
// Silly irrlicht's const-incorrectness
|
||||
Buffer<char> data_rw(data.c_str(), data.size());
|
||||
|
||||
const char *mesh_ext[] = {
|
||||
std::string name;
|
||||
|
||||
const char *ext[] = {
|
||||
".png", ".jpg", ".bmp", ".tga",
|
||||
".pcx", ".ppm", ".psd", ".wal", ".rgb",
|
||||
".3ds", ".obj", ".md2", ".md3", ".b3d",
|
||||
".ply", ".stl", NULL
|
||||
};
|
||||
name = removeStringEnd(filename, mesh_ext);
|
||||
name = removeStringEnd(filename, ext);
|
||||
if(name != "")
|
||||
{
|
||||
verbosestream<<"Client: Attempting to load mesh "
|
||||
verbosestream<<"Client: Attempting to load image "
|
||||
<<"file \""<<filename<<"\""<<std::endl;
|
||||
std::string basepath = porting::path_user + DIR_DELIM + "cache" +
|
||||
DIR_DELIM + "media";
|
||||
std::string basepath = getMeshCacheDir();
|
||||
std::string path = basepath + DIR_DELIM + filename;
|
||||
fs::CreateAllDirs(basepath);
|
||||
std::ofstream of(path.c_str(), std::ios::binary);
|
||||
|
@ -872,9 +902,6 @@ bool Client::loadMedia(const std::string &data, const std::string &filename)
|
|||
of.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
errorstream<<"Client: Don't know how to load file \""
|
||||
<<filename<<"\""<<std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1464,58 +1491,59 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
|
|||
{
|
||||
std::string datastring((char*)&data[2], datasize-2);
|
||||
std::istringstream is2(datastring, std::ios_base::binary);
|
||||
std::istringstream tmp_is(deSerializeLongString(is2), std::ios::binary);
|
||||
std::ostringstream tmp_os;
|
||||
decompressZlib(tmp_is, tmp_os);
|
||||
std::istringstream is(tmp_os.str());
|
||||
|
||||
// Mesh update thread must be stopped while
|
||||
// updating content definitions
|
||||
assert(!m_mesh_update_thread.IsRunning());
|
||||
|
||||
int num_files = readU16(is);
|
||||
int num_files = readU16(is2);
|
||||
|
||||
verbosestream<<"Client received TOCLIENT_ANNOUNCE_MEDIA ("
|
||||
<<num_files<<" files)"<<std::endl;
|
||||
|
||||
core::list<MediaRequest> file_requests;
|
||||
|
||||
for(int i=0; i<num_files; i++)
|
||||
if(num_files > 0)
|
||||
{
|
||||
//read file from cache
|
||||
std::string name = deSerializeString(is);
|
||||
std::string sha1_base64 = deSerializeString(is);
|
||||
|
||||
// if name contains illegal characters, ignore the file
|
||||
if(!string_allowed(name, TEXTURENAME_ALLOWED_CHARS)){
|
||||
errorstream<<"Client: ignoring illegal file name "
|
||||
<<"sent by server: \""<<name<<"\""<<std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string sha1_raw = base64_decode(sha1_base64);
|
||||
std::string sha1_hex = hex_encode(sha1_raw);
|
||||
std::ostringstream tmp_os(std::ios_base::binary);
|
||||
bool found_in_cache = m_media_cache.load_sha1(sha1_raw, tmp_os);
|
||||
m_media_name_sha1_map.set(name, sha1_raw);
|
||||
|
||||
// If found in cache, try to load it from there
|
||||
if(found_in_cache)
|
||||
std::istringstream tmp_is(deSerializeLongString(is2), std::ios::binary);
|
||||
std::ostringstream tmp_os;
|
||||
decompressZlib(tmp_is, tmp_os);
|
||||
std::istringstream is(tmp_os.str());
|
||||
for(int i=0; i<num_files; i++)
|
||||
{
|
||||
bool success = loadMedia(tmp_os.str(), name);
|
||||
if(success){
|
||||
verbosestream<<"Client: Loaded cached media: "
|
||||
<<sha1_hex<<" \""<<name<<"\""<<std::endl;
|
||||
//read file from cache
|
||||
std::string name = deSerializeString(is);
|
||||
std::string sha1_base64 = deSerializeString(is);
|
||||
|
||||
// if name contains illegal characters, ignore the file
|
||||
if(!string_allowed(name, TEXTURENAME_ALLOWED_CHARS)){
|
||||
errorstream<<"Client: ignoring illegal file name "
|
||||
<<"sent by server: \""<<name<<"\""<<std::endl;
|
||||
continue;
|
||||
} else{
|
||||
infostream<<"Client: Failed to load cached media: "
|
||||
<<sha1_hex<<" \""<<name<<"\""<<std::endl;
|
||||
}
|
||||
|
||||
std::string sha1_raw = base64_decode(sha1_base64);
|
||||
std::string sha1_hex = hex_encode(sha1_raw);
|
||||
std::ostringstream tmp_os(std::ios_base::binary);
|
||||
bool found_in_cache = m_media_cache.load_sha1(sha1_raw, tmp_os);
|
||||
m_media_name_sha1_map.set(name, sha1_raw);
|
||||
|
||||
// If found in cache, try to load it from there
|
||||
if(found_in_cache)
|
||||
{
|
||||
bool success = loadMedia(tmp_os.str(), name);
|
||||
if(success){
|
||||
verbosestream<<"Client: Loaded cached media: "
|
||||
<<sha1_hex<<" \""<<name<<"\""<<std::endl;
|
||||
continue;
|
||||
} else{
|
||||
infostream<<"Client: Failed to load cached media: "
|
||||
<<sha1_hex<<" \""<<name<<"\""<<std::endl;
|
||||
}
|
||||
}
|
||||
// Didn't load from cache; queue it to be requested
|
||||
verbosestream<<"Client: Adding file to request list: \""
|
||||
<<sha1_hex<<" \""<<name<<"\""<<std::endl;
|
||||
file_requests.push_back(MediaRequest(name));
|
||||
}
|
||||
// Didn't load from cache; queue it to be requested
|
||||
verbosestream<<"Client: Adding file to request list: \""
|
||||
<<sha1_hex<<" \""<<name<<"\""<<std::endl;
|
||||
file_requests.push_back(MediaRequest(name));
|
||||
}
|
||||
|
||||
ClientEvent event;
|
||||
|
@ -1551,10 +1579,6 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
|
|||
{
|
||||
std::string datastring((char*)&data[2], datasize-2);
|
||||
std::istringstream is2(datastring, std::ios_base::binary);
|
||||
std::istringstream tmp_is(deSerializeLongString(is2), std::ios::binary);
|
||||
std::ostringstream tmp_os;
|
||||
decompressZlib(tmp_is, tmp_os);
|
||||
std::istringstream is(tmp_os.str());
|
||||
|
||||
// Mesh update thread must be stopped while
|
||||
// updating content definitions
|
||||
|
@ -1572,53 +1596,72 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
|
|||
data
|
||||
}
|
||||
*/
|
||||
int num_bunches = readU16(is);
|
||||
int bunch_i = readU16(is);
|
||||
int num_bunches = readU16(is2);
|
||||
int bunch_i = readU16(is2);
|
||||
if(num_bunches >= 2)
|
||||
{
|
||||
m_media_receive_progress = (float)bunch_i / (float)(num_bunches - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_media_receive_progress = 1.0;
|
||||
}
|
||||
if(bunch_i == num_bunches - 1)
|
||||
{
|
||||
m_media_received = true;
|
||||
int num_files = readU32(is);
|
||||
infostream<<"Client: Received files: bunch "<<bunch_i<<"/"
|
||||
<<num_bunches<<" files="<<num_files
|
||||
<<" size="<<datasize<<std::endl;
|
||||
for(int i=0; i<num_files; i++){
|
||||
std::string name = deSerializeString(is);
|
||||
std::string data = deSerializeLongString(is);
|
||||
|
||||
// if name contains illegal characters, ignore the file
|
||||
if(!string_allowed(name, TEXTURENAME_ALLOWED_CHARS)){
|
||||
errorstream<<"Client: ignoring illegal file name "
|
||||
<<"sent by server: \""<<name<<"\""<<std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
bool success = loadMedia(data, name);
|
||||
if(success){
|
||||
verbosestream<<"Client: Loaded received media: "
|
||||
<<"\""<<name<<"\". Caching."<<std::endl;
|
||||
} else{
|
||||
infostream<<"Client: Failed to load received media: "
|
||||
<<"\""<<name<<"\". Not caching."<<std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
bool did = fs::CreateAllDirs(getMediaCacheDir());
|
||||
if(!did){
|
||||
errorstream<<"Could not create media cache directory"
|
||||
<<std::endl;
|
||||
}
|
||||
|
||||
}
|
||||
int num_files = readU32(is2);
|
||||
if(num_files >= 1)
|
||||
{
|
||||
std::istringstream tmp_is(deSerializeLongString(is2), std::ios::binary);
|
||||
std::ostringstream tmp_os;
|
||||
decompressZlib(tmp_is, tmp_os);
|
||||
std::istringstream is(tmp_os.str());
|
||||
infostream<<"Client: Received files: bunch "<<bunch_i<<"/"
|
||||
<<num_bunches<<" files="<<num_files
|
||||
<<" size="<<datasize<<std::endl;
|
||||
for(int i=0; i<num_files; i++)
|
||||
{
|
||||
core::map<std::string, std::string>::Node *n;
|
||||
n = m_media_name_sha1_map.find(name);
|
||||
if(n == NULL)
|
||||
errorstream<<"The server sent a file that has not "
|
||||
<<"been announced."<<std::endl;
|
||||
std::string name = deSerializeString(is);
|
||||
std::string data = deSerializeLongString(is);
|
||||
|
||||
// if name contains illegal characters, ignore the file
|
||||
if(!string_allowed(name, TEXTURENAME_ALLOWED_CHARS))
|
||||
{
|
||||
errorstream<<"Client: ignoring illegal file name "
|
||||
<<"sent by server: \""<<name<<"\""<<std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
bool success = loadMedia(data, name);
|
||||
if(success)
|
||||
{
|
||||
verbosestream<<"Client: Loaded received media: "
|
||||
<<"\""<<name<<"\". Caching."<<std::endl;
|
||||
}
|
||||
else
|
||||
m_media_cache.update_sha1(data);
|
||||
{
|
||||
infostream<<"Client: Failed to load received media: "
|
||||
<<"\""<<name<<"\". Not caching."<<std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
bool did = fs::CreateAllDirs(getMediaCacheDir());
|
||||
if(!did)
|
||||
{
|
||||
errorstream<<"Could not create media cache directory"
|
||||
<<std::endl;
|
||||
}
|
||||
|
||||
{
|
||||
core::map<std::string, std::string>::Node *n;
|
||||
n = m_media_name_sha1_map.find(name);
|
||||
if(n == NULL)
|
||||
errorstream<<"The server sent a file that has not "
|
||||
<<"been announced."<<std::endl;
|
||||
else
|
||||
m_media_cache.update_sha1(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1626,6 +1669,192 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
|
|||
event.type = CE_TEXTURES_UPDATED;
|
||||
m_client_event_queue.push_back(event);
|
||||
}
|
||||
else if(command == TOCLIENT_ANNOUNCE_MESH)
|
||||
{
|
||||
std::string datastring((char*)&data[2], datasize-2);
|
||||
std::istringstream is2(datastring, std::ios_base::binary);
|
||||
|
||||
// Mesh update thread must be stopped while
|
||||
// updating content definitions
|
||||
assert(!m_mesh_update_thread.IsRunning());
|
||||
|
||||
int num_files = readU16(is2);
|
||||
|
||||
verbosestream<<"Client received TOCLIENT_ANNOUNCE_MESH ("
|
||||
<<num_files<<" files)"<<std::endl;
|
||||
core::list<MeshRequest> file_requests;
|
||||
if(num_files > 0)
|
||||
{
|
||||
std::istringstream tmp_is(deSerializeLongString(is2), std::ios::binary);
|
||||
std::ostringstream tmp_os;
|
||||
decompressZlib(tmp_is, tmp_os);
|
||||
std::istringstream is(tmp_os.str());
|
||||
for(int i=0; i<num_files; i++)
|
||||
{
|
||||
//read file from cache
|
||||
std::string name = deSerializeString(is);
|
||||
std::string sha1_base64 = deSerializeString(is);
|
||||
|
||||
// if name contains illegal characters, ignore the file
|
||||
if(!string_allowed(name, TEXTURENAME_ALLOWED_CHARS)){
|
||||
errorstream<<"Client: ignoring illegal file name "
|
||||
<<"sent by server: \""<<name<<"\""<<std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string sha1_raw = base64_decode(sha1_base64);
|
||||
std::string sha1_hex = hex_encode(sha1_raw);
|
||||
std::ostringstream tmp_os(std::ios_base::binary);
|
||||
bool found_in_cache = m_mesh_cache.load_sha1(sha1_raw, tmp_os);
|
||||
m_mesh_name_sha1_map.set(name, sha1_raw);
|
||||
|
||||
// If found in cache, try to load it from there
|
||||
if(found_in_cache)
|
||||
{
|
||||
bool success = loadMeshes(tmp_os.str(), name);
|
||||
if(success)
|
||||
{
|
||||
verbosestream<<"Client: Loaded cached meshes: "
|
||||
<<sha1_hex<<" \""<<name<<"\""<<std::endl;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
infostream<<"Client: Failed to load cached meshes: "
|
||||
<<sha1_hex<<" \""<<name<<"\""<<std::endl;
|
||||
}
|
||||
}
|
||||
// Didn't load from cache; queue it to be requested
|
||||
verbosestream<<"Client: Adding file to request list: \""
|
||||
<<sha1_hex<<" \""<<name<<"\""<<std::endl;
|
||||
file_requests.push_back(MeshRequest(name));
|
||||
}
|
||||
}
|
||||
|
||||
ClientEvent event;
|
||||
event.type = CE_MESHES_UPDATED;
|
||||
m_client_event_queue.push_back(event);
|
||||
|
||||
/*
|
||||
u16 command
|
||||
u16 number of files requested
|
||||
for each file {
|
||||
u16 length of name
|
||||
string name
|
||||
}
|
||||
*/
|
||||
std::ostringstream os(std::ios_base::binary);
|
||||
writeU16(os, TOSERVER_REQUEST_MESH);
|
||||
writeU16(os, file_requests.size());
|
||||
|
||||
for(core::list<MeshRequest>::Iterator i = file_requests.begin();
|
||||
i != file_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 mesh request list to server ("
|
||||
<<file_requests.size()<<" files)"<<std::endl;
|
||||
}
|
||||
else if(command == TOCLIENT_MESH)
|
||||
{
|
||||
std::string datastring((char*)&data[2], datasize-2);
|
||||
std::istringstream is2(datastring, std::ios_base::binary);
|
||||
|
||||
// Mesh update thread must be stopped while
|
||||
// updating content definitions
|
||||
assert(!m_mesh_update_thread.IsRunning());
|
||||
|
||||
/*
|
||||
u16 command
|
||||
u16 total number of file bunches
|
||||
u16 index of this bunch
|
||||
u32 number of files in this bunch
|
||||
for each file {
|
||||
u16 length of name
|
||||
string name
|
||||
u32 length of data
|
||||
data
|
||||
}
|
||||
*/
|
||||
int num_bunches = readU16(is2);
|
||||
int bunch_i = readU16(is2);
|
||||
if(num_bunches >= 2)
|
||||
{
|
||||
m_mesh_receive_progress = (float)bunch_i / (float)(num_bunches - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_mesh_receive_progress = 1.0;
|
||||
}
|
||||
if(bunch_i == num_bunches - 1)
|
||||
{
|
||||
m_meshes_received = true;
|
||||
}
|
||||
int num_files = readU32(is2);
|
||||
if(num_files >= 1)
|
||||
{
|
||||
std::istringstream tmp_is(deSerializeLongString(is2), std::ios::binary);
|
||||
std::ostringstream tmp_os;
|
||||
decompressZlib(tmp_is, tmp_os);
|
||||
std::istringstream is(tmp_os.str());
|
||||
infostream<<"Client: Received files: bunch "<<bunch_i<<"/"
|
||||
<<num_bunches<<" files="<<num_files
|
||||
<<" size="<<datasize<<std::endl;
|
||||
for(int i=0; i<num_files; i++)
|
||||
{
|
||||
std::string name = deSerializeString(is);
|
||||
std::string data = deSerializeLongString(is);
|
||||
|
||||
// if name contains illegal characters, ignore the file
|
||||
if(!string_allowed(name, TEXTURENAME_ALLOWED_CHARS))
|
||||
{
|
||||
errorstream<<"Client: ignoring illegal file name "
|
||||
<<"sent by server: \""<<name<<"\""<<std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
bool success = loadMeshes(data, name);
|
||||
if(success)
|
||||
{
|
||||
verbosestream<<"Client: Loaded received meshes: "
|
||||
<<"\""<<name<<"\". Caching."<<std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
infostream<<"Client: Failed to load received meshes: "
|
||||
<<"\""<<name<<"\". Not caching."<<std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
bool did = fs::CreateAllDirs(getMeshCacheDir());
|
||||
if(!did)
|
||||
{
|
||||
errorstream<<"Could not create mesh cache directory"
|
||||
<<std::endl;
|
||||
}
|
||||
|
||||
{
|
||||
core::map<std::string, std::string>::Node *n;
|
||||
n = m_mesh_name_sha1_map.find(name);
|
||||
if(n == NULL)
|
||||
errorstream<<"The server sent a file that has not "
|
||||
<<"been announced."<<std::endl;
|
||||
else
|
||||
m_mesh_cache.update_sha1(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ClientEvent event;
|
||||
event.type = CE_MESHES_UPDATED;
|
||||
m_client_event_queue.push_back(event);
|
||||
}
|
||||
|
||||
else if(command == TOCLIENT_TOOLDEF)
|
||||
{
|
||||
infostream<<"Client: WARNING: Ignoring TOCLIENT_TOOLDEF"<<std::endl;
|
||||
|
|
14
src/client.h
14
src/client.h
|
@ -135,7 +135,8 @@ enum ClientEventType
|
|||
CE_PLAYER_FORCE_MOVE,
|
||||
CE_KICKED,
|
||||
CE_DEATHSCREEN,
|
||||
CE_TEXTURES_UPDATED
|
||||
CE_TEXTURES_UPDATED,
|
||||
CE_MESHES_UPDATED
|
||||
};
|
||||
|
||||
struct ClientEvent
|
||||
|
@ -291,8 +292,13 @@ public:
|
|||
float mediaReceiveProgress()
|
||||
{ return m_media_receive_progress; }
|
||||
|
||||
float meshReceiveProgress()
|
||||
{ return m_mesh_receive_progress; }
|
||||
|
||||
bool texturesReceived()
|
||||
{ return m_media_received; }
|
||||
bool meshesReceived()
|
||||
{ return m_meshes_received; }
|
||||
bool itemdefReceived()
|
||||
{ return m_itemdef_received; }
|
||||
bool nodedefReceived()
|
||||
|
@ -317,6 +323,7 @@ private:
|
|||
|
||||
// Insert a media file appropriately into the appropriate manager
|
||||
bool loadMedia(const std::string &data, const std::string &filename);
|
||||
bool loadMeshes(const std::string &data, const std::string &filename);
|
||||
|
||||
// Virtual methods from con::PeerHandler
|
||||
void peerAdded(con::Peer *peer);
|
||||
|
@ -373,8 +380,13 @@ private:
|
|||
FileCache m_media_cache;
|
||||
// Mapping from media file name to SHA1 checksum
|
||||
core::map<std::string, std::string> m_media_name_sha1_map;
|
||||
FileCache m_mesh_cache;
|
||||
// Mapping from media file name to SHA1 checksum
|
||||
core::map<std::string, std::string> m_mesh_name_sha1_map;
|
||||
float m_media_receive_progress;
|
||||
bool m_media_received;
|
||||
float m_mesh_receive_progress;
|
||||
bool m_meshes_received;
|
||||
bool m_itemdef_received;
|
||||
bool m_nodedef_received;
|
||||
friend class FarMesh;
|
||||
|
|
|
@ -321,6 +321,33 @@ enum ToClientCommand
|
|||
/*
|
||||
u16 command
|
||||
*/
|
||||
|
||||
TOCLIENT_MESH = 0x45,
|
||||
/*
|
||||
u16 command
|
||||
u16 total number of texture bunches
|
||||
u16 index of this bunch
|
||||
u32 number of files in this bunch
|
||||
for each file {
|
||||
u16 length of name
|
||||
string name
|
||||
u32 length of data
|
||||
data
|
||||
}
|
||||
*/
|
||||
|
||||
TOCLIENT_ANNOUNCE_MESH = 0x46,
|
||||
|
||||
/*
|
||||
u16 command
|
||||
u32 number of files
|
||||
for each texture {
|
||||
u16 length of name
|
||||
string name
|
||||
u16 length of sha1_digest
|
||||
string sha1_digest
|
||||
}
|
||||
*/
|
||||
};
|
||||
|
||||
enum ToServerCommand
|
||||
|
@ -511,6 +538,16 @@ enum ToServerCommand
|
|||
}
|
||||
*/
|
||||
|
||||
TOSERVER_REQUEST_MESH = 0x41,
|
||||
/*
|
||||
u16 command
|
||||
u16 number of files requested
|
||||
for each file {
|
||||
u16 length of name
|
||||
string name
|
||||
}
|
||||
*/
|
||||
|
||||
};
|
||||
|
||||
inline SharedBuffer<u8> makePacket_TOCLIENT_TIME_OF_DAY(u16 time, float time_speed)
|
||||
|
|
338
src/server.cpp
338
src/server.cpp
|
@ -2282,6 +2282,9 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
|||
|
||||
// Send media announcement
|
||||
sendMediaAnnouncement(peer_id);
|
||||
|
||||
// Send mesh announcement
|
||||
//sendMeshAnnouncement(peer_id);
|
||||
|
||||
// Send privileges
|
||||
SendPlayerPrivileges(peer_id);
|
||||
|
@ -2926,7 +2929,8 @@ 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_MEDIA) {
|
||||
else if(command == TOSERVER_REQUEST_MEDIA)
|
||||
{
|
||||
std::string datastring((char*)&data[2], datasize-2);
|
||||
std::istringstream is(datastring, std::ios_base::binary);
|
||||
|
||||
|
@ -2950,6 +2954,31 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
|||
// (definitions and files)
|
||||
getClient(peer_id)->definitions_sent = true;
|
||||
}
|
||||
else if(command == TOSERVER_REQUEST_MESH)
|
||||
{
|
||||
std::string datastring((char*)&data[2], datasize-2);
|
||||
std::istringstream is(datastring, std::ios_base::binary);
|
||||
|
||||
core::list<MeshRequest> tosend;
|
||||
u16 numfiles = readU16(is);
|
||||
|
||||
infostream<<"Sending "<<numfiles<<" files to "
|
||||
<<getPlayerName(peer_id)<<std::endl;
|
||||
verbosestream<<"TOSERVER_REQUEST_MESH: "<<std::endl;
|
||||
|
||||
for(int i = 0; i < numfiles; i++) {
|
||||
std::string name = deSerializeString(is);
|
||||
tosend.push_back(MeshRequest(name));
|
||||
verbosestream<<"TOSERVER_REQUEST_MESH: requested file "
|
||||
<<name<<std::endl;
|
||||
}
|
||||
|
||||
sendRequestedMesh(peer_id, tosend);
|
||||
|
||||
// Now the client should know about everything
|
||||
// (definitions and files)
|
||||
getClient(peer_id)->definitions_sent = true;
|
||||
}
|
||||
else if(command == TOSERVER_INTERACT)
|
||||
{
|
||||
std::string datastring((char*)&data[2], datasize-2);
|
||||
|
@ -4219,7 +4248,7 @@ void Server::sendMediaAnnouncement(u16 peer_id)
|
|||
*/
|
||||
|
||||
writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
|
||||
writeU16(tmp_os, file_announcements.size());
|
||||
writeU16(os, file_announcements.size());
|
||||
|
||||
for(core::list<SendableMediaAnnouncement>::Iterator
|
||||
j = file_announcements.begin();
|
||||
|
@ -4347,9 +4376,9 @@ void Server::sendRequestedMedia(u16 peer_id,
|
|||
*/
|
||||
|
||||
writeU16(os, TOCLIENT_MEDIA);
|
||||
writeU16(tmp_os, num_bunches);
|
||||
writeU16(tmp_os, i);
|
||||
writeU32(tmp_os, file_bunches[i].size());
|
||||
writeU16(os, num_bunches);
|
||||
writeU16(os, i);
|
||||
writeU32(os, file_bunches[i].size());
|
||||
|
||||
for(core::list<SendableMedia>::Iterator
|
||||
j = file_bunches[i].begin();
|
||||
|
@ -4373,6 +4402,305 @@ void Server::sendRequestedMedia(u16 peer_id,
|
|||
}
|
||||
}
|
||||
|
||||
void Server::fillMeshCache()
|
||||
{
|
||||
DSTACK(__FUNCTION_NAME);
|
||||
|
||||
infostream<<"Server: Calculating mesh file checksums"<<std::endl;
|
||||
|
||||
// Collect all media file paths
|
||||
std::list<std::string> paths;
|
||||
for(core::list<ModSpec>::Iterator i = m_mods.begin();
|
||||
i != m_mods.end(); i++){
|
||||
const ModSpec &mod = *i;
|
||||
paths.push_back(mod.path + DIR_DELIM + "meshes");
|
||||
paths.push_back(mod.path + DIR_DELIM + "meshtextures");
|
||||
}
|
||||
|
||||
// Collect media file information from paths into cache
|
||||
for(std::list<std::string>::iterator i = paths.begin();
|
||||
i != paths.end(); i++)
|
||||
{
|
||||
std::string meshpath = *i;
|
||||
std::vector<fs::DirListNode> dirlist = fs::GetDirListing(meshpath);
|
||||
for(u32 j=0; j<dirlist.size(); j++){
|
||||
if(dirlist[j].dir) // Ignode dirs
|
||||
continue;
|
||||
std::string filename = dirlist[j].name;
|
||||
// If name contains illegal characters, ignore the file
|
||||
if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
|
||||
infostream<<"Server: ignoring illegal file name: \""
|
||||
<<filename<<"\""<<std::endl;
|
||||
continue;
|
||||
}
|
||||
// If name is not in a supported format, ignore it
|
||||
const char *supported_ext[] = {
|
||||
".png", ".jpg", ".bmp", ".tga",
|
||||
".pcx", ".ppm", ".psd", ".wal", ".rgb",
|
||||
".obj", ".3ds", ".md2", ".md3",
|
||||
".b3d", ".ply", ".stl",
|
||||
NULL
|
||||
};
|
||||
if(removeStringEnd(filename, supported_ext) == ""){
|
||||
infostream<<"Server: ignoring unsupported file extension: \""
|
||||
<<filename<<"\""<<std::endl;
|
||||
continue;
|
||||
}
|
||||
// Ok, attempt to load the file and add to cache
|
||||
std::string filepath = meshpath + DIR_DELIM + filename;
|
||||
// Read data
|
||||
std::ifstream fis(filepath.c_str(), std::ios_base::binary);
|
||||
if(fis.good() == false){
|
||||
errorstream<<"Server::fillMeshCache(): Could not open \""
|
||||
<<filename<<"\" 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::fillMeshCache(): Failed to read \""
|
||||
<<filename<<"\""<<std::endl;
|
||||
continue;
|
||||
}
|
||||
if(tmp_os.str().length() == 0){
|
||||
errorstream<<"Server::fillMeshCache(): Empty file \""
|
||||
<<filepath<<"\""<<std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
SHA1 sha1;
|
||||
sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
|
||||
|
||||
unsigned char *digest = sha1.getDigest();
|
||||
std::string sha1_base64 = base64_encode(digest, 20);
|
||||
std::string sha1_hex = hex_encode((char*)digest, 20);
|
||||
free(digest);
|
||||
|
||||
// Put in list
|
||||
this->m_mesh[filename] = MeshInfo(filepath, sha1_base64);
|
||||
verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct SendableMeshAnnouncement
|
||||
{
|
||||
std::string name;
|
||||
std::string sha1_digest;
|
||||
|
||||
SendableMeshAnnouncement(const std::string name_="",
|
||||
const std::string sha1_digest_=""):
|
||||
name(name_),
|
||||
sha1_digest(sha1_digest_)
|
||||
{}
|
||||
};
|
||||
|
||||
void Server::sendMeshAnnouncement(u16 peer_id)
|
||||
{
|
||||
DSTACK(__FUNCTION_NAME);
|
||||
|
||||
verbosestream<<"Server: Announcing 3D files to id("<<peer_id<<")"
|
||||
<<std::endl;
|
||||
|
||||
core::list<SendableMeshAnnouncement> file_announcements;
|
||||
|
||||
for(std::map<std::string, MeshInfo>::iterator i = m_mesh.begin();
|
||||
i != m_mesh.end(); i++){
|
||||
// Put in list
|
||||
file_announcements.push_back(
|
||||
SendableMeshAnnouncement(i->first, i->second.sha1_digest));
|
||||
}
|
||||
|
||||
// Make packet
|
||||
std::ostringstream os(std::ios_base::binary);
|
||||
std::ostringstream tmp_os(std::ios_base::binary);
|
||||
|
||||
/*
|
||||
u16 command
|
||||
u32 number of files
|
||||
for each texture {
|
||||
u16 length of name
|
||||
string name
|
||||
u16 length of sha1_digest
|
||||
string sha1_digest
|
||||
}
|
||||
*/
|
||||
|
||||
writeU16(os, TOCLIENT_ANNOUNCE_MESH);
|
||||
writeU16(tmp_os, file_announcements.size());
|
||||
|
||||
for(core::list<SendableMeshAnnouncement>::Iterator
|
||||
j = file_announcements.begin();
|
||||
j != file_announcements.end(); j++){
|
||||
tmp_os<<serializeString(j->name);
|
||||
tmp_os<<serializeString(j->sha1_digest);
|
||||
}
|
||||
|
||||
// Make data buffer
|
||||
std::ostringstream tmp_os2(std::ios::binary);
|
||||
compressZlib(tmp_os.str(), tmp_os2);
|
||||
os<<serializeLongString(tmp_os2.str());
|
||||
std::string s = os.str();
|
||||
SharedBuffer<u8> data((u8*)s.c_str(), s.size());
|
||||
|
||||
// Send as reliable
|
||||
m_con.Send(peer_id, 0, data, true);
|
||||
|
||||
}
|
||||
|
||||
struct SendableMesh
|
||||
{
|
||||
std::string name;
|
||||
std::string path;
|
||||
std::string data;
|
||||
|
||||
SendableMesh(const std::string &name_="", const std::string path_="",
|
||||
const std::string &data_=""):
|
||||
name(name_),
|
||||
path(path_),
|
||||
data(data_)
|
||||
{}
|
||||
};
|
||||
|
||||
void Server::sendRequestedMesh(u16 peer_id,
|
||||
const core::list<MeshRequest> &tosend)
|
||||
{
|
||||
DSTACK(__FUNCTION_NAME);
|
||||
|
||||
verbosestream<<"Server::sendRequestedMesh(): "
|
||||
<<"Sending files to client"<<std::endl;
|
||||
|
||||
/* Read files */
|
||||
|
||||
// Put 5kB in one bunch (this is not accurate)
|
||||
u32 bytes_per_bunch = 5000;
|
||||
|
||||
core::array< core::list<SendableMesh> > file_bunches;
|
||||
file_bunches.push_back(core::list<SendableMesh>());
|
||||
|
||||
u32 file_size_bunch_total = 0;
|
||||
|
||||
for(core::list<MeshRequest>::ConstIterator i = tosend.begin();
|
||||
i != tosend.end(); i++)
|
||||
{
|
||||
if(m_mesh.find(i->name) == m_mesh.end())
|
||||
{
|
||||
errorstream<<"Server::sendRequestedMesh(): Client asked for "
|
||||
<<"unknown file \""<<(i->name)<<"\""<<std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
//TODO get path + name
|
||||
std::string tpath = m_mesh[(*i).name].path;
|
||||
|
||||
// Read data
|
||||
std::ifstream fis(tpath.c_str(), std::ios_base::binary);
|
||||
if(fis.good() == false)
|
||||
{
|
||||
errorstream<<"Server::sendRequestedMesh(): 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);
|
||||
file_size_bunch_total += len;
|
||||
if(fis.eof())
|
||||
{
|
||||
break;
|
||||
}
|
||||
if(!fis.good())
|
||||
{
|
||||
bad = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(bad)
|
||||
{
|
||||
errorstream<<"Server::sendRequestedMesh(): Failed to read \""
|
||||
<<(*i).name<<"\""<<std::endl;
|
||||
continue;
|
||||
}
|
||||
/*infostream<<"Server::sendRequestedMesh(): Loaded \""
|
||||
<<tname<<"\""<<std::endl;*/
|
||||
// Put in list
|
||||
file_bunches[file_bunches.size()-1].push_back(
|
||||
SendableMesh((*i).name, tpath, tmp_os.str()));
|
||||
|
||||
// Start next bunch if got enough data
|
||||
if(file_size_bunch_total >= bytes_per_bunch)
|
||||
{
|
||||
file_bunches.push_back(core::list<SendableMesh>());
|
||||
file_size_bunch_total = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Create and send packets */
|
||||
|
||||
u32 num_bunches = file_bunches.size();
|
||||
for(u32 i=0; i<num_bunches; i++)
|
||||
{
|
||||
std::ostringstream os(std::ios_base::binary);
|
||||
std::ostringstream tmp_os(std::ios_base::binary);
|
||||
|
||||
/*
|
||||
u16 command
|
||||
u16 total number of texture bunches
|
||||
u16 index of this bunch
|
||||
u32 number of files in this bunch
|
||||
for each file {
|
||||
u16 length of name
|
||||
string name
|
||||
u32 length of data
|
||||
data
|
||||
}
|
||||
*/
|
||||
|
||||
writeU16(os, TOCLIENT_MESH);
|
||||
writeU16(tmp_os, num_bunches);
|
||||
writeU16(tmp_os, i);
|
||||
writeU32(tmp_os, file_bunches[i].size());
|
||||
|
||||
for(core::list<SendableMesh>::Iterator
|
||||
j = file_bunches[i].begin();
|
||||
j != file_bunches[i].end(); j++){
|
||||
tmp_os<<serializeString(j->name);
|
||||
tmp_os<<serializeLongString(j->data);
|
||||
}
|
||||
|
||||
// Make data buffer
|
||||
std::ostringstream tmp_os2(std::ios::binary);
|
||||
compressZlib(tmp_os.str(), tmp_os2);
|
||||
os<<serializeLongString(tmp_os2.str());
|
||||
std::string s = os.str();
|
||||
verbosestream<<"Server::sendRequestedMesh(): bunch "
|
||||
<<i<<"/"<<num_bunches
|
||||
<<" files="<<file_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);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Something random
|
||||
*/
|
||||
|
|
27
src/server.h
27
src/server.h
|
@ -261,6 +261,15 @@ struct MediaRequest
|
|||
{}
|
||||
};
|
||||
|
||||
struct MeshRequest
|
||||
{
|
||||
std::string name;
|
||||
|
||||
MeshRequest(const std::string &name_=""):
|
||||
name(name_)
|
||||
{}
|
||||
};
|
||||
|
||||
struct MediaInfo
|
||||
{
|
||||
std::string path;
|
||||
|
@ -274,6 +283,19 @@ struct MediaInfo
|
|||
}
|
||||
};
|
||||
|
||||
struct MeshInfo
|
||||
{
|
||||
std::string path;
|
||||
std::string sha1_digest;
|
||||
|
||||
MeshInfo(const std::string path_="",
|
||||
const std::string sha1_digest_=""):
|
||||
path(path_),
|
||||
sha1_digest(sha1_digest_)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct ServerSoundParams
|
||||
{
|
||||
float gain;
|
||||
|
@ -628,6 +650,10 @@ private:
|
|||
void sendMediaAnnouncement(u16 peer_id);
|
||||
void sendRequestedMedia(u16 peer_id,
|
||||
const core::list<MediaRequest> &tosend);
|
||||
void fillMeshCache();
|
||||
void sendMeshAnnouncement(u16 peer_id);
|
||||
void sendRequestedMesh(u16 peer_id,
|
||||
const core::list<MeshRequest> &tosend);
|
||||
|
||||
/*
|
||||
Something random
|
||||
|
@ -826,6 +852,7 @@ private:
|
|||
friend class RemoteClient;
|
||||
|
||||
std::map<std::string,MediaInfo> m_media;
|
||||
std::map<std::string,MeshInfo> m_mesh;
|
||||
|
||||
/*
|
||||
Sounds
|
||||
|
|
Loading…
Reference in New Issue