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 //but make sure there wasn't another one open in meantime
1581 const auto it = m_formspec_state_data.find(peer_id);
1582 if (it != m_formspec_state_data.end() && it->second == formname) {
1583 m_formspec_state_data.erase(peer_id);
1585 pkt.putLongString("");
1587 m_formspec_state_data[peer_id] = formname;
1588 pkt.putLongString(FORMSPEC_VERSION_STRING + formspec);
1595 // Spawns a particle on peer with peer_id
1596 void Server::SendSpawnParticle(session_t peer_id, u16 protocol_version,
1597 v3f pos, v3f velocity, v3f acceleration,
1598 float expirationtime, float size, bool collisiondetection,
1599 bool collision_removal, bool object_collision,
1600 bool vertical, const std::string &texture,
1601 const struct TileAnimationParams &animation, u8 glow)
1603 static thread_local const float radius =
1604 g_settings->getS16("max_block_send_distance") * MAP_BLOCKSIZE * BS;
1606 if (peer_id == PEER_ID_INEXISTENT) {
1607 std::vector<session_t> clients = m_clients.getClientIDs();
1609 for (const session_t client_id : clients) {
1610 RemotePlayer *player = m_env->getPlayer(client_id);
1614 PlayerSAO *sao = player->getPlayerSAO();
1618 // Do not send to distant clients
1619 if (sao->getBasePosition().getDistanceFrom(pos * BS) > radius)
1622 SendSpawnParticle(client_id, player->protocol_version,
1623 pos, velocity, acceleration,
1624 expirationtime, size, collisiondetection, collision_removal,
1625 object_collision, vertical, texture, animation, glow);
1630 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1632 pkt << pos << velocity << acceleration << expirationtime
1633 << size << collisiondetection;
1634 pkt.putLongString(texture);
1636 pkt << collision_removal;
1637 // This is horrible but required (why are there two ways to serialize pkts?)
1638 std::ostringstream os(std::ios_base::binary);
1639 animation.serialize(os, protocol_version);
1640 pkt.putRawString(os.str());
1642 pkt << object_collision;
1647 // Adds a ParticleSpawner on peer with peer_id
1648 void Server::SendAddParticleSpawner(session_t peer_id, u16 protocol_version,
1649 u16 amount, float spawntime, v3f minpos, v3f maxpos,
1650 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1651 float minsize, float maxsize, bool collisiondetection, bool collision_removal,
1652 bool object_collision, u16 attached_id, bool vertical, const std::string &texture, u32 id,
1653 const struct TileAnimationParams &animation, u8 glow)
1655 if (peer_id == PEER_ID_INEXISTENT) {
1656 // This sucks and should be replaced:
1657 std::vector<session_t> clients = m_clients.getClientIDs();
1658 for (const session_t client_id : clients) {
1659 RemotePlayer *player = m_env->getPlayer(client_id);
1662 SendAddParticleSpawner(client_id, player->protocol_version,
1663 amount, spawntime, minpos, maxpos,
1664 minvel, maxvel, minacc, maxacc, minexptime, maxexptime,
1665 minsize, maxsize, collisiondetection, collision_removal,
1666 object_collision, attached_id, vertical, texture, id,
1672 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1674 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1675 << minacc << maxacc << minexptime << maxexptime << minsize
1676 << maxsize << collisiondetection;
1678 pkt.putLongString(texture);
1680 pkt << id << vertical;
1681 pkt << collision_removal;
1683 // This is horrible but required
1684 std::ostringstream os(std::ios_base::binary);
1685 animation.serialize(os, protocol_version);
1686 pkt.putRawString(os.str());
1688 pkt << object_collision;
1693 void Server::SendDeleteParticleSpawner(session_t peer_id, u32 id)
1695 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER, 4, peer_id);
1697 // Ugly error in this packet
1700 if (peer_id != PEER_ID_INEXISTENT)
1703 m_clients.sendToAll(&pkt);
1707 void Server::SendHUDAdd(session_t peer_id, u32 id, HudElement *form)
1709 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1711 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1712 << form->text << form->number << form->item << form->dir
1713 << form->align << form->offset << form->world_pos << form->size;
1718 void Server::SendHUDRemove(session_t peer_id, u32 id)
1720 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1725 void Server::SendHUDChange(session_t peer_id, u32 id, HudElementStat stat, void *value)
1727 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1728 pkt << id << (u8) stat;
1732 case HUD_STAT_SCALE:
1733 case HUD_STAT_ALIGN:
1734 case HUD_STAT_OFFSET:
1735 pkt << *(v2f *) value;
1739 pkt << *(std::string *) value;
1741 case HUD_STAT_WORLD_POS:
1742 pkt << *(v3f *) value;
1745 pkt << *(v2s32 *) value;
1747 case HUD_STAT_NUMBER:
1751 pkt << *(u32 *) value;
1758 void Server::SendHUDSetFlags(session_t peer_id, u32 flags, u32 mask)
1760 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1762 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1764 pkt << flags << mask;
1769 void Server::SendHUDSetParam(session_t peer_id, u16 param, const std::string &value)
1771 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1772 pkt << param << value;
1776 void Server::SendSetSky(session_t peer_id, const video::SColor &bgcolor,
1777 const std::string &type, const std::vector<std::string> ¶ms,
1780 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1781 pkt << bgcolor << type << (u16) params.size();
1783 for (const std::string ¶m : params)
1791 void Server::SendCloudParams(session_t peer_id, const CloudParams ¶ms)
1793 NetworkPacket pkt(TOCLIENT_CLOUD_PARAMS, 0, peer_id);
1794 pkt << params.density << params.color_bright << params.color_ambient
1795 << params.height << params.thickness << params.speed;
1799 void Server::SendOverrideDayNightRatio(session_t peer_id, bool do_override,
1802 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1805 pkt << do_override << (u16) (ratio * 65535);
1810 void Server::SendTimeOfDay(session_t peer_id, u16 time, f32 time_speed)
1812 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1813 pkt << time << time_speed;
1815 if (peer_id == PEER_ID_INEXISTENT) {
1816 m_clients.sendToAll(&pkt);
1823 void Server::SendPlayerHP(session_t peer_id)
1825 PlayerSAO *playersao = getPlayerSAO(peer_id);
1826 // In some rare case if the player is disconnected
1827 // while Lua call l_punch, for example, this can be NULL
1831 SendHP(peer_id, playersao->getHP());
1832 m_script->player_event(playersao,"health_changed");
1834 // Send to other clients
1835 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
1836 ActiveObjectMessage aom(playersao->getId(), true, str);
1837 playersao->m_messages_out.push(aom);
1840 void Server::SendPlayerBreath(PlayerSAO *sao)
1844 m_script->player_event(sao, "breath_changed");
1845 SendBreath(sao->getPeerID(), sao->getBreath());
1848 void Server::SendMovePlayer(session_t peer_id)
1850 RemotePlayer *player = m_env->getPlayer(peer_id);
1852 PlayerSAO *sao = player->getPlayerSAO();
1855 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1856 pkt << sao->getBasePosition() << sao->getLookPitch() << sao->getRotation().Y;
1859 v3f pos = sao->getBasePosition();
1860 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1861 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1862 << " pitch=" << sao->getLookPitch()
1863 << " yaw=" << sao->getRotation().Y
1870 void Server::SendLocalPlayerAnimations(session_t peer_id, v2s32 animation_frames[4],
1871 f32 animation_speed)
1873 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1876 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1877 << animation_frames[3] << animation_speed;
1882 void Server::SendEyeOffset(session_t peer_id, v3f first, v3f third)
1884 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1885 pkt << first << third;
1889 void Server::SendPlayerPrivileges(session_t peer_id)
1891 RemotePlayer *player = m_env->getPlayer(peer_id);
1893 if(player->getPeerId() == PEER_ID_INEXISTENT)
1896 std::set<std::string> privs;
1897 m_script->getAuth(player->getName(), NULL, &privs);
1899 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1900 pkt << (u16) privs.size();
1902 for (const std::string &priv : privs) {
1909 void Server::SendPlayerInventoryFormspec(session_t peer_id)
1911 RemotePlayer *player = m_env->getPlayer(peer_id);
1913 if (player->getPeerId() == PEER_ID_INEXISTENT)
1916 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1917 pkt.putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
1921 void Server::SendPlayerFormspecPrepend(session_t peer_id)
1923 RemotePlayer *player = m_env->getPlayer(peer_id);
1925 if (player->getPeerId() == PEER_ID_INEXISTENT)
1928 NetworkPacket pkt(TOCLIENT_FORMSPEC_PREPEND, 0, peer_id);
1929 pkt << FORMSPEC_VERSION_STRING + player->formspec_prepend;
1933 u32 Server::SendActiveObjectRemoveAdd(session_t peer_id, const std::string &datas)
1935 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, datas.size(), peer_id);
1936 pkt.putRawString(datas.c_str(), datas.size());
1938 return pkt.getSize();
1941 void Server::SendActiveObjectMessages(session_t peer_id, const std::string &datas,
1944 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
1945 datas.size(), peer_id);
1947 pkt.putRawString(datas.c_str(), datas.size());
1949 m_clients.send(pkt.getPeerId(),
1950 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
1954 void Server::SendCSMRestrictionFlags(session_t peer_id)
1956 NetworkPacket pkt(TOCLIENT_CSM_RESTRICTION_FLAGS,
1957 sizeof(m_csm_restriction_flags) + sizeof(m_csm_restriction_noderange), peer_id);
1958 pkt << m_csm_restriction_flags << m_csm_restriction_noderange;
1962 s32 Server::playSound(const SimpleSoundSpec &spec,
1963 const ServerSoundParams ¶ms)
1965 // Find out initial position of sound
1966 bool pos_exists = false;
1967 v3f pos = params.getPos(m_env, &pos_exists);
1968 // If position is not found while it should be, cancel sound
1969 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
1972 // Filter destination clients
1973 std::vector<session_t> dst_clients;
1974 if(!params.to_player.empty()) {
1975 RemotePlayer *player = m_env->getPlayer(params.to_player.c_str());
1977 infostream<<"Server::playSound: Player \""<<params.to_player
1978 <<"\" not found"<<std::endl;
1981 if (player->getPeerId() == PEER_ID_INEXISTENT) {
1982 infostream<<"Server::playSound: Player \""<<params.to_player
1983 <<"\" not connected"<<std::endl;
1986 dst_clients.push_back(player->getPeerId());
1988 std::vector<session_t> clients = m_clients.getClientIDs();
1990 for (const session_t client_id : clients) {
1991 RemotePlayer *player = m_env->getPlayer(client_id);
1995 PlayerSAO *sao = player->getPlayerSAO();
2000 if(sao->getBasePosition().getDistanceFrom(pos) >
2001 params.max_hear_distance)
2004 dst_clients.push_back(client_id);
2008 if(dst_clients.empty())
2012 s32 id = m_next_sound_id++;
2013 // The sound will exist as a reference in m_playing_sounds
2014 m_playing_sounds[id] = ServerPlayingSound();
2015 ServerPlayingSound &psound = m_playing_sounds[id];
2016 psound.params = params;
2019 float gain = params.gain * spec.gain;
2020 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2021 pkt << id << spec.name << gain
2022 << (u8) params.type << pos << params.object
2023 << params.loop << params.fade << params.pitch;
2025 // Backwards compability
2026 bool play_sound = gain > 0;
2028 for (const u16 dst_client : dst_clients) {
2029 if (play_sound || m_clients.getProtocolVersion(dst_client) >= 32) {
2030 psound.clients.insert(dst_client);
2031 m_clients.send(dst_client, 0, &pkt, true);
2036 void Server::stopSound(s32 handle)
2038 // Get sound reference
2039 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2040 m_playing_sounds.find(handle);
2041 if (i == m_playing_sounds.end())
2043 ServerPlayingSound &psound = i->second;
2045 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2048 for (std::unordered_set<session_t>::const_iterator si = psound.clients.begin();
2049 si != psound.clients.end(); ++si) {
2051 m_clients.send(*si, 0, &pkt, true);
2053 // Remove sound reference
2054 m_playing_sounds.erase(i);
2057 void Server::fadeSound(s32 handle, float step, float gain)
2059 // Get sound reference
2060 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2061 m_playing_sounds.find(handle);
2062 if (i == m_playing_sounds.end())
2065 ServerPlayingSound &psound = i->second;
2066 psound.params.gain = gain;
2068 NetworkPacket pkt(TOCLIENT_FADE_SOUND, 4);
2069 pkt << handle << step << gain;
2071 // Backwards compability
2072 bool play_sound = gain > 0;
2073 ServerPlayingSound compat_psound = psound;
2074 compat_psound.clients.clear();
2076 NetworkPacket compat_pkt(TOCLIENT_STOP_SOUND, 4);
2077 compat_pkt << handle;
2079 for (std::unordered_set<u16>::iterator it = psound.clients.begin();
2080 it != psound.clients.end();) {
2081 if (m_clients.getProtocolVersion(*it) >= 32) {
2083 m_clients.send(*it, 0, &pkt, true);
2086 compat_psound.clients.insert(*it);
2088 m_clients.send(*it, 0, &compat_pkt, true);
2089 psound.clients.erase(it++);
2093 // Remove sound reference
2094 if (!play_sound || psound.clients.empty())
2095 m_playing_sounds.erase(i);
2097 if (play_sound && !compat_psound.clients.empty()) {
2098 // Play new sound volume on older clients
2099 playSound(compat_psound.spec, compat_psound.params);
2103 void Server::sendRemoveNode(v3s16 p, std::unordered_set<u16> *far_players,
2106 float maxd = far_d_nodes * BS;
2107 v3f p_f = intToFloat(p, BS);
2108 v3s16 block_pos = getNodeBlockPos(p);
2110 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2113 std::vector<session_t> clients = m_clients.getClientIDs();
2116 for (session_t client_id : clients) {
2117 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
2121 RemotePlayer *player = m_env->getPlayer(client_id);
2122 PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr;
2124 // If player is far away, only set modified blocks not sent
2125 if (!client->isBlockSent(block_pos) || (sao &&
2126 sao->getBasePosition().getDistanceFrom(p_f) > maxd)) {
2128 far_players->emplace(client_id);
2130 client->SetBlockNotSent(block_pos);
2135 m_clients.send(client_id, 0, &pkt, true);
2141 void Server::sendAddNode(v3s16 p, MapNode n, std::unordered_set<u16> *far_players,
2142 float far_d_nodes, bool remove_metadata)
2144 float maxd = far_d_nodes * BS;
2145 v3f p_f = intToFloat(p, BS);
2146 v3s16 block_pos = getNodeBlockPos(p);
2148 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2149 pkt << p << n.param0 << n.param1 << n.param2
2150 << (u8) (remove_metadata ? 0 : 1);
2152 std::vector<session_t> clients = m_clients.getClientIDs();
2155 for (session_t client_id : clients) {
2156 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
2160 RemotePlayer *player = m_env->getPlayer(client_id);
2161 PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr;
2163 // If player is far away, only set modified blocks not sent
2164 if (!client->isBlockSent(block_pos) || (sao &&
2165 sao->getBasePosition().getDistanceFrom(p_f) > maxd)) {
2167 far_players->emplace(client_id);
2169 client->SetBlockNotSent(block_pos);
2174 m_clients.send(client_id, 0, &pkt, true);
2180 void Server::sendMetadataChanged(const std::list<v3s16> &meta_updates, float far_d_nodes)
2182 float maxd = far_d_nodes * BS;
2183 NodeMetadataList meta_updates_list(false);
2184 std::vector<session_t> clients = m_clients.getClientIDs();
2188 for (session_t i : clients) {
2189 RemoteClient *client = m_clients.lockedGetClientNoEx(i);
2193 ServerActiveObject *player = m_env->getActiveObject(i);
2194 v3f player_pos = player ? player->getBasePosition() : v3f();
2196 for (const v3s16 &pos : meta_updates) {
2197 NodeMetadata *meta = m_env->getMap().getNodeMetadata(pos);
2202 v3s16 block_pos = getNodeBlockPos(pos);
2203 if (!client->isBlockSent(block_pos) || (player &&
2204 player_pos.getDistanceFrom(intToFloat(pos, BS)) > maxd)) {
2205 client->SetBlockNotSent(block_pos);
2209 // Add the change to send list
2210 meta_updates_list.set(pos, meta);
2212 if (meta_updates_list.size() == 0)
2215 // Send the meta changes
2216 std::ostringstream os(std::ios::binary);
2217 meta_updates_list.serialize(os, client->net_proto_version, false, true);
2218 std::ostringstream oss(std::ios::binary);
2219 compressZlib(os.str(), oss);
2221 NetworkPacket pkt(TOCLIENT_NODEMETA_CHANGED, 0);
2222 pkt.putLongString(oss.str());
2223 m_clients.send(i, 0, &pkt, true);
2225 meta_updates_list.clear();
2231 void Server::SendBlockNoLock(session_t peer_id, MapBlock *block, u8 ver,
2232 u16 net_proto_version)
2235 Create a packet with the block in the right format
2238 std::ostringstream os(std::ios_base::binary);
2239 block->serialize(os, ver, false);
2240 block->serializeNetworkSpecific(os);
2241 std::string s = os.str();
2243 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2245 pkt << block->getPos();
2246 pkt.putRawString(s.c_str(), s.size());
2250 void Server::SendBlocks(float dtime)
2252 MutexAutoLock envlock(m_env_mutex);
2253 //TODO check if one big lock could be faster then multiple small ones
2255 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2257 std::vector<PrioritySortedBlockTransfer> queue;
2259 u32 total_sending = 0;
2262 ScopeProfiler sp2(g_profiler, "Server: selecting blocks for sending");
2264 std::vector<session_t> clients = m_clients.getClientIDs();
2267 for (const session_t client_id : clients) {
2268 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id, CS_Active);
2273 total_sending += client->getSendingCount();
2274 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2280 // Lowest priority number comes first.
2281 // Lowest is most important.
2282 std::sort(queue.begin(), queue.end());
2286 // Maximal total count calculation
2287 // The per-client block sends is halved with the maximal online users
2288 u32 max_blocks_to_send = (m_env->getPlayerCount() + g_settings->getU32("max_users")) *
2289 g_settings->getU32("max_simultaneous_block_sends_per_client") / 4 + 1;
2291 for (const PrioritySortedBlockTransfer &block_to_send : queue) {
2292 if (total_sending >= max_blocks_to_send)
2295 MapBlock *block = nullptr;
2297 block = m_env->getMap().getBlockNoCreate(block_to_send.pos);
2298 } catch (const InvalidPositionException &e) {
2302 RemoteClient *client = m_clients.lockedGetClientNoEx(block_to_send.peer_id,
2307 SendBlockNoLock(block_to_send.peer_id, block, client->serialization_version,
2308 client->net_proto_version);
2310 client->SentBlock(block_to_send.pos);
2316 void Server::fillMediaCache()
2318 infostream<<"Server: Calculating media file checksums"<<std::endl;
2320 // Collect all media file paths
2321 std::vector<std::string> paths;
2322 m_modmgr->getModsMediaPaths(paths);
2323 fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures");
2324 fs::GetRecursiveDirs(paths, porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2326 // Collect media file information from paths into cache
2327 for (const std::string &mediapath : paths) {
2328 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2329 for (const fs::DirListNode &dln : dirlist) {
2330 if (dln.dir) // Ignode dirs
2332 std::string filename = dln.name;
2333 // If name contains illegal characters, ignore the file
2334 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2335 infostream<<"Server: ignoring illegal file name: \""
2336 << filename << "\"" << std::endl;
2339 // If name is not in a supported format, ignore it
2340 const char *supported_ext[] = {
2341 ".png", ".jpg", ".bmp", ".tga",
2342 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2344 ".x", ".b3d", ".md2", ".obj",
2345 // Custom translation file format
2349 if (removeStringEnd(filename, supported_ext).empty()){
2350 infostream << "Server: ignoring unsupported file extension: \""
2351 << filename << "\"" << std::endl;
2354 // Ok, attempt to load the file and add to cache
2355 std::string filepath;
2356 filepath.append(mediapath).append(DIR_DELIM).append(filename);
2359 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2361 errorstream << "Server::fillMediaCache(): Could not open \""
2362 << filename << "\" for reading" << std::endl;
2365 std::ostringstream tmp_os(std::ios_base::binary);
2369 fis.read(buf, 1024);
2370 std::streamsize len = fis.gcount();
2371 tmp_os.write(buf, len);
2380 errorstream<<"Server::fillMediaCache(): Failed to read \""
2381 << filename << "\"" << std::endl;
2384 if(tmp_os.str().length() == 0) {
2385 errorstream << "Server::fillMediaCache(): Empty file \""
2386 << filepath << "\"" << std::endl;
2391 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2393 unsigned char *digest = sha1.getDigest();
2394 std::string sha1_base64 = base64_encode(digest, 20);
2395 std::string sha1_hex = hex_encode((char*)digest, 20);
2399 m_media[filename] = MediaInfo(filepath, sha1_base64);
2400 verbosestream << "Server: " << sha1_hex << " is " << filename
2406 void Server::sendMediaAnnouncement(session_t peer_id, const std::string &lang_code)
2408 verbosestream << "Server: Announcing files to id(" << peer_id << ")"
2412 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2415 std::string lang_suffix;
2416 lang_suffix.append(".").append(lang_code).append(".tr");
2417 for (const auto &i : m_media) {
2418 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2425 for (const auto &i : m_media) {
2426 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2428 pkt << i.first << i.second.sha1_digest;
2431 pkt << g_settings->get("remote_media");
2435 struct SendableMedia
2441 SendableMedia(const std::string &name_="", const std::string &path_="",
2442 const std::string &data_=""):
2449 void Server::sendRequestedMedia(session_t peer_id,
2450 const std::vector<std::string> &tosend)
2452 verbosestream<<"Server::sendRequestedMedia(): "
2453 <<"Sending files to client"<<std::endl;
2457 // Put 5kB in one bunch (this is not accurate)
2458 u32 bytes_per_bunch = 5000;
2460 std::vector< std::vector<SendableMedia> > file_bunches;
2461 file_bunches.emplace_back();
2463 u32 file_size_bunch_total = 0;
2465 for (const std::string &name : tosend) {
2466 if (m_media.find(name) == m_media.end()) {
2467 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2468 <<"unknown file \""<<(name)<<"\""<<std::endl;
2472 //TODO get path + name
2473 std::string tpath = m_media[name].path;
2476 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2478 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2479 <<tpath<<"\" for reading"<<std::endl;
2482 std::ostringstream tmp_os(std::ios_base::binary);
2486 fis.read(buf, 1024);
2487 std::streamsize len = fis.gcount();
2488 tmp_os.write(buf, len);
2489 file_size_bunch_total += len;
2498 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2499 <<name<<"\""<<std::endl;
2502 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2503 <<tname<<"\""<<std::endl;*/
2505 file_bunches[file_bunches.size()-1].emplace_back(name, tpath, tmp_os.str());
2507 // Start next bunch if got enough data
2508 if(file_size_bunch_total >= bytes_per_bunch) {
2509 file_bunches.emplace_back();
2510 file_size_bunch_total = 0;
2515 /* Create and send packets */
2517 u16 num_bunches = file_bunches.size();
2518 for (u16 i = 0; i < num_bunches; i++) {
2521 u16 total number of texture bunches
2522 u16 index of this bunch
2523 u32 number of files in this bunch
2532 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2533 pkt << num_bunches << i << (u32) file_bunches[i].size();
2535 for (const SendableMedia &j : file_bunches[i]) {
2537 pkt.putLongString(j.data);
2540 verbosestream << "Server::sendRequestedMedia(): bunch "
2541 << i << "/" << num_bunches
2542 << " files=" << file_bunches[i].size()
2543 << " size=" << pkt.getSize() << std::endl;
2548 void Server::sendDetachedInventory(const std::string &name, session_t peer_id)
2550 const auto &inv_it = m_detached_inventories.find(name);
2551 const auto &player_it = m_detached_inventories_player.find(name);
2553 if (player_it == m_detached_inventories_player.end() ||
2554 player_it->second.empty()) {
2555 // OK. Send to everyone
2557 RemotePlayer *p = m_env->getPlayer(player_it->second.c_str());
2559 return; // Player is offline
2561 if (peer_id != PEER_ID_INEXISTENT && peer_id != p->getPeerId())
2562 return; // Caller requested send to a different player, so don't send.
2564 peer_id = p->getPeerId();
2567 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2570 if (inv_it == m_detached_inventories.end()) {
2571 pkt << false; // Remove inventory
2573 pkt << true; // Update inventory
2575 // Serialization & NetworkPacket isn't a love story
2576 std::ostringstream os(std::ios_base::binary);
2577 inv_it->second->serialize(os);
2581 if (peer_id == PEER_ID_INEXISTENT)
2582 m_clients.sendToAll(&pkt);
2587 void Server::sendDetachedInventories(session_t peer_id)
2589 for (const auto &detached_inventory : m_detached_inventories) {
2590 const std::string &name = detached_inventory.first;
2591 //Inventory *inv = i->second;
2592 sendDetachedInventory(name, peer_id);
2600 void Server::DiePlayer(session_t peer_id, const PlayerHPChangeReason &reason)
2602 PlayerSAO *playersao = getPlayerSAO(peer_id);
2603 // In some rare cases this can be NULL -- if the player is disconnected
2604 // when a Lua function modifies l_punch, for example
2608 infostream << "Server::DiePlayer(): Player "
2609 << playersao->getPlayer()->getName()
2610 << " dies" << std::endl;
2612 playersao->setHP(0, reason);
2613 playersao->clearParentAttachment();
2615 // Trigger scripted stuff
2616 m_script->on_dieplayer(playersao, reason);
2618 SendPlayerHP(peer_id);
2619 SendDeathscreen(peer_id, false, v3f(0,0,0));
2622 void Server::RespawnPlayer(session_t peer_id)
2624 PlayerSAO *playersao = getPlayerSAO(peer_id);
2627 infostream << "Server::RespawnPlayer(): Player "
2628 << playersao->getPlayer()->getName()
2629 << " respawns" << std::endl;
2631 playersao->setHP(playersao->accessObjectProperties()->hp_max,
2632 PlayerHPChangeReason(PlayerHPChangeReason::RESPAWN));
2633 playersao->setBreath(playersao->accessObjectProperties()->breath_max);
2635 bool repositioned = m_script->on_respawnplayer(playersao);
2636 if (!repositioned) {
2637 // setPos will send the new position to client
2638 playersao->setPos(findSpawnPos());
2641 SendPlayerHP(peer_id);
2645 void Server::DenySudoAccess(session_t peer_id)
2647 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2652 void Server::DenyAccessVerCompliant(session_t peer_id, u16 proto_ver, AccessDeniedCode reason,
2653 const std::string &str_reason, bool reconnect)
2655 SendAccessDenied(peer_id, reason, str_reason, reconnect);
2657 m_clients.event(peer_id, CSE_SetDenied);
2658 DisconnectPeer(peer_id);
2662 void Server::DenyAccess(session_t peer_id, AccessDeniedCode reason,
2663 const std::string &custom_reason)
2665 SendAccessDenied(peer_id, reason, custom_reason);
2666 m_clients.event(peer_id, CSE_SetDenied);
2667 DisconnectPeer(peer_id);
2670 // 13/03/15: remove this function when protocol version 25 will become
2671 // the minimum version for MT users, maybe in 1 year
2672 void Server::DenyAccess_Legacy(session_t peer_id, const std::wstring &reason)
2674 SendAccessDenied_Legacy(peer_id, reason);
2675 m_clients.event(peer_id, CSE_SetDenied);
2676 DisconnectPeer(peer_id);
2679 void Server::DisconnectPeer(session_t peer_id)
2681 m_modchannel_mgr->leaveAllChannels(peer_id);
2682 m_con->DisconnectPeer(peer_id);
2685 void Server::acceptAuth(session_t peer_id, bool forSudoMode)
2688 RemoteClient* client = getClient(peer_id, CS_Invalid);
2690 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2692 // Right now, the auth mechs don't change between login and sudo mode.
2693 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2694 client->allowed_sudo_mechs = sudo_auth_mechs;
2696 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2697 << g_settings->getFloat("dedicated_server_step")
2701 m_clients.event(peer_id, CSE_AuthAccept);
2703 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2705 // We only support SRP right now
2706 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2708 resp_pkt << sudo_auth_mechs;
2710 m_clients.event(peer_id, CSE_SudoSuccess);
2714 void Server::DeleteClient(session_t peer_id, ClientDeletionReason reason)
2716 std::wstring message;
2719 Clear references to playing sounds
2721 for (std::unordered_map<s32, ServerPlayingSound>::iterator
2722 i = m_playing_sounds.begin(); i != m_playing_sounds.end();) {
2723 ServerPlayingSound &psound = i->second;
2724 psound.clients.erase(peer_id);
2725 if (psound.clients.empty())
2726 m_playing_sounds.erase(i++);
2731 // clear formspec info so the next client can't abuse the current state
2732 m_formspec_state_data.erase(peer_id);
2734 RemotePlayer *player = m_env->getPlayer(peer_id);
2736 /* Run scripts and remove from environment */
2738 PlayerSAO *playersao = player->getPlayerSAO();
2741 playersao->clearChildAttachments();
2742 playersao->clearParentAttachment();
2744 // inform connected clients
2745 const std::string &player_name = player->getName();
2746 NetworkPacket notice(TOCLIENT_UPDATE_PLAYER_LIST, 0, PEER_ID_INEXISTENT);
2747 // (u16) 1 + std::string represents a vector serialization representation
2748 notice << (u8) PLAYER_LIST_REMOVE << (u16) 1 << player_name;
2749 m_clients.sendToAll(¬ice);
2751 m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
2753 playersao->disconnected();
2760 if (player && reason != CDR_DENY) {
2761 std::ostringstream os(std::ios_base::binary);
2762 std::vector<session_t> clients = m_clients.getClientIDs();
2764 for (const session_t client_id : clients) {
2766 RemotePlayer *player = m_env->getPlayer(client_id);
2770 // Get name of player
2771 os << player->getName() << " ";
2774 std::string name = player->getName();
2775 actionstream << name << " "
2776 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2777 << " List of players: " << os.str() << std::endl;
2779 m_admin_chat->outgoing_queue.push_back(
2780 new ChatEventNick(CET_NICK_REMOVE, name));
2784 MutexAutoLock env_lock(m_env_mutex);
2785 m_clients.DeleteClient(peer_id);
2789 // Send leave chat message to all remaining clients
2790 if (!message.empty()) {
2791 SendChatMessage(PEER_ID_INEXISTENT,
2792 ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE, message));
2796 void Server::UpdateCrafting(RemotePlayer *player)
2798 InventoryList *clist = player->inventory.getList("craft");
2799 if (!clist || clist->getSize() == 0)
2802 // Get a preview for crafting
2804 InventoryLocation loc;
2805 loc.setPlayer(player->getName());
2806 std::vector<ItemStack> output_replacements;
2807 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2808 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(),
2811 InventoryList *plist = player->inventory.getList("craftpreview");
2812 if (plist && plist->getSize() >= 1) {
2813 // Put the new preview in
2814 plist->changeItem(0, preview);
2818 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2820 if (evt->type == CET_NICK_ADD) {
2821 // The terminal informed us of its nick choice
2822 m_admin_nick = ((ChatEventNick *)evt)->nick;
2823 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2824 errorstream << "You haven't set up an account." << std::endl
2825 << "Please log in using the client as '"
2826 << m_admin_nick << "' with a secure password." << std::endl
2827 << "Until then, you can't execute admin tasks via the console," << std::endl
2828 << "and everybody can claim the user account instead of you," << std::endl
2829 << "giving them full control over this server." << std::endl;
2832 assert(evt->type == CET_CHAT);
2833 handleAdminChat((ChatEventChat *)evt);
2837 std::wstring Server::handleChat(const std::string &name, const std::wstring &wname,
2838 std::wstring wmessage, bool check_shout_priv, RemotePlayer *player)
2840 // If something goes wrong, this player is to blame
2841 RollbackScopeActor rollback_scope(m_rollback,
2842 std::string("player:") + name);
2844 if (g_settings->getBool("strip_color_codes"))
2845 wmessage = unescape_enriched(wmessage);
2848 switch (player->canSendChatMessage()) {
2849 case RPLAYER_CHATRESULT_FLOODING: {
2850 std::wstringstream ws;
2851 ws << L"You cannot send more messages. You are limited to "
2852 << g_settings->getFloat("chat_message_limit_per_10sec")
2853 << L" messages per 10 seconds.";
2856 case RPLAYER_CHATRESULT_KICK:
2857 DenyAccess_Legacy(player->getPeerId(),
2858 L"You have been kicked due to message flooding.");
2860 case RPLAYER_CHATRESULT_OK:
2863 FATAL_ERROR("Unhandled chat filtering result found.");
2867 if (m_max_chatmessage_length > 0
2868 && wmessage.length() > m_max_chatmessage_length) {
2869 return L"Your message exceed the maximum chat message limit set on the server. "
2870 L"It was refused. Send a shorter message";
2873 // Run script hook, exit if script ate the chat message
2874 if (m_script->on_chat_message(name, wide_to_utf8(wmessage)))
2879 // Whether to send line to the player that sent the message, or to all players
2880 bool broadcast_line = true;
2882 if (check_shout_priv && !checkPriv(name, "shout")) {
2883 line += L"-!- You don't have permission to shout.";
2884 broadcast_line = false;
2893 Tell calling method to send the message to sender
2895 if (!broadcast_line)
2899 Send the message to others
2901 actionstream << "CHAT: " << wide_to_narrow(unescape_enriched(line)) << std::endl;
2903 std::vector<session_t> clients = m_clients.getClientIDs();
2906 Send the message back to the inital sender
2907 if they are using protocol version >= 29
2910 session_t peer_id_to_avoid_sending =
2911 (player ? player->getPeerId() : PEER_ID_INEXISTENT);
2913 if (player && player->protocol_version >= 29)
2914 peer_id_to_avoid_sending = PEER_ID_INEXISTENT;
2916 for (u16 cid : clients) {
2917 if (cid != peer_id_to_avoid_sending)
2918 SendChatMessage(cid, ChatMessage(line));
2923 void Server::handleAdminChat(const ChatEventChat *evt)
2925 std::string name = evt->nick;
2926 std::wstring wname = utf8_to_wide(name);
2927 std::wstring wmessage = evt->evt_msg;
2929 std::wstring answer = handleChat(name, wname, wmessage);
2931 // If asked to send answer to sender
2932 if (!answer.empty()) {
2933 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
2937 RemoteClient *Server::getClient(session_t peer_id, ClientState state_min)
2939 RemoteClient *client = getClientNoEx(peer_id,state_min);
2941 throw ClientNotFoundException("Client not found");
2945 RemoteClient *Server::getClientNoEx(session_t peer_id, ClientState state_min)
2947 return m_clients.getClientNoEx(peer_id, state_min);
2950 std::string Server::getPlayerName(session_t peer_id)
2952 RemotePlayer *player = m_env->getPlayer(peer_id);
2954 return "[id="+itos(peer_id)+"]";
2955 return player->getName();
2958 PlayerSAO *Server::getPlayerSAO(session_t peer_id)
2960 RemotePlayer *player = m_env->getPlayer(peer_id);
2963 return player->getPlayerSAO();
2966 std::wstring Server::getStatusString()
2968 std::wostringstream os(std::ios_base::binary);
2969 os << L"# Server: ";
2971 os << L"version=" << narrow_to_wide(g_version_string);
2973 os << L", uptime=" << m_uptime.get();
2975 os << L", max_lag=" << (m_env ? m_env->getMaxLagEstimate() : 0);
2977 // Information about clients
2979 os << L", clients={";
2981 std::vector<session_t> clients = m_clients.getClientIDs();
2982 for (session_t client_id : clients) {
2983 RemotePlayer *player = m_env->getPlayer(client_id);
2985 // Get name of player
2986 std::wstring name = L"unknown";
2988 name = narrow_to_wide(player->getName());
2990 // Add name to information string
3001 if (m_env && !((ServerMap*)(&m_env->getMap()))->isSavingEnabled())
3002 os << std::endl << L"# Server: " << " WARNING: Map saving is disabled.";
3004 if (!g_settings->get("motd").empty())
3005 os << std::endl << L"# Server: " << narrow_to_wide(g_settings->get("motd"));
3010 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
3012 std::set<std::string> privs;
3013 m_script->getAuth(name, NULL, &privs);
3017 bool Server::checkPriv(const std::string &name, const std::string &priv)
3019 std::set<std::string> privs = getPlayerEffectivePrivs(name);
3020 return (privs.count(priv) != 0);
3023 void Server::reportPrivsModified(const std::string &name)
3026 std::vector<session_t> clients = m_clients.getClientIDs();
3027 for (const session_t client_id : clients) {
3028 RemotePlayer *player = m_env->getPlayer(client_id);
3029 reportPrivsModified(player->getName());
3032 RemotePlayer *player = m_env->getPlayer(name.c_str());
3035 SendPlayerPrivileges(player->getPeerId());
3036 PlayerSAO *sao = player->getPlayerSAO();
3039 sao->updatePrivileges(
3040 getPlayerEffectivePrivs(name),
3045 void Server::reportInventoryFormspecModified(const std::string &name)
3047 RemotePlayer *player = m_env->getPlayer(name.c_str());
3050 SendPlayerInventoryFormspec(player->getPeerId());
3053 void Server::reportFormspecPrependModified(const std::string &name)
3055 RemotePlayer *player = m_env->getPlayer(name.c_str());
3058 SendPlayerFormspecPrepend(player->getPeerId());
3061 void Server::setIpBanned(const std::string &ip, const std::string &name)
3063 m_banmanager->add(ip, name);
3066 void Server::unsetIpBanned(const std::string &ip_or_name)
3068 m_banmanager->remove(ip_or_name);
3071 std::string Server::getBanDescription(const std::string &ip_or_name)
3073 return m_banmanager->getBanDescription(ip_or_name);
3076 void Server::notifyPlayer(const char *name, const std::wstring &msg)
3078 // m_env will be NULL if the server is initializing
3082 if (m_admin_nick == name && !m_admin_nick.empty()) {
3083 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
3086 RemotePlayer *player = m_env->getPlayer(name);
3091 if (player->getPeerId() == PEER_ID_INEXISTENT)
3094 SendChatMessage(player->getPeerId(), ChatMessage(msg));
3097 bool Server::showFormspec(const char *playername, const std::string &formspec,
3098 const std::string &formname)
3100 // m_env will be NULL if the server is initializing
3104 RemotePlayer *player = m_env->getPlayer(playername);
3108 SendShowFormspecMessage(player->getPeerId(), formspec, formname);
3112 u32 Server::hudAdd(RemotePlayer *player, HudElement *form)
3117 u32 id = player->addHud(form);
3119 SendHUDAdd(player->getPeerId(), id, form);
3124 bool Server::hudRemove(RemotePlayer *player, u32 id) {
3128 HudElement* todel = player->removeHud(id);
3135 SendHUDRemove(player->getPeerId(), id);
3139 bool Server::hudChange(RemotePlayer *player, u32 id, HudElementStat stat, void *data)
3144 SendHUDChange(player->getPeerId(), id, stat, data);
3148 bool Server::hudSetFlags(RemotePlayer *player, u32 flags, u32 mask)
3153 SendHUDSetFlags(player->getPeerId(), flags, mask);
3154 player->hud_flags &= ~mask;
3155 player->hud_flags |= flags;
3157 PlayerSAO* playersao = player->getPlayerSAO();
3162 m_script->player_event(playersao, "hud_changed");
3166 bool Server::hudSetHotbarItemcount(RemotePlayer *player, s32 hotbar_itemcount)
3171 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3174 player->setHotbarItemcount(hotbar_itemcount);
3175 std::ostringstream os(std::ios::binary);
3176 writeS32(os, hotbar_itemcount);
3177 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3181 void Server::hudSetHotbarImage(RemotePlayer *player, std::string name)
3186 player->setHotbarImage(name);
3187 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_IMAGE, name);
3190 void Server::hudSetHotbarSelectedImage(RemotePlayer *player, std::string name)
3195 player->setHotbarSelectedImage(name);
3196 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3199 Address Server::getPeerAddress(session_t peer_id)
3201 return m_con->GetPeerAddress(peer_id);
3204 void Server::setLocalPlayerAnimations(RemotePlayer *player,
3205 v2s32 animation_frames[4], f32 frame_speed)
3207 sanity_check(player);
3208 player->setLocalAnimations(animation_frames, frame_speed);
3209 SendLocalPlayerAnimations(player->getPeerId(), animation_frames, frame_speed);
3212 void Server::setPlayerEyeOffset(RemotePlayer *player, const v3f &first, const v3f &third)
3214 sanity_check(player);
3215 player->eye_offset_first = first;
3216 player->eye_offset_third = third;
3217 SendEyeOffset(player->getPeerId(), first, third);
3220 void Server::setSky(RemotePlayer *player, const video::SColor &bgcolor,
3221 const std::string &type, const std::vector<std::string> ¶ms,
3224 sanity_check(player);
3225 player->setSky(bgcolor, type, params, clouds);
3226 SendSetSky(player->getPeerId(), bgcolor, type, params, clouds);
3229 void Server::setClouds(RemotePlayer *player, const CloudParams ¶ms)
3231 sanity_check(player);
3232 player->setCloudParams(params);
3233 SendCloudParams(player->getPeerId(), params);
3236 bool Server::overrideDayNightRatio(RemotePlayer *player, bool do_override,
3242 player->overrideDayNightRatio(do_override, ratio);
3243 SendOverrideDayNightRatio(player->getPeerId(), do_override, ratio);
3247 void Server::notifyPlayers(const std::wstring &msg)
3249 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(msg));
3252 void Server::spawnParticle(const std::string &playername, v3f pos,
3253 v3f velocity, v3f acceleration,
3254 float expirationtime, float size, bool
3255 collisiondetection, bool collision_removal, bool object_collision,
3256 bool vertical, const std::string &texture,
3257 const struct TileAnimationParams &animation, u8 glow)
3259 // m_env will be NULL if the server is initializing
3263 session_t peer_id = PEER_ID_INEXISTENT;
3265 if (!playername.empty()) {
3266 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3269 peer_id = player->getPeerId();
3270 proto_ver = player->protocol_version;
3273 SendSpawnParticle(peer_id, proto_ver, pos, velocity, acceleration,
3274 expirationtime, size, collisiondetection, collision_removal,
3275 object_collision, vertical, texture, animation, glow);
3278 u32 Server::addParticleSpawner(u16 amount, float spawntime,
3279 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
3280 float minexptime, float maxexptime, float minsize, float maxsize,
3281 bool collisiondetection, bool collision_removal, bool object_collision,
3282 ServerActiveObject *attached, bool vertical, const std::string &texture,
3283 const std::string &playername, const struct TileAnimationParams &animation,
3286 // m_env will be NULL if the server is initializing
3290 session_t peer_id = PEER_ID_INEXISTENT;
3292 if (!playername.empty()) {
3293 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3296 peer_id = player->getPeerId();
3297 proto_ver = player->protocol_version;
3300 u16 attached_id = attached ? attached->getId() : 0;
3303 if (attached_id == 0)
3304 id = m_env->addParticleSpawner(spawntime);
3306 id = m_env->addParticleSpawner(spawntime, attached_id);
3308 SendAddParticleSpawner(peer_id, proto_ver, amount, spawntime,
3309 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3310 minexptime, maxexptime, minsize, maxsize, collisiondetection,
3311 collision_removal, object_collision, attached_id, vertical,
3312 texture, id, animation, glow);
3317 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3319 // m_env will be NULL if the server is initializing
3321 throw ServerError("Can't delete particle spawners during initialisation!");
3323 session_t peer_id = PEER_ID_INEXISTENT;
3324 if (!playername.empty()) {
3325 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3328 peer_id = player->getPeerId();
3331 m_env->deleteParticleSpawner(id);
3332 SendDeleteParticleSpawner(peer_id, id);
3335 Inventory* Server::createDetachedInventory(const std::string &name, const std::string &player)
3337 if(m_detached_inventories.count(name) > 0){
3338 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3339 delete m_detached_inventories[name];
3341 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3343 Inventory *inv = new Inventory(m_itemdef);
3345 m_detached_inventories[name] = inv;
3346 m_detached_inventories_player[name] = player;
3347 //TODO find a better way to do this
3348 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3352 bool Server::removeDetachedInventory(const std::string &name)
3354 const auto &inv_it = m_detached_inventories.find(name);
3355 if (inv_it == m_detached_inventories.end())
3358 delete inv_it->second;
3359 m_detached_inventories.erase(inv_it);
3361 const auto &player_it = m_detached_inventories_player.find(name);
3362 if (player_it != m_detached_inventories_player.end()) {
3363 RemotePlayer *player = m_env->getPlayer(player_it->second.c_str());
3365 if (player && player->getPeerId() != PEER_ID_INEXISTENT)
3366 sendDetachedInventory(name, player->getPeerId());
3368 m_detached_inventories_player.erase(player_it);
3370 // Notify all players about the change
3371 sendDetachedInventory(name, PEER_ID_INEXISTENT);
3376 // actions: time-reversed list
3377 // Return value: success/failure
3378 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3379 std::list<std::string> *log)
3381 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3382 ServerMap *map = (ServerMap*)(&m_env->getMap());
3384 // Fail if no actions to handle
3385 if (actions.empty()) {
3387 log->push_back("Nothing to do.");
3394 for (const RollbackAction &action : actions) {
3396 bool success = action.applyRevert(map, this, this);
3399 std::ostringstream os;
3400 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3401 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3403 log->push_back(os.str());
3405 std::ostringstream os;
3406 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3407 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3409 log->push_back(os.str());
3413 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3414 <<" failed"<<std::endl;
3416 // Call it done if less than half failed
3417 return num_failed <= num_tried/2;
3420 // IGameDef interface
3422 IItemDefManager *Server::getItemDefManager()
3427 const NodeDefManager *Server::getNodeDefManager()
3432 ICraftDefManager *Server::getCraftDefManager()
3437 u16 Server::allocateUnknownNodeId(const std::string &name)
3439 return m_nodedef->allocateDummy(name);
3442 IWritableItemDefManager *Server::getWritableItemDefManager()
3447 NodeDefManager *Server::getWritableNodeDefManager()
3452 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3457 const std::vector<ModSpec> & Server::getMods() const
3459 return m_modmgr->getMods();
3462 const ModSpec *Server::getModSpec(const std::string &modname) const
3464 return m_modmgr->getModSpec(modname);
3467 void Server::getModNames(std::vector<std::string> &modlist)
3469 m_modmgr->getModNames(modlist);
3472 std::string Server::getBuiltinLuaPath()
3474 return porting::path_share + DIR_DELIM + "builtin";
3477 std::string Server::getModStoragePath() const
3479 return m_path_world + DIR_DELIM + "mod_storage";
3482 v3f Server::findSpawnPos()
3484 ServerMap &map = m_env->getServerMap();
3486 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf)) {
3487 return nodeposf * BS;
3490 bool is_good = false;
3491 // Limit spawn range to mapgen edges (determined by 'mapgen_limit')
3492 s32 range_max = map.getMapgenParams()->getSpawnRangeMax();
3494 // Try to find a good place a few times
3495 for(s32 i = 0; i < 4000 && !is_good; i++) {
3496 s32 range = MYMIN(1 + i, range_max);
3497 // We're going to try to throw the player to this position
3498 v2s16 nodepos2d = v2s16(
3499 -range + (myrand() % (range * 2)),
3500 -range + (myrand() % (range * 2)));
3502 // Get spawn level at point
3503 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3504 // Continue if MAX_MAP_GENERATION_LIMIT was returned by
3505 // the mapgen to signify an unsuitable spawn position
3506 if (spawn_level == MAX_MAP_GENERATION_LIMIT)
3509 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3512 for (s32 i = 0; i < 10; i++) {
3513 v3s16 blockpos = getNodeBlockPos(nodepos);
3514 map.emergeBlock(blockpos, true);
3515 content_t c = map.getNodeNoEx(nodepos).getContent();
3516 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3518 if (air_count >= 2) {
3519 nodeposf = intToFloat(nodepos, BS);
3520 // Don't spawn the player outside map boundaries
3521 if (objectpos_over_limit(nodeposf))
3534 void Server::requestShutdown(const std::string &msg, bool reconnect, float delay)
3536 if (delay == 0.0f) {
3537 // No delay, shutdown immediately
3538 m_shutdown_state.is_requested = true;
3539 // only print to the infostream, a chat message saying
3540 // "Server Shutting Down" is sent when the server destructs.
3541 infostream << "*** Immediate Server shutdown requested." << std::endl;
3542 } else if (delay < 0.0f && m_shutdown_state.isTimerRunning()) {
3543 // Negative delay, cancel shutdown if requested
3544 m_shutdown_state.reset();
3545 std::wstringstream ws;
3547 ws << L"*** Server shutdown canceled.";
3549 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3550 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3551 // m_shutdown_* are already handled, skip.
3553 } else if (delay > 0.0f) {
3554 // Positive delay, tell the clients when the server will shut down
3555 std::wstringstream ws;
3557 ws << L"*** Server shutting down in "
3558 << duration_to_string(myround(delay)).c_str()
3561 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3562 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3565 m_shutdown_state.trigger(delay, msg, reconnect);
3568 PlayerSAO* Server::emergePlayer(const char *name, session_t peer_id, u16 proto_version)
3571 Try to get an existing player
3573 RemotePlayer *player = m_env->getPlayer(name);
3575 // If player is already connected, cancel
3576 if (player && player->getPeerId() != PEER_ID_INEXISTENT) {
3577 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3582 If player with the wanted peer_id already exists, cancel.
3584 if (m_env->getPlayer(peer_id)) {
3585 infostream<<"emergePlayer(): Player with wrong name but same"
3586 " peer_id already exists"<<std::endl;
3591 player = new RemotePlayer(name, idef());
3594 bool newplayer = false;
3597 PlayerSAO *playersao = m_env->loadPlayer(player, &newplayer, peer_id, isSingleplayer());
3599 // Complete init with server parts
3600 playersao->finalize(player, getPlayerEffectivePrivs(player->getName()));
3601 player->protocol_version = proto_version;
3605 m_script->on_newplayer(playersao);
3611 bool Server::registerModStorage(ModMetadata *storage)
3613 if (m_mod_storages.find(storage->getModName()) != m_mod_storages.end()) {
3614 errorstream << "Unable to register same mod storage twice. Storage name: "
3615 << storage->getModName() << std::endl;
3619 m_mod_storages[storage->getModName()] = storage;
3623 void Server::unregisterModStorage(const std::string &name)
3625 std::unordered_map<std::string, ModMetadata *>::const_iterator it = m_mod_storages.find(name);
3626 if (it != m_mod_storages.end()) {
3627 // Save unconditionaly on unregistration
3628 it->second->save(getModStoragePath());
3629 m_mod_storages.erase(name);
3633 void dedicated_server_loop(Server &server, bool &kill)
3635 verbosestream<<"dedicated_server_loop()"<<std::endl;
3637 IntervalLimiter m_profiler_interval;
3639 static thread_local const float steplen =
3640 g_settings->getFloat("dedicated_server_step");
3641 static thread_local const float profiler_print_interval =
3642 g_settings->getFloat("profiler_print_interval");
3645 // This is kind of a hack but can be done like this
3646 // because server.step() is very light
3648 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3649 sleep_ms((int)(steplen*1000.0));
3651 server.step(steplen);
3653 if (server.isShutdownRequested() || kill)
3659 if (profiler_print_interval != 0) {
3660 if(m_profiler_interval.step(steplen, profiler_print_interval))
3662 infostream<<"Profiler:"<<std::endl;
3663 g_profiler->print(infostream);
3664 g_profiler->clear();
3669 infostream << "Dedicated server quitting" << std::endl;
3671 if (g_settings->getBool("server_announce"))
3672 ServerList::sendAnnounce(ServerList::AA_DELETE,
3673 server.m_bind_addr.getPort());
3682 bool Server::joinModChannel(const std::string &channel)
3684 return m_modchannel_mgr->joinChannel(channel, PEER_ID_SERVER) &&
3685 m_modchannel_mgr->setChannelState(channel, MODCHANNEL_STATE_READ_WRITE);
3688 bool Server::leaveModChannel(const std::string &channel)
3690 return m_modchannel_mgr->leaveChannel(channel, PEER_ID_SERVER);
3693 bool Server::sendModChannelMessage(const std::string &channel, const std::string &message)
3695 if (!m_modchannel_mgr->canWriteOnChannel(channel))
3698 broadcastModChannelMessage(channel, message, PEER_ID_SERVER);
3702 ModChannel* Server::getModChannel(const std::string &channel)
3704 return m_modchannel_mgr->getModChannel(channel);
3707 void Server::broadcastModChannelMessage(const std::string &channel,
3708 const std::string &message, session_t from_peer)
3710 const std::vector<u16> &peers = m_modchannel_mgr->getChannelPeers(channel);
3714 if (message.size() > STRING_MAX_LEN) {
3715 warningstream << "ModChannel message too long, dropping before sending "
3716 << " (" << message.size() << " > " << STRING_MAX_LEN << ", channel: "
3717 << channel << ")" << std::endl;
3722 if (from_peer != PEER_ID_SERVER) {
3723 sender = getPlayerName(from_peer);
3726 NetworkPacket resp_pkt(TOCLIENT_MODCHANNEL_MSG,
3727 2 + channel.size() + 2 + sender.size() + 2 + message.size());
3728 resp_pkt << channel << sender << message;
3729 for (session_t peer_id : peers) {
3731 if (peer_id == from_peer)
3734 Send(peer_id, &resp_pkt);
3737 if (from_peer != PEER_ID_SERVER) {
3738 m_script->on_modchannel_message(channel, sender, message);