diff options
author | Perttu Ahola <celeron55@gmail.com> | 2011-11-15 23:58:56 +0200 |
---|---|---|
committer | Perttu Ahola <celeron55@gmail.com> | 2011-11-29 19:13:45 +0200 |
commit | 7696a385433f815d8af8c905b45e2d7656299329 (patch) | |
tree | 7d211d46b1e86c9d07bff5e66198771d501e6bd2 | |
parent | cde35d160600bb97c62c48fd1924c98d23a6ac98 (diff) | |
download | minetest-7696a385433f815d8af8c905b45e2d7656299329.tar.gz minetest-7696a385433f815d8af8c905b45e2d7656299329.tar.bz2 minetest-7696a385433f815d8af8c905b45e2d7656299329.zip |
Improve loading screen and protocol
-rw-r--r-- | src/client.cpp | 93 | ||||
-rw-r--r-- | src/client.h | 18 | ||||
-rw-r--r-- | src/clientserver.h | 24 | ||||
-rw-r--r-- | src/game.cpp | 110 | ||||
-rw-r--r-- | src/server.cpp | 88 |
5 files changed, 218 insertions, 115 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: " - <<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,15 +1571,17 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id) rfile->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: " + <<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); - // 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<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; }; 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, - /* - u16 command - u32 length of the next item - serialized ToolDefManager - */ - - TOCLIENT_TEXTURES = 0x39, + TOCLIENT_TEXTURES = 0x38, /* 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,17 +209,18 @@ enum ToClientCommand } */ - TOCLIENT_NODEDEF = 0x3a, + TOCLIENT_TOOLDEF = 0x39, /* u16 command u32 length of the next item - serialized NodeDefManager + serialized ToolDefManager */ - //TOCLIENT_CONTENT_SENDING_MODE = 0x38, + TOCLIENT_NODEDEF = 0x3a, /* u16 command - u8 mode (0 = off, 1 = on) + u32 length of the next item + serialized NodeDefManager */ }; 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<<std::endl; client.connect(connect_address); - - bool could_connect = false; + /* + 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()) @@ -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<<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 diff --git a/src/server.cpp b/src/server.cpp index 45630d301..2a9aac32b 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -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,40 +4208,57 @@ 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 + 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 + u32 length of data + data + } + */ + std::ostringstream os(std::ios_base::binary); - /* - u16 command - u32 number of textures - for each texture { - u16 length of name - string name - u32 length of data - data + writeU16(os, TOCLIENT_TEXTURES); + writeU16(os, num_bunches); + writeU16(os, i); + writeU32(os, texture_bunches[i].size()); + + for(core::list<SendableTexture>::Iterator + j = texture_bunches[i].begin(); + j != texture_bunches[i].end(); j++){ + os<<serializeString(j->name); + os<<serializeLongString(j->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 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); } - - // 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); } /* |