m_clients(m_con),
m_admin_chat(iface),
m_on_shutdown_errmsg(on_shutdown_errmsg),
- m_async_globals_data(""),
m_modchannel_mgr(new ModChannelMgr())
{
if (m_path_world.empty())
"minetest_core_latency",
"Latency value (in seconds)");
- m_aom_buffer_counter = m_metrics_backend->addCounter(
- "minetest_core_aom_generated_count",
- "Number of active object messages generated");
+
+ const std::string aom_types[] = {"reliable", "unreliable"};
+ for (u32 i = 0; i < ARRLEN(aom_types); i++) {
+ std::string help_str("Number of active object messages generated (");
+ help_str.append(aom_types[i]).append(")");
+ m_aom_buffer_counter[i] = m_metrics_backend->addCounter(
+ "minetest_core_aom_generated_count", help_str,
+ {{"type", aom_types[i]}});
+ }
m_packet_recv_counter = m_metrics_backend->addCounter(
"minetest_core_server_packet_recv",
"minetest_core_server_packet_recv_processed",
"Valid received packets processed");
+ m_map_edit_event_counter = m_metrics_backend->addCounter(
+ "minetest_core_map_edit_events",
+ "Number of map edit events");
+
m_lag_gauge->set(g_settings->getFloat("dedicated_server_step"));
}
}
// Create emerge manager
- m_emerge = new EmergeManager(this);
+ m_emerge = new EmergeManager(this, m_metrics_backend.get());
// Create ban manager
std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
m_script->loadMod(getBuiltinLuaPath() + DIR_DELIM "init.lua", BUILTIN_MOD_NAME);
+ m_gamespec.checkAndLog();
m_modmgr->loadMods(m_script);
// Read Textures and calculate sha1 sums
// Initialize Environment
m_startup_server_map = nullptr; // Ownership moved to ServerEnvironment
- m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
+ m_env = new ServerEnvironment(servermap, m_script, this,
+ m_path_world, m_metrics_backend.get());
m_inventory_mgr->setEnv(m_env);
m_clients.setEnv(m_env);
actionstream << "World at [" << m_path_world << "]" << std::endl;
actionstream << "Server for gameid=\"" << m_gamespec.id
<< "\" listening on ";
- m_bind_addr.print(&actionstream);
+ m_bind_addr.print(actionstream);
actionstream << "." << std::endl;
}
max_lag = dtime;
}
m_env->reportMaxLagEstimate(max_lag);
+
// Step environment
m_env->step(dtime);
}
// Get active object messages from environment
ActiveObjectMessage aom(0);
- u32 aom_count = 0;
+ u32 count_reliable = 0, count_unreliable = 0;
for(;;) {
if (!m_env->getActiveObjectMessage(&aom))
break;
+ if (aom.reliable)
+ count_reliable++;
+ else
+ count_unreliable++;
std::vector<ActiveObjectMessage>* message_list = nullptr;
auto n = buffered_messages.find(aom.id);
message_list = n->second;
}
message_list->push_back(std::move(aom));
- aom_count++;
}
- m_aom_buffer_counter->increment(aom_count);
+ m_aom_buffer_counter[0]->increment(count_reliable);
+ m_aom_buffer_counter[1]->increment(count_unreliable);
{
ClientInterface::AutoLock clientlock(m_clients);
// We will be accessing the environment
MutexAutoLock lock(m_env_mutex);
- // Don't send too many at a time
- //u32 count = 0;
-
- // Single change sending is disabled if queue size is not small
+ // Single change sending is disabled if queue size is big
bool disable_single_change_sending = false;
if(m_unsent_map_edit_queue.size() >= 4)
disable_single_change_sending = true;
- int event_count = m_unsent_map_edit_queue.size();
+ const auto event_count = m_unsent_map_edit_queue.size();
+ m_map_edit_event_counter->increment(event_count);
// We'll log the amount of each
Profiler prof;
- std::list<v3s16> node_meta_updates;
+ std::unordered_set<v3s16> node_meta_updates;
while (!m_unsent_map_edit_queue.empty()) {
MapEditEvent* event = m_unsent_map_edit_queue.front();
case MEET_BLOCK_NODE_METADATA_CHANGED: {
prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
if (!event->is_private_change) {
- // Don't send the change yet. Collect them to eliminate dupes.
- node_meta_updates.remove(event->p);
- node_meta_updates.push_back(event->p);
+ node_meta_updates.emplace(event->p);
}
if (MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(
}
// Send all metadata updates
- if (node_meta_updates.size())
+ if (!node_meta_updates.empty())
sendMetadataChanged(node_meta_updates);
}
}
}
-void Server::sendMetadataChanged(const std::list<v3s16> &meta_updates, float far_d_nodes)
+void Server::sendMetadataChanged(const std::unordered_set<v3s16> &positions, float far_d_nodes)
{
- float maxd = far_d_nodes * BS;
NodeMetadataList meta_updates_list(false);
- std::vector<session_t> clients = m_clients.getClientIDs();
+ std::ostringstream os(std::ios::binary);
+ std::vector<session_t> clients = m_clients.getClientIDs();
ClientInterface::AutoLock clientlock(m_clients);
for (session_t i : clients) {
if (!client)
continue;
- ServerActiveObject *player = m_env->getActiveObject(i);
- v3f player_pos = player ? player->getBasePosition() : v3f();
+ ServerActiveObject *player = getPlayerSAO(i);
+ v3s16 player_pos;
+ if (player)
+ player_pos = floatToInt(player->getBasePosition(), BS);
- for (const v3s16 &pos : meta_updates) {
+ for (const v3s16 pos : positions) {
NodeMetadata *meta = m_env->getMap().getNodeMetadata(pos);
if (!meta)
continue;
v3s16 block_pos = getNodeBlockPos(pos);
- if (!client->isBlockSent(block_pos) || (player &&
- player_pos.getDistanceFrom(intToFloat(pos, BS)) > maxd)) {
+ if (!client->isBlockSent(block_pos) ||
+ player_pos.getDistanceFrom(pos) > far_d_nodes) {
client->SetBlockNotSent(block_pos);
continue;
}
continue;
// Send the meta changes
- std::ostringstream os(std::ios::binary);
+ os.str("");
meta_updates_list.serialize(os, client->serialization_version, false, true, true);
- std::ostringstream oss(std::ios::binary);
- compressZlib(os.str(), oss);
+ std::string raw = os.str();
+ os.str("");
+ compressZlib(raw, os);
- NetworkPacket pkt(TOCLIENT_NODEMETA_CHANGED, 0);
- pkt.putLongString(oss.str());
- m_clients.send(i, 0, &pkt, true);
+ NetworkPacket pkt(TOCLIENT_NODEMETA_CHANGED, 0, i);
+ pkt.putLongString(os.str());
+ Send(&pkt);
meta_updates_list.clear();
}
}
void Server::SendBlockNoLock(session_t peer_id, MapBlock *block, u8 ver,
- u16 net_proto_version)
+ u16 net_proto_version, SerializedBlockCache *cache)
{
- /*
- Create a packet with the block in the right format
- */
thread_local const int net_compression_level = rangelim(g_settings->getS16("map_compression_level_net"), -1, 9);
- std::ostringstream os(std::ios_base::binary);
- block->serialize(os, ver, false, net_compression_level);
- block->serializeNetworkSpecific(os);
- std::string s = os.str();
+ std::string s, *sptr = nullptr;
- NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + s.size(), peer_id);
+ if (cache) {
+ auto it = cache->find({block->getPos(), ver});
+ if (it != cache->end())
+ sptr = &it->second;
+ }
+ // Serialize the block in the right format
+ if (!sptr) {
+ std::ostringstream os(std::ios_base::binary);
+ block->serialize(os, ver, false, net_compression_level);
+ block->serializeNetworkSpecific(os);
+ s = os.str();
+ sptr = &s;
+ }
+
+ NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + sptr->size(), peer_id);
pkt << block->getPos();
- pkt.putRawString(s.c_str(), s.size());
+ pkt.putRawString(*sptr);
Send(&pkt);
+
+ // Store away in cache
+ if (cache && sptr == &s)
+ (*cache)[{block->getPos(), ver}] = std::move(s);
}
void Server::SendBlocks(float dtime)
std::vector<PrioritySortedBlockTransfer> queue;
- u32 total_sending = 0;
+ u32 total_sending = 0, unique_clients = 0;
{
ScopeProfiler sp2(g_profiler, "Server::SendBlocks(): Collect list");
continue;
total_sending += client->getSendingCount();
+ const auto old_count = queue.size();
client->GetNextBlocks(m_env,m_emerge, dtime, queue);
+ unique_clients += queue.size() > old_count ? 1 : 0;
}
}
ScopeProfiler sp(g_profiler, "Server::SendBlocks(): Send to clients");
Map &map = m_env->getMap();
+ SerializedBlockCache cache, *cache_ptr = nullptr;
+ if (unique_clients > 1) {
+ // caching is pointless with a single client
+ cache_ptr = &cache;
+ }
+
for (const PrioritySortedBlockTransfer &block_to_send : queue) {
if (total_sending >= max_blocks_to_send)
break;
continue;
SendBlockNoLock(block_to_send.peer_id, block, client->serialization_version,
- client->net_proto_version);
+ client->net_proto_version, cache_ptr);
client->SentBlock(block_to_send.pos);
total_sending++;
<< playersao->getPlayer()->getName()
<< " respawns" << std::endl;
- playersao->setHP(playersao->accessObjectProperties()->hp_max,
+ const auto *prop = playersao->accessObjectProperties();
+ playersao->setHP(prop->hp_max,
PlayerHPChangeReason(PlayerHPChangeReason::RESPAWN));
- playersao->setBreath(playersao->accessObjectProperties()->breath_max);
+ playersao->setBreath(prop->breath_max);
bool repositioned = m_script->on_respawnplayer(playersao);
if (!repositioned) {
// Version
os << "version: " << g_version_string;
// Game
- os << " | game: " << (m_gamespec.name.empty() ? m_gamespec.id : m_gamespec.name);
+ os << " | game: " << (m_gamespec.title.empty() ? m_gamespec.id : m_gamespec.title);
// Uptime
os << " | uptime: " << duration_to_string((int) m_uptime_counter->get());
// Max lag estimate