Improve loading screen and protocol

This commit is contained in:
Perttu Ahola 2011-11-15 23:58:56 +02:00
parent cde35d1606
commit 7696a38543
5 changed files with 220 additions and 117 deletions

@ -211,7 +211,11 @@ Client::Client(
m_time_of_day(0),
m_map_seed(0),
m_password(password),
m_access_denied(false)
m_access_denied(false),
m_texture_receive_progress(0),
m_textures_received(false),
m_tooldef_received(false),
m_nodedef_received(false)
{
m_packetcounter_timer = 0.0;
//m_delete_unused_sectors_timer = 0.0;
@ -661,8 +665,14 @@ void Client::deletingPeer(con::Peer *peer, bool timeout)
void Client::ReceiveAll()
{
DSTACK(__FUNCTION_NAME);
u32 start_ms = porting::getTimeMs();
for(;;)
{
// Limit time even if there would be huge amounts of data to
// process
if(porting::getTimeMs() > start_ms + 100)
break;
try{
Receive();
}
@ -1505,24 +1515,6 @@ 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_TOOLDEF)
{
infostream<<"Client: Received tool definitions: packet size: "
<<datasize<<std::endl;
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();
std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
m_tooldef->deSerialize(tmp_is);
// Resume threads
m_mesh_update_thread.setRun(true);
m_mesh_update_thread.Start();
}
else if(command == TOCLIENT_TEXTURES)
{
infostream<<"Client: Received textures: packet size: "<<datasize
@ -1539,7 +1531,9 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
/*
u16 command
u32 number of textures
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
@ -1547,6 +1541,11 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
data
}
*/
int num_bunches = readU16(is);
int bunch_i = readU16(is);
m_texture_receive_progress = (float)bunch_i / (float)(num_bunches - 1);
if(bunch_i == num_bunches - 1)
m_textures_received = true;
int num_textures = readU32(is);
infostream<<"Client: Received textures: count: "<<num_textures
<<std::endl;
@ -1572,6 +1571,7 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
rfile->drop();
}
if(m_nodedef_received && m_textures_received){
// Rebuild inherited images and recreate textures
m_tsrc->rebuildImagesAndTextures();
@ -1581,6 +1581,7 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
// Update node textures
m_nodedef->updateTextures(m_tsrc);
}
// Resume threads
m_mesh_update_thread.setRun(true);
@ -1590,6 +1591,26 @@ 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_TOOLDEF)
{
infostream<<"Client: Received tool definitions: packet size: "
<<datasize<<std::endl;
std::string datastring((char*)&data[2], datasize-2);
std::istringstream is(datastring, std::ios_base::binary);
m_tooldef_received = true;
// Stop threads while updating content definitions
m_mesh_update_thread.stop();
std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
m_tooldef->deSerialize(tmp_is);
// Resume threads
m_mesh_update_thread.setRun(true);
m_mesh_update_thread.Start();
}
else if(command == TOCLIENT_NODEDEF)
{
infostream<<"Client: Received node definitions: packet size: "
@ -1598,18 +1619,22 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
std::string datastring((char*)&data[2], datasize-2);
std::istringstream is(datastring, std::ios_base::binary);
m_nodedef_received = true;
// Stop threads while updating content definitions
m_mesh_update_thread.stop();
std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
m_nodedef->deSerialize(tmp_is, this);
if(m_textures_received){
// Update texture atlas
if(g_settings->getBool("enable_texture_atlas"))
m_tsrc->buildMainAtlas(this);
// Update node textures
m_nodedef->updateTextures(m_tsrc);
}
// Resume threads
m_mesh_update_thread.setRun(true);

@ -305,12 +305,22 @@ public:
// Get event from queue. CE_NONE is returned if queue is empty.
ClientEvent getClientEvent();
inline bool accessDenied()
bool accessDenied()
{ return m_access_denied; }
inline std::wstring accessDeniedReason()
std::wstring accessDeniedReason()
{ return m_access_denied_reason; }
float textureReceiveProgress()
{ return m_texture_receive_progress; }
bool texturesReceived()
{ return m_textures_received; }
bool tooldefReceived()
{ return m_tooldef_received; }
bool nodedefReceived()
{ return m_nodedef_received; }
float getRTT(void);
// IGameDef interface
@ -367,6 +377,10 @@ private:
std::wstring m_access_denied_reason;
InventoryContext m_inventory_context;
Queue<ClientEvent> m_client_event_queue;
float m_texture_receive_progress;
bool m_textures_received;
bool m_tooldef_received;
bool m_nodedef_received;
friend class FarMesh;
};

@ -28,8 +28,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
PROTOCOL_VERSION 3:
Base for writing changes here
PROTOCOL_VERSION 4:
Add TOCLIENT_TOOLDEF
Add TOCLIENT_TEXTURES
Add TOCLIENT_TOOLDEF
Add TOCLIENT_NODEDEF
*/
@ -195,17 +195,12 @@ enum ToClientCommand
v3f1000 camera point target (to point the death cause or whatever)
*/
TOCLIENT_TOOLDEF = 0x38,
TOCLIENT_TEXTURES = 0x38,
/*
u16 command
u32 length of the next item
serialized ToolDefManager
*/
TOCLIENT_TEXTURES = 0x39,
/*
u16 command
u32 number of textures
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
@ -214,18 +209,19 @@ enum ToClientCommand
}
*/
TOCLIENT_TOOLDEF = 0x39,
/*
u16 command
u32 length of the next item
serialized ToolDefManager
*/
TOCLIENT_NODEDEF = 0x3a,
/*
u16 command
u32 length of the next item
serialized NodeDefManager
*/
//TOCLIENT_CONTENT_SENDING_MODE = 0x38,
/*
u16 command
u8 mode (0 = off, 1 = on)
*/
};
enum ToServerCommand

@ -632,21 +632,18 @@ void the_game(
/*
Draw "Loading" screen
*/
/*gui::IGUIStaticText *gui_loadingtext = */
//draw_load_screen(L"Loading and connecting...", driver, font);
draw_load_screen(L"Loading...", driver, font);
// Create tool definition manager
IWritableToolDefManager *tooldef = createToolDefManager();
// Create texture source
IWritableTextureSource *tsrc = createTextureSource(device);
// These will be filled by data received from the server
// Create tool definition manager
IWritableToolDefManager *tooldef = createToolDefManager();
// Create node definition manager
IWritableNodeDefManager *nodedef = createNodeDefManager();
// Fill node feature table with default definitions
//content_mapnode_init(nodedef);
/*
Create server.
SharedPtr will delete it when it goes out of scope.
@ -703,53 +700,50 @@ void the_game(
infostream<<std::endl;
client.connect(connect_address);
/*
Wait for server to accept connection
*/
bool could_connect = false;
try{
float frametime = 0.033;
const float timeout = 10.0;
float time_counter = 0.0;
for(;;)
{
if(client.connectedAndInitialized())
{
// Update client and server
client.step(frametime);
if(server != NULL)
server->step(frametime);
// End condition
if(client.connectedAndInitialized()){
could_connect = true;
break;
}
// Break conditions
if(client.accessDenied())
{
break;
}
// Wait for 10 seconds
if(time_counter >= 10.0)
{
if(time_counter >= timeout)
break;
}
// Display status
std::wostringstream ss;
ss<<L"Connecting to server... (timeout in ";
ss<<(int)(10.0 - time_counter + 1.0);
ss<<(int)(timeout - time_counter + 1.0);
ss<<L" seconds)";
draw_load_screen(ss.str(), driver, font);
/*// Update screen
driver->beginScene(true, true, video::SColor(255,0,0,0));
guienv->drawAll();
driver->endScene();*/
// Update client and server
client.step(0.1);
if(server != NULL)
server->step(0.1);
// Delay a bit
sleep_ms(100);
time_counter += 0.1;
sleep_ms(1000*frametime);
time_counter += frametime;
}
}
catch(con::PeerNotFoundException &e)
{}
/*
Handle failure to connect
*/
if(could_connect == false)
{
if(client.accessDenied())
@ -767,6 +761,56 @@ void the_game(
return;
}
/*
Wait until content has been received
*/
bool got_content = false;
{
float frametime = 0.033;
const float timeout = 5.0;
float time_counter = 0.0;
for(;;)
{
// Update client and server
client.step(frametime);
if(server != NULL)
server->step(frametime);
// End condition
if(client.texturesReceived() &&
client.tooldefReceived() &&
client.nodedefReceived()){
got_content = true;
break;
}
// Break conditions
if(!client.connectedAndInitialized())
break;
if(time_counter >= timeout)
break;
// Display status
std::wostringstream ss;
ss<<L"Waiting content... (continuing anyway in ";
ss<<(int)(timeout - time_counter + 1.0);
ss<<L" seconds)\n";
ss<<(client.tooldefReceived()?L"[X]":L"[ ]");
ss<<L" Tool definitions\n";
ss<<(client.nodedefReceived()?L"[X]":L"[ ]");
ss<<L" Node definitions\n";
//ss<<(client.texturesReceived()?L"[X]":L"[ ]");
ss<<L"["<<(int)(client.textureReceiveProgress()*100+0.5)<<L"%] ";
ss<<L" Textures\n";
draw_load_screen(ss.str(), driver, font);
// Delay a bit
sleep_ms(1000*frametime);
time_counter += frametime;
}
}
/*
Create skybox
*/

@ -2139,15 +2139,15 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
Send some initialization data
*/
// Send textures
SendTextures(peer_id);
// Send tool definitions
SendToolDef(m_con, peer_id, m_toolmgr);
// Send node definitions
SendNodeDef(m_con, peer_id, m_nodemgr);
// Send textures
SendTextures(peer_id);
// Send player info to all players
SendPlayerInfos();
@ -4160,7 +4160,13 @@ void Server::SendTextures(u16 peer_id)
/* Read textures */
core::list<SendableTexture> 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;
core::list<ModSpec> mods = getMods(m_modspaths);
for(core::list<ModSpec>::Iterator i = mods.begin();
i != mods.end(); i++){
@ -4186,6 +4192,7 @@ void Server::SendTextures(u16 peer_id)
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()){
@ -4201,15 +4208,27 @@ void Server::SendTextures(u16 peer_id)
errorstream<<"Server::SendTextures(): Loaded \""
<<tname<<"\""<<std::endl;
// Put in list
textures.push_back(SendableTexture(tname, tpath, tmp_os.str()));
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;
}
}
}
/* Create and send packet */
/* Create and send packets */
u32 num_bunches = texture_bunches.size();
for(u32 i=0; i<num_bunches; i++)
{
/*
u16 command
u32 number of textures
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
@ -4220,22 +4239,27 @@ void Server::SendTextures(u16 peer_id)
std::ostringstream os(std::ios_base::binary);
writeU16(os, TOCLIENT_TEXTURES);
writeU32(os, textures.size());
writeU16(os, num_bunches);
writeU16(os, i);
writeU32(os, texture_bunches[i].size());
for(core::list<SendableTexture>::Iterator i = textures.begin();
i != textures.end(); i++){
os<<serializeString(i->name);
os<<serializeLongString(i->data);
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::SendTextures(): number of textures: "
<<textures.size()<<", data size: "<<s.size()<<std::endl;
infostream<<"Server::SendTextures(): number of textures in bunch["
<<i<<"]: "<<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);
}
}
/*
Something random