Server::~Server()
{
- infostream << "Server destructing" << std::endl;
// Send shutdown message
SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE,
m_env->kickAllPlayers(SERVER_ACCESSDENIED_SHUTDOWN,
kick_msg, reconnect);
}
+
+ actionstream << "Server: Shutting down" << std::endl;
// Do this before stopping the server in case mapgen callbacks need to access
// server-controlled resources (like ModStorages). Also do them before
// Players far away from the change are stored here.
// Instead of sending the changes, MapBlocks are set not sent
// for them.
- std::vector<u16> far_players;
+ std::unordered_set<u16> far_players;
switch (event->type) {
case MEET_ADDNODE:
case MEET_SWAPNODE:
prof.add("MEET_ADDNODE", 1);
- sendAddNode(event->p, event->n, event->already_known_by_peer,
- &far_players, disable_single_change_sending ? 5 : 30,
+ sendAddNode(event->p, event->n, &far_players,
+ disable_single_change_sending ? 5 : 30,
event->type == MEET_ADDNODE);
break;
case MEET_REMOVENODE:
prof.add("MEET_REMOVENODE", 1);
- sendRemoveNode(event->p, event->already_known_by_peer,
- &far_players, disable_single_change_sending ? 5 : 30);
+ sendRemoveNode(event->p, &far_players,
+ disable_single_change_sending ? 5 : 30);
break;
case MEET_BLOCK_NODE_METADATA_CHANGED:
infostream << "Server: MEET_BLOCK_NODE_METADATA_CHANGED" << std::endl;
// Send Breath
SendPlayerBreath(playersao);
- // Note things in chat if not in simple singleplayer mode
- if (!m_simple_singleplayer_mode && g_settings->getBool("show_statusline_on_connect")) {
- // Send information about server to player in chat
- SendChatMessage(peer_id, ChatMessage(CHATMESSAGE_TYPE_SYSTEM, getStatusString()));
- }
Address addr = getPeerAddress(player->getPeerId());
std::string ip_str = addr.serializeString();
actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
void Server::SendSpawnParticle(session_t peer_id, u16 protocol_version,
v3f pos, v3f velocity, v3f acceleration,
float expirationtime, float size, bool collisiondetection,
- bool collision_removal,
+ bool collision_removal, bool object_collision,
bool vertical, const std::string &texture,
const struct TileAnimationParams &animation, u8 glow)
{
SendSpawnParticle(client_id, player->protocol_version,
pos, velocity, acceleration,
- expirationtime, size, collisiondetection,
- collision_removal, vertical, texture, animation, glow);
+ expirationtime, size, collisiondetection, collision_removal,
+ object_collision, vertical, texture, animation, glow);
}
return;
}
animation.serialize(os, protocol_version);
pkt.putRawString(os.str());
pkt << glow;
+ pkt << object_collision;
Send(&pkt);
}
u16 amount, float spawntime, v3f minpos, v3f maxpos,
v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
float minsize, float maxsize, bool collisiondetection, bool collision_removal,
- u16 attached_id, bool vertical, const std::string &texture, u32 id,
+ bool object_collision, u16 attached_id, bool vertical, const std::string &texture, u32 id,
const struct TileAnimationParams &animation, u8 glow)
{
if (peer_id == PEER_ID_INEXISTENT) {
amount, spawntime, minpos, maxpos,
minvel, maxvel, minacc, maxacc, minexptime, maxexptime,
minsize, maxsize, collisiondetection, collision_removal,
- attached_id, vertical, texture, id, animation, glow);
+ object_collision, attached_id, vertical, texture, id,
+ animation, glow);
}
return;
}
animation.serialize(os, protocol_version);
pkt.putRawString(os.str());
pkt << glow;
+ pkt << object_collision;
Send(&pkt);
}
}
}
-void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
- std::vector<u16> *far_players, float far_d_nodes)
+void Server::sendRemoveNode(v3s16 p, std::unordered_set<u16> *far_players,
+ float far_d_nodes)
{
- float maxd = far_d_nodes*BS;
+ float maxd = far_d_nodes * BS;
v3f p_f = intToFloat(p, BS);
+ v3s16 block_pos = getNodeBlockPos(p);
NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
pkt << p;
std::vector<session_t> clients = m_clients.getClientIDs();
+ m_clients.lock();
+
for (session_t client_id : clients) {
- if (far_players) {
- // Get player
- if (RemotePlayer *player = m_env->getPlayer(client_id)) {
- PlayerSAO *sao = player->getPlayerSAO();
- if (!sao)
- continue;
+ RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
+ if (!client)
+ continue;
- // If player is far away, only set modified blocks not sent
- v3f player_pos = sao->getBasePosition();
- if (player_pos.getDistanceFrom(p_f) > maxd) {
- far_players->push_back(client_id);
- continue;
- }
- }
+ RemotePlayer *player = m_env->getPlayer(client_id);
+ PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr;
+
+ // If player is far away, only set modified blocks not sent
+ if (!client->isBlockSent(block_pos) || (sao &&
+ sao->getBasePosition().getDistanceFrom(p_f) > maxd)) {
+ if (far_players)
+ far_players->emplace(client_id);
+ else
+ client->SetBlockNotSent(block_pos);
+ continue;
}
// Send as reliable
m_clients.send(client_id, 0, &pkt, true);
}
+
+ m_clients.unlock();
}
-void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
- std::vector<u16> *far_players, float far_d_nodes,
- bool remove_metadata)
+void Server::sendAddNode(v3s16 p, MapNode n, std::unordered_set<u16> *far_players,
+ float far_d_nodes, bool remove_metadata)
{
- float maxd = far_d_nodes*BS;
+ float maxd = far_d_nodes * BS;
v3f p_f = intToFloat(p, BS);
+ v3s16 block_pos = getNodeBlockPos(p);
+
+ NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
+ pkt << p << n.param0 << n.param1 << n.param2
+ << (u8) (remove_metadata ? 0 : 1);
std::vector<session_t> clients = m_clients.getClientIDs();
- for (const session_t client_id : clients) {
- if (far_players) {
- // Get player
- if (RemotePlayer *player = m_env->getPlayer(client_id)) {
- PlayerSAO *sao = player->getPlayerSAO();
- if (!sao)
- continue;
+ m_clients.lock();
- // If player is far away, only set modified blocks not sent
- v3f player_pos = sao->getBasePosition();
- if(player_pos.getDistanceFrom(p_f) > maxd) {
- far_players->push_back(client_id);
- continue;
- }
- }
- }
+ for (session_t client_id : clients) {
+ RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
+ if (!client)
+ continue;
- NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
- m_clients.lock();
- RemoteClient* client = m_clients.lockedGetClientNoEx(client_id);
- if (client) {
- pkt << p << n.param0 << n.param1 << n.param2
- << (u8) (remove_metadata ? 0 : 1);
+ RemotePlayer *player = m_env->getPlayer(client_id);
+ PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr;
+
+ // If player is far away, only set modified blocks not sent
+ if (!client->isBlockSent(block_pos) || (sao &&
+ sao->getBasePosition().getDistanceFrom(p_f) > maxd)) {
+ if (far_players)
+ far_players->emplace(client_id);
+ else
+ client->SetBlockNotSent(block_pos);
+ continue;
}
- m_clients.unlock();
// Send as reliable
- if (pkt.getSize() > 0)
- m_clients.send(client_id, 0, &pkt, true);
+ m_clients.send(client_id, 0, &pkt, true);
}
+
+ m_clients.unlock();
}
void Server::SendBlockNoLock(session_t peer_id, MapBlock *block, u8 ver,
void Server::sendDetachedInventory(const std::string &name, session_t peer_id)
{
- if(m_detached_inventories.count(name) == 0) {
- errorstream<<FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
- return;
- }
- Inventory *inv = m_detached_inventories[name];
- std::ostringstream os(std::ios_base::binary);
+ const auto &inv_it = m_detached_inventories.find(name);
+ const auto &player_it = m_detached_inventories_player.find(name);
- os << serializeString(name);
- inv->serialize(os);
+ if (player_it == m_detached_inventories_player.end() ||
+ player_it->second.empty()) {
+ // OK. Send to everyone
+ } else {
+ RemotePlayer *p = m_env->getPlayer(player_it->second.c_str());
+ if (!p)
+ return; // Player is offline
- // Make data buffer
- std::string s = os.str();
+ if (peer_id != PEER_ID_INEXISTENT && peer_id != p->getPeerId())
+ return; // Caller requested send to a different player, so don't send.
+
+ peer_id = p->getPeerId();
+ }
NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
- pkt.putRawString(s.c_str(), s.size());
+ pkt << name;
- const std::string &check = m_detached_inventories_player[name];
- if (peer_id == PEER_ID_INEXISTENT) {
- if (check.empty())
- return m_clients.sendToAll(&pkt);
- RemotePlayer *p = m_env->getPlayer(check.c_str());
- if (p)
- m_clients.send(p->getPeerId(), 0, &pkt, true);
+ if (inv_it == m_detached_inventories.end()) {
+ pkt << false; // Remove inventory
} else {
- if (check.empty() || getPlayerName(peer_id) == check)
- Send(&pkt);
+ pkt << true; // Update inventory
+
+ // Serialization & NetworkPacket isn't a love story
+ std::ostringstream os(std::ios_base::binary);
+ inv_it->second->serialize(os);
+ pkt << os.str();
}
+
+ if (peer_id == PEER_ID_INEXISTENT)
+ m_clients.sendToAll(&pkt);
+ else
+ Send(&pkt);
}
void Server::sendDetachedInventories(session_t peer_id)
playersao->clearParentAttachment();
// inform connected clients
+ const std::string &player_name = player->getName();
NetworkPacket notice(TOCLIENT_UPDATE_PLAYER_LIST, 0, PEER_ID_INEXISTENT);
// (u16) 1 + std::string represents a vector serialization representation
- notice << (u8) PLAYER_LIST_REMOVE << (u16) 1 << std::string(playersao->getPlayer()->getName());
+ notice << (u8) PLAYER_LIST_REMOVE << (u16) 1 << player_name;
m_clients.sendToAll(¬ice);
// run scripts
m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
void Server::spawnParticle(const std::string &playername, v3f pos,
v3f velocity, v3f acceleration,
float expirationtime, float size, bool
- collisiondetection, bool collision_removal,
+ collisiondetection, bool collision_removal, bool object_collision,
bool vertical, const std::string &texture,
const struct TileAnimationParams &animation, u8 glow)
{
}
SendSpawnParticle(peer_id, proto_ver, pos, velocity, acceleration,
- expirationtime, size, collisiondetection,
- collision_removal, vertical, texture, animation, glow);
+ expirationtime, size, collisiondetection, collision_removal,
+ object_collision, vertical, texture, animation, glow);
}
u32 Server::addParticleSpawner(u16 amount, float spawntime,
v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
float minexptime, float maxexptime, float minsize, float maxsize,
- bool collisiondetection, bool collision_removal,
+ bool collisiondetection, bool collision_removal, bool object_collision,
ServerActiveObject *attached, bool vertical, const std::string &texture,
const std::string &playername, const struct TileAnimationParams &animation,
u8 glow)
SendAddParticleSpawner(peer_id, proto_ver, amount, spawntime,
minpos, maxpos, minvel, maxvel, minacc, maxacc,
- minexptime, maxexptime, minsize, maxsize,
- collisiondetection, collision_removal, attached_id, vertical,
+ minexptime, maxexptime, minsize, maxsize, collisiondetection,
+ collision_removal, object_collision, attached_id, vertical,
texture, id, animation, glow);
return id;
return inv;
}
+bool Server::removeDetachedInventory(const std::string &name)
+{
+ const auto &inv_it = m_detached_inventories.find(name);
+ if (inv_it == m_detached_inventories.end())
+ return false;
+
+ delete inv_it->second;
+ m_detached_inventories.erase(inv_it);
+
+ const auto &player_it = m_detached_inventories_player.find(name);
+ if (player_it != m_detached_inventories_player.end()) {
+ RemotePlayer *player = m_env->getPlayer(player_it->second.c_str());
+
+ if (player && player->getPeerId() != PEER_ID_INEXISTENT)
+ sendDetachedInventory(name, player->getPeerId());
+
+ m_detached_inventories_player.erase(player_it);
+ } else {
+ // Notify all players about the change
+ sendDetachedInventory(name, PEER_ID_INEXISTENT);
+ }
+ return true;
+}
+
// actions: time-reversed list
// Return value: success/failure
bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,