diff options
-rw-r--r-- | src/constants.h | 5 | ||||
-rw-r--r-- | src/server.cpp | 321 | ||||
-rw-r--r-- | src/server.h | 27 |
3 files changed, 345 insertions, 8 deletions
diff --git a/src/constants.h b/src/constants.h index ee08e0ed4..f7ff0aef1 100644 --- a/src/constants.h +++ b/src/constants.h @@ -28,14 +28,13 @@ // The absolute working limit is (2^15 - viewing_range). #define MAP_GENERATION_LIMIT (31000) -//#define MAX_SIMULTANEOUS_BLOCK_SENDS 7 -//#define MAX_SIMULTANEOUS_BLOCK_SENDS 3 #define MAX_SIMULTANEOUS_BLOCK_SENDS 2 -//#define MAX_SIMULTANEOUS_BLOCK_SENDS 1 #define FULL_BLOCK_SEND_ENABLE_MIN_TIME_FROM_BUILDING 2.0 #define LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS 1 +#define MAX_SIMULTANEOUS_BLOCK_SENDS_SERVER_TOTAL 4 + // Viewing range stuff #define FPS_DEFAULT_WANTED 30 diff --git a/src/server.cpp b/src/server.cpp index 8969bdedd..83d43599f 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -246,9 +246,11 @@ void * EmergeThread::Thread() return NULL; } +#if 0 void RemoteClient::SendBlocks(Server *server, float dtime) { DSTACK(__FUNCTION_NAME); + /* Find what blocks to send to the client next, and send them. @@ -518,6 +520,262 @@ void RemoteClient::SendBlocks(Server *server, float dtime) // Don't add anything here. The loop breaks by returning. } +#endif // backup of SendBlocks + +void RemoteClient::GetNextBlocks(Server *server, float dtime, + core::array<PrioritySortedBlockTransfer> &dest) +{ + DSTACK(__FUNCTION_NAME); + + // Won't send anything if already sending + { + JMutexAutoLock lock(m_blocks_sending_mutex); + + if(m_blocks_sending.size() >= MAX_SIMULTANEOUS_BLOCK_SENDS) + { + //dstream<<"Not sending any blocks, Queue full."<<std::endl; + return; + } + } + + Player *player = server->m_env.getPlayer(peer_id); + + v3f playerpos = player->getPosition(); + v3f playerspeed = player->getSpeed(); + + v3s16 center_nodepos = floatToInt(playerpos); + + v3s16 center = getNodeBlockPos(center_nodepos); + + /* + Get the starting value of the block finder radius. + */ + s16 last_nearest_unsent_d; + s16 d_start; + { + JMutexAutoLock lock(m_blocks_sent_mutex); + + if(m_last_center != center) + { + m_nearest_unsent_d = 0; + m_last_center = center; + } + + static float reset_counter = 0; + reset_counter += dtime; + if(reset_counter > 5.0) + { + reset_counter = 0; + m_nearest_unsent_d = 0; + } + + last_nearest_unsent_d = m_nearest_unsent_d; + + d_start = m_nearest_unsent_d; + } + + u16 maximum_simultaneous_block_sends = MAX_SIMULTANEOUS_BLOCK_SENDS; + + { + SharedPtr<JMutexAutoLock> lock(m_time_from_building.getLock()); + m_time_from_building.m_value += dtime; + /* + Check the time from last addNode/removeNode. + Decrease send rate if player is building stuff. + */ + if(m_time_from_building.m_value + < FULL_BLOCK_SEND_ENABLE_MIN_TIME_FROM_BUILDING) + { + maximum_simultaneous_block_sends + = LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS; + } + } + + // Serialization version used + //u8 ser_version = serialization_version; + + //bool has_incomplete_blocks = false; + + /* + TODO: Get this from somewhere + */ + //s16 d_max = 7; + s16 d_max = 8; + + //TODO: Get this from somewhere (probably a bigger value) + s16 d_max_gen = 5; + + //dstream<<"Starting from "<<d_start<<std::endl; + + for(s16 d = d_start; d <= d_max; d++) + { + //dstream<<"RemoteClient::SendBlocks(): d="<<d<<std::endl; + + //if(has_incomplete_blocks == false) + { + JMutexAutoLock lock(m_blocks_sent_mutex); + /* + If m_nearest_unsent_d was changed by the EmergeThread + (it can change it to 0 through SetBlockNotSent), + update our d to it. + Else update m_nearest_unsent_d + */ + if(m_nearest_unsent_d != last_nearest_unsent_d) + { + d = m_nearest_unsent_d; + } + else + { + m_nearest_unsent_d = d; + } + last_nearest_unsent_d = m_nearest_unsent_d; + } + + /* + Get the border/face dot coordinates of a "d-radiused" + box + */ + core::list<v3s16> list; + getFacePositions(list, d); + + core::list<v3s16>::Iterator li; + for(li=list.begin(); li!=list.end(); li++) + { + v3s16 p = *li + center; + + /* + Send throttling + - Don't allow too many simultaneous transfers + + Also, don't send blocks that are already flying. + */ + { + JMutexAutoLock lock(m_blocks_sending_mutex); + + // Limit is dynamically lowered when building + if(m_blocks_sending.size() + >= maximum_simultaneous_block_sends) + { + /*dstream<<"Not sending more blocks. Queue full. " + <<m_blocks_sending.size() + <<std::endl;*/ + return; + } + + if(m_blocks_sending.find(p) != NULL) + continue; + } + + /* + Do not go over-limit + */ + if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE + || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE + || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE + || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE + || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE + || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE) + continue; + + bool generate = d <= d_max_gen; + + // Limit the generating area vertically to half + if(abs(p.Y - center.Y) > d_max_gen / 2) + generate = false; + + /* + Don't send already sent blocks + */ + { + JMutexAutoLock lock(m_blocks_sent_mutex); + + if(m_blocks_sent.find(p) != NULL) + continue; + } + + /* + Check if map has this block + */ + MapBlock *block = NULL; + try + { + block = server->m_env.getMap().getBlockNoCreate(p); + } + catch(InvalidPositionException &e) + { + } + + bool surely_not_found_on_disk = false; + if(block != NULL) + { + /*if(block->isIncomplete()) + { + has_incomplete_blocks = true; + continue; + }*/ + + if(block->isDummy()) + { + surely_not_found_on_disk = true; + } + } + + /* + If block has been marked to not exist on disk (dummy) + and generating new ones is not wanted, skip block. TODO + */ + if(generate == false && surely_not_found_on_disk == true) + { + // get next one. + continue; + } + + /* + Add inexistent block to emerge queue. + */ + if(block == NULL || surely_not_found_on_disk) + { + // Block not found. + SharedPtr<JMutexAutoLock> lock + (m_num_blocks_in_emerge_queue.getLock()); + + //TODO: Get value from somewhere + //TODO: Balance between clients + //if(server->m_emerge_queue.size() < 1) + + // Allow only one block in emerge queue + if(m_num_blocks_in_emerge_queue.m_value == 0) + { + // Add it to the emerge queue and trigger the thread + + u8 flags = 0; + if(generate == false) + flags |= TOSERVER_GETBLOCK_FLAG_OPTIONAL; + + { + m_num_blocks_in_emerge_queue.m_value++; + } + + server->m_emerge_queue.addBlock(peer_id, p, flags); + server->m_emergethread.trigger(); + } + + // get next one. + continue; + } + + /* + Add block to queue + */ + + PrioritySortedBlockTransfer q((float)d, p, peer_id); + + dest.push_back(q); + } + } + + // Don't add anything here. The loop breaks by returning. +} void RemoteClient::SendObjectData( Server *server, @@ -2069,6 +2327,7 @@ void Server::SendInventory(u16 peer_id) m_con.Send(peer_id, 0, data, true); } +#if 0 void Server::SendBlocks(float dtime) { DSTACK(__FUNCTION_NAME); @@ -2095,6 +2354,68 @@ void Server::SendBlocks(float dtime) //dstream<<"Server::SendBlocks(): END"<<std::endl; } +#endif + +void Server::SendBlocks(float dtime) +{ + DSTACK(__FUNCTION_NAME); + + JMutexAutoLock envlock(m_env_mutex); + + core::array<PrioritySortedBlockTransfer> queue; + + s32 total_sending = 0; + + for(core::map<u16, RemoteClient*>::Iterator + i = m_clients.getIterator(); + i.atEnd() == false; i++) + { + RemoteClient *client = i.getNode()->getValue(); + assert(client->peer_id == i.getNode()->getKey()); + + total_sending += client->SendingCount(); + + if(client->serialization_version == SER_FMT_VER_INVALID) + continue; + + client->GetNextBlocks(this, dtime, queue); + } + + // Sort. + // Lowest priority number comes first. + // Lowest is most important. + queue.sort(); + + JMutexAutoLock conlock(m_con_mutex); + + for(u32 i=0; i<queue.size(); i++) + { + //TODO: Calculate value dynamically + if(total_sending >= MAX_SIMULTANEOUS_BLOCK_SENDS_SERVER_TOTAL) + break; + + PrioritySortedBlockTransfer q = queue[i]; + + MapBlock *block = NULL; + try + { + block = m_env.getMap().getBlockNoCreate(q.pos); + } + catch(InvalidPositionException &e) + { + continue; + } + + RemoteClient *client = getClient(q.peer_id); + + SendBlockNoLock(q.peer_id, block, client->serialization_version); + + client->SentBlock(q.pos); + + total_sending++; + } +} + RemoteClient* Server::getClient(u16 peer_id) { diff --git a/src/server.h b/src/server.h index c178480d5..8e2e05626 100644 --- a/src/server.h +++ b/src/server.h @@ -208,11 +208,11 @@ u32 PIChecksum(core::list<PlayerInfo> &l); */ struct PrioritySortedBlockTransfer { - PrioritySortedBlockTransfer(float a_priority, v3s16 a_pos, u16 a_dest_peer) + PrioritySortedBlockTransfer(float a_priority, v3s16 a_pos, u16 a_peer_id) { priority = a_priority; pos = a_pos; - dest_peer = a_dest_peer; + peer_id = a_peer_id; } bool operator < (PrioritySortedBlockTransfer &other) { @@ -220,7 +220,7 @@ struct PrioritySortedBlockTransfer } float priority; v3s16 pos; - u16 a_dest_peer; + u16 peer_id; }; class RemoteClient @@ -252,8 +252,13 @@ public: { } - // Connection and environment should be locked when this is called - void SendBlocks(Server *server, float dtime); + /* + Finds block that should be sent next to the client. + Environment should be locked when this is called. + dtime is used for resetting send radius at slow interval + */ + void GetNextBlocks(Server *server, float dtime, + core::array<PrioritySortedBlockTransfer> &dest); // Connection and environment should be locked when this is called // steps() objects of blocks not found in active_blocks, then @@ -272,6 +277,18 @@ public: void SetBlocksNotSent(core::map<v3s16, MapBlock*> &blocks); void BlockEmerged(); + + /*bool IsSendingBlock(v3s16 p) + { + JMutexAutoLock lock(m_blocks_sending_mutex); + return (m_blocks_sending.find(p) != NULL); + }*/ + + s32 SendingCount() + { + JMutexAutoLock lock(m_blocks_sending_mutex); + return m_blocks_sending.size(); + } // Increments timeouts and removes timed-out blocks from list // NOTE: This doesn't fix the server-not-sending-block bug |