X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fserver.cpp;h=a2dfc8269790cbbd8b43aba9114453a73a2bd937;hb=ab7477c4c3e2a3647dc4fb65c71567946d33b0e3;hp=a5f55ab5df89d191b1be96e4a060b93128463448;hpb=4e249fb3fbf75f0359758760d88e22aa5b14533c;p=minetest.git diff --git a/src/server.cpp b/src/server.cpp index a5f55ab5d..a2dfc8269 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -1,3 +1,22 @@ +/* +Minetest-c55 +Copyright (C) 2010 celeron55, Perttu Ahola + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + /* (c) 2010 Perttu Ahola */ @@ -10,6 +29,7 @@ #include "jmutexautolock.h" #include "main.h" #include "constants.h" +#include "voxel.h" void * ServerThread::Thread() { @@ -74,6 +94,8 @@ void * EmergeThread::Thread() v3s16 &p = q->pos; //derr_server<<"EmergeThread::Thread(): running"<UpdateBlockWaterPressure(block, modified_blocks); + + for(core::map::Iterator i = changed_blocks.getIterator(); + i.atEnd() == false; i++) + { + MapBlock *block = i.getNode()->getValue(); + m_server->UpdateBlockWaterPressure(block, modified_blocks); + //v3s16 p = i.getNode()->getKey(); + //m_server->UpdateBlockWaterPressure(p, modified_blocks); + } + /* Collect a list of blocks that have been modified in addition to the fetched one. */ - // Add all the "changed blocks" + // Add all the "changed blocks" to modified_blocks for(core::map::Iterator i = changed_blocks.getIterator(); i.atEnd() == false; i++) { @@ -178,7 +215,10 @@ void * EmergeThread::Thread() modified_blocks.insert(block->getPos(), block); } - //TimeTaker timer("** updateLighting", g_device); + /*dstream<<"lighting "<SetBlocksNotSent(modified_blocks); } - - if(q->peer_ids.find(client->peer_id) != NULL) - { - // Decrement emerge queue count of client - client->BlockEmerged(); - } } } @@ -246,28 +280,23 @@ void * EmergeThread::Thread() return NULL; } -void RemoteClient::SendBlocks(Server *server, float dtime) +void RemoteClient::GetNextBlocks(Server *server, float dtime, + core::array &dest) { DSTACK(__FUNCTION_NAME); - /* - Find what blocks to send to the client next, and send them. - - Throttling is based on limiting the amount of blocks "flying" - at a given time. - */ - - // Can't send anything without knowing version - if(serialization_version == SER_FMT_VER_INVALID) + + // Increment timers { - dstream<<"RemoteClient::SendBlocks(): Not sending, no version." - <= MAX_SIMULTANEOUS_BLOCK_SENDS) + if(m_blocks_sending.size() >= g_settings.getU16 + ("max_simultaneous_block_sends_per_client")) { //dstream<<"Not sending any blocks, Queue full."< highest_speed) - { - highest_speed = playerspeed.X; - if(playerspeed.X > 0) - dir = v3s16(1,0,0); - else - dir = v3s16(-1,0,0); - } - if(abs(playerspeed.Y) > highest_speed) - { - highest_speed = playerspeed.Y; - if(playerspeed.Y > 0) - dir = v3s16(0,1,0); - else - dir = v3s16(0,-1,0); - } - if(abs(playerspeed.Z) > highest_speed) - { - highest_speed = playerspeed.Z; - if(playerspeed.Z > 0) - dir = v3s16(0,0,1); - else - dir = v3s16(0,0,-1); - } - - center += dir;*/ - - /* - Calculate the starting value of the block finder radius. - - The radius shall be the last used value minus the - maximum moved distance. - */ - /*s16 d_start = m_last_block_find_d; - if(max_moved >= d_start) - { - d_start = 0; - } - else - { - d_start -= max_moved; - }*/ - s16 last_nearest_unsent_d; s16 d_start; { @@ -345,12 +326,13 @@ void RemoteClient::SendBlocks(Server *server, float dtime) m_last_center = center; } - static float reset_counter = 0; - reset_counter += dtime; - if(reset_counter > 5.0) + /*dstream<<"m_nearest_unsent_reset_timer=" + < 5.0) { - reset_counter = 0; + m_nearest_unsent_reset_timer = 0; m_nearest_unsent_d = 0; + //dstream<<"Resetting m_nearest_unsent_d"< 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) { @@ -374,24 +360,29 @@ void RemoteClient::SendBlocks(Server *server, float dtime) = LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS; } } + + u32 num_blocks_selected; + { + JMutexAutoLock lock(m_blocks_sending_mutex); + num_blocks_selected = m_blocks_sending.size(); + } + + /* + next time d will be continued from the d from which the nearest + unsent block was found this time. + + This is because not necessarily any of the blocks found this + time are actually sent. + */ + s32 new_nearest_unsent_d = -1; // Serialization version used //u8 ser_version = serialization_version; //bool has_incomplete_blocks = false; - /* - TODO: Get this from somewhere - TODO: Values more than 7 make placing and removing blocks very - sluggish when the map is being generated. This is - because d is looped every time from 0 to d_max if no - blocks are found for sending. - */ - //s16 d_max = 7; - s16 d_max = 8; - - //TODO: Get this from somewhere (probably a bigger value) - s16 d_max_gen = 5; + s16 d_max = g_settings.getS16("max_block_send_distance"); + s16 d_max_gen = g_settings.getS16("max_block_generate_distance"); //dstream<<"Starting from "<= maximum_simultaneous_block_sends) + // Limit is dynamically lowered when building + if(num_blocks_selected + >= maximum_simultaneous_block_sends_now) { /*dstream<<"Not sending more blocks. Queue full. " < lock - (m_num_blocks_in_emerge_queue.getLock()); + /*SharedPtr 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) + if(server->m_emerge_queue.peerItemCount(peer_id) < 1) { // Add it to the emerge queue and trigger the thread @@ -539,10 +543,6 @@ void RemoteClient::SendBlocks(Server *server, float dtime) 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(); } @@ -552,23 +552,23 @@ void RemoteClient::SendBlocks(Server *server, float dtime) } /* - Send block + Add block to queue */ - - /*dstream<<"RemoteClient::SendBlocks(): d="<SendBlockNoLock(peer_id, block, serialization_version); - - /* - Add to history - */ - SentBlock(p); + PrioritySortedBlockTransfer q((float)d, p, peer_id); + + dest.push_back(q); + + num_blocks_selected += 1; } } +queue_full: - // Don't add anything here. The loop breaks by returning. + if(new_nearest_unsent_d != -1) + { + JMutexAutoLock lock(m_blocks_sent_mutex); + m_nearest_unsent_d = new_nearest_unsent_d; + } } void RemoteClient::SendObjectData( @@ -659,6 +659,10 @@ void RemoteClient::SendObjectData( in memory): - Set blocks changed - Add blocks to emerge queue if they are not found + + SUGGESTION: These could be ignored from the backside of the player + + TODO: Keep track of total size of packet and stop when it is too big */ Player *player = server->m_env.getPlayer(peer_id); @@ -669,9 +673,14 @@ void RemoteClient::SendObjectData( v3s16 center_nodepos = floatToInt(playerpos); v3s16 center = getNodeBlockPos(center_nodepos); - s16 d_max = ACTIVE_OBJECT_D_BLOCKS; + //s16 d_max = ACTIVE_OBJECT_D_BLOCKS; + s16 d_max = g_settings.getS16("active_object_range"); + + // Number of blocks whose objects were written to bos + u16 blockcount = 0; - core::map blocks; + //core::map blocks; + std::ostringstream bos(std::ios_base::binary); for(s16 d = 0; d <= d_max; d++) { @@ -691,13 +700,18 @@ void RemoteClient::SendObjectData( if(m_blocks_sent.find(p) == NULL) continue; } - + + // Try stepping block and add it to a send queue try { // Get block MapBlock *block = server->m_env.getMap().getBlockNoCreate(p); + // Skip block if there are no objects + if(block->getObjectCount() == 0) + continue; + // Step block if not in stepped_blocks and add to stepped_blocks if(stepped_blocks.find(p) == NULL) { @@ -705,9 +719,30 @@ void RemoteClient::SendObjectData( stepped_blocks.insert(p, true); block->setChangedFlag(); } - - // Add block to queue - blocks.insert(p, block); + + /* + Write objects + */ + + // Write blockpos + writeV3S16(buf, p); + bos.write((char*)buf, 6); + + // Write objects + block->serializeObjects(bos, serialization_version); + + blockcount++; + + /* + Stop collecting objects if data is already too big + */ + // Sum of player and object data sizes + s32 sum = (s32)os.tellp() + 2 + (s32)bos.tellp(); + // break out if data too big + if(sum > MAX_OBJECTDATA_SIZE) + { + goto skip_subsequent; + } } //try catch(InvalidPositionException &e) @@ -717,9 +752,9 @@ void RemoteClient::SendObjectData( // Fetch the block only if it is on disk. // Grab and increment counter - SharedPtr lock + /*SharedPtr lock (m_num_blocks_in_emerge_queue.getLock()); - m_num_blocks_in_emerge_queue.m_value++; + m_num_blocks_in_emerge_queue.m_value++;*/ // Add to queue as an anonymous fetch from disk u8 flags = TOSERVER_GETBLOCK_FLAG_OPTIONAL; @@ -729,33 +764,21 @@ void RemoteClient::SendObjectData( } } - /* - Write objects - */ - - u16 blockcount = blocks.size(); +skip_subsequent: // Write block count writeU16(buf, blockcount); os.write((char*)buf, 2); - - for(core::map::Iterator - i = blocks.getIterator(); - i.atEnd() == false; i++) - { - v3s16 p = i.getNode()->getKey(); - // Write blockpos - writeV3S16(buf, p); - os.write((char*)buf, 6); - // Write objects - MapBlock *block = i.getNode()->getValue(); - block->serializeObjects(os, serialization_version); - } - + + // Write block objects + os< data((u8*)s.c_str(), s.size()); @@ -824,12 +847,12 @@ void RemoteClient::SetBlocksNotSent(core::map &blocks) } } -void RemoteClient::BlockEmerged() +/*void RemoteClient::BlockEmerged() { SharedPtr lock(m_num_blocks_in_emerge_queue.getLock()); assert(m_num_blocks_in_emerge_queue.m_value > 0); m_num_blocks_in_emerge_queue.m_value--; -} +}*/ /*void RemoteClient::RunSendingTimeouts(float dtime, float timeout) { @@ -897,15 +920,20 @@ u32 PIChecksum(core::list &l) Server::Server( std::string mapsavedir, - bool creative_mode, - MapgenParams mapgen_params + HMParams hm_params, + MapParams map_params ): - m_env(new ServerMap(mapsavedir, mapgen_params), dout_server), + m_env(new ServerMap(mapsavedir, hm_params, map_params), dout_server), m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this), m_thread(this), - m_emergethread(this), - m_creative_mode(creative_mode) + m_emergethread(this) { + m_flowwater_timer = 0.0; + m_print_info_timer = 0.0; + m_objectdata_timer = 0.0; + m_emergethread_trigger_timer = 0.0; + m_savemap_timer = 0.0; + m_env_mutex.Init(); m_con_mutex.Init(); m_step_dtime_mutex.Init(); @@ -943,7 +971,7 @@ void Server::start(unsigned short port) m_thread.stop(); // Initialize connection - m_con.setTimeoutMs(50); + m_con.setTimeoutMs(30); m_con.Serve(port); // Start thread @@ -980,15 +1008,24 @@ void Server::step(float dtime) void Server::AsyncRunStep() { DSTACK(__FUNCTION_NAME); + float dtime; { JMutexAutoLock lock1(m_step_dtime_mutex); dtime = m_step_dtime; - if(dtime < 0.001) - return; - m_step_dtime = 0.0; } + // Send blocks to clients + SendBlocks(dtime); + + if(dtime < 0.001) + return; + + { + JMutexAutoLock lock1(m_step_dtime_mutex); + m_step_dtime -= dtime; + } + //dstream<<"Server steps "<= 0.25 && m_flow_active_nodes.size() > 0) + { + + counter = 0.0; + + core::map modified_blocks; + + { + + JMutexAutoLock envlock(m_env_mutex); + + MapVoxelManipulator v(&m_env.getMap()); + v.m_disable_water_climb = + g_settings.getBool("disable_water_climb"); + + if(g_settings.getBool("endless_water") == false) + v.flowWater(m_flow_active_nodes, 0, false, 250); + else + v.flowWater(m_flow_active_nodes, 0, false, 50); + + v.blitBack(modified_blocks); + + ServerMap &map = ((ServerMap&)m_env.getMap()); + + // Update lighting + core::map lighting_modified_blocks; + map.updateLighting(modified_blocks, lighting_modified_blocks); + + // Add blocks modified by lighting to modified_blocks + for(core::map::Iterator + i = lighting_modified_blocks.getIterator(); + i.atEnd() == false; i++) + { + MapBlock *block = i.getNode()->getValue(); + modified_blocks.insert(block->getPos(), block); + } + } // envlock + + /* + Set the modified blocks unsent for all the clients + */ + + JMutexAutoLock lock2(m_con_mutex); + + for(core::map::Iterator + i = m_clients.getIterator(); + i.atEnd() == false; i++) + { + RemoteClient *client = i.getNode()->getValue(); + + if(modified_blocks.size() > 0) + { + // Remove block from sent history + client->SetBlocksNotSent(modified_blocks); + } + } + + } // interval counter + } // Periodically print some info { - static float counter = 0.0; + float &counter = m_print_info_timer; counter += dtime; if(counter >= 30.0) { @@ -1031,32 +1141,116 @@ void Server::AsyncRunStep() } } - // Run time- and client- related stuff - // NOTE: If you intend to add something here, check that it - // doesn't fit in RemoteClient::SendBlocks for exampel. - /*{ - // Clients are behind connection lock - JMutexAutoLock lock(m_con_mutex); + /* + Update digging + + NOTE: Some of this could be moved to RemoteClient + */ + + { + JMutexAutoLock envlock(m_env_mutex); + JMutexAutoLock conlock(m_con_mutex); for(core::map::Iterator i = m_clients.getIterator(); i.atEnd() == false; i++) { RemoteClient *client = i.getNode()->getValue(); - //con::Peer *peer = m_con.GetPeer(client->peer_id); - //client->RunSendingTimeouts(dtime, peer->resend_timeout); + Player *player = m_env.getPlayer(client->peer_id); + + JMutexAutoLock digmutex(client->m_dig_mutex); + + if(client->m_dig_tool_item == -1) + continue; + + client->m_dig_time_remaining -= dtime; + + if(client->m_dig_time_remaining > 0) + continue; + + v3s16 p_under = client->m_dig_position; + + // Mandatory parameter; actually used for nothing + core::map modified_blocks; + + u8 material; + + try + { + // Get material at position + material = m_env.getMap().getNode(p_under).d; + // If it's not diggable, do nothing + if(content_diggable(material) == false) + { + derr_server<<"Server: Not finishing digging: Node not diggable" + <m_dig_tool_item = -1; + break; + } + } + catch(InvalidPositionException &e) + { + derr_server<<"Server: Not finishing digging: Node not found" + <m_dig_tool_item = -1; + break; + } + + // Create packet + u32 replysize = 8; + SharedBuffer reply(replysize); + writeU16(&reply[0], TOCLIENT_REMOVENODE); + writeS16(&reply[2], p_under.X); + writeS16(&reply[4], p_under.Y); + writeS16(&reply[6], p_under.Z); + // Send as reliable + m_con.SendToAll(0, reply, true); + + if(g_settings.getBool("creative_mode") == false) + { + // Add to inventory and send inventory + InventoryItem *item = new MaterialItem(material, 1); + player->inventory.addItem(item); + SendInventory(player->peer_id); + } + + /* + Remove the node + (this takes some time so it is done after the quick stuff) + */ + m_env.getMap().removeNodeAndUpdate(p_under, modified_blocks); + + /* + Update water + */ + + // Update water pressure around modification + // This also adds it to m_flow_active_nodes if appropriate + + MapVoxelManipulator v(&m_env.getMap()); + v.m_disable_water_climb = + g_settings.getBool("disable_water_climb"); + + VoxelArea area(p_under-v3s16(1,1,1), p_under+v3s16(1,1,1)); + + try + { + v.updateAreaWaterPressure(area, m_flow_active_nodes); + } + catch(ProcessingLimitException &e) + { + dstream<<"Processing limit reached (1)"<= 0.1) + if(counter >= g_settings.getFloat("objectdata_interval")) { JMutexAutoLock lock1(m_env_mutex); JMutexAutoLock lock2(m_con_mutex); @@ -1065,10 +1259,23 @@ void Server::AsyncRunStep() counter = 0.0; } } + + // Trigger emergethread (it gets somehow gets to a + // non-triggered but bysy state sometimes) + { + float &counter = m_emergethread_trigger_timer; + counter += dtime; + if(counter >= 2.0) + { + counter = 0.0; + + m_emergethread.trigger(); + } + } + // Save map { - // Save map - static float counter = 0.0; + float &counter = m_savemap_timer; counter += dtime; if(counter >= SERVER_MAP_SAVE_INTERVAL) { @@ -1366,7 +1573,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) // Left click if(button == 0) { - if(m_creative_mode == false) + if(g_settings.getBool("creative_mode") == false) { // Skip if inventory has no free space @@ -1387,19 +1594,23 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) block->removeObject(id); } } - else if(command == TOSERVER_CLICK_GROUND) + else if(command == TOSERVER_GROUND_ACTION) { if(datasize < 17) return; /* length: 17 [0] u16 command - [2] u8 button (0=left, 1=right) + [2] u8 action [3] v3s16 nodepos_undersurface [9] v3s16 nodepos_abovesurface [15] u16 item + actions: + 0: start digging + 1: place block + 2: stop digging (all parameters ignored) */ - u8 button = readU8(&data[2]); + u8 action = readU8(&data[2]); v3s16 p_under; p_under.X = readS16(&data[3]); p_under.Y = readS16(&data[5]); @@ -1413,60 +1624,67 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) //TODO: Check that target is reasonably close /* - Left button digs ground + 0: start digging */ - if(button == 0) + if(action == 0) { - core::map modified_blocks; - - u8 material; + u8 content; try { - // Get material at position - material = m_env.getMap().getNode(p_under).d; - // If it's air, do nothing - if(material == MATERIAL_AIR) + // Get content at position + content = m_env.getMap().getNode(p_under).d; + // If it's not diggable, do nothing + if(content_diggable(content) == false) { return; } - // Otherwise remove it - m_env.getMap().removeNodeAndUpdate(p_under, modified_blocks); } catch(InvalidPositionException &e) { - derr_server<<"Server: Ignoring REMOVENODE: Node not found" + derr_server<<"Server: Not starting digging: Node not found" <id); + JMutexAutoLock(client->m_dig_mutex); + client->m_dig_tool_item = 0; + client->m_dig_position = p_under; + float dig_time = 0.5; + if(content == CONTENT_STONE) + { + dig_time = 1.5; + } + else if(content == CONTENT_TORCH) + { + dig_time = 0.0; + } + client->m_dig_time_remaining = dig_time; + // Reset build time counter getClient(peer->id)->m_time_from_building.set(0.0); - // Create packet - u32 replysize = 8; - SharedBuffer reply(replysize); - writeU16(&reply[0], TOCLIENT_REMOVENODE); - writeS16(&reply[2], p_under.X); - writeS16(&reply[4], p_under.Y); - writeS16(&reply[6], p_under.Z); - // Send as reliable - m_con.SendToAll(0, reply, true); - - if(m_creative_mode == false) - { - // Add to inventory and send inventory - InventoryItem *item = new MaterialItem(material, 1); - player->inventory.addItem(item); - SendInventory(player->peer_id); - } + } // action == 0 - } // button == 0 /* - Right button places blocks and stuff + 2: stop digging */ - else if(button == 1) + else if(action == 2) + { + RemoteClient *client = getClient(peer->id); + JMutexAutoLock digmutex(client->m_dig_mutex); + client->m_dig_tool_item = -1; + } + + /* + 1: place block + */ + else if(action == 1) { // Get item @@ -1481,19 +1699,11 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) */ if(std::string("MaterialItem") == item->getName()) { - MaterialItem *mitem = (MaterialItem*)item; - - MapNode n; - n.d = mitem->getMaterial(); - try{ - // Don't add a node if there isn't air + // Don't add a node if this is not a free space MapNode n2 = m_env.getMap().getNode(p_over); - if(n2.d != MATERIAL_AIR) + if(content_buildable_to(n2.d) == false) return; - - core::map modified_blocks; - m_env.getMap().addNodeAndUpdate(p_over, n, modified_blocks); } catch(InvalidPositionException &e) { @@ -1505,17 +1715,14 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) // Reset build time counter getClient(peer->id)->m_time_from_building.set(0.0); - if(m_creative_mode == false) - { - // Remove from inventory and send inventory - if(mitem->getCount() == 1) - player->inventory.deleteItem(item_i); - else - mitem->remove(1); - // Send inventory - SendInventory(peer_id); - } - + // Create node data + MaterialItem *mitem = (MaterialItem*)item; + MapNode n; + n.d = mitem->getMaterial(); + if(content_directional(n.d)) + n.dir = packDir(p_under - p_over); + +#if 1 // Create packet u32 replysize = 8 + MapNode::serializedLength(peer_ser_ver); SharedBuffer reply(replysize); @@ -1526,6 +1733,95 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) n.serialize(&reply[8], peer_ser_ver); // Send as reliable m_con.SendToAll(0, reply, true); + + /* + Handle inventory + */ + if(g_settings.getBool("creative_mode") == false) + { + // Remove from inventory and send inventory + if(mitem->getCount() == 1) + player->inventory.deleteItem(item_i); + else + mitem->remove(1); + // Send inventory + SendInventory(peer_id); + } + + /* + Add node. + + This takes some time so it is done after the quick stuff + */ + core::map modified_blocks; + m_env.getMap().addNodeAndUpdate(p_over, n, modified_blocks); +#endif +#if 0 + /* + Handle inventory + */ + if(g_settings.getBool("creative_mode") == false) + { + // Remove from inventory and send inventory + if(mitem->getCount() == 1) + player->inventory.deleteItem(item_i); + else + mitem->remove(1); + // Send inventory + SendInventory(peer_id); + } + + /* + Add node. + + This takes some time so it is done after the quick stuff + */ + core::map modified_blocks; + m_env.getMap().addNodeAndUpdate(p_over, n, modified_blocks); + + /* + Set the modified blocks unsent for all the clients + */ + + //JMutexAutoLock lock2(m_con_mutex); + + for(core::map::Iterator + i = m_clients.getIterator(); + i.atEnd() == false; i++) + { + RemoteClient *client = i.getNode()->getValue(); + + if(modified_blocks.size() > 0) + { + // Remove block from sent history + client->SetBlocksNotSent(modified_blocks); + } + } +#endif + + /* + Update water + */ + + // Update water pressure around modification + // This also adds it to m_flow_active_nodes if appropriate + + MapVoxelManipulator v(&m_env.getMap()); + v.m_disable_water_climb = + g_settings.getBool("disable_water_climb"); + + VoxelArea area(p_over-v3s16(1,1,1), p_over+v3s16(1,1,1)); + + try + { + v.updateAreaWaterPressure(area, m_flow_active_nodes); + } + catch(ProcessingLimitException &e) + { + dstream<<"Processing limit reached (1)"<inventory.deleteItem(item_i); @@ -1584,16 +1880,17 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) } } - } // button == 1 + } // action == 1 /* - Catch invalid buttons + Catch invalid actions */ else { - derr_server<<"WARNING: Server: Invalid button " - < ps, u8 ver) -{ - DSTACK(__FUNCTION_NAME); - dstream<<"Server sending sector meta of " - <::Iterator i = ps.begin(); - core::list sendlist; - for(;;) - { - if(sendlist.size() == 255 || i == ps.end()) - { - if(sendlist.size() == 0) - break; - /* - [0] u16 command - [2] u8 sector count - [3...] v2s16 pos + sector metadata - */ - std::ostringstream os(std::ios_base::binary); - u8 buf[4]; - - writeU16(buf, TOCLIENT_SECTORMETA); - os.write((char*)buf, 2); - - writeU8(buf, sendlist.size()); - os.write((char*)buf, 1); - - for(core::list::Iterator - j = sendlist.begin(); - j != sendlist.end(); j++) - { - // Write position - writeV2S16(buf, *j); - os.write((char*)buf, 4); - - /* - Write ClientMapSector metadata - */ - - /* - [0] u8 serialization version - [1] s16 corners[0] - [3] s16 corners[1] - [5] s16 corners[2] - [7] s16 corners[3] - size = 9 - - In which corners are in these positions - v2s16(0,0), - v2s16(1,0), - v2s16(1,1), - v2s16(0,1), - */ - - // Write version - writeU8(buf, ver); - os.write((char*)buf, 1); - - // Write corners - // TODO: Get real values - s16 corners[4]; - ((ServerMap&)m_env.getMap()).getSectorCorners(*j, corners); - - writeS16(buf, corners[0]); - os.write((char*)buf, 2); - writeS16(buf, corners[1]); - os.write((char*)buf, 2); - writeS16(buf, corners[2]); - os.write((char*)buf, 2); - writeS16(buf, corners[3]); - os.write((char*)buf, 2); - } - - SharedBuffer data((u8*)os.str().c_str(), os.str().size()); - - /*dstream<<"Server::SendSectorMeta(): sending packet" - " with "< Server::getPlayerInfo() { DSTACK(__FUNCTION_NAME); @@ -1882,27 +2082,32 @@ void Server::peerAdded(con::Peer *peer) // The player shouldn't already exist assert(player == NULL); - player = new RemotePlayer(); + player = new ServerRemotePlayer(); player->peer_id = peer->id; /* Set player position */ - + + // We're going to throw the player to this position + //v2s16 nodepos(29990,29990); + //v2s16 nodepos(9990,9990); + v2s16 nodepos(0,0); + v2s16 sectorpos = getNodeSectorPos(nodepos); // Get zero sector (it could have been unloaded to disk) - m_env.getMap().emergeSector(v2s16(0,0)); + m_env.getMap().emergeSector(sectorpos); // Get ground height at origin - f32 groundheight = m_env.getMap().getGroundHeight(v2s16(0,0), true); - // The zero sector should have been generated + f32 groundheight = m_env.getMap().getGroundHeight(nodepos, true); + // The sector should have been generated -> groundheight exists assert(groundheight > GROUNDHEIGHT_VALID_MINVALUE); // Don't go underwater if(groundheight < WATER_LEVEL) groundheight = WATER_LEVEL; player->setPosition(intToFloat(v3s16( - 0, + nodepos.X, groundheight + 1, - 0 + nodepos.Y ))); /* @@ -1915,12 +2120,16 @@ void Server::peerAdded(con::Peer *peer) Add stuff to inventory */ - if(m_creative_mode) + if(g_settings.getBool("creative_mode")) { // Give all materials - assert(USEFUL_MATERIAL_COUNT <= PLAYER_INVENTORY_SIZE); - for(u16 i=0; iinventory.addItem(item); } @@ -1930,12 +2139,12 @@ void Server::peerAdded(con::Peer *peer) bool r = player->inventory.addItem(item); assert(r == true); } - // Rat + /*// Rat { InventoryItem *item = new MapBlockObjectItem("Rat"); bool r = player->inventory.addItem(item); assert(r == true); - } + }*/ } else { @@ -2077,10 +2286,12 @@ void Server::SendInventory(u16 peer_id) void Server::SendBlocks(float dtime) { DSTACK(__FUNCTION_NAME); - //dstream<<"Server::SendBlocks(): BEGIN"< queue; + + s32 total_sending = 0; for(core::map::Iterator i = m_clients.getIterator(); @@ -2088,19 +2299,52 @@ void Server::SendBlocks(float dtime) { 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; - - //dstream<<"Server::SendBlocks(): sending blocks for client "<peer_id<peer_id; - client->SendBlocks(this, dtime); + client->GetNextBlocks(this, dtime, queue); } - //dstream<<"Server::SendBlocks(): END"<= g_settings.getS32 + ("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) { DSTACK(__FUNCTION_NAME); @@ -2112,4 +2356,27 @@ RemoteClient* Server::getClient(u16 peer_id) return n->getValue(); } +void Server::UpdateBlockWaterPressure(MapBlock *block, + core::map &modified_blocks) +{ + MapVoxelManipulator v(&m_env.getMap()); + v.m_disable_water_climb = + g_settings.getBool("disable_water_climb"); + + VoxelArea area(block->getPosRelative(), + block->getPosRelative() + v3s16(1,1,1)*(MAP_BLOCKSIZE-1)); + + try + { + v.updateAreaWaterPressure(area, m_flow_active_nodes); + } + catch(ProcessingLimitException &e) + { + dstream<<"Processing limit reached (1)"<