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
97 * The real business of the server happens on the ServerThread.
99 * AsyncRunStep() runs an actual server step as soon as enough time has
100 * passed (dedicated_server_loop keeps track of that).
101 * Receive() blocks at least(!) 30ms waiting for a packet (so this loop
102 * doesn't busy wait) and will process any remaining packets.
105 m_server->AsyncRunStep(true);
107 while (!stopRequested()) {
109 m_server->AsyncRunStep();
113 } catch (con::PeerNotFoundException &e) {
114 infostream<<"Server: PeerNotFoundException"<<std::endl;
115 } catch (ClientNotFoundException &e) {
116 } catch (con::ConnectionBindFailed &e) {
117 m_server->setAsyncFatalError(e.what());
118 } catch (LuaError &e) {
119 m_server->setAsyncFatalError(
120 "ServerThread::run Lua: " + std::string(e.what()));
124 END_DEBUG_EXCEPTION_HANDLER
129 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
131 if(pos_exists) *pos_exists = false;
136 if(pos_exists) *pos_exists = true;
141 ServerActiveObject *sao = env->getActiveObject(object);
144 if(pos_exists) *pos_exists = true;
145 return sao->getBasePosition(); }
150 void Server::ShutdownState::reset()
154 should_reconnect = false;
155 is_requested = false;
158 void Server::ShutdownState::trigger(float delay, const std::string &msg, bool reconnect)
162 should_reconnect = reconnect;
165 void Server::ShutdownState::tick(float dtime, Server *server)
171 static const float shutdown_msg_times[] =
173 1, 2, 3, 4, 5, 10, 20, 40, 60, 120, 180, 300, 600, 1200, 1800, 3600
176 // Automated messages
177 if (m_timer < shutdown_msg_times[ARRLEN(shutdown_msg_times) - 1]) {
178 for (float t : shutdown_msg_times) {
179 // If shutdown timer matches an automessage, shot it
180 if (m_timer > t && m_timer - dtime < t) {
181 std::wstring periodicMsg = getShutdownTimerMessage();
183 infostream << wide_to_utf8(periodicMsg).c_str() << std::endl;
184 server->SendChatMessage(PEER_ID_INEXISTENT, periodicMsg);
191 if (m_timer < 0.0f) {
197 std::wstring Server::ShutdownState::getShutdownTimerMessage() const
199 std::wstringstream ws;
200 ws << L"*** Server shutting down in "
201 << duration_to_string(myround(m_timer)).c_str() << ".";
210 const std::string &path_world,
211 const SubgameSpec &gamespec,
212 bool simple_singleplayer_mode,
217 m_bind_addr(bind_addr),
218 m_path_world(path_world),
219 m_gamespec(gamespec),
220 m_simple_singleplayer_mode(simple_singleplayer_mode),
221 m_dedicated(dedicated),
222 m_async_fatal_error(""),
223 m_con(std::make_shared<con::Connection>(PROTOCOL_ID,
226 m_bind_addr.isIPv6(),
228 m_itemdef(createItemDefManager()),
229 m_nodedef(createNodeDefManager()),
230 m_craftdef(createCraftDefManager()),
231 m_thread(new ServerThread(this)),
235 m_modchannel_mgr(new ModChannelMgr())
237 m_lag = g_settings->getFloat("dedicated_server_step");
239 if (m_path_world.empty())
240 throw ServerError("Supplied empty world path");
242 if (!gamespec.isValid())
243 throw ServerError("Supplied invalid gamespec");
249 // Send shutdown message
250 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE,
251 L"*** Server shutting down"));
254 MutexAutoLock envlock(m_env_mutex);
256 infostream << "Server: Saving players" << std::endl;
257 m_env->saveLoadedPlayers();
259 infostream << "Server: Kicking players" << std::endl;
260 std::string kick_msg;
261 bool reconnect = false;
262 if (isShutdownRequested()) {
263 reconnect = m_shutdown_state.should_reconnect;
264 kick_msg = m_shutdown_state.message;
266 if (kick_msg.empty()) {
267 kick_msg = g_settings->get("kick_msg_shutdown");
269 m_env->saveLoadedPlayers(true);
270 m_env->kickAllPlayers(SERVER_ACCESSDENIED_SHUTDOWN,
271 kick_msg, reconnect);
274 actionstream << "Server: Shutting down" << std::endl;
276 // Do this before stopping the server in case mapgen callbacks need to access
277 // server-controlled resources (like ModStorages). Also do them before
278 // shutdown callbacks since they may modify state that is finalized in a
281 m_emerge->stopThreads();
284 MutexAutoLock envlock(m_env_mutex);
286 // Execute script shutdown hooks
287 infostream << "Executing shutdown hooks" << std::endl;
288 m_script->on_shutdown();
290 infostream << "Server: Saving environment metadata" << std::endl;
300 // Delete things in the reverse order of creation
309 // Deinitialize scripting
310 infostream << "Server: Deinitializing scripting" << std::endl;
313 // Delete detached inventories
314 for (auto &detached_inventory : m_detached_inventories) {
315 delete detached_inventory.second;
318 while (!m_unsent_map_edit_queue.empty()) {
319 delete m_unsent_map_edit_queue.front();
320 m_unsent_map_edit_queue.pop();
326 infostream << "Server created for gameid \"" << m_gamespec.id << "\"";
327 if (m_simple_singleplayer_mode)
328 infostream << " in simple singleplayer mode" << std::endl;
330 infostream << std::endl;
331 infostream << "- world: " << m_path_world << std::endl;
332 infostream << "- game: " << m_gamespec.path << std::endl;
334 // Create world if it doesn't exist
335 if (!loadGameConfAndInitWorld(m_path_world, m_gamespec))
336 throw ServerError("Failed to initialize world");
338 // Create emerge manager
339 m_emerge = new EmergeManager(this);
341 // Create ban manager
342 std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
343 m_banmanager = new BanManager(ban_path);
345 m_modmgr = std::unique_ptr<ServerModManager>(new ServerModManager(m_path_world));
346 std::vector<ModSpec> unsatisfied_mods = m_modmgr->getUnsatisfiedMods();
347 // complain about mods with unsatisfied dependencies
348 if (!m_modmgr->isConsistent()) {
349 m_modmgr->printUnsatisfiedModsError();
353 MutexAutoLock envlock(m_env_mutex);
355 // Create the Map (loads map_meta.txt, overriding configured mapgen params)
356 ServerMap *servermap = new ServerMap(m_path_world, this, m_emerge);
358 // Initialize scripting
359 infostream << "Server: Initializing Lua" << std::endl;
361 m_script = new ServerScripting(this);
363 m_script->loadMod(getBuiltinLuaPath() + DIR_DELIM "init.lua", BUILTIN_MOD_NAME);
365 m_modmgr->loadMods(m_script);
367 // Read Textures and calculate sha1 sums
370 // Apply item aliases in the node definition manager
371 m_nodedef->updateAliases(m_itemdef);
373 // Apply texture overrides from texturepack/override.txt
374 std::vector<std::string> paths;
375 fs::GetRecursiveDirs(paths, g_settings->get("texture_path"));
376 fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures");
377 for (const std::string &path : paths)
378 m_nodedef->applyTextureOverrides(path + DIR_DELIM + "override.txt");
380 m_nodedef->setNodeRegistrationStatus(true);
382 // Perform pending node name resolutions
383 m_nodedef->runNodeResolveCallbacks();
385 // unmap node names for connected nodeboxes
386 m_nodedef->mapNodeboxConnections();
388 // init the recipe hashes to speed up crafting
389 m_craftdef->initHashes(this);
391 // Initialize Environment
392 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
394 m_clients.setEnv(m_env);
396 if (!servermap->settings_mgr.makeMapgenParams())
397 FATAL_ERROR("Couldn't create any mapgen type");
399 // Initialize mapgens
400 m_emerge->initMapgens(servermap->getMapgenParams());
402 if (g_settings->getBool("enable_rollback_recording")) {
403 // Create rollback manager
404 m_rollback = new RollbackManager(m_path_world, this);
407 // Give environment reference to scripting api
408 m_script->initializeEnvironment(m_env);
410 // Register us to receive map edit events
411 servermap->addEventReceiver(this);
415 m_liquid_transform_every = g_settings->getFloat("liquid_update");
416 m_max_chatmessage_length = g_settings->getU16("chat_message_max_size");
417 m_csm_restriction_flags = g_settings->getU64("csm_restriction_flags");
418 m_csm_restriction_noderange = g_settings->getU32("csm_restriction_noderange");
423 infostream << "Starting server on " << m_bind_addr.serializeString()
424 << "..." << std::endl;
426 // Stop thread if already running
429 // Initialize connection
430 m_con->SetTimeoutMs(30);
431 m_con->Serve(m_bind_addr);
436 // ASCII art for the win!
438 << " .__ __ __ " << std::endl
439 << " _____ |__| ____ _____/ |_ ____ _______/ |_ " << std::endl
440 << " / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\" << std::endl
441 << "| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | " << std::endl
442 << "|__|_| /__|___| /\\___ >__| \\___ >____ > |__| " << std::endl
443 << " \\/ \\/ \\/ \\/ \\/ " << std::endl;
444 actionstream << "World at [" << m_path_world << "]" << std::endl;
445 actionstream << "Server for gameid=\"" << m_gamespec.id
446 << "\" listening on " << m_bind_addr.serializeString() << ":"
447 << m_bind_addr.getPort() << "." << std::endl;
452 infostream<<"Server: Stopping and waiting threads"<<std::endl;
454 // Stop threads (set run=false first so both start stopping)
456 //m_emergethread.setRun(false);
458 //m_emergethread.stop();
460 infostream<<"Server: Threads stopped"<<std::endl;
463 void Server::step(float dtime)
469 MutexAutoLock lock(m_step_dtime_mutex);
470 m_step_dtime += dtime;
472 // Throw if fatal error occurred in thread
473 std::string async_err = m_async_fatal_error.get();
474 if (!async_err.empty()) {
475 if (!m_simple_singleplayer_mode) {
476 m_env->kickAllPlayers(SERVER_ACCESSDENIED_CRASH,
477 g_settings->get("kick_msg_crash"),
478 g_settings->getBool("ask_reconnect_on_crash"));
480 throw ServerError("AsyncErr: " + async_err);
484 void Server::AsyncRunStep(bool initial_step)
489 MutexAutoLock lock1(m_step_dtime_mutex);
490 dtime = m_step_dtime;
494 // Send blocks to clients
498 if((dtime < 0.001) && !initial_step)
501 ScopeProfiler sp(g_profiler, "Server::AsyncRunStep()", SPT_AVG);
504 MutexAutoLock lock1(m_step_dtime_mutex);
505 m_step_dtime -= dtime;
512 m_uptime.set(m_uptime.get() + dtime);
518 Update time of day and overall game time
520 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
523 Send to clients at constant intervals
526 m_time_of_day_send_timer -= dtime;
527 if(m_time_of_day_send_timer < 0.0) {
528 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
529 u16 time = m_env->getTimeOfDay();
530 float time_speed = g_settings->getFloat("time_speed");
531 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
535 MutexAutoLock lock(m_env_mutex);
536 // Figure out and report maximum lag to environment
537 float max_lag = m_env->getMaxLagEstimate();
538 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
540 if(dtime > 0.1 && dtime > max_lag * 2.0)
541 infostream<<"Server: Maximum lag peaked to "<<dtime
545 m_env->reportMaxLagEstimate(max_lag);
550 static const float map_timer_and_unload_dtime = 2.92;
551 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
553 MutexAutoLock lock(m_env_mutex);
554 // Run Map's timers and unload unused data
555 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
556 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
557 g_settings->getFloat("server_unload_unused_data_timeout"),
562 Listen to the admin chat, if available
565 if (!m_admin_chat->command_queue.empty()) {
566 MutexAutoLock lock(m_env_mutex);
567 while (!m_admin_chat->command_queue.empty()) {
568 ChatEvent *evt = m_admin_chat->command_queue.pop_frontNoEx();
569 handleChatInterfaceEvent(evt);
573 m_admin_chat->outgoing_queue.push_back(
574 new ChatEventTimeInfo(m_env->getGameTime(), m_env->getTimeOfDay()));
581 /* Transform liquids */
582 m_liquid_transform_timer += dtime;
583 if(m_liquid_transform_timer >= m_liquid_transform_every)
585 m_liquid_transform_timer -= m_liquid_transform_every;
587 MutexAutoLock lock(m_env_mutex);
589 ScopeProfiler sp(g_profiler, "Server: liquid transform");
591 std::map<v3s16, MapBlock*> modified_blocks;
592 m_env->getMap().transformLiquids(modified_blocks, m_env);
595 Set the modified blocks unsent for all the clients
597 if (!modified_blocks.empty()) {
598 SetBlocksNotSent(modified_blocks);
601 m_clients.step(dtime);
603 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
605 // send masterserver announce
607 float &counter = m_masterserver_timer;
608 if (!isSingleplayer() && (!counter || counter >= 300.0) &&
609 g_settings->getBool("server_announce")) {
610 ServerList::sendAnnounce(counter ? ServerList::AA_UPDATE :
611 ServerList::AA_START,
612 m_bind_addr.getPort(),
613 m_clients.getPlayerNames(),
615 m_env->getGameTime(),
618 Mapgen::getMapgenName(m_emerge->mgparams->mgtype),
628 Check added and deleted active objects
631 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
632 MutexAutoLock envlock(m_env_mutex);
635 const RemoteClientMap &clients = m_clients.getClientList();
636 ScopeProfiler sp(g_profiler, "Server: update objects within range");
638 for (const auto &client_it : clients) {
639 RemoteClient *client = client_it.second;
641 if (client->getState() < CS_DefinitionsSent)
644 // This can happen if the client times out somehow
645 if (!m_env->getPlayer(client->peer_id))
648 PlayerSAO *playersao = getPlayerSAO(client->peer_id);
652 SendActiveObjectRemoveAdd(client, playersao);
656 // Save mod storages if modified
657 m_mod_storage_save_timer -= dtime;
658 if (m_mod_storage_save_timer <= 0.0f) {
659 infostream << "Saving registered mod storages." << std::endl;
660 m_mod_storage_save_timer = g_settings->getFloat("server_map_save_interval");
661 for (std::unordered_map<std::string, ModMetadata *>::const_iterator
662 it = m_mod_storages.begin(); it != m_mod_storages.end(); ++it) {
663 if (it->second->isModified()) {
664 it->second->save(getModStoragePath());
674 MutexAutoLock envlock(m_env_mutex);
675 ScopeProfiler sp(g_profiler, "Server: send SAO messages");
678 // Value = data sent by object
679 std::unordered_map<u16, std::vector<ActiveObjectMessage>*> buffered_messages;
681 // Get active object messages from environment
683 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
687 std::vector<ActiveObjectMessage>* message_list = nullptr;
688 std::unordered_map<u16, std::vector<ActiveObjectMessage>* >::iterator n;
689 n = buffered_messages.find(aom.id);
690 if (n == buffered_messages.end()) {
691 message_list = new std::vector<ActiveObjectMessage>;
692 buffered_messages[aom.id] = message_list;
695 message_list = n->second;
697 message_list->push_back(aom);
701 const RemoteClientMap &clients = m_clients.getClientList();
702 // Route data to every client
703 for (const auto &client_it : clients) {
704 RemoteClient *client = client_it.second;
705 PlayerSAO *player = getPlayerSAO(client->peer_id);
706 std::string reliable_data;
707 std::string unreliable_data;
708 // Go through all objects in message buffer
709 for (const auto &buffered_message : buffered_messages) {
710 // If object does not exist or is not known by client, skip it
711 u16 id = buffered_message.first;
712 ServerActiveObject *sao = m_env->getActiveObject(id);
713 if (!sao || client->m_known_objects.find(id) == client->m_known_objects.end())
716 // Get message list of object
717 std::vector<ActiveObjectMessage>* list = buffered_message.second;
718 // Go through every message
719 for (const ActiveObjectMessage &aom : *list) {
720 // Send position updates to players who do not see the attachment
721 if (aom.datastring[0] == GENERIC_CMD_UPDATE_POSITION) {
722 if (sao->getId() == player->getId())
725 // Do not send position updates for attached players
726 // as long the parent is known to the client
727 ServerActiveObject *parent = sao->getParent();
728 if (parent && client->m_known_objects.find(parent->getId()) !=
729 client->m_known_objects.end())
732 // Compose the full new data with header
733 std::string new_data;
736 writeU16((u8*)&buf[0], aom.id);
737 new_data.append(buf, 2);
739 new_data += serializeString(aom.datastring);
740 // Add data to buffer
742 reliable_data += new_data;
744 unreliable_data += new_data;
748 reliable_data and unreliable_data are now ready.
751 if (!reliable_data.empty()) {
752 SendActiveObjectMessages(client->peer_id, reliable_data);
755 if (!unreliable_data.empty()) {
756 SendActiveObjectMessages(client->peer_id, unreliable_data, false);
761 // Clear buffered_messages
762 for (auto &buffered_message : buffered_messages) {
763 delete buffered_message.second;
768 Send queued-for-sending map edit events.
771 // We will be accessing the environment
772 MutexAutoLock lock(m_env_mutex);
774 // Don't send too many at a time
777 // Single change sending is disabled if queue size is not small
778 bool disable_single_change_sending = false;
779 if(m_unsent_map_edit_queue.size() >= 4)
780 disable_single_change_sending = true;
782 int event_count = m_unsent_map_edit_queue.size();
784 // We'll log the amount of each
787 std::list<v3s16> node_meta_updates;
789 while (!m_unsent_map_edit_queue.empty()) {
790 MapEditEvent* event = m_unsent_map_edit_queue.front();
791 m_unsent_map_edit_queue.pop();
793 // Players far away from the change are stored here.
794 // Instead of sending the changes, MapBlocks are set not sent
796 std::unordered_set<u16> far_players;
798 switch (event->type) {
801 prof.add("MEET_ADDNODE", 1);
802 sendAddNode(event->p, event->n, &far_players,
803 disable_single_change_sending ? 5 : 30,
804 event->type == MEET_ADDNODE);
806 case MEET_REMOVENODE:
807 prof.add("MEET_REMOVENODE", 1);
808 sendRemoveNode(event->p, &far_players,
809 disable_single_change_sending ? 5 : 30);
811 case MEET_BLOCK_NODE_METADATA_CHANGED: {
812 verbosestream << "Server: MEET_BLOCK_NODE_METADATA_CHANGED" << std::endl;
813 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
814 if (!event->is_private_change) {
815 // Don't send the change yet. Collect them to eliminate dupes.
816 node_meta_updates.remove(event->p);
817 node_meta_updates.push_back(event->p);
820 if (MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(
821 getNodeBlockPos(event->p))) {
822 block->raiseModified(MOD_STATE_WRITE_NEEDED,
823 MOD_REASON_REPORT_META_CHANGE);
828 infostream << "Server: MEET_OTHER" << std::endl;
829 prof.add("MEET_OTHER", 1);
830 for (const v3s16 &modified_block : event->modified_blocks) {
831 m_clients.markBlockposAsNotSent(modified_block);
835 prof.add("unknown", 1);
836 warningstream << "Server: Unknown MapEditEvent "
837 << ((u32)event->type) << std::endl;
842 Set blocks not sent to far players
844 if (!far_players.empty()) {
845 // Convert list format to that wanted by SetBlocksNotSent
846 std::map<v3s16, MapBlock*> modified_blocks2;
847 for (const v3s16 &modified_block : event->modified_blocks) {
848 modified_blocks2[modified_block] =
849 m_env->getMap().getBlockNoCreateNoEx(modified_block);
852 // Set blocks not sent
853 for (const u16 far_player : far_players) {
854 if (RemoteClient *client = getClient(far_player))
855 client->SetBlocksNotSent(modified_blocks2);
862 if (event_count >= 5) {
863 infostream << "Server: MapEditEvents:" << std::endl;
864 prof.print(infostream);
865 } else if (event_count != 0) {
866 verbosestream << "Server: MapEditEvents:" << std::endl;
867 prof.print(verbosestream);
870 // Send all metadata updates
871 if (node_meta_updates.size())
872 sendMetadataChanged(node_meta_updates);
876 Trigger emergethread (it somehow gets to a non-triggered but
877 bysy state sometimes)
880 float &counter = m_emergethread_trigger_timer;
882 if (counter >= 2.0) {
885 m_emerge->startThreads();
889 // Save map, players and auth stuff
891 float &counter = m_savemap_timer;
893 static thread_local const float save_interval =
894 g_settings->getFloat("server_map_save_interval");
895 if (counter >= save_interval) {
897 MutexAutoLock lock(m_env_mutex);
899 ScopeProfiler sp(g_profiler, "Server: map saving (sum)");
902 if (m_banmanager->isModified()) {
903 m_banmanager->save();
906 // Save changed parts of map
907 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
910 m_env->saveLoadedPlayers();
912 // Save environment metadata
917 m_shutdown_state.tick(dtime, this);
920 void Server::Receive()
930 In the first iteration *wait* for a packet, afterwards process
931 all packets that are immediately available (no waiting).
934 m_con->Receive(&pkt);
937 if (!m_con->TryReceive(&pkt))
941 peer_id = pkt.getPeerId();
943 } catch (const con::InvalidIncomingDataException &e) {
944 infostream << "Server::Receive(): InvalidIncomingDataException: what()="
945 << e.what() << std::endl;
946 } catch (const SerializationError &e) {
947 infostream << "Server::Receive(): SerializationError: what()="
948 << e.what() << std::endl;
949 } catch (const ClientStateError &e) {
950 errorstream << "ProcessData: peer=" << peer_id << " what()="
951 << e.what() << std::endl;
952 DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
953 L"Try reconnecting or updating your client");
954 } catch (const con::PeerNotFoundException &e) {
956 } catch (const con::NoIncomingDataException &e) {
962 PlayerSAO* Server::StageTwoClientInit(session_t peer_id)
964 std::string playername;
965 PlayerSAO *playersao = NULL;
968 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
970 playername = client->getName();
971 playersao = emergePlayer(playername.c_str(), peer_id, client->net_proto_version);
973 } catch (std::exception &e) {
979 RemotePlayer *player = m_env->getPlayer(playername.c_str());
982 if (!playersao || !player) {
983 if (player && player->getPeerId() != PEER_ID_INEXISTENT) {
984 actionstream << "Server: Failed to emerge player \"" << playername
985 << "\" (player allocated to an another client)" << std::endl;
986 DenyAccess_Legacy(peer_id, L"Another client is connected with this "
987 L"name. If your client closed unexpectedly, try again in "
990 errorstream << "Server: " << playername << ": Failed to emerge player"
992 DenyAccess_Legacy(peer_id, L"Could not allocate player.");
998 Send complete position information
1000 SendMovePlayer(peer_id);
1003 SendPlayerPrivileges(peer_id);
1005 // Send inventory formspec
1006 SendPlayerInventoryFormspec(peer_id);
1009 SendInventory(playersao, false);
1011 // Send HP or death screen
1012 if (playersao->isDead())
1013 SendDeathscreen(peer_id, false, v3f(0,0,0));
1015 SendPlayerHPOrDie(playersao,
1016 PlayerHPChangeReason(PlayerHPChangeReason::SET_HP));
1019 SendPlayerBreath(playersao);
1025 Address addr = getPeerAddress(player->getPeerId());
1026 std::string ip_str = addr.serializeString();
1027 const std::vector<std::string> &names = m_clients.getPlayerNames();
1029 actionstream << player->getName() << " [" << ip_str << "] joins game. List of players: ";
1031 for (const std::string &name : names) {
1032 actionstream << name << " ";
1035 actionstream << player->getName() <<std::endl;
1040 inline void Server::handleCommand(NetworkPacket *pkt)
1042 const ToServerCommandHandler &opHandle = toServerCommandTable[pkt->getCommand()];
1043 (this->*opHandle.handler)(pkt);
1046 void Server::ProcessData(NetworkPacket *pkt)
1048 // Environment is locked first.
1049 MutexAutoLock envlock(m_env_mutex);
1051 ScopeProfiler sp(g_profiler, "Server: Process network packet (sum)");
1052 u32 peer_id = pkt->getPeerId();
1055 Address address = getPeerAddress(peer_id);
1056 std::string addr_s = address.serializeString();
1058 if(m_banmanager->isIpBanned(addr_s)) {
1059 std::string ban_name = m_banmanager->getBanName(addr_s);
1060 infostream << "Server: A banned client tried to connect from "
1061 << addr_s << "; banned name was "
1062 << ban_name << std::endl;
1063 // This actually doesn't seem to transfer to the client
1064 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1065 + utf8_to_wide(ban_name));
1069 catch(con::PeerNotFoundException &e) {
1071 * no peer for this packet found
1072 * most common reason is peer timeout, e.g. peer didn't
1073 * respond for some time, your server was overloaded or
1076 infostream << "Server::ProcessData(): Canceling: peer "
1077 << peer_id << " not found" << std::endl;
1082 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1084 // Command must be handled into ToServerCommandHandler
1085 if (command >= TOSERVER_NUM_MSG_TYPES) {
1086 infostream << "Server: Ignoring unknown command "
1087 << command << std::endl;
1091 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1096 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1098 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1099 errorstream << "Server::ProcessData(): Cancelling: Peer"
1100 " serialization format invalid or not initialized."
1101 " Skipping incoming command=" << command << std::endl;
1105 /* Handle commands related to client startup */
1106 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1111 if (m_clients.getClientState(peer_id) < CS_Active) {
1112 if (command == TOSERVER_PLAYERPOS) return;
1114 errorstream << "Got packet command: " << command << " for peer id "
1115 << peer_id << " but client isn't active yet. Dropping packet "
1121 } catch (SendFailedException &e) {
1122 errorstream << "Server::ProcessData(): SendFailedException: "
1123 << "what=" << e.what()
1125 } catch (PacketError &e) {
1126 actionstream << "Server::ProcessData(): PacketError: "
1127 << "what=" << e.what()
1132 void Server::setTimeOfDay(u32 time)
1134 m_env->setTimeOfDay(time);
1135 m_time_of_day_send_timer = 0;
1138 void Server::onMapEditEvent(const MapEditEvent &event)
1140 if (m_ignore_map_edit_events_area.contains(event.getArea()))
1143 m_unsent_map_edit_queue.push(new MapEditEvent(event));
1146 Inventory* Server::getInventory(const InventoryLocation &loc)
1149 case InventoryLocation::UNDEFINED:
1150 case InventoryLocation::CURRENT_PLAYER:
1152 case InventoryLocation::PLAYER:
1154 RemotePlayer *player = m_env->getPlayer(loc.name.c_str());
1157 PlayerSAO *playersao = player->getPlayerSAO();
1160 return playersao->getInventory();
1163 case InventoryLocation::NODEMETA:
1165 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1168 return meta->getInventory();
1171 case InventoryLocation::DETACHED:
1173 if(m_detached_inventories.count(loc.name) == 0)
1175 return m_detached_inventories[loc.name];
1179 sanity_check(false); // abort
1185 void Server::setInventoryModified(const InventoryLocation &loc)
1188 case InventoryLocation::UNDEFINED:
1190 case InventoryLocation::PLAYER:
1193 RemotePlayer *player = m_env->getPlayer(loc.name.c_str());
1198 player->setModified(true);
1199 player->inventory.setModified(true);
1200 // Updates are sent in ServerEnvironment::step()
1203 case InventoryLocation::NODEMETA:
1206 event.type = MEET_BLOCK_NODE_METADATA_CHANGED;
1208 m_env->getMap().dispatchEvent(event);
1211 case InventoryLocation::DETACHED:
1213 // Updates are sent in ServerEnvironment::step()
1217 sanity_check(false); // abort
1222 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1224 std::vector<session_t> clients = m_clients.getClientIDs();
1226 // Set the modified blocks unsent for all the clients
1227 for (const session_t client_id : clients) {
1228 if (RemoteClient *client = m_clients.lockedGetClientNoEx(client_id))
1229 client->SetBlocksNotSent(block);
1234 void Server::peerAdded(con::Peer *peer)
1236 verbosestream<<"Server::peerAdded(): peer->id="
1237 <<peer->id<<std::endl;
1239 m_peer_change_queue.push(con::PeerChange(con::PEER_ADDED, peer->id, false));
1242 void Server::deletingPeer(con::Peer *peer, bool timeout)
1244 verbosestream<<"Server::deletingPeer(): peer->id="
1245 <<peer->id<<", timeout="<<timeout<<std::endl;
1247 m_clients.event(peer->id, CSE_Disconnect);
1248 m_peer_change_queue.push(con::PeerChange(con::PEER_REMOVED, peer->id, timeout));
1251 bool Server::getClientConInfo(session_t peer_id, con::rtt_stat_type type, float* retval)
1253 *retval = m_con->getPeerStat(peer_id,type);
1254 return *retval != -1;
1257 bool Server::getClientInfo(
1266 std::string* vers_string
1269 *state = m_clients.getClientState(peer_id);
1271 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1278 *uptime = client->uptime();
1279 *ser_vers = client->serialization_version;
1280 *prot_vers = client->net_proto_version;
1282 *major = client->getMajor();
1283 *minor = client->getMinor();
1284 *patch = client->getPatch();
1285 *vers_string = client->getFull();
1292 void Server::handlePeerChanges()
1294 while(!m_peer_change_queue.empty())
1296 con::PeerChange c = m_peer_change_queue.front();
1297 m_peer_change_queue.pop();
1299 verbosestream<<"Server: Handling peer change: "
1300 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1305 case con::PEER_ADDED:
1306 m_clients.CreateClient(c.peer_id);
1309 case con::PEER_REMOVED:
1310 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1314 FATAL_ERROR("Invalid peer change event received!");
1320 void Server::printToConsoleOnly(const std::string &text)
1323 m_admin_chat->outgoing_queue.push_back(
1324 new ChatEventChat("", utf8_to_wide(text)));
1326 std::cout << text << std::endl;
1330 void Server::Send(NetworkPacket *pkt)
1332 Send(pkt->getPeerId(), pkt);
1335 void Server::Send(session_t peer_id, NetworkPacket *pkt)
1337 m_clients.send(peer_id,
1338 clientCommandFactoryTable[pkt->getCommand()].channel,
1340 clientCommandFactoryTable[pkt->getCommand()].reliable);
1343 void Server::SendMovement(session_t peer_id)
1345 std::ostringstream os(std::ios_base::binary);
1347 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1349 pkt << g_settings->getFloat("movement_acceleration_default");
1350 pkt << g_settings->getFloat("movement_acceleration_air");
1351 pkt << g_settings->getFloat("movement_acceleration_fast");
1352 pkt << g_settings->getFloat("movement_speed_walk");
1353 pkt << g_settings->getFloat("movement_speed_crouch");
1354 pkt << g_settings->getFloat("movement_speed_fast");
1355 pkt << g_settings->getFloat("movement_speed_climb");
1356 pkt << g_settings->getFloat("movement_speed_jump");
1357 pkt << g_settings->getFloat("movement_liquid_fluidity");
1358 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1359 pkt << g_settings->getFloat("movement_liquid_sink");
1360 pkt << g_settings->getFloat("movement_gravity");
1365 void Server::SendPlayerHPOrDie(PlayerSAO *playersao, const PlayerHPChangeReason &reason)
1367 if (playersao->isImmortal())
1370 session_t peer_id = playersao->getPeerID();
1371 bool is_alive = playersao->getHP() > 0;
1374 SendPlayerHP(peer_id);
1376 DiePlayer(peer_id, reason);
1379 void Server::SendHP(session_t peer_id, u16 hp)
1381 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1386 void Server::SendBreath(session_t peer_id, u16 breath)
1388 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1389 pkt << (u16) breath;
1393 void Server::SendAccessDenied(session_t peer_id, AccessDeniedCode reason,
1394 const std::string &custom_reason, bool reconnect)
1396 assert(reason < SERVER_ACCESSDENIED_MAX);
1398 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1400 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
1401 pkt << custom_reason;
1402 else if (reason == SERVER_ACCESSDENIED_SHUTDOWN ||
1403 reason == SERVER_ACCESSDENIED_CRASH)
1404 pkt << custom_reason << (u8)reconnect;
1408 void Server::SendAccessDenied_Legacy(session_t peer_id,const std::wstring &reason)
1410 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1415 void Server::SendDeathscreen(session_t peer_id, bool set_camera_point_target,
1416 v3f camera_point_target)
1418 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1419 pkt << set_camera_point_target << camera_point_target;
1423 void Server::SendItemDef(session_t peer_id,
1424 IItemDefManager *itemdef, u16 protocol_version)
1426 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1430 u32 length of the next item
1431 zlib-compressed serialized ItemDefManager
1433 std::ostringstream tmp_os(std::ios::binary);
1434 itemdef->serialize(tmp_os, protocol_version);
1435 std::ostringstream tmp_os2(std::ios::binary);
1436 compressZlib(tmp_os.str(), tmp_os2);
1437 pkt.putLongString(tmp_os2.str());
1440 verbosestream << "Server: Sending item definitions to id(" << peer_id
1441 << "): size=" << pkt.getSize() << std::endl;
1446 void Server::SendNodeDef(session_t peer_id,
1447 const NodeDefManager *nodedef, u16 protocol_version)
1449 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1453 u32 length of the next item
1454 zlib-compressed serialized NodeDefManager
1456 std::ostringstream tmp_os(std::ios::binary);
1457 nodedef->serialize(tmp_os, protocol_version);
1458 std::ostringstream tmp_os2(std::ios::binary);
1459 compressZlib(tmp_os.str(), tmp_os2);
1461 pkt.putLongString(tmp_os2.str());
1464 verbosestream << "Server: Sending node definitions to id(" << peer_id
1465 << "): size=" << pkt.getSize() << std::endl;
1471 Non-static send methods
1474 void Server::SendInventory(PlayerSAO *sao, bool incremental)
1476 RemotePlayer *player = sao->getPlayer();
1478 // Do not send new format to old clients
1479 incremental &= player->protocol_version >= 38;
1481 UpdateCrafting(player);
1487 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, sao->getPeerID());
1489 std::ostringstream os(std::ios::binary);
1490 sao->getInventory()->serialize(os, incremental);
1491 sao->getInventory()->setModified(false);
1492 player->setModified(true);
1494 const std::string &s = os.str();
1495 pkt.putRawString(s.c_str(), s.size());
1499 void Server::SendChatMessage(session_t peer_id, const ChatMessage &message)
1501 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1503 u8 type = message.type;
1504 pkt << version << type << std::wstring(L"") << message.message << (u64)message.timestamp;
1506 if (peer_id != PEER_ID_INEXISTENT) {
1507 RemotePlayer *player = m_env->getPlayer(peer_id);
1513 m_clients.sendToAll(&pkt);
1517 void Server::SendShowFormspecMessage(session_t peer_id, const std::string &formspec,
1518 const std::string &formname)
1520 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0, peer_id);
1521 if (formspec.empty()){
1522 //the client should close the formspec
1523 //but make sure there wasn't another one open in meantime
1524 const auto it = m_formspec_state_data.find(peer_id);
1525 if (it != m_formspec_state_data.end() && it->second == formname) {
1526 m_formspec_state_data.erase(peer_id);
1528 pkt.putLongString("");
1530 m_formspec_state_data[peer_id] = formname;
1531 pkt.putLongString(formspec);
1538 // Spawns a particle on peer with peer_id
1539 void Server::SendSpawnParticle(session_t peer_id, u16 protocol_version,
1540 v3f pos, v3f velocity, v3f acceleration,
1541 float expirationtime, float size, bool collisiondetection,
1542 bool collision_removal, bool object_collision,
1543 bool vertical, const std::string &texture,
1544 const struct TileAnimationParams &animation, u8 glow)
1546 static thread_local const float radius =
1547 g_settings->getS16("max_block_send_distance") * MAP_BLOCKSIZE * BS;
1549 if (peer_id == PEER_ID_INEXISTENT) {
1550 std::vector<session_t> clients = m_clients.getClientIDs();
1552 for (const session_t client_id : clients) {
1553 RemotePlayer *player = m_env->getPlayer(client_id);
1557 PlayerSAO *sao = player->getPlayerSAO();
1561 // Do not send to distant clients
1562 if (sao->getBasePosition().getDistanceFrom(pos * BS) > radius)
1565 SendSpawnParticle(client_id, player->protocol_version,
1566 pos, velocity, acceleration,
1567 expirationtime, size, collisiondetection, collision_removal,
1568 object_collision, vertical, texture, animation, glow);
1573 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1575 pkt << pos << velocity << acceleration << expirationtime
1576 << size << collisiondetection;
1577 pkt.putLongString(texture);
1579 pkt << collision_removal;
1580 // This is horrible but required (why are there two ways to serialize pkts?)
1581 std::ostringstream os(std::ios_base::binary);
1582 animation.serialize(os, protocol_version);
1583 pkt.putRawString(os.str());
1585 pkt << object_collision;
1590 // Adds a ParticleSpawner on peer with peer_id
1591 void Server::SendAddParticleSpawner(session_t peer_id, u16 protocol_version,
1592 u16 amount, float spawntime, v3f minpos, v3f maxpos,
1593 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1594 float minsize, float maxsize, bool collisiondetection, bool collision_removal,
1595 bool object_collision, u16 attached_id, bool vertical, const std::string &texture, u32 id,
1596 const struct TileAnimationParams &animation, u8 glow)
1598 if (peer_id == PEER_ID_INEXISTENT) {
1599 // This sucks and should be replaced:
1600 std::vector<session_t> clients = m_clients.getClientIDs();
1601 for (const session_t client_id : clients) {
1602 RemotePlayer *player = m_env->getPlayer(client_id);
1605 SendAddParticleSpawner(client_id, player->protocol_version,
1606 amount, spawntime, minpos, maxpos,
1607 minvel, maxvel, minacc, maxacc, minexptime, maxexptime,
1608 minsize, maxsize, collisiondetection, collision_removal,
1609 object_collision, attached_id, vertical, texture, id,
1615 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1617 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1618 << minacc << maxacc << minexptime << maxexptime << minsize
1619 << maxsize << collisiondetection;
1621 pkt.putLongString(texture);
1623 pkt << id << vertical;
1624 pkt << collision_removal;
1626 // This is horrible but required
1627 std::ostringstream os(std::ios_base::binary);
1628 animation.serialize(os, protocol_version);
1629 pkt.putRawString(os.str());
1631 pkt << object_collision;
1636 void Server::SendDeleteParticleSpawner(session_t peer_id, u32 id)
1638 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER, 4, peer_id);
1640 // Ugly error in this packet
1643 if (peer_id != PEER_ID_INEXISTENT)
1646 m_clients.sendToAll(&pkt);
1650 void Server::SendHUDAdd(session_t peer_id, u32 id, HudElement *form)
1652 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1654 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1655 << form->text << form->number << form->item << form->dir
1656 << form->align << form->offset << form->world_pos << form->size
1662 void Server::SendHUDRemove(session_t peer_id, u32 id)
1664 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1669 void Server::SendHUDChange(session_t peer_id, u32 id, HudElementStat stat, void *value)
1671 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1672 pkt << id << (u8) stat;
1676 case HUD_STAT_SCALE:
1677 case HUD_STAT_ALIGN:
1678 case HUD_STAT_OFFSET:
1679 pkt << *(v2f *) value;
1683 pkt << *(std::string *) value;
1685 case HUD_STAT_WORLD_POS:
1686 pkt << *(v3f *) value;
1689 pkt << *(v2s32 *) value;
1691 case HUD_STAT_NUMBER:
1695 pkt << *(u32 *) value;
1702 void Server::SendHUDSetFlags(session_t peer_id, u32 flags, u32 mask)
1704 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1706 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1708 pkt << flags << mask;
1713 void Server::SendHUDSetParam(session_t peer_id, u16 param, const std::string &value)
1715 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1716 pkt << param << value;
1720 void Server::SendSetSky(session_t peer_id, const SkyboxParams ¶ms)
1722 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1724 // Handle prior clients here
1725 if (m_clients.getProtocolVersion(peer_id) < 39) {
1726 pkt << params.bgcolor << params.type << (u16) params.textures.size();
1728 for (const std::string& texture : params.textures)
1731 pkt << params.clouds;
1732 } else { // Handle current clients and future clients
1733 pkt << params.bgcolor << params.type
1734 << params.clouds << params.sun_tint
1735 << params.moon_tint << params.tint_type;
1737 if (params.type == "skybox") {
1738 pkt << (u16) params.textures.size();
1739 for (const std::string &texture : params.textures)
1741 } else if (params.type == "regular") {
1742 pkt << params.sky_color.day_sky << params.sky_color.day_horizon
1743 << params.sky_color.dawn_sky << params.sky_color.dawn_horizon
1744 << params.sky_color.night_sky << params.sky_color.night_horizon
1745 << params.sky_color.indoors;
1752 void Server::SendSetSun(session_t peer_id, const SunParams ¶ms)
1754 NetworkPacket pkt(TOCLIENT_SET_SUN, 0, peer_id);
1755 pkt << params.visible << params.texture
1756 << params.tonemap << params.sunrise
1757 << params.sunrise_visible << params.scale;
1761 void Server::SendSetMoon(session_t peer_id, const MoonParams ¶ms)
1763 NetworkPacket pkt(TOCLIENT_SET_MOON, 0, peer_id);
1765 pkt << params.visible << params.texture
1766 << params.tonemap << params.scale;
1770 void Server::SendSetStars(session_t peer_id, const StarParams ¶ms)
1772 NetworkPacket pkt(TOCLIENT_SET_STARS, 0, peer_id);
1774 pkt << params.visible << params.count
1775 << params.starcolor << params.scale;
1780 void Server::SendCloudParams(session_t peer_id, const CloudParams ¶ms)
1782 NetworkPacket pkt(TOCLIENT_CLOUD_PARAMS, 0, peer_id);
1783 pkt << params.density << params.color_bright << params.color_ambient
1784 << params.height << params.thickness << params.speed;
1788 void Server::SendOverrideDayNightRatio(session_t peer_id, bool do_override,
1791 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1794 pkt << do_override << (u16) (ratio * 65535);
1799 void Server::SendTimeOfDay(session_t peer_id, u16 time, f32 time_speed)
1801 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1802 pkt << time << time_speed;
1804 if (peer_id == PEER_ID_INEXISTENT) {
1805 m_clients.sendToAll(&pkt);
1812 void Server::SendPlayerHP(session_t peer_id)
1814 PlayerSAO *playersao = getPlayerSAO(peer_id);
1817 SendHP(peer_id, playersao->getHP());
1818 m_script->player_event(playersao,"health_changed");
1820 // Send to other clients
1821 std::string str = gob_cmd_punched(playersao->getHP());
1822 ActiveObjectMessage aom(playersao->getId(), true, str);
1823 playersao->m_messages_out.push(aom);
1826 void Server::SendPlayerBreath(PlayerSAO *sao)
1830 m_script->player_event(sao, "breath_changed");
1831 SendBreath(sao->getPeerID(), sao->getBreath());
1834 void Server::SendMovePlayer(session_t peer_id)
1836 RemotePlayer *player = m_env->getPlayer(peer_id);
1838 PlayerSAO *sao = player->getPlayerSAO();
1841 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1842 pkt << sao->getBasePosition() << sao->getLookPitch() << sao->getRotation().Y;
1845 v3f pos = sao->getBasePosition();
1846 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1847 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1848 << " pitch=" << sao->getLookPitch()
1849 << " yaw=" << sao->getRotation().Y
1856 void Server::SendPlayerFov(session_t peer_id)
1858 NetworkPacket pkt(TOCLIENT_FOV, 4 + 1, peer_id);
1860 PlayerFovSpec fov_spec = m_env->getPlayer(peer_id)->getFov();
1861 pkt << fov_spec.fov << fov_spec.is_multiplier;
1866 void Server::SendLocalPlayerAnimations(session_t peer_id, v2s32 animation_frames[4],
1867 f32 animation_speed)
1869 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1872 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1873 << animation_frames[3] << animation_speed;
1878 void Server::SendEyeOffset(session_t peer_id, v3f first, v3f third)
1880 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1881 pkt << first << third;
1885 void Server::SendPlayerPrivileges(session_t peer_id)
1887 RemotePlayer *player = m_env->getPlayer(peer_id);
1889 if(player->getPeerId() == PEER_ID_INEXISTENT)
1892 std::set<std::string> privs;
1893 m_script->getAuth(player->getName(), NULL, &privs);
1895 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1896 pkt << (u16) privs.size();
1898 for (const std::string &priv : privs) {
1905 void Server::SendPlayerInventoryFormspec(session_t peer_id)
1907 RemotePlayer *player = m_env->getPlayer(peer_id);
1909 if (player->getPeerId() == PEER_ID_INEXISTENT)
1912 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1913 pkt.putLongString(player->inventory_formspec);
1918 void Server::SendPlayerFormspecPrepend(session_t peer_id)
1920 RemotePlayer *player = m_env->getPlayer(peer_id);
1922 if (player->getPeerId() == PEER_ID_INEXISTENT)
1925 NetworkPacket pkt(TOCLIENT_FORMSPEC_PREPEND, 0, peer_id);
1926 pkt << player->formspec_prepend;
1930 void Server::SendActiveObjectRemoveAdd(RemoteClient *client, PlayerSAO *playersao)
1932 // Radius inside which objects are active
1933 static thread_local const s16 radius =
1934 g_settings->getS16("active_object_send_range_blocks") * MAP_BLOCKSIZE;
1936 // Radius inside which players are active
1937 static thread_local const bool is_transfer_limited =
1938 g_settings->exists("unlimited_player_transfer_distance") &&
1939 !g_settings->getBool("unlimited_player_transfer_distance");
1941 static thread_local const s16 player_transfer_dist =
1942 g_settings->getS16("player_transfer_distance") * MAP_BLOCKSIZE;
1944 s16 player_radius = player_transfer_dist == 0 && is_transfer_limited ?
1945 radius : player_transfer_dist;
1947 s16 my_radius = MYMIN(radius, playersao->getWantedRange() * MAP_BLOCKSIZE);
1951 std::queue<u16> removed_objects, added_objects;
1952 m_env->getRemovedActiveObjects(playersao, my_radius, player_radius,
1953 client->m_known_objects, removed_objects);
1954 m_env->getAddedActiveObjects(playersao, my_radius, player_radius,
1955 client->m_known_objects, added_objects);
1957 int removed_count = removed_objects.size();
1958 int added_count = added_objects.size();
1960 if (removed_objects.empty() && added_objects.empty())
1966 // Handle removed objects
1967 writeU16((u8*)buf, removed_objects.size());
1968 data.append(buf, 2);
1969 while (!removed_objects.empty()) {
1971 u16 id = removed_objects.front();
1972 ServerActiveObject* obj = m_env->getActiveObject(id);
1974 // Add to data buffer for sending
1975 writeU16((u8*)buf, id);
1976 data.append(buf, 2);
1978 // Remove from known objects
1979 client->m_known_objects.erase(id);
1981 if (obj && obj->m_known_by_count > 0)
1982 obj->m_known_by_count--;
1984 removed_objects.pop();
1987 // Handle added objects
1988 writeU16((u8*)buf, added_objects.size());
1989 data.append(buf, 2);
1990 while (!added_objects.empty()) {
1992 u16 id = added_objects.front();
1993 ServerActiveObject *obj = m_env->getActiveObject(id);
1994 added_objects.pop();
1997 warningstream << FUNCTION_NAME << ": NULL object id="
1998 << (int)id << std::endl;
2003 u8 type = obj->getSendType();
2005 // Add to data buffer for sending
2006 writeU16((u8*)buf, id);
2007 data.append(buf, 2);
2008 writeU8((u8*)buf, type);
2009 data.append(buf, 1);
2011 data.append(serializeLongString(
2012 obj->getClientInitializationData(client->net_proto_version)));
2014 // Add to known objects
2015 client->m_known_objects.insert(id);
2017 obj->m_known_by_count++;
2020 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, data.size(), client->peer_id);
2021 pkt.putRawString(data.c_str(), data.size());
2024 verbosestream << "Server::SendActiveObjectRemoveAdd: "
2025 << removed_count << " removed, " << added_count << " added, "
2026 << "packet size is " << pkt.getSize() << std::endl;
2029 void Server::SendActiveObjectMessages(session_t peer_id, const std::string &datas,
2032 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
2033 datas.size(), peer_id);
2035 pkt.putRawString(datas.c_str(), datas.size());
2037 m_clients.send(pkt.getPeerId(),
2038 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
2042 void Server::SendCSMRestrictionFlags(session_t peer_id)
2044 NetworkPacket pkt(TOCLIENT_CSM_RESTRICTION_FLAGS,
2045 sizeof(m_csm_restriction_flags) + sizeof(m_csm_restriction_noderange), peer_id);
2046 pkt << m_csm_restriction_flags << m_csm_restriction_noderange;
2050 void Server::SendPlayerSpeed(session_t peer_id, const v3f &added_vel)
2052 NetworkPacket pkt(TOCLIENT_PLAYER_SPEED, 0, peer_id);
2057 inline s32 Server::nextSoundId()
2059 s32 ret = m_next_sound_id;
2060 if (m_next_sound_id == INT32_MAX)
2061 m_next_sound_id = 0; // signed overflow is undefined
2067 s32 Server::playSound(const SimpleSoundSpec &spec,
2068 const ServerSoundParams ¶ms, bool ephemeral)
2070 // Find out initial position of sound
2071 bool pos_exists = false;
2072 v3f pos = params.getPos(m_env, &pos_exists);
2073 // If position is not found while it should be, cancel sound
2074 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
2077 // Filter destination clients
2078 std::vector<session_t> dst_clients;
2079 if (!params.to_player.empty()) {
2080 RemotePlayer *player = m_env->getPlayer(params.to_player.c_str());
2082 infostream<<"Server::playSound: Player \""<<params.to_player
2083 <<"\" not found"<<std::endl;
2086 if (player->getPeerId() == PEER_ID_INEXISTENT) {
2087 infostream<<"Server::playSound: Player \""<<params.to_player
2088 <<"\" not connected"<<std::endl;
2091 dst_clients.push_back(player->getPeerId());
2093 std::vector<session_t> clients = m_clients.getClientIDs();
2095 for (const session_t client_id : clients) {
2096 RemotePlayer *player = m_env->getPlayer(client_id);
2099 if (!params.exclude_player.empty() &&
2100 params.exclude_player == player->getName())
2103 PlayerSAO *sao = player->getPlayerSAO();
2108 if(sao->getBasePosition().getDistanceFrom(pos) >
2109 params.max_hear_distance)
2112 dst_clients.push_back(client_id);
2116 if(dst_clients.empty())
2121 ServerPlayingSound *psound = nullptr;
2123 id = -1; // old clients will still use this, so pick a reserved ID
2126 // The sound will exist as a reference in m_playing_sounds
2127 m_playing_sounds[id] = ServerPlayingSound();
2128 psound = &m_playing_sounds[id];
2129 psound->params = params;
2130 psound->spec = spec;
2133 float gain = params.gain * spec.gain;
2134 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2135 pkt << id << spec.name << gain
2136 << (u8) params.type << pos << params.object
2137 << params.loop << params.fade << params.pitch
2140 bool as_reliable = !ephemeral;
2142 for (const u16 dst_client : dst_clients) {
2144 psound->clients.insert(dst_client);
2145 m_clients.send(dst_client, 0, &pkt, as_reliable);
2149 void Server::stopSound(s32 handle)
2151 // Get sound reference
2152 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2153 m_playing_sounds.find(handle);
2154 if (i == m_playing_sounds.end())
2156 ServerPlayingSound &psound = i->second;
2158 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2161 for (std::unordered_set<session_t>::const_iterator si = psound.clients.begin();
2162 si != psound.clients.end(); ++si) {
2164 m_clients.send(*si, 0, &pkt, true);
2166 // Remove sound reference
2167 m_playing_sounds.erase(i);
2170 void Server::fadeSound(s32 handle, float step, float gain)
2172 // Get sound reference
2173 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2174 m_playing_sounds.find(handle);
2175 if (i == m_playing_sounds.end())
2178 ServerPlayingSound &psound = i->second;
2179 psound.params.gain = gain;
2181 NetworkPacket pkt(TOCLIENT_FADE_SOUND, 4);
2182 pkt << handle << step << gain;
2184 // Backwards compability
2185 bool play_sound = gain > 0;
2186 ServerPlayingSound compat_psound = psound;
2187 compat_psound.clients.clear();
2189 NetworkPacket compat_pkt(TOCLIENT_STOP_SOUND, 4);
2190 compat_pkt << handle;
2192 for (std::unordered_set<u16>::iterator it = psound.clients.begin();
2193 it != psound.clients.end();) {
2194 if (m_clients.getProtocolVersion(*it) >= 32) {
2196 m_clients.send(*it, 0, &pkt, true);
2199 compat_psound.clients.insert(*it);
2201 m_clients.send(*it, 0, &compat_pkt, true);
2202 psound.clients.erase(it++);
2206 // Remove sound reference
2207 if (!play_sound || psound.clients.empty())
2208 m_playing_sounds.erase(i);
2210 if (play_sound && !compat_psound.clients.empty()) {
2211 // Play new sound volume on older clients
2212 playSound(compat_psound.spec, compat_psound.params);
2216 void Server::sendRemoveNode(v3s16 p, std::unordered_set<u16> *far_players,
2219 float maxd = far_d_nodes * BS;
2220 v3f p_f = intToFloat(p, BS);
2221 v3s16 block_pos = getNodeBlockPos(p);
2223 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2226 std::vector<session_t> clients = m_clients.getClientIDs();
2229 for (session_t client_id : clients) {
2230 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
2234 RemotePlayer *player = m_env->getPlayer(client_id);
2235 PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr;
2237 // If player is far away, only set modified blocks not sent
2238 if (!client->isBlockSent(block_pos) || (sao &&
2239 sao->getBasePosition().getDistanceFrom(p_f) > maxd)) {
2241 far_players->emplace(client_id);
2243 client->SetBlockNotSent(block_pos);
2248 m_clients.send(client_id, 0, &pkt, true);
2254 void Server::sendAddNode(v3s16 p, MapNode n, std::unordered_set<u16> *far_players,
2255 float far_d_nodes, bool remove_metadata)
2257 float maxd = far_d_nodes * BS;
2258 v3f p_f = intToFloat(p, BS);
2259 v3s16 block_pos = getNodeBlockPos(p);
2261 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2262 pkt << p << n.param0 << n.param1 << n.param2
2263 << (u8) (remove_metadata ? 0 : 1);
2265 std::vector<session_t> clients = m_clients.getClientIDs();
2268 for (session_t client_id : clients) {
2269 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
2273 RemotePlayer *player = m_env->getPlayer(client_id);
2274 PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr;
2276 // If player is far away, only set modified blocks not sent
2277 if (!client->isBlockSent(block_pos) || (sao &&
2278 sao->getBasePosition().getDistanceFrom(p_f) > maxd)) {
2280 far_players->emplace(client_id);
2282 client->SetBlockNotSent(block_pos);
2287 m_clients.send(client_id, 0, &pkt, true);
2293 void Server::sendMetadataChanged(const std::list<v3s16> &meta_updates, float far_d_nodes)
2295 float maxd = far_d_nodes * BS;
2296 NodeMetadataList meta_updates_list(false);
2297 std::vector<session_t> clients = m_clients.getClientIDs();
2301 for (session_t i : clients) {
2302 RemoteClient *client = m_clients.lockedGetClientNoEx(i);
2306 ServerActiveObject *player = m_env->getActiveObject(i);
2307 v3f player_pos = player ? player->getBasePosition() : v3f();
2309 for (const v3s16 &pos : meta_updates) {
2310 NodeMetadata *meta = m_env->getMap().getNodeMetadata(pos);
2315 v3s16 block_pos = getNodeBlockPos(pos);
2316 if (!client->isBlockSent(block_pos) || (player &&
2317 player_pos.getDistanceFrom(intToFloat(pos, BS)) > maxd)) {
2318 client->SetBlockNotSent(block_pos);
2322 // Add the change to send list
2323 meta_updates_list.set(pos, meta);
2325 if (meta_updates_list.size() == 0)
2328 // Send the meta changes
2329 std::ostringstream os(std::ios::binary);
2330 meta_updates_list.serialize(os, client->net_proto_version, false, true);
2331 std::ostringstream oss(std::ios::binary);
2332 compressZlib(os.str(), oss);
2334 NetworkPacket pkt(TOCLIENT_NODEMETA_CHANGED, 0);
2335 pkt.putLongString(oss.str());
2336 m_clients.send(i, 0, &pkt, true);
2338 meta_updates_list.clear();
2344 void Server::SendBlockNoLock(session_t peer_id, MapBlock *block, u8 ver,
2345 u16 net_proto_version)
2348 Create a packet with the block in the right format
2351 std::ostringstream os(std::ios_base::binary);
2352 block->serialize(os, ver, false);
2353 block->serializeNetworkSpecific(os);
2354 std::string s = os.str();
2356 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2358 pkt << block->getPos();
2359 pkt.putRawString(s.c_str(), s.size());
2363 void Server::SendBlocks(float dtime)
2365 MutexAutoLock envlock(m_env_mutex);
2366 //TODO check if one big lock could be faster then multiple small ones
2368 std::vector<PrioritySortedBlockTransfer> queue;
2370 u32 total_sending = 0;
2373 ScopeProfiler sp2(g_profiler, "Server::SendBlocks(): Collect list");
2375 std::vector<session_t> clients = m_clients.getClientIDs();
2378 for (const session_t client_id : clients) {
2379 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id, CS_Active);
2384 total_sending += client->getSendingCount();
2385 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2391 // Lowest priority number comes first.
2392 // Lowest is most important.
2393 std::sort(queue.begin(), queue.end());
2397 // Maximal total count calculation
2398 // The per-client block sends is halved with the maximal online users
2399 u32 max_blocks_to_send = (m_env->getPlayerCount() + g_settings->getU32("max_users")) *
2400 g_settings->getU32("max_simultaneous_block_sends_per_client") / 4 + 1;
2402 ScopeProfiler sp(g_profiler, "Server::SendBlocks(): Send to clients");
2403 Map &map = m_env->getMap();
2405 for (const PrioritySortedBlockTransfer &block_to_send : queue) {
2406 if (total_sending >= max_blocks_to_send)
2409 MapBlock *block = map.getBlockNoCreateNoEx(block_to_send.pos);
2413 RemoteClient *client = m_clients.lockedGetClientNoEx(block_to_send.peer_id,
2418 SendBlockNoLock(block_to_send.peer_id, block, client->serialization_version,
2419 client->net_proto_version);
2421 client->SentBlock(block_to_send.pos);
2427 bool Server::SendBlock(session_t peer_id, const v3s16 &blockpos)
2429 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2434 RemoteClient *client = m_clients.lockedGetClientNoEx(peer_id, CS_Active);
2435 if (!client || client->isBlockSent(blockpos)) {
2439 SendBlockNoLock(peer_id, block, client->serialization_version,
2440 client->net_proto_version);
2446 void Server::fillMediaCache()
2448 infostream<<"Server: Calculating media file checksums"<<std::endl;
2450 // Collect all media file paths
2451 std::vector<std::string> paths;
2452 m_modmgr->getModsMediaPaths(paths);
2453 fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures");
2454 fs::GetRecursiveDirs(paths, porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2456 // Collect media file information from paths into cache
2457 for (const std::string &mediapath : paths) {
2458 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2459 for (const fs::DirListNode &dln : dirlist) {
2460 if (dln.dir) // Ignode dirs
2462 std::string filename = dln.name;
2463 // If name contains illegal characters, ignore the file
2464 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2465 infostream<<"Server: ignoring illegal file name: \""
2466 << filename << "\"" << std::endl;
2469 // If name is not in a supported format, ignore it
2470 const char *supported_ext[] = {
2471 ".png", ".jpg", ".bmp", ".tga",
2472 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2474 ".x", ".b3d", ".md2", ".obj",
2475 // Custom translation file format
2479 if (removeStringEnd(filename, supported_ext).empty()){
2480 infostream << "Server: ignoring unsupported file extension: \""
2481 << filename << "\"" << std::endl;
2484 // Ok, attempt to load the file and add to cache
2485 std::string filepath;
2486 filepath.append(mediapath).append(DIR_DELIM).append(filename);
2489 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2491 errorstream << "Server::fillMediaCache(): Could not open \""
2492 << filename << "\" for reading" << std::endl;
2495 std::ostringstream tmp_os(std::ios_base::binary);
2499 fis.read(buf, 1024);
2500 std::streamsize len = fis.gcount();
2501 tmp_os.write(buf, len);
2510 errorstream<<"Server::fillMediaCache(): Failed to read \""
2511 << filename << "\"" << std::endl;
2514 if(tmp_os.str().length() == 0) {
2515 errorstream << "Server::fillMediaCache(): Empty file \""
2516 << filepath << "\"" << std::endl;
2521 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2523 unsigned char *digest = sha1.getDigest();
2524 std::string sha1_base64 = base64_encode(digest, 20);
2525 std::string sha1_hex = hex_encode((char*)digest, 20);
2529 m_media[filename] = MediaInfo(filepath, sha1_base64);
2530 verbosestream << "Server: " << sha1_hex << " is " << filename
2536 void Server::sendMediaAnnouncement(session_t peer_id, const std::string &lang_code)
2538 verbosestream << "Server: Announcing files to id(" << peer_id << ")"
2542 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2545 std::string lang_suffix;
2546 lang_suffix.append(".").append(lang_code).append(".tr");
2547 for (const auto &i : m_media) {
2548 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2555 for (const auto &i : m_media) {
2556 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2558 pkt << i.first << i.second.sha1_digest;
2561 pkt << g_settings->get("remote_media");
2565 struct SendableMedia
2571 SendableMedia(const std::string &name_="", const std::string &path_="",
2572 const std::string &data_=""):
2579 void Server::sendRequestedMedia(session_t peer_id,
2580 const std::vector<std::string> &tosend)
2582 verbosestream<<"Server::sendRequestedMedia(): "
2583 <<"Sending files to client"<<std::endl;
2587 // Put 5kB in one bunch (this is not accurate)
2588 u32 bytes_per_bunch = 5000;
2590 std::vector< std::vector<SendableMedia> > file_bunches;
2591 file_bunches.emplace_back();
2593 u32 file_size_bunch_total = 0;
2595 for (const std::string &name : tosend) {
2596 if (m_media.find(name) == m_media.end()) {
2597 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2598 <<"unknown file \""<<(name)<<"\""<<std::endl;
2602 //TODO get path + name
2603 std::string tpath = m_media[name].path;
2606 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2608 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2609 <<tpath<<"\" for reading"<<std::endl;
2612 std::ostringstream tmp_os(std::ios_base::binary);
2616 fis.read(buf, 1024);
2617 std::streamsize len = fis.gcount();
2618 tmp_os.write(buf, len);
2619 file_size_bunch_total += len;
2628 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2629 <<name<<"\""<<std::endl;
2632 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2633 <<tname<<"\""<<std::endl;*/
2635 file_bunches[file_bunches.size()-1].emplace_back(name, tpath, tmp_os.str());
2637 // Start next bunch if got enough data
2638 if(file_size_bunch_total >= bytes_per_bunch) {
2639 file_bunches.emplace_back();
2640 file_size_bunch_total = 0;
2645 /* Create and send packets */
2647 u16 num_bunches = file_bunches.size();
2648 for (u16 i = 0; i < num_bunches; i++) {
2651 u16 total number of texture bunches
2652 u16 index of this bunch
2653 u32 number of files in this bunch
2662 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2663 pkt << num_bunches << i << (u32) file_bunches[i].size();
2665 for (const SendableMedia &j : file_bunches[i]) {
2667 pkt.putLongString(j.data);
2670 verbosestream << "Server::sendRequestedMedia(): bunch "
2671 << i << "/" << num_bunches
2672 << " files=" << file_bunches[i].size()
2673 << " size=" << pkt.getSize() << std::endl;
2678 void Server::sendDetachedInventory(const std::string &name, session_t peer_id)
2680 const auto &inv_it = m_detached_inventories.find(name);
2681 const auto &player_it = m_detached_inventories_player.find(name);
2683 if (player_it == m_detached_inventories_player.end() ||
2684 player_it->second.empty()) {
2685 // OK. Send to everyone
2688 return; // Mods are not done loading
2690 RemotePlayer *p = m_env->getPlayer(player_it->second.c_str());
2692 return; // Player is offline
2694 if (peer_id != PEER_ID_INEXISTENT && peer_id != p->getPeerId())
2695 return; // Caller requested send to a different player, so don't send.
2697 peer_id = p->getPeerId();
2700 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2703 if (inv_it == m_detached_inventories.end()) {
2704 pkt << false; // Remove inventory
2706 pkt << true; // Update inventory
2708 // Serialization & NetworkPacket isn't a love story
2709 std::ostringstream os(std::ios_base::binary);
2710 inv_it->second->serialize(os);
2711 inv_it->second->setModified(false);
2713 const std::string &os_str = os.str();
2714 pkt << static_cast<u16>(os_str.size()); // HACK: to keep compatibility with 5.0.0 clients
2715 pkt.putRawString(os_str);
2718 if (peer_id == PEER_ID_INEXISTENT)
2719 m_clients.sendToAll(&pkt);
2724 void Server::sendDetachedInventories(session_t peer_id, bool incremental)
2726 for (const auto &detached_inventory : m_detached_inventories) {
2727 const std::string &name = detached_inventory.first;
2729 Inventory *inv = detached_inventory.second;
2730 if (!inv || !inv->checkModified())
2734 sendDetachedInventory(name, peer_id);
2742 void Server::DiePlayer(session_t peer_id, const PlayerHPChangeReason &reason)
2744 PlayerSAO *playersao = getPlayerSAO(peer_id);
2747 infostream << "Server::DiePlayer(): Player "
2748 << playersao->getPlayer()->getName()
2749 << " dies" << std::endl;
2751 playersao->setHP(0, reason);
2752 playersao->clearParentAttachment();
2754 // Trigger scripted stuff
2755 m_script->on_dieplayer(playersao, reason);
2757 SendPlayerHP(peer_id);
2758 SendDeathscreen(peer_id, false, v3f(0,0,0));
2761 void Server::RespawnPlayer(session_t peer_id)
2763 PlayerSAO *playersao = getPlayerSAO(peer_id);
2766 infostream << "Server::RespawnPlayer(): Player "
2767 << playersao->getPlayer()->getName()
2768 << " respawns" << std::endl;
2770 playersao->setHP(playersao->accessObjectProperties()->hp_max,
2771 PlayerHPChangeReason(PlayerHPChangeReason::RESPAWN));
2772 playersao->setBreath(playersao->accessObjectProperties()->breath_max);
2774 bool repositioned = m_script->on_respawnplayer(playersao);
2775 if (!repositioned) {
2776 // setPos will send the new position to client
2777 playersao->setPos(findSpawnPos());
2780 SendPlayerHP(peer_id);
2784 void Server::DenySudoAccess(session_t peer_id)
2786 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2791 void Server::DenyAccessVerCompliant(session_t peer_id, u16 proto_ver, AccessDeniedCode reason,
2792 const std::string &str_reason, bool reconnect)
2794 SendAccessDenied(peer_id, reason, str_reason, reconnect);
2796 m_clients.event(peer_id, CSE_SetDenied);
2797 DisconnectPeer(peer_id);
2801 void Server::DenyAccess(session_t peer_id, AccessDeniedCode reason,
2802 const std::string &custom_reason)
2804 SendAccessDenied(peer_id, reason, custom_reason);
2805 m_clients.event(peer_id, CSE_SetDenied);
2806 DisconnectPeer(peer_id);
2809 // 13/03/15: remove this function when protocol version 25 will become
2810 // the minimum version for MT users, maybe in 1 year
2811 void Server::DenyAccess_Legacy(session_t peer_id, const std::wstring &reason)
2813 SendAccessDenied_Legacy(peer_id, reason);
2814 m_clients.event(peer_id, CSE_SetDenied);
2815 DisconnectPeer(peer_id);
2818 void Server::DisconnectPeer(session_t peer_id)
2820 m_modchannel_mgr->leaveAllChannels(peer_id);
2821 m_con->DisconnectPeer(peer_id);
2824 void Server::acceptAuth(session_t peer_id, bool forSudoMode)
2827 RemoteClient* client = getClient(peer_id, CS_Invalid);
2829 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2831 // Right now, the auth mechs don't change between login and sudo mode.
2832 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2833 client->allowed_sudo_mechs = sudo_auth_mechs;
2835 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2836 << g_settings->getFloat("dedicated_server_step")
2840 m_clients.event(peer_id, CSE_AuthAccept);
2842 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2844 // We only support SRP right now
2845 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2847 resp_pkt << sudo_auth_mechs;
2849 m_clients.event(peer_id, CSE_SudoSuccess);
2853 void Server::DeleteClient(session_t peer_id, ClientDeletionReason reason)
2855 std::wstring message;
2858 Clear references to playing sounds
2860 for (std::unordered_map<s32, ServerPlayingSound>::iterator
2861 i = m_playing_sounds.begin(); i != m_playing_sounds.end();) {
2862 ServerPlayingSound &psound = i->second;
2863 psound.clients.erase(peer_id);
2864 if (psound.clients.empty())
2865 m_playing_sounds.erase(i++);
2870 // clear formspec info so the next client can't abuse the current state
2871 m_formspec_state_data.erase(peer_id);
2873 RemotePlayer *player = m_env->getPlayer(peer_id);
2875 /* Run scripts and remove from environment */
2877 PlayerSAO *playersao = player->getPlayerSAO();
2880 playersao->clearChildAttachments();
2881 playersao->clearParentAttachment();
2883 // inform connected clients
2884 const std::string &player_name = player->getName();
2885 NetworkPacket notice(TOCLIENT_UPDATE_PLAYER_LIST, 0, PEER_ID_INEXISTENT);
2886 // (u16) 1 + std::string represents a vector serialization representation
2887 notice << (u8) PLAYER_LIST_REMOVE << (u16) 1 << player_name;
2888 m_clients.sendToAll(¬ice);
2890 m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
2892 playersao->disconnected();
2899 if (player && reason != CDR_DENY) {
2900 std::ostringstream os(std::ios_base::binary);
2901 std::vector<session_t> clients = m_clients.getClientIDs();
2903 for (const session_t client_id : clients) {
2905 RemotePlayer *player = m_env->getPlayer(client_id);
2909 // Get name of player
2910 os << player->getName() << " ";
2913 std::string name = player->getName();
2914 actionstream << name << " "
2915 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2916 << " List of players: " << os.str() << std::endl;
2918 m_admin_chat->outgoing_queue.push_back(
2919 new ChatEventNick(CET_NICK_REMOVE, name));
2923 MutexAutoLock env_lock(m_env_mutex);
2924 m_clients.DeleteClient(peer_id);
2928 // Send leave chat message to all remaining clients
2929 if (!message.empty()) {
2930 SendChatMessage(PEER_ID_INEXISTENT,
2931 ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE, message));
2935 void Server::UpdateCrafting(RemotePlayer *player)
2937 InventoryList *clist = player->inventory.getList("craft");
2938 if (!clist || clist->getSize() == 0)
2941 if (!clist->checkModified()) {
2942 verbosestream << "Skip Server::UpdateCrafting(): list unmodified" << std::endl;
2946 // Get a preview for crafting
2948 InventoryLocation loc;
2949 loc.setPlayer(player->getName());
2950 std::vector<ItemStack> output_replacements;
2951 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2952 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(),
2955 InventoryList *plist = player->inventory.getList("craftpreview");
2956 if (plist && plist->getSize() >= 1) {
2957 // Put the new preview in
2958 plist->changeItem(0, preview);
2962 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2964 if (evt->type == CET_NICK_ADD) {
2965 // The terminal informed us of its nick choice
2966 m_admin_nick = ((ChatEventNick *)evt)->nick;
2967 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2968 errorstream << "You haven't set up an account." << std::endl
2969 << "Please log in using the client as '"
2970 << m_admin_nick << "' with a secure password." << std::endl
2971 << "Until then, you can't execute admin tasks via the console," << std::endl
2972 << "and everybody can claim the user account instead of you," << std::endl
2973 << "giving them full control over this server." << std::endl;
2976 assert(evt->type == CET_CHAT);
2977 handleAdminChat((ChatEventChat *)evt);
2981 std::wstring Server::handleChat(const std::string &name, const std::wstring &wname,
2982 std::wstring wmessage, bool check_shout_priv, RemotePlayer *player)
2984 // If something goes wrong, this player is to blame
2985 RollbackScopeActor rollback_scope(m_rollback,
2986 std::string("player:") + name);
2988 if (g_settings->getBool("strip_color_codes"))
2989 wmessage = unescape_enriched(wmessage);
2992 switch (player->canSendChatMessage()) {
2993 case RPLAYER_CHATRESULT_FLOODING: {
2994 std::wstringstream ws;
2995 ws << L"You cannot send more messages. You are limited to "
2996 << g_settings->getFloat("chat_message_limit_per_10sec")
2997 << L" messages per 10 seconds.";
3000 case RPLAYER_CHATRESULT_KICK:
3001 DenyAccess_Legacy(player->getPeerId(),
3002 L"You have been kicked due to message flooding.");
3004 case RPLAYER_CHATRESULT_OK:
3007 FATAL_ERROR("Unhandled chat filtering result found.");
3011 if (m_max_chatmessage_length > 0
3012 && wmessage.length() > m_max_chatmessage_length) {
3013 return L"Your message exceed the maximum chat message limit set on the server. "
3014 L"It was refused. Send a shorter message";
3017 auto message = trim(wide_to_utf8(wmessage));
3018 if (message.find_first_of("\n\r") != std::wstring::npos) {
3019 return L"New lines are not permitted in chat messages";
3022 // Run script hook, exit if script ate the chat message
3023 if (m_script->on_chat_message(name, message))
3028 // Whether to send line to the player that sent the message, or to all players
3029 bool broadcast_line = true;
3031 if (check_shout_priv && !checkPriv(name, "shout")) {
3032 line += L"-!- You don't have permission to shout.";
3033 broadcast_line = false;
3035 line += narrow_to_wide(m_script->formatChatMessage(name,
3036 wide_to_narrow(wmessage)));
3040 Tell calling method to send the message to sender
3042 if (!broadcast_line)
3046 Send the message to others
3048 actionstream << "CHAT: " << wide_to_narrow(unescape_enriched(line)) << std::endl;
3050 std::vector<session_t> clients = m_clients.getClientIDs();
3053 Send the message back to the inital sender
3054 if they are using protocol version >= 29
3057 session_t peer_id_to_avoid_sending =
3058 (player ? player->getPeerId() : PEER_ID_INEXISTENT);
3060 if (player && player->protocol_version >= 29)
3061 peer_id_to_avoid_sending = PEER_ID_INEXISTENT;
3063 for (u16 cid : clients) {
3064 if (cid != peer_id_to_avoid_sending)
3065 SendChatMessage(cid, ChatMessage(line));
3070 void Server::handleAdminChat(const ChatEventChat *evt)
3072 std::string name = evt->nick;
3073 std::wstring wname = utf8_to_wide(name);
3074 std::wstring wmessage = evt->evt_msg;
3076 std::wstring answer = handleChat(name, wname, wmessage);
3078 // If asked to send answer to sender
3079 if (!answer.empty()) {
3080 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
3084 RemoteClient *Server::getClient(session_t peer_id, ClientState state_min)
3086 RemoteClient *client = getClientNoEx(peer_id,state_min);
3088 throw ClientNotFoundException("Client not found");
3092 RemoteClient *Server::getClientNoEx(session_t peer_id, ClientState state_min)
3094 return m_clients.getClientNoEx(peer_id, state_min);
3097 std::string Server::getPlayerName(session_t peer_id)
3099 RemotePlayer *player = m_env->getPlayer(peer_id);
3101 return "[id="+itos(peer_id)+"]";
3102 return player->getName();
3105 PlayerSAO *Server::getPlayerSAO(session_t peer_id)
3107 RemotePlayer *player = m_env->getPlayer(peer_id);
3110 return player->getPlayerSAO();
3113 std::wstring Server::getStatusString()
3115 std::wostringstream os(std::ios_base::binary);
3116 os << L"# Server: ";
3118 os << L"version=" << narrow_to_wide(g_version_string);
3120 os << L", uptime=" << m_uptime.get();
3122 os << L", max_lag=" << (m_env ? m_env->getMaxLagEstimate() : 0);
3124 // Information about clients
3126 os << L", clients={";
3128 std::vector<session_t> clients = m_clients.getClientIDs();
3129 for (session_t client_id : clients) {
3130 RemotePlayer *player = m_env->getPlayer(client_id);
3132 // Get name of player
3133 std::wstring name = L"unknown";
3135 name = narrow_to_wide(player->getName());
3137 // Add name to information string
3148 if (m_env && !((ServerMap*)(&m_env->getMap()))->isSavingEnabled())
3149 os << std::endl << L"# Server: " << " WARNING: Map saving is disabled.";
3151 if (!g_settings->get("motd").empty())
3152 os << std::endl << L"# Server: " << narrow_to_wide(g_settings->get("motd"));
3157 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
3159 std::set<std::string> privs;
3160 m_script->getAuth(name, NULL, &privs);
3164 bool Server::checkPriv(const std::string &name, const std::string &priv)
3166 std::set<std::string> privs = getPlayerEffectivePrivs(name);
3167 return (privs.count(priv) != 0);
3170 void Server::reportPrivsModified(const std::string &name)
3173 std::vector<session_t> clients = m_clients.getClientIDs();
3174 for (const session_t client_id : clients) {
3175 RemotePlayer *player = m_env->getPlayer(client_id);
3176 reportPrivsModified(player->getName());
3179 RemotePlayer *player = m_env->getPlayer(name.c_str());
3182 SendPlayerPrivileges(player->getPeerId());
3183 PlayerSAO *sao = player->getPlayerSAO();
3186 sao->updatePrivileges(
3187 getPlayerEffectivePrivs(name),
3192 void Server::reportInventoryFormspecModified(const std::string &name)
3194 RemotePlayer *player = m_env->getPlayer(name.c_str());
3197 SendPlayerInventoryFormspec(player->getPeerId());
3200 void Server::reportFormspecPrependModified(const std::string &name)
3202 RemotePlayer *player = m_env->getPlayer(name.c_str());
3205 SendPlayerFormspecPrepend(player->getPeerId());
3208 void Server::setIpBanned(const std::string &ip, const std::string &name)
3210 m_banmanager->add(ip, name);
3213 void Server::unsetIpBanned(const std::string &ip_or_name)
3215 m_banmanager->remove(ip_or_name);
3218 std::string Server::getBanDescription(const std::string &ip_or_name)
3220 return m_banmanager->getBanDescription(ip_or_name);
3223 void Server::notifyPlayer(const char *name, const std::wstring &msg)
3225 // m_env will be NULL if the server is initializing
3229 if (m_admin_nick == name && !m_admin_nick.empty()) {
3230 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
3233 RemotePlayer *player = m_env->getPlayer(name);
3238 if (player->getPeerId() == PEER_ID_INEXISTENT)
3241 SendChatMessage(player->getPeerId(), ChatMessage(msg));
3244 bool Server::showFormspec(const char *playername, const std::string &formspec,
3245 const std::string &formname)
3247 // m_env will be NULL if the server is initializing
3251 RemotePlayer *player = m_env->getPlayer(playername);
3255 SendShowFormspecMessage(player->getPeerId(), formspec, formname);
3259 u32 Server::hudAdd(RemotePlayer *player, HudElement *form)
3264 u32 id = player->addHud(form);
3266 SendHUDAdd(player->getPeerId(), id, form);
3271 bool Server::hudRemove(RemotePlayer *player, u32 id) {
3275 HudElement* todel = player->removeHud(id);
3282 SendHUDRemove(player->getPeerId(), id);
3286 bool Server::hudChange(RemotePlayer *player, u32 id, HudElementStat stat, void *data)
3291 SendHUDChange(player->getPeerId(), id, stat, data);
3295 bool Server::hudSetFlags(RemotePlayer *player, u32 flags, u32 mask)
3300 SendHUDSetFlags(player->getPeerId(), flags, mask);
3301 player->hud_flags &= ~mask;
3302 player->hud_flags |= flags;
3304 PlayerSAO* playersao = player->getPlayerSAO();
3309 m_script->player_event(playersao, "hud_changed");
3313 bool Server::hudSetHotbarItemcount(RemotePlayer *player, s32 hotbar_itemcount)
3318 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3321 player->setHotbarItemcount(hotbar_itemcount);
3322 std::ostringstream os(std::ios::binary);
3323 writeS32(os, hotbar_itemcount);
3324 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3328 void Server::hudSetHotbarImage(RemotePlayer *player, const std::string &name)
3333 player->setHotbarImage(name);
3334 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_IMAGE, name);
3337 void Server::hudSetHotbarSelectedImage(RemotePlayer *player, const std::string &name)
3342 player->setHotbarSelectedImage(name);
3343 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3346 Address Server::getPeerAddress(session_t peer_id)
3348 return m_con->GetPeerAddress(peer_id);
3351 void Server::setLocalPlayerAnimations(RemotePlayer *player,
3352 v2s32 animation_frames[4], f32 frame_speed)
3354 sanity_check(player);
3355 player->setLocalAnimations(animation_frames, frame_speed);
3356 SendLocalPlayerAnimations(player->getPeerId(), animation_frames, frame_speed);
3359 void Server::setPlayerEyeOffset(RemotePlayer *player, const v3f &first, const v3f &third)
3361 sanity_check(player);
3362 player->eye_offset_first = first;
3363 player->eye_offset_third = third;
3364 SendEyeOffset(player->getPeerId(), first, third);
3367 void Server::setSky(RemotePlayer *player, const SkyboxParams ¶ms)
3369 sanity_check(player);
3370 player->setSky(params);
3371 SendSetSky(player->getPeerId(), params);
3374 void Server::setSun(RemotePlayer *player, const SunParams ¶ms)
3376 sanity_check(player);
3377 player->setSun(params);
3378 SendSetSun(player->getPeerId(), params);
3381 void Server::setMoon(RemotePlayer *player, const MoonParams ¶ms)
3383 sanity_check(player);
3384 player->setMoon(params);
3385 SendSetMoon(player->getPeerId(), params);
3388 void Server::setStars(RemotePlayer *player, const StarParams ¶ms)
3390 sanity_check(player);
3391 player->setStars(params);
3392 SendSetStars(player->getPeerId(), params);
3395 void Server::setClouds(RemotePlayer *player, const CloudParams ¶ms)
3397 sanity_check(player);
3398 player->setCloudParams(params);
3399 SendCloudParams(player->getPeerId(), params);
3402 bool Server::overrideDayNightRatio(RemotePlayer *player, bool do_override,
3408 player->overrideDayNightRatio(do_override, ratio);
3409 SendOverrideDayNightRatio(player->getPeerId(), do_override, ratio);
3413 void Server::notifyPlayers(const std::wstring &msg)
3415 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(msg));
3418 void Server::spawnParticle(const std::string &playername, v3f pos,
3419 v3f velocity, v3f acceleration,
3420 float expirationtime, float size, bool
3421 collisiondetection, bool collision_removal, bool object_collision,
3422 bool vertical, const std::string &texture,
3423 const struct TileAnimationParams &animation, u8 glow)
3425 // m_env will be NULL if the server is initializing
3429 session_t peer_id = PEER_ID_INEXISTENT;
3431 if (!playername.empty()) {
3432 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3435 peer_id = player->getPeerId();
3436 proto_ver = player->protocol_version;
3439 SendSpawnParticle(peer_id, proto_ver, pos, velocity, acceleration,
3440 expirationtime, size, collisiondetection, collision_removal,
3441 object_collision, vertical, texture, animation, glow);
3444 u32 Server::addParticleSpawner(u16 amount, float spawntime,
3445 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
3446 float minexptime, float maxexptime, float minsize, float maxsize,
3447 bool collisiondetection, bool collision_removal, bool object_collision,
3448 ServerActiveObject *attached, bool vertical, const std::string &texture,
3449 const std::string &playername, const struct TileAnimationParams &animation,
3452 // m_env will be NULL if the server is initializing
3456 session_t peer_id = PEER_ID_INEXISTENT;
3458 if (!playername.empty()) {
3459 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3462 peer_id = player->getPeerId();
3463 proto_ver = player->protocol_version;
3466 u16 attached_id = attached ? attached->getId() : 0;
3469 if (attached_id == 0)
3470 id = m_env->addParticleSpawner(spawntime);
3472 id = m_env->addParticleSpawner(spawntime, attached_id);
3474 SendAddParticleSpawner(peer_id, proto_ver, amount, spawntime,
3475 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3476 minexptime, maxexptime, minsize, maxsize, collisiondetection,
3477 collision_removal, object_collision, attached_id, vertical,
3478 texture, id, animation, glow);
3483 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3485 // m_env will be NULL if the server is initializing
3487 throw ServerError("Can't delete particle spawners during initialisation!");
3489 session_t peer_id = PEER_ID_INEXISTENT;
3490 if (!playername.empty()) {
3491 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3494 peer_id = player->getPeerId();
3497 m_env->deleteParticleSpawner(id);
3498 SendDeleteParticleSpawner(peer_id, id);
3501 Inventory* Server::createDetachedInventory(const std::string &name, const std::string &player)
3503 if(m_detached_inventories.count(name) > 0){
3504 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3505 delete m_detached_inventories[name];
3507 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3509 Inventory *inv = new Inventory(m_itemdef);
3511 m_detached_inventories[name] = inv;
3512 if (!player.empty())
3513 m_detached_inventories_player[name] = player;
3515 //TODO find a better way to do this
3516 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3520 bool Server::removeDetachedInventory(const std::string &name)
3522 const auto &inv_it = m_detached_inventories.find(name);
3523 if (inv_it == m_detached_inventories.end())
3526 delete inv_it->second;
3527 m_detached_inventories.erase(inv_it);
3529 if (!m_env) // Mods are not done loading
3532 const auto &player_it = m_detached_inventories_player.find(name);
3533 if (player_it != m_detached_inventories_player.end()) {
3534 RemotePlayer *player = m_env->getPlayer(player_it->second.c_str());
3536 if (player && player->getPeerId() != PEER_ID_INEXISTENT)
3537 sendDetachedInventory(name, player->getPeerId());
3539 m_detached_inventories_player.erase(player_it);
3541 // Notify all players about the change
3542 sendDetachedInventory(name, PEER_ID_INEXISTENT);
3547 // actions: time-reversed list
3548 // Return value: success/failure
3549 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3550 std::list<std::string> *log)
3552 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3553 ServerMap *map = (ServerMap*)(&m_env->getMap());
3555 // Fail if no actions to handle
3556 if (actions.empty()) {
3558 log->push_back("Nothing to do.");
3565 for (const RollbackAction &action : actions) {
3567 bool success = action.applyRevert(map, this, this);
3570 std::ostringstream os;
3571 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3572 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3574 log->push_back(os.str());
3576 std::ostringstream os;
3577 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3578 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3580 log->push_back(os.str());
3584 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3585 <<" failed"<<std::endl;
3587 // Call it done if less than half failed
3588 return num_failed <= num_tried/2;
3591 // IGameDef interface
3593 IItemDefManager *Server::getItemDefManager()
3598 const NodeDefManager *Server::getNodeDefManager()
3603 ICraftDefManager *Server::getCraftDefManager()
3608 u16 Server::allocateUnknownNodeId(const std::string &name)
3610 return m_nodedef->allocateDummy(name);
3613 IWritableItemDefManager *Server::getWritableItemDefManager()
3618 NodeDefManager *Server::getWritableNodeDefManager()
3623 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3628 const std::vector<ModSpec> & Server::getMods() const
3630 return m_modmgr->getMods();
3633 const ModSpec *Server::getModSpec(const std::string &modname) const
3635 return m_modmgr->getModSpec(modname);
3638 void Server::getModNames(std::vector<std::string> &modlist)
3640 m_modmgr->getModNames(modlist);
3643 std::string Server::getBuiltinLuaPath()
3645 return porting::path_share + DIR_DELIM + "builtin";
3648 std::string Server::getModStoragePath() const
3650 return m_path_world + DIR_DELIM + "mod_storage";
3653 v3f Server::findSpawnPos()
3655 ServerMap &map = m_env->getServerMap();
3657 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf))
3658 return nodeposf * BS;
3660 bool is_good = false;
3661 // Limit spawn range to mapgen edges (determined by 'mapgen_limit')
3662 s32 range_max = map.getMapgenParams()->getSpawnRangeMax();
3664 // Try to find a good place a few times
3665 for (s32 i = 0; i < 4000 && !is_good; i++) {
3666 s32 range = MYMIN(1 + i, range_max);
3667 // We're going to try to throw the player to this position
3668 v2s16 nodepos2d = v2s16(
3669 -range + (myrand() % (range * 2)),
3670 -range + (myrand() % (range * 2)));
3671 // Get spawn level at point
3672 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3673 // Continue if MAX_MAP_GENERATION_LIMIT was returned by the mapgen to
3674 // signify an unsuitable spawn position, or if outside limits.
3675 if (spawn_level >= MAX_MAP_GENERATION_LIMIT ||
3676 spawn_level <= -MAX_MAP_GENERATION_LIMIT)
3679 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3680 // Consecutive empty nodes
3683 // Search upwards from 'spawn level' for 2 consecutive empty nodes, to
3684 // avoid obstructions in already-generated mapblocks.
3685 // In ungenerated mapblocks consisting of 'ignore' nodes, there will be
3686 // no obstructions, but mapgen decorations are generated after spawn so
3687 // the player may end up inside one.
3688 for (s32 i = 0; i < 8; i++) {
3689 v3s16 blockpos = getNodeBlockPos(nodepos);
3690 map.emergeBlock(blockpos, true);
3691 content_t c = map.getNode(nodepos).getContent();
3693 // In generated mapblocks allow spawn in all 'airlike' drawtype nodes.
3694 // In ungenerated mapblocks allow spawn in 'ignore' nodes.
3695 if (m_nodedef->get(c).drawtype == NDT_AIRLIKE || c == CONTENT_IGNORE) {
3697 if (air_count >= 2) {
3698 // Spawn in lower empty node
3700 nodeposf = intToFloat(nodepos, BS);
3701 // Don't spawn the player outside map boundaries
3702 if (objectpos_over_limit(nodeposf))
3703 // Exit this loop, positions above are probably over limit
3706 // Good position found, cause an exit from main loop
3720 // No suitable spawn point found, return fallback 0,0,0
3721 return v3f(0.0f, 0.0f, 0.0f);
3724 void Server::requestShutdown(const std::string &msg, bool reconnect, float delay)
3726 if (delay == 0.0f) {
3727 // No delay, shutdown immediately
3728 m_shutdown_state.is_requested = true;
3729 // only print to the infostream, a chat message saying
3730 // "Server Shutting Down" is sent when the server destructs.
3731 infostream << "*** Immediate Server shutdown requested." << std::endl;
3732 } else if (delay < 0.0f && m_shutdown_state.isTimerRunning()) {
3733 // Negative delay, cancel shutdown if requested
3734 m_shutdown_state.reset();
3735 std::wstringstream ws;
3737 ws << L"*** Server shutdown canceled.";
3739 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3740 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3741 // m_shutdown_* are already handled, skip.
3743 } else if (delay > 0.0f) {
3744 // Positive delay, tell the clients when the server will shut down
3745 std::wstringstream ws;
3747 ws << L"*** Server shutting down in "
3748 << duration_to_string(myround(delay)).c_str()
3751 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3752 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3755 m_shutdown_state.trigger(delay, msg, reconnect);
3758 PlayerSAO* Server::emergePlayer(const char *name, session_t peer_id, u16 proto_version)
3761 Try to get an existing player
3763 RemotePlayer *player = m_env->getPlayer(name);
3765 // If player is already connected, cancel
3766 if (player && player->getPeerId() != PEER_ID_INEXISTENT) {
3767 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3772 If player with the wanted peer_id already exists, cancel.
3774 if (m_env->getPlayer(peer_id)) {
3775 infostream<<"emergePlayer(): Player with wrong name but same"
3776 " peer_id already exists"<<std::endl;
3781 player = new RemotePlayer(name, idef());
3784 bool newplayer = false;
3787 PlayerSAO *playersao = m_env->loadPlayer(player, &newplayer, peer_id, isSingleplayer());
3789 // Complete init with server parts
3790 playersao->finalize(player, getPlayerEffectivePrivs(player->getName()));
3791 player->protocol_version = proto_version;
3795 m_script->on_newplayer(playersao);
3801 bool Server::registerModStorage(ModMetadata *storage)
3803 if (m_mod_storages.find(storage->getModName()) != m_mod_storages.end()) {
3804 errorstream << "Unable to register same mod storage twice. Storage name: "
3805 << storage->getModName() << std::endl;
3809 m_mod_storages[storage->getModName()] = storage;
3813 void Server::unregisterModStorage(const std::string &name)
3815 std::unordered_map<std::string, ModMetadata *>::const_iterator it = m_mod_storages.find(name);
3816 if (it != m_mod_storages.end()) {
3817 // Save unconditionaly on unregistration
3818 it->second->save(getModStoragePath());
3819 m_mod_storages.erase(name);
3823 void dedicated_server_loop(Server &server, bool &kill)
3825 verbosestream<<"dedicated_server_loop()"<<std::endl;
3827 IntervalLimiter m_profiler_interval;
3829 static thread_local const float steplen =
3830 g_settings->getFloat("dedicated_server_step");
3831 static thread_local const float profiler_print_interval =
3832 g_settings->getFloat("profiler_print_interval");
3835 * The dedicated server loop only does time-keeping (in Server::step) and
3836 * provides a way to main.cpp to kill the server externally (bool &kill).
3840 // This is kind of a hack but can be done like this
3841 // because server.step() is very light
3842 sleep_ms((int)(steplen*1000.0));
3843 server.step(steplen);
3845 if (server.isShutdownRequested() || kill)
3851 if (profiler_print_interval != 0) {
3852 if(m_profiler_interval.step(steplen, profiler_print_interval))
3854 infostream<<"Profiler:"<<std::endl;
3855 g_profiler->print(infostream);
3856 g_profiler->clear();
3861 infostream << "Dedicated server quitting" << std::endl;
3863 if (g_settings->getBool("server_announce"))
3864 ServerList::sendAnnounce(ServerList::AA_DELETE,
3865 server.m_bind_addr.getPort());
3874 bool Server::joinModChannel(const std::string &channel)
3876 return m_modchannel_mgr->joinChannel(channel, PEER_ID_SERVER) &&
3877 m_modchannel_mgr->setChannelState(channel, MODCHANNEL_STATE_READ_WRITE);
3880 bool Server::leaveModChannel(const std::string &channel)
3882 return m_modchannel_mgr->leaveChannel(channel, PEER_ID_SERVER);
3885 bool Server::sendModChannelMessage(const std::string &channel, const std::string &message)
3887 if (!m_modchannel_mgr->canWriteOnChannel(channel))
3890 broadcastModChannelMessage(channel, message, PEER_ID_SERVER);
3894 ModChannel* Server::getModChannel(const std::string &channel)
3896 return m_modchannel_mgr->getModChannel(channel);
3899 void Server::broadcastModChannelMessage(const std::string &channel,
3900 const std::string &message, session_t from_peer)
3902 const std::vector<u16> &peers = m_modchannel_mgr->getChannelPeers(channel);
3906 if (message.size() > STRING_MAX_LEN) {
3907 warningstream << "ModChannel message too long, dropping before sending "
3908 << " (" << message.size() << " > " << STRING_MAX_LEN << ", channel: "
3909 << channel << ")" << std::endl;
3914 if (from_peer != PEER_ID_SERVER) {
3915 sender = getPlayerName(from_peer);
3918 NetworkPacket resp_pkt(TOCLIENT_MODCHANNEL_MSG,
3919 2 + channel.size() + 2 + sender.size() + 2 + message.size());
3920 resp_pkt << channel << sender << message;
3921 for (session_t peer_id : peers) {
3923 if (peer_id == from_peer)
3926 Send(peer_id, &resp_pkt);
3929 if (from_peer != PEER_ID_SERVER) {
3930 m_script->on_modchannel_message(channel, sender, message);