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");
239 infostream << "Server destructing" << std::endl;
241 // Send shutdown message
242 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE,
243 L"*** Server shutting down"));
246 MutexAutoLock envlock(m_env_mutex);
248 infostream << "Server: Saving players" << std::endl;
249 m_env->saveLoadedPlayers();
251 infostream << "Server: Kicking players" << std::endl;
252 std::string kick_msg;
253 bool reconnect = false;
254 if (isShutdownRequested()) {
255 reconnect = m_shutdown_state.should_reconnect;
256 kick_msg = m_shutdown_state.message;
258 if (kick_msg.empty()) {
259 kick_msg = g_settings->get("kick_msg_shutdown");
261 m_env->kickAllPlayers(SERVER_ACCESSDENIED_SHUTDOWN,
262 kick_msg, reconnect);
265 // Do this before stopping the server in case mapgen callbacks need to access
266 // server-controlled resources (like ModStorages). Also do them before
267 // shutdown callbacks since they may modify state that is finalized in a
270 m_emerge->stopThreads();
273 MutexAutoLock envlock(m_env_mutex);
275 // Execute script shutdown hooks
276 infostream << "Executing shutdown hooks" << std::endl;
277 m_script->on_shutdown();
279 infostream << "Server: Saving environment metadata" << std::endl;
289 // Delete things in the reverse order of creation
298 // Deinitialize scripting
299 infostream << "Server: Deinitializing scripting" << std::endl;
302 // Delete detached inventories
303 for (auto &detached_inventory : m_detached_inventories) {
304 delete detached_inventory.second;
310 infostream << "Server created for gameid \"" << m_gamespec.id << "\"";
311 if (m_simple_singleplayer_mode)
312 infostream << " in simple singleplayer mode" << std::endl;
314 infostream << std::endl;
315 infostream << "- world: " << m_path_world << std::endl;
316 infostream << "- game: " << m_gamespec.path << std::endl;
318 // Create world if it doesn't exist
319 if (!loadGameConfAndInitWorld(m_path_world, m_gamespec))
320 throw ServerError("Failed to initialize world");
322 // Create server thread
323 m_thread = new ServerThread(this);
325 // Create emerge manager
326 m_emerge = new EmergeManager(this);
328 // Create ban manager
329 std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
330 m_banmanager = new BanManager(ban_path);
332 m_modmgr = std::unique_ptr<ServerModManager>(new ServerModManager(m_path_world));
333 std::vector<ModSpec> unsatisfied_mods = m_modmgr->getUnsatisfiedMods();
334 // complain about mods with unsatisfied dependencies
335 if (!m_modmgr->isConsistent()) {
336 m_modmgr->printUnsatisfiedModsError();
340 MutexAutoLock envlock(m_env_mutex);
342 // Create the Map (loads map_meta.txt, overriding configured mapgen params)
343 ServerMap *servermap = new ServerMap(m_path_world, this, m_emerge);
345 // Initialize scripting
346 infostream << "Server: Initializing Lua" << std::endl;
348 m_script = new ServerScripting(this);
350 m_script->loadMod(getBuiltinLuaPath() + DIR_DELIM "init.lua", BUILTIN_MOD_NAME);
352 m_modmgr->loadMods(m_script);
354 // Read Textures and calculate sha1 sums
357 // Apply item aliases in the node definition manager
358 m_nodedef->updateAliases(m_itemdef);
360 // Apply texture overrides from texturepack/override.txt
361 std::vector<std::string> paths;
362 fs::GetRecursiveDirs(paths, g_settings->get("texture_path"));
363 fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures");
364 for (const std::string &path : paths)
365 m_nodedef->applyTextureOverrides(path + DIR_DELIM + "override.txt");
367 m_nodedef->setNodeRegistrationStatus(true);
369 // Perform pending node name resolutions
370 m_nodedef->runNodeResolveCallbacks();
372 // unmap node names for connected nodeboxes
373 m_nodedef->mapNodeboxConnections();
375 // init the recipe hashes to speed up crafting
376 m_craftdef->initHashes(this);
378 // Initialize Environment
379 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
381 m_clients.setEnv(m_env);
383 if (!servermap->settings_mgr.makeMapgenParams())
384 FATAL_ERROR("Couldn't create any mapgen type");
386 // Initialize mapgens
387 m_emerge->initMapgens(servermap->getMapgenParams());
389 if (g_settings->getBool("enable_rollback_recording")) {
390 // Create rollback manager
391 m_rollback = new RollbackManager(m_path_world, this);
394 // Give environment reference to scripting api
395 m_script->initializeEnvironment(m_env);
397 // Register us to receive map edit events
398 servermap->addEventReceiver(this);
402 m_liquid_transform_every = g_settings->getFloat("liquid_update");
403 m_max_chatmessage_length = g_settings->getU16("chat_message_max_size");
404 m_csm_flavour_limits = g_settings->getU64("csm_flavour_limits");
405 m_csm_noderange_limit = g_settings->getU32("csm_flavour_noderange_limit");
410 infostream << "Starting server on " << m_bind_addr.serializeString()
411 << "..." << std::endl;
413 // Stop thread if already running
416 // Initialize connection
417 m_con->SetTimeoutMs(30);
418 m_con->Serve(m_bind_addr);
423 // ASCII art for the win!
425 << " .__ __ __ " << std::endl
426 << " _____ |__| ____ _____/ |_ ____ _______/ |_ " << std::endl
427 << " / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\" << std::endl
428 << "| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | " << std::endl
429 << "|__|_| /__|___| /\\___ >__| \\___ >____ > |__| " << std::endl
430 << " \\/ \\/ \\/ \\/ \\/ " << std::endl;
431 actionstream << "World at [" << m_path_world << "]" << std::endl;
432 actionstream << "Server for gameid=\"" << m_gamespec.id
433 << "\" listening on " << m_bind_addr.serializeString() << ":"
434 << m_bind_addr.getPort() << "." << std::endl;
439 infostream<<"Server: Stopping and waiting threads"<<std::endl;
441 // Stop threads (set run=false first so both start stopping)
443 //m_emergethread.setRun(false);
445 //m_emergethread.stop();
447 infostream<<"Server: Threads stopped"<<std::endl;
450 void Server::step(float dtime)
456 MutexAutoLock lock(m_step_dtime_mutex);
457 m_step_dtime += dtime;
459 // Throw if fatal error occurred in thread
460 std::string async_err = m_async_fatal_error.get();
461 if (!async_err.empty()) {
462 if (!m_simple_singleplayer_mode) {
463 m_env->kickAllPlayers(SERVER_ACCESSDENIED_CRASH,
464 g_settings->get("kick_msg_crash"),
465 g_settings->getBool("ask_reconnect_on_crash"));
467 throw ServerError("AsyncErr: " + async_err);
471 void Server::AsyncRunStep(bool initial_step)
473 g_profiler->add("Server::AsyncRunStep (num)", 1);
477 MutexAutoLock lock1(m_step_dtime_mutex);
478 dtime = m_step_dtime;
482 // Send blocks to clients
486 if((dtime < 0.001) && !initial_step)
489 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
491 //infostream<<"Server steps "<<dtime<<std::endl;
492 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
495 MutexAutoLock lock1(m_step_dtime_mutex);
496 m_step_dtime -= dtime;
503 m_uptime.set(m_uptime.get() + dtime);
509 Update time of day and overall game time
511 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
514 Send to clients at constant intervals
517 m_time_of_day_send_timer -= dtime;
518 if(m_time_of_day_send_timer < 0.0) {
519 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
520 u16 time = m_env->getTimeOfDay();
521 float time_speed = g_settings->getFloat("time_speed");
522 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
526 MutexAutoLock lock(m_env_mutex);
527 // Figure out and report maximum lag to environment
528 float max_lag = m_env->getMaxLagEstimate();
529 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
531 if(dtime > 0.1 && dtime > max_lag * 2.0)
532 infostream<<"Server: Maximum lag peaked to "<<dtime
536 m_env->reportMaxLagEstimate(max_lag);
538 ScopeProfiler sp(g_profiler, "SEnv step");
539 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
543 static const float map_timer_and_unload_dtime = 2.92;
544 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
546 MutexAutoLock lock(m_env_mutex);
547 // Run Map's timers and unload unused data
548 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
549 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
550 g_settings->getFloat("server_unload_unused_data_timeout"),
555 Listen to the admin chat, if available
558 if (!m_admin_chat->command_queue.empty()) {
559 MutexAutoLock lock(m_env_mutex);
560 while (!m_admin_chat->command_queue.empty()) {
561 ChatEvent *evt = m_admin_chat->command_queue.pop_frontNoEx();
562 handleChatInterfaceEvent(evt);
566 m_admin_chat->outgoing_queue.push_back(
567 new ChatEventTimeInfo(m_env->getGameTime(), m_env->getTimeOfDay()));
574 /* Transform liquids */
575 m_liquid_transform_timer += dtime;
576 if(m_liquid_transform_timer >= m_liquid_transform_every)
578 m_liquid_transform_timer -= m_liquid_transform_every;
580 MutexAutoLock lock(m_env_mutex);
582 ScopeProfiler sp(g_profiler, "Server: liquid transform");
584 std::map<v3s16, MapBlock*> modified_blocks;
585 m_env->getMap().transformLiquids(modified_blocks, m_env);
588 Set the modified blocks unsent for all the clients
590 if (!modified_blocks.empty()) {
591 SetBlocksNotSent(modified_blocks);
594 m_clients.step(dtime);
596 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
598 // send masterserver announce
600 float &counter = m_masterserver_timer;
601 if (!isSingleplayer() && (!counter || counter >= 300.0) &&
602 g_settings->getBool("server_announce")) {
603 ServerList::sendAnnounce(counter ? ServerList::AA_UPDATE :
604 ServerList::AA_START,
605 m_bind_addr.getPort(),
606 m_clients.getPlayerNames(),
608 m_env->getGameTime(),
611 Mapgen::getMapgenName(m_emerge->mgparams->mgtype),
621 Check added and deleted active objects
624 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
625 MutexAutoLock envlock(m_env_mutex);
628 const RemoteClientMap &clients = m_clients.getClientList();
629 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
631 // Radius inside which objects are active
632 static thread_local const s16 radius =
633 g_settings->getS16("active_object_send_range_blocks") * MAP_BLOCKSIZE;
635 // Radius inside which players are active
636 static thread_local const bool is_transfer_limited =
637 g_settings->exists("unlimited_player_transfer_distance") &&
638 !g_settings->getBool("unlimited_player_transfer_distance");
639 static thread_local const s16 player_transfer_dist =
640 g_settings->getS16("player_transfer_distance") * MAP_BLOCKSIZE;
641 s16 player_radius = player_transfer_dist;
642 if (player_radius == 0 && is_transfer_limited)
643 player_radius = radius;
645 for (const auto &client_it : clients) {
646 RemoteClient *client = client_it.second;
648 // If definitions and textures have not been sent, don't
649 // send objects either
650 if (client->getState() < CS_DefinitionsSent)
653 RemotePlayer *player = m_env->getPlayer(client->peer_id);
655 // This can happen if the client timeouts somehow
659 PlayerSAO *playersao = player->getPlayerSAO();
663 s16 my_radius = MYMIN(radius, playersao->getWantedRange() * MAP_BLOCKSIZE);
664 if (my_radius <= 0) my_radius = radius;
665 //infostream << "Server: Active Radius " << my_radius << std::endl;
667 std::queue<u16> removed_objects;
668 std::queue<u16> added_objects;
669 m_env->getRemovedActiveObjects(playersao, my_radius, player_radius,
670 client->m_known_objects, removed_objects);
671 m_env->getAddedActiveObjects(playersao, my_radius, player_radius,
672 client->m_known_objects, added_objects);
674 // Ignore if nothing happened
675 if (removed_objects.empty() && added_objects.empty()) {
679 std::string data_buffer;
683 // Handle removed objects
684 writeU16((u8*)buf, removed_objects.size());
685 data_buffer.append(buf, 2);
686 while (!removed_objects.empty()) {
688 u16 id = removed_objects.front();
689 ServerActiveObject* obj = m_env->getActiveObject(id);
691 // Add to data buffer for sending
692 writeU16((u8*)buf, id);
693 data_buffer.append(buf, 2);
695 // Remove from known objects
696 client->m_known_objects.erase(id);
698 if(obj && obj->m_known_by_count > 0)
699 obj->m_known_by_count--;
700 removed_objects.pop();
703 // Handle added objects
704 writeU16((u8*)buf, added_objects.size());
705 data_buffer.append(buf, 2);
706 while (!added_objects.empty()) {
708 u16 id = added_objects.front();
709 ServerActiveObject* obj = m_env->getActiveObject(id);
712 u8 type = ACTIVEOBJECT_TYPE_INVALID;
714 warningstream << FUNCTION_NAME << ": NULL object" << std::endl;
716 type = obj->getSendType();
718 // Add to data buffer for sending
719 writeU16((u8*)buf, id);
720 data_buffer.append(buf, 2);
721 writeU8((u8*)buf, type);
722 data_buffer.append(buf, 1);
725 data_buffer.append(serializeLongString(
726 obj->getClientInitializationData(client->net_proto_version)));
728 data_buffer.append(serializeLongString(""));
730 // Add to known objects
731 client->m_known_objects.insert(id);
734 obj->m_known_by_count++;
739 u32 pktSize = SendActiveObjectRemoveAdd(client->peer_id, data_buffer);
740 verbosestream << "Server: Sent object remove/add: "
741 << removed_objects.size() << " removed, "
742 << added_objects.size() << " added, "
743 << "packet size is " << pktSize << std::endl;
747 m_mod_storage_save_timer -= dtime;
748 if (m_mod_storage_save_timer <= 0.0f) {
749 infostream << "Saving registered mod storages." << std::endl;
750 m_mod_storage_save_timer = g_settings->getFloat("server_map_save_interval");
751 for (std::unordered_map<std::string, ModMetadata *>::const_iterator
752 it = m_mod_storages.begin(); it != m_mod_storages.end(); ++it) {
753 if (it->second->isModified()) {
754 it->second->save(getModStoragePath());
764 MutexAutoLock envlock(m_env_mutex);
765 ScopeProfiler sp(g_profiler, "Server: sending object messages");
768 // Value = data sent by object
769 std::unordered_map<u16, std::vector<ActiveObjectMessage>*> buffered_messages;
771 // Get active object messages from environment
773 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
777 std::vector<ActiveObjectMessage>* message_list = nullptr;
778 std::unordered_map<u16, std::vector<ActiveObjectMessage>* >::iterator n;
779 n = buffered_messages.find(aom.id);
780 if (n == buffered_messages.end()) {
781 message_list = new std::vector<ActiveObjectMessage>;
782 buffered_messages[aom.id] = message_list;
785 message_list = n->second;
787 message_list->push_back(aom);
791 const RemoteClientMap &clients = m_clients.getClientList();
792 // Route data to every client
793 for (const auto &client_it : clients) {
794 RemoteClient *client = client_it.second;
795 std::string reliable_data;
796 std::string unreliable_data;
797 // Go through all objects in message buffer
798 for (const auto &buffered_message : buffered_messages) {
799 // If object is not known by client, skip it
800 u16 id = buffered_message.first;
801 if (client->m_known_objects.find(id) == client->m_known_objects.end())
804 // Get message list of object
805 std::vector<ActiveObjectMessage>* list = buffered_message.second;
806 // Go through every message
807 for (const ActiveObjectMessage &aom : *list) {
808 // Compose the full new data with header
809 std::string new_data;
812 writeU16((u8*)&buf[0], aom.id);
813 new_data.append(buf, 2);
815 new_data += serializeString(aom.datastring);
816 // Add data to buffer
818 reliable_data += new_data;
820 unreliable_data += new_data;
824 reliable_data and unreliable_data are now ready.
827 if (!reliable_data.empty()) {
828 SendActiveObjectMessages(client->peer_id, reliable_data);
831 if (!unreliable_data.empty()) {
832 SendActiveObjectMessages(client->peer_id, unreliable_data, false);
837 // Clear buffered_messages
838 for (auto &buffered_message : buffered_messages) {
839 delete buffered_message.second;
844 Send queued-for-sending map edit events.
847 // We will be accessing the environment
848 MutexAutoLock lock(m_env_mutex);
850 // Don't send too many at a time
853 // Single change sending is disabled if queue size is not small
854 bool disable_single_change_sending = false;
855 if(m_unsent_map_edit_queue.size() >= 4)
856 disable_single_change_sending = true;
858 int event_count = m_unsent_map_edit_queue.size();
860 // We'll log the amount of each
863 while (!m_unsent_map_edit_queue.empty()) {
864 MapEditEvent* event = m_unsent_map_edit_queue.front();
865 m_unsent_map_edit_queue.pop();
867 // Players far away from the change are stored here.
868 // Instead of sending the changes, MapBlocks are set not sent
870 std::vector<u16> far_players;
872 switch (event->type) {
875 prof.add("MEET_ADDNODE", 1);
876 sendAddNode(event->p, event->n, event->already_known_by_peer,
877 &far_players, disable_single_change_sending ? 5 : 30,
878 event->type == MEET_ADDNODE);
880 case MEET_REMOVENODE:
881 prof.add("MEET_REMOVENODE", 1);
882 sendRemoveNode(event->p, event->already_known_by_peer,
883 &far_players, disable_single_change_sending ? 5 : 30);
885 case MEET_BLOCK_NODE_METADATA_CHANGED:
886 infostream << "Server: MEET_BLOCK_NODE_METADATA_CHANGED" << std::endl;
887 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
888 m_clients.markBlockposAsNotSent(event->p);
891 infostream << "Server: MEET_OTHER" << std::endl;
892 prof.add("MEET_OTHER", 1);
893 for (const v3s16 &modified_block : event->modified_blocks) {
894 m_clients.markBlockposAsNotSent(modified_block);
898 prof.add("unknown", 1);
899 warningstream << "Server: Unknown MapEditEvent "
900 << ((u32)event->type) << std::endl;
905 Set blocks not sent to far players
907 if (!far_players.empty()) {
908 // Convert list format to that wanted by SetBlocksNotSent
909 std::map<v3s16, MapBlock*> modified_blocks2;
910 for (const v3s16 &modified_block : event->modified_blocks) {
911 modified_blocks2[modified_block] =
912 m_env->getMap().getBlockNoCreateNoEx(modified_block);
915 // Set blocks not sent
916 for (const u16 far_player : far_players) {
917 if (RemoteClient *client = getClient(far_player))
918 client->SetBlocksNotSent(modified_blocks2);
925 if (event_count >= 5) {
926 infostream << "Server: MapEditEvents:" << std::endl;
927 prof.print(infostream);
928 } else if (event_count != 0) {
929 verbosestream << "Server: MapEditEvents:" << std::endl;
930 prof.print(verbosestream);
936 Trigger emergethread (it somehow gets to a non-triggered but
937 bysy state sometimes)
940 float &counter = m_emergethread_trigger_timer;
942 if (counter >= 2.0) {
945 m_emerge->startThreads();
949 // Save map, players and auth stuff
951 float &counter = m_savemap_timer;
953 static thread_local const float save_interval =
954 g_settings->getFloat("server_map_save_interval");
955 if (counter >= save_interval) {
957 MutexAutoLock lock(m_env_mutex);
959 ScopeProfiler sp(g_profiler, "Server: saving stuff");
962 if (m_banmanager->isModified()) {
963 m_banmanager->save();
966 // Save changed parts of map
967 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
970 m_env->saveLoadedPlayers();
972 // Save environment metadata
977 m_shutdown_state.tick(dtime, this);
980 void Server::Receive()
985 m_con->Receive(&pkt);
986 peer_id = pkt.getPeerId();
988 } catch (const con::InvalidIncomingDataException &e) {
989 infostream << "Server::Receive(): InvalidIncomingDataException: what()="
990 << e.what() << std::endl;
991 } catch (const SerializationError &e) {
992 infostream << "Server::Receive(): SerializationError: what()="
993 << e.what() << std::endl;
994 } catch (const ClientStateError &e) {
995 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
996 DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
997 L"Try reconnecting or updating your client");
998 } catch (const con::PeerNotFoundException &e) {
1003 PlayerSAO* Server::StageTwoClientInit(session_t peer_id)
1005 std::string playername;
1006 PlayerSAO *playersao = NULL;
1009 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1011 playername = client->getName();
1012 playersao = emergePlayer(playername.c_str(), peer_id, client->net_proto_version);
1014 } catch (std::exception &e) {
1020 RemotePlayer *player = m_env->getPlayer(playername.c_str());
1022 // If failed, cancel
1023 if (!playersao || !player) {
1024 if (player && player->getPeerId() != PEER_ID_INEXISTENT) {
1025 actionstream << "Server: Failed to emerge player \"" << playername
1026 << "\" (player allocated to an another client)" << std::endl;
1027 DenyAccess_Legacy(peer_id, L"Another client is connected with this "
1028 L"name. If your client closed unexpectedly, try again in "
1031 errorstream << "Server: " << playername << ": Failed to emerge player"
1033 DenyAccess_Legacy(peer_id, L"Could not allocate player.");
1039 Send complete position information
1041 SendMovePlayer(peer_id);
1044 SendPlayerPrivileges(peer_id);
1046 // Send inventory formspec
1047 SendPlayerInventoryFormspec(peer_id);
1050 SendInventory(playersao);
1052 // Send HP or death screen
1053 if (playersao->isDead())
1054 SendDeathscreen(peer_id, false, v3f(0,0,0));
1056 SendPlayerHPOrDie(playersao,
1057 PlayerHPChangeReason(PlayerHPChangeReason::SET_HP));
1060 SendPlayerBreath(playersao);
1062 // Note things in chat if not in simple singleplayer mode
1063 if (!m_simple_singleplayer_mode && g_settings->getBool("show_statusline_on_connect")) {
1064 // Send information about server to player in chat
1065 SendChatMessage(peer_id, ChatMessage(CHATMESSAGE_TYPE_SYSTEM, getStatusString()));
1067 Address addr = getPeerAddress(player->getPeerId());
1068 std::string ip_str = addr.serializeString();
1069 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1074 const std::vector<std::string> &names = m_clients.getPlayerNames();
1076 actionstream << player->getName() << " joins game. List of players: ";
1078 for (const std::string &name : names) {
1079 actionstream << name << " ";
1082 actionstream << player->getName() <<std::endl;
1087 inline void Server::handleCommand(NetworkPacket* pkt)
1089 const ToServerCommandHandler& opHandle = toServerCommandTable[pkt->getCommand()];
1090 (this->*opHandle.handler)(pkt);
1093 void Server::ProcessData(NetworkPacket *pkt)
1095 // Environment is locked first.
1096 MutexAutoLock envlock(m_env_mutex);
1098 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1099 u32 peer_id = pkt->getPeerId();
1102 Address address = getPeerAddress(peer_id);
1103 std::string addr_s = address.serializeString();
1105 if(m_banmanager->isIpBanned(addr_s)) {
1106 std::string ban_name = m_banmanager->getBanName(addr_s);
1107 infostream << "Server: A banned client tried to connect from "
1108 << addr_s << "; banned name was "
1109 << ban_name << std::endl;
1110 // This actually doesn't seem to transfer to the client
1111 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1112 + utf8_to_wide(ban_name));
1116 catch(con::PeerNotFoundException &e) {
1118 * no peer for this packet found
1119 * most common reason is peer timeout, e.g. peer didn't
1120 * respond for some time, your server was overloaded or
1123 infostream << "Server::ProcessData(): Canceling: peer "
1124 << peer_id << " not found" << std::endl;
1129 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1131 // Command must be handled into ToServerCommandHandler
1132 if (command >= TOSERVER_NUM_MSG_TYPES) {
1133 infostream << "Server: Ignoring unknown command "
1134 << command << std::endl;
1138 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1143 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1145 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1146 errorstream << "Server::ProcessData(): Cancelling: Peer"
1147 " serialization format invalid or not initialized."
1148 " Skipping incoming command=" << command << std::endl;
1152 /* Handle commands related to client startup */
1153 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1158 if (m_clients.getClientState(peer_id) < CS_Active) {
1159 if (command == TOSERVER_PLAYERPOS) return;
1161 errorstream << "Got packet command: " << command << " for peer id "
1162 << peer_id << " but client isn't active yet. Dropping packet "
1168 } catch (SendFailedException &e) {
1169 errorstream << "Server::ProcessData(): SendFailedException: "
1170 << "what=" << e.what()
1172 } catch (PacketError &e) {
1173 actionstream << "Server::ProcessData(): PacketError: "
1174 << "what=" << e.what()
1179 void Server::setTimeOfDay(u32 time)
1181 m_env->setTimeOfDay(time);
1182 m_time_of_day_send_timer = 0;
1185 void Server::onMapEditEvent(MapEditEvent *event)
1187 if (m_ignore_map_edit_events_area.contains(event->getArea()))
1189 MapEditEvent *e = event->clone();
1190 m_unsent_map_edit_queue.push(e);
1193 Inventory* Server::getInventory(const InventoryLocation &loc)
1196 case InventoryLocation::UNDEFINED:
1197 case InventoryLocation::CURRENT_PLAYER:
1199 case InventoryLocation::PLAYER:
1201 RemotePlayer *player = m_env->getPlayer(loc.name.c_str());
1204 PlayerSAO *playersao = player->getPlayerSAO();
1207 return playersao->getInventory();
1210 case InventoryLocation::NODEMETA:
1212 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1215 return meta->getInventory();
1218 case InventoryLocation::DETACHED:
1220 if(m_detached_inventories.count(loc.name) == 0)
1222 return m_detached_inventories[loc.name];
1226 sanity_check(false); // abort
1231 void Server::setInventoryModified(const InventoryLocation &loc, bool playerSend)
1234 case InventoryLocation::UNDEFINED:
1236 case InventoryLocation::PLAYER:
1241 RemotePlayer *player = m_env->getPlayer(loc.name.c_str());
1246 PlayerSAO *playersao = player->getPlayerSAO();
1250 SendInventory(playersao);
1253 case InventoryLocation::NODEMETA:
1255 v3s16 blockpos = getNodeBlockPos(loc.p);
1257 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
1259 block->raiseModified(MOD_STATE_WRITE_NEEDED);
1261 m_clients.markBlockposAsNotSent(blockpos);
1264 case InventoryLocation::DETACHED:
1266 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
1270 sanity_check(false); // abort
1275 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1277 std::vector<session_t> clients = m_clients.getClientIDs();
1279 // Set the modified blocks unsent for all the clients
1280 for (const session_t client_id : clients) {
1281 if (RemoteClient *client = m_clients.lockedGetClientNoEx(client_id))
1282 client->SetBlocksNotSent(block);
1287 void Server::peerAdded(con::Peer *peer)
1289 verbosestream<<"Server::peerAdded(): peer->id="
1290 <<peer->id<<std::endl;
1292 m_peer_change_queue.push(con::PeerChange(con::PEER_ADDED, peer->id, false));
1295 void Server::deletingPeer(con::Peer *peer, bool timeout)
1297 verbosestream<<"Server::deletingPeer(): peer->id="
1298 <<peer->id<<", timeout="<<timeout<<std::endl;
1300 m_clients.event(peer->id, CSE_Disconnect);
1301 m_peer_change_queue.push(con::PeerChange(con::PEER_REMOVED, peer->id, timeout));
1304 bool Server::getClientConInfo(session_t peer_id, con::rtt_stat_type type, float* retval)
1306 *retval = m_con->getPeerStat(peer_id,type);
1307 return *retval != -1;
1310 bool Server::getClientInfo(
1319 std::string* vers_string
1322 *state = m_clients.getClientState(peer_id);
1324 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1331 *uptime = client->uptime();
1332 *ser_vers = client->serialization_version;
1333 *prot_vers = client->net_proto_version;
1335 *major = client->getMajor();
1336 *minor = client->getMinor();
1337 *patch = client->getPatch();
1338 *vers_string = client->getPatch();
1345 void Server::handlePeerChanges()
1347 while(!m_peer_change_queue.empty())
1349 con::PeerChange c = m_peer_change_queue.front();
1350 m_peer_change_queue.pop();
1352 verbosestream<<"Server: Handling peer change: "
1353 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1358 case con::PEER_ADDED:
1359 m_clients.CreateClient(c.peer_id);
1362 case con::PEER_REMOVED:
1363 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1367 FATAL_ERROR("Invalid peer change event received!");
1373 void Server::printToConsoleOnly(const std::string &text)
1376 m_admin_chat->outgoing_queue.push_back(
1377 new ChatEventChat("", utf8_to_wide(text)));
1379 std::cout << text << std::endl;
1383 void Server::Send(NetworkPacket *pkt)
1385 Send(pkt->getPeerId(), pkt);
1388 void Server::Send(session_t peer_id, NetworkPacket *pkt)
1390 m_clients.send(peer_id,
1391 clientCommandFactoryTable[pkt->getCommand()].channel,
1393 clientCommandFactoryTable[pkt->getCommand()].reliable);
1396 void Server::SendMovement(session_t peer_id)
1398 std::ostringstream os(std::ios_base::binary);
1400 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1402 pkt << g_settings->getFloat("movement_acceleration_default");
1403 pkt << g_settings->getFloat("movement_acceleration_air");
1404 pkt << g_settings->getFloat("movement_acceleration_fast");
1405 pkt << g_settings->getFloat("movement_speed_walk");
1406 pkt << g_settings->getFloat("movement_speed_crouch");
1407 pkt << g_settings->getFloat("movement_speed_fast");
1408 pkt << g_settings->getFloat("movement_speed_climb");
1409 pkt << g_settings->getFloat("movement_speed_jump");
1410 pkt << g_settings->getFloat("movement_liquid_fluidity");
1411 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1412 pkt << g_settings->getFloat("movement_liquid_sink");
1413 pkt << g_settings->getFloat("movement_gravity");
1418 void Server::SendPlayerHPOrDie(PlayerSAO *playersao, const PlayerHPChangeReason &reason)
1420 if (!g_settings->getBool("enable_damage"))
1423 session_t peer_id = playersao->getPeerID();
1424 bool is_alive = playersao->getHP() > 0;
1427 SendPlayerHP(peer_id);
1429 DiePlayer(peer_id, reason);
1432 void Server::SendHP(session_t peer_id, u16 hp)
1434 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1439 void Server::SendBreath(session_t peer_id, u16 breath)
1441 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1442 pkt << (u16) breath;
1446 void Server::SendAccessDenied(session_t peer_id, AccessDeniedCode reason,
1447 const std::string &custom_reason, bool reconnect)
1449 assert(reason < SERVER_ACCESSDENIED_MAX);
1451 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1453 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
1454 pkt << custom_reason;
1455 else if (reason == SERVER_ACCESSDENIED_SHUTDOWN ||
1456 reason == SERVER_ACCESSDENIED_CRASH)
1457 pkt << custom_reason << (u8)reconnect;
1461 void Server::SendAccessDenied_Legacy(session_t peer_id,const std::wstring &reason)
1463 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1468 void Server::SendDeathscreen(session_t peer_id, bool set_camera_point_target,
1469 v3f camera_point_target)
1471 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1472 pkt << set_camera_point_target << camera_point_target;
1476 void Server::SendItemDef(session_t peer_id,
1477 IItemDefManager *itemdef, u16 protocol_version)
1479 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1483 u32 length of the next item
1484 zlib-compressed serialized ItemDefManager
1486 std::ostringstream tmp_os(std::ios::binary);
1487 itemdef->serialize(tmp_os, protocol_version);
1488 std::ostringstream tmp_os2(std::ios::binary);
1489 compressZlib(tmp_os.str(), tmp_os2);
1490 pkt.putLongString(tmp_os2.str());
1493 verbosestream << "Server: Sending item definitions to id(" << peer_id
1494 << "): size=" << pkt.getSize() << std::endl;
1499 void Server::SendNodeDef(session_t peer_id,
1500 const NodeDefManager *nodedef, u16 protocol_version)
1502 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1506 u32 length of the next item
1507 zlib-compressed serialized NodeDefManager
1509 std::ostringstream tmp_os(std::ios::binary);
1510 nodedef->serialize(tmp_os, protocol_version);
1511 std::ostringstream tmp_os2(std::ios::binary);
1512 compressZlib(tmp_os.str(), tmp_os2);
1514 pkt.putLongString(tmp_os2.str());
1517 verbosestream << "Server: Sending node definitions to id(" << peer_id
1518 << "): size=" << pkt.getSize() << std::endl;
1524 Non-static send methods
1527 void Server::SendInventory(PlayerSAO* playerSAO)
1529 UpdateCrafting(playerSAO->getPlayer());
1535 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, playerSAO->getPeerID());
1537 std::ostringstream os;
1538 playerSAO->getInventory()->serialize(os);
1540 std::string s = os.str();
1542 pkt.putRawString(s.c_str(), s.size());
1546 void Server::SendChatMessage(session_t peer_id, const ChatMessage &message)
1548 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1550 u8 type = message.type;
1551 pkt << version << type << std::wstring(L"") << message.message << message.timestamp;
1553 if (peer_id != PEER_ID_INEXISTENT) {
1554 RemotePlayer *player = m_env->getPlayer(peer_id);
1560 m_clients.sendToAll(&pkt);
1564 void Server::SendShowFormspecMessage(session_t peer_id, const std::string &formspec,
1565 const std::string &formname)
1567 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1568 if (formspec.empty()){
1569 //the client should close the formspec
1570 m_formspec_state_data.erase(peer_id);
1571 pkt.putLongString("");
1573 m_formspec_state_data[peer_id] = formname;
1574 pkt.putLongString(FORMSPEC_VERSION_STRING + formspec);
1581 // Spawns a particle on peer with peer_id
1582 void Server::SendSpawnParticle(session_t peer_id, u16 protocol_version,
1583 v3f pos, v3f velocity, v3f acceleration,
1584 float expirationtime, float size, bool collisiondetection,
1585 bool collision_removal,
1586 bool vertical, const std::string &texture,
1587 const struct TileAnimationParams &animation, u8 glow)
1589 static thread_local const float radius =
1590 g_settings->getS16("max_block_send_distance") * MAP_BLOCKSIZE * BS;
1592 if (peer_id == PEER_ID_INEXISTENT) {
1593 std::vector<session_t> clients = m_clients.getClientIDs();
1595 for (const session_t client_id : clients) {
1596 RemotePlayer *player = m_env->getPlayer(client_id);
1600 PlayerSAO *sao = player->getPlayerSAO();
1604 // Do not send to distant clients
1605 if (sao->getBasePosition().getDistanceFrom(pos * BS) > radius)
1608 SendSpawnParticle(client_id, player->protocol_version,
1609 pos, velocity, acceleration,
1610 expirationtime, size, collisiondetection,
1611 collision_removal, vertical, texture, animation, glow);
1616 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1618 pkt << pos << velocity << acceleration << expirationtime
1619 << size << collisiondetection;
1620 pkt.putLongString(texture);
1622 pkt << collision_removal;
1623 // This is horrible but required (why are there two ways to serialize pkts?)
1624 std::ostringstream os(std::ios_base::binary);
1625 animation.serialize(os, protocol_version);
1626 pkt.putRawString(os.str());
1632 // Adds a ParticleSpawner on peer with peer_id
1633 void Server::SendAddParticleSpawner(session_t peer_id, u16 protocol_version,
1634 u16 amount, float spawntime, v3f minpos, v3f maxpos,
1635 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1636 float minsize, float maxsize, bool collisiondetection, bool collision_removal,
1637 u16 attached_id, bool vertical, const std::string &texture, u32 id,
1638 const struct TileAnimationParams &animation, u8 glow)
1640 if (peer_id == PEER_ID_INEXISTENT) {
1641 // This sucks and should be replaced:
1642 std::vector<session_t> clients = m_clients.getClientIDs();
1643 for (const session_t client_id : clients) {
1644 RemotePlayer *player = m_env->getPlayer(client_id);
1647 SendAddParticleSpawner(client_id, player->protocol_version,
1648 amount, spawntime, minpos, maxpos,
1649 minvel, maxvel, minacc, maxacc, minexptime, maxexptime,
1650 minsize, maxsize, collisiondetection, collision_removal,
1651 attached_id, vertical, texture, id, animation, glow);
1656 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1658 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1659 << minacc << maxacc << minexptime << maxexptime << minsize
1660 << maxsize << collisiondetection;
1662 pkt.putLongString(texture);
1664 pkt << id << vertical;
1665 pkt << collision_removal;
1667 // This is horrible but required
1668 std::ostringstream os(std::ios_base::binary);
1669 animation.serialize(os, protocol_version);
1670 pkt.putRawString(os.str());
1676 void Server::SendDeleteParticleSpawner(session_t peer_id, u32 id)
1678 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER, 4, peer_id);
1680 // Ugly error in this packet
1683 if (peer_id != PEER_ID_INEXISTENT)
1686 m_clients.sendToAll(&pkt);
1690 void Server::SendHUDAdd(session_t peer_id, u32 id, HudElement *form)
1692 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1694 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1695 << form->text << form->number << form->item << form->dir
1696 << form->align << form->offset << form->world_pos << form->size;
1701 void Server::SendHUDRemove(session_t peer_id, u32 id)
1703 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1708 void Server::SendHUDChange(session_t peer_id, u32 id, HudElementStat stat, void *value)
1710 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1711 pkt << id << (u8) stat;
1715 case HUD_STAT_SCALE:
1716 case HUD_STAT_ALIGN:
1717 case HUD_STAT_OFFSET:
1718 pkt << *(v2f *) value;
1722 pkt << *(std::string *) value;
1724 case HUD_STAT_WORLD_POS:
1725 pkt << *(v3f *) value;
1728 pkt << *(v2s32 *) value;
1730 case HUD_STAT_NUMBER:
1734 pkt << *(u32 *) value;
1741 void Server::SendHUDSetFlags(session_t peer_id, u32 flags, u32 mask)
1743 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1745 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1747 pkt << flags << mask;
1752 void Server::SendHUDSetParam(session_t peer_id, u16 param, const std::string &value)
1754 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1755 pkt << param << value;
1759 void Server::SendSetSky(session_t peer_id, const video::SColor &bgcolor,
1760 const std::string &type, const std::vector<std::string> ¶ms,
1763 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1764 pkt << bgcolor << type << (u16) params.size();
1766 for (const std::string ¶m : params)
1774 void Server::SendCloudParams(session_t peer_id, const CloudParams ¶ms)
1776 NetworkPacket pkt(TOCLIENT_CLOUD_PARAMS, 0, peer_id);
1777 pkt << params.density << params.color_bright << params.color_ambient
1778 << params.height << params.thickness << params.speed;
1782 void Server::SendOverrideDayNightRatio(session_t peer_id, bool do_override,
1785 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1788 pkt << do_override << (u16) (ratio * 65535);
1793 void Server::SendTimeOfDay(session_t peer_id, u16 time, f32 time_speed)
1795 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1796 pkt << time << time_speed;
1798 if (peer_id == PEER_ID_INEXISTENT) {
1799 m_clients.sendToAll(&pkt);
1806 void Server::SendPlayerHP(session_t peer_id)
1808 PlayerSAO *playersao = getPlayerSAO(peer_id);
1809 // In some rare case if the player is disconnected
1810 // while Lua call l_punch, for example, this can be NULL
1814 SendHP(peer_id, playersao->getHP());
1815 m_script->player_event(playersao,"health_changed");
1817 // Send to other clients
1818 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
1819 ActiveObjectMessage aom(playersao->getId(), true, str);
1820 playersao->m_messages_out.push(aom);
1823 void Server::SendPlayerBreath(PlayerSAO *sao)
1827 m_script->player_event(sao, "breath_changed");
1828 SendBreath(sao->getPeerID(), sao->getBreath());
1831 void Server::SendMovePlayer(session_t peer_id)
1833 RemotePlayer *player = m_env->getPlayer(peer_id);
1835 PlayerSAO *sao = player->getPlayerSAO();
1838 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1839 pkt << sao->getBasePosition() << sao->getPitch() << sao->getYaw();
1842 v3f pos = sao->getBasePosition();
1843 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1844 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1845 << " pitch=" << sao->getPitch()
1846 << " yaw=" << sao->getYaw()
1853 void Server::SendLocalPlayerAnimations(session_t peer_id, v2s32 animation_frames[4],
1854 f32 animation_speed)
1856 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1859 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1860 << animation_frames[3] << animation_speed;
1865 void Server::SendEyeOffset(session_t peer_id, v3f first, v3f third)
1867 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1868 pkt << first << third;
1872 void Server::SendPlayerPrivileges(session_t peer_id)
1874 RemotePlayer *player = m_env->getPlayer(peer_id);
1876 if(player->getPeerId() == PEER_ID_INEXISTENT)
1879 std::set<std::string> privs;
1880 m_script->getAuth(player->getName(), NULL, &privs);
1882 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1883 pkt << (u16) privs.size();
1885 for (const std::string &priv : privs) {
1892 void Server::SendPlayerInventoryFormspec(session_t peer_id)
1894 RemotePlayer *player = m_env->getPlayer(peer_id);
1896 if (player->getPeerId() == PEER_ID_INEXISTENT)
1899 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1900 pkt.putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
1904 void Server::SendPlayerFormspecPrepend(session_t peer_id)
1906 RemotePlayer *player = m_env->getPlayer(peer_id);
1908 if (player->getPeerId() == PEER_ID_INEXISTENT)
1911 NetworkPacket pkt(TOCLIENT_FORMSPEC_PREPEND, 0, peer_id);
1912 pkt << FORMSPEC_VERSION_STRING + player->formspec_prepend;
1916 u32 Server::SendActiveObjectRemoveAdd(session_t peer_id, const std::string &datas)
1918 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, datas.size(), peer_id);
1919 pkt.putRawString(datas.c_str(), datas.size());
1921 return pkt.getSize();
1924 void Server::SendActiveObjectMessages(session_t peer_id, const std::string &datas,
1927 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
1928 datas.size(), peer_id);
1930 pkt.putRawString(datas.c_str(), datas.size());
1932 m_clients.send(pkt.getPeerId(),
1933 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
1937 void Server::SendCSMFlavourLimits(session_t peer_id)
1939 NetworkPacket pkt(TOCLIENT_CSM_FLAVOUR_LIMITS,
1940 sizeof(m_csm_flavour_limits) + sizeof(m_csm_noderange_limit), peer_id);
1941 pkt << m_csm_flavour_limits << m_csm_noderange_limit;
1945 s32 Server::playSound(const SimpleSoundSpec &spec,
1946 const ServerSoundParams ¶ms)
1948 // Find out initial position of sound
1949 bool pos_exists = false;
1950 v3f pos = params.getPos(m_env, &pos_exists);
1951 // If position is not found while it should be, cancel sound
1952 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
1955 // Filter destination clients
1956 std::vector<session_t> dst_clients;
1957 if(!params.to_player.empty()) {
1958 RemotePlayer *player = m_env->getPlayer(params.to_player.c_str());
1960 infostream<<"Server::playSound: Player \""<<params.to_player
1961 <<"\" not found"<<std::endl;
1964 if (player->getPeerId() == PEER_ID_INEXISTENT) {
1965 infostream<<"Server::playSound: Player \""<<params.to_player
1966 <<"\" not connected"<<std::endl;
1969 dst_clients.push_back(player->getPeerId());
1971 std::vector<session_t> clients = m_clients.getClientIDs();
1973 for (const session_t client_id : clients) {
1974 RemotePlayer *player = m_env->getPlayer(client_id);
1978 PlayerSAO *sao = player->getPlayerSAO();
1983 if(sao->getBasePosition().getDistanceFrom(pos) >
1984 params.max_hear_distance)
1987 dst_clients.push_back(client_id);
1991 if(dst_clients.empty())
1995 s32 id = m_next_sound_id++;
1996 // The sound will exist as a reference in m_playing_sounds
1997 m_playing_sounds[id] = ServerPlayingSound();
1998 ServerPlayingSound &psound = m_playing_sounds[id];
1999 psound.params = params;
2002 float gain = params.gain * spec.gain;
2003 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2004 pkt << id << spec.name << gain
2005 << (u8) params.type << pos << params.object
2006 << params.loop << params.fade << params.pitch;
2008 // Backwards compability
2009 bool play_sound = gain > 0;
2011 for (const u16 dst_client : dst_clients) {
2012 if (play_sound || m_clients.getProtocolVersion(dst_client) >= 32) {
2013 psound.clients.insert(dst_client);
2014 m_clients.send(dst_client, 0, &pkt, true);
2019 void Server::stopSound(s32 handle)
2021 // Get sound reference
2022 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2023 m_playing_sounds.find(handle);
2024 if (i == m_playing_sounds.end())
2026 ServerPlayingSound &psound = i->second;
2028 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2031 for (std::unordered_set<session_t>::const_iterator si = psound.clients.begin();
2032 si != psound.clients.end(); ++si) {
2034 m_clients.send(*si, 0, &pkt, true);
2036 // Remove sound reference
2037 m_playing_sounds.erase(i);
2040 void Server::fadeSound(s32 handle, float step, float gain)
2042 // Get sound reference
2043 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2044 m_playing_sounds.find(handle);
2045 if (i == m_playing_sounds.end())
2048 ServerPlayingSound &psound = i->second;
2049 psound.params.gain = gain;
2051 NetworkPacket pkt(TOCLIENT_FADE_SOUND, 4);
2052 pkt << handle << step << gain;
2054 // Backwards compability
2055 bool play_sound = gain > 0;
2056 ServerPlayingSound compat_psound = psound;
2057 compat_psound.clients.clear();
2059 NetworkPacket compat_pkt(TOCLIENT_STOP_SOUND, 4);
2060 compat_pkt << handle;
2062 for (std::unordered_set<u16>::iterator it = psound.clients.begin();
2063 it != psound.clients.end();) {
2064 if (m_clients.getProtocolVersion(*it) >= 32) {
2066 m_clients.send(*it, 0, &pkt, true);
2069 compat_psound.clients.insert(*it);
2071 m_clients.send(*it, 0, &compat_pkt, true);
2072 psound.clients.erase(it++);
2076 // Remove sound reference
2077 if (!play_sound || psound.clients.empty())
2078 m_playing_sounds.erase(i);
2080 if (play_sound && !compat_psound.clients.empty()) {
2081 // Play new sound volume on older clients
2082 playSound(compat_psound.spec, compat_psound.params);
2086 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
2087 std::vector<u16> *far_players, float far_d_nodes)
2089 float maxd = far_d_nodes*BS;
2090 v3f p_f = intToFloat(p, BS);
2092 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2095 std::vector<session_t> clients = m_clients.getClientIDs();
2096 for (session_t client_id : clients) {
2099 if (RemotePlayer *player = m_env->getPlayer(client_id)) {
2100 PlayerSAO *sao = player->getPlayerSAO();
2104 // If player is far away, only set modified blocks not sent
2105 v3f player_pos = sao->getBasePosition();
2106 if (player_pos.getDistanceFrom(p_f) > maxd) {
2107 far_players->push_back(client_id);
2114 m_clients.send(client_id, 0, &pkt, true);
2118 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
2119 std::vector<u16> *far_players, float far_d_nodes,
2120 bool remove_metadata)
2122 float maxd = far_d_nodes*BS;
2123 v3f p_f = intToFloat(p, BS);
2125 std::vector<session_t> clients = m_clients.getClientIDs();
2126 for (const session_t client_id : clients) {
2129 if (RemotePlayer *player = m_env->getPlayer(client_id)) {
2130 PlayerSAO *sao = player->getPlayerSAO();
2134 // If player is far away, only set modified blocks not sent
2135 v3f player_pos = sao->getBasePosition();
2136 if(player_pos.getDistanceFrom(p_f) > maxd) {
2137 far_players->push_back(client_id);
2143 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2145 RemoteClient* client = m_clients.lockedGetClientNoEx(client_id);
2147 pkt << p << n.param0 << n.param1 << n.param2
2148 << (u8) (remove_metadata ? 0 : 1);
2153 if (pkt.getSize() > 0)
2154 m_clients.send(client_id, 0, &pkt, true);
2158 void Server::SendBlockNoLock(session_t peer_id, MapBlock *block, u8 ver,
2159 u16 net_proto_version)
2162 Create a packet with the block in the right format
2165 std::ostringstream os(std::ios_base::binary);
2166 block->serialize(os, ver, false);
2167 block->serializeNetworkSpecific(os);
2168 std::string s = os.str();
2170 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2172 pkt << block->getPos();
2173 pkt.putRawString(s.c_str(), s.size());
2177 void Server::SendBlocks(float dtime)
2179 MutexAutoLock envlock(m_env_mutex);
2180 //TODO check if one big lock could be faster then multiple small ones
2182 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2184 std::vector<PrioritySortedBlockTransfer> queue;
2186 u32 total_sending = 0;
2189 ScopeProfiler sp2(g_profiler, "Server: selecting blocks for sending");
2191 std::vector<session_t> clients = m_clients.getClientIDs();
2194 for (const session_t client_id : clients) {
2195 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id, CS_Active);
2200 total_sending += client->getSendingCount();
2201 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2207 // Lowest priority number comes first.
2208 // Lowest is most important.
2209 std::sort(queue.begin(), queue.end());
2213 // Maximal total count calculation
2214 // The per-client block sends is halved with the maximal online users
2215 u32 max_blocks_to_send = (m_env->getPlayerCount() + g_settings->getU32("max_users")) *
2216 g_settings->getU32("max_simultaneous_block_sends_per_client") / 4 + 1;
2218 for (const PrioritySortedBlockTransfer &block_to_send : queue) {
2219 if (total_sending >= max_blocks_to_send)
2222 MapBlock *block = nullptr;
2224 block = m_env->getMap().getBlockNoCreate(block_to_send.pos);
2225 } catch (const InvalidPositionException &e) {
2229 RemoteClient *client = m_clients.lockedGetClientNoEx(block_to_send.peer_id,
2234 SendBlockNoLock(block_to_send.peer_id, block, client->serialization_version,
2235 client->net_proto_version);
2237 client->SentBlock(block_to_send.pos);
2243 void Server::fillMediaCache()
2245 infostream<<"Server: Calculating media file checksums"<<std::endl;
2247 // Collect all media file paths
2248 std::vector<std::string> paths;
2249 m_modmgr->getModsMediaPaths(paths);
2250 fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures");
2251 fs::GetRecursiveDirs(paths, porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2253 // Collect media file information from paths into cache
2254 for (const std::string &mediapath : paths) {
2255 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2256 for (const fs::DirListNode &dln : dirlist) {
2257 if (dln.dir) // Ignode dirs
2259 std::string filename = dln.name;
2260 // If name contains illegal characters, ignore the file
2261 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2262 infostream<<"Server: ignoring illegal file name: \""
2263 << filename << "\"" << std::endl;
2266 // If name is not in a supported format, ignore it
2267 const char *supported_ext[] = {
2268 ".png", ".jpg", ".bmp", ".tga",
2269 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2271 ".x", ".b3d", ".md2", ".obj",
2272 // Custom translation file format
2276 if (removeStringEnd(filename, supported_ext).empty()){
2277 infostream << "Server: ignoring unsupported file extension: \""
2278 << filename << "\"" << std::endl;
2281 // Ok, attempt to load the file and add to cache
2282 std::string filepath;
2283 filepath.append(mediapath).append(DIR_DELIM).append(filename);
2286 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2288 errorstream << "Server::fillMediaCache(): Could not open \""
2289 << filename << "\" for reading" << std::endl;
2292 std::ostringstream tmp_os(std::ios_base::binary);
2296 fis.read(buf, 1024);
2297 std::streamsize len = fis.gcount();
2298 tmp_os.write(buf, len);
2307 errorstream<<"Server::fillMediaCache(): Failed to read \""
2308 << filename << "\"" << std::endl;
2311 if(tmp_os.str().length() == 0) {
2312 errorstream << "Server::fillMediaCache(): Empty file \""
2313 << filepath << "\"" << std::endl;
2318 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2320 unsigned char *digest = sha1.getDigest();
2321 std::string sha1_base64 = base64_encode(digest, 20);
2322 std::string sha1_hex = hex_encode((char*)digest, 20);
2326 m_media[filename] = MediaInfo(filepath, sha1_base64);
2327 verbosestream << "Server: " << sha1_hex << " is " << filename
2333 void Server::sendMediaAnnouncement(session_t peer_id, const std::string &lang_code)
2335 verbosestream << "Server: Announcing files to id(" << peer_id << ")"
2339 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2342 std::string lang_suffix;
2343 lang_suffix.append(".").append(lang_code).append(".tr");
2344 for (const auto &i : m_media) {
2345 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2352 for (const auto &i : m_media) {
2353 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2355 pkt << i.first << i.second.sha1_digest;
2358 pkt << g_settings->get("remote_media");
2362 struct SendableMedia
2368 SendableMedia(const std::string &name_="", const std::string &path_="",
2369 const std::string &data_=""):
2376 void Server::sendRequestedMedia(session_t peer_id,
2377 const std::vector<std::string> &tosend)
2379 verbosestream<<"Server::sendRequestedMedia(): "
2380 <<"Sending files to client"<<std::endl;
2384 // Put 5kB in one bunch (this is not accurate)
2385 u32 bytes_per_bunch = 5000;
2387 std::vector< std::vector<SendableMedia> > file_bunches;
2388 file_bunches.emplace_back();
2390 u32 file_size_bunch_total = 0;
2392 for (const std::string &name : tosend) {
2393 if (m_media.find(name) == m_media.end()) {
2394 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2395 <<"unknown file \""<<(name)<<"\""<<std::endl;
2399 //TODO get path + name
2400 std::string tpath = m_media[name].path;
2403 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2405 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2406 <<tpath<<"\" for reading"<<std::endl;
2409 std::ostringstream tmp_os(std::ios_base::binary);
2413 fis.read(buf, 1024);
2414 std::streamsize len = fis.gcount();
2415 tmp_os.write(buf, len);
2416 file_size_bunch_total += len;
2425 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2426 <<name<<"\""<<std::endl;
2429 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2430 <<tname<<"\""<<std::endl;*/
2432 file_bunches[file_bunches.size()-1].emplace_back(name, tpath, tmp_os.str());
2434 // Start next bunch if got enough data
2435 if(file_size_bunch_total >= bytes_per_bunch) {
2436 file_bunches.emplace_back();
2437 file_size_bunch_total = 0;
2442 /* Create and send packets */
2444 u16 num_bunches = file_bunches.size();
2445 for (u16 i = 0; i < num_bunches; i++) {
2448 u16 total number of texture bunches
2449 u16 index of this bunch
2450 u32 number of files in this bunch
2459 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2460 pkt << num_bunches << i << (u32) file_bunches[i].size();
2462 for (const SendableMedia &j : file_bunches[i]) {
2464 pkt.putLongString(j.data);
2467 verbosestream << "Server::sendRequestedMedia(): bunch "
2468 << i << "/" << num_bunches
2469 << " files=" << file_bunches[i].size()
2470 << " size=" << pkt.getSize() << std::endl;
2475 void Server::sendDetachedInventory(const std::string &name, session_t peer_id)
2477 if(m_detached_inventories.count(name) == 0) {
2478 errorstream<<FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
2481 Inventory *inv = m_detached_inventories[name];
2482 std::ostringstream os(std::ios_base::binary);
2484 os << serializeString(name);
2488 std::string s = os.str();
2490 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2491 pkt.putRawString(s.c_str(), s.size());
2493 const std::string &check = m_detached_inventories_player[name];
2494 if (peer_id == PEER_ID_INEXISTENT) {
2496 return m_clients.sendToAll(&pkt);
2497 RemotePlayer *p = m_env->getPlayer(check.c_str());
2499 m_clients.send(p->getPeerId(), 0, &pkt, true);
2501 if (check.empty() || getPlayerName(peer_id) == check)
2506 void Server::sendDetachedInventories(session_t peer_id)
2508 for (const auto &detached_inventory : m_detached_inventories) {
2509 const std::string &name = detached_inventory.first;
2510 //Inventory *inv = i->second;
2511 sendDetachedInventory(name, peer_id);
2519 void Server::DiePlayer(session_t peer_id, const PlayerHPChangeReason &reason)
2521 PlayerSAO *playersao = getPlayerSAO(peer_id);
2522 // In some rare cases this can be NULL -- if the player is disconnected
2523 // when a Lua function modifies l_punch, for example
2527 infostream << "Server::DiePlayer(): Player "
2528 << playersao->getPlayer()->getName()
2529 << " dies" << std::endl;
2531 playersao->setHP(0, reason);
2532 playersao->clearParentAttachment();
2534 // Trigger scripted stuff
2535 m_script->on_dieplayer(playersao, reason);
2537 SendPlayerHP(peer_id);
2538 SendDeathscreen(peer_id, false, v3f(0,0,0));
2541 void Server::RespawnPlayer(session_t peer_id)
2543 PlayerSAO *playersao = getPlayerSAO(peer_id);
2546 infostream << "Server::RespawnPlayer(): Player "
2547 << playersao->getPlayer()->getName()
2548 << " respawns" << std::endl;
2550 playersao->setHP(playersao->accessObjectProperties()->hp_max,
2551 PlayerHPChangeReason(PlayerHPChangeReason::RESPAWN));
2552 playersao->setBreath(playersao->accessObjectProperties()->breath_max);
2554 bool repositioned = m_script->on_respawnplayer(playersao);
2555 if (!repositioned) {
2556 // setPos will send the new position to client
2557 playersao->setPos(findSpawnPos());
2560 SendPlayerHP(peer_id);
2564 void Server::DenySudoAccess(session_t peer_id)
2566 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2571 void Server::DenyAccessVerCompliant(session_t peer_id, u16 proto_ver, AccessDeniedCode reason,
2572 const std::string &str_reason, bool reconnect)
2574 SendAccessDenied(peer_id, reason, str_reason, reconnect);
2576 m_clients.event(peer_id, CSE_SetDenied);
2577 DisconnectPeer(peer_id);
2581 void Server::DenyAccess(session_t peer_id, AccessDeniedCode reason,
2582 const std::string &custom_reason)
2584 SendAccessDenied(peer_id, reason, custom_reason);
2585 m_clients.event(peer_id, CSE_SetDenied);
2586 DisconnectPeer(peer_id);
2589 // 13/03/15: remove this function when protocol version 25 will become
2590 // the minimum version for MT users, maybe in 1 year
2591 void Server::DenyAccess_Legacy(session_t peer_id, const std::wstring &reason)
2593 SendAccessDenied_Legacy(peer_id, reason);
2594 m_clients.event(peer_id, CSE_SetDenied);
2595 DisconnectPeer(peer_id);
2598 void Server::DisconnectPeer(session_t peer_id)
2600 m_modchannel_mgr->leaveAllChannels(peer_id);
2601 m_con->DisconnectPeer(peer_id);
2604 void Server::acceptAuth(session_t peer_id, bool forSudoMode)
2607 RemoteClient* client = getClient(peer_id, CS_Invalid);
2609 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2611 // Right now, the auth mechs don't change between login and sudo mode.
2612 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2613 client->allowed_sudo_mechs = sudo_auth_mechs;
2615 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2616 << g_settings->getFloat("dedicated_server_step")
2620 m_clients.event(peer_id, CSE_AuthAccept);
2622 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2624 // We only support SRP right now
2625 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2627 resp_pkt << sudo_auth_mechs;
2629 m_clients.event(peer_id, CSE_SudoSuccess);
2633 void Server::DeleteClient(session_t peer_id, ClientDeletionReason reason)
2635 std::wstring message;
2638 Clear references to playing sounds
2640 for (std::unordered_map<s32, ServerPlayingSound>::iterator
2641 i = m_playing_sounds.begin(); i != m_playing_sounds.end();) {
2642 ServerPlayingSound &psound = i->second;
2643 psound.clients.erase(peer_id);
2644 if (psound.clients.empty())
2645 m_playing_sounds.erase(i++);
2650 // clear formspec info so the next client can't abuse the current state
2651 m_formspec_state_data.erase(peer_id);
2653 RemotePlayer *player = m_env->getPlayer(peer_id);
2655 /* Run scripts and remove from environment */
2657 PlayerSAO *playersao = player->getPlayerSAO();
2660 playersao->clearChildAttachments();
2661 playersao->clearParentAttachment();
2663 // inform connected clients
2664 NetworkPacket notice(TOCLIENT_UPDATE_PLAYER_LIST, 0, PEER_ID_INEXISTENT);
2665 // (u16) 1 + std::string represents a vector serialization representation
2666 notice << (u8) PLAYER_LIST_REMOVE << (u16) 1 << std::string(playersao->getPlayer()->getName());
2667 m_clients.sendToAll(¬ice);
2669 m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
2671 playersao->disconnected();
2678 if (player && reason != CDR_DENY) {
2679 std::ostringstream os(std::ios_base::binary);
2680 std::vector<session_t> clients = m_clients.getClientIDs();
2682 for (const session_t client_id : clients) {
2684 RemotePlayer *player = m_env->getPlayer(client_id);
2688 // Get name of player
2689 os << player->getName() << " ";
2692 std::string name = player->getName();
2693 actionstream << name << " "
2694 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2695 << " List of players: " << os.str() << std::endl;
2697 m_admin_chat->outgoing_queue.push_back(
2698 new ChatEventNick(CET_NICK_REMOVE, name));
2702 MutexAutoLock env_lock(m_env_mutex);
2703 m_clients.DeleteClient(peer_id);
2707 // Send leave chat message to all remaining clients
2708 if (!message.empty()) {
2709 SendChatMessage(PEER_ID_INEXISTENT,
2710 ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE, message));
2714 void Server::UpdateCrafting(RemotePlayer *player)
2716 InventoryList *clist = player->inventory.getList("craft");
2717 if (!clist || clist->getSize() == 0)
2720 // Get a preview for crafting
2722 InventoryLocation loc;
2723 loc.setPlayer(player->getName());
2724 std::vector<ItemStack> output_replacements;
2725 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2726 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(),
2729 InventoryList *plist = player->inventory.getList("craftpreview");
2730 if (plist && plist->getSize() >= 1) {
2731 // Put the new preview in
2732 plist->changeItem(0, preview);
2736 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2738 if (evt->type == CET_NICK_ADD) {
2739 // The terminal informed us of its nick choice
2740 m_admin_nick = ((ChatEventNick *)evt)->nick;
2741 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2742 errorstream << "You haven't set up an account." << std::endl
2743 << "Please log in using the client as '"
2744 << m_admin_nick << "' with a secure password." << std::endl
2745 << "Until then, you can't execute admin tasks via the console," << std::endl
2746 << "and everybody can claim the user account instead of you," << std::endl
2747 << "giving them full control over this server." << std::endl;
2750 assert(evt->type == CET_CHAT);
2751 handleAdminChat((ChatEventChat *)evt);
2755 std::wstring Server::handleChat(const std::string &name, const std::wstring &wname,
2756 std::wstring wmessage, bool check_shout_priv, RemotePlayer *player)
2758 // If something goes wrong, this player is to blame
2759 RollbackScopeActor rollback_scope(m_rollback,
2760 std::string("player:") + name);
2762 if (g_settings->getBool("strip_color_codes"))
2763 wmessage = unescape_enriched(wmessage);
2766 switch (player->canSendChatMessage()) {
2767 case RPLAYER_CHATRESULT_FLOODING: {
2768 std::wstringstream ws;
2769 ws << L"You cannot send more messages. You are limited to "
2770 << g_settings->getFloat("chat_message_limit_per_10sec")
2771 << L" messages per 10 seconds.";
2774 case RPLAYER_CHATRESULT_KICK:
2775 DenyAccess_Legacy(player->getPeerId(),
2776 L"You have been kicked due to message flooding.");
2778 case RPLAYER_CHATRESULT_OK:
2781 FATAL_ERROR("Unhandled chat filtering result found.");
2785 if (m_max_chatmessage_length > 0
2786 && wmessage.length() > m_max_chatmessage_length) {
2787 return L"Your message exceed the maximum chat message limit set on the server. "
2788 L"It was refused. Send a shorter message";
2791 // Run script hook, exit if script ate the chat message
2792 if (m_script->on_chat_message(name, wide_to_utf8(wmessage)))
2797 // Whether to send line to the player that sent the message, or to all players
2798 bool broadcast_line = true;
2800 if (check_shout_priv && !checkPriv(name, "shout")) {
2801 line += L"-!- You don't have permission to shout.";
2802 broadcast_line = false;
2811 Tell calling method to send the message to sender
2813 if (!broadcast_line)
2817 Send the message to others
2819 actionstream << "CHAT: " << wide_to_narrow(unescape_enriched(line)) << std::endl;
2821 std::vector<session_t> clients = m_clients.getClientIDs();
2824 Send the message back to the inital sender
2825 if they are using protocol version >= 29
2828 session_t peer_id_to_avoid_sending =
2829 (player ? player->getPeerId() : PEER_ID_INEXISTENT);
2831 if (player && player->protocol_version >= 29)
2832 peer_id_to_avoid_sending = PEER_ID_INEXISTENT;
2834 for (u16 cid : clients) {
2835 if (cid != peer_id_to_avoid_sending)
2836 SendChatMessage(cid, ChatMessage(line));
2841 void Server::handleAdminChat(const ChatEventChat *evt)
2843 std::string name = evt->nick;
2844 std::wstring wname = utf8_to_wide(name);
2845 std::wstring wmessage = evt->evt_msg;
2847 std::wstring answer = handleChat(name, wname, wmessage);
2849 // If asked to send answer to sender
2850 if (!answer.empty()) {
2851 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
2855 RemoteClient *Server::getClient(session_t peer_id, ClientState state_min)
2857 RemoteClient *client = getClientNoEx(peer_id,state_min);
2859 throw ClientNotFoundException("Client not found");
2863 RemoteClient *Server::getClientNoEx(session_t peer_id, ClientState state_min)
2865 return m_clients.getClientNoEx(peer_id, state_min);
2868 std::string Server::getPlayerName(session_t peer_id)
2870 RemotePlayer *player = m_env->getPlayer(peer_id);
2872 return "[id="+itos(peer_id)+"]";
2873 return player->getName();
2876 PlayerSAO *Server::getPlayerSAO(session_t peer_id)
2878 RemotePlayer *player = m_env->getPlayer(peer_id);
2881 return player->getPlayerSAO();
2884 std::wstring Server::getStatusString()
2886 std::wostringstream os(std::ios_base::binary);
2889 os<<L"version="<<narrow_to_wide(g_version_string);
2891 os<<L", uptime="<<m_uptime.get();
2893 os<<L", max_lag="<<m_env->getMaxLagEstimate();
2894 // Information about clients
2897 std::vector<session_t> clients = m_clients.getClientIDs();
2898 for (session_t client_id : clients) {
2900 RemotePlayer *player = m_env->getPlayer(client_id);
2901 // Get name of player
2902 std::wstring name = L"unknown";
2904 name = narrow_to_wide(player->getName());
2905 // Add name to information string
2914 if (!((ServerMap*)(&m_env->getMap()))->isSavingEnabled())
2915 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
2917 if (!g_settings->get("motd").empty())
2918 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
2922 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
2924 std::set<std::string> privs;
2925 m_script->getAuth(name, NULL, &privs);
2929 bool Server::checkPriv(const std::string &name, const std::string &priv)
2931 std::set<std::string> privs = getPlayerEffectivePrivs(name);
2932 return (privs.count(priv) != 0);
2935 void Server::reportPrivsModified(const std::string &name)
2938 std::vector<session_t> clients = m_clients.getClientIDs();
2939 for (const session_t client_id : clients) {
2940 RemotePlayer *player = m_env->getPlayer(client_id);
2941 reportPrivsModified(player->getName());
2944 RemotePlayer *player = m_env->getPlayer(name.c_str());
2947 SendPlayerPrivileges(player->getPeerId());
2948 PlayerSAO *sao = player->getPlayerSAO();
2951 sao->updatePrivileges(
2952 getPlayerEffectivePrivs(name),
2957 void Server::reportInventoryFormspecModified(const std::string &name)
2959 RemotePlayer *player = m_env->getPlayer(name.c_str());
2962 SendPlayerInventoryFormspec(player->getPeerId());
2965 void Server::reportFormspecPrependModified(const std::string &name)
2967 RemotePlayer *player = m_env->getPlayer(name.c_str());
2970 SendPlayerFormspecPrepend(player->getPeerId());
2973 void Server::setIpBanned(const std::string &ip, const std::string &name)
2975 m_banmanager->add(ip, name);
2978 void Server::unsetIpBanned(const std::string &ip_or_name)
2980 m_banmanager->remove(ip_or_name);
2983 std::string Server::getBanDescription(const std::string &ip_or_name)
2985 return m_banmanager->getBanDescription(ip_or_name);
2988 void Server::notifyPlayer(const char *name, const std::wstring &msg)
2990 // m_env will be NULL if the server is initializing
2994 if (m_admin_nick == name && !m_admin_nick.empty()) {
2995 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
2998 RemotePlayer *player = m_env->getPlayer(name);
3003 if (player->getPeerId() == PEER_ID_INEXISTENT)
3006 SendChatMessage(player->getPeerId(), ChatMessage(msg));
3009 bool Server::showFormspec(const char *playername, const std::string &formspec,
3010 const std::string &formname)
3012 // m_env will be NULL if the server is initializing
3016 RemotePlayer *player = m_env->getPlayer(playername);
3020 SendShowFormspecMessage(player->getPeerId(), formspec, formname);
3024 u32 Server::hudAdd(RemotePlayer *player, HudElement *form)
3029 u32 id = player->addHud(form);
3031 SendHUDAdd(player->getPeerId(), id, form);
3036 bool Server::hudRemove(RemotePlayer *player, u32 id) {
3040 HudElement* todel = player->removeHud(id);
3047 SendHUDRemove(player->getPeerId(), id);
3051 bool Server::hudChange(RemotePlayer *player, u32 id, HudElementStat stat, void *data)
3056 SendHUDChange(player->getPeerId(), id, stat, data);
3060 bool Server::hudSetFlags(RemotePlayer *player, u32 flags, u32 mask)
3065 SendHUDSetFlags(player->getPeerId(), flags, mask);
3066 player->hud_flags &= ~mask;
3067 player->hud_flags |= flags;
3069 PlayerSAO* playersao = player->getPlayerSAO();
3074 m_script->player_event(playersao, "hud_changed");
3078 bool Server::hudSetHotbarItemcount(RemotePlayer *player, s32 hotbar_itemcount)
3083 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3086 player->setHotbarItemcount(hotbar_itemcount);
3087 std::ostringstream os(std::ios::binary);
3088 writeS32(os, hotbar_itemcount);
3089 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3093 void Server::hudSetHotbarImage(RemotePlayer *player, std::string name)
3098 player->setHotbarImage(name);
3099 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_IMAGE, name);
3102 void Server::hudSetHotbarSelectedImage(RemotePlayer *player, std::string name)
3107 player->setHotbarSelectedImage(name);
3108 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3111 Address Server::getPeerAddress(session_t peer_id)
3113 return m_con->GetPeerAddress(peer_id);
3116 void Server::setLocalPlayerAnimations(RemotePlayer *player,
3117 v2s32 animation_frames[4], f32 frame_speed)
3119 sanity_check(player);
3120 player->setLocalAnimations(animation_frames, frame_speed);
3121 SendLocalPlayerAnimations(player->getPeerId(), animation_frames, frame_speed);
3124 void Server::setPlayerEyeOffset(RemotePlayer *player, const v3f &first, const v3f &third)
3126 sanity_check(player);
3127 player->eye_offset_first = first;
3128 player->eye_offset_third = third;
3129 SendEyeOffset(player->getPeerId(), first, third);
3132 void Server::setSky(RemotePlayer *player, const video::SColor &bgcolor,
3133 const std::string &type, const std::vector<std::string> ¶ms,
3136 sanity_check(player);
3137 player->setSky(bgcolor, type, params, clouds);
3138 SendSetSky(player->getPeerId(), bgcolor, type, params, clouds);
3141 void Server::setClouds(RemotePlayer *player, const CloudParams ¶ms)
3143 sanity_check(player);
3144 player->setCloudParams(params);
3145 SendCloudParams(player->getPeerId(), params);
3148 bool Server::overrideDayNightRatio(RemotePlayer *player, bool do_override,
3154 player->overrideDayNightRatio(do_override, ratio);
3155 SendOverrideDayNightRatio(player->getPeerId(), do_override, ratio);
3159 void Server::notifyPlayers(const std::wstring &msg)
3161 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(msg));
3164 void Server::spawnParticle(const std::string &playername, v3f pos,
3165 v3f velocity, v3f acceleration,
3166 float expirationtime, float size, bool
3167 collisiondetection, bool collision_removal,
3168 bool vertical, const std::string &texture,
3169 const struct TileAnimationParams &animation, u8 glow)
3171 // m_env will be NULL if the server is initializing
3175 session_t peer_id = PEER_ID_INEXISTENT;
3177 if (!playername.empty()) {
3178 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3181 peer_id = player->getPeerId();
3182 proto_ver = player->protocol_version;
3185 SendSpawnParticle(peer_id, proto_ver, pos, velocity, acceleration,
3186 expirationtime, size, collisiondetection,
3187 collision_removal, vertical, texture, animation, glow);
3190 u32 Server::addParticleSpawner(u16 amount, float spawntime,
3191 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
3192 float minexptime, float maxexptime, float minsize, float maxsize,
3193 bool collisiondetection, bool collision_removal,
3194 ServerActiveObject *attached, bool vertical, const std::string &texture,
3195 const std::string &playername, const struct TileAnimationParams &animation,
3198 // m_env will be NULL if the server is initializing
3202 session_t peer_id = PEER_ID_INEXISTENT;
3204 if (!playername.empty()) {
3205 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3208 peer_id = player->getPeerId();
3209 proto_ver = player->protocol_version;
3212 u16 attached_id = attached ? attached->getId() : 0;
3215 if (attached_id == 0)
3216 id = m_env->addParticleSpawner(spawntime);
3218 id = m_env->addParticleSpawner(spawntime, attached_id);
3220 SendAddParticleSpawner(peer_id, proto_ver, amount, spawntime,
3221 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3222 minexptime, maxexptime, minsize, maxsize,
3223 collisiondetection, collision_removal, attached_id, vertical,
3224 texture, id, animation, glow);
3229 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3231 // m_env will be NULL if the server is initializing
3233 throw ServerError("Can't delete particle spawners during initialisation!");
3235 session_t peer_id = PEER_ID_INEXISTENT;
3236 if (!playername.empty()) {
3237 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3240 peer_id = player->getPeerId();
3243 m_env->deleteParticleSpawner(id);
3244 SendDeleteParticleSpawner(peer_id, id);
3247 Inventory* Server::createDetachedInventory(const std::string &name, const std::string &player)
3249 if(m_detached_inventories.count(name) > 0){
3250 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3251 delete m_detached_inventories[name];
3253 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3255 Inventory *inv = new Inventory(m_itemdef);
3257 m_detached_inventories[name] = inv;
3258 m_detached_inventories_player[name] = player;
3259 //TODO find a better way to do this
3260 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3264 // actions: time-reversed list
3265 // Return value: success/failure
3266 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3267 std::list<std::string> *log)
3269 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3270 ServerMap *map = (ServerMap*)(&m_env->getMap());
3272 // Fail if no actions to handle
3273 if (actions.empty()) {
3275 log->push_back("Nothing to do.");
3282 for (const RollbackAction &action : actions) {
3284 bool success = action.applyRevert(map, this, this);
3287 std::ostringstream os;
3288 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3289 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3291 log->push_back(os.str());
3293 std::ostringstream os;
3294 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3295 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3297 log->push_back(os.str());
3301 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3302 <<" failed"<<std::endl;
3304 // Call it done if less than half failed
3305 return num_failed <= num_tried/2;
3308 // IGameDef interface
3310 IItemDefManager *Server::getItemDefManager()
3315 const NodeDefManager *Server::getNodeDefManager()
3320 ICraftDefManager *Server::getCraftDefManager()
3325 u16 Server::allocateUnknownNodeId(const std::string &name)
3327 return m_nodedef->allocateDummy(name);
3330 IWritableItemDefManager *Server::getWritableItemDefManager()
3335 NodeDefManager *Server::getWritableNodeDefManager()
3340 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3345 const std::vector<ModSpec> & Server::getMods() const
3347 return m_modmgr->getMods();
3350 const ModSpec *Server::getModSpec(const std::string &modname) const
3352 return m_modmgr->getModSpec(modname);
3355 void Server::getModNames(std::vector<std::string> &modlist)
3357 m_modmgr->getModNames(modlist);
3360 std::string Server::getBuiltinLuaPath()
3362 return porting::path_share + DIR_DELIM + "builtin";
3365 std::string Server::getModStoragePath() const
3367 return m_path_world + DIR_DELIM + "mod_storage";
3370 v3f Server::findSpawnPos()
3372 ServerMap &map = m_env->getServerMap();
3374 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf)) {
3375 return nodeposf * BS;
3378 bool is_good = false;
3379 // Limit spawn range to mapgen edges (determined by 'mapgen_limit')
3380 s32 range_max = map.getMapgenParams()->getSpawnRangeMax();
3382 // Try to find a good place a few times
3383 for(s32 i = 0; i < 4000 && !is_good; i++) {
3384 s32 range = MYMIN(1 + i, range_max);
3385 // We're going to try to throw the player to this position
3386 v2s16 nodepos2d = v2s16(
3387 -range + (myrand() % (range * 2)),
3388 -range + (myrand() % (range * 2)));
3390 // Get spawn level at point
3391 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3392 // Continue if MAX_MAP_GENERATION_LIMIT was returned by
3393 // the mapgen to signify an unsuitable spawn position
3394 if (spawn_level == MAX_MAP_GENERATION_LIMIT)
3397 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3400 for (s32 i = 0; i < 10; i++) {
3401 v3s16 blockpos = getNodeBlockPos(nodepos);
3402 map.emergeBlock(blockpos, true);
3403 content_t c = map.getNodeNoEx(nodepos).getContent();
3404 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3406 if (air_count >= 2) {
3407 nodeposf = intToFloat(nodepos, BS);
3408 // Don't spawn the player outside map boundaries
3409 if (objectpos_over_limit(nodeposf))
3422 void Server::requestShutdown(const std::string &msg, bool reconnect, float delay)
3424 if (delay == 0.0f) {
3425 // No delay, shutdown immediately
3426 m_shutdown_state.is_requested = true;
3427 // only print to the infostream, a chat message saying
3428 // "Server Shutting Down" is sent when the server destructs.
3429 infostream << "*** Immediate Server shutdown requested." << std::endl;
3430 } else if (delay < 0.0f && m_shutdown_state.isTimerRunning()) {
3431 // Negative delay, cancel shutdown if requested
3432 m_shutdown_state.reset();
3433 std::wstringstream ws;
3435 ws << L"*** Server shutdown canceled.";
3437 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3438 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3439 // m_shutdown_* are already handled, skip.
3441 } else if (delay > 0.0f) {
3442 // Positive delay, tell the clients when the server will shut down
3443 std::wstringstream ws;
3445 ws << L"*** Server shutting down in "
3446 << duration_to_string(myround(delay)).c_str()
3449 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3450 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3453 m_shutdown_state.trigger(delay, msg, reconnect);
3456 PlayerSAO* Server::emergePlayer(const char *name, session_t peer_id, u16 proto_version)
3459 Try to get an existing player
3461 RemotePlayer *player = m_env->getPlayer(name);
3463 // If player is already connected, cancel
3464 if (player && player->getPeerId() != PEER_ID_INEXISTENT) {
3465 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3470 If player with the wanted peer_id already exists, cancel.
3472 if (m_env->getPlayer(peer_id)) {
3473 infostream<<"emergePlayer(): Player with wrong name but same"
3474 " peer_id already exists"<<std::endl;
3479 player = new RemotePlayer(name, idef());
3482 bool newplayer = false;
3485 PlayerSAO *playersao = m_env->loadPlayer(player, &newplayer, peer_id, isSingleplayer());
3487 // Complete init with server parts
3488 playersao->finalize(player, getPlayerEffectivePrivs(player->getName()));
3489 player->protocol_version = proto_version;
3493 m_script->on_newplayer(playersao);
3499 bool Server::registerModStorage(ModMetadata *storage)
3501 if (m_mod_storages.find(storage->getModName()) != m_mod_storages.end()) {
3502 errorstream << "Unable to register same mod storage twice. Storage name: "
3503 << storage->getModName() << std::endl;
3507 m_mod_storages[storage->getModName()] = storage;
3511 void Server::unregisterModStorage(const std::string &name)
3513 std::unordered_map<std::string, ModMetadata *>::const_iterator it = m_mod_storages.find(name);
3514 if (it != m_mod_storages.end()) {
3515 // Save unconditionaly on unregistration
3516 it->second->save(getModStoragePath());
3517 m_mod_storages.erase(name);
3521 void dedicated_server_loop(Server &server, bool &kill)
3523 verbosestream<<"dedicated_server_loop()"<<std::endl;
3525 IntervalLimiter m_profiler_interval;
3527 static thread_local const float steplen =
3528 g_settings->getFloat("dedicated_server_step");
3529 static thread_local const float profiler_print_interval =
3530 g_settings->getFloat("profiler_print_interval");
3533 // This is kind of a hack but can be done like this
3534 // because server.step() is very light
3536 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3537 sleep_ms((int)(steplen*1000.0));
3539 server.step(steplen);
3541 if (server.isShutdownRequested() || kill)
3547 if (profiler_print_interval != 0) {
3548 if(m_profiler_interval.step(steplen, profiler_print_interval))
3550 infostream<<"Profiler:"<<std::endl;
3551 g_profiler->print(infostream);
3552 g_profiler->clear();
3557 infostream << "Dedicated server quitting" << std::endl;
3559 if (g_settings->getBool("server_announce"))
3560 ServerList::sendAnnounce(ServerList::AA_DELETE,
3561 server.m_bind_addr.getPort());
3570 bool Server::joinModChannel(const std::string &channel)
3572 return m_modchannel_mgr->joinChannel(channel, PEER_ID_SERVER) &&
3573 m_modchannel_mgr->setChannelState(channel, MODCHANNEL_STATE_READ_WRITE);
3576 bool Server::leaveModChannel(const std::string &channel)
3578 return m_modchannel_mgr->leaveChannel(channel, PEER_ID_SERVER);
3581 bool Server::sendModChannelMessage(const std::string &channel, const std::string &message)
3583 if (!m_modchannel_mgr->canWriteOnChannel(channel))
3586 broadcastModChannelMessage(channel, message, PEER_ID_SERVER);
3590 ModChannel* Server::getModChannel(const std::string &channel)
3592 return m_modchannel_mgr->getModChannel(channel);
3595 void Server::broadcastModChannelMessage(const std::string &channel,
3596 const std::string &message, session_t from_peer)
3598 const std::vector<u16> &peers = m_modchannel_mgr->getChannelPeers(channel);
3602 if (message.size() > STRING_MAX_LEN) {
3603 warningstream << "ModChannel message too long, dropping before sending "
3604 << " (" << message.size() << " > " << STRING_MAX_LEN << ", channel: "
3605 << channel << ")" << std::endl;
3610 if (from_peer != PEER_ID_SERVER) {
3611 sender = getPlayerName(from_peer);
3614 NetworkPacket resp_pkt(TOCLIENT_MODCHANNEL_MSG,
3615 2 + channel.size() + 2 + sender.size() + 2 + message.size());
3616 resp_pkt << channel << sender << message;
3617 for (session_t peer_id : peers) {
3619 if (peer_id == from_peer)
3622 Send(peer_id, &resp_pkt);
3625 if (from_peer != PEER_ID_SERVER) {
3626 m_script->on_modchannel_message(channel, sender, message);