Sending of textures WIP
parent
7bdc328a71
commit
45fc45a49e
|
@ -34,6 +34,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
#include "nodemetadata.h"
|
#include "nodemetadata.h"
|
||||||
#include "nodedef.h"
|
#include "nodedef.h"
|
||||||
#include "tooldef.h"
|
#include "tooldef.h"
|
||||||
|
#include <IFileSystem.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
QueuedMeshUpdate
|
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.setRun(true);
|
||||||
m_mesh_update_thread.Start();
|
m_mesh_update_thread.Start();
|
||||||
}
|
}
|
||||||
|
else if(command == TOCLIENT_TEXTURES)
|
||||||
|
{
|
||||||
|
infostream<<"Client: Received textures: packet size: "<<datasize
|
||||||
|
<<std::endl;
|
||||||
|
|
||||||
|
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
|
||||||
|
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: "<<num_textures
|
||||||
|
<<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->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
|
else
|
||||||
{
|
{
|
||||||
infostream<<"Client: Ignoring unknown command "
|
infostream<<"Client: Ignoring unknown command "
|
||||||
|
|
|
@ -29,6 +29,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
Base for writing changes here
|
Base for writing changes here
|
||||||
PROTOCOL_VERSION 4:
|
PROTOCOL_VERSION 4:
|
||||||
Add TOCLIENT_TOOLDEF
|
Add TOCLIENT_TOOLDEF
|
||||||
|
Add TOCLIENT_TEXTURES
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define PROTOCOL_VERSION 4
|
#define PROTOCOL_VERSION 4
|
||||||
|
@ -198,6 +199,18 @@ enum ToClientCommand
|
||||||
serialized ToolDefManager
|
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,
|
//TOCLIENT_CONTENT_SENDING_MODE = 0x38,
|
||||||
/*
|
/*
|
||||||
u16 command
|
u16 command
|
||||||
|
|
165
src/server.cpp
165
src/server.cpp
|
@ -944,6 +944,35 @@ u32 PIChecksum(core::list<PlayerInfo> &l)
|
||||||
return checksum;
|
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<ModSpec> getMods(core::list<std::string> &modspaths)
|
||||||
|
{
|
||||||
|
core::list<ModSpec> mods;
|
||||||
|
for(core::list<std::string>::Iterator i = modspaths.begin();
|
||||||
|
i != modspaths.end(); i++){
|
||||||
|
std::string modspath = *i;
|
||||||
|
std::vector<fs::DirListNode> dirlist = fs::GetDirListing(modspath);
|
||||||
|
for(u32 j=0; j<dirlist.size(); j++){
|
||||||
|
if(!dirlist[j].dir)
|
||||||
|
continue;
|
||||||
|
std::string modname = dirlist[j].name;
|
||||||
|
std::string modpath = modspath + DIR_DELIM + modname;
|
||||||
|
mods.push_back(ModSpec(modname, modpath));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mods;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Server
|
Server
|
||||||
*/
|
*/
|
||||||
|
@ -988,6 +1017,9 @@ Server::Server(
|
||||||
|
|
||||||
// Initialize default node definitions
|
// Initialize default node definitions
|
||||||
content_mapnode_init(NULL, m_nodemgr);
|
content_mapnode_init(NULL, m_nodemgr);
|
||||||
|
|
||||||
|
// Add default global mod path
|
||||||
|
m_modspaths.push_back(porting::path_data + DIR_DELIM + "mods");
|
||||||
|
|
||||||
// Initialize scripting
|
// Initialize scripting
|
||||||
|
|
||||||
|
@ -997,26 +1029,17 @@ Server::Server(
|
||||||
// Export API
|
// Export API
|
||||||
scriptapi_export(m_lua, this);
|
scriptapi_export(m_lua, this);
|
||||||
// Load and run scripts
|
// Load and run scripts
|
||||||
core::list<std::string> modspaths;
|
core::list<ModSpec> mods = getMods(m_modspaths);
|
||||||
modspaths.push_back(porting::path_data + DIR_DELIM + "mods");
|
for(core::list<ModSpec>::Iterator i = mods.begin();
|
||||||
for(core::list<std::string>::Iterator i = modspaths.begin();
|
i != mods.end(); i++){
|
||||||
i != modspaths.end(); i++){
|
ModSpec mod = *i;
|
||||||
std::string modspath = *i;
|
infostream<<"Server: Loading mod \""<<mod.name<<"\""<<std::endl;
|
||||||
std::vector<fs::DirListNode> dirlist = fs::GetDirListing(modspath);
|
std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
|
||||||
for(u32 j=0; j<dirlist.size(); j++){
|
bool success = script_load(m_lua, scriptpath.c_str());
|
||||||
if(!dirlist[j].dir)
|
if(!success){
|
||||||
continue;
|
errorstream<<"Server: Failed to load and run "
|
||||||
std::string modname = dirlist[j].name;
|
<<scriptpath<<std::endl;
|
||||||
infostream<<"Server: Loading mod \""<<modname<<"\" script..."
|
assert(0);
|
||||||
<<std::endl;
|
|
||||||
std::string scriptpath = modspath + DIR_DELIM + modname
|
|
||||||
+ DIR_DELIM + "init.lua";
|
|
||||||
bool success = script_load(m_lua, scriptpath.c_str());
|
|
||||||
if(!success){
|
|
||||||
errorstream<<"Server: Failed to load and run "
|
|
||||||
<<scriptpath<<std::endl;
|
|
||||||
assert(0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2115,6 +2138,9 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
||||||
/*
|
/*
|
||||||
Send some initialization data
|
Send some initialization data
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// Send textures
|
||||||
|
SendTextures(peer_id);
|
||||||
|
|
||||||
// Send tool definitions
|
// Send tool definitions
|
||||||
SendToolDef(m_con, peer_id, m_toolmgr);
|
SendToolDef(m_con, peer_id, m_toolmgr);
|
||||||
|
@ -4080,6 +4106,105 @@ void Server::SendBlocks(float dtime)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct SendableTexture
|
||||||
|
{
|
||||||
|
std::string name;
|
||||||
|
std::string path;
|
||||||
|
std::string data;
|
||||||
|
|
||||||
|
SendableTexture(const std::string &name_="", const std::string path_="",
|
||||||
|
const std::string &data_=""):
|
||||||
|
name(name_),
|
||||||
|
path(path_),
|
||||||
|
data(data_)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
void Server::SendTextures(u16 peer_id)
|
||||||
|
{
|
||||||
|
DSTACK(__FUNCTION_NAME);
|
||||||
|
|
||||||
|
infostream<<"Server::SendTextures(): Sending textures to client"<<std::endl;
|
||||||
|
|
||||||
|
/* Read textures */
|
||||||
|
|
||||||
|
core::list<SendableTexture> textures;
|
||||||
|
core::list<ModSpec> mods = getMods(m_modspaths);
|
||||||
|
for(core::list<ModSpec>::Iterator i = mods.begin();
|
||||||
|
i != mods.end(); i++){
|
||||||
|
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);
|
||||||
|
if(fis.eof())
|
||||||
|
break;
|
||||||
|
if(!fis.good()){
|
||||||
|
bad = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(bad){
|
||||||
|
errorstream<<"Server::SendTextures(): Failed to read \""
|
||||||
|
<<tname<<"\""<<std::endl;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
errorstream<<"Server::SendTextures(): Loaded \""
|
||||||
|
<<tname<<"\""<<std::endl;
|
||||||
|
// Put in list
|
||||||
|
textures.push_back(SendableTexture(tname, tpath, tmp_os.str()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create and send packet */
|
||||||
|
|
||||||
|
/*
|
||||||
|
u16 command
|
||||||
|
u32 number of textures
|
||||||
|
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);
|
||||||
|
writeU32(os, textures.size());
|
||||||
|
|
||||||
|
for(core::list<SendableTexture>::Iterator i = textures.begin();
|
||||||
|
i != textures.end(); i++){
|
||||||
|
os<<serializeString(i->name);
|
||||||
|
os<<serializeLongString(i->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make data buffer
|
||||||
|
std::string s = os.str();
|
||||||
|
infostream<<"Server::SendTextures(): number of textures: "
|
||||||
|
<<textures.size()<<", data 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
|
Something random
|
||||||
*/
|
*/
|
||||||
|
|
10
src/server.h
10
src/server.h
|
@ -515,7 +515,10 @@ private:
|
||||||
IToolDefManager *tooldef);
|
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
|
// 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)
|
// Sends blocks to clients (locks env and con on its own)
|
||||||
void SendBlocks(float dtime);
|
void SendBlocks(float dtime);
|
||||||
|
|
||||||
|
void SendTextures(u16 peer_id);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Something random
|
Something random
|
||||||
|
@ -682,6 +687,9 @@ private:
|
||||||
|
|
||||||
// Configuration path ("" = no configuration file)
|
// Configuration path ("" = no configuration file)
|
||||||
std::string m_configpath;
|
std::string m_configpath;
|
||||||
|
|
||||||
|
// Mod parent directory paths
|
||||||
|
core::list<std::string> m_modspaths;
|
||||||
|
|
||||||
bool m_shutdown_requested;
|
bool m_shutdown_requested;
|
||||||
|
|
||||||
|
|
109
src/tile.cpp
109
src/tile.cpp
|
@ -242,14 +242,6 @@ public:
|
||||||
*/
|
*/
|
||||||
void updateAP(AtlasPointer &ap);
|
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.
|
Processes queued texture requests from other threads.
|
||||||
|
|
||||||
|
@ -257,6 +249,17 @@ public:
|
||||||
*/
|
*/
|
||||||
void processQueue();
|
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:
|
private:
|
||||||
|
|
||||||
// The id of the thread that is allowed to use irrlicht directly
|
// 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<std::string, u32, u8, u8>
|
|
||||||
request = m_get_texture_queue.pop();
|
|
||||||
|
|
||||||
infostream<<"TextureSource::processQueue(): "
|
|
||||||
<<"got texture request with "
|
|
||||||
<<"name=\""<<request.key<<"\""
|
|
||||||
<<std::endl;
|
|
||||||
|
|
||||||
GetResult<std::string, u32, u8, u8>
|
|
||||||
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)
|
u32 TextureSource::getTextureId(const std::string &name)
|
||||||
{
|
{
|
||||||
//infostream<<"getTextureId(): \""<<name<<"\""<<std::endl;
|
//infostream<<"getTextureId(): \""<<name<<"\""<<std::endl;
|
||||||
|
@ -624,6 +602,31 @@ void TextureSource::updateAP(AtlasPointer &ap)
|
||||||
ap = ap2;
|
ap = ap2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TextureSource::processQueue()
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Fetch textures
|
||||||
|
*/
|
||||||
|
if(m_get_texture_queue.size() > 0)
|
||||||
|
{
|
||||||
|
GetRequest<std::string, u32, u8, u8>
|
||||||
|
request = m_get_texture_queue.pop();
|
||||||
|
|
||||||
|
infostream<<"TextureSource::processQueue(): "
|
||||||
|
<<"got texture request with "
|
||||||
|
<<"name=\""<<request.key<<"\""
|
||||||
|
<<std::endl;
|
||||||
|
|
||||||
|
GetResult<std::string, u32, u8, u8>
|
||||||
|
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)
|
void TextureSource::buildMainAtlas(class IGameDef *gamedef)
|
||||||
{
|
{
|
||||||
assert(gamedef->tsrc() == this);
|
assert(gamedef->tsrc() == this);
|
||||||
|
@ -864,6 +867,46 @@ void TextureSource::buildMainAtlas(class IGameDef *gamedef)
|
||||||
driver->writeImageToFile(atlas_img, atlaspath.c_str());*/
|
driver->writeImageToFile(atlas_img, atlaspath.c_str());*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TextureSource::insertImage(const std::string &name, video::IImage *img)
|
||||||
|
{
|
||||||
|
infostream<<"TextureSource::insertImage(): name="<<name<<std::endl;
|
||||||
|
|
||||||
|
JMutexAutoLock lock(m_atlaspointer_cache_mutex);
|
||||||
|
|
||||||
|
video::IVideoDriver* driver = m_device->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<std::string, u32>::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<u32> 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,
|
video::IImage* generate_image_from_scratch(std::string name,
|
||||||
IrrlichtDevice *device)
|
IrrlichtDevice *device)
|
||||||
{
|
{
|
||||||
|
|
|
@ -156,8 +156,10 @@ public:
|
||||||
{return NULL;}
|
{return NULL;}
|
||||||
virtual void updateAP(AtlasPointer &ap){};
|
virtual void updateAP(AtlasPointer &ap){};
|
||||||
|
|
||||||
virtual void buildMainAtlas(class IGameDef *gamedef)=0;
|
|
||||||
virtual void processQueue()=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);
|
IWritableTextureSource* createTextureSource(IrrlichtDevice *device);
|
||||||
|
|
Loading…
Reference in New Issue