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 "serverobject.h"
38 #include "genericobject.h"
42 #include "scripting_server.h"
47 #include "mapgen/mapgen.h"
48 #include "mapgen/mg_biome.h"
49 #include "content_mapnode.h"
50 #include "content_nodemeta.h"
51 #include "content_sao.h"
52 #include "content/mods.h"
53 #include "modchannels.h"
54 #include "serverlist.h"
55 #include "util/string.h"
57 #include "util/serialize.h"
58 #include "util/thread.h"
59 #include "defaultsettings.h"
60 #include "server/mods.h"
61 #include "util/base64.h"
62 #include "util/sha1.h"
64 #include "database/database.h"
65 #include "chatmessage.h"
66 #include "chat_interface.h"
67 #include "remoteplayer.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
96 m_server->AsyncRunStep(true);
98 while (!stopRequested()) {
100 m_server->AsyncRunStep();
104 } catch (con::NoIncomingDataException &e) {
105 } catch (con::PeerNotFoundException &e) {
106 infostream<<"Server: PeerNotFoundException"<<std::endl;
107 } catch (ClientNotFoundException &e) {
108 } catch (con::ConnectionBindFailed &e) {
109 m_server->setAsyncFatalError(e.what());
110 } catch (LuaError &e) {
111 m_server->setAsyncFatalError(
112 "ServerThread::run Lua: " + std::string(e.what()));
116 END_DEBUG_EXCEPTION_HANDLER
121 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
123 if(pos_exists) *pos_exists = false;
128 if(pos_exists) *pos_exists = true;
133 ServerActiveObject *sao = env->getActiveObject(object);
136 if(pos_exists) *pos_exists = true;
137 return sao->getBasePosition(); }
142 void Server::ShutdownState::reset()
146 should_reconnect = false;
147 is_requested = false;
150 void Server::ShutdownState::trigger(float delay, const std::string &msg, bool reconnect)
154 should_reconnect = reconnect;
157 void Server::ShutdownState::tick(float dtime, Server *server)
163 static const float shutdown_msg_times[] =
165 1, 2, 3, 4, 5, 10, 20, 40, 60, 120, 180, 300, 600, 1200, 1800, 3600
168 // Automated messages
169 if (m_timer < shutdown_msg_times[ARRLEN(shutdown_msg_times) - 1]) {
170 for (float t : shutdown_msg_times) {
171 // If shutdown timer matches an automessage, shot it
172 if (m_timer > t && m_timer - dtime < t) {
173 std::wstring periodicMsg = getShutdownTimerMessage();
175 infostream << wide_to_utf8(periodicMsg).c_str() << std::endl;
176 server->SendChatMessage(PEER_ID_INEXISTENT, periodicMsg);
183 if (m_timer < 0.0f) {
189 std::wstring Server::ShutdownState::getShutdownTimerMessage() const
191 std::wstringstream ws;
192 ws << L"*** Server shutting down in "
193 << duration_to_string(myround(m_timer)).c_str() << ".";
202 const std::string &path_world,
203 const SubgameSpec &gamespec,
204 bool simple_singleplayer_mode,
209 m_bind_addr(bind_addr),
210 m_path_world(path_world),
211 m_gamespec(gamespec),
212 m_simple_singleplayer_mode(simple_singleplayer_mode),
213 m_dedicated(dedicated),
214 m_async_fatal_error(""),
215 m_con(std::make_shared<con::Connection>(PROTOCOL_ID,
218 m_bind_addr.isIPv6(),
220 m_itemdef(createItemDefManager()),
221 m_nodedef(createNodeDefManager()),
222 m_craftdef(createCraftDefManager()),
223 m_thread(new ServerThread(this)),
227 m_modchannel_mgr(new ModChannelMgr())
229 m_lag = g_settings->getFloat("dedicated_server_step");
231 if (m_path_world.empty())
232 throw ServerError("Supplied empty world path");
234 if (!gamespec.isValid())
235 throw ServerError("Supplied invalid gamespec");
241 // Send shutdown message
242 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE,
243 L"*** Server shutting down"));
246 MutexAutoLock envlock(m_env_mutex);
248 infostream << "Server: Saving players" << std::endl;
249 m_env->saveLoadedPlayers();
251 infostream << "Server: Kicking players" << std::endl;
252 std::string kick_msg;
253 bool reconnect = false;
254 if (isShutdownRequested()) {
255 reconnect = m_shutdown_state.should_reconnect;
256 kick_msg = m_shutdown_state.message;
258 if (kick_msg.empty()) {
259 kick_msg = g_settings->get("kick_msg_shutdown");
261 m_env->saveLoadedPlayers(true);
262 m_env->kickAllPlayers(SERVER_ACCESSDENIED_SHUTDOWN,
263 kick_msg, reconnect);
266 actionstream << "Server: Shutting down" << std::endl;
268 // Do this before stopping the server in case mapgen callbacks need to access
269 // server-controlled resources (like ModStorages). Also do them before
270 // shutdown callbacks since they may modify state that is finalized in a
273 m_emerge->stopThreads();
276 MutexAutoLock envlock(m_env_mutex);
278 // Execute script shutdown hooks
279 infostream << "Executing shutdown hooks" << std::endl;
280 m_script->on_shutdown();
282 infostream << "Server: Saving environment metadata" << std::endl;
292 // Delete things in the reverse order of creation
301 // Deinitialize scripting
302 infostream << "Server: Deinitializing scripting" << std::endl;
305 // Delete detached inventories
306 for (auto &detached_inventory : m_detached_inventories) {
307 delete detached_inventory.second;
310 while (!m_unsent_map_edit_queue.empty()) {
311 delete m_unsent_map_edit_queue.front();
312 m_unsent_map_edit_queue.pop();
318 infostream << "Server created for gameid \"" << m_gamespec.id << "\"";
319 if (m_simple_singleplayer_mode)
320 infostream << " in simple singleplayer mode" << std::endl;
322 infostream << std::endl;
323 infostream << "- world: " << m_path_world << std::endl;
324 infostream << "- game: " << m_gamespec.path << std::endl;
326 // Create world if it doesn't exist
327 if (!loadGameConfAndInitWorld(m_path_world, m_gamespec))
328 throw ServerError("Failed to initialize world");
330 // Create emerge manager
331 m_emerge = new EmergeManager(this);
333 // Create ban manager
334 std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
335 m_banmanager = new BanManager(ban_path);
337 m_modmgr = std::unique_ptr<ServerModManager>(new ServerModManager(m_path_world));
338 std::vector<ModSpec> unsatisfied_mods = m_modmgr->getUnsatisfiedMods();
339 // complain about mods with unsatisfied dependencies
340 if (!m_modmgr->isConsistent()) {
341 m_modmgr->printUnsatisfiedModsError();
345 MutexAutoLock envlock(m_env_mutex);
347 // Create the Map (loads map_meta.txt, overriding configured mapgen params)
348 ServerMap *servermap = new ServerMap(m_path_world, this, m_emerge);
350 // Initialize scripting
351 infostream << "Server: Initializing Lua" << std::endl;
353 m_script = new ServerScripting(this);
355 m_script->loadMod(getBuiltinLuaPath() + DIR_DELIM "init.lua", BUILTIN_MOD_NAME);
357 m_modmgr->loadMods(m_script);
359 // Read Textures and calculate sha1 sums
362 // Apply item aliases in the node definition manager
363 m_nodedef->updateAliases(m_itemdef);
365 // Apply texture overrides from texturepack/override.txt
366 std::vector<std::string> paths;
367 fs::GetRecursiveDirs(paths, g_settings->get("texture_path"));
368 fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures");
369 for (const std::string &path : paths)
370 m_nodedef->applyTextureOverrides(path + DIR_DELIM + "override.txt");
372 m_nodedef->setNodeRegistrationStatus(true);
374 // Perform pending node name resolutions
375 m_nodedef->runNodeResolveCallbacks();
377 // unmap node names for connected nodeboxes
378 m_nodedef->mapNodeboxConnections();
380 // init the recipe hashes to speed up crafting
381 m_craftdef->initHashes(this);
383 // Initialize Environment
384 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
386 m_clients.setEnv(m_env);
388 if (!servermap->settings_mgr.makeMapgenParams())
389 FATAL_ERROR("Couldn't create any mapgen type");
391 // Initialize mapgens
392 m_emerge->initMapgens(servermap->getMapgenParams());
394 if (g_settings->getBool("enable_rollback_recording")) {
395 // Create rollback manager
396 m_rollback = new RollbackManager(m_path_world, this);
399 // Give environment reference to scripting api
400 m_script->initializeEnvironment(m_env);
402 // Register us to receive map edit events
403 servermap->addEventReceiver(this);
407 m_liquid_transform_every = g_settings->getFloat("liquid_update");
408 m_max_chatmessage_length = g_settings->getU16("chat_message_max_size");
409 m_csm_restriction_flags = g_settings->getU64("csm_restriction_flags");
410 m_csm_restriction_noderange = g_settings->getU32("csm_restriction_noderange");
415 infostream << "Starting server on " << m_bind_addr.serializeString()
416 << "..." << std::endl;
418 // Stop thread if already running
421 // Initialize connection
422 m_con->SetTimeoutMs(30);
423 m_con->Serve(m_bind_addr);
428 // ASCII art for the win!
430 << " .__ __ __ " << std::endl
431 << " _____ |__| ____ _____/ |_ ____ _______/ |_ " << std::endl
432 << " / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\" << std::endl
433 << "| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | " << std::endl
434 << "|__|_| /__|___| /\\___ >__| \\___ >____ > |__| " << std::endl
435 << " \\/ \\/ \\/ \\/ \\/ " << std::endl;
436 actionstream << "World at [" << m_path_world << "]" << std::endl;
437 actionstream << "Server for gameid=\"" << m_gamespec.id
438 << "\" listening on " << m_bind_addr.serializeString() << ":"
439 << m_bind_addr.getPort() << "." << std::endl;
444 infostream<<"Server: Stopping and waiting threads"<<std::endl;
446 // Stop threads (set run=false first so both start stopping)
448 //m_emergethread.setRun(false);
450 //m_emergethread.stop();
452 infostream<<"Server: Threads stopped"<<std::endl;
455 void Server::step(float dtime)
461 MutexAutoLock lock(m_step_dtime_mutex);
462 m_step_dtime += dtime;
464 // Throw if fatal error occurred in thread
465 std::string async_err = m_async_fatal_error.get();
466 if (!async_err.empty()) {
467 if (!m_simple_singleplayer_mode) {
468 m_env->kickAllPlayers(SERVER_ACCESSDENIED_CRASH,
469 g_settings->get("kick_msg_crash"),
470 g_settings->getBool("ask_reconnect_on_crash"));
472 throw ServerError("AsyncErr: " + async_err);
476 void Server::AsyncRunStep(bool initial_step)
481 MutexAutoLock lock1(m_step_dtime_mutex);
482 dtime = m_step_dtime;
486 // Send blocks to clients
490 if((dtime < 0.001) && !initial_step)
493 ScopeProfiler sp(g_profiler, "Server::AsyncRunStep()", SPT_AVG);
496 MutexAutoLock lock1(m_step_dtime_mutex);
497 m_step_dtime -= dtime;
504 m_uptime.set(m_uptime.get() + dtime);
510 Update time of day and overall game time
512 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
515 Send to clients at constant intervals
518 m_time_of_day_send_timer -= dtime;
519 if(m_time_of_day_send_timer < 0.0) {
520 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
521 u16 time = m_env->getTimeOfDay();
522 float time_speed = g_settings->getFloat("time_speed");
523 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
527 MutexAutoLock lock(m_env_mutex);
528 // Figure out and report maximum lag to environment
529 float max_lag = m_env->getMaxLagEstimate();
530 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
532 if(dtime > 0.1 && dtime > max_lag * 2.0)
533 infostream<<"Server: Maximum lag peaked to "<<dtime
537 m_env->reportMaxLagEstimate(max_lag);
542 static const float map_timer_and_unload_dtime = 2.92;
543 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
545 MutexAutoLock lock(m_env_mutex);
546 // Run Map's timers and unload unused data
547 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
548 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
549 g_settings->getFloat("server_unload_unused_data_timeout"),
554 Listen to the admin chat, if available
557 if (!m_admin_chat->command_queue.empty()) {
558 MutexAutoLock lock(m_env_mutex);
559 while (!m_admin_chat->command_queue.empty()) {
560 ChatEvent *evt = m_admin_chat->command_queue.pop_frontNoEx();
561 handleChatInterfaceEvent(evt);
565 m_admin_chat->outgoing_queue.push_back(
566 new ChatEventTimeInfo(m_env->getGameTime(), m_env->getTimeOfDay()));
573 /* Transform liquids */
574 m_liquid_transform_timer += dtime;
575 if(m_liquid_transform_timer >= m_liquid_transform_every)
577 m_liquid_transform_timer -= m_liquid_transform_every;
579 MutexAutoLock lock(m_env_mutex);
581 ScopeProfiler sp(g_profiler, "Server: liquid transform");
583 std::map<v3s16, MapBlock*> modified_blocks;
584 m_env->getMap().transformLiquids(modified_blocks, m_env);
587 Set the modified blocks unsent for all the clients
589 if (!modified_blocks.empty()) {
590 SetBlocksNotSent(modified_blocks);
593 m_clients.step(dtime);
595 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
597 // send masterserver announce
599 float &counter = m_masterserver_timer;
600 if (!isSingleplayer() && (!counter || counter >= 300.0) &&
601 g_settings->getBool("server_announce")) {
602 ServerList::sendAnnounce(counter ? ServerList::AA_UPDATE :
603 ServerList::AA_START,
604 m_bind_addr.getPort(),
605 m_clients.getPlayerNames(),
607 m_env->getGameTime(),
610 Mapgen::getMapgenName(m_emerge->mgparams->mgtype),
620 Check added and deleted active objects
623 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
624 MutexAutoLock envlock(m_env_mutex);
627 const RemoteClientMap &clients = m_clients.getClientList();
628 ScopeProfiler sp(g_profiler, "Server: update objects within range");
630 for (const auto &client_it : clients) {
631 RemoteClient *client = client_it.second;
633 if (client->getState() < CS_DefinitionsSent)
636 // This can happen if the client times out somehow
637 if (!m_env->getPlayer(client->peer_id))
640 PlayerSAO *playersao = getPlayerSAO(client->peer_id);
644 SendActiveObjectRemoveAdd(client, playersao);
648 // Save mod storages if modified
649 m_mod_storage_save_timer -= dtime;
650 if (m_mod_storage_save_timer <= 0.0f) {
651 infostream << "Saving registered mod storages." << std::endl;
652 m_mod_storage_save_timer = g_settings->getFloat("server_map_save_interval");
653 for (std::unordered_map<std::string, ModMetadata *>::const_iterator
654 it = m_mod_storages.begin(); it != m_mod_storages.end(); ++it) {
655 if (it->second->isModified()) {
656 it->second->save(getModStoragePath());
666 MutexAutoLock envlock(m_env_mutex);
667 ScopeProfiler sp(g_profiler, "Server: send SAO messages");
670 // Value = data sent by object
671 std::unordered_map<u16, std::vector<ActiveObjectMessage>*> buffered_messages;
673 // Get active object messages from environment
675 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
679 std::vector<ActiveObjectMessage>* message_list = nullptr;
680 std::unordered_map<u16, std::vector<ActiveObjectMessage>* >::iterator n;
681 n = buffered_messages.find(aom.id);
682 if (n == buffered_messages.end()) {
683 message_list = new std::vector<ActiveObjectMessage>;
684 buffered_messages[aom.id] = message_list;
687 message_list = n->second;
689 message_list->push_back(aom);
693 const RemoteClientMap &clients = m_clients.getClientList();
694 // Route data to every client
695 for (const auto &client_it : clients) {
696 RemoteClient *client = client_it.second;
697 PlayerSAO *player = getPlayerSAO(client->peer_id);
698 std::string reliable_data;
699 std::string unreliable_data;
700 // Go through all objects in message buffer
701 for (const auto &buffered_message : buffered_messages) {
702 // If object does not exist or is not known by client, skip it
703 u16 id = buffered_message.first;
704 ServerActiveObject *sao = m_env->getActiveObject(id);
705 if (!sao || client->m_known_objects.find(id) == client->m_known_objects.end())
708 // Get message list of object
709 std::vector<ActiveObjectMessage>* list = buffered_message.second;
710 // Go through every message
711 for (const ActiveObjectMessage &aom : *list) {
712 // Send position updates to players who do not see the attachment
713 if (aom.datastring[0] == GENERIC_CMD_UPDATE_POSITION) {
714 if (sao->getId() == player->getId())
717 // Do not send position updates for attached players
718 // as long the parent is known to the client
719 ServerActiveObject *parent = sao->getParent();
720 if (parent && client->m_known_objects.find(parent->getId()) !=
721 client->m_known_objects.end())
724 // Compose the full new data with header
725 std::string new_data;
728 writeU16((u8*)&buf[0], aom.id);
729 new_data.append(buf, 2);
731 new_data += serializeString(aom.datastring);
732 // Add data to buffer
734 reliable_data += new_data;
736 unreliable_data += new_data;
740 reliable_data and unreliable_data are now ready.
743 if (!reliable_data.empty()) {
744 SendActiveObjectMessages(client->peer_id, reliable_data);
747 if (!unreliable_data.empty()) {
748 SendActiveObjectMessages(client->peer_id, unreliable_data, false);
753 // Clear buffered_messages
754 for (auto &buffered_message : buffered_messages) {
755 delete buffered_message.second;
760 Send queued-for-sending map edit events.
763 // We will be accessing the environment
764 MutexAutoLock lock(m_env_mutex);
766 // Don't send too many at a time
769 // Single change sending is disabled if queue size is not small
770 bool disable_single_change_sending = false;
771 if(m_unsent_map_edit_queue.size() >= 4)
772 disable_single_change_sending = true;
774 int event_count = m_unsent_map_edit_queue.size();
776 // We'll log the amount of each
779 std::list<v3s16> node_meta_updates;
781 while (!m_unsent_map_edit_queue.empty()) {
782 MapEditEvent* event = m_unsent_map_edit_queue.front();
783 m_unsent_map_edit_queue.pop();
785 // Players far away from the change are stored here.
786 // Instead of sending the changes, MapBlocks are set not sent
788 std::unordered_set<u16> far_players;
790 switch (event->type) {
793 prof.add("MEET_ADDNODE", 1);
794 sendAddNode(event->p, event->n, &far_players,
795 disable_single_change_sending ? 5 : 30,
796 event->type == MEET_ADDNODE);
798 case MEET_REMOVENODE:
799 prof.add("MEET_REMOVENODE", 1);
800 sendRemoveNode(event->p, &far_players,
801 disable_single_change_sending ? 5 : 30);
803 case MEET_BLOCK_NODE_METADATA_CHANGED: {
804 verbosestream << "Server: MEET_BLOCK_NODE_METADATA_CHANGED" << std::endl;
805 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
806 if (!event->is_private_change) {
807 // Don't send the change yet. Collect them to eliminate dupes.
808 node_meta_updates.remove(event->p);
809 node_meta_updates.push_back(event->p);
812 if (MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(
813 getNodeBlockPos(event->p))) {
814 block->raiseModified(MOD_STATE_WRITE_NEEDED,
815 MOD_REASON_REPORT_META_CHANGE);
820 infostream << "Server: MEET_OTHER" << std::endl;
821 prof.add("MEET_OTHER", 1);
822 for (const v3s16 &modified_block : event->modified_blocks) {
823 m_clients.markBlockposAsNotSent(modified_block);
827 prof.add("unknown", 1);
828 warningstream << "Server: Unknown MapEditEvent "
829 << ((u32)event->type) << std::endl;
834 Set blocks not sent to far players
836 if (!far_players.empty()) {
837 // Convert list format to that wanted by SetBlocksNotSent
838 std::map<v3s16, MapBlock*> modified_blocks2;
839 for (const v3s16 &modified_block : event->modified_blocks) {
840 modified_blocks2[modified_block] =
841 m_env->getMap().getBlockNoCreateNoEx(modified_block);
844 // Set blocks not sent
845 for (const u16 far_player : far_players) {
846 if (RemoteClient *client = getClient(far_player))
847 client->SetBlocksNotSent(modified_blocks2);
854 if (event_count >= 5) {
855 infostream << "Server: MapEditEvents:" << std::endl;
856 prof.print(infostream);
857 } else if (event_count != 0) {
858 verbosestream << "Server: MapEditEvents:" << std::endl;
859 prof.print(verbosestream);
862 // Send all metadata updates
863 if (node_meta_updates.size())
864 sendMetadataChanged(node_meta_updates);
868 Trigger emergethread (it somehow gets to a non-triggered but
869 bysy state sometimes)
872 float &counter = m_emergethread_trigger_timer;
874 if (counter >= 2.0) {
877 m_emerge->startThreads();
881 // Save map, players and auth stuff
883 float &counter = m_savemap_timer;
885 static thread_local const float save_interval =
886 g_settings->getFloat("server_map_save_interval");
887 if (counter >= save_interval) {
889 MutexAutoLock lock(m_env_mutex);
891 ScopeProfiler sp(g_profiler, "Server: map saving (sum)");
894 if (m_banmanager->isModified()) {
895 m_banmanager->save();
898 // Save changed parts of map
899 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
902 m_env->saveLoadedPlayers();
904 // Save environment metadata
909 m_shutdown_state.tick(dtime, this);
912 void Server::Receive()
914 session_t peer_id = 0;
917 m_con->Receive(&pkt);
918 peer_id = pkt.getPeerId();
920 } catch (const con::InvalidIncomingDataException &e) {
921 infostream << "Server::Receive(): InvalidIncomingDataException: what()="
922 << e.what() << std::endl;
923 } catch (const SerializationError &e) {
924 infostream << "Server::Receive(): SerializationError: what()="
925 << e.what() << std::endl;
926 } catch (const ClientStateError &e) {
927 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
928 DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
929 L"Try reconnecting or updating your client");
930 } catch (const con::PeerNotFoundException &e) {
935 PlayerSAO* Server::StageTwoClientInit(session_t peer_id)
937 std::string playername;
938 PlayerSAO *playersao = NULL;
941 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
943 playername = client->getName();
944 playersao = emergePlayer(playername.c_str(), peer_id, client->net_proto_version);
946 } catch (std::exception &e) {
952 RemotePlayer *player = m_env->getPlayer(playername.c_str());
955 if (!playersao || !player) {
956 if (player && player->getPeerId() != PEER_ID_INEXISTENT) {
957 actionstream << "Server: Failed to emerge player \"" << playername
958 << "\" (player allocated to an another client)" << std::endl;
959 DenyAccess_Legacy(peer_id, L"Another client is connected with this "
960 L"name. If your client closed unexpectedly, try again in "
963 errorstream << "Server: " << playername << ": Failed to emerge player"
965 DenyAccess_Legacy(peer_id, L"Could not allocate player.");
971 Send complete position information
973 SendMovePlayer(peer_id);
976 SendPlayerPrivileges(peer_id);
978 // Send inventory formspec
979 SendPlayerInventoryFormspec(peer_id);
982 SendInventory(playersao, false);
984 // Send HP or death screen
985 if (playersao->isDead())
986 SendDeathscreen(peer_id, false, v3f(0,0,0));
988 SendPlayerHPOrDie(playersao,
989 PlayerHPChangeReason(PlayerHPChangeReason::SET_HP));
992 SendPlayerBreath(playersao);
994 Address addr = getPeerAddress(player->getPeerId());
995 std::string ip_str = addr.serializeString();
996 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1001 const std::vector<std::string> &names = m_clients.getPlayerNames();
1003 actionstream << player->getName() << " joins game. List of players: ";
1005 for (const std::string &name : names) {
1006 actionstream << name << " ";
1009 actionstream << player->getName() <<std::endl;
1014 inline void Server::handleCommand(NetworkPacket *pkt)
1016 const ToServerCommandHandler &opHandle = toServerCommandTable[pkt->getCommand()];
1017 (this->*opHandle.handler)(pkt);
1020 void Server::ProcessData(NetworkPacket *pkt)
1022 // Environment is locked first.
1023 MutexAutoLock envlock(m_env_mutex);
1025 ScopeProfiler sp(g_profiler, "Server: Process network packet (sum)");
1026 u32 peer_id = pkt->getPeerId();
1029 Address address = getPeerAddress(peer_id);
1030 std::string addr_s = address.serializeString();
1032 if(m_banmanager->isIpBanned(addr_s)) {
1033 std::string ban_name = m_banmanager->getBanName(addr_s);
1034 infostream << "Server: A banned client tried to connect from "
1035 << addr_s << "; banned name was "
1036 << ban_name << std::endl;
1037 // This actually doesn't seem to transfer to the client
1038 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1039 + utf8_to_wide(ban_name));
1043 catch(con::PeerNotFoundException &e) {
1045 * no peer for this packet found
1046 * most common reason is peer timeout, e.g. peer didn't
1047 * respond for some time, your server was overloaded or
1050 infostream << "Server::ProcessData(): Canceling: peer "
1051 << peer_id << " not found" << std::endl;
1056 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1058 // Command must be handled into ToServerCommandHandler
1059 if (command >= TOSERVER_NUM_MSG_TYPES) {
1060 infostream << "Server: Ignoring unknown command "
1061 << command << std::endl;
1065 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1070 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1072 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1073 errorstream << "Server::ProcessData(): Cancelling: Peer"
1074 " serialization format invalid or not initialized."
1075 " Skipping incoming command=" << command << std::endl;
1079 /* Handle commands related to client startup */
1080 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1085 if (m_clients.getClientState(peer_id) < CS_Active) {
1086 if (command == TOSERVER_PLAYERPOS) return;
1088 errorstream << "Got packet command: " << command << " for peer id "
1089 << peer_id << " but client isn't active yet. Dropping packet "
1095 } catch (SendFailedException &e) {
1096 errorstream << "Server::ProcessData(): SendFailedException: "
1097 << "what=" << e.what()
1099 } catch (PacketError &e) {
1100 actionstream << "Server::ProcessData(): PacketError: "
1101 << "what=" << e.what()
1106 void Server::setTimeOfDay(u32 time)
1108 m_env->setTimeOfDay(time);
1109 m_time_of_day_send_timer = 0;
1112 void Server::onMapEditEvent(const MapEditEvent &event)
1114 if (m_ignore_map_edit_events_area.contains(event.getArea()))
1117 m_unsent_map_edit_queue.push(new MapEditEvent(event));
1120 Inventory* Server::getInventory(const InventoryLocation &loc)
1123 case InventoryLocation::UNDEFINED:
1124 case InventoryLocation::CURRENT_PLAYER:
1126 case InventoryLocation::PLAYER:
1128 RemotePlayer *player = m_env->getPlayer(loc.name.c_str());
1131 PlayerSAO *playersao = player->getPlayerSAO();
1134 return playersao->getInventory();
1137 case InventoryLocation::NODEMETA:
1139 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1142 return meta->getInventory();
1145 case InventoryLocation::DETACHED:
1147 if(m_detached_inventories.count(loc.name) == 0)
1149 return m_detached_inventories[loc.name];
1153 sanity_check(false); // abort
1159 void Server::setInventoryModified(const InventoryLocation &loc)
1162 case InventoryLocation::UNDEFINED:
1164 case InventoryLocation::PLAYER:
1167 RemotePlayer *player = m_env->getPlayer(loc.name.c_str());
1172 player->setModified(true);
1173 player->inventory.setModified(true);
1174 // Updates are sent in ServerEnvironment::step()
1177 case InventoryLocation::NODEMETA:
1180 event.type = MEET_BLOCK_NODE_METADATA_CHANGED;
1182 m_env->getMap().dispatchEvent(event);
1185 case InventoryLocation::DETACHED:
1187 // Updates are sent in ServerEnvironment::step()
1191 sanity_check(false); // abort
1196 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1198 std::vector<session_t> clients = m_clients.getClientIDs();
1200 // Set the modified blocks unsent for all the clients
1201 for (const session_t client_id : clients) {
1202 if (RemoteClient *client = m_clients.lockedGetClientNoEx(client_id))
1203 client->SetBlocksNotSent(block);
1208 void Server::peerAdded(con::Peer *peer)
1210 verbosestream<<"Server::peerAdded(): peer->id="
1211 <<peer->id<<std::endl;
1213 m_peer_change_queue.push(con::PeerChange(con::PEER_ADDED, peer->id, false));
1216 void Server::deletingPeer(con::Peer *peer, bool timeout)
1218 verbosestream<<"Server::deletingPeer(): peer->id="
1219 <<peer->id<<", timeout="<<timeout<<std::endl;
1221 m_clients.event(peer->id, CSE_Disconnect);
1222 m_peer_change_queue.push(con::PeerChange(con::PEER_REMOVED, peer->id, timeout));
1225 bool Server::getClientConInfo(session_t peer_id, con::rtt_stat_type type, float* retval)
1227 *retval = m_con->getPeerStat(peer_id,type);
1228 return *retval != -1;
1231 bool Server::getClientInfo(
1240 std::string* vers_string
1243 *state = m_clients.getClientState(peer_id);
1245 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1252 *uptime = client->uptime();
1253 *ser_vers = client->serialization_version;
1254 *prot_vers = client->net_proto_version;
1256 *major = client->getMajor();
1257 *minor = client->getMinor();
1258 *patch = client->getPatch();
1259 *vers_string = client->getPatch();
1266 void Server::handlePeerChanges()
1268 while(!m_peer_change_queue.empty())
1270 con::PeerChange c = m_peer_change_queue.front();
1271 m_peer_change_queue.pop();
1273 verbosestream<<"Server: Handling peer change: "
1274 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1279 case con::PEER_ADDED:
1280 m_clients.CreateClient(c.peer_id);
1283 case con::PEER_REMOVED:
1284 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1288 FATAL_ERROR("Invalid peer change event received!");
1294 void Server::printToConsoleOnly(const std::string &text)
1297 m_admin_chat->outgoing_queue.push_back(
1298 new ChatEventChat("", utf8_to_wide(text)));
1300 std::cout << text << std::endl;
1304 void Server::Send(NetworkPacket *pkt)
1306 Send(pkt->getPeerId(), pkt);
1309 void Server::Send(session_t peer_id, NetworkPacket *pkt)
1311 m_clients.send(peer_id,
1312 clientCommandFactoryTable[pkt->getCommand()].channel,
1314 clientCommandFactoryTable[pkt->getCommand()].reliable);
1317 void Server::SendMovement(session_t peer_id)
1319 std::ostringstream os(std::ios_base::binary);
1321 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1323 pkt << g_settings->getFloat("movement_acceleration_default");
1324 pkt << g_settings->getFloat("movement_acceleration_air");
1325 pkt << g_settings->getFloat("movement_acceleration_fast");
1326 pkt << g_settings->getFloat("movement_speed_walk");
1327 pkt << g_settings->getFloat("movement_speed_crouch");
1328 pkt << g_settings->getFloat("movement_speed_fast");
1329 pkt << g_settings->getFloat("movement_speed_climb");
1330 pkt << g_settings->getFloat("movement_speed_jump");
1331 pkt << g_settings->getFloat("movement_liquid_fluidity");
1332 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1333 pkt << g_settings->getFloat("movement_liquid_sink");
1334 pkt << g_settings->getFloat("movement_gravity");
1339 void Server::SendPlayerHPOrDie(PlayerSAO *playersao, const PlayerHPChangeReason &reason)
1341 if (playersao->isImmortal())
1344 session_t peer_id = playersao->getPeerID();
1345 bool is_alive = playersao->getHP() > 0;
1348 SendPlayerHP(peer_id);
1350 DiePlayer(peer_id, reason);
1353 void Server::SendHP(session_t peer_id, u16 hp)
1355 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1360 void Server::SendBreath(session_t peer_id, u16 breath)
1362 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1363 pkt << (u16) breath;
1367 void Server::SendAccessDenied(session_t peer_id, AccessDeniedCode reason,
1368 const std::string &custom_reason, bool reconnect)
1370 assert(reason < SERVER_ACCESSDENIED_MAX);
1372 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1374 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
1375 pkt << custom_reason;
1376 else if (reason == SERVER_ACCESSDENIED_SHUTDOWN ||
1377 reason == SERVER_ACCESSDENIED_CRASH)
1378 pkt << custom_reason << (u8)reconnect;
1382 void Server::SendAccessDenied_Legacy(session_t peer_id,const std::wstring &reason)
1384 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1389 void Server::SendDeathscreen(session_t peer_id, bool set_camera_point_target,
1390 v3f camera_point_target)
1392 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1393 pkt << set_camera_point_target << camera_point_target;
1397 void Server::SendItemDef(session_t peer_id,
1398 IItemDefManager *itemdef, u16 protocol_version)
1400 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1404 u32 length of the next item
1405 zlib-compressed serialized ItemDefManager
1407 std::ostringstream tmp_os(std::ios::binary);
1408 itemdef->serialize(tmp_os, protocol_version);
1409 std::ostringstream tmp_os2(std::ios::binary);
1410 compressZlib(tmp_os.str(), tmp_os2);
1411 pkt.putLongString(tmp_os2.str());
1414 verbosestream << "Server: Sending item definitions to id(" << peer_id
1415 << "): size=" << pkt.getSize() << std::endl;
1420 void Server::SendNodeDef(session_t peer_id,
1421 const NodeDefManager *nodedef, u16 protocol_version)
1423 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1427 u32 length of the next item
1428 zlib-compressed serialized NodeDefManager
1430 std::ostringstream tmp_os(std::ios::binary);
1431 nodedef->serialize(tmp_os, protocol_version);
1432 std::ostringstream tmp_os2(std::ios::binary);
1433 compressZlib(tmp_os.str(), tmp_os2);
1435 pkt.putLongString(tmp_os2.str());
1438 verbosestream << "Server: Sending node definitions to id(" << peer_id
1439 << "): size=" << pkt.getSize() << std::endl;
1445 Non-static send methods
1448 void Server::SendInventory(PlayerSAO *sao, bool incremental)
1450 RemotePlayer *player = sao->getPlayer();
1452 // Do not send new format to old clients
1453 incremental &= player->protocol_version >= 38;
1455 UpdateCrafting(player);
1461 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, sao->getPeerID());
1463 std::ostringstream os(std::ios::binary);
1464 sao->getInventory()->serialize(os, incremental);
1465 sao->getInventory()->setModified(false);
1466 player->setModified(true);
1468 const std::string &s = os.str();
1469 pkt.putRawString(s.c_str(), s.size());
1473 void Server::SendChatMessage(session_t peer_id, const ChatMessage &message)
1475 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1477 u8 type = message.type;
1478 pkt << version << type << std::wstring(L"") << message.message << (u64)message.timestamp;
1480 if (peer_id != PEER_ID_INEXISTENT) {
1481 RemotePlayer *player = m_env->getPlayer(peer_id);
1487 m_clients.sendToAll(&pkt);
1491 void Server::SendShowFormspecMessage(session_t peer_id, const std::string &formspec,
1492 const std::string &formname)
1494 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0, peer_id);
1495 if (formspec.empty()){
1496 //the client should close the formspec
1497 //but make sure there wasn't another one open in meantime
1498 const auto it = m_formspec_state_data.find(peer_id);
1499 if (it != m_formspec_state_data.end() && it->second == formname) {
1500 m_formspec_state_data.erase(peer_id);
1502 pkt.putLongString("");
1504 m_formspec_state_data[peer_id] = formname;
1505 pkt.putLongString(formspec);
1512 // Spawns a particle on peer with peer_id
1513 void Server::SendSpawnParticle(session_t peer_id, u16 protocol_version,
1514 v3f pos, v3f velocity, v3f acceleration,
1515 float expirationtime, float size, bool collisiondetection,
1516 bool collision_removal, bool object_collision,
1517 bool vertical, const std::string &texture,
1518 const struct TileAnimationParams &animation, u8 glow)
1520 static thread_local const float radius =
1521 g_settings->getS16("max_block_send_distance") * MAP_BLOCKSIZE * BS;
1523 if (peer_id == PEER_ID_INEXISTENT) {
1524 std::vector<session_t> clients = m_clients.getClientIDs();
1526 for (const session_t client_id : clients) {
1527 RemotePlayer *player = m_env->getPlayer(client_id);
1531 PlayerSAO *sao = player->getPlayerSAO();
1535 // Do not send to distant clients
1536 if (sao->getBasePosition().getDistanceFrom(pos * BS) > radius)
1539 SendSpawnParticle(client_id, player->protocol_version,
1540 pos, velocity, acceleration,
1541 expirationtime, size, collisiondetection, collision_removal,
1542 object_collision, vertical, texture, animation, glow);
1547 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1549 pkt << pos << velocity << acceleration << expirationtime
1550 << size << collisiondetection;
1551 pkt.putLongString(texture);
1553 pkt << collision_removal;
1554 // This is horrible but required (why are there two ways to serialize pkts?)
1555 std::ostringstream os(std::ios_base::binary);
1556 animation.serialize(os, protocol_version);
1557 pkt.putRawString(os.str());
1559 pkt << object_collision;
1564 // Adds a ParticleSpawner on peer with peer_id
1565 void Server::SendAddParticleSpawner(session_t peer_id, u16 protocol_version,
1566 u16 amount, float spawntime, v3f minpos, v3f maxpos,
1567 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1568 float minsize, float maxsize, bool collisiondetection, bool collision_removal,
1569 bool object_collision, u16 attached_id, bool vertical, const std::string &texture, u32 id,
1570 const struct TileAnimationParams &animation, u8 glow)
1572 if (peer_id == PEER_ID_INEXISTENT) {
1573 // This sucks and should be replaced:
1574 std::vector<session_t> clients = m_clients.getClientIDs();
1575 for (const session_t client_id : clients) {
1576 RemotePlayer *player = m_env->getPlayer(client_id);
1579 SendAddParticleSpawner(client_id, player->protocol_version,
1580 amount, spawntime, minpos, maxpos,
1581 minvel, maxvel, minacc, maxacc, minexptime, maxexptime,
1582 minsize, maxsize, collisiondetection, collision_removal,
1583 object_collision, attached_id, vertical, texture, id,
1589 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1591 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1592 << minacc << maxacc << minexptime << maxexptime << minsize
1593 << maxsize << collisiondetection;
1595 pkt.putLongString(texture);
1597 pkt << id << vertical;
1598 pkt << collision_removal;
1600 // This is horrible but required
1601 std::ostringstream os(std::ios_base::binary);
1602 animation.serialize(os, protocol_version);
1603 pkt.putRawString(os.str());
1605 pkt << object_collision;
1610 void Server::SendDeleteParticleSpawner(session_t peer_id, u32 id)
1612 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER, 4, peer_id);
1614 // Ugly error in this packet
1617 if (peer_id != PEER_ID_INEXISTENT)
1620 m_clients.sendToAll(&pkt);
1624 void Server::SendHUDAdd(session_t peer_id, u32 id, HudElement *form)
1626 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1628 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1629 << form->text << form->number << form->item << form->dir
1630 << form->align << form->offset << form->world_pos << form->size;
1635 void Server::SendHUDRemove(session_t peer_id, u32 id)
1637 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1642 void Server::SendHUDChange(session_t peer_id, u32 id, HudElementStat stat, void *value)
1644 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1645 pkt << id << (u8) stat;
1649 case HUD_STAT_SCALE:
1650 case HUD_STAT_ALIGN:
1651 case HUD_STAT_OFFSET:
1652 pkt << *(v2f *) value;
1656 pkt << *(std::string *) value;
1658 case HUD_STAT_WORLD_POS:
1659 pkt << *(v3f *) value;
1662 pkt << *(v2s32 *) value;
1664 case HUD_STAT_NUMBER:
1668 pkt << *(u32 *) value;
1675 void Server::SendHUDSetFlags(session_t peer_id, u32 flags, u32 mask)
1677 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1679 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1681 pkt << flags << mask;
1686 void Server::SendHUDSetParam(session_t peer_id, u16 param, const std::string &value)
1688 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1689 pkt << param << value;
1693 void Server::SendSetSky(session_t peer_id, const video::SColor &bgcolor,
1694 const std::string &type, const std::vector<std::string> ¶ms,
1697 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1698 pkt << bgcolor << type << (u16) params.size();
1700 for (const std::string ¶m : params)
1708 void Server::SendCloudParams(session_t peer_id, const CloudParams ¶ms)
1710 NetworkPacket pkt(TOCLIENT_CLOUD_PARAMS, 0, peer_id);
1711 pkt << params.density << params.color_bright << params.color_ambient
1712 << params.height << params.thickness << params.speed;
1716 void Server::SendOverrideDayNightRatio(session_t peer_id, bool do_override,
1719 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1722 pkt << do_override << (u16) (ratio * 65535);
1727 void Server::SendTimeOfDay(session_t peer_id, u16 time, f32 time_speed)
1729 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1730 pkt << time << time_speed;
1732 if (peer_id == PEER_ID_INEXISTENT) {
1733 m_clients.sendToAll(&pkt);
1740 void Server::SendPlayerHP(session_t peer_id)
1742 PlayerSAO *playersao = getPlayerSAO(peer_id);
1743 // In some rare case if the player is disconnected
1744 // while Lua call l_punch, for example, this can be NULL
1748 SendHP(peer_id, playersao->getHP());
1749 m_script->player_event(playersao,"health_changed");
1751 // Send to other clients
1752 std::string str = gob_cmd_punched(playersao->getHP());
1753 ActiveObjectMessage aom(playersao->getId(), true, str);
1754 playersao->m_messages_out.push(aom);
1757 void Server::SendPlayerBreath(PlayerSAO *sao)
1761 m_script->player_event(sao, "breath_changed");
1762 SendBreath(sao->getPeerID(), sao->getBreath());
1765 void Server::SendMovePlayer(session_t peer_id)
1767 RemotePlayer *player = m_env->getPlayer(peer_id);
1769 PlayerSAO *sao = player->getPlayerSAO();
1772 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1773 pkt << sao->getBasePosition() << sao->getLookPitch() << sao->getRotation().Y;
1776 v3f pos = sao->getBasePosition();
1777 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1778 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1779 << " pitch=" << sao->getLookPitch()
1780 << " yaw=" << sao->getRotation().Y
1787 void Server::SendPlayerFov(session_t peer_id)
1789 NetworkPacket pkt(TOCLIENT_FOV, 4 + 1, peer_id);
1791 PlayerFovSpec fov_spec = m_env->getPlayer(peer_id)->getFov();
1792 pkt << fov_spec.fov << fov_spec.is_multiplier;
1797 void Server::SendLocalPlayerAnimations(session_t peer_id, v2s32 animation_frames[4],
1798 f32 animation_speed)
1800 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1803 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1804 << animation_frames[3] << animation_speed;
1809 void Server::SendEyeOffset(session_t peer_id, v3f first, v3f third)
1811 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1812 pkt << first << third;
1816 void Server::SendPlayerPrivileges(session_t peer_id)
1818 RemotePlayer *player = m_env->getPlayer(peer_id);
1820 if(player->getPeerId() == PEER_ID_INEXISTENT)
1823 std::set<std::string> privs;
1824 m_script->getAuth(player->getName(), NULL, &privs);
1826 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1827 pkt << (u16) privs.size();
1829 for (const std::string &priv : privs) {
1836 void Server::SendPlayerInventoryFormspec(session_t peer_id)
1838 RemotePlayer *player = m_env->getPlayer(peer_id);
1840 if (player->getPeerId() == PEER_ID_INEXISTENT)
1843 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1844 pkt.putLongString(player->inventory_formspec);
1849 void Server::SendPlayerFormspecPrepend(session_t peer_id)
1851 RemotePlayer *player = m_env->getPlayer(peer_id);
1853 if (player->getPeerId() == PEER_ID_INEXISTENT)
1856 NetworkPacket pkt(TOCLIENT_FORMSPEC_PREPEND, 0, peer_id);
1857 pkt << player->formspec_prepend;
1861 void Server::SendActiveObjectRemoveAdd(RemoteClient *client, PlayerSAO *playersao)
1863 // Radius inside which objects are active
1864 static thread_local const s16 radius =
1865 g_settings->getS16("active_object_send_range_blocks") * MAP_BLOCKSIZE;
1867 // Radius inside which players are active
1868 static thread_local const bool is_transfer_limited =
1869 g_settings->exists("unlimited_player_transfer_distance") &&
1870 !g_settings->getBool("unlimited_player_transfer_distance");
1872 static thread_local const s16 player_transfer_dist =
1873 g_settings->getS16("player_transfer_distance") * MAP_BLOCKSIZE;
1875 s16 player_radius = player_transfer_dist == 0 && is_transfer_limited ?
1876 radius : player_transfer_dist;
1878 s16 my_radius = MYMIN(radius, playersao->getWantedRange() * MAP_BLOCKSIZE);
1882 std::queue<u16> removed_objects, added_objects;
1883 m_env->getRemovedActiveObjects(playersao, my_radius, player_radius,
1884 client->m_known_objects, removed_objects);
1885 m_env->getAddedActiveObjects(playersao, my_radius, player_radius,
1886 client->m_known_objects, added_objects);
1888 int removed_count = removed_objects.size();
1889 int added_count = added_objects.size();
1891 if (removed_objects.empty() && added_objects.empty())
1897 // Handle removed objects
1898 writeU16((u8*)buf, removed_objects.size());
1899 data.append(buf, 2);
1900 while (!removed_objects.empty()) {
1902 u16 id = removed_objects.front();
1903 ServerActiveObject* obj = m_env->getActiveObject(id);
1905 // Add to data buffer for sending
1906 writeU16((u8*)buf, id);
1907 data.append(buf, 2);
1909 // Remove from known objects
1910 client->m_known_objects.erase(id);
1912 if (obj && obj->m_known_by_count > 0)
1913 obj->m_known_by_count--;
1915 removed_objects.pop();
1918 // Handle added objects
1919 writeU16((u8*)buf, added_objects.size());
1920 data.append(buf, 2);
1921 while (!added_objects.empty()) {
1923 u16 id = added_objects.front();
1924 ServerActiveObject *obj = m_env->getActiveObject(id);
1925 added_objects.pop();
1928 warningstream << FUNCTION_NAME << ": NULL object id="
1929 << (int)id << std::endl;
1934 u8 type = obj->getSendType();
1936 // Add to data buffer for sending
1937 writeU16((u8*)buf, id);
1938 data.append(buf, 2);
1939 writeU8((u8*)buf, type);
1940 data.append(buf, 1);
1942 data.append(serializeLongString(
1943 obj->getClientInitializationData(client->net_proto_version)));
1945 // Add to known objects
1946 client->m_known_objects.insert(id);
1948 obj->m_known_by_count++;
1951 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, data.size(), client->peer_id);
1952 pkt.putRawString(data.c_str(), data.size());
1955 verbosestream << "Server::SendActiveObjectRemoveAdd: "
1956 << removed_count << " removed, " << added_count << " added, "
1957 << "packet size is " << pkt.getSize() << std::endl;
1960 void Server::SendActiveObjectMessages(session_t peer_id, const std::string &datas,
1963 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
1964 datas.size(), peer_id);
1966 pkt.putRawString(datas.c_str(), datas.size());
1968 m_clients.send(pkt.getPeerId(),
1969 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
1973 void Server::SendCSMRestrictionFlags(session_t peer_id)
1975 NetworkPacket pkt(TOCLIENT_CSM_RESTRICTION_FLAGS,
1976 sizeof(m_csm_restriction_flags) + sizeof(m_csm_restriction_noderange), peer_id);
1977 pkt << m_csm_restriction_flags << m_csm_restriction_noderange;
1981 void Server::SendPlayerSpeed(session_t peer_id, const v3f &added_vel)
1983 NetworkPacket pkt(TOCLIENT_PLAYER_SPEED, 0, peer_id);
1988 s32 Server::playSound(const SimpleSoundSpec &spec,
1989 const ServerSoundParams ¶ms)
1991 // Find out initial position of sound
1992 bool pos_exists = false;
1993 v3f pos = params.getPos(m_env, &pos_exists);
1994 // If position is not found while it should be, cancel sound
1995 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
1998 // Filter destination clients
1999 std::vector<session_t> dst_clients;
2000 if(!params.to_player.empty()) {
2001 RemotePlayer *player = m_env->getPlayer(params.to_player.c_str());
2003 infostream<<"Server::playSound: Player \""<<params.to_player
2004 <<"\" not found"<<std::endl;
2007 if (player->getPeerId() == PEER_ID_INEXISTENT) {
2008 infostream<<"Server::playSound: Player \""<<params.to_player
2009 <<"\" not connected"<<std::endl;
2012 dst_clients.push_back(player->getPeerId());
2014 std::vector<session_t> clients = m_clients.getClientIDs();
2016 for (const session_t client_id : clients) {
2017 RemotePlayer *player = m_env->getPlayer(client_id);
2021 PlayerSAO *sao = player->getPlayerSAO();
2026 if(sao->getBasePosition().getDistanceFrom(pos) >
2027 params.max_hear_distance)
2030 dst_clients.push_back(client_id);
2034 if(dst_clients.empty())
2038 s32 id = m_next_sound_id++;
2039 // The sound will exist as a reference in m_playing_sounds
2040 m_playing_sounds[id] = ServerPlayingSound();
2041 ServerPlayingSound &psound = m_playing_sounds[id];
2042 psound.params = params;
2045 float gain = params.gain * spec.gain;
2046 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2047 pkt << id << spec.name << gain
2048 << (u8) params.type << pos << params.object
2049 << params.loop << params.fade << params.pitch;
2051 // Backwards compability
2052 bool play_sound = gain > 0;
2054 for (const u16 dst_client : dst_clients) {
2055 if (play_sound || m_clients.getProtocolVersion(dst_client) >= 32) {
2056 psound.clients.insert(dst_client);
2057 m_clients.send(dst_client, 0, &pkt, true);
2062 void Server::stopSound(s32 handle)
2064 // Get sound reference
2065 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2066 m_playing_sounds.find(handle);
2067 if (i == m_playing_sounds.end())
2069 ServerPlayingSound &psound = i->second;
2071 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2074 for (std::unordered_set<session_t>::const_iterator si = psound.clients.begin();
2075 si != psound.clients.end(); ++si) {
2077 m_clients.send(*si, 0, &pkt, true);
2079 // Remove sound reference
2080 m_playing_sounds.erase(i);
2083 void Server::fadeSound(s32 handle, float step, float gain)
2085 // Get sound reference
2086 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2087 m_playing_sounds.find(handle);
2088 if (i == m_playing_sounds.end())
2091 ServerPlayingSound &psound = i->second;
2092 psound.params.gain = gain;
2094 NetworkPacket pkt(TOCLIENT_FADE_SOUND, 4);
2095 pkt << handle << step << gain;
2097 // Backwards compability
2098 bool play_sound = gain > 0;
2099 ServerPlayingSound compat_psound = psound;
2100 compat_psound.clients.clear();
2102 NetworkPacket compat_pkt(TOCLIENT_STOP_SOUND, 4);
2103 compat_pkt << handle;
2105 for (std::unordered_set<u16>::iterator it = psound.clients.begin();
2106 it != psound.clients.end();) {
2107 if (m_clients.getProtocolVersion(*it) >= 32) {
2109 m_clients.send(*it, 0, &pkt, true);
2112 compat_psound.clients.insert(*it);
2114 m_clients.send(*it, 0, &compat_pkt, true);
2115 psound.clients.erase(it++);
2119 // Remove sound reference
2120 if (!play_sound || psound.clients.empty())
2121 m_playing_sounds.erase(i);
2123 if (play_sound && !compat_psound.clients.empty()) {
2124 // Play new sound volume on older clients
2125 playSound(compat_psound.spec, compat_psound.params);
2129 void Server::sendRemoveNode(v3s16 p, std::unordered_set<u16> *far_players,
2132 float maxd = far_d_nodes * BS;
2133 v3f p_f = intToFloat(p, BS);
2134 v3s16 block_pos = getNodeBlockPos(p);
2136 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2139 std::vector<session_t> clients = m_clients.getClientIDs();
2142 for (session_t client_id : clients) {
2143 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
2147 RemotePlayer *player = m_env->getPlayer(client_id);
2148 PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr;
2150 // If player is far away, only set modified blocks not sent
2151 if (!client->isBlockSent(block_pos) || (sao &&
2152 sao->getBasePosition().getDistanceFrom(p_f) > maxd)) {
2154 far_players->emplace(client_id);
2156 client->SetBlockNotSent(block_pos);
2161 m_clients.send(client_id, 0, &pkt, true);
2167 void Server::sendAddNode(v3s16 p, MapNode n, std::unordered_set<u16> *far_players,
2168 float far_d_nodes, bool remove_metadata)
2170 float maxd = far_d_nodes * BS;
2171 v3f p_f = intToFloat(p, BS);
2172 v3s16 block_pos = getNodeBlockPos(p);
2174 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2175 pkt << p << n.param0 << n.param1 << n.param2
2176 << (u8) (remove_metadata ? 0 : 1);
2178 std::vector<session_t> clients = m_clients.getClientIDs();
2181 for (session_t client_id : clients) {
2182 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
2186 RemotePlayer *player = m_env->getPlayer(client_id);
2187 PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr;
2189 // If player is far away, only set modified blocks not sent
2190 if (!client->isBlockSent(block_pos) || (sao &&
2191 sao->getBasePosition().getDistanceFrom(p_f) > maxd)) {
2193 far_players->emplace(client_id);
2195 client->SetBlockNotSent(block_pos);
2200 m_clients.send(client_id, 0, &pkt, true);
2206 void Server::sendMetadataChanged(const std::list<v3s16> &meta_updates, float far_d_nodes)
2208 float maxd = far_d_nodes * BS;
2209 NodeMetadataList meta_updates_list(false);
2210 std::vector<session_t> clients = m_clients.getClientIDs();
2214 for (session_t i : clients) {
2215 RemoteClient *client = m_clients.lockedGetClientNoEx(i);
2219 ServerActiveObject *player = m_env->getActiveObject(i);
2220 v3f player_pos = player ? player->getBasePosition() : v3f();
2222 for (const v3s16 &pos : meta_updates) {
2223 NodeMetadata *meta = m_env->getMap().getNodeMetadata(pos);
2228 v3s16 block_pos = getNodeBlockPos(pos);
2229 if (!client->isBlockSent(block_pos) || (player &&
2230 player_pos.getDistanceFrom(intToFloat(pos, BS)) > maxd)) {
2231 client->SetBlockNotSent(block_pos);
2235 // Add the change to send list
2236 meta_updates_list.set(pos, meta);
2238 if (meta_updates_list.size() == 0)
2241 // Send the meta changes
2242 std::ostringstream os(std::ios::binary);
2243 meta_updates_list.serialize(os, client->net_proto_version, false, true);
2244 std::ostringstream oss(std::ios::binary);
2245 compressZlib(os.str(), oss);
2247 NetworkPacket pkt(TOCLIENT_NODEMETA_CHANGED, 0);
2248 pkt.putLongString(oss.str());
2249 m_clients.send(i, 0, &pkt, true);
2251 meta_updates_list.clear();
2257 void Server::SendBlockNoLock(session_t peer_id, MapBlock *block, u8 ver,
2258 u16 net_proto_version)
2261 Create a packet with the block in the right format
2264 std::ostringstream os(std::ios_base::binary);
2265 block->serialize(os, ver, false);
2266 block->serializeNetworkSpecific(os);
2267 std::string s = os.str();
2269 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2271 pkt << block->getPos();
2272 pkt.putRawString(s.c_str(), s.size());
2276 void Server::SendBlocks(float dtime)
2278 MutexAutoLock envlock(m_env_mutex);
2279 //TODO check if one big lock could be faster then multiple small ones
2281 std::vector<PrioritySortedBlockTransfer> queue;
2283 u32 total_sending = 0;
2286 ScopeProfiler sp2(g_profiler, "Server::SendBlocks(): Collect list");
2288 std::vector<session_t> clients = m_clients.getClientIDs();
2291 for (const session_t client_id : clients) {
2292 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id, CS_Active);
2297 total_sending += client->getSendingCount();
2298 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2304 // Lowest priority number comes first.
2305 // Lowest is most important.
2306 std::sort(queue.begin(), queue.end());
2310 // Maximal total count calculation
2311 // The per-client block sends is halved with the maximal online users
2312 u32 max_blocks_to_send = (m_env->getPlayerCount() + g_settings->getU32("max_users")) *
2313 g_settings->getU32("max_simultaneous_block_sends_per_client") / 4 + 1;
2315 ScopeProfiler sp(g_profiler, "Server::SendBlocks(): Send to clients");
2316 Map &map = m_env->getMap();
2318 for (const PrioritySortedBlockTransfer &block_to_send : queue) {
2319 if (total_sending >= max_blocks_to_send)
2322 MapBlock *block = map.getBlockNoCreateNoEx(block_to_send.pos);
2326 RemoteClient *client = m_clients.lockedGetClientNoEx(block_to_send.peer_id,
2331 SendBlockNoLock(block_to_send.peer_id, block, client->serialization_version,
2332 client->net_proto_version);
2334 client->SentBlock(block_to_send.pos);
2340 bool Server::SendBlock(session_t peer_id, const v3s16 &blockpos)
2342 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2347 RemoteClient *client = m_clients.lockedGetClientNoEx(peer_id, CS_Active);
2348 if (!client || client->isBlockSent(blockpos)) {
2352 SendBlockNoLock(peer_id, block, client->serialization_version,
2353 client->net_proto_version);
2359 void Server::fillMediaCache()
2361 infostream<<"Server: Calculating media file checksums"<<std::endl;
2363 // Collect all media file paths
2364 std::vector<std::string> paths;
2365 m_modmgr->getModsMediaPaths(paths);
2366 fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures");
2367 fs::GetRecursiveDirs(paths, porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2369 // Collect media file information from paths into cache
2370 for (const std::string &mediapath : paths) {
2371 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2372 for (const fs::DirListNode &dln : dirlist) {
2373 if (dln.dir) // Ignode dirs
2375 std::string filename = dln.name;
2376 // If name contains illegal characters, ignore the file
2377 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2378 infostream<<"Server: ignoring illegal file name: \""
2379 << filename << "\"" << std::endl;
2382 // If name is not in a supported format, ignore it
2383 const char *supported_ext[] = {
2384 ".png", ".jpg", ".bmp", ".tga",
2385 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2387 ".x", ".b3d", ".md2", ".obj",
2388 // Custom translation file format
2392 if (removeStringEnd(filename, supported_ext).empty()){
2393 infostream << "Server: ignoring unsupported file extension: \""
2394 << filename << "\"" << std::endl;
2397 // Ok, attempt to load the file and add to cache
2398 std::string filepath;
2399 filepath.append(mediapath).append(DIR_DELIM).append(filename);
2402 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2404 errorstream << "Server::fillMediaCache(): Could not open \""
2405 << filename << "\" for reading" << std::endl;
2408 std::ostringstream tmp_os(std::ios_base::binary);
2412 fis.read(buf, 1024);
2413 std::streamsize len = fis.gcount();
2414 tmp_os.write(buf, len);
2423 errorstream<<"Server::fillMediaCache(): Failed to read \""
2424 << filename << "\"" << std::endl;
2427 if(tmp_os.str().length() == 0) {
2428 errorstream << "Server::fillMediaCache(): Empty file \""
2429 << filepath << "\"" << std::endl;
2434 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2436 unsigned char *digest = sha1.getDigest();
2437 std::string sha1_base64 = base64_encode(digest, 20);
2438 std::string sha1_hex = hex_encode((char*)digest, 20);
2442 m_media[filename] = MediaInfo(filepath, sha1_base64);
2443 verbosestream << "Server: " << sha1_hex << " is " << filename
2449 void Server::sendMediaAnnouncement(session_t peer_id, const std::string &lang_code)
2451 verbosestream << "Server: Announcing files to id(" << peer_id << ")"
2455 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2458 std::string lang_suffix;
2459 lang_suffix.append(".").append(lang_code).append(".tr");
2460 for (const auto &i : m_media) {
2461 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2468 for (const auto &i : m_media) {
2469 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2471 pkt << i.first << i.second.sha1_digest;
2474 pkt << g_settings->get("remote_media");
2478 struct SendableMedia
2484 SendableMedia(const std::string &name_="", const std::string &path_="",
2485 const std::string &data_=""):
2492 void Server::sendRequestedMedia(session_t peer_id,
2493 const std::vector<std::string> &tosend)
2495 verbosestream<<"Server::sendRequestedMedia(): "
2496 <<"Sending files to client"<<std::endl;
2500 // Put 5kB in one bunch (this is not accurate)
2501 u32 bytes_per_bunch = 5000;
2503 std::vector< std::vector<SendableMedia> > file_bunches;
2504 file_bunches.emplace_back();
2506 u32 file_size_bunch_total = 0;
2508 for (const std::string &name : tosend) {
2509 if (m_media.find(name) == m_media.end()) {
2510 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2511 <<"unknown file \""<<(name)<<"\""<<std::endl;
2515 //TODO get path + name
2516 std::string tpath = m_media[name].path;
2519 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2521 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2522 <<tpath<<"\" for reading"<<std::endl;
2525 std::ostringstream tmp_os(std::ios_base::binary);
2529 fis.read(buf, 1024);
2530 std::streamsize len = fis.gcount();
2531 tmp_os.write(buf, len);
2532 file_size_bunch_total += len;
2541 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2542 <<name<<"\""<<std::endl;
2545 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2546 <<tname<<"\""<<std::endl;*/
2548 file_bunches[file_bunches.size()-1].emplace_back(name, tpath, tmp_os.str());
2550 // Start next bunch if got enough data
2551 if(file_size_bunch_total >= bytes_per_bunch) {
2552 file_bunches.emplace_back();
2553 file_size_bunch_total = 0;
2558 /* Create and send packets */
2560 u16 num_bunches = file_bunches.size();
2561 for (u16 i = 0; i < num_bunches; i++) {
2564 u16 total number of texture bunches
2565 u16 index of this bunch
2566 u32 number of files in this bunch
2575 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2576 pkt << num_bunches << i << (u32) file_bunches[i].size();
2578 for (const SendableMedia &j : file_bunches[i]) {
2580 pkt.putLongString(j.data);
2583 verbosestream << "Server::sendRequestedMedia(): bunch "
2584 << i << "/" << num_bunches
2585 << " files=" << file_bunches[i].size()
2586 << " size=" << pkt.getSize() << std::endl;
2591 void Server::sendDetachedInventory(const std::string &name, session_t peer_id)
2593 const auto &inv_it = m_detached_inventories.find(name);
2594 const auto &player_it = m_detached_inventories_player.find(name);
2596 if (player_it == m_detached_inventories_player.end() ||
2597 player_it->second.empty()) {
2598 // OK. Send to everyone
2601 return; // Mods are not done loading
2603 RemotePlayer *p = m_env->getPlayer(player_it->second.c_str());
2605 return; // Player is offline
2607 if (peer_id != PEER_ID_INEXISTENT && peer_id != p->getPeerId())
2608 return; // Caller requested send to a different player, so don't send.
2610 peer_id = p->getPeerId();
2613 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2616 if (inv_it == m_detached_inventories.end()) {
2617 pkt << false; // Remove inventory
2619 pkt << true; // Update inventory
2621 // Serialization & NetworkPacket isn't a love story
2622 std::ostringstream os(std::ios_base::binary);
2623 inv_it->second->serialize(os);
2624 inv_it->second->setModified(false);
2626 const std::string &os_str = os.str();
2627 pkt << static_cast<u16>(os_str.size()); // HACK: to keep compatibility with 5.0.0 clients
2628 pkt.putRawString(os_str);
2631 if (peer_id == PEER_ID_INEXISTENT)
2632 m_clients.sendToAll(&pkt);
2637 void Server::sendDetachedInventories(session_t peer_id, bool incremental)
2639 for (const auto &detached_inventory : m_detached_inventories) {
2640 const std::string &name = detached_inventory.first;
2642 Inventory *inv = detached_inventory.second;
2643 if (!inv || !inv->checkModified())
2647 sendDetachedInventory(name, peer_id);
2655 void Server::DiePlayer(session_t peer_id, const PlayerHPChangeReason &reason)
2657 PlayerSAO *playersao = getPlayerSAO(peer_id);
2658 // In some rare cases this can be NULL -- if the player is disconnected
2659 // when a Lua function modifies l_punch, for example
2663 infostream << "Server::DiePlayer(): Player "
2664 << playersao->getPlayer()->getName()
2665 << " dies" << std::endl;
2667 playersao->setHP(0, reason);
2668 playersao->clearParentAttachment();
2670 // Trigger scripted stuff
2671 m_script->on_dieplayer(playersao, reason);
2673 SendPlayerHP(peer_id);
2674 SendDeathscreen(peer_id, false, v3f(0,0,0));
2677 void Server::RespawnPlayer(session_t peer_id)
2679 PlayerSAO *playersao = getPlayerSAO(peer_id);
2682 infostream << "Server::RespawnPlayer(): Player "
2683 << playersao->getPlayer()->getName()
2684 << " respawns" << std::endl;
2686 playersao->setHP(playersao->accessObjectProperties()->hp_max,
2687 PlayerHPChangeReason(PlayerHPChangeReason::RESPAWN));
2688 playersao->setBreath(playersao->accessObjectProperties()->breath_max);
2690 bool repositioned = m_script->on_respawnplayer(playersao);
2691 if (!repositioned) {
2692 // setPos will send the new position to client
2693 playersao->setPos(findSpawnPos());
2696 SendPlayerHP(peer_id);
2700 void Server::DenySudoAccess(session_t peer_id)
2702 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2707 void Server::DenyAccessVerCompliant(session_t peer_id, u16 proto_ver, AccessDeniedCode reason,
2708 const std::string &str_reason, bool reconnect)
2710 SendAccessDenied(peer_id, reason, str_reason, reconnect);
2712 m_clients.event(peer_id, CSE_SetDenied);
2713 DisconnectPeer(peer_id);
2717 void Server::DenyAccess(session_t peer_id, AccessDeniedCode reason,
2718 const std::string &custom_reason)
2720 SendAccessDenied(peer_id, reason, custom_reason);
2721 m_clients.event(peer_id, CSE_SetDenied);
2722 DisconnectPeer(peer_id);
2725 // 13/03/15: remove this function when protocol version 25 will become
2726 // the minimum version for MT users, maybe in 1 year
2727 void Server::DenyAccess_Legacy(session_t peer_id, const std::wstring &reason)
2729 SendAccessDenied_Legacy(peer_id, reason);
2730 m_clients.event(peer_id, CSE_SetDenied);
2731 DisconnectPeer(peer_id);
2734 void Server::DisconnectPeer(session_t peer_id)
2736 m_modchannel_mgr->leaveAllChannels(peer_id);
2737 m_con->DisconnectPeer(peer_id);
2740 void Server::acceptAuth(session_t peer_id, bool forSudoMode)
2743 RemoteClient* client = getClient(peer_id, CS_Invalid);
2745 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2747 // Right now, the auth mechs don't change between login and sudo mode.
2748 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2749 client->allowed_sudo_mechs = sudo_auth_mechs;
2751 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2752 << g_settings->getFloat("dedicated_server_step")
2756 m_clients.event(peer_id, CSE_AuthAccept);
2758 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2760 // We only support SRP right now
2761 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2763 resp_pkt << sudo_auth_mechs;
2765 m_clients.event(peer_id, CSE_SudoSuccess);
2769 void Server::DeleteClient(session_t peer_id, ClientDeletionReason reason)
2771 std::wstring message;
2774 Clear references to playing sounds
2776 for (std::unordered_map<s32, ServerPlayingSound>::iterator
2777 i = m_playing_sounds.begin(); i != m_playing_sounds.end();) {
2778 ServerPlayingSound &psound = i->second;
2779 psound.clients.erase(peer_id);
2780 if (psound.clients.empty())
2781 m_playing_sounds.erase(i++);
2786 // clear formspec info so the next client can't abuse the current state
2787 m_formspec_state_data.erase(peer_id);
2789 RemotePlayer *player = m_env->getPlayer(peer_id);
2791 /* Run scripts and remove from environment */
2793 PlayerSAO *playersao = player->getPlayerSAO();
2796 playersao->clearChildAttachments();
2797 playersao->clearParentAttachment();
2799 // inform connected clients
2800 const std::string &player_name = player->getName();
2801 NetworkPacket notice(TOCLIENT_UPDATE_PLAYER_LIST, 0, PEER_ID_INEXISTENT);
2802 // (u16) 1 + std::string represents a vector serialization representation
2803 notice << (u8) PLAYER_LIST_REMOVE << (u16) 1 << player_name;
2804 m_clients.sendToAll(¬ice);
2806 m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
2808 playersao->disconnected();
2815 if (player && reason != CDR_DENY) {
2816 std::ostringstream os(std::ios_base::binary);
2817 std::vector<session_t> clients = m_clients.getClientIDs();
2819 for (const session_t client_id : clients) {
2821 RemotePlayer *player = m_env->getPlayer(client_id);
2825 // Get name of player
2826 os << player->getName() << " ";
2829 std::string name = player->getName();
2830 actionstream << name << " "
2831 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2832 << " List of players: " << os.str() << std::endl;
2834 m_admin_chat->outgoing_queue.push_back(
2835 new ChatEventNick(CET_NICK_REMOVE, name));
2839 MutexAutoLock env_lock(m_env_mutex);
2840 m_clients.DeleteClient(peer_id);
2844 // Send leave chat message to all remaining clients
2845 if (!message.empty()) {
2846 SendChatMessage(PEER_ID_INEXISTENT,
2847 ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE, message));
2851 void Server::UpdateCrafting(RemotePlayer *player)
2853 InventoryList *clist = player->inventory.getList("craft");
2854 if (!clist || clist->getSize() == 0)
2857 if (!clist->checkModified()) {
2858 verbosestream << "Skip Server::UpdateCrafting(): list unmodified" << std::endl;
2862 // Get a preview for crafting
2864 InventoryLocation loc;
2865 loc.setPlayer(player->getName());
2866 std::vector<ItemStack> output_replacements;
2867 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2868 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(),
2871 InventoryList *plist = player->inventory.getList("craftpreview");
2872 if (plist && plist->getSize() >= 1) {
2873 // Put the new preview in
2874 plist->changeItem(0, preview);
2878 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2880 if (evt->type == CET_NICK_ADD) {
2881 // The terminal informed us of its nick choice
2882 m_admin_nick = ((ChatEventNick *)evt)->nick;
2883 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2884 errorstream << "You haven't set up an account." << std::endl
2885 << "Please log in using the client as '"
2886 << m_admin_nick << "' with a secure password." << std::endl
2887 << "Until then, you can't execute admin tasks via the console," << std::endl
2888 << "and everybody can claim the user account instead of you," << std::endl
2889 << "giving them full control over this server." << std::endl;
2892 assert(evt->type == CET_CHAT);
2893 handleAdminChat((ChatEventChat *)evt);
2897 std::wstring Server::handleChat(const std::string &name, const std::wstring &wname,
2898 std::wstring wmessage, bool check_shout_priv, RemotePlayer *player)
2900 // If something goes wrong, this player is to blame
2901 RollbackScopeActor rollback_scope(m_rollback,
2902 std::string("player:") + name);
2904 if (g_settings->getBool("strip_color_codes"))
2905 wmessage = unescape_enriched(wmessage);
2908 switch (player->canSendChatMessage()) {
2909 case RPLAYER_CHATRESULT_FLOODING: {
2910 std::wstringstream ws;
2911 ws << L"You cannot send more messages. You are limited to "
2912 << g_settings->getFloat("chat_message_limit_per_10sec")
2913 << L" messages per 10 seconds.";
2916 case RPLAYER_CHATRESULT_KICK:
2917 DenyAccess_Legacy(player->getPeerId(),
2918 L"You have been kicked due to message flooding.");
2920 case RPLAYER_CHATRESULT_OK:
2923 FATAL_ERROR("Unhandled chat filtering result found.");
2927 if (m_max_chatmessage_length > 0
2928 && wmessage.length() > m_max_chatmessage_length) {
2929 return L"Your message exceed the maximum chat message limit set on the server. "
2930 L"It was refused. Send a shorter message";
2933 auto message = trim(wide_to_utf8(wmessage));
2934 if (message.find_first_of("\n\r") != std::wstring::npos) {
2935 return L"New lines are not permitted in chat messages";
2938 // Run script hook, exit if script ate the chat message
2939 if (m_script->on_chat_message(name, message))
2944 // Whether to send line to the player that sent the message, or to all players
2945 bool broadcast_line = true;
2947 if (check_shout_priv && !checkPriv(name, "shout")) {
2948 line += L"-!- You don't have permission to shout.";
2949 broadcast_line = false;
2951 line += narrow_to_wide(m_script->formatChatMessage(name,
2952 wide_to_narrow(wmessage)));
2956 Tell calling method to send the message to sender
2958 if (!broadcast_line)
2962 Send the message to others
2964 actionstream << "CHAT: " << wide_to_narrow(unescape_enriched(line)) << std::endl;
2966 std::vector<session_t> clients = m_clients.getClientIDs();
2969 Send the message back to the inital sender
2970 if they are using protocol version >= 29
2973 session_t peer_id_to_avoid_sending =
2974 (player ? player->getPeerId() : PEER_ID_INEXISTENT);
2976 if (player && player->protocol_version >= 29)
2977 peer_id_to_avoid_sending = PEER_ID_INEXISTENT;
2979 for (u16 cid : clients) {
2980 if (cid != peer_id_to_avoid_sending)
2981 SendChatMessage(cid, ChatMessage(line));
2986 void Server::handleAdminChat(const ChatEventChat *evt)
2988 std::string name = evt->nick;
2989 std::wstring wname = utf8_to_wide(name);
2990 std::wstring wmessage = evt->evt_msg;
2992 std::wstring answer = handleChat(name, wname, wmessage);
2994 // If asked to send answer to sender
2995 if (!answer.empty()) {
2996 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
3000 RemoteClient *Server::getClient(session_t peer_id, ClientState state_min)
3002 RemoteClient *client = getClientNoEx(peer_id,state_min);
3004 throw ClientNotFoundException("Client not found");
3008 RemoteClient *Server::getClientNoEx(session_t peer_id, ClientState state_min)
3010 return m_clients.getClientNoEx(peer_id, state_min);
3013 std::string Server::getPlayerName(session_t peer_id)
3015 RemotePlayer *player = m_env->getPlayer(peer_id);
3017 return "[id="+itos(peer_id)+"]";
3018 return player->getName();
3021 PlayerSAO *Server::getPlayerSAO(session_t peer_id)
3023 RemotePlayer *player = m_env->getPlayer(peer_id);
3026 return player->getPlayerSAO();
3029 std::wstring Server::getStatusString()
3031 std::wostringstream os(std::ios_base::binary);
3032 os << L"# Server: ";
3034 os << L"version=" << narrow_to_wide(g_version_string);
3036 os << L", uptime=" << m_uptime.get();
3038 os << L", max_lag=" << (m_env ? m_env->getMaxLagEstimate() : 0);
3040 // Information about clients
3042 os << L", clients={";
3044 std::vector<session_t> clients = m_clients.getClientIDs();
3045 for (session_t client_id : clients) {
3046 RemotePlayer *player = m_env->getPlayer(client_id);
3048 // Get name of player
3049 std::wstring name = L"unknown";
3051 name = narrow_to_wide(player->getName());
3053 // Add name to information string
3064 if (m_env && !((ServerMap*)(&m_env->getMap()))->isSavingEnabled())
3065 os << std::endl << L"# Server: " << " WARNING: Map saving is disabled.";
3067 if (!g_settings->get("motd").empty())
3068 os << std::endl << L"# Server: " << narrow_to_wide(g_settings->get("motd"));
3073 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
3075 std::set<std::string> privs;
3076 m_script->getAuth(name, NULL, &privs);
3080 bool Server::checkPriv(const std::string &name, const std::string &priv)
3082 std::set<std::string> privs = getPlayerEffectivePrivs(name);
3083 return (privs.count(priv) != 0);
3086 void Server::reportPrivsModified(const std::string &name)
3089 std::vector<session_t> clients = m_clients.getClientIDs();
3090 for (const session_t client_id : clients) {
3091 RemotePlayer *player = m_env->getPlayer(client_id);
3092 reportPrivsModified(player->getName());
3095 RemotePlayer *player = m_env->getPlayer(name.c_str());
3098 SendPlayerPrivileges(player->getPeerId());
3099 PlayerSAO *sao = player->getPlayerSAO();
3102 sao->updatePrivileges(
3103 getPlayerEffectivePrivs(name),
3108 void Server::reportInventoryFormspecModified(const std::string &name)
3110 RemotePlayer *player = m_env->getPlayer(name.c_str());
3113 SendPlayerInventoryFormspec(player->getPeerId());
3116 void Server::reportFormspecPrependModified(const std::string &name)
3118 RemotePlayer *player = m_env->getPlayer(name.c_str());
3121 SendPlayerFormspecPrepend(player->getPeerId());
3124 void Server::setIpBanned(const std::string &ip, const std::string &name)
3126 m_banmanager->add(ip, name);
3129 void Server::unsetIpBanned(const std::string &ip_or_name)
3131 m_banmanager->remove(ip_or_name);
3134 std::string Server::getBanDescription(const std::string &ip_or_name)
3136 return m_banmanager->getBanDescription(ip_or_name);
3139 void Server::notifyPlayer(const char *name, const std::wstring &msg)
3141 // m_env will be NULL if the server is initializing
3145 if (m_admin_nick == name && !m_admin_nick.empty()) {
3146 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
3149 RemotePlayer *player = m_env->getPlayer(name);
3154 if (player->getPeerId() == PEER_ID_INEXISTENT)
3157 SendChatMessage(player->getPeerId(), ChatMessage(msg));
3160 bool Server::showFormspec(const char *playername, const std::string &formspec,
3161 const std::string &formname)
3163 // m_env will be NULL if the server is initializing
3167 RemotePlayer *player = m_env->getPlayer(playername);
3171 SendShowFormspecMessage(player->getPeerId(), formspec, formname);
3175 u32 Server::hudAdd(RemotePlayer *player, HudElement *form)
3180 u32 id = player->addHud(form);
3182 SendHUDAdd(player->getPeerId(), id, form);
3187 bool Server::hudRemove(RemotePlayer *player, u32 id) {
3191 HudElement* todel = player->removeHud(id);
3198 SendHUDRemove(player->getPeerId(), id);
3202 bool Server::hudChange(RemotePlayer *player, u32 id, HudElementStat stat, void *data)
3207 SendHUDChange(player->getPeerId(), id, stat, data);
3211 bool Server::hudSetFlags(RemotePlayer *player, u32 flags, u32 mask)
3216 SendHUDSetFlags(player->getPeerId(), flags, mask);
3217 player->hud_flags &= ~mask;
3218 player->hud_flags |= flags;
3220 PlayerSAO* playersao = player->getPlayerSAO();
3225 m_script->player_event(playersao, "hud_changed");
3229 bool Server::hudSetHotbarItemcount(RemotePlayer *player, s32 hotbar_itemcount)
3234 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3237 player->setHotbarItemcount(hotbar_itemcount);
3238 std::ostringstream os(std::ios::binary);
3239 writeS32(os, hotbar_itemcount);
3240 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3244 void Server::hudSetHotbarImage(RemotePlayer *player, const std::string &name)
3249 player->setHotbarImage(name);
3250 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_IMAGE, name);
3253 void Server::hudSetHotbarSelectedImage(RemotePlayer *player, const std::string &name)
3258 player->setHotbarSelectedImage(name);
3259 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3262 Address Server::getPeerAddress(session_t peer_id)
3264 return m_con->GetPeerAddress(peer_id);
3267 void Server::setLocalPlayerAnimations(RemotePlayer *player,
3268 v2s32 animation_frames[4], f32 frame_speed)
3270 sanity_check(player);
3271 player->setLocalAnimations(animation_frames, frame_speed);
3272 SendLocalPlayerAnimations(player->getPeerId(), animation_frames, frame_speed);
3275 void Server::setPlayerEyeOffset(RemotePlayer *player, const v3f &first, const v3f &third)
3277 sanity_check(player);
3278 player->eye_offset_first = first;
3279 player->eye_offset_third = third;
3280 SendEyeOffset(player->getPeerId(), first, third);
3283 void Server::setSky(RemotePlayer *player, const video::SColor &bgcolor,
3284 const std::string &type, const std::vector<std::string> ¶ms,
3287 sanity_check(player);
3288 player->setSky(bgcolor, type, params, clouds);
3289 SendSetSky(player->getPeerId(), bgcolor, type, params, clouds);
3292 void Server::setClouds(RemotePlayer *player, const CloudParams ¶ms)
3294 sanity_check(player);
3295 player->setCloudParams(params);
3296 SendCloudParams(player->getPeerId(), params);
3299 bool Server::overrideDayNightRatio(RemotePlayer *player, bool do_override,
3305 player->overrideDayNightRatio(do_override, ratio);
3306 SendOverrideDayNightRatio(player->getPeerId(), do_override, ratio);
3310 void Server::notifyPlayers(const std::wstring &msg)
3312 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(msg));
3315 void Server::spawnParticle(const std::string &playername, v3f pos,
3316 v3f velocity, v3f acceleration,
3317 float expirationtime, float size, bool
3318 collisiondetection, bool collision_removal, bool object_collision,
3319 bool vertical, const std::string &texture,
3320 const struct TileAnimationParams &animation, u8 glow)
3322 // m_env will be NULL if the server is initializing
3326 session_t peer_id = PEER_ID_INEXISTENT;
3328 if (!playername.empty()) {
3329 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3332 peer_id = player->getPeerId();
3333 proto_ver = player->protocol_version;
3336 SendSpawnParticle(peer_id, proto_ver, pos, velocity, acceleration,
3337 expirationtime, size, collisiondetection, collision_removal,
3338 object_collision, vertical, texture, animation, glow);
3341 u32 Server::addParticleSpawner(u16 amount, float spawntime,
3342 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
3343 float minexptime, float maxexptime, float minsize, float maxsize,
3344 bool collisiondetection, bool collision_removal, bool object_collision,
3345 ServerActiveObject *attached, bool vertical, const std::string &texture,
3346 const std::string &playername, const struct TileAnimationParams &animation,
3349 // m_env will be NULL if the server is initializing
3353 session_t peer_id = PEER_ID_INEXISTENT;
3355 if (!playername.empty()) {
3356 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3359 peer_id = player->getPeerId();
3360 proto_ver = player->protocol_version;
3363 u16 attached_id = attached ? attached->getId() : 0;
3366 if (attached_id == 0)
3367 id = m_env->addParticleSpawner(spawntime);
3369 id = m_env->addParticleSpawner(spawntime, attached_id);
3371 SendAddParticleSpawner(peer_id, proto_ver, amount, spawntime,
3372 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3373 minexptime, maxexptime, minsize, maxsize, collisiondetection,
3374 collision_removal, object_collision, attached_id, vertical,
3375 texture, id, animation, glow);
3380 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3382 // m_env will be NULL if the server is initializing
3384 throw ServerError("Can't delete particle spawners during initialisation!");
3386 session_t peer_id = PEER_ID_INEXISTENT;
3387 if (!playername.empty()) {
3388 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3391 peer_id = player->getPeerId();
3394 m_env->deleteParticleSpawner(id);
3395 SendDeleteParticleSpawner(peer_id, id);
3398 Inventory* Server::createDetachedInventory(const std::string &name, const std::string &player)
3400 if(m_detached_inventories.count(name) > 0){
3401 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3402 delete m_detached_inventories[name];
3404 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3406 Inventory *inv = new Inventory(m_itemdef);
3408 m_detached_inventories[name] = inv;
3409 if (!player.empty())
3410 m_detached_inventories_player[name] = player;
3412 //TODO find a better way to do this
3413 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3417 bool Server::removeDetachedInventory(const std::string &name)
3419 const auto &inv_it = m_detached_inventories.find(name);
3420 if (inv_it == m_detached_inventories.end())
3423 delete inv_it->second;
3424 m_detached_inventories.erase(inv_it);
3426 if (!m_env) // Mods are not done loading
3429 const auto &player_it = m_detached_inventories_player.find(name);
3430 if (player_it != m_detached_inventories_player.end()) {
3431 RemotePlayer *player = m_env->getPlayer(player_it->second.c_str());
3433 if (player && player->getPeerId() != PEER_ID_INEXISTENT)
3434 sendDetachedInventory(name, player->getPeerId());
3436 m_detached_inventories_player.erase(player_it);
3438 // Notify all players about the change
3439 sendDetachedInventory(name, PEER_ID_INEXISTENT);
3444 // actions: time-reversed list
3445 // Return value: success/failure
3446 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3447 std::list<std::string> *log)
3449 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3450 ServerMap *map = (ServerMap*)(&m_env->getMap());
3452 // Fail if no actions to handle
3453 if (actions.empty()) {
3455 log->push_back("Nothing to do.");
3462 for (const RollbackAction &action : actions) {
3464 bool success = action.applyRevert(map, this, this);
3467 std::ostringstream os;
3468 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3469 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3471 log->push_back(os.str());
3473 std::ostringstream os;
3474 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3475 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3477 log->push_back(os.str());
3481 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3482 <<" failed"<<std::endl;
3484 // Call it done if less than half failed
3485 return num_failed <= num_tried/2;
3488 // IGameDef interface
3490 IItemDefManager *Server::getItemDefManager()
3495 const NodeDefManager *Server::getNodeDefManager()
3500 ICraftDefManager *Server::getCraftDefManager()
3505 u16 Server::allocateUnknownNodeId(const std::string &name)
3507 return m_nodedef->allocateDummy(name);
3510 IWritableItemDefManager *Server::getWritableItemDefManager()
3515 NodeDefManager *Server::getWritableNodeDefManager()
3520 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3525 const std::vector<ModSpec> & Server::getMods() const
3527 return m_modmgr->getMods();
3530 const ModSpec *Server::getModSpec(const std::string &modname) const
3532 return m_modmgr->getModSpec(modname);
3535 void Server::getModNames(std::vector<std::string> &modlist)
3537 m_modmgr->getModNames(modlist);
3540 std::string Server::getBuiltinLuaPath()
3542 return porting::path_share + DIR_DELIM + "builtin";
3545 std::string Server::getModStoragePath() const
3547 return m_path_world + DIR_DELIM + "mod_storage";
3550 v3f Server::findSpawnPos()
3552 ServerMap &map = m_env->getServerMap();
3554 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf))
3555 return nodeposf * BS;
3557 bool is_good = false;
3558 // Limit spawn range to mapgen edges (determined by 'mapgen_limit')
3559 s32 range_max = map.getMapgenParams()->getSpawnRangeMax();
3561 // Try to find a good place a few times
3562 for (s32 i = 0; i < 4000 && !is_good; i++) {
3563 s32 range = MYMIN(1 + i, range_max);
3564 // We're going to try to throw the player to this position
3565 v2s16 nodepos2d = v2s16(
3566 -range + (myrand() % (range * 2)),
3567 -range + (myrand() % (range * 2)));
3568 // Get spawn level at point
3569 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3570 // Continue if MAX_MAP_GENERATION_LIMIT was returned by the mapgen to
3571 // signify an unsuitable spawn position, or if outside limits.
3572 if (spawn_level >= MAX_MAP_GENERATION_LIMIT ||
3573 spawn_level <= -MAX_MAP_GENERATION_LIMIT)
3576 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3577 // Consecutive empty nodes
3580 // Search upwards from 'spawn level' for 2 consecutive empty nodes, to
3581 // avoid obstructions in already-generated mapblocks.
3582 // In ungenerated mapblocks consisting of 'ignore' nodes, there will be
3583 // no obstructions, but mapgen decorations are generated after spawn so
3584 // the player may end up inside one.
3585 for (s32 i = 0; i < 8; i++) {
3586 v3s16 blockpos = getNodeBlockPos(nodepos);
3587 map.emergeBlock(blockpos, true);
3588 content_t c = map.getNode(nodepos).getContent();
3590 // In generated mapblocks allow spawn in all 'airlike' drawtype nodes.
3591 // In ungenerated mapblocks allow spawn in 'ignore' nodes.
3592 if (m_nodedef->get(c).drawtype == NDT_AIRLIKE || c == CONTENT_IGNORE) {
3594 if (air_count >= 2) {
3595 // Spawn in lower empty node
3597 nodeposf = intToFloat(nodepos, BS);
3598 // Don't spawn the player outside map boundaries
3599 if (objectpos_over_limit(nodeposf))
3600 // Exit this loop, positions above are probably over limit
3603 // Good position found, cause an exit from main loop
3617 // No suitable spawn point found, return fallback 0,0,0
3618 return v3f(0.0f, 0.0f, 0.0f);
3621 void Server::requestShutdown(const std::string &msg, bool reconnect, float delay)
3623 if (delay == 0.0f) {
3624 // No delay, shutdown immediately
3625 m_shutdown_state.is_requested = true;
3626 // only print to the infostream, a chat message saying
3627 // "Server Shutting Down" is sent when the server destructs.
3628 infostream << "*** Immediate Server shutdown requested." << std::endl;
3629 } else if (delay < 0.0f && m_shutdown_state.isTimerRunning()) {
3630 // Negative delay, cancel shutdown if requested
3631 m_shutdown_state.reset();
3632 std::wstringstream ws;
3634 ws << L"*** Server shutdown canceled.";
3636 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3637 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3638 // m_shutdown_* are already handled, skip.
3640 } else if (delay > 0.0f) {
3641 // Positive delay, tell the clients when the server will shut down
3642 std::wstringstream ws;
3644 ws << L"*** Server shutting down in "
3645 << duration_to_string(myround(delay)).c_str()
3648 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3649 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3652 m_shutdown_state.trigger(delay, msg, reconnect);
3655 PlayerSAO* Server::emergePlayer(const char *name, session_t peer_id, u16 proto_version)
3658 Try to get an existing player
3660 RemotePlayer *player = m_env->getPlayer(name);
3662 // If player is already connected, cancel
3663 if (player && player->getPeerId() != PEER_ID_INEXISTENT) {
3664 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3669 If player with the wanted peer_id already exists, cancel.
3671 if (m_env->getPlayer(peer_id)) {
3672 infostream<<"emergePlayer(): Player with wrong name but same"
3673 " peer_id already exists"<<std::endl;
3678 player = new RemotePlayer(name, idef());
3681 bool newplayer = false;
3684 PlayerSAO *playersao = m_env->loadPlayer(player, &newplayer, peer_id, isSingleplayer());
3686 // Complete init with server parts
3687 playersao->finalize(player, getPlayerEffectivePrivs(player->getName()));
3688 player->protocol_version = proto_version;
3692 m_script->on_newplayer(playersao);
3698 bool Server::registerModStorage(ModMetadata *storage)
3700 if (m_mod_storages.find(storage->getModName()) != m_mod_storages.end()) {
3701 errorstream << "Unable to register same mod storage twice. Storage name: "
3702 << storage->getModName() << std::endl;
3706 m_mod_storages[storage->getModName()] = storage;
3710 void Server::unregisterModStorage(const std::string &name)
3712 std::unordered_map<std::string, ModMetadata *>::const_iterator it = m_mod_storages.find(name);
3713 if (it != m_mod_storages.end()) {
3714 // Save unconditionaly on unregistration
3715 it->second->save(getModStoragePath());
3716 m_mod_storages.erase(name);
3720 void dedicated_server_loop(Server &server, bool &kill)
3722 verbosestream<<"dedicated_server_loop()"<<std::endl;
3724 IntervalLimiter m_profiler_interval;
3726 static thread_local const float steplen =
3727 g_settings->getFloat("dedicated_server_step");
3728 static thread_local const float profiler_print_interval =
3729 g_settings->getFloat("profiler_print_interval");
3732 // This is kind of a hack but can be done like this
3733 // because server.step() is very light
3734 sleep_ms((int)(steplen*1000.0));
3735 server.step(steplen);
3737 if (server.isShutdownRequested() || kill)
3743 if (profiler_print_interval != 0) {
3744 if(m_profiler_interval.step(steplen, profiler_print_interval))
3746 infostream<<"Profiler:"<<std::endl;
3747 g_profiler->print(infostream);
3748 g_profiler->clear();
3753 infostream << "Dedicated server quitting" << std::endl;
3755 if (g_settings->getBool("server_announce"))
3756 ServerList::sendAnnounce(ServerList::AA_DELETE,
3757 server.m_bind_addr.getPort());
3766 bool Server::joinModChannel(const std::string &channel)
3768 return m_modchannel_mgr->joinChannel(channel, PEER_ID_SERVER) &&
3769 m_modchannel_mgr->setChannelState(channel, MODCHANNEL_STATE_READ_WRITE);
3772 bool Server::leaveModChannel(const std::string &channel)
3774 return m_modchannel_mgr->leaveChannel(channel, PEER_ID_SERVER);
3777 bool Server::sendModChannelMessage(const std::string &channel, const std::string &message)
3779 if (!m_modchannel_mgr->canWriteOnChannel(channel))
3782 broadcastModChannelMessage(channel, message, PEER_ID_SERVER);
3786 ModChannel* Server::getModChannel(const std::string &channel)
3788 return m_modchannel_mgr->getModChannel(channel);
3791 void Server::broadcastModChannelMessage(const std::string &channel,
3792 const std::string &message, session_t from_peer)
3794 const std::vector<u16> &peers = m_modchannel_mgr->getChannelPeers(channel);
3798 if (message.size() > STRING_MAX_LEN) {
3799 warningstream << "ModChannel message too long, dropping before sending "
3800 << " (" << message.size() << " > " << STRING_MAX_LEN << ", channel: "
3801 << channel << ")" << std::endl;
3806 if (from_peer != PEER_ID_SERVER) {
3807 sender = getPlayerName(from_peer);
3810 NetworkPacket resp_pkt(TOCLIENT_MODCHANNEL_MSG,
3811 2 + channel.size() + 2 + sender.size() + 2 + message.size());
3812 resp_pkt << channel << sender << message;
3813 for (session_t peer_id : peers) {
3815 if (peer_id == from_peer)
3818 Send(peer_id, &resp_pkt);
3821 if (from_peer != PEER_ID_SERVER) {
3822 m_script->on_modchannel_message(channel, sender, message);