3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include "network/connection.h"
25 #include "network/networkprotocol.h"
26 #include "network/serveropcodes.h"
28 #include "environment.h"
30 #include "threading/mutex_auto_lock.h"
31 #include "constants.h"
37 #include "server/serveractiveobject.h"
41 #include "scripting_server.h"
46 #include "mapgen/mapgen.h"
47 #include "mapgen/mg_biome.h"
48 #include "content_mapnode.h"
49 #include "content_nodemeta.h"
50 #include "content/mods.h"
51 #include "modchannels.h"
52 #include "serverlist.h"
53 #include "util/string.h"
55 #include "util/serialize.h"
56 #include "util/thread.h"
57 #include "defaultsettings.h"
58 #include "server/mods.h"
59 #include "util/base64.h"
60 #include "util/sha1.h"
62 #include "database/database.h"
63 #include "chatmessage.h"
64 #include "chat_interface.h"
65 #include "remoteplayer.h"
66 #include "server/player_sao.h"
67 #include "translation.h"
69 class ClientNotFoundException : public BaseException
72 ClientNotFoundException(const char *s):
77 class ServerThread : public Thread
81 ServerThread(Server *server):
92 void *ServerThread::run()
94 BEGIN_DEBUG_EXCEPTION_HANDLER
97 * The real business of the server happens on the ServerThread.
99 * AsyncRunStep() runs an actual server step as soon as enough time has
100 * passed (dedicated_server_loop keeps track of that).
101 * Receive() blocks at least(!) 30ms waiting for a packet (so this loop
102 * doesn't busy wait) and will process any remaining packets.
105 m_server->AsyncRunStep(true);
107 while (!stopRequested()) {
109 m_server->AsyncRunStep();
113 } catch (con::PeerNotFoundException &e) {
114 infostream<<"Server: PeerNotFoundException"<<std::endl;
115 } catch (ClientNotFoundException &e) {
116 } catch (con::ConnectionBindFailed &e) {
117 m_server->setAsyncFatalError(e.what());
118 } catch (LuaError &e) {
119 m_server->setAsyncFatalError(
120 "ServerThread::run Lua: " + std::string(e.what()));
124 END_DEBUG_EXCEPTION_HANDLER
129 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
131 if(pos_exists) *pos_exists = false;
136 if(pos_exists) *pos_exists = true;
141 ServerActiveObject *sao = env->getActiveObject(object);
144 if(pos_exists) *pos_exists = true;
145 return sao->getBasePosition(); }
150 void Server::ShutdownState::reset()
154 should_reconnect = false;
155 is_requested = false;
158 void Server::ShutdownState::trigger(float delay, const std::string &msg, bool reconnect)
162 should_reconnect = reconnect;
165 void Server::ShutdownState::tick(float dtime, Server *server)
171 static const float shutdown_msg_times[] =
173 1, 2, 3, 4, 5, 10, 20, 40, 60, 120, 180, 300, 600, 1200, 1800, 3600
176 // Automated messages
177 if (m_timer < shutdown_msg_times[ARRLEN(shutdown_msg_times) - 1]) {
178 for (float t : shutdown_msg_times) {
179 // If shutdown timer matches an automessage, shot it
180 if (m_timer > t && m_timer - dtime < t) {
181 std::wstring periodicMsg = getShutdownTimerMessage();
183 infostream << wide_to_utf8(periodicMsg).c_str() << std::endl;
184 server->SendChatMessage(PEER_ID_INEXISTENT, periodicMsg);
191 if (m_timer < 0.0f) {
197 std::wstring Server::ShutdownState::getShutdownTimerMessage() const
199 std::wstringstream ws;
200 ws << L"*** Server shutting down in "
201 << duration_to_string(myround(m_timer)).c_str() << ".";
210 const std::string &path_world,
211 const SubgameSpec &gamespec,
212 bool simple_singleplayer_mode,
217 m_bind_addr(bind_addr),
218 m_path_world(path_world),
219 m_gamespec(gamespec),
220 m_simple_singleplayer_mode(simple_singleplayer_mode),
221 m_dedicated(dedicated),
222 m_async_fatal_error(""),
223 m_con(std::make_shared<con::Connection>(PROTOCOL_ID,
226 m_bind_addr.isIPv6(),
228 m_itemdef(createItemDefManager()),
229 m_nodedef(createNodeDefManager()),
230 m_craftdef(createCraftDefManager()),
231 m_thread(new ServerThread(this)),
234 m_modchannel_mgr(new ModChannelMgr())
236 if (m_path_world.empty())
237 throw ServerError("Supplied empty world path");
239 if (!gamespec.isValid())
240 throw ServerError("Supplied invalid gamespec");
243 m_metrics_backend = std::unique_ptr<MetricsBackend>(createPrometheusMetricsBackend());
245 m_metrics_backend = std::unique_ptr<MetricsBackend>(new MetricsBackend());
248 m_uptime_counter = m_metrics_backend->addCounter("minetest_core_server_uptime", "Server uptime (in seconds)");
249 m_player_gauge = m_metrics_backend->addGauge("minetest_core_player_number", "Number of connected players");
251 m_timeofday_gauge = m_metrics_backend->addGauge(
252 "minetest_core_timeofday",
253 "Time of day value");
255 m_lag_gauge = m_metrics_backend->addGauge(
256 "minetest_core_latency",
257 "Latency value (in seconds)");
259 m_aom_buffer_counter = m_metrics_backend->addCounter(
260 "minetest_core_aom_generated_count",
261 "Number of active object messages generated");
263 m_packet_recv_counter = m_metrics_backend->addCounter(
264 "minetest_core_server_packet_recv",
265 "Processable packets received");
267 m_packet_recv_processed_counter = m_metrics_backend->addCounter(
268 "minetest_core_server_packet_recv_processed",
269 "Valid received packets processed");
271 m_lag_gauge->set(g_settings->getFloat("dedicated_server_step"));
277 // Send shutdown message
278 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE,
279 L"*** Server shutting down"));
282 MutexAutoLock envlock(m_env_mutex);
284 infostream << "Server: Saving players" << std::endl;
285 m_env->saveLoadedPlayers();
287 infostream << "Server: Kicking players" << std::endl;
288 std::string kick_msg;
289 bool reconnect = false;
290 if (isShutdownRequested()) {
291 reconnect = m_shutdown_state.should_reconnect;
292 kick_msg = m_shutdown_state.message;
294 if (kick_msg.empty()) {
295 kick_msg = g_settings->get("kick_msg_shutdown");
297 m_env->saveLoadedPlayers(true);
298 m_env->kickAllPlayers(SERVER_ACCESSDENIED_SHUTDOWN,
299 kick_msg, reconnect);
302 actionstream << "Server: Shutting down" << std::endl;
304 // Do this before stopping the server in case mapgen callbacks need to access
305 // server-controlled resources (like ModStorages). Also do them before
306 // shutdown callbacks since they may modify state that is finalized in a
309 m_emerge->stopThreads();
312 MutexAutoLock envlock(m_env_mutex);
314 // Execute script shutdown hooks
315 infostream << "Executing shutdown hooks" << std::endl;
316 m_script->on_shutdown();
318 infostream << "Server: Saving environment metadata" << std::endl;
328 // Delete things in the reverse order of creation
337 // Deinitialize scripting
338 infostream << "Server: Deinitializing scripting" << std::endl;
341 // Delete detached inventories
342 for (auto &detached_inventory : m_detached_inventories) {
343 delete detached_inventory.second;
346 while (!m_unsent_map_edit_queue.empty()) {
347 delete m_unsent_map_edit_queue.front();
348 m_unsent_map_edit_queue.pop();
354 infostream << "Server created for gameid \"" << m_gamespec.id << "\"";
355 if (m_simple_singleplayer_mode)
356 infostream << " in simple singleplayer mode" << std::endl;
358 infostream << std::endl;
359 infostream << "- world: " << m_path_world << std::endl;
360 infostream << "- game: " << m_gamespec.path << std::endl;
362 // Create world if it doesn't exist
363 if (!loadGameConfAndInitWorld(m_path_world, m_gamespec))
364 throw ServerError("Failed to initialize world");
366 // Create emerge manager
367 m_emerge = new EmergeManager(this);
369 // Create ban manager
370 std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
371 m_banmanager = new BanManager(ban_path);
373 m_modmgr = std::unique_ptr<ServerModManager>(new ServerModManager(m_path_world));
374 std::vector<ModSpec> unsatisfied_mods = m_modmgr->getUnsatisfiedMods();
375 // complain about mods with unsatisfied dependencies
376 if (!m_modmgr->isConsistent()) {
377 m_modmgr->printUnsatisfiedModsError();
381 MutexAutoLock envlock(m_env_mutex);
383 // Create the Map (loads map_meta.txt, overriding configured mapgen params)
384 ServerMap *servermap = new ServerMap(m_path_world, this, m_emerge, m_metrics_backend.get());
386 // Initialize scripting
387 infostream << "Server: Initializing Lua" << std::endl;
389 m_script = new ServerScripting(this);
391 m_script->loadMod(getBuiltinLuaPath() + DIR_DELIM "init.lua", BUILTIN_MOD_NAME);
393 m_modmgr->loadMods(m_script);
395 // Read Textures and calculate sha1 sums
398 // Apply item aliases in the node definition manager
399 m_nodedef->updateAliases(m_itemdef);
401 // Apply texture overrides from texturepack/override.txt
402 std::vector<std::string> paths;
403 fs::GetRecursiveDirs(paths, g_settings->get("texture_path"));
404 fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures");
405 for (const std::string &path : paths) {
406 TextureOverrideSource override_source(path + DIR_DELIM + "override.txt");
407 m_nodedef->applyTextureOverrides(override_source.getNodeTileOverrides());
408 m_itemdef->applyTextureOverrides(override_source.getItemTextureOverrides());
411 m_nodedef->setNodeRegistrationStatus(true);
413 // Perform pending node name resolutions
414 m_nodedef->runNodeResolveCallbacks();
416 // unmap node names for connected nodeboxes
417 m_nodedef->mapNodeboxConnections();
419 // init the recipe hashes to speed up crafting
420 m_craftdef->initHashes(this);
422 // Initialize Environment
423 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
425 m_clients.setEnv(m_env);
427 if (!servermap->settings_mgr.makeMapgenParams())
428 FATAL_ERROR("Couldn't create any mapgen type");
430 // Initialize mapgens
431 m_emerge->initMapgens(servermap->getMapgenParams());
433 if (g_settings->getBool("enable_rollback_recording")) {
434 // Create rollback manager
435 m_rollback = new RollbackManager(m_path_world, this);
438 // Give environment reference to scripting api
439 m_script->initializeEnvironment(m_env);
441 // Register us to receive map edit events
442 servermap->addEventReceiver(this);
446 m_liquid_transform_every = g_settings->getFloat("liquid_update");
447 m_max_chatmessage_length = g_settings->getU16("chat_message_max_size");
448 m_csm_restriction_flags = g_settings->getU64("csm_restriction_flags");
449 m_csm_restriction_noderange = g_settings->getU32("csm_restriction_noderange");
454 infostream << "Starting server on " << m_bind_addr.serializeString()
455 << "..." << std::endl;
457 // Stop thread if already running
460 // Initialize connection
461 m_con->SetTimeoutMs(30);
462 m_con->Serve(m_bind_addr);
467 // ASCII art for the win!
469 << " .__ __ __ " << std::endl
470 << " _____ |__| ____ _____/ |_ ____ _______/ |_ " << std::endl
471 << " / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\" << std::endl
472 << "| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | " << std::endl
473 << "|__|_| /__|___| /\\___ >__| \\___ >____ > |__| " << std::endl
474 << " \\/ \\/ \\/ \\/ \\/ " << std::endl;
475 actionstream << "World at [" << m_path_world << "]" << std::endl;
476 actionstream << "Server for gameid=\"" << m_gamespec.id
477 << "\" listening on " << m_bind_addr.serializeString() << ":"
478 << m_bind_addr.getPort() << "." << std::endl;
483 infostream<<"Server: Stopping and waiting threads"<<std::endl;
485 // Stop threads (set run=false first so both start stopping)
487 //m_emergethread.setRun(false);
489 //m_emergethread.stop();
491 infostream<<"Server: Threads stopped"<<std::endl;
494 void Server::step(float dtime)
500 MutexAutoLock lock(m_step_dtime_mutex);
501 m_step_dtime += dtime;
503 // Throw if fatal error occurred in thread
504 std::string async_err = m_async_fatal_error.get();
505 if (!async_err.empty()) {
506 if (!m_simple_singleplayer_mode) {
507 m_env->kickAllPlayers(SERVER_ACCESSDENIED_CRASH,
508 g_settings->get("kick_msg_crash"),
509 g_settings->getBool("ask_reconnect_on_crash"));
511 throw ServerError("AsyncErr: " + async_err);
515 void Server::AsyncRunStep(bool initial_step)
520 MutexAutoLock lock1(m_step_dtime_mutex);
521 dtime = m_step_dtime;
525 // Send blocks to clients
529 if((dtime < 0.001) && !initial_step)
532 ScopeProfiler sp(g_profiler, "Server::AsyncRunStep()", SPT_AVG);
535 MutexAutoLock lock1(m_step_dtime_mutex);
536 m_step_dtime -= dtime;
542 m_uptime_counter->increment(dtime);
547 Update time of day and overall game time
549 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
552 Send to clients at constant intervals
555 m_time_of_day_send_timer -= dtime;
556 if (m_time_of_day_send_timer < 0.0) {
557 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
558 u16 time = m_env->getTimeOfDay();
559 float time_speed = g_settings->getFloat("time_speed");
560 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
562 m_timeofday_gauge->set(time);
566 MutexAutoLock lock(m_env_mutex);
567 // Figure out and report maximum lag to environment
568 float max_lag = m_env->getMaxLagEstimate();
569 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
571 if(dtime > 0.1 && dtime > max_lag * 2.0)
572 infostream<<"Server: Maximum lag peaked to "<<dtime
576 m_env->reportMaxLagEstimate(max_lag);
581 static const float map_timer_and_unload_dtime = 2.92;
582 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
584 MutexAutoLock lock(m_env_mutex);
585 // Run Map's timers and unload unused data
586 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
587 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
588 g_settings->getFloat("server_unload_unused_data_timeout"),
593 Listen to the admin chat, if available
596 if (!m_admin_chat->command_queue.empty()) {
597 MutexAutoLock lock(m_env_mutex);
598 while (!m_admin_chat->command_queue.empty()) {
599 ChatEvent *evt = m_admin_chat->command_queue.pop_frontNoEx();
600 handleChatInterfaceEvent(evt);
604 m_admin_chat->outgoing_queue.push_back(
605 new ChatEventTimeInfo(m_env->getGameTime(), m_env->getTimeOfDay()));
612 /* Transform liquids */
613 m_liquid_transform_timer += dtime;
614 if(m_liquid_transform_timer >= m_liquid_transform_every)
616 m_liquid_transform_timer -= m_liquid_transform_every;
618 MutexAutoLock lock(m_env_mutex);
620 ScopeProfiler sp(g_profiler, "Server: liquid transform");
622 std::map<v3s16, MapBlock*> modified_blocks;
623 m_env->getMap().transformLiquids(modified_blocks, m_env);
626 Set the modified blocks unsent for all the clients
628 if (!modified_blocks.empty()) {
629 SetBlocksNotSent(modified_blocks);
632 m_clients.step(dtime);
634 m_lag_gauge->increment((m_lag_gauge->get() > dtime ? -1 : 1) * dtime/100);
636 // send masterserver announce
638 float &counter = m_masterserver_timer;
639 if (!isSingleplayer() && (!counter || counter >= 300.0) &&
640 g_settings->getBool("server_announce")) {
641 ServerList::sendAnnounce(counter ? ServerList::AA_UPDATE :
642 ServerList::AA_START,
643 m_bind_addr.getPort(),
644 m_clients.getPlayerNames(),
645 m_uptime_counter->get(),
646 m_env->getGameTime(),
649 Mapgen::getMapgenName(m_emerge->mgparams->mgtype),
659 Check added and deleted active objects
662 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
663 MutexAutoLock envlock(m_env_mutex);
666 const RemoteClientMap &clients = m_clients.getClientList();
667 ScopeProfiler sp(g_profiler, "Server: update objects within range");
669 m_player_gauge->set(clients.size());
670 for (const auto &client_it : clients) {
671 RemoteClient *client = client_it.second;
673 if (client->getState() < CS_DefinitionsSent)
676 // This can happen if the client times out somehow
677 if (!m_env->getPlayer(client->peer_id))
680 PlayerSAO *playersao = getPlayerSAO(client->peer_id);
684 SendActiveObjectRemoveAdd(client, playersao);
688 // Save mod storages if modified
689 m_mod_storage_save_timer -= dtime;
690 if (m_mod_storage_save_timer <= 0.0f) {
691 m_mod_storage_save_timer = g_settings->getFloat("server_map_save_interval");
693 for (std::unordered_map<std::string, ModMetadata *>::const_iterator
694 it = m_mod_storages.begin(); it != m_mod_storages.end(); ++it) {
695 if (it->second->isModified()) {
696 it->second->save(getModStoragePath());
701 infostream << "Saved " << n << " modified mod storages." << std::endl;
709 MutexAutoLock envlock(m_env_mutex);
710 ScopeProfiler sp(g_profiler, "Server: send SAO messages");
713 // Value = data sent by object
714 std::unordered_map<u16, std::vector<ActiveObjectMessage>*> buffered_messages;
716 // Get active object messages from environment
718 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
722 std::vector<ActiveObjectMessage>* message_list = nullptr;
723 std::unordered_map<u16, std::vector<ActiveObjectMessage>* >::iterator n;
724 n = buffered_messages.find(aom.id);
725 if (n == buffered_messages.end()) {
726 message_list = new std::vector<ActiveObjectMessage>;
727 buffered_messages[aom.id] = message_list;
730 message_list = n->second;
732 message_list->push_back(aom);
735 m_aom_buffer_counter->increment(buffered_messages.size());
738 const RemoteClientMap &clients = m_clients.getClientList();
739 // Route data to every client
740 for (const auto &client_it : clients) {
741 RemoteClient *client = client_it.second;
742 PlayerSAO *player = getPlayerSAO(client->peer_id);
743 std::string reliable_data;
744 std::string unreliable_data;
745 // Go through all objects in message buffer
746 for (const auto &buffered_message : buffered_messages) {
747 // If object does not exist or is not known by client, skip it
748 u16 id = buffered_message.first;
749 ServerActiveObject *sao = m_env->getActiveObject(id);
750 if (!sao || client->m_known_objects.find(id) == client->m_known_objects.end())
753 // Get message list of object
754 std::vector<ActiveObjectMessage>* list = buffered_message.second;
755 // Go through every message
756 for (const ActiveObjectMessage &aom : *list) {
757 // Send position updates to players who do not see the attachment
758 if (aom.datastring[0] == AO_CMD_UPDATE_POSITION) {
759 if (sao->getId() == player->getId())
762 // Do not send position updates for attached players
763 // as long the parent is known to the client
764 ServerActiveObject *parent = sao->getParent();
765 if (parent && client->m_known_objects.find(parent->getId()) !=
766 client->m_known_objects.end())
769 // Compose the full new data with header
770 std::string new_data;
773 writeU16((u8*)&buf[0], aom.id);
774 new_data.append(buf, 2);
776 new_data += serializeString(aom.datastring);
777 // Add data to buffer
779 reliable_data += new_data;
781 unreliable_data += new_data;
785 reliable_data and unreliable_data are now ready.
788 if (!reliable_data.empty()) {
789 SendActiveObjectMessages(client->peer_id, reliable_data);
792 if (!unreliable_data.empty()) {
793 SendActiveObjectMessages(client->peer_id, unreliable_data, false);
798 // Clear buffered_messages
799 for (auto &buffered_message : buffered_messages) {
800 delete buffered_message.second;
805 Send queued-for-sending map edit events.
808 // We will be accessing the environment
809 MutexAutoLock lock(m_env_mutex);
811 // Don't send too many at a time
814 // Single change sending is disabled if queue size is not small
815 bool disable_single_change_sending = false;
816 if(m_unsent_map_edit_queue.size() >= 4)
817 disable_single_change_sending = true;
819 int event_count = m_unsent_map_edit_queue.size();
821 // We'll log the amount of each
824 std::list<v3s16> node_meta_updates;
826 while (!m_unsent_map_edit_queue.empty()) {
827 MapEditEvent* event = m_unsent_map_edit_queue.front();
828 m_unsent_map_edit_queue.pop();
830 // Players far away from the change are stored here.
831 // Instead of sending the changes, MapBlocks are set not sent
833 std::unordered_set<u16> far_players;
835 switch (event->type) {
838 prof.add("MEET_ADDNODE", 1);
839 sendAddNode(event->p, event->n, &far_players,
840 disable_single_change_sending ? 5 : 30,
841 event->type == MEET_ADDNODE);
843 case MEET_REMOVENODE:
844 prof.add("MEET_REMOVENODE", 1);
845 sendRemoveNode(event->p, &far_players,
846 disable_single_change_sending ? 5 : 30);
848 case MEET_BLOCK_NODE_METADATA_CHANGED: {
849 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
850 if (!event->is_private_change) {
851 // Don't send the change yet. Collect them to eliminate dupes.
852 node_meta_updates.remove(event->p);
853 node_meta_updates.push_back(event->p);
856 if (MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(
857 getNodeBlockPos(event->p))) {
858 block->raiseModified(MOD_STATE_WRITE_NEEDED,
859 MOD_REASON_REPORT_META_CHANGE);
864 prof.add("MEET_OTHER", 1);
865 for (const v3s16 &modified_block : event->modified_blocks) {
866 m_clients.markBlockposAsNotSent(modified_block);
870 prof.add("unknown", 1);
871 warningstream << "Server: Unknown MapEditEvent "
872 << ((u32)event->type) << std::endl;
877 Set blocks not sent to far players
879 if (!far_players.empty()) {
880 // Convert list format to that wanted by SetBlocksNotSent
881 std::map<v3s16, MapBlock*> modified_blocks2;
882 for (const v3s16 &modified_block : event->modified_blocks) {
883 modified_blocks2[modified_block] =
884 m_env->getMap().getBlockNoCreateNoEx(modified_block);
887 // Set blocks not sent
888 for (const u16 far_player : far_players) {
889 if (RemoteClient *client = getClient(far_player))
890 client->SetBlocksNotSent(modified_blocks2);
897 if (event_count >= 5) {
898 infostream << "Server: MapEditEvents:" << std::endl;
899 prof.print(infostream);
900 } else if (event_count != 0) {
901 verbosestream << "Server: MapEditEvents:" << std::endl;
902 prof.print(verbosestream);
905 // Send all metadata updates
906 if (node_meta_updates.size())
907 sendMetadataChanged(node_meta_updates);
911 Trigger emergethread (it somehow gets to a non-triggered but
912 bysy state sometimes)
915 float &counter = m_emergethread_trigger_timer;
917 if (counter >= 2.0) {
920 m_emerge->startThreads();
924 // Save map, players and auth stuff
926 float &counter = m_savemap_timer;
928 static thread_local const float save_interval =
929 g_settings->getFloat("server_map_save_interval");
930 if (counter >= save_interval) {
932 MutexAutoLock lock(m_env_mutex);
934 ScopeProfiler sp(g_profiler, "Server: map saving (sum)");
937 if (m_banmanager->isModified()) {
938 m_banmanager->save();
941 // Save changed parts of map
942 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
945 m_env->saveLoadedPlayers();
947 // Save environment metadata
952 m_shutdown_state.tick(dtime, this);
955 void Server::Receive()
965 In the first iteration *wait* for a packet, afterwards process
966 all packets that are immediately available (no waiting).
969 m_con->Receive(&pkt);
972 if (!m_con->TryReceive(&pkt))
976 peer_id = pkt.getPeerId();
977 m_packet_recv_counter->increment();
979 m_packet_recv_processed_counter->increment();
980 } catch (const con::InvalidIncomingDataException &e) {
981 infostream << "Server::Receive(): InvalidIncomingDataException: what()="
982 << e.what() << std::endl;
983 } catch (const SerializationError &e) {
984 infostream << "Server::Receive(): SerializationError: what()="
985 << e.what() << std::endl;
986 } catch (const ClientStateError &e) {
987 errorstream << "ProcessData: peer=" << peer_id << " what()="
988 << e.what() << std::endl;
989 DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
990 L"Try reconnecting or updating your client");
991 } catch (const con::PeerNotFoundException &e) {
993 } catch (const con::NoIncomingDataException &e) {
999 PlayerSAO* Server::StageTwoClientInit(session_t peer_id)
1001 std::string playername;
1002 PlayerSAO *playersao = NULL;
1005 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1007 playername = client->getName();
1008 playersao = emergePlayer(playername.c_str(), peer_id, client->net_proto_version);
1010 } catch (std::exception &e) {
1016 RemotePlayer *player = m_env->getPlayer(playername.c_str());
1018 // If failed, cancel
1019 if (!playersao || !player) {
1020 if (player && player->getPeerId() != PEER_ID_INEXISTENT) {
1021 actionstream << "Server: Failed to emerge player \"" << playername
1022 << "\" (player allocated to an another client)" << std::endl;
1023 DenyAccess_Legacy(peer_id, L"Another client is connected with this "
1024 L"name. If your client closed unexpectedly, try again in "
1027 errorstream << "Server: " << playername << ": Failed to emerge player"
1029 DenyAccess_Legacy(peer_id, L"Could not allocate player.");
1035 Send complete position information
1037 SendMovePlayer(peer_id);
1040 SendPlayerPrivileges(peer_id);
1042 // Send inventory formspec
1043 SendPlayerInventoryFormspec(peer_id);
1046 SendInventory(playersao, false);
1048 // Send HP or death screen
1049 if (playersao->isDead())
1050 SendDeathscreen(peer_id, false, v3f(0,0,0));
1052 SendPlayerHPOrDie(playersao,
1053 PlayerHPChangeReason(PlayerHPChangeReason::SET_HP));
1056 SendPlayerBreath(playersao);
1062 Address addr = getPeerAddress(player->getPeerId());
1063 std::string ip_str = addr.serializeString();
1064 const std::vector<std::string> &names = m_clients.getPlayerNames();
1066 actionstream << player->getName() << " [" << ip_str << "] joins game. List of players: ";
1068 for (const std::string &name : names) {
1069 actionstream << name << " ";
1072 actionstream << player->getName() <<std::endl;
1077 inline void Server::handleCommand(NetworkPacket *pkt)
1079 const ToServerCommandHandler &opHandle = toServerCommandTable[pkt->getCommand()];
1080 (this->*opHandle.handler)(pkt);
1083 void Server::ProcessData(NetworkPacket *pkt)
1085 // Environment is locked first.
1086 MutexAutoLock envlock(m_env_mutex);
1088 ScopeProfiler sp(g_profiler, "Server: Process network packet (sum)");
1089 u32 peer_id = pkt->getPeerId();
1092 Address address = getPeerAddress(peer_id);
1093 std::string addr_s = address.serializeString();
1095 if(m_banmanager->isIpBanned(addr_s)) {
1096 std::string ban_name = m_banmanager->getBanName(addr_s);
1097 infostream << "Server: A banned client tried to connect from "
1098 << addr_s << "; banned name was "
1099 << ban_name << std::endl;
1100 // This actually doesn't seem to transfer to the client
1101 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1102 + utf8_to_wide(ban_name));
1106 catch(con::PeerNotFoundException &e) {
1108 * no peer for this packet found
1109 * most common reason is peer timeout, e.g. peer didn't
1110 * respond for some time, your server was overloaded or
1113 infostream << "Server::ProcessData(): Canceling: peer "
1114 << peer_id << " not found" << std::endl;
1119 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1121 // Command must be handled into ToServerCommandHandler
1122 if (command >= TOSERVER_NUM_MSG_TYPES) {
1123 infostream << "Server: Ignoring unknown command "
1124 << command << std::endl;
1128 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1133 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1135 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1136 errorstream << "Server::ProcessData(): Cancelling: Peer"
1137 " serialization format invalid or not initialized."
1138 " Skipping incoming command=" << command << std::endl;
1142 /* Handle commands related to client startup */
1143 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1148 if (m_clients.getClientState(peer_id) < CS_Active) {
1149 if (command == TOSERVER_PLAYERPOS) return;
1151 errorstream << "Got packet command: " << command << " for peer id "
1152 << peer_id << " but client isn't active yet. Dropping packet "
1158 } catch (SendFailedException &e) {
1159 errorstream << "Server::ProcessData(): SendFailedException: "
1160 << "what=" << e.what()
1162 } catch (PacketError &e) {
1163 actionstream << "Server::ProcessData(): PacketError: "
1164 << "what=" << e.what()
1169 void Server::setTimeOfDay(u32 time)
1171 m_env->setTimeOfDay(time);
1172 m_time_of_day_send_timer = 0;
1175 void Server::onMapEditEvent(const MapEditEvent &event)
1177 if (m_ignore_map_edit_events_area.contains(event.getArea()))
1180 m_unsent_map_edit_queue.push(new MapEditEvent(event));
1183 Inventory* Server::getInventory(const InventoryLocation &loc)
1186 case InventoryLocation::UNDEFINED:
1187 case InventoryLocation::CURRENT_PLAYER:
1189 case InventoryLocation::PLAYER:
1191 RemotePlayer *player = m_env->getPlayer(loc.name.c_str());
1194 PlayerSAO *playersao = player->getPlayerSAO();
1197 return playersao->getInventory();
1200 case InventoryLocation::NODEMETA:
1202 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1205 return meta->getInventory();
1208 case InventoryLocation::DETACHED:
1210 if(m_detached_inventories.count(loc.name) == 0)
1212 return m_detached_inventories[loc.name];
1216 sanity_check(false); // abort
1222 void Server::setInventoryModified(const InventoryLocation &loc)
1225 case InventoryLocation::UNDEFINED:
1227 case InventoryLocation::PLAYER:
1230 RemotePlayer *player = m_env->getPlayer(loc.name.c_str());
1235 player->setModified(true);
1236 player->inventory.setModified(true);
1237 // Updates are sent in ServerEnvironment::step()
1240 case InventoryLocation::NODEMETA:
1243 event.type = MEET_BLOCK_NODE_METADATA_CHANGED;
1245 m_env->getMap().dispatchEvent(event);
1248 case InventoryLocation::DETACHED:
1250 // Updates are sent in ServerEnvironment::step()
1254 sanity_check(false); // abort
1259 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1261 std::vector<session_t> clients = m_clients.getClientIDs();
1263 // Set the modified blocks unsent for all the clients
1264 for (const session_t client_id : clients) {
1265 if (RemoteClient *client = m_clients.lockedGetClientNoEx(client_id))
1266 client->SetBlocksNotSent(block);
1271 void Server::peerAdded(con::Peer *peer)
1273 verbosestream<<"Server::peerAdded(): peer->id="
1274 <<peer->id<<std::endl;
1276 m_peer_change_queue.push(con::PeerChange(con::PEER_ADDED, peer->id, false));
1279 void Server::deletingPeer(con::Peer *peer, bool timeout)
1281 verbosestream<<"Server::deletingPeer(): peer->id="
1282 <<peer->id<<", timeout="<<timeout<<std::endl;
1284 m_clients.event(peer->id, CSE_Disconnect);
1285 m_peer_change_queue.push(con::PeerChange(con::PEER_REMOVED, peer->id, timeout));
1288 bool Server::getClientConInfo(session_t peer_id, con::rtt_stat_type type, float* retval)
1290 *retval = m_con->getPeerStat(peer_id,type);
1291 return *retval != -1;
1294 bool Server::getClientInfo(
1303 std::string* vers_string,
1304 std::string* lang_code
1307 *state = m_clients.getClientState(peer_id);
1309 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1316 *uptime = client->uptime();
1317 *ser_vers = client->serialization_version;
1318 *prot_vers = client->net_proto_version;
1320 *major = client->getMajor();
1321 *minor = client->getMinor();
1322 *patch = client->getPatch();
1323 *vers_string = client->getFull();
1324 *lang_code = client->getLangCode();
1331 void Server::handlePeerChanges()
1333 while(!m_peer_change_queue.empty())
1335 con::PeerChange c = m_peer_change_queue.front();
1336 m_peer_change_queue.pop();
1338 verbosestream<<"Server: Handling peer change: "
1339 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1344 case con::PEER_ADDED:
1345 m_clients.CreateClient(c.peer_id);
1348 case con::PEER_REMOVED:
1349 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1353 FATAL_ERROR("Invalid peer change event received!");
1359 void Server::printToConsoleOnly(const std::string &text)
1362 m_admin_chat->outgoing_queue.push_back(
1363 new ChatEventChat("", utf8_to_wide(text)));
1365 std::cout << text << std::endl;
1369 void Server::Send(NetworkPacket *pkt)
1371 Send(pkt->getPeerId(), pkt);
1374 void Server::Send(session_t peer_id, NetworkPacket *pkt)
1376 m_clients.send(peer_id,
1377 clientCommandFactoryTable[pkt->getCommand()].channel,
1379 clientCommandFactoryTable[pkt->getCommand()].reliable);
1382 void Server::SendMovement(session_t peer_id)
1384 std::ostringstream os(std::ios_base::binary);
1386 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1388 pkt << g_settings->getFloat("movement_acceleration_default");
1389 pkt << g_settings->getFloat("movement_acceleration_air");
1390 pkt << g_settings->getFloat("movement_acceleration_fast");
1391 pkt << g_settings->getFloat("movement_speed_walk");
1392 pkt << g_settings->getFloat("movement_speed_crouch");
1393 pkt << g_settings->getFloat("movement_speed_fast");
1394 pkt << g_settings->getFloat("movement_speed_climb");
1395 pkt << g_settings->getFloat("movement_speed_jump");
1396 pkt << g_settings->getFloat("movement_liquid_fluidity");
1397 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1398 pkt << g_settings->getFloat("movement_liquid_sink");
1399 pkt << g_settings->getFloat("movement_gravity");
1404 void Server::SendPlayerHPOrDie(PlayerSAO *playersao, const PlayerHPChangeReason &reason)
1406 if (playersao->isImmortal())
1409 session_t peer_id = playersao->getPeerID();
1410 bool is_alive = playersao->getHP() > 0;
1413 SendPlayerHP(peer_id);
1415 DiePlayer(peer_id, reason);
1418 void Server::SendHP(session_t peer_id, u16 hp)
1420 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1425 void Server::SendBreath(session_t peer_id, u16 breath)
1427 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1428 pkt << (u16) breath;
1432 void Server::SendAccessDenied(session_t peer_id, AccessDeniedCode reason,
1433 const std::string &custom_reason, bool reconnect)
1435 assert(reason < SERVER_ACCESSDENIED_MAX);
1437 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1439 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
1440 pkt << custom_reason;
1441 else if (reason == SERVER_ACCESSDENIED_SHUTDOWN ||
1442 reason == SERVER_ACCESSDENIED_CRASH)
1443 pkt << custom_reason << (u8)reconnect;
1447 void Server::SendAccessDenied_Legacy(session_t peer_id,const std::wstring &reason)
1449 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1454 void Server::SendDeathscreen(session_t peer_id, bool set_camera_point_target,
1455 v3f camera_point_target)
1457 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1458 pkt << set_camera_point_target << camera_point_target;
1462 void Server::SendItemDef(session_t peer_id,
1463 IItemDefManager *itemdef, u16 protocol_version)
1465 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1469 u32 length of the next item
1470 zlib-compressed serialized ItemDefManager
1472 std::ostringstream tmp_os(std::ios::binary);
1473 itemdef->serialize(tmp_os, protocol_version);
1474 std::ostringstream tmp_os2(std::ios::binary);
1475 compressZlib(tmp_os.str(), tmp_os2);
1476 pkt.putLongString(tmp_os2.str());
1479 verbosestream << "Server: Sending item definitions to id(" << peer_id
1480 << "): size=" << pkt.getSize() << std::endl;
1485 void Server::SendNodeDef(session_t peer_id,
1486 const NodeDefManager *nodedef, u16 protocol_version)
1488 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1492 u32 length of the next item
1493 zlib-compressed serialized NodeDefManager
1495 std::ostringstream tmp_os(std::ios::binary);
1496 nodedef->serialize(tmp_os, protocol_version);
1497 std::ostringstream tmp_os2(std::ios::binary);
1498 compressZlib(tmp_os.str(), tmp_os2);
1500 pkt.putLongString(tmp_os2.str());
1503 verbosestream << "Server: Sending node definitions to id(" << peer_id
1504 << "): size=" << pkt.getSize() << std::endl;
1510 Non-static send methods
1513 void Server::SendInventory(PlayerSAO *sao, bool incremental)
1515 RemotePlayer *player = sao->getPlayer();
1517 // Do not send new format to old clients
1518 incremental &= player->protocol_version >= 38;
1520 UpdateCrafting(player);
1526 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, sao->getPeerID());
1528 std::ostringstream os(std::ios::binary);
1529 sao->getInventory()->serialize(os, incremental);
1530 sao->getInventory()->setModified(false);
1531 player->setModified(true);
1533 const std::string &s = os.str();
1534 pkt.putRawString(s.c_str(), s.size());
1538 void Server::SendChatMessage(session_t peer_id, const ChatMessage &message)
1540 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1542 u8 type = message.type;
1543 pkt << version << type << std::wstring(L"") << message.message << (u64)message.timestamp;
1545 if (peer_id != PEER_ID_INEXISTENT) {
1546 RemotePlayer *player = m_env->getPlayer(peer_id);
1552 m_clients.sendToAll(&pkt);
1556 void Server::SendShowFormspecMessage(session_t peer_id, const std::string &formspec,
1557 const std::string &formname)
1559 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0, peer_id);
1560 if (formspec.empty()){
1561 //the client should close the formspec
1562 //but make sure there wasn't another one open in meantime
1563 const auto it = m_formspec_state_data.find(peer_id);
1564 if (it != m_formspec_state_data.end() && it->second == formname) {
1565 m_formspec_state_data.erase(peer_id);
1567 pkt.putLongString("");
1569 m_formspec_state_data[peer_id] = formname;
1570 pkt.putLongString(formspec);
1577 // Spawns a particle on peer with peer_id
1578 void Server::SendSpawnParticle(session_t peer_id, u16 protocol_version,
1579 v3f pos, v3f velocity, v3f acceleration,
1580 float expirationtime, float size, bool collisiondetection,
1581 bool collision_removal, bool object_collision,
1582 bool vertical, const std::string &texture,
1583 const struct TileAnimationParams &animation, u8 glow)
1585 static thread_local const float radius =
1586 g_settings->getS16("max_block_send_distance") * MAP_BLOCKSIZE * BS;
1588 if (peer_id == PEER_ID_INEXISTENT) {
1589 std::vector<session_t> clients = m_clients.getClientIDs();
1591 for (const session_t client_id : clients) {
1592 RemotePlayer *player = m_env->getPlayer(client_id);
1596 PlayerSAO *sao = player->getPlayerSAO();
1600 // Do not send to distant clients
1601 if (sao->getBasePosition().getDistanceFrom(pos * BS) > radius)
1604 SendSpawnParticle(client_id, player->protocol_version,
1605 pos, velocity, acceleration,
1606 expirationtime, size, collisiondetection, collision_removal,
1607 object_collision, vertical, texture, animation, glow);
1612 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1614 pkt << pos << velocity << acceleration << expirationtime
1615 << size << collisiondetection;
1616 pkt.putLongString(texture);
1618 pkt << collision_removal;
1619 // This is horrible but required (why are there two ways to serialize pkts?)
1620 std::ostringstream os(std::ios_base::binary);
1621 animation.serialize(os, protocol_version);
1622 pkt.putRawString(os.str());
1624 pkt << object_collision;
1629 // Adds a ParticleSpawner on peer with peer_id
1630 void Server::SendAddParticleSpawner(session_t peer_id, u16 protocol_version,
1631 u16 amount, float spawntime, v3f minpos, v3f maxpos,
1632 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1633 float minsize, float maxsize, bool collisiondetection, bool collision_removal,
1634 bool object_collision, u16 attached_id, bool vertical, const std::string &texture, u32 id,
1635 const struct TileAnimationParams &animation, u8 glow)
1637 if (peer_id == PEER_ID_INEXISTENT) {
1638 // This sucks and should be replaced:
1639 std::vector<session_t> clients = m_clients.getClientIDs();
1640 for (const session_t client_id : clients) {
1641 RemotePlayer *player = m_env->getPlayer(client_id);
1644 SendAddParticleSpawner(client_id, player->protocol_version,
1645 amount, spawntime, minpos, maxpos,
1646 minvel, maxvel, minacc, maxacc, minexptime, maxexptime,
1647 minsize, maxsize, collisiondetection, collision_removal,
1648 object_collision, attached_id, vertical, texture, id,
1654 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1656 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1657 << minacc << maxacc << minexptime << maxexptime << minsize
1658 << maxsize << collisiondetection;
1660 pkt.putLongString(texture);
1662 pkt << id << vertical;
1663 pkt << collision_removal;
1665 // This is horrible but required
1666 std::ostringstream os(std::ios_base::binary);
1667 animation.serialize(os, protocol_version);
1668 pkt.putRawString(os.str());
1670 pkt << object_collision;
1675 void Server::SendDeleteParticleSpawner(session_t peer_id, u32 id)
1677 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER, 4, peer_id);
1679 // Ugly error in this packet
1682 if (peer_id != PEER_ID_INEXISTENT)
1685 m_clients.sendToAll(&pkt);
1689 void Server::SendHUDAdd(session_t peer_id, u32 id, HudElement *form)
1691 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1693 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1694 << form->text << form->number << form->item << form->dir
1695 << form->align << form->offset << form->world_pos << form->size
1701 void Server::SendHUDRemove(session_t peer_id, u32 id)
1703 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1708 void Server::SendHUDChange(session_t peer_id, u32 id, HudElementStat stat, void *value)
1710 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1711 pkt << id << (u8) stat;
1715 case HUD_STAT_SCALE:
1716 case HUD_STAT_ALIGN:
1717 case HUD_STAT_OFFSET:
1718 pkt << *(v2f *) value;
1722 pkt << *(std::string *) value;
1724 case HUD_STAT_WORLD_POS:
1725 pkt << *(v3f *) value;
1728 pkt << *(v2s32 *) value;
1730 case HUD_STAT_NUMBER:
1734 pkt << *(u32 *) value;
1741 void Server::SendHUDSetFlags(session_t peer_id, u32 flags, u32 mask)
1743 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1745 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1747 pkt << flags << mask;
1752 void Server::SendHUDSetParam(session_t peer_id, u16 param, const std::string &value)
1754 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1755 pkt << param << value;
1759 void Server::SendSetSky(session_t peer_id, const SkyboxParams ¶ms)
1761 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1763 // Handle prior clients here
1764 if (m_clients.getProtocolVersion(peer_id) < 39) {
1765 pkt << params.bgcolor << params.type << (u16) params.textures.size();
1767 for (const std::string& texture : params.textures)
1770 pkt << params.clouds;
1771 } else { // Handle current clients and future clients
1772 pkt << params.bgcolor << params.type
1773 << params.clouds << params.fog_sun_tint
1774 << params.fog_moon_tint << params.fog_tint_type;
1776 if (params.type == "skybox") {
1777 pkt << (u16) params.textures.size();
1778 for (const std::string &texture : params.textures)
1780 } else if (params.type == "regular") {
1781 pkt << params.sky_color.day_sky << params.sky_color.day_horizon
1782 << params.sky_color.dawn_sky << params.sky_color.dawn_horizon
1783 << params.sky_color.night_sky << params.sky_color.night_horizon
1784 << params.sky_color.indoors;
1791 void Server::SendSetSun(session_t peer_id, const SunParams ¶ms)
1793 NetworkPacket pkt(TOCLIENT_SET_SUN, 0, peer_id);
1794 pkt << params.visible << params.texture
1795 << params.tonemap << params.sunrise
1796 << params.sunrise_visible << params.scale;
1800 void Server::SendSetMoon(session_t peer_id, const MoonParams ¶ms)
1802 NetworkPacket pkt(TOCLIENT_SET_MOON, 0, peer_id);
1804 pkt << params.visible << params.texture
1805 << params.tonemap << params.scale;
1809 void Server::SendSetStars(session_t peer_id, const StarParams ¶ms)
1811 NetworkPacket pkt(TOCLIENT_SET_STARS, 0, peer_id);
1813 pkt << params.visible << params.count
1814 << params.starcolor << params.scale;
1819 void Server::SendCloudParams(session_t peer_id, const CloudParams ¶ms)
1821 NetworkPacket pkt(TOCLIENT_CLOUD_PARAMS, 0, peer_id);
1822 pkt << params.density << params.color_bright << params.color_ambient
1823 << params.height << params.thickness << params.speed;
1827 void Server::SendOverrideDayNightRatio(session_t peer_id, bool do_override,
1830 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1833 pkt << do_override << (u16) (ratio * 65535);
1838 void Server::SendTimeOfDay(session_t peer_id, u16 time, f32 time_speed)
1840 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1841 pkt << time << time_speed;
1843 if (peer_id == PEER_ID_INEXISTENT) {
1844 m_clients.sendToAll(&pkt);
1851 void Server::SendPlayerHP(session_t peer_id)
1853 PlayerSAO *playersao = getPlayerSAO(peer_id);
1856 SendHP(peer_id, playersao->getHP());
1857 m_script->player_event(playersao,"health_changed");
1859 // Send to other clients
1860 playersao->sendPunchCommand();
1863 void Server::SendPlayerBreath(PlayerSAO *sao)
1867 m_script->player_event(sao, "breath_changed");
1868 SendBreath(sao->getPeerID(), sao->getBreath());
1871 void Server::SendMovePlayer(session_t peer_id)
1873 RemotePlayer *player = m_env->getPlayer(peer_id);
1875 PlayerSAO *sao = player->getPlayerSAO();
1878 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1879 pkt << sao->getBasePosition() << sao->getLookPitch() << sao->getRotation().Y;
1882 v3f pos = sao->getBasePosition();
1883 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1884 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1885 << " pitch=" << sao->getLookPitch()
1886 << " yaw=" << sao->getRotation().Y
1893 void Server::SendPlayerFov(session_t peer_id)
1895 NetworkPacket pkt(TOCLIENT_FOV, 4 + 1 + 4, peer_id);
1897 PlayerFovSpec fov_spec = m_env->getPlayer(peer_id)->getFov();
1898 pkt << fov_spec.fov << fov_spec.is_multiplier << fov_spec.transition_time;
1903 void Server::SendLocalPlayerAnimations(session_t peer_id, v2s32 animation_frames[4],
1904 f32 animation_speed)
1906 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1909 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1910 << animation_frames[3] << animation_speed;
1915 void Server::SendEyeOffset(session_t peer_id, v3f first, v3f third)
1917 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1918 pkt << first << third;
1922 void Server::SendPlayerPrivileges(session_t peer_id)
1924 RemotePlayer *player = m_env->getPlayer(peer_id);
1926 if(player->getPeerId() == PEER_ID_INEXISTENT)
1929 std::set<std::string> privs;
1930 m_script->getAuth(player->getName(), NULL, &privs);
1932 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1933 pkt << (u16) privs.size();
1935 for (const std::string &priv : privs) {
1942 void Server::SendPlayerInventoryFormspec(session_t peer_id)
1944 RemotePlayer *player = m_env->getPlayer(peer_id);
1946 if (player->getPeerId() == PEER_ID_INEXISTENT)
1949 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1950 pkt.putLongString(player->inventory_formspec);
1955 void Server::SendPlayerFormspecPrepend(session_t peer_id)
1957 RemotePlayer *player = m_env->getPlayer(peer_id);
1959 if (player->getPeerId() == PEER_ID_INEXISTENT)
1962 NetworkPacket pkt(TOCLIENT_FORMSPEC_PREPEND, 0, peer_id);
1963 pkt << player->formspec_prepend;
1967 void Server::SendActiveObjectRemoveAdd(RemoteClient *client, PlayerSAO *playersao)
1969 // Radius inside which objects are active
1970 static thread_local const s16 radius =
1971 g_settings->getS16("active_object_send_range_blocks") * MAP_BLOCKSIZE;
1973 // Radius inside which players are active
1974 static thread_local const bool is_transfer_limited =
1975 g_settings->exists("unlimited_player_transfer_distance") &&
1976 !g_settings->getBool("unlimited_player_transfer_distance");
1978 static thread_local const s16 player_transfer_dist =
1979 g_settings->getS16("player_transfer_distance") * MAP_BLOCKSIZE;
1981 s16 player_radius = player_transfer_dist == 0 && is_transfer_limited ?
1982 radius : player_transfer_dist;
1984 s16 my_radius = MYMIN(radius, playersao->getWantedRange() * MAP_BLOCKSIZE);
1988 std::queue<u16> removed_objects, added_objects;
1989 m_env->getRemovedActiveObjects(playersao, my_radius, player_radius,
1990 client->m_known_objects, removed_objects);
1991 m_env->getAddedActiveObjects(playersao, my_radius, player_radius,
1992 client->m_known_objects, added_objects);
1994 int removed_count = removed_objects.size();
1995 int added_count = added_objects.size();
1997 if (removed_objects.empty() && added_objects.empty())
2003 // Handle removed objects
2004 writeU16((u8*)buf, removed_objects.size());
2005 data.append(buf, 2);
2006 while (!removed_objects.empty()) {
2008 u16 id = removed_objects.front();
2009 ServerActiveObject* obj = m_env->getActiveObject(id);
2011 // Add to data buffer for sending
2012 writeU16((u8*)buf, id);
2013 data.append(buf, 2);
2015 // Remove from known objects
2016 client->m_known_objects.erase(id);
2018 if (obj && obj->m_known_by_count > 0)
2019 obj->m_known_by_count--;
2021 removed_objects.pop();
2024 // Handle added objects
2025 writeU16((u8*)buf, added_objects.size());
2026 data.append(buf, 2);
2027 while (!added_objects.empty()) {
2029 u16 id = added_objects.front();
2030 ServerActiveObject *obj = m_env->getActiveObject(id);
2031 added_objects.pop();
2034 warningstream << FUNCTION_NAME << ": NULL object id="
2035 << (int)id << std::endl;
2040 u8 type = obj->getSendType();
2042 // Add to data buffer for sending
2043 writeU16((u8*)buf, id);
2044 data.append(buf, 2);
2045 writeU8((u8*)buf, type);
2046 data.append(buf, 1);
2048 data.append(serializeLongString(
2049 obj->getClientInitializationData(client->net_proto_version)));
2051 // Add to known objects
2052 client->m_known_objects.insert(id);
2054 obj->m_known_by_count++;
2057 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, data.size(), client->peer_id);
2058 pkt.putRawString(data.c_str(), data.size());
2061 verbosestream << "Server::SendActiveObjectRemoveAdd: "
2062 << removed_count << " removed, " << added_count << " added, "
2063 << "packet size is " << pkt.getSize() << std::endl;
2066 void Server::SendActiveObjectMessages(session_t peer_id, const std::string &datas,
2069 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
2070 datas.size(), peer_id);
2072 pkt.putRawString(datas.c_str(), datas.size());
2074 m_clients.send(pkt.getPeerId(),
2075 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
2079 void Server::SendCSMRestrictionFlags(session_t peer_id)
2081 NetworkPacket pkt(TOCLIENT_CSM_RESTRICTION_FLAGS,
2082 sizeof(m_csm_restriction_flags) + sizeof(m_csm_restriction_noderange), peer_id);
2083 pkt << m_csm_restriction_flags << m_csm_restriction_noderange;
2087 void Server::SendPlayerSpeed(session_t peer_id, const v3f &added_vel)
2089 NetworkPacket pkt(TOCLIENT_PLAYER_SPEED, 0, peer_id);
2094 inline s32 Server::nextSoundId()
2096 s32 ret = m_next_sound_id;
2097 if (m_next_sound_id == INT32_MAX)
2098 m_next_sound_id = 0; // signed overflow is undefined
2104 s32 Server::playSound(const SimpleSoundSpec &spec,
2105 const ServerSoundParams ¶ms, bool ephemeral)
2107 // Find out initial position of sound
2108 bool pos_exists = false;
2109 v3f pos = params.getPos(m_env, &pos_exists);
2110 // If position is not found while it should be, cancel sound
2111 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
2114 // Filter destination clients
2115 std::vector<session_t> dst_clients;
2116 if (!params.to_player.empty()) {
2117 RemotePlayer *player = m_env->getPlayer(params.to_player.c_str());
2119 infostream<<"Server::playSound: Player \""<<params.to_player
2120 <<"\" not found"<<std::endl;
2123 if (player->getPeerId() == PEER_ID_INEXISTENT) {
2124 infostream<<"Server::playSound: Player \""<<params.to_player
2125 <<"\" not connected"<<std::endl;
2128 dst_clients.push_back(player->getPeerId());
2130 std::vector<session_t> clients = m_clients.getClientIDs();
2132 for (const session_t client_id : clients) {
2133 RemotePlayer *player = m_env->getPlayer(client_id);
2136 if (!params.exclude_player.empty() &&
2137 params.exclude_player == player->getName())
2140 PlayerSAO *sao = player->getPlayerSAO();
2145 if(sao->getBasePosition().getDistanceFrom(pos) >
2146 params.max_hear_distance)
2149 dst_clients.push_back(client_id);
2153 if(dst_clients.empty())
2158 ServerPlayingSound *psound = nullptr;
2160 id = -1; // old clients will still use this, so pick a reserved ID
2163 // The sound will exist as a reference in m_playing_sounds
2164 m_playing_sounds[id] = ServerPlayingSound();
2165 psound = &m_playing_sounds[id];
2166 psound->params = params;
2167 psound->spec = spec;
2170 float gain = params.gain * spec.gain;
2171 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2172 pkt << id << spec.name << gain
2173 << (u8) params.type << pos << params.object
2174 << params.loop << params.fade << params.pitch
2177 bool as_reliable = !ephemeral;
2179 for (const u16 dst_client : dst_clients) {
2181 psound->clients.insert(dst_client);
2182 m_clients.send(dst_client, 0, &pkt, as_reliable);
2186 void Server::stopSound(s32 handle)
2188 // Get sound reference
2189 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2190 m_playing_sounds.find(handle);
2191 if (i == m_playing_sounds.end())
2193 ServerPlayingSound &psound = i->second;
2195 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2198 for (std::unordered_set<session_t>::const_iterator si = psound.clients.begin();
2199 si != psound.clients.end(); ++si) {
2201 m_clients.send(*si, 0, &pkt, true);
2203 // Remove sound reference
2204 m_playing_sounds.erase(i);
2207 void Server::fadeSound(s32 handle, float step, float gain)
2209 // Get sound reference
2210 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2211 m_playing_sounds.find(handle);
2212 if (i == m_playing_sounds.end())
2215 ServerPlayingSound &psound = i->second;
2216 psound.params.gain = gain;
2218 NetworkPacket pkt(TOCLIENT_FADE_SOUND, 4);
2219 pkt << handle << step << gain;
2221 // Backwards compability
2222 bool play_sound = gain > 0;
2223 ServerPlayingSound compat_psound = psound;
2224 compat_psound.clients.clear();
2226 NetworkPacket compat_pkt(TOCLIENT_STOP_SOUND, 4);
2227 compat_pkt << handle;
2229 for (std::unordered_set<u16>::iterator it = psound.clients.begin();
2230 it != psound.clients.end();) {
2231 if (m_clients.getProtocolVersion(*it) >= 32) {
2233 m_clients.send(*it, 0, &pkt, true);
2236 compat_psound.clients.insert(*it);
2238 m_clients.send(*it, 0, &compat_pkt, true);
2239 psound.clients.erase(it++);
2243 // Remove sound reference
2244 if (!play_sound || psound.clients.empty())
2245 m_playing_sounds.erase(i);
2247 if (play_sound && !compat_psound.clients.empty()) {
2248 // Play new sound volume on older clients
2249 playSound(compat_psound.spec, compat_psound.params);
2253 void Server::sendRemoveNode(v3s16 p, std::unordered_set<u16> *far_players,
2256 float maxd = far_d_nodes * BS;
2257 v3f p_f = intToFloat(p, BS);
2258 v3s16 block_pos = getNodeBlockPos(p);
2260 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2263 std::vector<session_t> clients = m_clients.getClientIDs();
2266 for (session_t client_id : clients) {
2267 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
2271 RemotePlayer *player = m_env->getPlayer(client_id);
2272 PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr;
2274 // If player is far away, only set modified blocks not sent
2275 if (!client->isBlockSent(block_pos) || (sao &&
2276 sao->getBasePosition().getDistanceFrom(p_f) > maxd)) {
2278 far_players->emplace(client_id);
2280 client->SetBlockNotSent(block_pos);
2285 m_clients.send(client_id, 0, &pkt, true);
2291 void Server::sendAddNode(v3s16 p, MapNode n, std::unordered_set<u16> *far_players,
2292 float far_d_nodes, bool remove_metadata)
2294 float maxd = far_d_nodes * BS;
2295 v3f p_f = intToFloat(p, BS);
2296 v3s16 block_pos = getNodeBlockPos(p);
2298 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2299 pkt << p << n.param0 << n.param1 << n.param2
2300 << (u8) (remove_metadata ? 0 : 1);
2302 std::vector<session_t> clients = m_clients.getClientIDs();
2305 for (session_t client_id : clients) {
2306 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
2310 RemotePlayer *player = m_env->getPlayer(client_id);
2311 PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr;
2313 // If player is far away, only set modified blocks not sent
2314 if (!client->isBlockSent(block_pos) || (sao &&
2315 sao->getBasePosition().getDistanceFrom(p_f) > maxd)) {
2317 far_players->emplace(client_id);
2319 client->SetBlockNotSent(block_pos);
2324 m_clients.send(client_id, 0, &pkt, true);
2330 void Server::sendMetadataChanged(const std::list<v3s16> &meta_updates, float far_d_nodes)
2332 float maxd = far_d_nodes * BS;
2333 NodeMetadataList meta_updates_list(false);
2334 std::vector<session_t> clients = m_clients.getClientIDs();
2338 for (session_t i : clients) {
2339 RemoteClient *client = m_clients.lockedGetClientNoEx(i);
2343 ServerActiveObject *player = m_env->getActiveObject(i);
2344 v3f player_pos = player ? player->getBasePosition() : v3f();
2346 for (const v3s16 &pos : meta_updates) {
2347 NodeMetadata *meta = m_env->getMap().getNodeMetadata(pos);
2352 v3s16 block_pos = getNodeBlockPos(pos);
2353 if (!client->isBlockSent(block_pos) || (player &&
2354 player_pos.getDistanceFrom(intToFloat(pos, BS)) > maxd)) {
2355 client->SetBlockNotSent(block_pos);
2359 // Add the change to send list
2360 meta_updates_list.set(pos, meta);
2362 if (meta_updates_list.size() == 0)
2365 // Send the meta changes
2366 std::ostringstream os(std::ios::binary);
2367 meta_updates_list.serialize(os, client->net_proto_version, false, true);
2368 std::ostringstream oss(std::ios::binary);
2369 compressZlib(os.str(), oss);
2371 NetworkPacket pkt(TOCLIENT_NODEMETA_CHANGED, 0);
2372 pkt.putLongString(oss.str());
2373 m_clients.send(i, 0, &pkt, true);
2375 meta_updates_list.clear();
2381 void Server::SendBlockNoLock(session_t peer_id, MapBlock *block, u8 ver,
2382 u16 net_proto_version)
2385 Create a packet with the block in the right format
2388 std::ostringstream os(std::ios_base::binary);
2389 block->serialize(os, ver, false);
2390 block->serializeNetworkSpecific(os);
2391 std::string s = os.str();
2393 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2395 pkt << block->getPos();
2396 pkt.putRawString(s.c_str(), s.size());
2400 void Server::SendBlocks(float dtime)
2402 MutexAutoLock envlock(m_env_mutex);
2403 //TODO check if one big lock could be faster then multiple small ones
2405 std::vector<PrioritySortedBlockTransfer> queue;
2407 u32 total_sending = 0;
2410 ScopeProfiler sp2(g_profiler, "Server::SendBlocks(): Collect list");
2412 std::vector<session_t> clients = m_clients.getClientIDs();
2415 for (const session_t client_id : clients) {
2416 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id, CS_Active);
2421 total_sending += client->getSendingCount();
2422 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2428 // Lowest priority number comes first.
2429 // Lowest is most important.
2430 std::sort(queue.begin(), queue.end());
2434 // Maximal total count calculation
2435 // The per-client block sends is halved with the maximal online users
2436 u32 max_blocks_to_send = (m_env->getPlayerCount() + g_settings->getU32("max_users")) *
2437 g_settings->getU32("max_simultaneous_block_sends_per_client") / 4 + 1;
2439 ScopeProfiler sp(g_profiler, "Server::SendBlocks(): Send to clients");
2440 Map &map = m_env->getMap();
2442 for (const PrioritySortedBlockTransfer &block_to_send : queue) {
2443 if (total_sending >= max_blocks_to_send)
2446 MapBlock *block = map.getBlockNoCreateNoEx(block_to_send.pos);
2450 RemoteClient *client = m_clients.lockedGetClientNoEx(block_to_send.peer_id,
2455 SendBlockNoLock(block_to_send.peer_id, block, client->serialization_version,
2456 client->net_proto_version);
2458 client->SentBlock(block_to_send.pos);
2464 bool Server::SendBlock(session_t peer_id, const v3s16 &blockpos)
2466 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2471 RemoteClient *client = m_clients.lockedGetClientNoEx(peer_id, CS_Active);
2472 if (!client || client->isBlockSent(blockpos)) {
2476 SendBlockNoLock(peer_id, block, client->serialization_version,
2477 client->net_proto_version);
2483 void Server::fillMediaCache()
2485 infostream<<"Server: Calculating media file checksums"<<std::endl;
2487 // Collect all media file paths
2488 std::vector<std::string> paths;
2489 m_modmgr->getModsMediaPaths(paths);
2490 fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures");
2491 fs::GetRecursiveDirs(paths, porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2493 // Collect media file information from paths into cache
2494 for (const std::string &mediapath : paths) {
2495 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2496 for (const fs::DirListNode &dln : dirlist) {
2497 if (dln.dir) // Ignode dirs
2499 std::string filename = dln.name;
2500 // If name contains illegal characters, ignore the file
2501 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2502 infostream<<"Server: ignoring illegal file name: \""
2503 << filename << "\"" << std::endl;
2506 // If name is not in a supported format, ignore it
2507 const char *supported_ext[] = {
2508 ".png", ".jpg", ".bmp", ".tga",
2509 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2511 ".x", ".b3d", ".md2", ".obj",
2512 // Custom translation file format
2516 if (removeStringEnd(filename, supported_ext).empty()){
2517 infostream << "Server: ignoring unsupported file extension: \""
2518 << filename << "\"" << std::endl;
2521 // Ok, attempt to load the file and add to cache
2522 std::string filepath;
2523 filepath.append(mediapath).append(DIR_DELIM).append(filename);
2526 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2528 errorstream << "Server::fillMediaCache(): Could not open \""
2529 << filename << "\" for reading" << std::endl;
2532 std::ostringstream tmp_os(std::ios_base::binary);
2536 fis.read(buf, 1024);
2537 std::streamsize len = fis.gcount();
2538 tmp_os.write(buf, len);
2547 errorstream<<"Server::fillMediaCache(): Failed to read \""
2548 << filename << "\"" << std::endl;
2551 if(tmp_os.str().length() == 0) {
2552 errorstream << "Server::fillMediaCache(): Empty file \""
2553 << filepath << "\"" << std::endl;
2558 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2560 unsigned char *digest = sha1.getDigest();
2561 std::string sha1_base64 = base64_encode(digest, 20);
2562 std::string sha1_hex = hex_encode((char*)digest, 20);
2566 m_media[filename] = MediaInfo(filepath, sha1_base64);
2567 verbosestream << "Server: " << sha1_hex << " is " << filename
2573 void Server::sendMediaAnnouncement(session_t peer_id, const std::string &lang_code)
2576 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2579 std::string lang_suffix;
2580 lang_suffix.append(".").append(lang_code).append(".tr");
2581 for (const auto &i : m_media) {
2582 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2589 for (const auto &i : m_media) {
2590 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2592 pkt << i.first << i.second.sha1_digest;
2595 pkt << g_settings->get("remote_media");
2598 verbosestream << "Server: Announcing files to id(" << peer_id
2599 << "): count=" << media_sent << " size=" << pkt.getSize() << std::endl;
2602 struct SendableMedia
2608 SendableMedia(const std::string &name_="", const std::string &path_="",
2609 const std::string &data_=""):
2616 void Server::sendRequestedMedia(session_t peer_id,
2617 const std::vector<std::string> &tosend)
2619 verbosestream<<"Server::sendRequestedMedia(): "
2620 <<"Sending files to client"<<std::endl;
2624 // Put 5kB in one bunch (this is not accurate)
2625 u32 bytes_per_bunch = 5000;
2627 std::vector< std::vector<SendableMedia> > file_bunches;
2628 file_bunches.emplace_back();
2630 u32 file_size_bunch_total = 0;
2632 for (const std::string &name : tosend) {
2633 if (m_media.find(name) == m_media.end()) {
2634 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2635 <<"unknown file \""<<(name)<<"\""<<std::endl;
2639 //TODO get path + name
2640 std::string tpath = m_media[name].path;
2643 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2645 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2646 <<tpath<<"\" for reading"<<std::endl;
2649 std::ostringstream tmp_os(std::ios_base::binary);
2653 fis.read(buf, 1024);
2654 std::streamsize len = fis.gcount();
2655 tmp_os.write(buf, len);
2656 file_size_bunch_total += len;
2665 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2666 <<name<<"\""<<std::endl;
2669 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2670 <<tname<<"\""<<std::endl;*/
2672 file_bunches[file_bunches.size()-1].emplace_back(name, tpath, tmp_os.str());
2674 // Start next bunch if got enough data
2675 if(file_size_bunch_total >= bytes_per_bunch) {
2676 file_bunches.emplace_back();
2677 file_size_bunch_total = 0;
2682 /* Create and send packets */
2684 u16 num_bunches = file_bunches.size();
2685 for (u16 i = 0; i < num_bunches; i++) {
2688 u16 total number of texture bunches
2689 u16 index of this bunch
2690 u32 number of files in this bunch
2699 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2700 pkt << num_bunches << i << (u32) file_bunches[i].size();
2702 for (const SendableMedia &j : file_bunches[i]) {
2704 pkt.putLongString(j.data);
2707 verbosestream << "Server::sendRequestedMedia(): bunch "
2708 << i << "/" << num_bunches
2709 << " files=" << file_bunches[i].size()
2710 << " size=" << pkt.getSize() << std::endl;
2715 void Server::sendDetachedInventory(const std::string &name, session_t peer_id)
2717 const auto &inv_it = m_detached_inventories.find(name);
2718 const auto &player_it = m_detached_inventories_player.find(name);
2720 if (player_it == m_detached_inventories_player.end() ||
2721 player_it->second.empty()) {
2722 // OK. Send to everyone
2725 return; // Mods are not done loading
2727 RemotePlayer *p = m_env->getPlayer(player_it->second.c_str());
2729 return; // Player is offline
2731 if (peer_id != PEER_ID_INEXISTENT && peer_id != p->getPeerId())
2732 return; // Caller requested send to a different player, so don't send.
2734 peer_id = p->getPeerId();
2737 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2740 if (inv_it == m_detached_inventories.end()) {
2741 pkt << false; // Remove inventory
2743 pkt << true; // Update inventory
2745 // Serialization & NetworkPacket isn't a love story
2746 std::ostringstream os(std::ios_base::binary);
2747 inv_it->second->serialize(os);
2748 inv_it->second->setModified(false);
2750 const std::string &os_str = os.str();
2751 pkt << static_cast<u16>(os_str.size()); // HACK: to keep compatibility with 5.0.0 clients
2752 pkt.putRawString(os_str);
2755 if (peer_id == PEER_ID_INEXISTENT)
2756 m_clients.sendToAll(&pkt);
2761 void Server::sendDetachedInventories(session_t peer_id, bool incremental)
2763 for (const auto &detached_inventory : m_detached_inventories) {
2764 const std::string &name = detached_inventory.first;
2766 Inventory *inv = detached_inventory.second;
2767 if (!inv || !inv->checkModified())
2771 sendDetachedInventory(name, peer_id);
2779 void Server::DiePlayer(session_t peer_id, const PlayerHPChangeReason &reason)
2781 PlayerSAO *playersao = getPlayerSAO(peer_id);
2784 infostream << "Server::DiePlayer(): Player "
2785 << playersao->getPlayer()->getName()
2786 << " dies" << std::endl;
2788 playersao->setHP(0, reason);
2789 playersao->clearParentAttachment();
2791 // Trigger scripted stuff
2792 m_script->on_dieplayer(playersao, reason);
2794 SendPlayerHP(peer_id);
2795 SendDeathscreen(peer_id, false, v3f(0,0,0));
2798 void Server::RespawnPlayer(session_t peer_id)
2800 PlayerSAO *playersao = getPlayerSAO(peer_id);
2803 infostream << "Server::RespawnPlayer(): Player "
2804 << playersao->getPlayer()->getName()
2805 << " respawns" << std::endl;
2807 playersao->setHP(playersao->accessObjectProperties()->hp_max,
2808 PlayerHPChangeReason(PlayerHPChangeReason::RESPAWN));
2809 playersao->setBreath(playersao->accessObjectProperties()->breath_max);
2811 bool repositioned = m_script->on_respawnplayer(playersao);
2812 if (!repositioned) {
2813 // setPos will send the new position to client
2814 playersao->setPos(findSpawnPos());
2817 SendPlayerHP(peer_id);
2821 void Server::DenySudoAccess(session_t peer_id)
2823 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2828 void Server::DenyAccessVerCompliant(session_t peer_id, u16 proto_ver, AccessDeniedCode reason,
2829 const std::string &str_reason, bool reconnect)
2831 SendAccessDenied(peer_id, reason, str_reason, reconnect);
2833 m_clients.event(peer_id, CSE_SetDenied);
2834 DisconnectPeer(peer_id);
2838 void Server::DenyAccess(session_t peer_id, AccessDeniedCode reason,
2839 const std::string &custom_reason)
2841 SendAccessDenied(peer_id, reason, custom_reason);
2842 m_clients.event(peer_id, CSE_SetDenied);
2843 DisconnectPeer(peer_id);
2846 // 13/03/15: remove this function when protocol version 25 will become
2847 // the minimum version for MT users, maybe in 1 year
2848 void Server::DenyAccess_Legacy(session_t peer_id, const std::wstring &reason)
2850 SendAccessDenied_Legacy(peer_id, reason);
2851 m_clients.event(peer_id, CSE_SetDenied);
2852 DisconnectPeer(peer_id);
2855 void Server::DisconnectPeer(session_t peer_id)
2857 m_modchannel_mgr->leaveAllChannels(peer_id);
2858 m_con->DisconnectPeer(peer_id);
2861 void Server::acceptAuth(session_t peer_id, bool forSudoMode)
2864 RemoteClient* client = getClient(peer_id, CS_Invalid);
2866 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2868 // Right now, the auth mechs don't change between login and sudo mode.
2869 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2870 client->allowed_sudo_mechs = sudo_auth_mechs;
2872 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2873 << g_settings->getFloat("dedicated_server_step")
2877 m_clients.event(peer_id, CSE_AuthAccept);
2879 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2881 // We only support SRP right now
2882 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2884 resp_pkt << sudo_auth_mechs;
2886 m_clients.event(peer_id, CSE_SudoSuccess);
2890 void Server::DeleteClient(session_t peer_id, ClientDeletionReason reason)
2892 std::wstring message;
2895 Clear references to playing sounds
2897 for (std::unordered_map<s32, ServerPlayingSound>::iterator
2898 i = m_playing_sounds.begin(); i != m_playing_sounds.end();) {
2899 ServerPlayingSound &psound = i->second;
2900 psound.clients.erase(peer_id);
2901 if (psound.clients.empty())
2902 m_playing_sounds.erase(i++);
2907 // clear formspec info so the next client can't abuse the current state
2908 m_formspec_state_data.erase(peer_id);
2910 RemotePlayer *player = m_env->getPlayer(peer_id);
2912 /* Run scripts and remove from environment */
2914 PlayerSAO *playersao = player->getPlayerSAO();
2917 playersao->clearChildAttachments();
2918 playersao->clearParentAttachment();
2920 // inform connected clients
2921 const std::string &player_name = player->getName();
2922 NetworkPacket notice(TOCLIENT_UPDATE_PLAYER_LIST, 0, PEER_ID_INEXISTENT);
2923 // (u16) 1 + std::string represents a vector serialization representation
2924 notice << (u8) PLAYER_LIST_REMOVE << (u16) 1 << player_name;
2925 m_clients.sendToAll(¬ice);
2927 m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
2929 playersao->disconnected();
2936 if (player && reason != CDR_DENY) {
2937 std::ostringstream os(std::ios_base::binary);
2938 std::vector<session_t> clients = m_clients.getClientIDs();
2940 for (const session_t client_id : clients) {
2942 RemotePlayer *player = m_env->getPlayer(client_id);
2946 // Get name of player
2947 os << player->getName() << " ";
2950 std::string name = player->getName();
2951 actionstream << name << " "
2952 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2953 << " List of players: " << os.str() << std::endl;
2955 m_admin_chat->outgoing_queue.push_back(
2956 new ChatEventNick(CET_NICK_REMOVE, name));
2960 MutexAutoLock env_lock(m_env_mutex);
2961 m_clients.DeleteClient(peer_id);
2965 // Send leave chat message to all remaining clients
2966 if (!message.empty()) {
2967 SendChatMessage(PEER_ID_INEXISTENT,
2968 ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE, message));
2972 void Server::UpdateCrafting(RemotePlayer *player)
2974 InventoryList *clist = player->inventory.getList("craft");
2975 if (!clist || clist->getSize() == 0)
2978 if (!clist->checkModified())
2981 // Get a preview for crafting
2983 InventoryLocation loc;
2984 loc.setPlayer(player->getName());
2985 std::vector<ItemStack> output_replacements;
2986 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2987 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(),
2990 InventoryList *plist = player->inventory.getList("craftpreview");
2991 if (plist && plist->getSize() >= 1) {
2992 // Put the new preview in
2993 plist->changeItem(0, preview);
2997 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2999 if (evt->type == CET_NICK_ADD) {
3000 // The terminal informed us of its nick choice
3001 m_admin_nick = ((ChatEventNick *)evt)->nick;
3002 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
3003 errorstream << "You haven't set up an account." << std::endl
3004 << "Please log in using the client as '"
3005 << m_admin_nick << "' with a secure password." << std::endl
3006 << "Until then, you can't execute admin tasks via the console," << std::endl
3007 << "and everybody can claim the user account instead of you," << std::endl
3008 << "giving them full control over this server." << std::endl;
3011 assert(evt->type == CET_CHAT);
3012 handleAdminChat((ChatEventChat *)evt);
3016 std::wstring Server::handleChat(const std::string &name, const std::wstring &wname,
3017 std::wstring wmessage, bool check_shout_priv, RemotePlayer *player)
3019 // If something goes wrong, this player is to blame
3020 RollbackScopeActor rollback_scope(m_rollback,
3021 std::string("player:") + name);
3023 if (g_settings->getBool("strip_color_codes"))
3024 wmessage = unescape_enriched(wmessage);
3027 switch (player->canSendChatMessage()) {
3028 case RPLAYER_CHATRESULT_FLOODING: {
3029 std::wstringstream ws;
3030 ws << L"You cannot send more messages. You are limited to "
3031 << g_settings->getFloat("chat_message_limit_per_10sec")
3032 << L" messages per 10 seconds.";
3035 case RPLAYER_CHATRESULT_KICK:
3036 DenyAccess_Legacy(player->getPeerId(),
3037 L"You have been kicked due to message flooding.");
3039 case RPLAYER_CHATRESULT_OK:
3042 FATAL_ERROR("Unhandled chat filtering result found.");
3046 if (m_max_chatmessage_length > 0
3047 && wmessage.length() > m_max_chatmessage_length) {
3048 return L"Your message exceed the maximum chat message limit set on the server. "
3049 L"It was refused. Send a shorter message";
3052 auto message = trim(wide_to_utf8(wmessage));
3053 if (message.find_first_of("\n\r") != std::wstring::npos) {
3054 return L"New lines are not permitted in chat messages";
3057 // Run script hook, exit if script ate the chat message
3058 if (m_script->on_chat_message(name, message))
3063 // Whether to send line to the player that sent the message, or to all players
3064 bool broadcast_line = true;
3066 if (check_shout_priv && !checkPriv(name, "shout")) {
3067 line += L"-!- You don't have permission to shout.";
3068 broadcast_line = false;
3071 Workaround for fixing chat on Android. Lua doesn't handle
3072 the Cyrillic alphabet and some characters on older Android devices
3075 line += L"<" + wname + L"> " + wmessage;
3077 line += narrow_to_wide(m_script->formatChatMessage(name,
3078 wide_to_narrow(wmessage)));
3083 Tell calling method to send the message to sender
3085 if (!broadcast_line)
3089 Send the message to others
3091 actionstream << "CHAT: " << wide_to_narrow(unescape_enriched(line)) << std::endl;
3093 std::vector<session_t> clients = m_clients.getClientIDs();
3096 Send the message back to the inital sender
3097 if they are using protocol version >= 29
3100 session_t peer_id_to_avoid_sending =
3101 (player ? player->getPeerId() : PEER_ID_INEXISTENT);
3103 if (player && player->protocol_version >= 29)
3104 peer_id_to_avoid_sending = PEER_ID_INEXISTENT;
3106 for (u16 cid : clients) {
3107 if (cid != peer_id_to_avoid_sending)
3108 SendChatMessage(cid, ChatMessage(line));
3113 void Server::handleAdminChat(const ChatEventChat *evt)
3115 std::string name = evt->nick;
3116 std::wstring wname = utf8_to_wide(name);
3117 std::wstring wmessage = evt->evt_msg;
3119 std::wstring answer = handleChat(name, wname, wmessage);
3121 // If asked to send answer to sender
3122 if (!answer.empty()) {
3123 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
3127 RemoteClient *Server::getClient(session_t peer_id, ClientState state_min)
3129 RemoteClient *client = getClientNoEx(peer_id,state_min);
3131 throw ClientNotFoundException("Client not found");
3135 RemoteClient *Server::getClientNoEx(session_t peer_id, ClientState state_min)
3137 return m_clients.getClientNoEx(peer_id, state_min);
3140 std::string Server::getPlayerName(session_t peer_id)
3142 RemotePlayer *player = m_env->getPlayer(peer_id);
3144 return "[id="+itos(peer_id)+"]";
3145 return player->getName();
3148 PlayerSAO *Server::getPlayerSAO(session_t peer_id)
3150 RemotePlayer *player = m_env->getPlayer(peer_id);
3153 return player->getPlayerSAO();
3156 std::wstring Server::getStatusString()
3158 std::wostringstream os(std::ios_base::binary);
3159 os << L"# Server: ";
3161 os << L"version=" << narrow_to_wide(g_version_string);
3163 os << L", uptime=" << m_uptime_counter->get();
3165 os << L", max_lag=" << (m_env ? m_env->getMaxLagEstimate() : 0);
3167 // Information about clients
3169 os << L", clients={";
3171 std::vector<session_t> clients = m_clients.getClientIDs();
3172 for (session_t client_id : clients) {
3173 RemotePlayer *player = m_env->getPlayer(client_id);
3175 // Get name of player
3176 std::wstring name = L"unknown";
3178 name = narrow_to_wide(player->getName());
3180 // Add name to information string
3191 if (m_env && !((ServerMap*)(&m_env->getMap()))->isSavingEnabled())
3192 os << std::endl << L"# Server: " << " WARNING: Map saving is disabled.";
3194 if (!g_settings->get("motd").empty())
3195 os << std::endl << L"# Server: " << narrow_to_wide(g_settings->get("motd"));
3200 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
3202 std::set<std::string> privs;
3203 m_script->getAuth(name, NULL, &privs);
3207 bool Server::checkPriv(const std::string &name, const std::string &priv)
3209 std::set<std::string> privs = getPlayerEffectivePrivs(name);
3210 return (privs.count(priv) != 0);
3213 void Server::reportPrivsModified(const std::string &name)
3216 std::vector<session_t> clients = m_clients.getClientIDs();
3217 for (const session_t client_id : clients) {
3218 RemotePlayer *player = m_env->getPlayer(client_id);
3219 reportPrivsModified(player->getName());
3222 RemotePlayer *player = m_env->getPlayer(name.c_str());
3225 SendPlayerPrivileges(player->getPeerId());
3226 PlayerSAO *sao = player->getPlayerSAO();
3229 sao->updatePrivileges(
3230 getPlayerEffectivePrivs(name),
3235 void Server::reportInventoryFormspecModified(const std::string &name)
3237 RemotePlayer *player = m_env->getPlayer(name.c_str());
3240 SendPlayerInventoryFormspec(player->getPeerId());
3243 void Server::reportFormspecPrependModified(const std::string &name)
3245 RemotePlayer *player = m_env->getPlayer(name.c_str());
3248 SendPlayerFormspecPrepend(player->getPeerId());
3251 void Server::setIpBanned(const std::string &ip, const std::string &name)
3253 m_banmanager->add(ip, name);
3256 void Server::unsetIpBanned(const std::string &ip_or_name)
3258 m_banmanager->remove(ip_or_name);
3261 std::string Server::getBanDescription(const std::string &ip_or_name)
3263 return m_banmanager->getBanDescription(ip_or_name);
3266 void Server::notifyPlayer(const char *name, const std::wstring &msg)
3268 // m_env will be NULL if the server is initializing
3272 if (m_admin_nick == name && !m_admin_nick.empty()) {
3273 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
3276 RemotePlayer *player = m_env->getPlayer(name);
3281 if (player->getPeerId() == PEER_ID_INEXISTENT)
3284 SendChatMessage(player->getPeerId(), ChatMessage(msg));
3287 bool Server::showFormspec(const char *playername, const std::string &formspec,
3288 const std::string &formname)
3290 // m_env will be NULL if the server is initializing
3294 RemotePlayer *player = m_env->getPlayer(playername);
3298 SendShowFormspecMessage(player->getPeerId(), formspec, formname);
3302 u32 Server::hudAdd(RemotePlayer *player, HudElement *form)
3307 u32 id = player->addHud(form);
3309 SendHUDAdd(player->getPeerId(), id, form);
3314 bool Server::hudRemove(RemotePlayer *player, u32 id) {
3318 HudElement* todel = player->removeHud(id);
3325 SendHUDRemove(player->getPeerId(), id);
3329 bool Server::hudChange(RemotePlayer *player, u32 id, HudElementStat stat, void *data)
3334 SendHUDChange(player->getPeerId(), id, stat, data);
3338 bool Server::hudSetFlags(RemotePlayer *player, u32 flags, u32 mask)
3343 SendHUDSetFlags(player->getPeerId(), flags, mask);
3344 player->hud_flags &= ~mask;
3345 player->hud_flags |= flags;
3347 PlayerSAO* playersao = player->getPlayerSAO();
3352 m_script->player_event(playersao, "hud_changed");
3356 bool Server::hudSetHotbarItemcount(RemotePlayer *player, s32 hotbar_itemcount)
3361 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3364 player->setHotbarItemcount(hotbar_itemcount);
3365 std::ostringstream os(std::ios::binary);
3366 writeS32(os, hotbar_itemcount);
3367 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3371 void Server::hudSetHotbarImage(RemotePlayer *player, const std::string &name)
3376 player->setHotbarImage(name);
3377 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_IMAGE, name);
3380 void Server::hudSetHotbarSelectedImage(RemotePlayer *player, const std::string &name)
3385 player->setHotbarSelectedImage(name);
3386 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3389 Address Server::getPeerAddress(session_t peer_id)
3391 return m_con->GetPeerAddress(peer_id);
3394 void Server::setLocalPlayerAnimations(RemotePlayer *player,
3395 v2s32 animation_frames[4], f32 frame_speed)
3397 sanity_check(player);
3398 player->setLocalAnimations(animation_frames, frame_speed);
3399 SendLocalPlayerAnimations(player->getPeerId(), animation_frames, frame_speed);
3402 void Server::setPlayerEyeOffset(RemotePlayer *player, const v3f &first, const v3f &third)
3404 sanity_check(player);
3405 player->eye_offset_first = first;
3406 player->eye_offset_third = third;
3407 SendEyeOffset(player->getPeerId(), first, third);
3410 void Server::setSky(RemotePlayer *player, const SkyboxParams ¶ms)
3412 sanity_check(player);
3413 player->setSky(params);
3414 SendSetSky(player->getPeerId(), params);
3417 void Server::setSun(RemotePlayer *player, const SunParams ¶ms)
3419 sanity_check(player);
3420 player->setSun(params);
3421 SendSetSun(player->getPeerId(), params);
3424 void Server::setMoon(RemotePlayer *player, const MoonParams ¶ms)
3426 sanity_check(player);
3427 player->setMoon(params);
3428 SendSetMoon(player->getPeerId(), params);
3431 void Server::setStars(RemotePlayer *player, const StarParams ¶ms)
3433 sanity_check(player);
3434 player->setStars(params);
3435 SendSetStars(player->getPeerId(), params);
3438 void Server::setClouds(RemotePlayer *player, const CloudParams ¶ms)
3440 sanity_check(player);
3441 player->setCloudParams(params);
3442 SendCloudParams(player->getPeerId(), params);
3445 bool Server::overrideDayNightRatio(RemotePlayer *player, bool do_override,
3451 player->overrideDayNightRatio(do_override, ratio);
3452 SendOverrideDayNightRatio(player->getPeerId(), do_override, ratio);
3456 void Server::notifyPlayers(const std::wstring &msg)
3458 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(msg));
3461 void Server::spawnParticle(const std::string &playername, v3f pos,
3462 v3f velocity, v3f acceleration,
3463 float expirationtime, float size, bool
3464 collisiondetection, bool collision_removal, bool object_collision,
3465 bool vertical, const std::string &texture,
3466 const struct TileAnimationParams &animation, u8 glow)
3468 // m_env will be NULL if the server is initializing
3472 session_t peer_id = PEER_ID_INEXISTENT;
3474 if (!playername.empty()) {
3475 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3478 peer_id = player->getPeerId();
3479 proto_ver = player->protocol_version;
3482 SendSpawnParticle(peer_id, proto_ver, pos, velocity, acceleration,
3483 expirationtime, size, collisiondetection, collision_removal,
3484 object_collision, vertical, texture, animation, glow);
3487 u32 Server::addParticleSpawner(u16 amount, float spawntime,
3488 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
3489 float minexptime, float maxexptime, float minsize, float maxsize,
3490 bool collisiondetection, bool collision_removal, bool object_collision,
3491 ServerActiveObject *attached, bool vertical, const std::string &texture,
3492 const std::string &playername, const struct TileAnimationParams &animation,
3495 // m_env will be NULL if the server is initializing
3499 session_t peer_id = PEER_ID_INEXISTENT;
3501 if (!playername.empty()) {
3502 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3505 peer_id = player->getPeerId();
3506 proto_ver = player->protocol_version;
3509 u16 attached_id = attached ? attached->getId() : 0;
3512 if (attached_id == 0)
3513 id = m_env->addParticleSpawner(spawntime);
3515 id = m_env->addParticleSpawner(spawntime, attached_id);
3517 SendAddParticleSpawner(peer_id, proto_ver, amount, spawntime,
3518 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3519 minexptime, maxexptime, minsize, maxsize, collisiondetection,
3520 collision_removal, object_collision, attached_id, vertical,
3521 texture, id, animation, glow);
3526 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3528 // m_env will be NULL if the server is initializing
3530 throw ServerError("Can't delete particle spawners during initialisation!");
3532 session_t peer_id = PEER_ID_INEXISTENT;
3533 if (!playername.empty()) {
3534 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3537 peer_id = player->getPeerId();
3540 m_env->deleteParticleSpawner(id);
3541 SendDeleteParticleSpawner(peer_id, id);
3544 Inventory* Server::createDetachedInventory(const std::string &name, const std::string &player)
3546 if(m_detached_inventories.count(name) > 0){
3547 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3548 delete m_detached_inventories[name];
3550 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3552 Inventory *inv = new Inventory(m_itemdef);
3554 m_detached_inventories[name] = inv;
3555 if (!player.empty())
3556 m_detached_inventories_player[name] = player;
3558 //TODO find a better way to do this
3559 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3563 bool Server::removeDetachedInventory(const std::string &name)
3565 const auto &inv_it = m_detached_inventories.find(name);
3566 if (inv_it == m_detached_inventories.end())
3569 delete inv_it->second;
3570 m_detached_inventories.erase(inv_it);
3572 if (!m_env) // Mods are not done loading
3575 const auto &player_it = m_detached_inventories_player.find(name);
3576 if (player_it != m_detached_inventories_player.end()) {
3577 RemotePlayer *player = m_env->getPlayer(player_it->second.c_str());
3579 if (player && player->getPeerId() != PEER_ID_INEXISTENT)
3580 sendDetachedInventory(name, player->getPeerId());
3582 m_detached_inventories_player.erase(player_it);
3584 // Notify all players about the change
3585 sendDetachedInventory(name, PEER_ID_INEXISTENT);
3590 // actions: time-reversed list
3591 // Return value: success/failure
3592 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3593 std::list<std::string> *log)
3595 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3596 ServerMap *map = (ServerMap*)(&m_env->getMap());
3598 // Fail if no actions to handle
3599 if (actions.empty()) {
3601 log->push_back("Nothing to do.");
3608 for (const RollbackAction &action : actions) {
3610 bool success = action.applyRevert(map, this, this);
3613 std::ostringstream os;
3614 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3615 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3617 log->push_back(os.str());
3619 std::ostringstream os;
3620 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3621 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3623 log->push_back(os.str());
3627 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3628 <<" failed"<<std::endl;
3630 // Call it done if less than half failed
3631 return num_failed <= num_tried/2;
3634 // IGameDef interface
3636 IItemDefManager *Server::getItemDefManager()
3641 const NodeDefManager *Server::getNodeDefManager()
3646 ICraftDefManager *Server::getCraftDefManager()
3651 u16 Server::allocateUnknownNodeId(const std::string &name)
3653 return m_nodedef->allocateDummy(name);
3656 IWritableItemDefManager *Server::getWritableItemDefManager()
3661 NodeDefManager *Server::getWritableNodeDefManager()
3666 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3671 const std::vector<ModSpec> & Server::getMods() const
3673 return m_modmgr->getMods();
3676 const ModSpec *Server::getModSpec(const std::string &modname) const
3678 return m_modmgr->getModSpec(modname);
3681 void Server::getModNames(std::vector<std::string> &modlist)
3683 m_modmgr->getModNames(modlist);
3686 std::string Server::getBuiltinLuaPath()
3688 return porting::path_share + DIR_DELIM + "builtin";
3691 std::string Server::getModStoragePath() const
3693 return m_path_world + DIR_DELIM + "mod_storage";
3696 v3f Server::findSpawnPos()
3698 ServerMap &map = m_env->getServerMap();
3700 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf))
3701 return nodeposf * BS;
3703 bool is_good = false;
3704 // Limit spawn range to mapgen edges (determined by 'mapgen_limit')
3705 s32 range_max = map.getMapgenParams()->getSpawnRangeMax();
3707 // Try to find a good place a few times
3708 for (s32 i = 0; i < 4000 && !is_good; i++) {
3709 s32 range = MYMIN(1 + i, range_max);
3710 // We're going to try to throw the player to this position
3711 v2s16 nodepos2d = v2s16(
3712 -range + (myrand() % (range * 2)),
3713 -range + (myrand() % (range * 2)));
3714 // Get spawn level at point
3715 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3716 // Continue if MAX_MAP_GENERATION_LIMIT was returned by the mapgen to
3717 // signify an unsuitable spawn position, or if outside limits.
3718 if (spawn_level >= MAX_MAP_GENERATION_LIMIT ||
3719 spawn_level <= -MAX_MAP_GENERATION_LIMIT)
3722 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3723 // Consecutive empty nodes
3726 // Search upwards from 'spawn level' for 2 consecutive empty nodes, to
3727 // avoid obstructions in already-generated mapblocks.
3728 // In ungenerated mapblocks consisting of 'ignore' nodes, there will be
3729 // no obstructions, but mapgen decorations are generated after spawn so
3730 // the player may end up inside one.
3731 for (s32 i = 0; i < 8; i++) {
3732 v3s16 blockpos = getNodeBlockPos(nodepos);
3733 map.emergeBlock(blockpos, true);
3734 content_t c = map.getNode(nodepos).getContent();
3736 // In generated mapblocks allow spawn in all 'airlike' drawtype nodes.
3737 // In ungenerated mapblocks allow spawn in 'ignore' nodes.
3738 if (m_nodedef->get(c).drawtype == NDT_AIRLIKE || c == CONTENT_IGNORE) {
3740 if (air_count >= 2) {
3741 // Spawn in lower empty node
3743 nodeposf = intToFloat(nodepos, BS);
3744 // Don't spawn the player outside map boundaries
3745 if (objectpos_over_limit(nodeposf))
3746 // Exit this loop, positions above are probably over limit
3749 // Good position found, cause an exit from main loop
3763 // No suitable spawn point found, return fallback 0,0,0
3764 return v3f(0.0f, 0.0f, 0.0f);
3767 void Server::requestShutdown(const std::string &msg, bool reconnect, float delay)
3769 if (delay == 0.0f) {
3770 // No delay, shutdown immediately
3771 m_shutdown_state.is_requested = true;
3772 // only print to the infostream, a chat message saying
3773 // "Server Shutting Down" is sent when the server destructs.
3774 infostream << "*** Immediate Server shutdown requested." << std::endl;
3775 } else if (delay < 0.0f && m_shutdown_state.isTimerRunning()) {
3776 // Negative delay, cancel shutdown if requested
3777 m_shutdown_state.reset();
3778 std::wstringstream ws;
3780 ws << L"*** Server shutdown canceled.";
3782 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3783 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3784 // m_shutdown_* are already handled, skip.
3786 } else if (delay > 0.0f) {
3787 // Positive delay, tell the clients when the server will shut down
3788 std::wstringstream ws;
3790 ws << L"*** Server shutting down in "
3791 << duration_to_string(myround(delay)).c_str()
3794 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3795 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3798 m_shutdown_state.trigger(delay, msg, reconnect);
3801 PlayerSAO* Server::emergePlayer(const char *name, session_t peer_id, u16 proto_version)
3804 Try to get an existing player
3806 RemotePlayer *player = m_env->getPlayer(name);
3808 // If player is already connected, cancel
3809 if (player && player->getPeerId() != PEER_ID_INEXISTENT) {
3810 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3815 If player with the wanted peer_id already exists, cancel.
3817 if (m_env->getPlayer(peer_id)) {
3818 infostream<<"emergePlayer(): Player with wrong name but same"
3819 " peer_id already exists"<<std::endl;
3824 player = new RemotePlayer(name, idef());
3827 bool newplayer = false;
3830 PlayerSAO *playersao = m_env->loadPlayer(player, &newplayer, peer_id, isSingleplayer());
3832 // Complete init with server parts
3833 playersao->finalize(player, getPlayerEffectivePrivs(player->getName()));
3834 player->protocol_version = proto_version;
3838 m_script->on_newplayer(playersao);
3844 bool Server::registerModStorage(ModMetadata *storage)
3846 if (m_mod_storages.find(storage->getModName()) != m_mod_storages.end()) {
3847 errorstream << "Unable to register same mod storage twice. Storage name: "
3848 << storage->getModName() << std::endl;
3852 m_mod_storages[storage->getModName()] = storage;
3856 void Server::unregisterModStorage(const std::string &name)
3858 std::unordered_map<std::string, ModMetadata *>::const_iterator it = m_mod_storages.find(name);
3859 if (it != m_mod_storages.end()) {
3860 // Save unconditionaly on unregistration
3861 it->second->save(getModStoragePath());
3862 m_mod_storages.erase(name);
3866 void dedicated_server_loop(Server &server, bool &kill)
3868 verbosestream<<"dedicated_server_loop()"<<std::endl;
3870 IntervalLimiter m_profiler_interval;
3872 static thread_local const float steplen =
3873 g_settings->getFloat("dedicated_server_step");
3874 static thread_local const float profiler_print_interval =
3875 g_settings->getFloat("profiler_print_interval");
3878 * The dedicated server loop only does time-keeping (in Server::step) and
3879 * provides a way to main.cpp to kill the server externally (bool &kill).
3883 // This is kind of a hack but can be done like this
3884 // because server.step() is very light
3885 sleep_ms((int)(steplen*1000.0));
3886 server.step(steplen);
3888 if (server.isShutdownRequested() || kill)
3894 if (profiler_print_interval != 0) {
3895 if(m_profiler_interval.step(steplen, profiler_print_interval))
3897 infostream<<"Profiler:"<<std::endl;
3898 g_profiler->print(infostream);
3899 g_profiler->clear();
3904 infostream << "Dedicated server quitting" << std::endl;
3906 if (g_settings->getBool("server_announce"))
3907 ServerList::sendAnnounce(ServerList::AA_DELETE,
3908 server.m_bind_addr.getPort());
3917 bool Server::joinModChannel(const std::string &channel)
3919 return m_modchannel_mgr->joinChannel(channel, PEER_ID_SERVER) &&
3920 m_modchannel_mgr->setChannelState(channel, MODCHANNEL_STATE_READ_WRITE);
3923 bool Server::leaveModChannel(const std::string &channel)
3925 return m_modchannel_mgr->leaveChannel(channel, PEER_ID_SERVER);
3928 bool Server::sendModChannelMessage(const std::string &channel, const std::string &message)
3930 if (!m_modchannel_mgr->canWriteOnChannel(channel))
3933 broadcastModChannelMessage(channel, message, PEER_ID_SERVER);
3937 ModChannel* Server::getModChannel(const std::string &channel)
3939 return m_modchannel_mgr->getModChannel(channel);
3942 void Server::broadcastModChannelMessage(const std::string &channel,
3943 const std::string &message, session_t from_peer)
3945 const std::vector<u16> &peers = m_modchannel_mgr->getChannelPeers(channel);
3949 if (message.size() > STRING_MAX_LEN) {
3950 warningstream << "ModChannel message too long, dropping before sending "
3951 << " (" << message.size() << " > " << STRING_MAX_LEN << ", channel: "
3952 << channel << ")" << std::endl;
3957 if (from_peer != PEER_ID_SERVER) {
3958 sender = getPlayerName(from_peer);
3961 NetworkPacket resp_pkt(TOCLIENT_MODCHANNEL_MSG,
3962 2 + channel.size() + 2 + sender.size() + 2 + message.size());
3963 resp_pkt << channel << sender << message;
3964 for (session_t peer_id : peers) {
3966 if (peer_id == from_peer)
3969 Send(peer_id, &resp_pkt);
3972 if (from_peer != PEER_ID_SERVER) {
3973 m_script->on_modchannel_message(channel, sender, message);
3977 void Server::loadTranslationLanguage(const std::string &lang_code)
3979 if (g_server_translations->count(lang_code))
3980 return; // Already loaded
3982 std::string suffix = "." + lang_code + ".tr";
3983 for (const auto &i : m_media) {
3984 if (str_ends_with(i.first, suffix)) {
3985 std::ifstream t(i.second.path);
3986 std::string data((std::istreambuf_iterator<char>(t)),
3987 std::istreambuf_iterator<char>());
3989 (*g_server_translations)[lang_code].loadTranslation(data);