3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include "network/connection.h"
25 #include "network/networkprotocol.h"
26 #include "network/serveropcodes.h"
28 #include "environment.h"
30 #include "threading/mutex_auto_lock.h"
31 #include "constants.h"
37 #include "serverobject.h"
38 #include "genericobject.h"
42 #include "scripting_server.h"
47 #include "mapgen/mapgen.h"
48 #include "mapgen/mg_biome.h"
49 #include "content_mapnode.h"
50 #include "content_nodemeta.h"
51 #include "content_sao.h"
52 #include "content/mods.h"
53 #include "modchannels.h"
54 #include "serverlist.h"
55 #include "util/string.h"
57 #include "util/serialize.h"
58 #include "util/thread.h"
59 #include "defaultsettings.h"
60 #include "server/mods.h"
61 #include "util/base64.h"
62 #include "util/sha1.h"
64 #include "database/database.h"
65 #include "chatmessage.h"
66 #include "chat_interface.h"
67 #include "remoteplayer.h"
69 class ClientNotFoundException : public BaseException
72 ClientNotFoundException(const char *s):
77 class ServerThread : public Thread
81 ServerThread(Server *server):
92 void *ServerThread::run()
94 BEGIN_DEBUG_EXCEPTION_HANDLER
96 m_server->AsyncRunStep(true);
98 while (!stopRequested()) {
100 m_server->AsyncRunStep();
104 } catch (con::NoIncomingDataException &e) {
105 } catch (con::PeerNotFoundException &e) {
106 infostream<<"Server: PeerNotFoundException"<<std::endl;
107 } catch (ClientNotFoundException &e) {
108 } catch (con::ConnectionBindFailed &e) {
109 m_server->setAsyncFatalError(e.what());
110 } catch (LuaError &e) {
111 m_server->setAsyncFatalError(
112 "ServerThread::run Lua: " + std::string(e.what()));
116 END_DEBUG_EXCEPTION_HANDLER
121 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
123 if(pos_exists) *pos_exists = false;
128 if(pos_exists) *pos_exists = true;
133 ServerActiveObject *sao = env->getActiveObject(object);
136 if(pos_exists) *pos_exists = true;
137 return sao->getBasePosition(); }
142 void Server::ShutdownState::reset()
146 should_reconnect = false;
147 is_requested = false;
150 void Server::ShutdownState::trigger(float delay, const std::string &msg, bool reconnect)
154 should_reconnect = reconnect;
157 void Server::ShutdownState::tick(float dtime, Server *server)
163 static const float shutdown_msg_times[] =
165 1, 2, 3, 4, 5, 10, 20, 40, 60, 120, 180, 300, 600, 1200, 1800, 3600
168 // Automated messages
169 if (m_timer < shutdown_msg_times[ARRLEN(shutdown_msg_times) - 1]) {
170 for (float t : shutdown_msg_times) {
171 // If shutdown timer matches an automessage, shot it
172 if (m_timer > t && m_timer - dtime < t) {
173 std::wstring periodicMsg = getShutdownTimerMessage();
175 infostream << wide_to_utf8(periodicMsg).c_str() << std::endl;
176 server->SendChatMessage(PEER_ID_INEXISTENT, periodicMsg);
183 if (m_timer < 0.0f) {
189 std::wstring Server::ShutdownState::getShutdownTimerMessage() const
191 std::wstringstream ws;
192 ws << L"*** Server shutting down in "
193 << duration_to_string(myround(m_timer)).c_str() << ".";
202 const std::string &path_world,
203 const SubgameSpec &gamespec,
204 bool simple_singleplayer_mode,
209 m_bind_addr(bind_addr),
210 m_path_world(path_world),
211 m_gamespec(gamespec),
212 m_simple_singleplayer_mode(simple_singleplayer_mode),
213 m_dedicated(dedicated),
214 m_async_fatal_error(""),
215 m_con(std::make_shared<con::Connection>(PROTOCOL_ID,
218 m_bind_addr.isIPv6(),
220 m_itemdef(createItemDefManager()),
221 m_nodedef(createNodeDefManager()),
222 m_craftdef(createCraftDefManager()),
226 m_modchannel_mgr(new ModChannelMgr())
228 m_lag = g_settings->getFloat("dedicated_server_step");
230 if (m_path_world.empty())
231 throw ServerError("Supplied empty world path");
233 if (!gamespec.isValid())
234 throw ServerError("Supplied invalid gamespec");
240 // Send shutdown message
241 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE,
242 L"*** Server shutting down"));
245 MutexAutoLock envlock(m_env_mutex);
247 infostream << "Server: Saving players" << std::endl;
248 m_env->saveLoadedPlayers();
250 infostream << "Server: Kicking players" << std::endl;
251 std::string kick_msg;
252 bool reconnect = false;
253 if (isShutdownRequested()) {
254 reconnect = m_shutdown_state.should_reconnect;
255 kick_msg = m_shutdown_state.message;
257 if (kick_msg.empty()) {
258 kick_msg = g_settings->get("kick_msg_shutdown");
260 m_env->kickAllPlayers(SERVER_ACCESSDENIED_SHUTDOWN,
261 kick_msg, reconnect);
264 actionstream << "Server: Shutting down" << std::endl;
266 // Do this before stopping the server in case mapgen callbacks need to access
267 // server-controlled resources (like ModStorages). Also do them before
268 // shutdown callbacks since they may modify state that is finalized in a
271 m_emerge->stopThreads();
274 MutexAutoLock envlock(m_env_mutex);
276 // Execute script shutdown hooks
277 infostream << "Executing shutdown hooks" << std::endl;
278 m_script->on_shutdown();
280 infostream << "Server: Saving environment metadata" << std::endl;
290 // Delete things in the reverse order of creation
299 // Deinitialize scripting
300 infostream << "Server: Deinitializing scripting" << std::endl;
303 // Delete detached inventories
304 for (auto &detached_inventory : m_detached_inventories) {
305 delete detached_inventory.second;
311 infostream << "Server created for gameid \"" << m_gamespec.id << "\"";
312 if (m_simple_singleplayer_mode)
313 infostream << " in simple singleplayer mode" << std::endl;
315 infostream << std::endl;
316 infostream << "- world: " << m_path_world << std::endl;
317 infostream << "- game: " << m_gamespec.path << std::endl;
319 // Create world if it doesn't exist
320 if (!loadGameConfAndInitWorld(m_path_world, m_gamespec))
321 throw ServerError("Failed to initialize world");
323 // Create server thread
324 m_thread = new ServerThread(this);
326 // Create emerge manager
327 m_emerge = new EmergeManager(this);
329 // Create ban manager
330 std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
331 m_banmanager = new BanManager(ban_path);
333 m_modmgr = std::unique_ptr<ServerModManager>(new ServerModManager(m_path_world));
334 std::vector<ModSpec> unsatisfied_mods = m_modmgr->getUnsatisfiedMods();
335 // complain about mods with unsatisfied dependencies
336 if (!m_modmgr->isConsistent()) {
337 m_modmgr->printUnsatisfiedModsError();
341 MutexAutoLock envlock(m_env_mutex);
343 // Create the Map (loads map_meta.txt, overriding configured mapgen params)
344 ServerMap *servermap = new ServerMap(m_path_world, this, m_emerge);
346 // Initialize scripting
347 infostream << "Server: Initializing Lua" << std::endl;
349 m_script = new ServerScripting(this);
351 m_script->loadMod(getBuiltinLuaPath() + DIR_DELIM "init.lua", BUILTIN_MOD_NAME);
353 m_modmgr->loadMods(m_script);
355 // Read Textures and calculate sha1 sums
358 // Apply item aliases in the node definition manager
359 m_nodedef->updateAliases(m_itemdef);
361 // Apply texture overrides from texturepack/override.txt
362 std::vector<std::string> paths;
363 fs::GetRecursiveDirs(paths, g_settings->get("texture_path"));
364 fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures");
365 for (const std::string &path : paths)
366 m_nodedef->applyTextureOverrides(path + DIR_DELIM + "override.txt");
368 m_nodedef->setNodeRegistrationStatus(true);
370 // Perform pending node name resolutions
371 m_nodedef->runNodeResolveCallbacks();
373 // unmap node names for connected nodeboxes
374 m_nodedef->mapNodeboxConnections();
376 // init the recipe hashes to speed up crafting
377 m_craftdef->initHashes(this);
379 // Initialize Environment
380 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
382 m_clients.setEnv(m_env);
384 if (!servermap->settings_mgr.makeMapgenParams())
385 FATAL_ERROR("Couldn't create any mapgen type");
387 // Initialize mapgens
388 m_emerge->initMapgens(servermap->getMapgenParams());
390 if (g_settings->getBool("enable_rollback_recording")) {
391 // Create rollback manager
392 m_rollback = new RollbackManager(m_path_world, this);
395 // Give environment reference to scripting api
396 m_script->initializeEnvironment(m_env);
398 // Register us to receive map edit events
399 servermap->addEventReceiver(this);
403 m_liquid_transform_every = g_settings->getFloat("liquid_update");
404 m_max_chatmessage_length = g_settings->getU16("chat_message_max_size");
405 m_csm_restriction_flags = g_settings->getU64("csm_restriction_flags");
406 m_csm_restriction_noderange = g_settings->getU32("csm_restriction_noderange");
411 infostream << "Starting server on " << m_bind_addr.serializeString()
412 << "..." << std::endl;
414 // Stop thread if already running
417 // Initialize connection
418 m_con->SetTimeoutMs(30);
419 m_con->Serve(m_bind_addr);
424 // ASCII art for the win!
426 << " .__ __ __ " << std::endl
427 << " _____ |__| ____ _____/ |_ ____ _______/ |_ " << std::endl
428 << " / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\" << std::endl
429 << "| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | " << std::endl
430 << "|__|_| /__|___| /\\___ >__| \\___ >____ > |__| " << std::endl
431 << " \\/ \\/ \\/ \\/ \\/ " << std::endl;
432 actionstream << "World at [" << m_path_world << "]" << std::endl;
433 actionstream << "Server for gameid=\"" << m_gamespec.id
434 << "\" listening on " << m_bind_addr.serializeString() << ":"
435 << m_bind_addr.getPort() << "." << std::endl;
440 infostream<<"Server: Stopping and waiting threads"<<std::endl;
442 // Stop threads (set run=false first so both start stopping)
444 //m_emergethread.setRun(false);
446 //m_emergethread.stop();
448 infostream<<"Server: Threads stopped"<<std::endl;
451 void Server::step(float dtime)
457 MutexAutoLock lock(m_step_dtime_mutex);
458 m_step_dtime += dtime;
460 // Throw if fatal error occurred in thread
461 std::string async_err = m_async_fatal_error.get();
462 if (!async_err.empty()) {
463 if (!m_simple_singleplayer_mode) {
464 m_env->kickAllPlayers(SERVER_ACCESSDENIED_CRASH,
465 g_settings->get("kick_msg_crash"),
466 g_settings->getBool("ask_reconnect_on_crash"));
468 throw ServerError("AsyncErr: " + async_err);
472 void Server::AsyncRunStep(bool initial_step)
474 g_profiler->add("Server::AsyncRunStep (num)", 1);
478 MutexAutoLock lock1(m_step_dtime_mutex);
479 dtime = m_step_dtime;
483 // Send blocks to clients
487 if((dtime < 0.001) && !initial_step)
490 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
492 //infostream<<"Server steps "<<dtime<<std::endl;
493 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
496 MutexAutoLock lock1(m_step_dtime_mutex);
497 m_step_dtime -= dtime;
504 m_uptime.set(m_uptime.get() + dtime);
510 Update time of day and overall game time
512 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
515 Send to clients at constant intervals
518 m_time_of_day_send_timer -= dtime;
519 if(m_time_of_day_send_timer < 0.0) {
520 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
521 u16 time = m_env->getTimeOfDay();
522 float time_speed = g_settings->getFloat("time_speed");
523 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
527 MutexAutoLock lock(m_env_mutex);
528 // Figure out and report maximum lag to environment
529 float max_lag = m_env->getMaxLagEstimate();
530 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
532 if(dtime > 0.1 && dtime > max_lag * 2.0)
533 infostream<<"Server: Maximum lag peaked to "<<dtime
537 m_env->reportMaxLagEstimate(max_lag);
539 ScopeProfiler sp(g_profiler, "SEnv step");
540 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
544 static const float map_timer_and_unload_dtime = 2.92;
545 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
547 MutexAutoLock lock(m_env_mutex);
548 // Run Map's timers and unload unused data
549 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
550 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
551 g_settings->getFloat("server_unload_unused_data_timeout"),
556 Listen to the admin chat, if available
559 if (!m_admin_chat->command_queue.empty()) {
560 MutexAutoLock lock(m_env_mutex);
561 while (!m_admin_chat->command_queue.empty()) {
562 ChatEvent *evt = m_admin_chat->command_queue.pop_frontNoEx();
563 handleChatInterfaceEvent(evt);
567 m_admin_chat->outgoing_queue.push_back(
568 new ChatEventTimeInfo(m_env->getGameTime(), m_env->getTimeOfDay()));
575 /* Transform liquids */
576 m_liquid_transform_timer += dtime;
577 if(m_liquid_transform_timer >= m_liquid_transform_every)
579 m_liquid_transform_timer -= m_liquid_transform_every;
581 MutexAutoLock lock(m_env_mutex);
583 ScopeProfiler sp(g_profiler, "Server: liquid transform");
585 std::map<v3s16, MapBlock*> modified_blocks;
586 m_env->getMap().transformLiquids(modified_blocks, m_env);
589 Set the modified blocks unsent for all the clients
591 if (!modified_blocks.empty()) {
592 SetBlocksNotSent(modified_blocks);
595 m_clients.step(dtime);
597 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
599 // send masterserver announce
601 float &counter = m_masterserver_timer;
602 if (!isSingleplayer() && (!counter || counter >= 300.0) &&
603 g_settings->getBool("server_announce")) {
604 ServerList::sendAnnounce(counter ? ServerList::AA_UPDATE :
605 ServerList::AA_START,
606 m_bind_addr.getPort(),
607 m_clients.getPlayerNames(),
609 m_env->getGameTime(),
612 Mapgen::getMapgenName(m_emerge->mgparams->mgtype),
622 Check added and deleted active objects
625 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
626 MutexAutoLock envlock(m_env_mutex);
629 const RemoteClientMap &clients = m_clients.getClientList();
630 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
632 // Radius inside which objects are active
633 static thread_local const s16 radius =
634 g_settings->getS16("active_object_send_range_blocks") * MAP_BLOCKSIZE;
636 // Radius inside which players are active
637 static thread_local const bool is_transfer_limited =
638 g_settings->exists("unlimited_player_transfer_distance") &&
639 !g_settings->getBool("unlimited_player_transfer_distance");
640 static thread_local const s16 player_transfer_dist =
641 g_settings->getS16("player_transfer_distance") * MAP_BLOCKSIZE;
642 s16 player_radius = player_transfer_dist;
643 if (player_radius == 0 && is_transfer_limited)
644 player_radius = radius;
646 for (const auto &client_it : clients) {
647 RemoteClient *client = client_it.second;
649 // If definitions and textures have not been sent, don't
650 // send objects either
651 if (client->getState() < CS_DefinitionsSent)
654 RemotePlayer *player = m_env->getPlayer(client->peer_id);
656 // This can happen if the client timeouts somehow
660 PlayerSAO *playersao = player->getPlayerSAO();
664 s16 my_radius = MYMIN(radius, playersao->getWantedRange() * MAP_BLOCKSIZE);
665 if (my_radius <= 0) my_radius = radius;
666 //infostream << "Server: Active Radius " << my_radius << std::endl;
668 std::queue<u16> removed_objects;
669 std::queue<u16> added_objects;
670 m_env->getRemovedActiveObjects(playersao, my_radius, player_radius,
671 client->m_known_objects, removed_objects);
672 m_env->getAddedActiveObjects(playersao, my_radius, player_radius,
673 client->m_known_objects, added_objects);
675 // Ignore if nothing happened
676 if (removed_objects.empty() && added_objects.empty()) {
680 std::string data_buffer;
684 // Handle removed objects
685 writeU16((u8*)buf, removed_objects.size());
686 data_buffer.append(buf, 2);
687 while (!removed_objects.empty()) {
689 u16 id = removed_objects.front();
690 ServerActiveObject* obj = m_env->getActiveObject(id);
692 // Add to data buffer for sending
693 writeU16((u8*)buf, id);
694 data_buffer.append(buf, 2);
696 // Remove from known objects
697 client->m_known_objects.erase(id);
699 if(obj && obj->m_known_by_count > 0)
700 obj->m_known_by_count--;
701 removed_objects.pop();
704 // Handle added objects
705 writeU16((u8*)buf, added_objects.size());
706 data_buffer.append(buf, 2);
707 while (!added_objects.empty()) {
709 u16 id = added_objects.front();
710 ServerActiveObject* obj = m_env->getActiveObject(id);
713 u8 type = ACTIVEOBJECT_TYPE_INVALID;
715 warningstream << FUNCTION_NAME << ": NULL object" << std::endl;
717 type = obj->getSendType();
719 // Add to data buffer for sending
720 writeU16((u8*)buf, id);
721 data_buffer.append(buf, 2);
722 writeU8((u8*)buf, type);
723 data_buffer.append(buf, 1);
726 data_buffer.append(serializeLongString(
727 obj->getClientInitializationData(client->net_proto_version)));
729 data_buffer.append(serializeLongString(""));
731 // Add to known objects
732 client->m_known_objects.insert(id);
735 obj->m_known_by_count++;
740 u32 pktSize = SendActiveObjectRemoveAdd(client->peer_id, data_buffer);
741 verbosestream << "Server: Sent object remove/add: "
742 << removed_objects.size() << " removed, "
743 << added_objects.size() << " added, "
744 << "packet size is " << pktSize << std::endl;
748 m_mod_storage_save_timer -= dtime;
749 if (m_mod_storage_save_timer <= 0.0f) {
750 infostream << "Saving registered mod storages." << std::endl;
751 m_mod_storage_save_timer = g_settings->getFloat("server_map_save_interval");
752 for (std::unordered_map<std::string, ModMetadata *>::const_iterator
753 it = m_mod_storages.begin(); it != m_mod_storages.end(); ++it) {
754 if (it->second->isModified()) {
755 it->second->save(getModStoragePath());
765 MutexAutoLock envlock(m_env_mutex);
766 ScopeProfiler sp(g_profiler, "Server: sending object messages");
769 // Value = data sent by object
770 std::unordered_map<u16, std::vector<ActiveObjectMessage>*> buffered_messages;
772 // Get active object messages from environment
774 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
778 std::vector<ActiveObjectMessage>* message_list = nullptr;
779 std::unordered_map<u16, std::vector<ActiveObjectMessage>* >::iterator n;
780 n = buffered_messages.find(aom.id);
781 if (n == buffered_messages.end()) {
782 message_list = new std::vector<ActiveObjectMessage>;
783 buffered_messages[aom.id] = message_list;
786 message_list = n->second;
788 message_list->push_back(aom);
792 const RemoteClientMap &clients = m_clients.getClientList();
793 // Route data to every client
794 for (const auto &client_it : clients) {
795 RemoteClient *client = client_it.second;
796 std::string reliable_data;
797 std::string unreliable_data;
798 // Go through all objects in message buffer
799 for (const auto &buffered_message : buffered_messages) {
800 // If object is not known by client, skip it
801 u16 id = buffered_message.first;
802 if (client->m_known_objects.find(id) == client->m_known_objects.end())
805 // Get message list of object
806 std::vector<ActiveObjectMessage>* list = buffered_message.second;
807 // Go through every message
808 for (const ActiveObjectMessage &aom : *list) {
809 // Compose the full new data with header
810 std::string new_data;
813 writeU16((u8*)&buf[0], aom.id);
814 new_data.append(buf, 2);
816 new_data += serializeString(aom.datastring);
817 // Add data to buffer
819 reliable_data += new_data;
821 unreliable_data += new_data;
825 reliable_data and unreliable_data are now ready.
828 if (!reliable_data.empty()) {
829 SendActiveObjectMessages(client->peer_id, reliable_data);
832 if (!unreliable_data.empty()) {
833 SendActiveObjectMessages(client->peer_id, unreliable_data, false);
838 // Clear buffered_messages
839 for (auto &buffered_message : buffered_messages) {
840 delete buffered_message.second;
845 Send queued-for-sending map edit events.
848 // We will be accessing the environment
849 MutexAutoLock lock(m_env_mutex);
851 // Don't send too many at a time
854 // Single change sending is disabled if queue size is not small
855 bool disable_single_change_sending = false;
856 if(m_unsent_map_edit_queue.size() >= 4)
857 disable_single_change_sending = true;
859 int event_count = m_unsent_map_edit_queue.size();
861 // We'll log the amount of each
864 std::list<v3s16> node_meta_updates;
866 while (!m_unsent_map_edit_queue.empty()) {
867 MapEditEvent* event = m_unsent_map_edit_queue.front();
868 m_unsent_map_edit_queue.pop();
870 // Players far away from the change are stored here.
871 // Instead of sending the changes, MapBlocks are set not sent
873 std::unordered_set<u16> far_players;
875 switch (event->type) {
878 prof.add("MEET_ADDNODE", 1);
879 sendAddNode(event->p, event->n, &far_players,
880 disable_single_change_sending ? 5 : 30,
881 event->type == MEET_ADDNODE);
883 case MEET_REMOVENODE:
884 prof.add("MEET_REMOVENODE", 1);
885 sendRemoveNode(event->p, &far_players,
886 disable_single_change_sending ? 5 : 30);
888 case MEET_BLOCK_NODE_METADATA_CHANGED: {
889 verbosestream << "Server: MEET_BLOCK_NODE_METADATA_CHANGED" << std::endl;
890 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
891 if (!event->is_private_change) {
892 // Don't send the change yet. Collect them to eliminate dupes.
893 node_meta_updates.remove(event->p);
894 node_meta_updates.push_back(event->p);
897 if (MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(
898 getNodeBlockPos(event->p))) {
899 block->raiseModified(MOD_STATE_WRITE_NEEDED,
900 MOD_REASON_REPORT_META_CHANGE);
905 infostream << "Server: MEET_OTHER" << std::endl;
906 prof.add("MEET_OTHER", 1);
907 for (const v3s16 &modified_block : event->modified_blocks) {
908 m_clients.markBlockposAsNotSent(modified_block);
912 prof.add("unknown", 1);
913 warningstream << "Server: Unknown MapEditEvent "
914 << ((u32)event->type) << std::endl;
919 Set blocks not sent to far players
921 if (!far_players.empty()) {
922 // Convert list format to that wanted by SetBlocksNotSent
923 std::map<v3s16, MapBlock*> modified_blocks2;
924 for (const v3s16 &modified_block : event->modified_blocks) {
925 modified_blocks2[modified_block] =
926 m_env->getMap().getBlockNoCreateNoEx(modified_block);
929 // Set blocks not sent
930 for (const u16 far_player : far_players) {
931 if (RemoteClient *client = getClient(far_player))
932 client->SetBlocksNotSent(modified_blocks2);
939 if (event_count >= 5) {
940 infostream << "Server: MapEditEvents:" << std::endl;
941 prof.print(infostream);
942 } else if (event_count != 0) {
943 verbosestream << "Server: MapEditEvents:" << std::endl;
944 prof.print(verbosestream);
947 // Send all metadata updates
948 if (node_meta_updates.size())
949 sendMetadataChanged(node_meta_updates);
953 Trigger emergethread (it somehow gets to a non-triggered but
954 bysy state sometimes)
957 float &counter = m_emergethread_trigger_timer;
959 if (counter >= 2.0) {
962 m_emerge->startThreads();
966 // Save map, players and auth stuff
968 float &counter = m_savemap_timer;
970 static thread_local const float save_interval =
971 g_settings->getFloat("server_map_save_interval");
972 if (counter >= save_interval) {
974 MutexAutoLock lock(m_env_mutex);
976 ScopeProfiler sp(g_profiler, "Server: saving stuff");
979 if (m_banmanager->isModified()) {
980 m_banmanager->save();
983 // Save changed parts of map
984 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
987 m_env->saveLoadedPlayers();
989 // Save environment metadata
994 m_shutdown_state.tick(dtime, this);
997 void Server::Receive()
999 session_t peer_id = 0;
1002 m_con->Receive(&pkt);
1003 peer_id = pkt.getPeerId();
1005 } catch (const con::InvalidIncomingDataException &e) {
1006 infostream << "Server::Receive(): InvalidIncomingDataException: what()="
1007 << e.what() << std::endl;
1008 } catch (const SerializationError &e) {
1009 infostream << "Server::Receive(): SerializationError: what()="
1010 << e.what() << std::endl;
1011 } catch (const ClientStateError &e) {
1012 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1013 DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
1014 L"Try reconnecting or updating your client");
1015 } catch (const con::PeerNotFoundException &e) {
1020 PlayerSAO* Server::StageTwoClientInit(session_t peer_id)
1022 std::string playername;
1023 PlayerSAO *playersao = NULL;
1026 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1028 playername = client->getName();
1029 playersao = emergePlayer(playername.c_str(), peer_id, client->net_proto_version);
1031 } catch (std::exception &e) {
1037 RemotePlayer *player = m_env->getPlayer(playername.c_str());
1039 // If failed, cancel
1040 if (!playersao || !player) {
1041 if (player && player->getPeerId() != PEER_ID_INEXISTENT) {
1042 actionstream << "Server: Failed to emerge player \"" << playername
1043 << "\" (player allocated to an another client)" << std::endl;
1044 DenyAccess_Legacy(peer_id, L"Another client is connected with this "
1045 L"name. If your client closed unexpectedly, try again in "
1048 errorstream << "Server: " << playername << ": Failed to emerge player"
1050 DenyAccess_Legacy(peer_id, L"Could not allocate player.");
1056 Send complete position information
1058 SendMovePlayer(peer_id);
1061 SendPlayerPrivileges(peer_id);
1063 // Send inventory formspec
1064 SendPlayerInventoryFormspec(peer_id);
1067 SendInventory(playersao);
1069 // Send HP or death screen
1070 if (playersao->isDead())
1071 SendDeathscreen(peer_id, false, v3f(0,0,0));
1073 SendPlayerHPOrDie(playersao,
1074 PlayerHPChangeReason(PlayerHPChangeReason::SET_HP));
1077 SendPlayerBreath(playersao);
1079 Address addr = getPeerAddress(player->getPeerId());
1080 std::string ip_str = addr.serializeString();
1081 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1086 const std::vector<std::string> &names = m_clients.getPlayerNames();
1088 actionstream << player->getName() << " joins game. List of players: ";
1090 for (const std::string &name : names) {
1091 actionstream << name << " ";
1094 actionstream << player->getName() <<std::endl;
1099 inline void Server::handleCommand(NetworkPacket* pkt)
1101 const ToServerCommandHandler& opHandle = toServerCommandTable[pkt->getCommand()];
1102 (this->*opHandle.handler)(pkt);
1105 void Server::ProcessData(NetworkPacket *pkt)
1107 // Environment is locked first.
1108 MutexAutoLock envlock(m_env_mutex);
1110 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1111 u32 peer_id = pkt->getPeerId();
1114 Address address = getPeerAddress(peer_id);
1115 std::string addr_s = address.serializeString();
1117 if(m_banmanager->isIpBanned(addr_s)) {
1118 std::string ban_name = m_banmanager->getBanName(addr_s);
1119 infostream << "Server: A banned client tried to connect from "
1120 << addr_s << "; banned name was "
1121 << ban_name << std::endl;
1122 // This actually doesn't seem to transfer to the client
1123 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1124 + utf8_to_wide(ban_name));
1128 catch(con::PeerNotFoundException &e) {
1130 * no peer for this packet found
1131 * most common reason is peer timeout, e.g. peer didn't
1132 * respond for some time, your server was overloaded or
1135 infostream << "Server::ProcessData(): Canceling: peer "
1136 << peer_id << " not found" << std::endl;
1141 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1143 // Command must be handled into ToServerCommandHandler
1144 if (command >= TOSERVER_NUM_MSG_TYPES) {
1145 infostream << "Server: Ignoring unknown command "
1146 << command << std::endl;
1150 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1155 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1157 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1158 errorstream << "Server::ProcessData(): Cancelling: Peer"
1159 " serialization format invalid or not initialized."
1160 " Skipping incoming command=" << command << std::endl;
1164 /* Handle commands related to client startup */
1165 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1170 if (m_clients.getClientState(peer_id) < CS_Active) {
1171 if (command == TOSERVER_PLAYERPOS) return;
1173 errorstream << "Got packet command: " << command << " for peer id "
1174 << peer_id << " but client isn't active yet. Dropping packet "
1180 } catch (SendFailedException &e) {
1181 errorstream << "Server::ProcessData(): SendFailedException: "
1182 << "what=" << e.what()
1184 } catch (PacketError &e) {
1185 actionstream << "Server::ProcessData(): PacketError: "
1186 << "what=" << e.what()
1191 void Server::setTimeOfDay(u32 time)
1193 m_env->setTimeOfDay(time);
1194 m_time_of_day_send_timer = 0;
1197 void Server::onMapEditEvent(MapEditEvent *event)
1199 if (m_ignore_map_edit_events_area.contains(event->getArea()))
1201 MapEditEvent *e = event->clone();
1202 m_unsent_map_edit_queue.push(e);
1205 Inventory* Server::getInventory(const InventoryLocation &loc)
1208 case InventoryLocation::UNDEFINED:
1209 case InventoryLocation::CURRENT_PLAYER:
1211 case InventoryLocation::PLAYER:
1213 RemotePlayer *player = m_env->getPlayer(loc.name.c_str());
1216 PlayerSAO *playersao = player->getPlayerSAO();
1219 return playersao->getInventory();
1222 case InventoryLocation::NODEMETA:
1224 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1227 return meta->getInventory();
1230 case InventoryLocation::DETACHED:
1232 if(m_detached_inventories.count(loc.name) == 0)
1234 return m_detached_inventories[loc.name];
1238 sanity_check(false); // abort
1244 void Server::setInventoryModified(const InventoryLocation &loc, bool playerSend)
1247 case InventoryLocation::UNDEFINED:
1249 case InventoryLocation::PLAYER:
1254 RemotePlayer *player = m_env->getPlayer(loc.name.c_str());
1259 PlayerSAO *playersao = player->getPlayerSAO();
1263 SendInventory(playersao);
1266 case InventoryLocation::NODEMETA:
1269 event.type = MEET_BLOCK_NODE_METADATA_CHANGED;
1271 m_env->getMap().dispatchEvent(&event);
1274 case InventoryLocation::DETACHED:
1276 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
1280 sanity_check(false); // abort
1285 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1287 std::vector<session_t> clients = m_clients.getClientIDs();
1289 // Set the modified blocks unsent for all the clients
1290 for (const session_t client_id : clients) {
1291 if (RemoteClient *client = m_clients.lockedGetClientNoEx(client_id))
1292 client->SetBlocksNotSent(block);
1297 void Server::peerAdded(con::Peer *peer)
1299 verbosestream<<"Server::peerAdded(): peer->id="
1300 <<peer->id<<std::endl;
1302 m_peer_change_queue.push(con::PeerChange(con::PEER_ADDED, peer->id, false));
1305 void Server::deletingPeer(con::Peer *peer, bool timeout)
1307 verbosestream<<"Server::deletingPeer(): peer->id="
1308 <<peer->id<<", timeout="<<timeout<<std::endl;
1310 m_clients.event(peer->id, CSE_Disconnect);
1311 m_peer_change_queue.push(con::PeerChange(con::PEER_REMOVED, peer->id, timeout));
1314 bool Server::getClientConInfo(session_t peer_id, con::rtt_stat_type type, float* retval)
1316 *retval = m_con->getPeerStat(peer_id,type);
1317 return *retval != -1;
1320 bool Server::getClientInfo(
1329 std::string* vers_string
1332 *state = m_clients.getClientState(peer_id);
1334 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1341 *uptime = client->uptime();
1342 *ser_vers = client->serialization_version;
1343 *prot_vers = client->net_proto_version;
1345 *major = client->getMajor();
1346 *minor = client->getMinor();
1347 *patch = client->getPatch();
1348 *vers_string = client->getPatch();
1355 void Server::handlePeerChanges()
1357 while(!m_peer_change_queue.empty())
1359 con::PeerChange c = m_peer_change_queue.front();
1360 m_peer_change_queue.pop();
1362 verbosestream<<"Server: Handling peer change: "
1363 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1368 case con::PEER_ADDED:
1369 m_clients.CreateClient(c.peer_id);
1372 case con::PEER_REMOVED:
1373 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1377 FATAL_ERROR("Invalid peer change event received!");
1383 void Server::printToConsoleOnly(const std::string &text)
1386 m_admin_chat->outgoing_queue.push_back(
1387 new ChatEventChat("", utf8_to_wide(text)));
1389 std::cout << text << std::endl;
1393 void Server::Send(NetworkPacket *pkt)
1395 Send(pkt->getPeerId(), pkt);
1398 void Server::Send(session_t peer_id, NetworkPacket *pkt)
1400 m_clients.send(peer_id,
1401 clientCommandFactoryTable[pkt->getCommand()].channel,
1403 clientCommandFactoryTable[pkt->getCommand()].reliable);
1406 void Server::SendMovement(session_t peer_id)
1408 std::ostringstream os(std::ios_base::binary);
1410 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1412 pkt << g_settings->getFloat("movement_acceleration_default");
1413 pkt << g_settings->getFloat("movement_acceleration_air");
1414 pkt << g_settings->getFloat("movement_acceleration_fast");
1415 pkt << g_settings->getFloat("movement_speed_walk");
1416 pkt << g_settings->getFloat("movement_speed_crouch");
1417 pkt << g_settings->getFloat("movement_speed_fast");
1418 pkt << g_settings->getFloat("movement_speed_climb");
1419 pkt << g_settings->getFloat("movement_speed_jump");
1420 pkt << g_settings->getFloat("movement_liquid_fluidity");
1421 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1422 pkt << g_settings->getFloat("movement_liquid_sink");
1423 pkt << g_settings->getFloat("movement_gravity");
1428 void Server::SendPlayerHPOrDie(PlayerSAO *playersao, const PlayerHPChangeReason &reason)
1430 if (!g_settings->getBool("enable_damage"))
1433 session_t peer_id = playersao->getPeerID();
1434 bool is_alive = playersao->getHP() > 0;
1437 SendPlayerHP(peer_id);
1439 DiePlayer(peer_id, reason);
1442 void Server::SendHP(session_t peer_id, u16 hp)
1444 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1449 void Server::SendBreath(session_t peer_id, u16 breath)
1451 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1452 pkt << (u16) breath;
1456 void Server::SendAccessDenied(session_t peer_id, AccessDeniedCode reason,
1457 const std::string &custom_reason, bool reconnect)
1459 assert(reason < SERVER_ACCESSDENIED_MAX);
1461 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1463 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
1464 pkt << custom_reason;
1465 else if (reason == SERVER_ACCESSDENIED_SHUTDOWN ||
1466 reason == SERVER_ACCESSDENIED_CRASH)
1467 pkt << custom_reason << (u8)reconnect;
1471 void Server::SendAccessDenied_Legacy(session_t peer_id,const std::wstring &reason)
1473 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1478 void Server::SendDeathscreen(session_t peer_id, bool set_camera_point_target,
1479 v3f camera_point_target)
1481 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1482 pkt << set_camera_point_target << camera_point_target;
1486 void Server::SendItemDef(session_t peer_id,
1487 IItemDefManager *itemdef, u16 protocol_version)
1489 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1493 u32 length of the next item
1494 zlib-compressed serialized ItemDefManager
1496 std::ostringstream tmp_os(std::ios::binary);
1497 itemdef->serialize(tmp_os, protocol_version);
1498 std::ostringstream tmp_os2(std::ios::binary);
1499 compressZlib(tmp_os.str(), tmp_os2);
1500 pkt.putLongString(tmp_os2.str());
1503 verbosestream << "Server: Sending item definitions to id(" << peer_id
1504 << "): size=" << pkt.getSize() << std::endl;
1509 void Server::SendNodeDef(session_t peer_id,
1510 const NodeDefManager *nodedef, u16 protocol_version)
1512 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1516 u32 length of the next item
1517 zlib-compressed serialized NodeDefManager
1519 std::ostringstream tmp_os(std::ios::binary);
1520 nodedef->serialize(tmp_os, protocol_version);
1521 std::ostringstream tmp_os2(std::ios::binary);
1522 compressZlib(tmp_os.str(), tmp_os2);
1524 pkt.putLongString(tmp_os2.str());
1527 verbosestream << "Server: Sending node definitions to id(" << peer_id
1528 << "): size=" << pkt.getSize() << std::endl;
1534 Non-static send methods
1537 void Server::SendInventory(PlayerSAO* playerSAO)
1539 UpdateCrafting(playerSAO->getPlayer());
1545 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, playerSAO->getPeerID());
1547 std::ostringstream os;
1548 playerSAO->getInventory()->serialize(os);
1550 std::string s = os.str();
1552 pkt.putRawString(s.c_str(), s.size());
1556 void Server::SendChatMessage(session_t peer_id, const ChatMessage &message)
1558 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1560 u8 type = message.type;
1561 pkt << version << type << std::wstring(L"") << message.message << message.timestamp;
1563 if (peer_id != PEER_ID_INEXISTENT) {
1564 RemotePlayer *player = m_env->getPlayer(peer_id);
1570 m_clients.sendToAll(&pkt);
1574 void Server::SendShowFormspecMessage(session_t peer_id, const std::string &formspec,
1575 const std::string &formname)
1577 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1578 if (formspec.empty()){
1579 //the client should close the formspec
1580 m_formspec_state_data.erase(peer_id);
1581 pkt.putLongString("");
1583 m_formspec_state_data[peer_id] = formname;
1584 pkt.putLongString(FORMSPEC_VERSION_STRING + formspec);
1591 // Spawns a particle on peer with peer_id
1592 void Server::SendSpawnParticle(session_t peer_id, u16 protocol_version,
1593 v3f pos, v3f velocity, v3f acceleration,
1594 float expirationtime, float size, bool collisiondetection,
1595 bool collision_removal, bool object_collision,
1596 bool vertical, const std::string &texture,
1597 const struct TileAnimationParams &animation, u8 glow)
1599 static thread_local const float radius =
1600 g_settings->getS16("max_block_send_distance") * MAP_BLOCKSIZE * BS;
1602 if (peer_id == PEER_ID_INEXISTENT) {
1603 std::vector<session_t> clients = m_clients.getClientIDs();
1605 for (const session_t client_id : clients) {
1606 RemotePlayer *player = m_env->getPlayer(client_id);
1610 PlayerSAO *sao = player->getPlayerSAO();
1614 // Do not send to distant clients
1615 if (sao->getBasePosition().getDistanceFrom(pos * BS) > radius)
1618 SendSpawnParticle(client_id, player->protocol_version,
1619 pos, velocity, acceleration,
1620 expirationtime, size, collisiondetection, collision_removal,
1621 object_collision, vertical, texture, animation, glow);
1626 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1628 pkt << pos << velocity << acceleration << expirationtime
1629 << size << collisiondetection;
1630 pkt.putLongString(texture);
1632 pkt << collision_removal;
1633 // This is horrible but required (why are there two ways to serialize pkts?)
1634 std::ostringstream os(std::ios_base::binary);
1635 animation.serialize(os, protocol_version);
1636 pkt.putRawString(os.str());
1638 pkt << object_collision;
1643 // Adds a ParticleSpawner on peer with peer_id
1644 void Server::SendAddParticleSpawner(session_t peer_id, u16 protocol_version,
1645 u16 amount, float spawntime, v3f minpos, v3f maxpos,
1646 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1647 float minsize, float maxsize, bool collisiondetection, bool collision_removal,
1648 bool object_collision, u16 attached_id, bool vertical, const std::string &texture, u32 id,
1649 const struct TileAnimationParams &animation, u8 glow)
1651 if (peer_id == PEER_ID_INEXISTENT) {
1652 // This sucks and should be replaced:
1653 std::vector<session_t> clients = m_clients.getClientIDs();
1654 for (const session_t client_id : clients) {
1655 RemotePlayer *player = m_env->getPlayer(client_id);
1658 SendAddParticleSpawner(client_id, player->protocol_version,
1659 amount, spawntime, minpos, maxpos,
1660 minvel, maxvel, minacc, maxacc, minexptime, maxexptime,
1661 minsize, maxsize, collisiondetection, collision_removal,
1662 object_collision, attached_id, vertical, texture, id,
1668 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1670 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1671 << minacc << maxacc << minexptime << maxexptime << minsize
1672 << maxsize << collisiondetection;
1674 pkt.putLongString(texture);
1676 pkt << id << vertical;
1677 pkt << collision_removal;
1679 // This is horrible but required
1680 std::ostringstream os(std::ios_base::binary);
1681 animation.serialize(os, protocol_version);
1682 pkt.putRawString(os.str());
1684 pkt << object_collision;
1689 void Server::SendDeleteParticleSpawner(session_t peer_id, u32 id)
1691 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER, 4, peer_id);
1693 // Ugly error in this packet
1696 if (peer_id != PEER_ID_INEXISTENT)
1699 m_clients.sendToAll(&pkt);
1703 void Server::SendHUDAdd(session_t peer_id, u32 id, HudElement *form)
1705 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1707 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1708 << form->text << form->number << form->item << form->dir
1709 << form->align << form->offset << form->world_pos << form->size;
1714 void Server::SendHUDRemove(session_t peer_id, u32 id)
1716 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1721 void Server::SendHUDChange(session_t peer_id, u32 id, HudElementStat stat, void *value)
1723 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1724 pkt << id << (u8) stat;
1728 case HUD_STAT_SCALE:
1729 case HUD_STAT_ALIGN:
1730 case HUD_STAT_OFFSET:
1731 pkt << *(v2f *) value;
1735 pkt << *(std::string *) value;
1737 case HUD_STAT_WORLD_POS:
1738 pkt << *(v3f *) value;
1741 pkt << *(v2s32 *) value;
1743 case HUD_STAT_NUMBER:
1747 pkt << *(u32 *) value;
1754 void Server::SendHUDSetFlags(session_t peer_id, u32 flags, u32 mask)
1756 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1758 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1760 pkt << flags << mask;
1765 void Server::SendHUDSetParam(session_t peer_id, u16 param, const std::string &value)
1767 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1768 pkt << param << value;
1772 void Server::SendSetSky(session_t peer_id, const video::SColor &bgcolor,
1773 const std::string &type, const std::vector<std::string> ¶ms,
1776 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1777 pkt << bgcolor << type << (u16) params.size();
1779 for (const std::string ¶m : params)
1787 void Server::SendCloudParams(session_t peer_id, const CloudParams ¶ms)
1789 NetworkPacket pkt(TOCLIENT_CLOUD_PARAMS, 0, peer_id);
1790 pkt << params.density << params.color_bright << params.color_ambient
1791 << params.height << params.thickness << params.speed;
1795 void Server::SendOverrideDayNightRatio(session_t peer_id, bool do_override,
1798 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1801 pkt << do_override << (u16) (ratio * 65535);
1806 void Server::SendTimeOfDay(session_t peer_id, u16 time, f32 time_speed)
1808 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1809 pkt << time << time_speed;
1811 if (peer_id == PEER_ID_INEXISTENT) {
1812 m_clients.sendToAll(&pkt);
1819 void Server::SendPlayerHP(session_t peer_id)
1821 PlayerSAO *playersao = getPlayerSAO(peer_id);
1822 // In some rare case if the player is disconnected
1823 // while Lua call l_punch, for example, this can be NULL
1827 SendHP(peer_id, playersao->getHP());
1828 m_script->player_event(playersao,"health_changed");
1830 // Send to other clients
1831 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
1832 ActiveObjectMessage aom(playersao->getId(), true, str);
1833 playersao->m_messages_out.push(aom);
1836 void Server::SendPlayerBreath(PlayerSAO *sao)
1840 m_script->player_event(sao, "breath_changed");
1841 SendBreath(sao->getPeerID(), sao->getBreath());
1844 void Server::SendMovePlayer(session_t peer_id)
1846 RemotePlayer *player = m_env->getPlayer(peer_id);
1848 PlayerSAO *sao = player->getPlayerSAO();
1851 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1852 pkt << sao->getBasePosition() << sao->getLookPitch() << sao->getRotation().Y;
1855 v3f pos = sao->getBasePosition();
1856 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1857 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1858 << " pitch=" << sao->getLookPitch()
1859 << " yaw=" << sao->getRotation().Y
1866 void Server::SendLocalPlayerAnimations(session_t peer_id, v2s32 animation_frames[4],
1867 f32 animation_speed)
1869 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1872 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1873 << animation_frames[3] << animation_speed;
1878 void Server::SendEyeOffset(session_t peer_id, v3f first, v3f third)
1880 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1881 pkt << first << third;
1885 void Server::SendPlayerPrivileges(session_t peer_id)
1887 RemotePlayer *player = m_env->getPlayer(peer_id);
1889 if(player->getPeerId() == PEER_ID_INEXISTENT)
1892 std::set<std::string> privs;
1893 m_script->getAuth(player->getName(), NULL, &privs);
1895 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1896 pkt << (u16) privs.size();
1898 for (const std::string &priv : privs) {
1905 void Server::SendPlayerInventoryFormspec(session_t peer_id)
1907 RemotePlayer *player = m_env->getPlayer(peer_id);
1909 if (player->getPeerId() == PEER_ID_INEXISTENT)
1912 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1913 pkt.putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
1917 void Server::SendPlayerFormspecPrepend(session_t peer_id)
1919 RemotePlayer *player = m_env->getPlayer(peer_id);
1921 if (player->getPeerId() == PEER_ID_INEXISTENT)
1924 NetworkPacket pkt(TOCLIENT_FORMSPEC_PREPEND, 0, peer_id);
1925 pkt << FORMSPEC_VERSION_STRING + player->formspec_prepend;
1929 u32 Server::SendActiveObjectRemoveAdd(session_t peer_id, const std::string &datas)
1931 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, datas.size(), peer_id);
1932 pkt.putRawString(datas.c_str(), datas.size());
1934 return pkt.getSize();
1937 void Server::SendActiveObjectMessages(session_t peer_id, const std::string &datas,
1940 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
1941 datas.size(), peer_id);
1943 pkt.putRawString(datas.c_str(), datas.size());
1945 m_clients.send(pkt.getPeerId(),
1946 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
1950 void Server::SendCSMRestrictionFlags(session_t peer_id)
1952 NetworkPacket pkt(TOCLIENT_CSM_RESTRICTION_FLAGS,
1953 sizeof(m_csm_restriction_flags) + sizeof(m_csm_restriction_noderange), peer_id);
1954 pkt << m_csm_restriction_flags << m_csm_restriction_noderange;
1958 s32 Server::playSound(const SimpleSoundSpec &spec,
1959 const ServerSoundParams ¶ms)
1961 // Find out initial position of sound
1962 bool pos_exists = false;
1963 v3f pos = params.getPos(m_env, &pos_exists);
1964 // If position is not found while it should be, cancel sound
1965 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
1968 // Filter destination clients
1969 std::vector<session_t> dst_clients;
1970 if(!params.to_player.empty()) {
1971 RemotePlayer *player = m_env->getPlayer(params.to_player.c_str());
1973 infostream<<"Server::playSound: Player \""<<params.to_player
1974 <<"\" not found"<<std::endl;
1977 if (player->getPeerId() == PEER_ID_INEXISTENT) {
1978 infostream<<"Server::playSound: Player \""<<params.to_player
1979 <<"\" not connected"<<std::endl;
1982 dst_clients.push_back(player->getPeerId());
1984 std::vector<session_t> clients = m_clients.getClientIDs();
1986 for (const session_t client_id : clients) {
1987 RemotePlayer *player = m_env->getPlayer(client_id);
1991 PlayerSAO *sao = player->getPlayerSAO();
1996 if(sao->getBasePosition().getDistanceFrom(pos) >
1997 params.max_hear_distance)
2000 dst_clients.push_back(client_id);
2004 if(dst_clients.empty())
2008 s32 id = m_next_sound_id++;
2009 // The sound will exist as a reference in m_playing_sounds
2010 m_playing_sounds[id] = ServerPlayingSound();
2011 ServerPlayingSound &psound = m_playing_sounds[id];
2012 psound.params = params;
2015 float gain = params.gain * spec.gain;
2016 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2017 pkt << id << spec.name << gain
2018 << (u8) params.type << pos << params.object
2019 << params.loop << params.fade << params.pitch;
2021 // Backwards compability
2022 bool play_sound = gain > 0;
2024 for (const u16 dst_client : dst_clients) {
2025 if (play_sound || m_clients.getProtocolVersion(dst_client) >= 32) {
2026 psound.clients.insert(dst_client);
2027 m_clients.send(dst_client, 0, &pkt, true);
2032 void Server::stopSound(s32 handle)
2034 // Get sound reference
2035 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2036 m_playing_sounds.find(handle);
2037 if (i == m_playing_sounds.end())
2039 ServerPlayingSound &psound = i->second;
2041 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2044 for (std::unordered_set<session_t>::const_iterator si = psound.clients.begin();
2045 si != psound.clients.end(); ++si) {
2047 m_clients.send(*si, 0, &pkt, true);
2049 // Remove sound reference
2050 m_playing_sounds.erase(i);
2053 void Server::fadeSound(s32 handle, float step, float gain)
2055 // Get sound reference
2056 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2057 m_playing_sounds.find(handle);
2058 if (i == m_playing_sounds.end())
2061 ServerPlayingSound &psound = i->second;
2062 psound.params.gain = gain;
2064 NetworkPacket pkt(TOCLIENT_FADE_SOUND, 4);
2065 pkt << handle << step << gain;
2067 // Backwards compability
2068 bool play_sound = gain > 0;
2069 ServerPlayingSound compat_psound = psound;
2070 compat_psound.clients.clear();
2072 NetworkPacket compat_pkt(TOCLIENT_STOP_SOUND, 4);
2073 compat_pkt << handle;
2075 for (std::unordered_set<u16>::iterator it = psound.clients.begin();
2076 it != psound.clients.end();) {
2077 if (m_clients.getProtocolVersion(*it) >= 32) {
2079 m_clients.send(*it, 0, &pkt, true);
2082 compat_psound.clients.insert(*it);
2084 m_clients.send(*it, 0, &compat_pkt, true);
2085 psound.clients.erase(it++);
2089 // Remove sound reference
2090 if (!play_sound || psound.clients.empty())
2091 m_playing_sounds.erase(i);
2093 if (play_sound && !compat_psound.clients.empty()) {
2094 // Play new sound volume on older clients
2095 playSound(compat_psound.spec, compat_psound.params);
2099 void Server::sendRemoveNode(v3s16 p, std::unordered_set<u16> *far_players,
2102 float maxd = far_d_nodes * BS;
2103 v3f p_f = intToFloat(p, BS);
2104 v3s16 block_pos = getNodeBlockPos(p);
2106 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2109 std::vector<session_t> clients = m_clients.getClientIDs();
2112 for (session_t client_id : clients) {
2113 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
2117 RemotePlayer *player = m_env->getPlayer(client_id);
2118 PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr;
2120 // If player is far away, only set modified blocks not sent
2121 if (!client->isBlockSent(block_pos) || (sao &&
2122 sao->getBasePosition().getDistanceFrom(p_f) > maxd)) {
2124 far_players->emplace(client_id);
2126 client->SetBlockNotSent(block_pos);
2131 m_clients.send(client_id, 0, &pkt, true);
2137 void Server::sendAddNode(v3s16 p, MapNode n, std::unordered_set<u16> *far_players,
2138 float far_d_nodes, bool remove_metadata)
2140 float maxd = far_d_nodes * BS;
2141 v3f p_f = intToFloat(p, BS);
2142 v3s16 block_pos = getNodeBlockPos(p);
2144 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2145 pkt << p << n.param0 << n.param1 << n.param2
2146 << (u8) (remove_metadata ? 0 : 1);
2148 std::vector<session_t> clients = m_clients.getClientIDs();
2151 for (session_t client_id : clients) {
2152 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
2156 RemotePlayer *player = m_env->getPlayer(client_id);
2157 PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr;
2159 // If player is far away, only set modified blocks not sent
2160 if (!client->isBlockSent(block_pos) || (sao &&
2161 sao->getBasePosition().getDistanceFrom(p_f) > maxd)) {
2163 far_players->emplace(client_id);
2165 client->SetBlockNotSent(block_pos);
2170 m_clients.send(client_id, 0, &pkt, true);
2176 void Server::sendMetadataChanged(const std::list<v3s16> &meta_updates, float far_d_nodes)
2178 float maxd = far_d_nodes * BS;
2179 NodeMetadataList meta_updates_list(false);
2180 std::vector<session_t> clients = m_clients.getClientIDs();
2184 for (session_t i : clients) {
2185 RemoteClient *client = m_clients.lockedGetClientNoEx(i);
2189 ServerActiveObject *player = m_env->getActiveObject(i);
2190 v3f player_pos = player ? player->getBasePosition() : v3f();
2192 for (const v3s16 &pos : meta_updates) {
2193 NodeMetadata *meta = m_env->getMap().getNodeMetadata(pos);
2198 v3s16 block_pos = getNodeBlockPos(pos);
2199 if (!client->isBlockSent(block_pos) || (player &&
2200 player_pos.getDistanceFrom(intToFloat(pos, BS)) > maxd)) {
2201 client->SetBlockNotSent(block_pos);
2205 // Add the change to send list
2206 meta_updates_list.set(pos, meta);
2208 if (meta_updates_list.size() == 0)
2211 // Send the meta changes
2212 std::ostringstream os(std::ios::binary);
2213 meta_updates_list.serialize(os, client->net_proto_version, false, true);
2214 std::ostringstream oss(std::ios::binary);
2215 compressZlib(os.str(), oss);
2217 NetworkPacket pkt(TOCLIENT_NODEMETA_CHANGED, 0);
2218 pkt.putLongString(oss.str());
2219 m_clients.send(i, 0, &pkt, true);
2221 meta_updates_list.clear();
2227 void Server::SendBlockNoLock(session_t peer_id, MapBlock *block, u8 ver,
2228 u16 net_proto_version)
2231 Create a packet with the block in the right format
2234 std::ostringstream os(std::ios_base::binary);
2235 block->serialize(os, ver, false);
2236 block->serializeNetworkSpecific(os);
2237 std::string s = os.str();
2239 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2241 pkt << block->getPos();
2242 pkt.putRawString(s.c_str(), s.size());
2246 void Server::SendBlocks(float dtime)
2248 MutexAutoLock envlock(m_env_mutex);
2249 //TODO check if one big lock could be faster then multiple small ones
2251 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2253 std::vector<PrioritySortedBlockTransfer> queue;
2255 u32 total_sending = 0;
2258 ScopeProfiler sp2(g_profiler, "Server: selecting blocks for sending");
2260 std::vector<session_t> clients = m_clients.getClientIDs();
2263 for (const session_t client_id : clients) {
2264 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id, CS_Active);
2269 total_sending += client->getSendingCount();
2270 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2276 // Lowest priority number comes first.
2277 // Lowest is most important.
2278 std::sort(queue.begin(), queue.end());
2282 // Maximal total count calculation
2283 // The per-client block sends is halved with the maximal online users
2284 u32 max_blocks_to_send = (m_env->getPlayerCount() + g_settings->getU32("max_users")) *
2285 g_settings->getU32("max_simultaneous_block_sends_per_client") / 4 + 1;
2287 for (const PrioritySortedBlockTransfer &block_to_send : queue) {
2288 if (total_sending >= max_blocks_to_send)
2291 MapBlock *block = nullptr;
2293 block = m_env->getMap().getBlockNoCreate(block_to_send.pos);
2294 } catch (const InvalidPositionException &e) {
2298 RemoteClient *client = m_clients.lockedGetClientNoEx(block_to_send.peer_id,
2303 SendBlockNoLock(block_to_send.peer_id, block, client->serialization_version,
2304 client->net_proto_version);
2306 client->SentBlock(block_to_send.pos);
2312 void Server::fillMediaCache()
2314 infostream<<"Server: Calculating media file checksums"<<std::endl;
2316 // Collect all media file paths
2317 std::vector<std::string> paths;
2318 m_modmgr->getModsMediaPaths(paths);
2319 fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures");
2320 fs::GetRecursiveDirs(paths, porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2322 // Collect media file information from paths into cache
2323 for (const std::string &mediapath : paths) {
2324 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2325 for (const fs::DirListNode &dln : dirlist) {
2326 if (dln.dir) // Ignode dirs
2328 std::string filename = dln.name;
2329 // If name contains illegal characters, ignore the file
2330 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2331 infostream<<"Server: ignoring illegal file name: \""
2332 << filename << "\"" << std::endl;
2335 // If name is not in a supported format, ignore it
2336 const char *supported_ext[] = {
2337 ".png", ".jpg", ".bmp", ".tga",
2338 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2340 ".x", ".b3d", ".md2", ".obj",
2341 // Custom translation file format
2345 if (removeStringEnd(filename, supported_ext).empty()){
2346 infostream << "Server: ignoring unsupported file extension: \""
2347 << filename << "\"" << std::endl;
2350 // Ok, attempt to load the file and add to cache
2351 std::string filepath;
2352 filepath.append(mediapath).append(DIR_DELIM).append(filename);
2355 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2357 errorstream << "Server::fillMediaCache(): Could not open \""
2358 << filename << "\" for reading" << std::endl;
2361 std::ostringstream tmp_os(std::ios_base::binary);
2365 fis.read(buf, 1024);
2366 std::streamsize len = fis.gcount();
2367 tmp_os.write(buf, len);
2376 errorstream<<"Server::fillMediaCache(): Failed to read \""
2377 << filename << "\"" << std::endl;
2380 if(tmp_os.str().length() == 0) {
2381 errorstream << "Server::fillMediaCache(): Empty file \""
2382 << filepath << "\"" << std::endl;
2387 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2389 unsigned char *digest = sha1.getDigest();
2390 std::string sha1_base64 = base64_encode(digest, 20);
2391 std::string sha1_hex = hex_encode((char*)digest, 20);
2395 m_media[filename] = MediaInfo(filepath, sha1_base64);
2396 verbosestream << "Server: " << sha1_hex << " is " << filename
2402 void Server::sendMediaAnnouncement(session_t peer_id, const std::string &lang_code)
2404 verbosestream << "Server: Announcing files to id(" << peer_id << ")"
2408 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2411 std::string lang_suffix;
2412 lang_suffix.append(".").append(lang_code).append(".tr");
2413 for (const auto &i : m_media) {
2414 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2421 for (const auto &i : m_media) {
2422 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2424 pkt << i.first << i.second.sha1_digest;
2427 pkt << g_settings->get("remote_media");
2431 struct SendableMedia
2437 SendableMedia(const std::string &name_="", const std::string &path_="",
2438 const std::string &data_=""):
2445 void Server::sendRequestedMedia(session_t peer_id,
2446 const std::vector<std::string> &tosend)
2448 verbosestream<<"Server::sendRequestedMedia(): "
2449 <<"Sending files to client"<<std::endl;
2453 // Put 5kB in one bunch (this is not accurate)
2454 u32 bytes_per_bunch = 5000;
2456 std::vector< std::vector<SendableMedia> > file_bunches;
2457 file_bunches.emplace_back();
2459 u32 file_size_bunch_total = 0;
2461 for (const std::string &name : tosend) {
2462 if (m_media.find(name) == m_media.end()) {
2463 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2464 <<"unknown file \""<<(name)<<"\""<<std::endl;
2468 //TODO get path + name
2469 std::string tpath = m_media[name].path;
2472 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2474 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2475 <<tpath<<"\" for reading"<<std::endl;
2478 std::ostringstream tmp_os(std::ios_base::binary);
2482 fis.read(buf, 1024);
2483 std::streamsize len = fis.gcount();
2484 tmp_os.write(buf, len);
2485 file_size_bunch_total += len;
2494 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2495 <<name<<"\""<<std::endl;
2498 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2499 <<tname<<"\""<<std::endl;*/
2501 file_bunches[file_bunches.size()-1].emplace_back(name, tpath, tmp_os.str());
2503 // Start next bunch if got enough data
2504 if(file_size_bunch_total >= bytes_per_bunch) {
2505 file_bunches.emplace_back();
2506 file_size_bunch_total = 0;
2511 /* Create and send packets */
2513 u16 num_bunches = file_bunches.size();
2514 for (u16 i = 0; i < num_bunches; i++) {
2517 u16 total number of texture bunches
2518 u16 index of this bunch
2519 u32 number of files in this bunch
2528 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2529 pkt << num_bunches << i << (u32) file_bunches[i].size();
2531 for (const SendableMedia &j : file_bunches[i]) {
2533 pkt.putLongString(j.data);
2536 verbosestream << "Server::sendRequestedMedia(): bunch "
2537 << i << "/" << num_bunches
2538 << " files=" << file_bunches[i].size()
2539 << " size=" << pkt.getSize() << std::endl;
2544 void Server::sendDetachedInventory(const std::string &name, session_t peer_id)
2546 const auto &inv_it = m_detached_inventories.find(name);
2547 const auto &player_it = m_detached_inventories_player.find(name);
2549 if (player_it == m_detached_inventories_player.end() ||
2550 player_it->second.empty()) {
2551 // OK. Send to everyone
2553 RemotePlayer *p = m_env->getPlayer(player_it->second.c_str());
2555 return; // Player is offline
2557 if (peer_id != PEER_ID_INEXISTENT && peer_id != p->getPeerId())
2558 return; // Caller requested send to a different player, so don't send.
2560 peer_id = p->getPeerId();
2563 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2566 if (inv_it == m_detached_inventories.end()) {
2567 pkt << false; // Remove inventory
2569 pkt << true; // Update inventory
2571 // Serialization & NetworkPacket isn't a love story
2572 std::ostringstream os(std::ios_base::binary);
2573 inv_it->second->serialize(os);
2577 if (peer_id == PEER_ID_INEXISTENT)
2578 m_clients.sendToAll(&pkt);
2583 void Server::sendDetachedInventories(session_t peer_id)
2585 for (const auto &detached_inventory : m_detached_inventories) {
2586 const std::string &name = detached_inventory.first;
2587 //Inventory *inv = i->second;
2588 sendDetachedInventory(name, peer_id);
2596 void Server::DiePlayer(session_t peer_id, const PlayerHPChangeReason &reason)
2598 PlayerSAO *playersao = getPlayerSAO(peer_id);
2599 // In some rare cases this can be NULL -- if the player is disconnected
2600 // when a Lua function modifies l_punch, for example
2604 infostream << "Server::DiePlayer(): Player "
2605 << playersao->getPlayer()->getName()
2606 << " dies" << std::endl;
2608 playersao->setHP(0, reason);
2609 playersao->clearParentAttachment();
2611 // Trigger scripted stuff
2612 m_script->on_dieplayer(playersao, reason);
2614 SendPlayerHP(peer_id);
2615 SendDeathscreen(peer_id, false, v3f(0,0,0));
2618 void Server::RespawnPlayer(session_t peer_id)
2620 PlayerSAO *playersao = getPlayerSAO(peer_id);
2623 infostream << "Server::RespawnPlayer(): Player "
2624 << playersao->getPlayer()->getName()
2625 << " respawns" << std::endl;
2627 playersao->setHP(playersao->accessObjectProperties()->hp_max,
2628 PlayerHPChangeReason(PlayerHPChangeReason::RESPAWN));
2629 playersao->setBreath(playersao->accessObjectProperties()->breath_max);
2631 bool repositioned = m_script->on_respawnplayer(playersao);
2632 if (!repositioned) {
2633 // setPos will send the new position to client
2634 playersao->setPos(findSpawnPos());
2637 SendPlayerHP(peer_id);
2641 void Server::DenySudoAccess(session_t peer_id)
2643 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2648 void Server::DenyAccessVerCompliant(session_t peer_id, u16 proto_ver, AccessDeniedCode reason,
2649 const std::string &str_reason, bool reconnect)
2651 SendAccessDenied(peer_id, reason, str_reason, reconnect);
2653 m_clients.event(peer_id, CSE_SetDenied);
2654 DisconnectPeer(peer_id);
2658 void Server::DenyAccess(session_t peer_id, AccessDeniedCode reason,
2659 const std::string &custom_reason)
2661 SendAccessDenied(peer_id, reason, custom_reason);
2662 m_clients.event(peer_id, CSE_SetDenied);
2663 DisconnectPeer(peer_id);
2666 // 13/03/15: remove this function when protocol version 25 will become
2667 // the minimum version for MT users, maybe in 1 year
2668 void Server::DenyAccess_Legacy(session_t peer_id, const std::wstring &reason)
2670 SendAccessDenied_Legacy(peer_id, reason);
2671 m_clients.event(peer_id, CSE_SetDenied);
2672 DisconnectPeer(peer_id);
2675 void Server::DisconnectPeer(session_t peer_id)
2677 m_modchannel_mgr->leaveAllChannels(peer_id);
2678 m_con->DisconnectPeer(peer_id);
2681 void Server::acceptAuth(session_t peer_id, bool forSudoMode)
2684 RemoteClient* client = getClient(peer_id, CS_Invalid);
2686 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2688 // Right now, the auth mechs don't change between login and sudo mode.
2689 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2690 client->allowed_sudo_mechs = sudo_auth_mechs;
2692 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2693 << g_settings->getFloat("dedicated_server_step")
2697 m_clients.event(peer_id, CSE_AuthAccept);
2699 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2701 // We only support SRP right now
2702 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2704 resp_pkt << sudo_auth_mechs;
2706 m_clients.event(peer_id, CSE_SudoSuccess);
2710 void Server::DeleteClient(session_t peer_id, ClientDeletionReason reason)
2712 std::wstring message;
2715 Clear references to playing sounds
2717 for (std::unordered_map<s32, ServerPlayingSound>::iterator
2718 i = m_playing_sounds.begin(); i != m_playing_sounds.end();) {
2719 ServerPlayingSound &psound = i->second;
2720 psound.clients.erase(peer_id);
2721 if (psound.clients.empty())
2722 m_playing_sounds.erase(i++);
2727 // clear formspec info so the next client can't abuse the current state
2728 m_formspec_state_data.erase(peer_id);
2730 RemotePlayer *player = m_env->getPlayer(peer_id);
2732 /* Run scripts and remove from environment */
2734 PlayerSAO *playersao = player->getPlayerSAO();
2737 playersao->clearChildAttachments();
2738 playersao->clearParentAttachment();
2740 // inform connected clients
2741 const std::string &player_name = player->getName();
2742 NetworkPacket notice(TOCLIENT_UPDATE_PLAYER_LIST, 0, PEER_ID_INEXISTENT);
2743 // (u16) 1 + std::string represents a vector serialization representation
2744 notice << (u8) PLAYER_LIST_REMOVE << (u16) 1 << player_name;
2745 m_clients.sendToAll(¬ice);
2747 m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
2749 playersao->disconnected();
2756 if (player && reason != CDR_DENY) {
2757 std::ostringstream os(std::ios_base::binary);
2758 std::vector<session_t> clients = m_clients.getClientIDs();
2760 for (const session_t client_id : clients) {
2762 RemotePlayer *player = m_env->getPlayer(client_id);
2766 // Get name of player
2767 os << player->getName() << " ";
2770 std::string name = player->getName();
2771 actionstream << name << " "
2772 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2773 << " List of players: " << os.str() << std::endl;
2775 m_admin_chat->outgoing_queue.push_back(
2776 new ChatEventNick(CET_NICK_REMOVE, name));
2780 MutexAutoLock env_lock(m_env_mutex);
2781 m_clients.DeleteClient(peer_id);
2785 // Send leave chat message to all remaining clients
2786 if (!message.empty()) {
2787 SendChatMessage(PEER_ID_INEXISTENT,
2788 ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE, message));
2792 void Server::UpdateCrafting(RemotePlayer *player)
2794 InventoryList *clist = player->inventory.getList("craft");
2795 if (!clist || clist->getSize() == 0)
2798 // Get a preview for crafting
2800 InventoryLocation loc;
2801 loc.setPlayer(player->getName());
2802 std::vector<ItemStack> output_replacements;
2803 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2804 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(),
2807 InventoryList *plist = player->inventory.getList("craftpreview");
2808 if (plist && plist->getSize() >= 1) {
2809 // Put the new preview in
2810 plist->changeItem(0, preview);
2814 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2816 if (evt->type == CET_NICK_ADD) {
2817 // The terminal informed us of its nick choice
2818 m_admin_nick = ((ChatEventNick *)evt)->nick;
2819 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2820 errorstream << "You haven't set up an account." << std::endl
2821 << "Please log in using the client as '"
2822 << m_admin_nick << "' with a secure password." << std::endl
2823 << "Until then, you can't execute admin tasks via the console," << std::endl
2824 << "and everybody can claim the user account instead of you," << std::endl
2825 << "giving them full control over this server." << std::endl;
2828 assert(evt->type == CET_CHAT);
2829 handleAdminChat((ChatEventChat *)evt);
2833 std::wstring Server::handleChat(const std::string &name, const std::wstring &wname,
2834 std::wstring wmessage, bool check_shout_priv, RemotePlayer *player)
2836 // If something goes wrong, this player is to blame
2837 RollbackScopeActor rollback_scope(m_rollback,
2838 std::string("player:") + name);
2840 if (g_settings->getBool("strip_color_codes"))
2841 wmessage = unescape_enriched(wmessage);
2844 switch (player->canSendChatMessage()) {
2845 case RPLAYER_CHATRESULT_FLOODING: {
2846 std::wstringstream ws;
2847 ws << L"You cannot send more messages. You are limited to "
2848 << g_settings->getFloat("chat_message_limit_per_10sec")
2849 << L" messages per 10 seconds.";
2852 case RPLAYER_CHATRESULT_KICK:
2853 DenyAccess_Legacy(player->getPeerId(),
2854 L"You have been kicked due to message flooding.");
2856 case RPLAYER_CHATRESULT_OK:
2859 FATAL_ERROR("Unhandled chat filtering result found.");
2863 if (m_max_chatmessage_length > 0
2864 && wmessage.length() > m_max_chatmessage_length) {
2865 return L"Your message exceed the maximum chat message limit set on the server. "
2866 L"It was refused. Send a shorter message";
2869 // Run script hook, exit if script ate the chat message
2870 if (m_script->on_chat_message(name, wide_to_utf8(wmessage)))
2875 // Whether to send line to the player that sent the message, or to all players
2876 bool broadcast_line = true;
2878 if (check_shout_priv && !checkPriv(name, "shout")) {
2879 line += L"-!- You don't have permission to shout.";
2880 broadcast_line = false;
2889 Tell calling method to send the message to sender
2891 if (!broadcast_line)
2895 Send the message to others
2897 actionstream << "CHAT: " << wide_to_narrow(unescape_enriched(line)) << std::endl;
2899 std::vector<session_t> clients = m_clients.getClientIDs();
2902 Send the message back to the inital sender
2903 if they are using protocol version >= 29
2906 session_t peer_id_to_avoid_sending =
2907 (player ? player->getPeerId() : PEER_ID_INEXISTENT);
2909 if (player && player->protocol_version >= 29)
2910 peer_id_to_avoid_sending = PEER_ID_INEXISTENT;
2912 for (u16 cid : clients) {
2913 if (cid != peer_id_to_avoid_sending)
2914 SendChatMessage(cid, ChatMessage(line));
2919 void Server::handleAdminChat(const ChatEventChat *evt)
2921 std::string name = evt->nick;
2922 std::wstring wname = utf8_to_wide(name);
2923 std::wstring wmessage = evt->evt_msg;
2925 std::wstring answer = handleChat(name, wname, wmessage);
2927 // If asked to send answer to sender
2928 if (!answer.empty()) {
2929 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
2933 RemoteClient *Server::getClient(session_t peer_id, ClientState state_min)
2935 RemoteClient *client = getClientNoEx(peer_id,state_min);
2937 throw ClientNotFoundException("Client not found");
2941 RemoteClient *Server::getClientNoEx(session_t peer_id, ClientState state_min)
2943 return m_clients.getClientNoEx(peer_id, state_min);
2946 std::string Server::getPlayerName(session_t peer_id)
2948 RemotePlayer *player = m_env->getPlayer(peer_id);
2950 return "[id="+itos(peer_id)+"]";
2951 return player->getName();
2954 PlayerSAO *Server::getPlayerSAO(session_t peer_id)
2956 RemotePlayer *player = m_env->getPlayer(peer_id);
2959 return player->getPlayerSAO();
2962 std::wstring Server::getStatusString()
2964 std::wostringstream os(std::ios_base::binary);
2965 os << L"# Server: ";
2967 os << L"version=" << narrow_to_wide(g_version_string);
2969 os << L", uptime=" << m_uptime.get();
2971 os << L", max_lag=" << (m_env ? m_env->getMaxLagEstimate() : 0);
2973 // Information about clients
2975 os << L", clients={";
2977 std::vector<session_t> clients = m_clients.getClientIDs();
2978 for (session_t client_id : clients) {
2979 RemotePlayer *player = m_env->getPlayer(client_id);
2981 // Get name of player
2982 std::wstring name = L"unknown";
2984 name = narrow_to_wide(player->getName());
2986 // Add name to information string
2997 if (m_env && !((ServerMap*)(&m_env->getMap()))->isSavingEnabled())
2998 os << std::endl << L"# Server: " << " WARNING: Map saving is disabled.";
3000 if (!g_settings->get("motd").empty())
3001 os << std::endl << L"# Server: " << narrow_to_wide(g_settings->get("motd"));
3006 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
3008 std::set<std::string> privs;
3009 m_script->getAuth(name, NULL, &privs);
3013 bool Server::checkPriv(const std::string &name, const std::string &priv)
3015 std::set<std::string> privs = getPlayerEffectivePrivs(name);
3016 return (privs.count(priv) != 0);
3019 void Server::reportPrivsModified(const std::string &name)
3022 std::vector<session_t> clients = m_clients.getClientIDs();
3023 for (const session_t client_id : clients) {
3024 RemotePlayer *player = m_env->getPlayer(client_id);
3025 reportPrivsModified(player->getName());
3028 RemotePlayer *player = m_env->getPlayer(name.c_str());
3031 SendPlayerPrivileges(player->getPeerId());
3032 PlayerSAO *sao = player->getPlayerSAO();
3035 sao->updatePrivileges(
3036 getPlayerEffectivePrivs(name),
3041 void Server::reportInventoryFormspecModified(const std::string &name)
3043 RemotePlayer *player = m_env->getPlayer(name.c_str());
3046 SendPlayerInventoryFormspec(player->getPeerId());
3049 void Server::reportFormspecPrependModified(const std::string &name)
3051 RemotePlayer *player = m_env->getPlayer(name.c_str());
3054 SendPlayerFormspecPrepend(player->getPeerId());
3057 void Server::setIpBanned(const std::string &ip, const std::string &name)
3059 m_banmanager->add(ip, name);
3062 void Server::unsetIpBanned(const std::string &ip_or_name)
3064 m_banmanager->remove(ip_or_name);
3067 std::string Server::getBanDescription(const std::string &ip_or_name)
3069 return m_banmanager->getBanDescription(ip_or_name);
3072 void Server::notifyPlayer(const char *name, const std::wstring &msg)
3074 // m_env will be NULL if the server is initializing
3078 if (m_admin_nick == name && !m_admin_nick.empty()) {
3079 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
3082 RemotePlayer *player = m_env->getPlayer(name);
3087 if (player->getPeerId() == PEER_ID_INEXISTENT)
3090 SendChatMessage(player->getPeerId(), ChatMessage(msg));
3093 bool Server::showFormspec(const char *playername, const std::string &formspec,
3094 const std::string &formname)
3096 // m_env will be NULL if the server is initializing
3100 RemotePlayer *player = m_env->getPlayer(playername);
3104 SendShowFormspecMessage(player->getPeerId(), formspec, formname);
3108 u32 Server::hudAdd(RemotePlayer *player, HudElement *form)
3113 u32 id = player->addHud(form);
3115 SendHUDAdd(player->getPeerId(), id, form);
3120 bool Server::hudRemove(RemotePlayer *player, u32 id) {
3124 HudElement* todel = player->removeHud(id);
3131 SendHUDRemove(player->getPeerId(), id);
3135 bool Server::hudChange(RemotePlayer *player, u32 id, HudElementStat stat, void *data)
3140 SendHUDChange(player->getPeerId(), id, stat, data);
3144 bool Server::hudSetFlags(RemotePlayer *player, u32 flags, u32 mask)
3149 SendHUDSetFlags(player->getPeerId(), flags, mask);
3150 player->hud_flags &= ~mask;
3151 player->hud_flags |= flags;
3153 PlayerSAO* playersao = player->getPlayerSAO();
3158 m_script->player_event(playersao, "hud_changed");
3162 bool Server::hudSetHotbarItemcount(RemotePlayer *player, s32 hotbar_itemcount)
3167 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3170 player->setHotbarItemcount(hotbar_itemcount);
3171 std::ostringstream os(std::ios::binary);
3172 writeS32(os, hotbar_itemcount);
3173 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3177 void Server::hudSetHotbarImage(RemotePlayer *player, std::string name)
3182 player->setHotbarImage(name);
3183 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_IMAGE, name);
3186 void Server::hudSetHotbarSelectedImage(RemotePlayer *player, std::string name)
3191 player->setHotbarSelectedImage(name);
3192 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3195 Address Server::getPeerAddress(session_t peer_id)
3197 return m_con->GetPeerAddress(peer_id);
3200 void Server::setLocalPlayerAnimations(RemotePlayer *player,
3201 v2s32 animation_frames[4], f32 frame_speed)
3203 sanity_check(player);
3204 player->setLocalAnimations(animation_frames, frame_speed);
3205 SendLocalPlayerAnimations(player->getPeerId(), animation_frames, frame_speed);
3208 void Server::setPlayerEyeOffset(RemotePlayer *player, const v3f &first, const v3f &third)
3210 sanity_check(player);
3211 player->eye_offset_first = first;
3212 player->eye_offset_third = third;
3213 SendEyeOffset(player->getPeerId(), first, third);
3216 void Server::setSky(RemotePlayer *player, const video::SColor &bgcolor,
3217 const std::string &type, const std::vector<std::string> ¶ms,
3220 sanity_check(player);
3221 player->setSky(bgcolor, type, params, clouds);
3222 SendSetSky(player->getPeerId(), bgcolor, type, params, clouds);
3225 void Server::setClouds(RemotePlayer *player, const CloudParams ¶ms)
3227 sanity_check(player);
3228 player->setCloudParams(params);
3229 SendCloudParams(player->getPeerId(), params);
3232 bool Server::overrideDayNightRatio(RemotePlayer *player, bool do_override,
3238 player->overrideDayNightRatio(do_override, ratio);
3239 SendOverrideDayNightRatio(player->getPeerId(), do_override, ratio);
3243 void Server::notifyPlayers(const std::wstring &msg)
3245 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(msg));
3248 void Server::spawnParticle(const std::string &playername, v3f pos,
3249 v3f velocity, v3f acceleration,
3250 float expirationtime, float size, bool
3251 collisiondetection, bool collision_removal, bool object_collision,
3252 bool vertical, const std::string &texture,
3253 const struct TileAnimationParams &animation, u8 glow)
3255 // m_env will be NULL if the server is initializing
3259 session_t peer_id = PEER_ID_INEXISTENT;
3261 if (!playername.empty()) {
3262 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3265 peer_id = player->getPeerId();
3266 proto_ver = player->protocol_version;
3269 SendSpawnParticle(peer_id, proto_ver, pos, velocity, acceleration,
3270 expirationtime, size, collisiondetection, collision_removal,
3271 object_collision, vertical, texture, animation, glow);
3274 u32 Server::addParticleSpawner(u16 amount, float spawntime,
3275 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
3276 float minexptime, float maxexptime, float minsize, float maxsize,
3277 bool collisiondetection, bool collision_removal, bool object_collision,
3278 ServerActiveObject *attached, bool vertical, const std::string &texture,
3279 const std::string &playername, const struct TileAnimationParams &animation,
3282 // m_env will be NULL if the server is initializing
3286 session_t peer_id = PEER_ID_INEXISTENT;
3288 if (!playername.empty()) {
3289 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3292 peer_id = player->getPeerId();
3293 proto_ver = player->protocol_version;
3296 u16 attached_id = attached ? attached->getId() : 0;
3299 if (attached_id == 0)
3300 id = m_env->addParticleSpawner(spawntime);
3302 id = m_env->addParticleSpawner(spawntime, attached_id);
3304 SendAddParticleSpawner(peer_id, proto_ver, amount, spawntime,
3305 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3306 minexptime, maxexptime, minsize, maxsize, collisiondetection,
3307 collision_removal, object_collision, attached_id, vertical,
3308 texture, id, animation, glow);
3313 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3315 // m_env will be NULL if the server is initializing
3317 throw ServerError("Can't delete particle spawners during initialisation!");
3319 session_t peer_id = PEER_ID_INEXISTENT;
3320 if (!playername.empty()) {
3321 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3324 peer_id = player->getPeerId();
3327 m_env->deleteParticleSpawner(id);
3328 SendDeleteParticleSpawner(peer_id, id);
3331 Inventory* Server::createDetachedInventory(const std::string &name, const std::string &player)
3333 if(m_detached_inventories.count(name) > 0){
3334 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3335 delete m_detached_inventories[name];
3337 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3339 Inventory *inv = new Inventory(m_itemdef);
3341 m_detached_inventories[name] = inv;
3342 m_detached_inventories_player[name] = player;
3343 //TODO find a better way to do this
3344 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3348 bool Server::removeDetachedInventory(const std::string &name)
3350 const auto &inv_it = m_detached_inventories.find(name);
3351 if (inv_it == m_detached_inventories.end())
3354 delete inv_it->second;
3355 m_detached_inventories.erase(inv_it);
3357 const auto &player_it = m_detached_inventories_player.find(name);
3358 if (player_it != m_detached_inventories_player.end()) {
3359 RemotePlayer *player = m_env->getPlayer(player_it->second.c_str());
3361 if (player && player->getPeerId() != PEER_ID_INEXISTENT)
3362 sendDetachedInventory(name, player->getPeerId());
3364 m_detached_inventories_player.erase(player_it);
3366 // Notify all players about the change
3367 sendDetachedInventory(name, PEER_ID_INEXISTENT);
3372 // actions: time-reversed list
3373 // Return value: success/failure
3374 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3375 std::list<std::string> *log)
3377 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3378 ServerMap *map = (ServerMap*)(&m_env->getMap());
3380 // Fail if no actions to handle
3381 if (actions.empty()) {
3383 log->push_back("Nothing to do.");
3390 for (const RollbackAction &action : actions) {
3392 bool success = action.applyRevert(map, this, this);
3395 std::ostringstream os;
3396 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3397 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3399 log->push_back(os.str());
3401 std::ostringstream os;
3402 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3403 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3405 log->push_back(os.str());
3409 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3410 <<" failed"<<std::endl;
3412 // Call it done if less than half failed
3413 return num_failed <= num_tried/2;
3416 // IGameDef interface
3418 IItemDefManager *Server::getItemDefManager()
3423 const NodeDefManager *Server::getNodeDefManager()
3428 ICraftDefManager *Server::getCraftDefManager()
3433 u16 Server::allocateUnknownNodeId(const std::string &name)
3435 return m_nodedef->allocateDummy(name);
3438 IWritableItemDefManager *Server::getWritableItemDefManager()
3443 NodeDefManager *Server::getWritableNodeDefManager()
3448 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3453 const std::vector<ModSpec> & Server::getMods() const
3455 return m_modmgr->getMods();
3458 const ModSpec *Server::getModSpec(const std::string &modname) const
3460 return m_modmgr->getModSpec(modname);
3463 void Server::getModNames(std::vector<std::string> &modlist)
3465 m_modmgr->getModNames(modlist);
3468 std::string Server::getBuiltinLuaPath()
3470 return porting::path_share + DIR_DELIM + "builtin";
3473 std::string Server::getModStoragePath() const
3475 return m_path_world + DIR_DELIM + "mod_storage";
3478 v3f Server::findSpawnPos()
3480 ServerMap &map = m_env->getServerMap();
3482 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf)) {
3483 return nodeposf * BS;
3486 bool is_good = false;
3487 // Limit spawn range to mapgen edges (determined by 'mapgen_limit')
3488 s32 range_max = map.getMapgenParams()->getSpawnRangeMax();
3490 // Try to find a good place a few times
3491 for(s32 i = 0; i < 4000 && !is_good; i++) {
3492 s32 range = MYMIN(1 + i, range_max);
3493 // We're going to try to throw the player to this position
3494 v2s16 nodepos2d = v2s16(
3495 -range + (myrand() % (range * 2)),
3496 -range + (myrand() % (range * 2)));
3498 // Get spawn level at point
3499 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3500 // Continue if MAX_MAP_GENERATION_LIMIT was returned by
3501 // the mapgen to signify an unsuitable spawn position
3502 if (spawn_level == MAX_MAP_GENERATION_LIMIT)
3505 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3508 for (s32 i = 0; i < 10; i++) {
3509 v3s16 blockpos = getNodeBlockPos(nodepos);
3510 map.emergeBlock(blockpos, true);
3511 content_t c = map.getNodeNoEx(nodepos).getContent();
3512 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3514 if (air_count >= 2) {
3515 nodeposf = intToFloat(nodepos, BS);
3516 // Don't spawn the player outside map boundaries
3517 if (objectpos_over_limit(nodeposf))
3530 void Server::requestShutdown(const std::string &msg, bool reconnect, float delay)
3532 if (delay == 0.0f) {
3533 // No delay, shutdown immediately
3534 m_shutdown_state.is_requested = true;
3535 // only print to the infostream, a chat message saying
3536 // "Server Shutting Down" is sent when the server destructs.
3537 infostream << "*** Immediate Server shutdown requested." << std::endl;
3538 } else if (delay < 0.0f && m_shutdown_state.isTimerRunning()) {
3539 // Negative delay, cancel shutdown if requested
3540 m_shutdown_state.reset();
3541 std::wstringstream ws;
3543 ws << L"*** Server shutdown canceled.";
3545 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3546 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3547 // m_shutdown_* are already handled, skip.
3549 } else if (delay > 0.0f) {
3550 // Positive delay, tell the clients when the server will shut down
3551 std::wstringstream ws;
3553 ws << L"*** Server shutting down in "
3554 << duration_to_string(myround(delay)).c_str()
3557 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3558 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3561 m_shutdown_state.trigger(delay, msg, reconnect);
3564 PlayerSAO* Server::emergePlayer(const char *name, session_t peer_id, u16 proto_version)
3567 Try to get an existing player
3569 RemotePlayer *player = m_env->getPlayer(name);
3571 // If player is already connected, cancel
3572 if (player && player->getPeerId() != PEER_ID_INEXISTENT) {
3573 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3578 If player with the wanted peer_id already exists, cancel.
3580 if (m_env->getPlayer(peer_id)) {
3581 infostream<<"emergePlayer(): Player with wrong name but same"
3582 " peer_id already exists"<<std::endl;
3587 player = new RemotePlayer(name, idef());
3590 bool newplayer = false;
3593 PlayerSAO *playersao = m_env->loadPlayer(player, &newplayer, peer_id, isSingleplayer());
3595 // Complete init with server parts
3596 playersao->finalize(player, getPlayerEffectivePrivs(player->getName()));
3597 player->protocol_version = proto_version;
3601 m_script->on_newplayer(playersao);
3607 bool Server::registerModStorage(ModMetadata *storage)
3609 if (m_mod_storages.find(storage->getModName()) != m_mod_storages.end()) {
3610 errorstream << "Unable to register same mod storage twice. Storage name: "
3611 << storage->getModName() << std::endl;
3615 m_mod_storages[storage->getModName()] = storage;
3619 void Server::unregisterModStorage(const std::string &name)
3621 std::unordered_map<std::string, ModMetadata *>::const_iterator it = m_mod_storages.find(name);
3622 if (it != m_mod_storages.end()) {
3623 // Save unconditionaly on unregistration
3624 it->second->save(getModStoragePath());
3625 m_mod_storages.erase(name);
3629 void dedicated_server_loop(Server &server, bool &kill)
3631 verbosestream<<"dedicated_server_loop()"<<std::endl;
3633 IntervalLimiter m_profiler_interval;
3635 static thread_local const float steplen =
3636 g_settings->getFloat("dedicated_server_step");
3637 static thread_local const float profiler_print_interval =
3638 g_settings->getFloat("profiler_print_interval");
3641 // This is kind of a hack but can be done like this
3642 // because server.step() is very light
3644 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3645 sleep_ms((int)(steplen*1000.0));
3647 server.step(steplen);
3649 if (server.isShutdownRequested() || kill)
3655 if (profiler_print_interval != 0) {
3656 if(m_profiler_interval.step(steplen, profiler_print_interval))
3658 infostream<<"Profiler:"<<std::endl;
3659 g_profiler->print(infostream);
3660 g_profiler->clear();
3665 infostream << "Dedicated server quitting" << std::endl;
3667 if (g_settings->getBool("server_announce"))
3668 ServerList::sendAnnounce(ServerList::AA_DELETE,
3669 server.m_bind_addr.getPort());
3678 bool Server::joinModChannel(const std::string &channel)
3680 return m_modchannel_mgr->joinChannel(channel, PEER_ID_SERVER) &&
3681 m_modchannel_mgr->setChannelState(channel, MODCHANNEL_STATE_READ_WRITE);
3684 bool Server::leaveModChannel(const std::string &channel)
3686 return m_modchannel_mgr->leaveChannel(channel, PEER_ID_SERVER);
3689 bool Server::sendModChannelMessage(const std::string &channel, const std::string &message)
3691 if (!m_modchannel_mgr->canWriteOnChannel(channel))
3694 broadcastModChannelMessage(channel, message, PEER_ID_SERVER);
3698 ModChannel* Server::getModChannel(const std::string &channel)
3700 return m_modchannel_mgr->getModChannel(channel);
3703 void Server::broadcastModChannelMessage(const std::string &channel,
3704 const std::string &message, session_t from_peer)
3706 const std::vector<u16> &peers = m_modchannel_mgr->getChannelPeers(channel);
3710 if (message.size() > STRING_MAX_LEN) {
3711 warningstream << "ModChannel message too long, dropping before sending "
3712 << " (" << message.size() << " > " << STRING_MAX_LEN << ", channel: "
3713 << channel << ")" << std::endl;
3718 if (from_peer != PEER_ID_SERVER) {
3719 sender = getPlayerName(from_peer);
3722 NetworkPacket resp_pkt(TOCLIENT_MODCHANNEL_MSG,
3723 2 + channel.size() + 2 + sender.size() + 2 + message.size());
3724 resp_pkt << channel << sender << message;
3725 for (session_t peer_id : peers) {
3727 if (peer_id == from_peer)
3730 Send(peer_id, &resp_pkt);
3733 if (from_peer != PEER_ID_SERVER) {
3734 m_script->on_modchannel_message(channel, sender, message);