X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fserver.cpp;h=a2dfc8269790cbbd8b43aba9114453a73a2bd937;hb=ab7477c4c3e2a3647dc4fb65c71567946d33b0e3;hp=a4035284718defead7336bea5cd9fd84e0c9455c;hpb=d10627a77fe022263e2319be282fbec68e713545;p=minetest.git diff --git a/src/server.cpp b/src/server.cpp index a40352847..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++) { @@ -224,12 +261,6 @@ void * EmergeThread::Thread() // Remove block from sent history client->SetBlocksNotSent(modified_blocks); } - - /*if(q->peer_ids.find(client->peer_id) != NULL) - { - // Decrement emerge queue count of client - client->BlockEmerged(); - }*/ } } @@ -254,6 +285,12 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime, { DSTACK(__FUNCTION_NAME); + // Increment timers + { + JMutexAutoLock lock(m_blocks_sent_mutex); + m_nearest_unsent_reset_timer += dtime; + } + // Won't send anything if already sending { JMutexAutoLock lock(m_blocks_sending_mutex); @@ -289,12 +326,13 @@ void RemoteClient::GetNextBlocks(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"< BLOCK_SEND_DISABLE_LIMITS_MAX_D) + + u16 maximum_simultaneous_block_sends_now = + maximum_simultaneous_block_sends; + + if(d <= BLOCK_SEND_DISABLE_LIMITS_MAX_D) + { + maximum_simultaneous_block_sends_now = + maximum_simultaneous_block_sends_setting; + } + { JMutexAutoLock lock(m_blocks_sending_mutex); // Limit is dynamically lowered when building - if(m_blocks_sending.size() - >= maximum_simultaneous_block_sends) + if(num_blocks_selected + >= maximum_simultaneous_block_sends_now) { /*dstream<<"Not sending more blocks. Queue full. " <= 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) { @@ -984,29 +1141,114 @@ 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::GetNextBlocks for example. - /*{ - // 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)"<= g_settings.getFloat("objectdata_interval")) { @@ -1021,7 +1263,7 @@ void Server::AsyncRunStep() // Trigger emergethread (it gets somehow gets to a // non-triggered but bysy state sometimes) { - static float counter = 0.0; + float &counter = m_emergethread_trigger_timer; counter += dtime; if(counter >= 2.0) { @@ -1033,7 +1275,7 @@ void Server::AsyncRunStep() // Save map { - static float counter = 0.0; + float &counter = m_savemap_timer; counter += dtime; if(counter >= SERVER_MAP_SAVE_INTERVAL) { @@ -1352,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]); @@ -1378,64 +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; } } 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(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); - } + } // action == 0 - /* - Remove the node - (this takes some time so it is done after the quick stuff) - */ - m_env.getMap().removeNodeAndUpdate(p_under, modified_blocks); + /* + 2: stop digging + */ + else if(action == 2) + { + RemoteClient *client = getClient(peer->id); + JMutexAutoLock digmutex(client->m_dig_mutex); + client->m_dig_tool_item = -1; + } - } // button == 0 /* - Right button places blocks and stuff + 1: place block */ - else if(button == 1) + else if(action == 1) { // Get item @@ -1450,15 +1699,10 @@ 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; } catch(InvalidPositionException &e) @@ -1471,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(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); - } - + // 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); @@ -1493,6 +1734,43 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) // 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. @@ -1500,6 +1778,50 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) */ 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)"< 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); @@ -1856,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 ))); /* @@ -1892,9 +2123,13 @@ void Server::peerAdded(con::Peer *peer) if(g_settings.getBool("creative_mode")) { // Give all materials - assert(USEFUL_MATERIAL_COUNT <= PLAYER_INVENTORY_SIZE); - for(u16 i=0; iinventory.addItem(item); } @@ -2121,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)"<