From 7696a385433f815d8af8c905b45e2d7656299329 Mon Sep 17 00:00:00 2001 From: Perttu Ahola Date: Tue, 15 Nov 2011 23:58:56 +0200 Subject: [PATCH] Improve loading screen and protocol --- src/client.cpp | 93 ++++++++++++++++++++++++-------------- src/client.h | 18 +++++++- src/clientserver.h | 28 +++++------- src/game.cpp | 110 +++++++++++++++++++++++++++++++-------------- src/server.cpp | 88 +++++++++++++++++++++++------------- 5 files changed, 220 insertions(+), 117 deletions(-) diff --git a/src/client.cpp b/src/client.cpp index 4d9233d66..9752ec5e2 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -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: " - <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: "<drop(); } - // Rebuild inherited images and recreate textures - m_tsrc->rebuildImagesAndTextures(); + if(m_nodedef_received && m_textures_received){ + // Rebuild inherited images and recreate textures + m_tsrc->rebuildImagesAndTextures(); - // Update texture atlas - if(g_settings->getBool("enable_texture_atlas")) - m_tsrc->buildMainAtlas(this); - - // Update node textures - m_nodedef->updateTextures(m_tsrc); + // 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); @@ -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: " + <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); - // Update texture atlas - if(g_settings->getBool("enable_texture_atlas")) - m_tsrc->buildMainAtlas(this); - - // Update node textures - m_nodedef->updateTextures(m_tsrc); + 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); diff --git a/src/client.h b/src/client.h index b160a3bc9..625170b17 100644 --- a/src/client.h +++ b/src/client.h @@ -305,11 +305,21 @@ 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); @@ -367,6 +377,10 @@ private: std::wstring m_access_denied_reason; InventoryContext m_inventory_context; Queue m_client_event_queue; + float m_texture_receive_progress; + bool m_textures_received; + bool m_tooldef_received; + bool m_nodedef_received; friend class FarMesh; }; diff --git a/src/clientserver.h b/src/clientserver.h index cd54fe239..148f99cc3 100644 --- a/src/clientserver.h +++ b/src/clientserver.h @@ -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 diff --git a/src/game.cpp b/src/game.cpp index bb1998066..925dead7c 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -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. @@ -702,54 +699,51 @@ void the_game( connect_address.print(&infostream); infostream<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<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()) @@ -766,6 +760,56 @@ void the_game( //gui_loadingtext->remove(); 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< textures; + // Put 5kB in one bunch (this is not accurate) + u32 bytes_per_bunch = 5000; + + core::array< core::list > texture_bunches; + texture_bunches.push_back(core::list()); + + u32 texture_size_bunch_total = 0; core::list mods = getMods(m_modspaths); for(core::list::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,40 +4208,57 @@ void Server::SendTextures(u16 peer_id) errorstream<<"Server::SendTextures(): Loaded \"" <= bytes_per_bunch){ + texture_bunches.push_back(core::list()); + texture_size_bunch_total = 0; + } } } - /* Create and send packet */ + /* Create and send packets */ + + u32 num_bunches = texture_bunches.size(); + for(u32 i=0; i::Iterator + j = texture_bunches[i].begin(); + j != texture_bunches[i].end(); j++){ + os<name); + os<data); } - */ - std::ostringstream os(std::ios_base::binary); - - writeU16(os, TOCLIENT_TEXTURES); - writeU32(os, textures.size()); - - for(core::list::Iterator i = textures.begin(); - i != textures.end(); i++){ - os<name); - os<data); + + // Make data buffer + std::string s = os.str(); + infostream<<"Server::SendTextures(): number of textures in bunch[" + < 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(): number of textures: " - < data((u8*)s.c_str(), s.size()); - // Send as reliable - m_con.Send(peer_id, 0, data, true); } /*