3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include "network/connection.h"
25 #include "network/networkprotocol.h"
26 #include "network/serveropcodes.h"
28 #include "environment.h"
30 #include "threading/mutex_auto_lock.h"
31 #include "constants.h"
37 #include "server/serveractiveobject.h"
41 #include "scripting_server.h"
46 #include "mapgen/mapgen.h"
47 #include "mapgen/mg_biome.h"
48 #include "content_mapnode.h"
49 #include "content_nodemeta.h"
50 #include "content/mods.h"
51 #include "modchannels.h"
52 #include "serverlist.h"
53 #include "util/string.h"
55 #include "util/serialize.h"
56 #include "util/thread.h"
57 #include "defaultsettings.h"
58 #include "server/mods.h"
59 #include "util/base64.h"
60 #include "util/sha1.h"
62 #include "database/database.h"
63 #include "chatmessage.h"
64 #include "chat_interface.h"
65 #include "remoteplayer.h"
66 #include "server/player_sao.h"
68 class ClientNotFoundException : public BaseException
71 ClientNotFoundException(const char *s):
76 class ServerThread : public Thread
80 ServerThread(Server *server):
91 void *ServerThread::run()
93 BEGIN_DEBUG_EXCEPTION_HANDLER
96 * The real business of the server happens on the ServerThread.
98 * AsyncRunStep() runs an actual server step as soon as enough time has
99 * passed (dedicated_server_loop keeps track of that).
100 * Receive() blocks at least(!) 30ms waiting for a packet (so this loop
101 * doesn't busy wait) and will process any remaining packets.
104 m_server->AsyncRunStep(true);
106 while (!stopRequested()) {
108 m_server->AsyncRunStep();
112 } catch (con::PeerNotFoundException &e) {
113 infostream<<"Server: PeerNotFoundException"<<std::endl;
114 } catch (ClientNotFoundException &e) {
115 } catch (con::ConnectionBindFailed &e) {
116 m_server->setAsyncFatalError(e.what());
117 } catch (LuaError &e) {
118 m_server->setAsyncFatalError(
119 "ServerThread::run Lua: " + std::string(e.what()));
123 END_DEBUG_EXCEPTION_HANDLER
128 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
130 if(pos_exists) *pos_exists = false;
135 if(pos_exists) *pos_exists = true;
140 ServerActiveObject *sao = env->getActiveObject(object);
143 if(pos_exists) *pos_exists = true;
144 return sao->getBasePosition(); }
149 void Server::ShutdownState::reset()
153 should_reconnect = false;
154 is_requested = false;
157 void Server::ShutdownState::trigger(float delay, const std::string &msg, bool reconnect)
161 should_reconnect = reconnect;
164 void Server::ShutdownState::tick(float dtime, Server *server)
170 static const float shutdown_msg_times[] =
172 1, 2, 3, 4, 5, 10, 20, 40, 60, 120, 180, 300, 600, 1200, 1800, 3600
175 // Automated messages
176 if (m_timer < shutdown_msg_times[ARRLEN(shutdown_msg_times) - 1]) {
177 for (float t : shutdown_msg_times) {
178 // If shutdown timer matches an automessage, shot it
179 if (m_timer > t && m_timer - dtime < t) {
180 std::wstring periodicMsg = getShutdownTimerMessage();
182 infostream << wide_to_utf8(periodicMsg).c_str() << std::endl;
183 server->SendChatMessage(PEER_ID_INEXISTENT, periodicMsg);
190 if (m_timer < 0.0f) {
196 std::wstring Server::ShutdownState::getShutdownTimerMessage() const
198 std::wstringstream ws;
199 ws << L"*** Server shutting down in "
200 << duration_to_string(myround(m_timer)).c_str() << ".";
209 const std::string &path_world,
210 const SubgameSpec &gamespec,
211 bool simple_singleplayer_mode,
216 m_bind_addr(bind_addr),
217 m_path_world(path_world),
218 m_gamespec(gamespec),
219 m_simple_singleplayer_mode(simple_singleplayer_mode),
220 m_dedicated(dedicated),
221 m_async_fatal_error(""),
222 m_con(std::make_shared<con::Connection>(PROTOCOL_ID,
225 m_bind_addr.isIPv6(),
227 m_itemdef(createItemDefManager()),
228 m_nodedef(createNodeDefManager()),
229 m_craftdef(createCraftDefManager()),
230 m_thread(new ServerThread(this)),
234 m_modchannel_mgr(new ModChannelMgr())
236 m_lag = g_settings->getFloat("dedicated_server_step");
238 if (m_path_world.empty())
239 throw ServerError("Supplied empty world path");
241 if (!gamespec.isValid())
242 throw ServerError("Supplied invalid gamespec");
248 // Send shutdown message
249 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE,
250 L"*** Server shutting down"));
253 MutexAutoLock envlock(m_env_mutex);
255 infostream << "Server: Saving players" << std::endl;
256 m_env->saveLoadedPlayers();
258 infostream << "Server: Kicking players" << std::endl;
259 std::string kick_msg;
260 bool reconnect = false;
261 if (isShutdownRequested()) {
262 reconnect = m_shutdown_state.should_reconnect;
263 kick_msg = m_shutdown_state.message;
265 if (kick_msg.empty()) {
266 kick_msg = g_settings->get("kick_msg_shutdown");
268 m_env->saveLoadedPlayers(true);
269 m_env->kickAllPlayers(SERVER_ACCESSDENIED_SHUTDOWN,
270 kick_msg, reconnect);
273 actionstream << "Server: Shutting down" << std::endl;
275 // Do this before stopping the server in case mapgen callbacks need to access
276 // server-controlled resources (like ModStorages). Also do them before
277 // shutdown callbacks since they may modify state that is finalized in a
280 m_emerge->stopThreads();
283 MutexAutoLock envlock(m_env_mutex);
285 // Execute script shutdown hooks
286 infostream << "Executing shutdown hooks" << std::endl;
287 m_script->on_shutdown();
289 infostream << "Server: Saving environment metadata" << std::endl;
299 // Delete things in the reverse order of creation
308 // Deinitialize scripting
309 infostream << "Server: Deinitializing scripting" << std::endl;
312 // Delete detached inventories
313 for (auto &detached_inventory : m_detached_inventories) {
314 delete detached_inventory.second;
317 while (!m_unsent_map_edit_queue.empty()) {
318 delete m_unsent_map_edit_queue.front();
319 m_unsent_map_edit_queue.pop();
325 infostream << "Server created for gameid \"" << m_gamespec.id << "\"";
326 if (m_simple_singleplayer_mode)
327 infostream << " in simple singleplayer mode" << std::endl;
329 infostream << std::endl;
330 infostream << "- world: " << m_path_world << std::endl;
331 infostream << "- game: " << m_gamespec.path << std::endl;
333 // Create world if it doesn't exist
334 if (!loadGameConfAndInitWorld(m_path_world, m_gamespec))
335 throw ServerError("Failed to initialize world");
337 // Create emerge manager
338 m_emerge = new EmergeManager(this);
340 // Create ban manager
341 std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
342 m_banmanager = new BanManager(ban_path);
344 m_modmgr = std::unique_ptr<ServerModManager>(new ServerModManager(m_path_world));
345 std::vector<ModSpec> unsatisfied_mods = m_modmgr->getUnsatisfiedMods();
346 // complain about mods with unsatisfied dependencies
347 if (!m_modmgr->isConsistent()) {
348 m_modmgr->printUnsatisfiedModsError();
352 MutexAutoLock envlock(m_env_mutex);
354 // Create the Map (loads map_meta.txt, overriding configured mapgen params)
355 ServerMap *servermap = new ServerMap(m_path_world, this, m_emerge);
357 // Initialize scripting
358 infostream << "Server: Initializing Lua" << std::endl;
360 m_script = new ServerScripting(this);
362 m_script->loadMod(getBuiltinLuaPath() + DIR_DELIM "init.lua", BUILTIN_MOD_NAME);
364 m_modmgr->loadMods(m_script);
366 // Read Textures and calculate sha1 sums
369 // Apply item aliases in the node definition manager
370 m_nodedef->updateAliases(m_itemdef);
372 // Apply texture overrides from texturepack/override.txt
373 std::vector<std::string> paths;
374 fs::GetRecursiveDirs(paths, g_settings->get("texture_path"));
375 fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures");
376 for (const std::string &path : paths) {
377 TextureOverrideSource override_source(path + DIR_DELIM + "override.txt");
378 m_nodedef->applyTextureOverrides(override_source.getNodeTileOverrides());
379 m_itemdef->applyTextureOverrides(override_source.getItemTextureOverrides());
382 m_nodedef->setNodeRegistrationStatus(true);
384 // Perform pending node name resolutions
385 m_nodedef->runNodeResolveCallbacks();
387 // unmap node names for connected nodeboxes
388 m_nodedef->mapNodeboxConnections();
390 // init the recipe hashes to speed up crafting
391 m_craftdef->initHashes(this);
393 // Initialize Environment
394 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
396 m_clients.setEnv(m_env);
398 if (!servermap->settings_mgr.makeMapgenParams())
399 FATAL_ERROR("Couldn't create any mapgen type");
401 // Initialize mapgens
402 m_emerge->initMapgens(servermap->getMapgenParams());
404 if (g_settings->getBool("enable_rollback_recording")) {
405 // Create rollback manager
406 m_rollback = new RollbackManager(m_path_world, this);
409 // Give environment reference to scripting api
410 m_script->initializeEnvironment(m_env);
412 // Register us to receive map edit events
413 servermap->addEventReceiver(this);
417 m_liquid_transform_every = g_settings->getFloat("liquid_update");
418 m_max_chatmessage_length = g_settings->getU16("chat_message_max_size");
419 m_csm_restriction_flags = g_settings->getU64("csm_restriction_flags");
420 m_csm_restriction_noderange = g_settings->getU32("csm_restriction_noderange");
425 infostream << "Starting server on " << m_bind_addr.serializeString()
426 << "..." << std::endl;
428 // Stop thread if already running
431 // Initialize connection
432 m_con->SetTimeoutMs(30);
433 m_con->Serve(m_bind_addr);
438 // ASCII art for the win!
440 << " .__ __ __ " << std::endl
441 << " _____ |__| ____ _____/ |_ ____ _______/ |_ " << std::endl
442 << " / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\" << std::endl
443 << "| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | " << std::endl
444 << "|__|_| /__|___| /\\___ >__| \\___ >____ > |__| " << std::endl
445 << " \\/ \\/ \\/ \\/ \\/ " << std::endl;
446 actionstream << "World at [" << m_path_world << "]" << std::endl;
447 actionstream << "Server for gameid=\"" << m_gamespec.id
448 << "\" listening on " << m_bind_addr.serializeString() << ":"
449 << m_bind_addr.getPort() << "." << std::endl;
454 infostream<<"Server: Stopping and waiting threads"<<std::endl;
456 // Stop threads (set run=false first so both start stopping)
458 //m_emergethread.setRun(false);
460 //m_emergethread.stop();
462 infostream<<"Server: Threads stopped"<<std::endl;
465 void Server::step(float dtime)
471 MutexAutoLock lock(m_step_dtime_mutex);
472 m_step_dtime += dtime;
474 // Throw if fatal error occurred in thread
475 std::string async_err = m_async_fatal_error.get();
476 if (!async_err.empty()) {
477 if (!m_simple_singleplayer_mode) {
478 m_env->kickAllPlayers(SERVER_ACCESSDENIED_CRASH,
479 g_settings->get("kick_msg_crash"),
480 g_settings->getBool("ask_reconnect_on_crash"));
482 throw ServerError("AsyncErr: " + async_err);
486 void Server::AsyncRunStep(bool initial_step)
491 MutexAutoLock lock1(m_step_dtime_mutex);
492 dtime = m_step_dtime;
496 // Send blocks to clients
500 if((dtime < 0.001) && !initial_step)
503 ScopeProfiler sp(g_profiler, "Server::AsyncRunStep()", SPT_AVG);
506 MutexAutoLock lock1(m_step_dtime_mutex);
507 m_step_dtime -= dtime;
514 m_uptime.set(m_uptime.get() + dtime);
520 Update time of day and overall game time
522 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
525 Send to clients at constant intervals
528 m_time_of_day_send_timer -= dtime;
529 if(m_time_of_day_send_timer < 0.0) {
530 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
531 u16 time = m_env->getTimeOfDay();
532 float time_speed = g_settings->getFloat("time_speed");
533 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
537 MutexAutoLock lock(m_env_mutex);
538 // Figure out and report maximum lag to environment
539 float max_lag = m_env->getMaxLagEstimate();
540 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
542 if(dtime > 0.1 && dtime > max_lag * 2.0)
543 infostream<<"Server: Maximum lag peaked to "<<dtime
547 m_env->reportMaxLagEstimate(max_lag);
552 static const float map_timer_and_unload_dtime = 2.92;
553 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
555 MutexAutoLock lock(m_env_mutex);
556 // Run Map's timers and unload unused data
557 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
558 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
559 g_settings->getFloat("server_unload_unused_data_timeout"),
564 Listen to the admin chat, if available
567 if (!m_admin_chat->command_queue.empty()) {
568 MutexAutoLock lock(m_env_mutex);
569 while (!m_admin_chat->command_queue.empty()) {
570 ChatEvent *evt = m_admin_chat->command_queue.pop_frontNoEx();
571 handleChatInterfaceEvent(evt);
575 m_admin_chat->outgoing_queue.push_back(
576 new ChatEventTimeInfo(m_env->getGameTime(), m_env->getTimeOfDay()));
583 /* Transform liquids */
584 m_liquid_transform_timer += dtime;
585 if(m_liquid_transform_timer >= m_liquid_transform_every)
587 m_liquid_transform_timer -= m_liquid_transform_every;
589 MutexAutoLock lock(m_env_mutex);
591 ScopeProfiler sp(g_profiler, "Server: liquid transform");
593 std::map<v3s16, MapBlock*> modified_blocks;
594 m_env->getMap().transformLiquids(modified_blocks, m_env);
597 Set the modified blocks unsent for all the clients
599 if (!modified_blocks.empty()) {
600 SetBlocksNotSent(modified_blocks);
603 m_clients.step(dtime);
605 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
607 // send masterserver announce
609 float &counter = m_masterserver_timer;
610 if (!isSingleplayer() && (!counter || counter >= 300.0) &&
611 g_settings->getBool("server_announce")) {
612 ServerList::sendAnnounce(counter ? ServerList::AA_UPDATE :
613 ServerList::AA_START,
614 m_bind_addr.getPort(),
615 m_clients.getPlayerNames(),
617 m_env->getGameTime(),
620 Mapgen::getMapgenName(m_emerge->mgparams->mgtype),
630 Check added and deleted active objects
633 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
634 MutexAutoLock envlock(m_env_mutex);
637 const RemoteClientMap &clients = m_clients.getClientList();
638 ScopeProfiler sp(g_profiler, "Server: update objects within range");
640 for (const auto &client_it : clients) {
641 RemoteClient *client = client_it.second;
643 if (client->getState() < CS_DefinitionsSent)
646 // This can happen if the client times out somehow
647 if (!m_env->getPlayer(client->peer_id))
650 PlayerSAO *playersao = getPlayerSAO(client->peer_id);
654 SendActiveObjectRemoveAdd(client, playersao);
658 // Save mod storages if modified
659 m_mod_storage_save_timer -= dtime;
660 if (m_mod_storage_save_timer <= 0.0f) {
661 m_mod_storage_save_timer = g_settings->getFloat("server_map_save_interval");
663 for (std::unordered_map<std::string, ModMetadata *>::const_iterator
664 it = m_mod_storages.begin(); it != m_mod_storages.end(); ++it) {
665 if (it->second->isModified()) {
666 it->second->save(getModStoragePath());
671 infostream << "Saved " << n << " modified mod storages." << std::endl;
679 MutexAutoLock envlock(m_env_mutex);
680 ScopeProfiler sp(g_profiler, "Server: send SAO messages");
683 // Value = data sent by object
684 std::unordered_map<u16, std::vector<ActiveObjectMessage>*> buffered_messages;
686 // Get active object messages from environment
688 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
692 std::vector<ActiveObjectMessage>* message_list = nullptr;
693 std::unordered_map<u16, std::vector<ActiveObjectMessage>* >::iterator n;
694 n = buffered_messages.find(aom.id);
695 if (n == buffered_messages.end()) {
696 message_list = new std::vector<ActiveObjectMessage>;
697 buffered_messages[aom.id] = message_list;
700 message_list = n->second;
702 message_list->push_back(aom);
706 const RemoteClientMap &clients = m_clients.getClientList();
707 // Route data to every client
708 for (const auto &client_it : clients) {
709 RemoteClient *client = client_it.second;
710 PlayerSAO *player = getPlayerSAO(client->peer_id);
711 std::string reliable_data;
712 std::string unreliable_data;
713 // Go through all objects in message buffer
714 for (const auto &buffered_message : buffered_messages) {
715 // If object does not exist or is not known by client, skip it
716 u16 id = buffered_message.first;
717 ServerActiveObject *sao = m_env->getActiveObject(id);
718 if (!sao || client->m_known_objects.find(id) == client->m_known_objects.end())
721 // Get message list of object
722 std::vector<ActiveObjectMessage>* list = buffered_message.second;
723 // Go through every message
724 for (const ActiveObjectMessage &aom : *list) {
725 // Send position updates to players who do not see the attachment
726 if (aom.datastring[0] == AO_CMD_UPDATE_POSITION) {
727 if (sao->getId() == player->getId())
730 // Do not send position updates for attached players
731 // as long the parent is known to the client
732 ServerActiveObject *parent = sao->getParent();
733 if (parent && client->m_known_objects.find(parent->getId()) !=
734 client->m_known_objects.end())
737 // Compose the full new data with header
738 std::string new_data;
741 writeU16((u8*)&buf[0], aom.id);
742 new_data.append(buf, 2);
744 new_data += serializeString(aom.datastring);
745 // Add data to buffer
747 reliable_data += new_data;
749 unreliable_data += new_data;
753 reliable_data and unreliable_data are now ready.
756 if (!reliable_data.empty()) {
757 SendActiveObjectMessages(client->peer_id, reliable_data);
760 if (!unreliable_data.empty()) {
761 SendActiveObjectMessages(client->peer_id, unreliable_data, false);
766 // Clear buffered_messages
767 for (auto &buffered_message : buffered_messages) {
768 delete buffered_message.second;
773 Send queued-for-sending map edit events.
776 // We will be accessing the environment
777 MutexAutoLock lock(m_env_mutex);
779 // Don't send too many at a time
782 // Single change sending is disabled if queue size is not small
783 bool disable_single_change_sending = false;
784 if(m_unsent_map_edit_queue.size() >= 4)
785 disable_single_change_sending = true;
787 int event_count = m_unsent_map_edit_queue.size();
789 // We'll log the amount of each
792 std::list<v3s16> node_meta_updates;
794 while (!m_unsent_map_edit_queue.empty()) {
795 MapEditEvent* event = m_unsent_map_edit_queue.front();
796 m_unsent_map_edit_queue.pop();
798 // Players far away from the change are stored here.
799 // Instead of sending the changes, MapBlocks are set not sent
801 std::unordered_set<u16> far_players;
803 switch (event->type) {
806 prof.add("MEET_ADDNODE", 1);
807 sendAddNode(event->p, event->n, &far_players,
808 disable_single_change_sending ? 5 : 30,
809 event->type == MEET_ADDNODE);
811 case MEET_REMOVENODE:
812 prof.add("MEET_REMOVENODE", 1);
813 sendRemoveNode(event->p, &far_players,
814 disable_single_change_sending ? 5 : 30);
816 case MEET_BLOCK_NODE_METADATA_CHANGED: {
817 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
818 if (!event->is_private_change) {
819 // Don't send the change yet. Collect them to eliminate dupes.
820 node_meta_updates.remove(event->p);
821 node_meta_updates.push_back(event->p);
824 if (MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(
825 getNodeBlockPos(event->p))) {
826 block->raiseModified(MOD_STATE_WRITE_NEEDED,
827 MOD_REASON_REPORT_META_CHANGE);
832 prof.add("MEET_OTHER", 1);
833 for (const v3s16 &modified_block : event->modified_blocks) {
834 m_clients.markBlockposAsNotSent(modified_block);
838 prof.add("unknown", 1);
839 warningstream << "Server: Unknown MapEditEvent "
840 << ((u32)event->type) << std::endl;
845 Set blocks not sent to far players
847 if (!far_players.empty()) {
848 // Convert list format to that wanted by SetBlocksNotSent
849 std::map<v3s16, MapBlock*> modified_blocks2;
850 for (const v3s16 &modified_block : event->modified_blocks) {
851 modified_blocks2[modified_block] =
852 m_env->getMap().getBlockNoCreateNoEx(modified_block);
855 // Set blocks not sent
856 for (const u16 far_player : far_players) {
857 if (RemoteClient *client = getClient(far_player))
858 client->SetBlocksNotSent(modified_blocks2);
865 if (event_count >= 5) {
866 infostream << "Server: MapEditEvents:" << std::endl;
867 prof.print(infostream);
868 } else if (event_count != 0) {
869 verbosestream << "Server: MapEditEvents:" << std::endl;
870 prof.print(verbosestream);
873 // Send all metadata updates
874 if (node_meta_updates.size())
875 sendMetadataChanged(node_meta_updates);
879 Trigger emergethread (it somehow gets to a non-triggered but
880 bysy state sometimes)
883 float &counter = m_emergethread_trigger_timer;
885 if (counter >= 2.0) {
888 m_emerge->startThreads();
892 // Save map, players and auth stuff
894 float &counter = m_savemap_timer;
896 static thread_local const float save_interval =
897 g_settings->getFloat("server_map_save_interval");
898 if (counter >= save_interval) {
900 MutexAutoLock lock(m_env_mutex);
902 ScopeProfiler sp(g_profiler, "Server: map saving (sum)");
905 if (m_banmanager->isModified()) {
906 m_banmanager->save();
909 // Save changed parts of map
910 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
913 m_env->saveLoadedPlayers();
915 // Save environment metadata
920 m_shutdown_state.tick(dtime, this);
923 void Server::Receive()
933 In the first iteration *wait* for a packet, afterwards process
934 all packets that are immediately available (no waiting).
937 m_con->Receive(&pkt);
940 if (!m_con->TryReceive(&pkt))
944 peer_id = pkt.getPeerId();
946 } catch (const con::InvalidIncomingDataException &e) {
947 infostream << "Server::Receive(): InvalidIncomingDataException: what()="
948 << e.what() << std::endl;
949 } catch (const SerializationError &e) {
950 infostream << "Server::Receive(): SerializationError: what()="
951 << e.what() << std::endl;
952 } catch (const ClientStateError &e) {
953 errorstream << "ProcessData: peer=" << peer_id << " what()="
954 << e.what() << std::endl;
955 DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
956 L"Try reconnecting or updating your client");
957 } catch (const con::PeerNotFoundException &e) {
959 } catch (const con::NoIncomingDataException &e) {
965 PlayerSAO* Server::StageTwoClientInit(session_t peer_id)
967 std::string playername;
968 PlayerSAO *playersao = NULL;
971 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
973 playername = client->getName();
974 playersao = emergePlayer(playername.c_str(), peer_id, client->net_proto_version);
976 } catch (std::exception &e) {
982 RemotePlayer *player = m_env->getPlayer(playername.c_str());
985 if (!playersao || !player) {
986 if (player && player->getPeerId() != PEER_ID_INEXISTENT) {
987 actionstream << "Server: Failed to emerge player \"" << playername
988 << "\" (player allocated to an another client)" << std::endl;
989 DenyAccess_Legacy(peer_id, L"Another client is connected with this "
990 L"name. If your client closed unexpectedly, try again in "
993 errorstream << "Server: " << playername << ": Failed to emerge player"
995 DenyAccess_Legacy(peer_id, L"Could not allocate player.");
1001 Send complete position information
1003 SendMovePlayer(peer_id);
1006 SendPlayerPrivileges(peer_id);
1008 // Send inventory formspec
1009 SendPlayerInventoryFormspec(peer_id);
1012 SendInventory(playersao, false);
1014 // Send HP or death screen
1015 if (playersao->isDead())
1016 SendDeathscreen(peer_id, false, v3f(0,0,0));
1018 SendPlayerHPOrDie(playersao,
1019 PlayerHPChangeReason(PlayerHPChangeReason::SET_HP));
1022 SendPlayerBreath(playersao);
1028 Address addr = getPeerAddress(player->getPeerId());
1029 std::string ip_str = addr.serializeString();
1030 const std::vector<std::string> &names = m_clients.getPlayerNames();
1032 actionstream << player->getName() << " [" << ip_str << "] joins game. List of players: ";
1034 for (const std::string &name : names) {
1035 actionstream << name << " ";
1038 actionstream << player->getName() <<std::endl;
1043 inline void Server::handleCommand(NetworkPacket *pkt)
1045 const ToServerCommandHandler &opHandle = toServerCommandTable[pkt->getCommand()];
1046 (this->*opHandle.handler)(pkt);
1049 void Server::ProcessData(NetworkPacket *pkt)
1051 // Environment is locked first.
1052 MutexAutoLock envlock(m_env_mutex);
1054 ScopeProfiler sp(g_profiler, "Server: Process network packet (sum)");
1055 u32 peer_id = pkt->getPeerId();
1058 Address address = getPeerAddress(peer_id);
1059 std::string addr_s = address.serializeString();
1061 if(m_banmanager->isIpBanned(addr_s)) {
1062 std::string ban_name = m_banmanager->getBanName(addr_s);
1063 infostream << "Server: A banned client tried to connect from "
1064 << addr_s << "; banned name was "
1065 << ban_name << std::endl;
1066 // This actually doesn't seem to transfer to the client
1067 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1068 + utf8_to_wide(ban_name));
1072 catch(con::PeerNotFoundException &e) {
1074 * no peer for this packet found
1075 * most common reason is peer timeout, e.g. peer didn't
1076 * respond for some time, your server was overloaded or
1079 infostream << "Server::ProcessData(): Canceling: peer "
1080 << peer_id << " not found" << std::endl;
1085 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1087 // Command must be handled into ToServerCommandHandler
1088 if (command >= TOSERVER_NUM_MSG_TYPES) {
1089 infostream << "Server: Ignoring unknown command "
1090 << command << std::endl;
1094 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1099 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1101 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1102 errorstream << "Server::ProcessData(): Cancelling: Peer"
1103 " serialization format invalid or not initialized."
1104 " Skipping incoming command=" << command << std::endl;
1108 /* Handle commands related to client startup */
1109 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1114 if (m_clients.getClientState(peer_id) < CS_Active) {
1115 if (command == TOSERVER_PLAYERPOS) return;
1117 errorstream << "Got packet command: " << command << " for peer id "
1118 << peer_id << " but client isn't active yet. Dropping packet "
1124 } catch (SendFailedException &e) {
1125 errorstream << "Server::ProcessData(): SendFailedException: "
1126 << "what=" << e.what()
1128 } catch (PacketError &e) {
1129 actionstream << "Server::ProcessData(): PacketError: "
1130 << "what=" << e.what()
1135 void Server::setTimeOfDay(u32 time)
1137 m_env->setTimeOfDay(time);
1138 m_time_of_day_send_timer = 0;
1141 void Server::onMapEditEvent(const MapEditEvent &event)
1143 if (m_ignore_map_edit_events_area.contains(event.getArea()))
1146 m_unsent_map_edit_queue.push(new MapEditEvent(event));
1149 Inventory* Server::getInventory(const InventoryLocation &loc)
1152 case InventoryLocation::UNDEFINED:
1153 case InventoryLocation::CURRENT_PLAYER:
1155 case InventoryLocation::PLAYER:
1157 RemotePlayer *player = m_env->getPlayer(loc.name.c_str());
1160 PlayerSAO *playersao = player->getPlayerSAO();
1163 return playersao->getInventory();
1166 case InventoryLocation::NODEMETA:
1168 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1171 return meta->getInventory();
1174 case InventoryLocation::DETACHED:
1176 if(m_detached_inventories.count(loc.name) == 0)
1178 return m_detached_inventories[loc.name];
1182 sanity_check(false); // abort
1188 void Server::setInventoryModified(const InventoryLocation &loc)
1191 case InventoryLocation::UNDEFINED:
1193 case InventoryLocation::PLAYER:
1196 RemotePlayer *player = m_env->getPlayer(loc.name.c_str());
1201 player->setModified(true);
1202 player->inventory.setModified(true);
1203 // Updates are sent in ServerEnvironment::step()
1206 case InventoryLocation::NODEMETA:
1209 event.type = MEET_BLOCK_NODE_METADATA_CHANGED;
1211 m_env->getMap().dispatchEvent(event);
1214 case InventoryLocation::DETACHED:
1216 // Updates are sent in ServerEnvironment::step()
1220 sanity_check(false); // abort
1225 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1227 std::vector<session_t> clients = m_clients.getClientIDs();
1229 // Set the modified blocks unsent for all the clients
1230 for (const session_t client_id : clients) {
1231 if (RemoteClient *client = m_clients.lockedGetClientNoEx(client_id))
1232 client->SetBlocksNotSent(block);
1237 void Server::peerAdded(con::Peer *peer)
1239 verbosestream<<"Server::peerAdded(): peer->id="
1240 <<peer->id<<std::endl;
1242 m_peer_change_queue.push(con::PeerChange(con::PEER_ADDED, peer->id, false));
1245 void Server::deletingPeer(con::Peer *peer, bool timeout)
1247 verbosestream<<"Server::deletingPeer(): peer->id="
1248 <<peer->id<<", timeout="<<timeout<<std::endl;
1250 m_clients.event(peer->id, CSE_Disconnect);
1251 m_peer_change_queue.push(con::PeerChange(con::PEER_REMOVED, peer->id, timeout));
1254 bool Server::getClientConInfo(session_t peer_id, con::rtt_stat_type type, float* retval)
1256 *retval = m_con->getPeerStat(peer_id,type);
1257 return *retval != -1;
1260 bool Server::getClientInfo(
1269 std::string* vers_string
1272 *state = m_clients.getClientState(peer_id);
1274 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1281 *uptime = client->uptime();
1282 *ser_vers = client->serialization_version;
1283 *prot_vers = client->net_proto_version;
1285 *major = client->getMajor();
1286 *minor = client->getMinor();
1287 *patch = client->getPatch();
1288 *vers_string = client->getFull();
1295 void Server::handlePeerChanges()
1297 while(!m_peer_change_queue.empty())
1299 con::PeerChange c = m_peer_change_queue.front();
1300 m_peer_change_queue.pop();
1302 verbosestream<<"Server: Handling peer change: "
1303 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1308 case con::PEER_ADDED:
1309 m_clients.CreateClient(c.peer_id);
1312 case con::PEER_REMOVED:
1313 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1317 FATAL_ERROR("Invalid peer change event received!");
1323 void Server::printToConsoleOnly(const std::string &text)
1326 m_admin_chat->outgoing_queue.push_back(
1327 new ChatEventChat("", utf8_to_wide(text)));
1329 std::cout << text << std::endl;
1333 void Server::Send(NetworkPacket *pkt)
1335 Send(pkt->getPeerId(), pkt);
1338 void Server::Send(session_t peer_id, NetworkPacket *pkt)
1340 m_clients.send(peer_id,
1341 clientCommandFactoryTable[pkt->getCommand()].channel,
1343 clientCommandFactoryTable[pkt->getCommand()].reliable);
1346 void Server::SendMovement(session_t peer_id)
1348 std::ostringstream os(std::ios_base::binary);
1350 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1352 pkt << g_settings->getFloat("movement_acceleration_default");
1353 pkt << g_settings->getFloat("movement_acceleration_air");
1354 pkt << g_settings->getFloat("movement_acceleration_fast");
1355 pkt << g_settings->getFloat("movement_speed_walk");
1356 pkt << g_settings->getFloat("movement_speed_crouch");
1357 pkt << g_settings->getFloat("movement_speed_fast");
1358 pkt << g_settings->getFloat("movement_speed_climb");
1359 pkt << g_settings->getFloat("movement_speed_jump");
1360 pkt << g_settings->getFloat("movement_liquid_fluidity");
1361 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1362 pkt << g_settings->getFloat("movement_liquid_sink");
1363 pkt << g_settings->getFloat("movement_gravity");
1368 void Server::SendPlayerHPOrDie(PlayerSAO *playersao, const PlayerHPChangeReason &reason)
1370 if (playersao->isImmortal())
1373 session_t peer_id = playersao->getPeerID();
1374 bool is_alive = playersao->getHP() > 0;
1377 SendPlayerHP(peer_id);
1379 DiePlayer(peer_id, reason);
1382 void Server::SendHP(session_t peer_id, u16 hp)
1384 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1389 void Server::SendBreath(session_t peer_id, u16 breath)
1391 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1392 pkt << (u16) breath;
1396 void Server::SendAccessDenied(session_t peer_id, AccessDeniedCode reason,
1397 const std::string &custom_reason, bool reconnect)
1399 assert(reason < SERVER_ACCESSDENIED_MAX);
1401 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1403 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
1404 pkt << custom_reason;
1405 else if (reason == SERVER_ACCESSDENIED_SHUTDOWN ||
1406 reason == SERVER_ACCESSDENIED_CRASH)
1407 pkt << custom_reason << (u8)reconnect;
1411 void Server::SendAccessDenied_Legacy(session_t peer_id,const std::wstring &reason)
1413 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1418 void Server::SendDeathscreen(session_t peer_id, bool set_camera_point_target,
1419 v3f camera_point_target)
1421 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1422 pkt << set_camera_point_target << camera_point_target;
1426 void Server::SendItemDef(session_t peer_id,
1427 IItemDefManager *itemdef, u16 protocol_version)
1429 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1433 u32 length of the next item
1434 zlib-compressed serialized ItemDefManager
1436 std::ostringstream tmp_os(std::ios::binary);
1437 itemdef->serialize(tmp_os, protocol_version);
1438 std::ostringstream tmp_os2(std::ios::binary);
1439 compressZlib(tmp_os.str(), tmp_os2);
1440 pkt.putLongString(tmp_os2.str());
1443 verbosestream << "Server: Sending item definitions to id(" << peer_id
1444 << "): size=" << pkt.getSize() << std::endl;
1449 void Server::SendNodeDef(session_t peer_id,
1450 const NodeDefManager *nodedef, u16 protocol_version)
1452 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1456 u32 length of the next item
1457 zlib-compressed serialized NodeDefManager
1459 std::ostringstream tmp_os(std::ios::binary);
1460 nodedef->serialize(tmp_os, protocol_version);
1461 std::ostringstream tmp_os2(std::ios::binary);
1462 compressZlib(tmp_os.str(), tmp_os2);
1464 pkt.putLongString(tmp_os2.str());
1467 verbosestream << "Server: Sending node definitions to id(" << peer_id
1468 << "): size=" << pkt.getSize() << std::endl;
1474 Non-static send methods
1477 void Server::SendInventory(PlayerSAO *sao, bool incremental)
1479 RemotePlayer *player = sao->getPlayer();
1481 // Do not send new format to old clients
1482 incremental &= player->protocol_version >= 38;
1484 UpdateCrafting(player);
1490 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, sao->getPeerID());
1492 std::ostringstream os(std::ios::binary);
1493 sao->getInventory()->serialize(os, incremental);
1494 sao->getInventory()->setModified(false);
1495 player->setModified(true);
1497 const std::string &s = os.str();
1498 pkt.putRawString(s.c_str(), s.size());
1502 void Server::SendChatMessage(session_t peer_id, const ChatMessage &message)
1504 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1506 u8 type = message.type;
1507 pkt << version << type << std::wstring(L"") << message.message << (u64)message.timestamp;
1509 if (peer_id != PEER_ID_INEXISTENT) {
1510 RemotePlayer *player = m_env->getPlayer(peer_id);
1516 m_clients.sendToAll(&pkt);
1520 void Server::SendShowFormspecMessage(session_t peer_id, const std::string &formspec,
1521 const std::string &formname)
1523 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0, peer_id);
1524 if (formspec.empty()){
1525 //the client should close the formspec
1526 //but make sure there wasn't another one open in meantime
1527 const auto it = m_formspec_state_data.find(peer_id);
1528 if (it != m_formspec_state_data.end() && it->second == formname) {
1529 m_formspec_state_data.erase(peer_id);
1531 pkt.putLongString("");
1533 m_formspec_state_data[peer_id] = formname;
1534 pkt.putLongString(formspec);
1541 // Spawns a particle on peer with peer_id
1542 void Server::SendSpawnParticle(session_t peer_id, u16 protocol_version,
1543 v3f pos, v3f velocity, v3f acceleration,
1544 float expirationtime, float size, bool collisiondetection,
1545 bool collision_removal, bool object_collision,
1546 bool vertical, const std::string &texture,
1547 const struct TileAnimationParams &animation, u8 glow)
1549 static thread_local const float radius =
1550 g_settings->getS16("max_block_send_distance") * MAP_BLOCKSIZE * BS;
1552 if (peer_id == PEER_ID_INEXISTENT) {
1553 std::vector<session_t> clients = m_clients.getClientIDs();
1555 for (const session_t client_id : clients) {
1556 RemotePlayer *player = m_env->getPlayer(client_id);
1560 PlayerSAO *sao = player->getPlayerSAO();
1564 // Do not send to distant clients
1565 if (sao->getBasePosition().getDistanceFrom(pos * BS) > radius)
1568 SendSpawnParticle(client_id, player->protocol_version,
1569 pos, velocity, acceleration,
1570 expirationtime, size, collisiondetection, collision_removal,
1571 object_collision, vertical, texture, animation, glow);
1576 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1578 pkt << pos << velocity << acceleration << expirationtime
1579 << size << collisiondetection;
1580 pkt.putLongString(texture);
1582 pkt << collision_removal;
1583 // This is horrible but required (why are there two ways to serialize pkts?)
1584 std::ostringstream os(std::ios_base::binary);
1585 animation.serialize(os, protocol_version);
1586 pkt.putRawString(os.str());
1588 pkt << object_collision;
1593 // Adds a ParticleSpawner on peer with peer_id
1594 void Server::SendAddParticleSpawner(session_t peer_id, u16 protocol_version,
1595 u16 amount, float spawntime, v3f minpos, v3f maxpos,
1596 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1597 float minsize, float maxsize, bool collisiondetection, bool collision_removal,
1598 bool object_collision, u16 attached_id, bool vertical, const std::string &texture, u32 id,
1599 const struct TileAnimationParams &animation, u8 glow)
1601 if (peer_id == PEER_ID_INEXISTENT) {
1602 // This sucks and should be replaced:
1603 std::vector<session_t> clients = m_clients.getClientIDs();
1604 for (const session_t client_id : clients) {
1605 RemotePlayer *player = m_env->getPlayer(client_id);
1608 SendAddParticleSpawner(client_id, player->protocol_version,
1609 amount, spawntime, minpos, maxpos,
1610 minvel, maxvel, minacc, maxacc, minexptime, maxexptime,
1611 minsize, maxsize, collisiondetection, collision_removal,
1612 object_collision, attached_id, vertical, texture, id,
1618 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1620 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1621 << minacc << maxacc << minexptime << maxexptime << minsize
1622 << maxsize << collisiondetection;
1624 pkt.putLongString(texture);
1626 pkt << id << vertical;
1627 pkt << collision_removal;
1629 // This is horrible but required
1630 std::ostringstream os(std::ios_base::binary);
1631 animation.serialize(os, protocol_version);
1632 pkt.putRawString(os.str());
1634 pkt << object_collision;
1639 void Server::SendDeleteParticleSpawner(session_t peer_id, u32 id)
1641 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER, 4, peer_id);
1643 // Ugly error in this packet
1646 if (peer_id != PEER_ID_INEXISTENT)
1649 m_clients.sendToAll(&pkt);
1653 void Server::SendHUDAdd(session_t peer_id, u32 id, HudElement *form)
1655 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1657 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1658 << form->text << form->number << form->item << form->dir
1659 << form->align << form->offset << form->world_pos << form->size
1665 void Server::SendHUDRemove(session_t peer_id, u32 id)
1667 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1672 void Server::SendHUDChange(session_t peer_id, u32 id, HudElementStat stat, void *value)
1674 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1675 pkt << id << (u8) stat;
1679 case HUD_STAT_SCALE:
1680 case HUD_STAT_ALIGN:
1681 case HUD_STAT_OFFSET:
1682 pkt << *(v2f *) value;
1686 pkt << *(std::string *) value;
1688 case HUD_STAT_WORLD_POS:
1689 pkt << *(v3f *) value;
1692 pkt << *(v2s32 *) value;
1694 case HUD_STAT_NUMBER:
1698 pkt << *(u32 *) value;
1705 void Server::SendHUDSetFlags(session_t peer_id, u32 flags, u32 mask)
1707 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1709 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1711 pkt << flags << mask;
1716 void Server::SendHUDSetParam(session_t peer_id, u16 param, const std::string &value)
1718 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1719 pkt << param << value;
1723 void Server::SendSetSky(session_t peer_id, const SkyboxParams ¶ms)
1725 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1727 // Handle prior clients here
1728 if (m_clients.getProtocolVersion(peer_id) < 39) {
1729 pkt << params.bgcolor << params.type << (u16) params.textures.size();
1731 for (const std::string& texture : params.textures)
1734 pkt << params.clouds;
1735 } else { // Handle current clients and future clients
1736 pkt << params.bgcolor << params.type
1737 << params.clouds << params.sun_tint
1738 << params.moon_tint << params.tint_type;
1740 if (params.type == "skybox") {
1741 pkt << (u16) params.textures.size();
1742 for (const std::string &texture : params.textures)
1744 } else if (params.type == "regular") {
1745 pkt << params.sky_color.day_sky << params.sky_color.day_horizon
1746 << params.sky_color.dawn_sky << params.sky_color.dawn_horizon
1747 << params.sky_color.night_sky << params.sky_color.night_horizon
1748 << params.sky_color.indoors;
1755 void Server::SendSetSun(session_t peer_id, const SunParams ¶ms)
1757 NetworkPacket pkt(TOCLIENT_SET_SUN, 0, peer_id);
1758 pkt << params.visible << params.texture
1759 << params.tonemap << params.sunrise
1760 << params.sunrise_visible << params.scale;
1764 void Server::SendSetMoon(session_t peer_id, const MoonParams ¶ms)
1766 NetworkPacket pkt(TOCLIENT_SET_MOON, 0, peer_id);
1768 pkt << params.visible << params.texture
1769 << params.tonemap << params.scale;
1773 void Server::SendSetStars(session_t peer_id, const StarParams ¶ms)
1775 NetworkPacket pkt(TOCLIENT_SET_STARS, 0, peer_id);
1777 pkt << params.visible << params.count
1778 << params.starcolor << params.scale;
1783 void Server::SendCloudParams(session_t peer_id, const CloudParams ¶ms)
1785 NetworkPacket pkt(TOCLIENT_CLOUD_PARAMS, 0, peer_id);
1786 pkt << params.density << params.color_bright << params.color_ambient
1787 << params.height << params.thickness << params.speed;
1791 void Server::SendOverrideDayNightRatio(session_t peer_id, bool do_override,
1794 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1797 pkt << do_override << (u16) (ratio * 65535);
1802 void Server::SendTimeOfDay(session_t peer_id, u16 time, f32 time_speed)
1804 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1805 pkt << time << time_speed;
1807 if (peer_id == PEER_ID_INEXISTENT) {
1808 m_clients.sendToAll(&pkt);
1815 void Server::SendPlayerHP(session_t peer_id)
1817 PlayerSAO *playersao = getPlayerSAO(peer_id);
1820 SendHP(peer_id, playersao->getHP());
1821 m_script->player_event(playersao,"health_changed");
1823 // Send to other clients
1824 playersao->sendPunchCommand();
1827 void Server::SendPlayerBreath(PlayerSAO *sao)
1831 m_script->player_event(sao, "breath_changed");
1832 SendBreath(sao->getPeerID(), sao->getBreath());
1835 void Server::SendMovePlayer(session_t peer_id)
1837 RemotePlayer *player = m_env->getPlayer(peer_id);
1839 PlayerSAO *sao = player->getPlayerSAO();
1842 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1843 pkt << sao->getBasePosition() << sao->getLookPitch() << sao->getRotation().Y;
1846 v3f pos = sao->getBasePosition();
1847 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1848 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1849 << " pitch=" << sao->getLookPitch()
1850 << " yaw=" << sao->getRotation().Y
1857 void Server::SendPlayerFov(session_t peer_id)
1859 NetworkPacket pkt(TOCLIENT_FOV, 4 + 1, peer_id);
1861 PlayerFovSpec fov_spec = m_env->getPlayer(peer_id)->getFov();
1862 pkt << fov_spec.fov << fov_spec.is_multiplier;
1867 void Server::SendLocalPlayerAnimations(session_t peer_id, v2s32 animation_frames[4],
1868 f32 animation_speed)
1870 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1873 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1874 << animation_frames[3] << animation_speed;
1879 void Server::SendEyeOffset(session_t peer_id, v3f first, v3f third)
1881 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1882 pkt << first << third;
1886 void Server::SendPlayerPrivileges(session_t peer_id)
1888 RemotePlayer *player = m_env->getPlayer(peer_id);
1890 if(player->getPeerId() == PEER_ID_INEXISTENT)
1893 std::set<std::string> privs;
1894 m_script->getAuth(player->getName(), NULL, &privs);
1896 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1897 pkt << (u16) privs.size();
1899 for (const std::string &priv : privs) {
1906 void Server::SendPlayerInventoryFormspec(session_t peer_id)
1908 RemotePlayer *player = m_env->getPlayer(peer_id);
1910 if (player->getPeerId() == PEER_ID_INEXISTENT)
1913 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1914 pkt.putLongString(player->inventory_formspec);
1919 void Server::SendPlayerFormspecPrepend(session_t peer_id)
1921 RemotePlayer *player = m_env->getPlayer(peer_id);
1923 if (player->getPeerId() == PEER_ID_INEXISTENT)
1926 NetworkPacket pkt(TOCLIENT_FORMSPEC_PREPEND, 0, peer_id);
1927 pkt << player->formspec_prepend;
1931 void Server::SendActiveObjectRemoveAdd(RemoteClient *client, PlayerSAO *playersao)
1933 // Radius inside which objects are active
1934 static thread_local const s16 radius =
1935 g_settings->getS16("active_object_send_range_blocks") * MAP_BLOCKSIZE;
1937 // Radius inside which players are active
1938 static thread_local const bool is_transfer_limited =
1939 g_settings->exists("unlimited_player_transfer_distance") &&
1940 !g_settings->getBool("unlimited_player_transfer_distance");
1942 static thread_local const s16 player_transfer_dist =
1943 g_settings->getS16("player_transfer_distance") * MAP_BLOCKSIZE;
1945 s16 player_radius = player_transfer_dist == 0 && is_transfer_limited ?
1946 radius : player_transfer_dist;
1948 s16 my_radius = MYMIN(radius, playersao->getWantedRange() * MAP_BLOCKSIZE);
1952 std::queue<u16> removed_objects, added_objects;
1953 m_env->getRemovedActiveObjects(playersao, my_radius, player_radius,
1954 client->m_known_objects, removed_objects);
1955 m_env->getAddedActiveObjects(playersao, my_radius, player_radius,
1956 client->m_known_objects, added_objects);
1958 int removed_count = removed_objects.size();
1959 int added_count = added_objects.size();
1961 if (removed_objects.empty() && added_objects.empty())
1967 // Handle removed objects
1968 writeU16((u8*)buf, removed_objects.size());
1969 data.append(buf, 2);
1970 while (!removed_objects.empty()) {
1972 u16 id = removed_objects.front();
1973 ServerActiveObject* obj = m_env->getActiveObject(id);
1975 // Add to data buffer for sending
1976 writeU16((u8*)buf, id);
1977 data.append(buf, 2);
1979 // Remove from known objects
1980 client->m_known_objects.erase(id);
1982 if (obj && obj->m_known_by_count > 0)
1983 obj->m_known_by_count--;
1985 removed_objects.pop();
1988 // Handle added objects
1989 writeU16((u8*)buf, added_objects.size());
1990 data.append(buf, 2);
1991 while (!added_objects.empty()) {
1993 u16 id = added_objects.front();
1994 ServerActiveObject *obj = m_env->getActiveObject(id);
1995 added_objects.pop();
1998 warningstream << FUNCTION_NAME << ": NULL object id="
1999 << (int)id << std::endl;
2004 u8 type = obj->getSendType();
2006 // Add to data buffer for sending
2007 writeU16((u8*)buf, id);
2008 data.append(buf, 2);
2009 writeU8((u8*)buf, type);
2010 data.append(buf, 1);
2012 data.append(serializeLongString(
2013 obj->getClientInitializationData(client->net_proto_version)));
2015 // Add to known objects
2016 client->m_known_objects.insert(id);
2018 obj->m_known_by_count++;
2021 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, data.size(), client->peer_id);
2022 pkt.putRawString(data.c_str(), data.size());
2025 verbosestream << "Server::SendActiveObjectRemoveAdd: "
2026 << removed_count << " removed, " << added_count << " added, "
2027 << "packet size is " << pkt.getSize() << std::endl;
2030 void Server::SendActiveObjectMessages(session_t peer_id, const std::string &datas,
2033 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
2034 datas.size(), peer_id);
2036 pkt.putRawString(datas.c_str(), datas.size());
2038 m_clients.send(pkt.getPeerId(),
2039 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
2043 void Server::SendCSMRestrictionFlags(session_t peer_id)
2045 NetworkPacket pkt(TOCLIENT_CSM_RESTRICTION_FLAGS,
2046 sizeof(m_csm_restriction_flags) + sizeof(m_csm_restriction_noderange), peer_id);
2047 pkt << m_csm_restriction_flags << m_csm_restriction_noderange;
2051 void Server::SendPlayerSpeed(session_t peer_id, const v3f &added_vel)
2053 NetworkPacket pkt(TOCLIENT_PLAYER_SPEED, 0, peer_id);
2058 inline s32 Server::nextSoundId()
2060 s32 ret = m_next_sound_id;
2061 if (m_next_sound_id == INT32_MAX)
2062 m_next_sound_id = 0; // signed overflow is undefined
2068 s32 Server::playSound(const SimpleSoundSpec &spec,
2069 const ServerSoundParams ¶ms, bool ephemeral)
2071 // Find out initial position of sound
2072 bool pos_exists = false;
2073 v3f pos = params.getPos(m_env, &pos_exists);
2074 // If position is not found while it should be, cancel sound
2075 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
2078 // Filter destination clients
2079 std::vector<session_t> dst_clients;
2080 if (!params.to_player.empty()) {
2081 RemotePlayer *player = m_env->getPlayer(params.to_player.c_str());
2083 infostream<<"Server::playSound: Player \""<<params.to_player
2084 <<"\" not found"<<std::endl;
2087 if (player->getPeerId() == PEER_ID_INEXISTENT) {
2088 infostream<<"Server::playSound: Player \""<<params.to_player
2089 <<"\" not connected"<<std::endl;
2092 dst_clients.push_back(player->getPeerId());
2094 std::vector<session_t> clients = m_clients.getClientIDs();
2096 for (const session_t client_id : clients) {
2097 RemotePlayer *player = m_env->getPlayer(client_id);
2100 if (!params.exclude_player.empty() &&
2101 params.exclude_player == player->getName())
2104 PlayerSAO *sao = player->getPlayerSAO();
2109 if(sao->getBasePosition().getDistanceFrom(pos) >
2110 params.max_hear_distance)
2113 dst_clients.push_back(client_id);
2117 if(dst_clients.empty())
2122 ServerPlayingSound *psound = nullptr;
2124 id = -1; // old clients will still use this, so pick a reserved ID
2127 // The sound will exist as a reference in m_playing_sounds
2128 m_playing_sounds[id] = ServerPlayingSound();
2129 psound = &m_playing_sounds[id];
2130 psound->params = params;
2131 psound->spec = spec;
2134 float gain = params.gain * spec.gain;
2135 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2136 pkt << id << spec.name << gain
2137 << (u8) params.type << pos << params.object
2138 << params.loop << params.fade << params.pitch
2141 bool as_reliable = !ephemeral;
2143 for (const u16 dst_client : dst_clients) {
2145 psound->clients.insert(dst_client);
2146 m_clients.send(dst_client, 0, &pkt, as_reliable);
2150 void Server::stopSound(s32 handle)
2152 // Get sound reference
2153 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2154 m_playing_sounds.find(handle);
2155 if (i == m_playing_sounds.end())
2157 ServerPlayingSound &psound = i->second;
2159 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2162 for (std::unordered_set<session_t>::const_iterator si = psound.clients.begin();
2163 si != psound.clients.end(); ++si) {
2165 m_clients.send(*si, 0, &pkt, true);
2167 // Remove sound reference
2168 m_playing_sounds.erase(i);
2171 void Server::fadeSound(s32 handle, float step, float gain)
2173 // Get sound reference
2174 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2175 m_playing_sounds.find(handle);
2176 if (i == m_playing_sounds.end())
2179 ServerPlayingSound &psound = i->second;
2180 psound.params.gain = gain;
2182 NetworkPacket pkt(TOCLIENT_FADE_SOUND, 4);
2183 pkt << handle << step << gain;
2185 // Backwards compability
2186 bool play_sound = gain > 0;
2187 ServerPlayingSound compat_psound = psound;
2188 compat_psound.clients.clear();
2190 NetworkPacket compat_pkt(TOCLIENT_STOP_SOUND, 4);
2191 compat_pkt << handle;
2193 for (std::unordered_set<u16>::iterator it = psound.clients.begin();
2194 it != psound.clients.end();) {
2195 if (m_clients.getProtocolVersion(*it) >= 32) {
2197 m_clients.send(*it, 0, &pkt, true);
2200 compat_psound.clients.insert(*it);
2202 m_clients.send(*it, 0, &compat_pkt, true);
2203 psound.clients.erase(it++);
2207 // Remove sound reference
2208 if (!play_sound || psound.clients.empty())
2209 m_playing_sounds.erase(i);
2211 if (play_sound && !compat_psound.clients.empty()) {
2212 // Play new sound volume on older clients
2213 playSound(compat_psound.spec, compat_psound.params);
2217 void Server::sendRemoveNode(v3s16 p, std::unordered_set<u16> *far_players,
2220 float maxd = far_d_nodes * BS;
2221 v3f p_f = intToFloat(p, BS);
2222 v3s16 block_pos = getNodeBlockPos(p);
2224 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2227 std::vector<session_t> clients = m_clients.getClientIDs();
2230 for (session_t client_id : clients) {
2231 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
2235 RemotePlayer *player = m_env->getPlayer(client_id);
2236 PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr;
2238 // If player is far away, only set modified blocks not sent
2239 if (!client->isBlockSent(block_pos) || (sao &&
2240 sao->getBasePosition().getDistanceFrom(p_f) > maxd)) {
2242 far_players->emplace(client_id);
2244 client->SetBlockNotSent(block_pos);
2249 m_clients.send(client_id, 0, &pkt, true);
2255 void Server::sendAddNode(v3s16 p, MapNode n, std::unordered_set<u16> *far_players,
2256 float far_d_nodes, bool remove_metadata)
2258 float maxd = far_d_nodes * BS;
2259 v3f p_f = intToFloat(p, BS);
2260 v3s16 block_pos = getNodeBlockPos(p);
2262 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2263 pkt << p << n.param0 << n.param1 << n.param2
2264 << (u8) (remove_metadata ? 0 : 1);
2266 std::vector<session_t> clients = m_clients.getClientIDs();
2269 for (session_t client_id : clients) {
2270 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
2274 RemotePlayer *player = m_env->getPlayer(client_id);
2275 PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr;
2277 // If player is far away, only set modified blocks not sent
2278 if (!client->isBlockSent(block_pos) || (sao &&
2279 sao->getBasePosition().getDistanceFrom(p_f) > maxd)) {
2281 far_players->emplace(client_id);
2283 client->SetBlockNotSent(block_pos);
2288 m_clients.send(client_id, 0, &pkt, true);
2294 void Server::sendMetadataChanged(const std::list<v3s16> &meta_updates, float far_d_nodes)
2296 float maxd = far_d_nodes * BS;
2297 NodeMetadataList meta_updates_list(false);
2298 std::vector<session_t> clients = m_clients.getClientIDs();
2302 for (session_t i : clients) {
2303 RemoteClient *client = m_clients.lockedGetClientNoEx(i);
2307 ServerActiveObject *player = m_env->getActiveObject(i);
2308 v3f player_pos = player ? player->getBasePosition() : v3f();
2310 for (const v3s16 &pos : meta_updates) {
2311 NodeMetadata *meta = m_env->getMap().getNodeMetadata(pos);
2316 v3s16 block_pos = getNodeBlockPos(pos);
2317 if (!client->isBlockSent(block_pos) || (player &&
2318 player_pos.getDistanceFrom(intToFloat(pos, BS)) > maxd)) {
2319 client->SetBlockNotSent(block_pos);
2323 // Add the change to send list
2324 meta_updates_list.set(pos, meta);
2326 if (meta_updates_list.size() == 0)
2329 // Send the meta changes
2330 std::ostringstream os(std::ios::binary);
2331 meta_updates_list.serialize(os, client->net_proto_version, false, true);
2332 std::ostringstream oss(std::ios::binary);
2333 compressZlib(os.str(), oss);
2335 NetworkPacket pkt(TOCLIENT_NODEMETA_CHANGED, 0);
2336 pkt.putLongString(oss.str());
2337 m_clients.send(i, 0, &pkt, true);
2339 meta_updates_list.clear();
2345 void Server::SendBlockNoLock(session_t peer_id, MapBlock *block, u8 ver,
2346 u16 net_proto_version)
2349 Create a packet with the block in the right format
2352 std::ostringstream os(std::ios_base::binary);
2353 block->serialize(os, ver, false);
2354 block->serializeNetworkSpecific(os);
2355 std::string s = os.str();
2357 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2359 pkt << block->getPos();
2360 pkt.putRawString(s.c_str(), s.size());
2364 void Server::SendBlocks(float dtime)
2366 MutexAutoLock envlock(m_env_mutex);
2367 //TODO check if one big lock could be faster then multiple small ones
2369 std::vector<PrioritySortedBlockTransfer> queue;
2371 u32 total_sending = 0;
2374 ScopeProfiler sp2(g_profiler, "Server::SendBlocks(): Collect list");
2376 std::vector<session_t> clients = m_clients.getClientIDs();
2379 for (const session_t client_id : clients) {
2380 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id, CS_Active);
2385 total_sending += client->getSendingCount();
2386 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2392 // Lowest priority number comes first.
2393 // Lowest is most important.
2394 std::sort(queue.begin(), queue.end());
2398 // Maximal total count calculation
2399 // The per-client block sends is halved with the maximal online users
2400 u32 max_blocks_to_send = (m_env->getPlayerCount() + g_settings->getU32("max_users")) *
2401 g_settings->getU32("max_simultaneous_block_sends_per_client") / 4 + 1;
2403 ScopeProfiler sp(g_profiler, "Server::SendBlocks(): Send to clients");
2404 Map &map = m_env->getMap();
2406 for (const PrioritySortedBlockTransfer &block_to_send : queue) {
2407 if (total_sending >= max_blocks_to_send)
2410 MapBlock *block = map.getBlockNoCreateNoEx(block_to_send.pos);
2414 RemoteClient *client = m_clients.lockedGetClientNoEx(block_to_send.peer_id,
2419 SendBlockNoLock(block_to_send.peer_id, block, client->serialization_version,
2420 client->net_proto_version);
2422 client->SentBlock(block_to_send.pos);
2428 bool Server::SendBlock(session_t peer_id, const v3s16 &blockpos)
2430 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2435 RemoteClient *client = m_clients.lockedGetClientNoEx(peer_id, CS_Active);
2436 if (!client || client->isBlockSent(blockpos)) {
2440 SendBlockNoLock(peer_id, block, client->serialization_version,
2441 client->net_proto_version);
2447 void Server::fillMediaCache()
2449 infostream<<"Server: Calculating media file checksums"<<std::endl;
2451 // Collect all media file paths
2452 std::vector<std::string> paths;
2453 m_modmgr->getModsMediaPaths(paths);
2454 fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures");
2455 fs::GetRecursiveDirs(paths, porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2457 // Collect media file information from paths into cache
2458 for (const std::string &mediapath : paths) {
2459 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2460 for (const fs::DirListNode &dln : dirlist) {
2461 if (dln.dir) // Ignode dirs
2463 std::string filename = dln.name;
2464 // If name contains illegal characters, ignore the file
2465 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2466 infostream<<"Server: ignoring illegal file name: \""
2467 << filename << "\"" << std::endl;
2470 // If name is not in a supported format, ignore it
2471 const char *supported_ext[] = {
2472 ".png", ".jpg", ".bmp", ".tga",
2473 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2475 ".x", ".b3d", ".md2", ".obj",
2476 // Custom translation file format
2480 if (removeStringEnd(filename, supported_ext).empty()){
2481 infostream << "Server: ignoring unsupported file extension: \""
2482 << filename << "\"" << std::endl;
2485 // Ok, attempt to load the file and add to cache
2486 std::string filepath;
2487 filepath.append(mediapath).append(DIR_DELIM).append(filename);
2490 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2492 errorstream << "Server::fillMediaCache(): Could not open \""
2493 << filename << "\" for reading" << std::endl;
2496 std::ostringstream tmp_os(std::ios_base::binary);
2500 fis.read(buf, 1024);
2501 std::streamsize len = fis.gcount();
2502 tmp_os.write(buf, len);
2511 errorstream<<"Server::fillMediaCache(): Failed to read \""
2512 << filename << "\"" << std::endl;
2515 if(tmp_os.str().length() == 0) {
2516 errorstream << "Server::fillMediaCache(): Empty file \""
2517 << filepath << "\"" << std::endl;
2522 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2524 unsigned char *digest = sha1.getDigest();
2525 std::string sha1_base64 = base64_encode(digest, 20);
2526 std::string sha1_hex = hex_encode((char*)digest, 20);
2530 m_media[filename] = MediaInfo(filepath, sha1_base64);
2531 verbosestream << "Server: " << sha1_hex << " is " << filename
2537 void Server::sendMediaAnnouncement(session_t peer_id, const std::string &lang_code)
2540 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2543 std::string lang_suffix;
2544 lang_suffix.append(".").append(lang_code).append(".tr");
2545 for (const auto &i : m_media) {
2546 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2553 for (const auto &i : m_media) {
2554 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2556 pkt << i.first << i.second.sha1_digest;
2559 pkt << g_settings->get("remote_media");
2562 verbosestream << "Server: Announcing files to id(" << peer_id
2563 << "): count=" << media_sent << " size=" << pkt.getSize() << std::endl;
2566 struct SendableMedia
2572 SendableMedia(const std::string &name_="", const std::string &path_="",
2573 const std::string &data_=""):
2580 void Server::sendRequestedMedia(session_t peer_id,
2581 const std::vector<std::string> &tosend)
2583 verbosestream<<"Server::sendRequestedMedia(): "
2584 <<"Sending files to client"<<std::endl;
2588 // Put 5kB in one bunch (this is not accurate)
2589 u32 bytes_per_bunch = 5000;
2591 std::vector< std::vector<SendableMedia> > file_bunches;
2592 file_bunches.emplace_back();
2594 u32 file_size_bunch_total = 0;
2596 for (const std::string &name : tosend) {
2597 if (m_media.find(name) == m_media.end()) {
2598 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2599 <<"unknown file \""<<(name)<<"\""<<std::endl;
2603 //TODO get path + name
2604 std::string tpath = m_media[name].path;
2607 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2609 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2610 <<tpath<<"\" for reading"<<std::endl;
2613 std::ostringstream tmp_os(std::ios_base::binary);
2617 fis.read(buf, 1024);
2618 std::streamsize len = fis.gcount();
2619 tmp_os.write(buf, len);
2620 file_size_bunch_total += len;
2629 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2630 <<name<<"\""<<std::endl;
2633 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2634 <<tname<<"\""<<std::endl;*/
2636 file_bunches[file_bunches.size()-1].emplace_back(name, tpath, tmp_os.str());
2638 // Start next bunch if got enough data
2639 if(file_size_bunch_total >= bytes_per_bunch) {
2640 file_bunches.emplace_back();
2641 file_size_bunch_total = 0;
2646 /* Create and send packets */
2648 u16 num_bunches = file_bunches.size();
2649 for (u16 i = 0; i < num_bunches; i++) {
2652 u16 total number of texture bunches
2653 u16 index of this bunch
2654 u32 number of files in this bunch
2663 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2664 pkt << num_bunches << i << (u32) file_bunches[i].size();
2666 for (const SendableMedia &j : file_bunches[i]) {
2668 pkt.putLongString(j.data);
2671 verbosestream << "Server::sendRequestedMedia(): bunch "
2672 << i << "/" << num_bunches
2673 << " files=" << file_bunches[i].size()
2674 << " size=" << pkt.getSize() << std::endl;
2679 void Server::sendDetachedInventory(const std::string &name, session_t peer_id)
2681 const auto &inv_it = m_detached_inventories.find(name);
2682 const auto &player_it = m_detached_inventories_player.find(name);
2684 if (player_it == m_detached_inventories_player.end() ||
2685 player_it->second.empty()) {
2686 // OK. Send to everyone
2689 return; // Mods are not done loading
2691 RemotePlayer *p = m_env->getPlayer(player_it->second.c_str());
2693 return; // Player is offline
2695 if (peer_id != PEER_ID_INEXISTENT && peer_id != p->getPeerId())
2696 return; // Caller requested send to a different player, so don't send.
2698 peer_id = p->getPeerId();
2701 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2704 if (inv_it == m_detached_inventories.end()) {
2705 pkt << false; // Remove inventory
2707 pkt << true; // Update inventory
2709 // Serialization & NetworkPacket isn't a love story
2710 std::ostringstream os(std::ios_base::binary);
2711 inv_it->second->serialize(os);
2712 inv_it->second->setModified(false);
2714 const std::string &os_str = os.str();
2715 pkt << static_cast<u16>(os_str.size()); // HACK: to keep compatibility with 5.0.0 clients
2716 pkt.putRawString(os_str);
2719 if (peer_id == PEER_ID_INEXISTENT)
2720 m_clients.sendToAll(&pkt);
2725 void Server::sendDetachedInventories(session_t peer_id, bool incremental)
2727 for (const auto &detached_inventory : m_detached_inventories) {
2728 const std::string &name = detached_inventory.first;
2730 Inventory *inv = detached_inventory.second;
2731 if (!inv || !inv->checkModified())
2735 sendDetachedInventory(name, peer_id);
2743 void Server::DiePlayer(session_t peer_id, const PlayerHPChangeReason &reason)
2745 PlayerSAO *playersao = getPlayerSAO(peer_id);
2748 infostream << "Server::DiePlayer(): Player "
2749 << playersao->getPlayer()->getName()
2750 << " dies" << std::endl;
2752 playersao->setHP(0, reason);
2753 playersao->clearParentAttachment();
2755 // Trigger scripted stuff
2756 m_script->on_dieplayer(playersao, reason);
2758 SendPlayerHP(peer_id);
2759 SendDeathscreen(peer_id, false, v3f(0,0,0));
2762 void Server::RespawnPlayer(session_t peer_id)
2764 PlayerSAO *playersao = getPlayerSAO(peer_id);
2767 infostream << "Server::RespawnPlayer(): Player "
2768 << playersao->getPlayer()->getName()
2769 << " respawns" << std::endl;
2771 playersao->setHP(playersao->accessObjectProperties()->hp_max,
2772 PlayerHPChangeReason(PlayerHPChangeReason::RESPAWN));
2773 playersao->setBreath(playersao->accessObjectProperties()->breath_max);
2775 bool repositioned = m_script->on_respawnplayer(playersao);
2776 if (!repositioned) {
2777 // setPos will send the new position to client
2778 playersao->setPos(findSpawnPos());
2781 SendPlayerHP(peer_id);
2785 void Server::DenySudoAccess(session_t peer_id)
2787 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2792 void Server::DenyAccessVerCompliant(session_t peer_id, u16 proto_ver, AccessDeniedCode reason,
2793 const std::string &str_reason, bool reconnect)
2795 SendAccessDenied(peer_id, reason, str_reason, reconnect);
2797 m_clients.event(peer_id, CSE_SetDenied);
2798 DisconnectPeer(peer_id);
2802 void Server::DenyAccess(session_t peer_id, AccessDeniedCode reason,
2803 const std::string &custom_reason)
2805 SendAccessDenied(peer_id, reason, custom_reason);
2806 m_clients.event(peer_id, CSE_SetDenied);
2807 DisconnectPeer(peer_id);
2810 // 13/03/15: remove this function when protocol version 25 will become
2811 // the minimum version for MT users, maybe in 1 year
2812 void Server::DenyAccess_Legacy(session_t peer_id, const std::wstring &reason)
2814 SendAccessDenied_Legacy(peer_id, reason);
2815 m_clients.event(peer_id, CSE_SetDenied);
2816 DisconnectPeer(peer_id);
2819 void Server::DisconnectPeer(session_t peer_id)
2821 m_modchannel_mgr->leaveAllChannels(peer_id);
2822 m_con->DisconnectPeer(peer_id);
2825 void Server::acceptAuth(session_t peer_id, bool forSudoMode)
2828 RemoteClient* client = getClient(peer_id, CS_Invalid);
2830 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2832 // Right now, the auth mechs don't change between login and sudo mode.
2833 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2834 client->allowed_sudo_mechs = sudo_auth_mechs;
2836 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2837 << g_settings->getFloat("dedicated_server_step")
2841 m_clients.event(peer_id, CSE_AuthAccept);
2843 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2845 // We only support SRP right now
2846 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2848 resp_pkt << sudo_auth_mechs;
2850 m_clients.event(peer_id, CSE_SudoSuccess);
2854 void Server::DeleteClient(session_t peer_id, ClientDeletionReason reason)
2856 std::wstring message;
2859 Clear references to playing sounds
2861 for (std::unordered_map<s32, ServerPlayingSound>::iterator
2862 i = m_playing_sounds.begin(); i != m_playing_sounds.end();) {
2863 ServerPlayingSound &psound = i->second;
2864 psound.clients.erase(peer_id);
2865 if (psound.clients.empty())
2866 m_playing_sounds.erase(i++);
2871 // clear formspec info so the next client can't abuse the current state
2872 m_formspec_state_data.erase(peer_id);
2874 RemotePlayer *player = m_env->getPlayer(peer_id);
2876 /* Run scripts and remove from environment */
2878 PlayerSAO *playersao = player->getPlayerSAO();
2881 playersao->clearChildAttachments();
2882 playersao->clearParentAttachment();
2884 // inform connected clients
2885 const std::string &player_name = player->getName();
2886 NetworkPacket notice(TOCLIENT_UPDATE_PLAYER_LIST, 0, PEER_ID_INEXISTENT);
2887 // (u16) 1 + std::string represents a vector serialization representation
2888 notice << (u8) PLAYER_LIST_REMOVE << (u16) 1 << player_name;
2889 m_clients.sendToAll(¬ice);
2891 m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
2893 playersao->disconnected();
2900 if (player && reason != CDR_DENY) {
2901 std::ostringstream os(std::ios_base::binary);
2902 std::vector<session_t> clients = m_clients.getClientIDs();
2904 for (const session_t client_id : clients) {
2906 RemotePlayer *player = m_env->getPlayer(client_id);
2910 // Get name of player
2911 os << player->getName() << " ";
2914 std::string name = player->getName();
2915 actionstream << name << " "
2916 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2917 << " List of players: " << os.str() << std::endl;
2919 m_admin_chat->outgoing_queue.push_back(
2920 new ChatEventNick(CET_NICK_REMOVE, name));
2924 MutexAutoLock env_lock(m_env_mutex);
2925 m_clients.DeleteClient(peer_id);
2929 // Send leave chat message to all remaining clients
2930 if (!message.empty()) {
2931 SendChatMessage(PEER_ID_INEXISTENT,
2932 ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE, message));
2936 void Server::UpdateCrafting(RemotePlayer *player)
2938 InventoryList *clist = player->inventory.getList("craft");
2939 if (!clist || clist->getSize() == 0)
2942 if (!clist->checkModified())
2945 // Get a preview for crafting
2947 InventoryLocation loc;
2948 loc.setPlayer(player->getName());
2949 std::vector<ItemStack> output_replacements;
2950 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2951 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(),
2954 InventoryList *plist = player->inventory.getList("craftpreview");
2955 if (plist && plist->getSize() >= 1) {
2956 // Put the new preview in
2957 plist->changeItem(0, preview);
2961 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2963 if (evt->type == CET_NICK_ADD) {
2964 // The terminal informed us of its nick choice
2965 m_admin_nick = ((ChatEventNick *)evt)->nick;
2966 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2967 errorstream << "You haven't set up an account." << std::endl
2968 << "Please log in using the client as '"
2969 << m_admin_nick << "' with a secure password." << std::endl
2970 << "Until then, you can't execute admin tasks via the console," << std::endl
2971 << "and everybody can claim the user account instead of you," << std::endl
2972 << "giving them full control over this server." << std::endl;
2975 assert(evt->type == CET_CHAT);
2976 handleAdminChat((ChatEventChat *)evt);
2980 std::wstring Server::handleChat(const std::string &name, const std::wstring &wname,
2981 std::wstring wmessage, bool check_shout_priv, RemotePlayer *player)
2983 // If something goes wrong, this player is to blame
2984 RollbackScopeActor rollback_scope(m_rollback,
2985 std::string("player:") + name);
2987 if (g_settings->getBool("strip_color_codes"))
2988 wmessage = unescape_enriched(wmessage);
2991 switch (player->canSendChatMessage()) {
2992 case RPLAYER_CHATRESULT_FLOODING: {
2993 std::wstringstream ws;
2994 ws << L"You cannot send more messages. You are limited to "
2995 << g_settings->getFloat("chat_message_limit_per_10sec")
2996 << L" messages per 10 seconds.";
2999 case RPLAYER_CHATRESULT_KICK:
3000 DenyAccess_Legacy(player->getPeerId(),
3001 L"You have been kicked due to message flooding.");
3003 case RPLAYER_CHATRESULT_OK:
3006 FATAL_ERROR("Unhandled chat filtering result found.");
3010 if (m_max_chatmessage_length > 0
3011 && wmessage.length() > m_max_chatmessage_length) {
3012 return L"Your message exceed the maximum chat message limit set on the server. "
3013 L"It was refused. Send a shorter message";
3016 auto message = trim(wide_to_utf8(wmessage));
3017 if (message.find_first_of("\n\r") != std::wstring::npos) {
3018 return L"New lines are not permitted in chat messages";
3021 // Run script hook, exit if script ate the chat message
3022 if (m_script->on_chat_message(name, message))
3027 // Whether to send line to the player that sent the message, or to all players
3028 bool broadcast_line = true;
3030 if (check_shout_priv && !checkPriv(name, "shout")) {
3031 line += L"-!- You don't have permission to shout.";
3032 broadcast_line = false;
3034 line += narrow_to_wide(m_script->formatChatMessage(name,
3035 wide_to_narrow(wmessage)));
3039 Tell calling method to send the message to sender
3041 if (!broadcast_line)
3045 Send the message to others
3047 actionstream << "CHAT: " << wide_to_narrow(unescape_enriched(line)) << std::endl;
3049 std::vector<session_t> clients = m_clients.getClientIDs();
3052 Send the message back to the inital sender
3053 if they are using protocol version >= 29
3056 session_t peer_id_to_avoid_sending =
3057 (player ? player->getPeerId() : PEER_ID_INEXISTENT);
3059 if (player && player->protocol_version >= 29)
3060 peer_id_to_avoid_sending = PEER_ID_INEXISTENT;
3062 for (u16 cid : clients) {
3063 if (cid != peer_id_to_avoid_sending)
3064 SendChatMessage(cid, ChatMessage(line));
3069 void Server::handleAdminChat(const ChatEventChat *evt)
3071 std::string name = evt->nick;
3072 std::wstring wname = utf8_to_wide(name);
3073 std::wstring wmessage = evt->evt_msg;
3075 std::wstring answer = handleChat(name, wname, wmessage);
3077 // If asked to send answer to sender
3078 if (!answer.empty()) {
3079 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
3083 RemoteClient *Server::getClient(session_t peer_id, ClientState state_min)
3085 RemoteClient *client = getClientNoEx(peer_id,state_min);
3087 throw ClientNotFoundException("Client not found");
3091 RemoteClient *Server::getClientNoEx(session_t peer_id, ClientState state_min)
3093 return m_clients.getClientNoEx(peer_id, state_min);
3096 std::string Server::getPlayerName(session_t peer_id)
3098 RemotePlayer *player = m_env->getPlayer(peer_id);
3100 return "[id="+itos(peer_id)+"]";
3101 return player->getName();
3104 PlayerSAO *Server::getPlayerSAO(session_t peer_id)
3106 RemotePlayer *player = m_env->getPlayer(peer_id);
3109 return player->getPlayerSAO();
3112 std::wstring Server::getStatusString()
3114 std::wostringstream os(std::ios_base::binary);
3115 os << L"# Server: ";
3117 os << L"version=" << narrow_to_wide(g_version_string);
3119 os << L", uptime=" << m_uptime.get();
3121 os << L", max_lag=" << (m_env ? m_env->getMaxLagEstimate() : 0);
3123 // Information about clients
3125 os << L", clients={";
3127 std::vector<session_t> clients = m_clients.getClientIDs();
3128 for (session_t client_id : clients) {
3129 RemotePlayer *player = m_env->getPlayer(client_id);
3131 // Get name of player
3132 std::wstring name = L"unknown";
3134 name = narrow_to_wide(player->getName());
3136 // Add name to information string
3147 if (m_env && !((ServerMap*)(&m_env->getMap()))->isSavingEnabled())
3148 os << std::endl << L"# Server: " << " WARNING: Map saving is disabled.";
3150 if (!g_settings->get("motd").empty())
3151 os << std::endl << L"# Server: " << narrow_to_wide(g_settings->get("motd"));
3156 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
3158 std::set<std::string> privs;
3159 m_script->getAuth(name, NULL, &privs);
3163 bool Server::checkPriv(const std::string &name, const std::string &priv)
3165 std::set<std::string> privs = getPlayerEffectivePrivs(name);
3166 return (privs.count(priv) != 0);
3169 void Server::reportPrivsModified(const std::string &name)
3172 std::vector<session_t> clients = m_clients.getClientIDs();
3173 for (const session_t client_id : clients) {
3174 RemotePlayer *player = m_env->getPlayer(client_id);
3175 reportPrivsModified(player->getName());
3178 RemotePlayer *player = m_env->getPlayer(name.c_str());
3181 SendPlayerPrivileges(player->getPeerId());
3182 PlayerSAO *sao = player->getPlayerSAO();
3185 sao->updatePrivileges(
3186 getPlayerEffectivePrivs(name),
3191 void Server::reportInventoryFormspecModified(const std::string &name)
3193 RemotePlayer *player = m_env->getPlayer(name.c_str());
3196 SendPlayerInventoryFormspec(player->getPeerId());
3199 void Server::reportFormspecPrependModified(const std::string &name)
3201 RemotePlayer *player = m_env->getPlayer(name.c_str());
3204 SendPlayerFormspecPrepend(player->getPeerId());
3207 void Server::setIpBanned(const std::string &ip, const std::string &name)
3209 m_banmanager->add(ip, name);
3212 void Server::unsetIpBanned(const std::string &ip_or_name)
3214 m_banmanager->remove(ip_or_name);
3217 std::string Server::getBanDescription(const std::string &ip_or_name)
3219 return m_banmanager->getBanDescription(ip_or_name);
3222 void Server::notifyPlayer(const char *name, const std::wstring &msg)
3224 // m_env will be NULL if the server is initializing
3228 if (m_admin_nick == name && !m_admin_nick.empty()) {
3229 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
3232 RemotePlayer *player = m_env->getPlayer(name);
3237 if (player->getPeerId() == PEER_ID_INEXISTENT)
3240 SendChatMessage(player->getPeerId(), ChatMessage(msg));
3243 bool Server::showFormspec(const char *playername, const std::string &formspec,
3244 const std::string &formname)
3246 // m_env will be NULL if the server is initializing
3250 RemotePlayer *player = m_env->getPlayer(playername);
3254 SendShowFormspecMessage(player->getPeerId(), formspec, formname);
3258 u32 Server::hudAdd(RemotePlayer *player, HudElement *form)
3263 u32 id = player->addHud(form);
3265 SendHUDAdd(player->getPeerId(), id, form);
3270 bool Server::hudRemove(RemotePlayer *player, u32 id) {
3274 HudElement* todel = player->removeHud(id);
3281 SendHUDRemove(player->getPeerId(), id);
3285 bool Server::hudChange(RemotePlayer *player, u32 id, HudElementStat stat, void *data)
3290 SendHUDChange(player->getPeerId(), id, stat, data);
3294 bool Server::hudSetFlags(RemotePlayer *player, u32 flags, u32 mask)
3299 SendHUDSetFlags(player->getPeerId(), flags, mask);
3300 player->hud_flags &= ~mask;
3301 player->hud_flags |= flags;
3303 PlayerSAO* playersao = player->getPlayerSAO();
3308 m_script->player_event(playersao, "hud_changed");
3312 bool Server::hudSetHotbarItemcount(RemotePlayer *player, s32 hotbar_itemcount)
3317 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3320 player->setHotbarItemcount(hotbar_itemcount);
3321 std::ostringstream os(std::ios::binary);
3322 writeS32(os, hotbar_itemcount);
3323 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3327 void Server::hudSetHotbarImage(RemotePlayer *player, const std::string &name)
3332 player->setHotbarImage(name);
3333 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_IMAGE, name);
3336 void Server::hudSetHotbarSelectedImage(RemotePlayer *player, const std::string &name)
3341 player->setHotbarSelectedImage(name);
3342 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3345 Address Server::getPeerAddress(session_t peer_id)
3347 return m_con->GetPeerAddress(peer_id);
3350 void Server::setLocalPlayerAnimations(RemotePlayer *player,
3351 v2s32 animation_frames[4], f32 frame_speed)
3353 sanity_check(player);
3354 player->setLocalAnimations(animation_frames, frame_speed);
3355 SendLocalPlayerAnimations(player->getPeerId(), animation_frames, frame_speed);
3358 void Server::setPlayerEyeOffset(RemotePlayer *player, const v3f &first, const v3f &third)
3360 sanity_check(player);
3361 player->eye_offset_first = first;
3362 player->eye_offset_third = third;
3363 SendEyeOffset(player->getPeerId(), first, third);
3366 void Server::setSky(RemotePlayer *player, const SkyboxParams ¶ms)
3368 sanity_check(player);
3369 player->setSky(params);
3370 SendSetSky(player->getPeerId(), params);
3373 void Server::setSun(RemotePlayer *player, const SunParams ¶ms)
3375 sanity_check(player);
3376 player->setSun(params);
3377 SendSetSun(player->getPeerId(), params);
3380 void Server::setMoon(RemotePlayer *player, const MoonParams ¶ms)
3382 sanity_check(player);
3383 player->setMoon(params);
3384 SendSetMoon(player->getPeerId(), params);
3387 void Server::setStars(RemotePlayer *player, const StarParams ¶ms)
3389 sanity_check(player);
3390 player->setStars(params);
3391 SendSetStars(player->getPeerId(), params);
3394 void Server::setClouds(RemotePlayer *player, const CloudParams ¶ms)
3396 sanity_check(player);
3397 player->setCloudParams(params);
3398 SendCloudParams(player->getPeerId(), params);
3401 bool Server::overrideDayNightRatio(RemotePlayer *player, bool do_override,
3407 player->overrideDayNightRatio(do_override, ratio);
3408 SendOverrideDayNightRatio(player->getPeerId(), do_override, ratio);
3412 void Server::notifyPlayers(const std::wstring &msg)
3414 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(msg));
3417 void Server::spawnParticle(const std::string &playername, v3f pos,
3418 v3f velocity, v3f acceleration,
3419 float expirationtime, float size, bool
3420 collisiondetection, bool collision_removal, bool object_collision,
3421 bool vertical, const std::string &texture,
3422 const struct TileAnimationParams &animation, u8 glow)
3424 // m_env will be NULL if the server is initializing
3428 session_t peer_id = PEER_ID_INEXISTENT;
3430 if (!playername.empty()) {
3431 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3434 peer_id = player->getPeerId();
3435 proto_ver = player->protocol_version;
3438 SendSpawnParticle(peer_id, proto_ver, pos, velocity, acceleration,
3439 expirationtime, size, collisiondetection, collision_removal,
3440 object_collision, vertical, texture, animation, glow);
3443 u32 Server::addParticleSpawner(u16 amount, float spawntime,
3444 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
3445 float minexptime, float maxexptime, float minsize, float maxsize,
3446 bool collisiondetection, bool collision_removal, bool object_collision,
3447 ServerActiveObject *attached, bool vertical, const std::string &texture,
3448 const std::string &playername, const struct TileAnimationParams &animation,
3451 // m_env will be NULL if the server is initializing
3455 session_t peer_id = PEER_ID_INEXISTENT;
3457 if (!playername.empty()) {
3458 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3461 peer_id = player->getPeerId();
3462 proto_ver = player->protocol_version;
3465 u16 attached_id = attached ? attached->getId() : 0;
3468 if (attached_id == 0)
3469 id = m_env->addParticleSpawner(spawntime);
3471 id = m_env->addParticleSpawner(spawntime, attached_id);
3473 SendAddParticleSpawner(peer_id, proto_ver, amount, spawntime,
3474 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3475 minexptime, maxexptime, minsize, maxsize, collisiondetection,
3476 collision_removal, object_collision, attached_id, vertical,
3477 texture, id, animation, glow);
3482 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3484 // m_env will be NULL if the server is initializing
3486 throw ServerError("Can't delete particle spawners during initialisation!");
3488 session_t peer_id = PEER_ID_INEXISTENT;
3489 if (!playername.empty()) {
3490 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3493 peer_id = player->getPeerId();
3496 m_env->deleteParticleSpawner(id);
3497 SendDeleteParticleSpawner(peer_id, id);
3500 Inventory* Server::createDetachedInventory(const std::string &name, const std::string &player)
3502 if(m_detached_inventories.count(name) > 0){
3503 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3504 delete m_detached_inventories[name];
3506 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3508 Inventory *inv = new Inventory(m_itemdef);
3510 m_detached_inventories[name] = inv;
3511 if (!player.empty())
3512 m_detached_inventories_player[name] = player;
3514 //TODO find a better way to do this
3515 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3519 bool Server::removeDetachedInventory(const std::string &name)
3521 const auto &inv_it = m_detached_inventories.find(name);
3522 if (inv_it == m_detached_inventories.end())
3525 delete inv_it->second;
3526 m_detached_inventories.erase(inv_it);
3528 if (!m_env) // Mods are not done loading
3531 const auto &player_it = m_detached_inventories_player.find(name);
3532 if (player_it != m_detached_inventories_player.end()) {
3533 RemotePlayer *player = m_env->getPlayer(player_it->second.c_str());
3535 if (player && player->getPeerId() != PEER_ID_INEXISTENT)
3536 sendDetachedInventory(name, player->getPeerId());
3538 m_detached_inventories_player.erase(player_it);
3540 // Notify all players about the change
3541 sendDetachedInventory(name, PEER_ID_INEXISTENT);
3546 // actions: time-reversed list
3547 // Return value: success/failure
3548 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3549 std::list<std::string> *log)
3551 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3552 ServerMap *map = (ServerMap*)(&m_env->getMap());
3554 // Fail if no actions to handle
3555 if (actions.empty()) {
3557 log->push_back("Nothing to do.");
3564 for (const RollbackAction &action : actions) {
3566 bool success = action.applyRevert(map, this, this);
3569 std::ostringstream os;
3570 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3571 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3573 log->push_back(os.str());
3575 std::ostringstream os;
3576 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3577 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3579 log->push_back(os.str());
3583 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3584 <<" failed"<<std::endl;
3586 // Call it done if less than half failed
3587 return num_failed <= num_tried/2;
3590 // IGameDef interface
3592 IItemDefManager *Server::getItemDefManager()
3597 const NodeDefManager *Server::getNodeDefManager()
3602 ICraftDefManager *Server::getCraftDefManager()
3607 u16 Server::allocateUnknownNodeId(const std::string &name)
3609 return m_nodedef->allocateDummy(name);
3612 IWritableItemDefManager *Server::getWritableItemDefManager()
3617 NodeDefManager *Server::getWritableNodeDefManager()
3622 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3627 const std::vector<ModSpec> & Server::getMods() const
3629 return m_modmgr->getMods();
3632 const ModSpec *Server::getModSpec(const std::string &modname) const
3634 return m_modmgr->getModSpec(modname);
3637 void Server::getModNames(std::vector<std::string> &modlist)
3639 m_modmgr->getModNames(modlist);
3642 std::string Server::getBuiltinLuaPath()
3644 return porting::path_share + DIR_DELIM + "builtin";
3647 std::string Server::getModStoragePath() const
3649 return m_path_world + DIR_DELIM + "mod_storage";
3652 v3f Server::findSpawnPos()
3654 ServerMap &map = m_env->getServerMap();
3656 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf))
3657 return nodeposf * BS;
3659 bool is_good = false;
3660 // Limit spawn range to mapgen edges (determined by 'mapgen_limit')
3661 s32 range_max = map.getMapgenParams()->getSpawnRangeMax();
3663 // Try to find a good place a few times
3664 for (s32 i = 0; i < 4000 && !is_good; i++) {
3665 s32 range = MYMIN(1 + i, range_max);
3666 // We're going to try to throw the player to this position
3667 v2s16 nodepos2d = v2s16(
3668 -range + (myrand() % (range * 2)),
3669 -range + (myrand() % (range * 2)));
3670 // Get spawn level at point
3671 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3672 // Continue if MAX_MAP_GENERATION_LIMIT was returned by the mapgen to
3673 // signify an unsuitable spawn position, or if outside limits.
3674 if (spawn_level >= MAX_MAP_GENERATION_LIMIT ||
3675 spawn_level <= -MAX_MAP_GENERATION_LIMIT)
3678 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3679 // Consecutive empty nodes
3682 // Search upwards from 'spawn level' for 2 consecutive empty nodes, to
3683 // avoid obstructions in already-generated mapblocks.
3684 // In ungenerated mapblocks consisting of 'ignore' nodes, there will be
3685 // no obstructions, but mapgen decorations are generated after spawn so
3686 // the player may end up inside one.
3687 for (s32 i = 0; i < 8; i++) {
3688 v3s16 blockpos = getNodeBlockPos(nodepos);
3689 map.emergeBlock(blockpos, true);
3690 content_t c = map.getNode(nodepos).getContent();
3692 // In generated mapblocks allow spawn in all 'airlike' drawtype nodes.
3693 // In ungenerated mapblocks allow spawn in 'ignore' nodes.
3694 if (m_nodedef->get(c).drawtype == NDT_AIRLIKE || c == CONTENT_IGNORE) {
3696 if (air_count >= 2) {
3697 // Spawn in lower empty node
3699 nodeposf = intToFloat(nodepos, BS);
3700 // Don't spawn the player outside map boundaries
3701 if (objectpos_over_limit(nodeposf))
3702 // Exit this loop, positions above are probably over limit
3705 // Good position found, cause an exit from main loop
3719 // No suitable spawn point found, return fallback 0,0,0
3720 return v3f(0.0f, 0.0f, 0.0f);
3723 void Server::requestShutdown(const std::string &msg, bool reconnect, float delay)
3725 if (delay == 0.0f) {
3726 // No delay, shutdown immediately
3727 m_shutdown_state.is_requested = true;
3728 // only print to the infostream, a chat message saying
3729 // "Server Shutting Down" is sent when the server destructs.
3730 infostream << "*** Immediate Server shutdown requested." << std::endl;
3731 } else if (delay < 0.0f && m_shutdown_state.isTimerRunning()) {
3732 // Negative delay, cancel shutdown if requested
3733 m_shutdown_state.reset();
3734 std::wstringstream ws;
3736 ws << L"*** Server shutdown canceled.";
3738 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3739 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3740 // m_shutdown_* are already handled, skip.
3742 } else if (delay > 0.0f) {
3743 // Positive delay, tell the clients when the server will shut down
3744 std::wstringstream ws;
3746 ws << L"*** Server shutting down in "
3747 << duration_to_string(myround(delay)).c_str()
3750 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3751 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3754 m_shutdown_state.trigger(delay, msg, reconnect);
3757 PlayerSAO* Server::emergePlayer(const char *name, session_t peer_id, u16 proto_version)
3760 Try to get an existing player
3762 RemotePlayer *player = m_env->getPlayer(name);
3764 // If player is already connected, cancel
3765 if (player && player->getPeerId() != PEER_ID_INEXISTENT) {
3766 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3771 If player with the wanted peer_id already exists, cancel.
3773 if (m_env->getPlayer(peer_id)) {
3774 infostream<<"emergePlayer(): Player with wrong name but same"
3775 " peer_id already exists"<<std::endl;
3780 player = new RemotePlayer(name, idef());
3783 bool newplayer = false;
3786 PlayerSAO *playersao = m_env->loadPlayer(player, &newplayer, peer_id, isSingleplayer());
3788 // Complete init with server parts
3789 playersao->finalize(player, getPlayerEffectivePrivs(player->getName()));
3790 player->protocol_version = proto_version;
3794 m_script->on_newplayer(playersao);
3800 bool Server::registerModStorage(ModMetadata *storage)
3802 if (m_mod_storages.find(storage->getModName()) != m_mod_storages.end()) {
3803 errorstream << "Unable to register same mod storage twice. Storage name: "
3804 << storage->getModName() << std::endl;
3808 m_mod_storages[storage->getModName()] = storage;
3812 void Server::unregisterModStorage(const std::string &name)
3814 std::unordered_map<std::string, ModMetadata *>::const_iterator it = m_mod_storages.find(name);
3815 if (it != m_mod_storages.end()) {
3816 // Save unconditionaly on unregistration
3817 it->second->save(getModStoragePath());
3818 m_mod_storages.erase(name);
3822 void dedicated_server_loop(Server &server, bool &kill)
3824 verbosestream<<"dedicated_server_loop()"<<std::endl;
3826 IntervalLimiter m_profiler_interval;
3828 static thread_local const float steplen =
3829 g_settings->getFloat("dedicated_server_step");
3830 static thread_local const float profiler_print_interval =
3831 g_settings->getFloat("profiler_print_interval");
3834 * The dedicated server loop only does time-keeping (in Server::step) and
3835 * provides a way to main.cpp to kill the server externally (bool &kill).
3839 // This is kind of a hack but can be done like this
3840 // because server.step() is very light
3841 sleep_ms((int)(steplen*1000.0));
3842 server.step(steplen);
3844 if (server.isShutdownRequested() || kill)
3850 if (profiler_print_interval != 0) {
3851 if(m_profiler_interval.step(steplen, profiler_print_interval))
3853 infostream<<"Profiler:"<<std::endl;
3854 g_profiler->print(infostream);
3855 g_profiler->clear();
3860 infostream << "Dedicated server quitting" << std::endl;
3862 if (g_settings->getBool("server_announce"))
3863 ServerList::sendAnnounce(ServerList::AA_DELETE,
3864 server.m_bind_addr.getPort());
3873 bool Server::joinModChannel(const std::string &channel)
3875 return m_modchannel_mgr->joinChannel(channel, PEER_ID_SERVER) &&
3876 m_modchannel_mgr->setChannelState(channel, MODCHANNEL_STATE_READ_WRITE);
3879 bool Server::leaveModChannel(const std::string &channel)
3881 return m_modchannel_mgr->leaveChannel(channel, PEER_ID_SERVER);
3884 bool Server::sendModChannelMessage(const std::string &channel, const std::string &message)
3886 if (!m_modchannel_mgr->canWriteOnChannel(channel))
3889 broadcastModChannelMessage(channel, message, PEER_ID_SERVER);
3893 ModChannel* Server::getModChannel(const std::string &channel)
3895 return m_modchannel_mgr->getModChannel(channel);
3898 void Server::broadcastModChannelMessage(const std::string &channel,
3899 const std::string &message, session_t from_peer)
3901 const std::vector<u16> &peers = m_modchannel_mgr->getChannelPeers(channel);
3905 if (message.size() > STRING_MAX_LEN) {
3906 warningstream << "ModChannel message too long, dropping before sending "
3907 << " (" << message.size() << " > " << STRING_MAX_LEN << ", channel: "
3908 << channel << ")" << std::endl;
3913 if (from_peer != PEER_ID_SERVER) {
3914 sender = getPlayerName(from_peer);
3917 NetworkPacket resp_pkt(TOCLIENT_MODCHANNEL_MSG,
3918 2 + channel.size() + 2 + sender.size() + 2 + message.size());
3919 resp_pkt << channel << sender << message;
3920 for (session_t peer_id : peers) {
3922 if (peer_id == from_peer)
3925 Send(peer_id, &resp_pkt);
3928 if (from_peer != PEER_ID_SERVER) {
3929 m_script->on_modchannel_message(channel, sender, message);