aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client.cpp93
-rw-r--r--src/client.h18
-rw-r--r--src/clientserver.h24
-rw-r--r--src/game.cpp110
-rw-r--r--src/server.cpp88
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);
}
/*