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()),
223 m_thread(new ServerThread(this)),
227 m_modchannel_mgr(new ModChannelMgr())
229 m_lag = g_settings->getFloat("dedicated_server_step");
231 if (m_path_world.empty())
232 throw ServerError("Supplied empty world path");
234 if (!gamespec.isValid())
235 throw ServerError("Supplied invalid gamespec");
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->saveLoadedPlayers(true);
262 m_env->kickAllPlayers(SERVER_ACCESSDENIED_SHUTDOWN,
263 kick_msg, reconnect);
266 actionstream << "Server: Shutting down" << std::endl;
268 // Do this before stopping the server in case mapgen callbacks need to access
269 // server-controlled resources (like ModStorages). Also do them before
270 // shutdown callbacks since they may modify state that is finalized in a
273 m_emerge->stopThreads();
276 MutexAutoLock envlock(m_env_mutex);
278 // Execute script shutdown hooks
279 infostream << "Executing shutdown hooks" << std::endl;
280 m_script->on_shutdown();
282 infostream << "Server: Saving environment metadata" << std::endl;
292 // Delete things in the reverse order of creation
301 // Deinitialize scripting
302 infostream << "Server: Deinitializing scripting" << std::endl;
305 // Delete detached inventories
306 for (auto &detached_inventory : m_detached_inventories) {
307 delete detached_inventory.second;
313 infostream << "Server created for gameid \"" << m_gamespec.id << "\"";
314 if (m_simple_singleplayer_mode)
315 infostream << " in simple singleplayer mode" << std::endl;
317 infostream << std::endl;
318 infostream << "- world: " << m_path_world << std::endl;
319 infostream << "- game: " << m_gamespec.path << std::endl;
321 // Create world if it doesn't exist
322 if (!loadGameConfAndInitWorld(m_path_world, m_gamespec))
323 throw ServerError("Failed to initialize world");
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_restriction_flags = g_settings->getU64("csm_restriction_flags");
405 m_csm_restriction_noderange = g_settings->getU32("csm_restriction_noderange");
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 std::list<v3s16> node_meta_updates;
865 while (!m_unsent_map_edit_queue.empty()) {
866 MapEditEvent* event = m_unsent_map_edit_queue.front();
867 m_unsent_map_edit_queue.pop();
869 // Players far away from the change are stored here.
870 // Instead of sending the changes, MapBlocks are set not sent
872 std::unordered_set<u16> far_players;
874 switch (event->type) {
877 prof.add("MEET_ADDNODE", 1);
878 sendAddNode(event->p, event->n, &far_players,
879 disable_single_change_sending ? 5 : 30,
880 event->type == MEET_ADDNODE);
882 case MEET_REMOVENODE:
883 prof.add("MEET_REMOVENODE", 1);
884 sendRemoveNode(event->p, &far_players,
885 disable_single_change_sending ? 5 : 30);
887 case MEET_BLOCK_NODE_METADATA_CHANGED: {
888 verbosestream << "Server: MEET_BLOCK_NODE_METADATA_CHANGED" << std::endl;
889 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
890 if (!event->is_private_change) {
891 // Don't send the change yet. Collect them to eliminate dupes.
892 node_meta_updates.remove(event->p);
893 node_meta_updates.push_back(event->p);
896 if (MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(
897 getNodeBlockPos(event->p))) {
898 block->raiseModified(MOD_STATE_WRITE_NEEDED,
899 MOD_REASON_REPORT_META_CHANGE);
904 infostream << "Server: MEET_OTHER" << std::endl;
905 prof.add("MEET_OTHER", 1);
906 for (const v3s16 &modified_block : event->modified_blocks) {
907 m_clients.markBlockposAsNotSent(modified_block);
911 prof.add("unknown", 1);
912 warningstream << "Server: Unknown MapEditEvent "
913 << ((u32)event->type) << std::endl;
918 Set blocks not sent to far players
920 if (!far_players.empty()) {
921 // Convert list format to that wanted by SetBlocksNotSent
922 std::map<v3s16, MapBlock*> modified_blocks2;
923 for (const v3s16 &modified_block : event->modified_blocks) {
924 modified_blocks2[modified_block] =
925 m_env->getMap().getBlockNoCreateNoEx(modified_block);
928 // Set blocks not sent
929 for (const u16 far_player : far_players) {
930 if (RemoteClient *client = getClient(far_player))
931 client->SetBlocksNotSent(modified_blocks2);
938 if (event_count >= 5) {
939 infostream << "Server: MapEditEvents:" << std::endl;
940 prof.print(infostream);
941 } else if (event_count != 0) {
942 verbosestream << "Server: MapEditEvents:" << std::endl;
943 prof.print(verbosestream);
946 // Send all metadata updates
947 if (node_meta_updates.size())
948 sendMetadataChanged(node_meta_updates);
952 Trigger emergethread (it somehow gets to a non-triggered but
953 bysy state sometimes)
956 float &counter = m_emergethread_trigger_timer;
958 if (counter >= 2.0) {
961 m_emerge->startThreads();
965 // Save map, players and auth stuff
967 float &counter = m_savemap_timer;
969 static thread_local const float save_interval =
970 g_settings->getFloat("server_map_save_interval");
971 if (counter >= save_interval) {
973 MutexAutoLock lock(m_env_mutex);
975 ScopeProfiler sp(g_profiler, "Server: saving stuff");
978 if (m_banmanager->isModified()) {
979 m_banmanager->save();
982 // Save changed parts of map
983 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
986 m_env->saveLoadedPlayers();
988 // Save environment metadata
993 m_shutdown_state.tick(dtime, this);
996 void Server::Receive()
998 session_t peer_id = 0;
1001 m_con->Receive(&pkt);
1002 peer_id = pkt.getPeerId();
1004 } catch (const con::InvalidIncomingDataException &e) {
1005 infostream << "Server::Receive(): InvalidIncomingDataException: what()="
1006 << e.what() << std::endl;
1007 } catch (const SerializationError &e) {
1008 infostream << "Server::Receive(): SerializationError: what()="
1009 << e.what() << std::endl;
1010 } catch (const ClientStateError &e) {
1011 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1012 DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
1013 L"Try reconnecting or updating your client");
1014 } catch (const con::PeerNotFoundException &e) {
1019 PlayerSAO* Server::StageTwoClientInit(session_t peer_id)
1021 std::string playername;
1022 PlayerSAO *playersao = NULL;
1025 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1027 playername = client->getName();
1028 playersao = emergePlayer(playername.c_str(), peer_id, client->net_proto_version);
1030 } catch (std::exception &e) {
1036 RemotePlayer *player = m_env->getPlayer(playername.c_str());
1038 // If failed, cancel
1039 if (!playersao || !player) {
1040 if (player && player->getPeerId() != PEER_ID_INEXISTENT) {
1041 actionstream << "Server: Failed to emerge player \"" << playername
1042 << "\" (player allocated to an another client)" << std::endl;
1043 DenyAccess_Legacy(peer_id, L"Another client is connected with this "
1044 L"name. If your client closed unexpectedly, try again in "
1047 errorstream << "Server: " << playername << ": Failed to emerge player"
1049 DenyAccess_Legacy(peer_id, L"Could not allocate player.");
1055 Send complete position information
1057 SendMovePlayer(peer_id);
1060 SendPlayerPrivileges(peer_id);
1062 // Send inventory formspec
1063 SendPlayerInventoryFormspec(peer_id);
1066 SendInventory(playersao);
1068 // Send HP or death screen
1069 if (playersao->isDead())
1070 SendDeathscreen(peer_id, false, v3f(0,0,0));
1072 SendPlayerHPOrDie(playersao,
1073 PlayerHPChangeReason(PlayerHPChangeReason::SET_HP));
1076 SendPlayerBreath(playersao);
1078 Address addr = getPeerAddress(player->getPeerId());
1079 std::string ip_str = addr.serializeString();
1080 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1085 const std::vector<std::string> &names = m_clients.getPlayerNames();
1087 actionstream << player->getName() << " joins game. List of players: ";
1089 for (const std::string &name : names) {
1090 actionstream << name << " ";
1093 actionstream << player->getName() <<std::endl;
1098 inline void Server::handleCommand(NetworkPacket* pkt)
1100 const ToServerCommandHandler& opHandle = toServerCommandTable[pkt->getCommand()];
1101 (this->*opHandle.handler)(pkt);
1104 void Server::ProcessData(NetworkPacket *pkt)
1106 // Environment is locked first.
1107 MutexAutoLock envlock(m_env_mutex);
1109 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1110 u32 peer_id = pkt->getPeerId();
1113 Address address = getPeerAddress(peer_id);
1114 std::string addr_s = address.serializeString();
1116 if(m_banmanager->isIpBanned(addr_s)) {
1117 std::string ban_name = m_banmanager->getBanName(addr_s);
1118 infostream << "Server: A banned client tried to connect from "
1119 << addr_s << "; banned name was "
1120 << ban_name << std::endl;
1121 // This actually doesn't seem to transfer to the client
1122 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1123 + utf8_to_wide(ban_name));
1127 catch(con::PeerNotFoundException &e) {
1129 * no peer for this packet found
1130 * most common reason is peer timeout, e.g. peer didn't
1131 * respond for some time, your server was overloaded or
1134 infostream << "Server::ProcessData(): Canceling: peer "
1135 << peer_id << " not found" << std::endl;
1140 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1142 // Command must be handled into ToServerCommandHandler
1143 if (command >= TOSERVER_NUM_MSG_TYPES) {
1144 infostream << "Server: Ignoring unknown command "
1145 << command << std::endl;
1149 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1154 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1156 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1157 errorstream << "Server::ProcessData(): Cancelling: Peer"
1158 " serialization format invalid or not initialized."
1159 " Skipping incoming command=" << command << std::endl;
1163 /* Handle commands related to client startup */
1164 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1169 if (m_clients.getClientState(peer_id) < CS_Active) {
1170 if (command == TOSERVER_PLAYERPOS) return;
1172 errorstream << "Got packet command: " << command << " for peer id "
1173 << peer_id << " but client isn't active yet. Dropping packet "
1179 } catch (SendFailedException &e) {
1180 errorstream << "Server::ProcessData(): SendFailedException: "
1181 << "what=" << e.what()
1183 } catch (PacketError &e) {
1184 actionstream << "Server::ProcessData(): PacketError: "
1185 << "what=" << e.what()
1190 void Server::setTimeOfDay(u32 time)
1192 m_env->setTimeOfDay(time);
1193 m_time_of_day_send_timer = 0;
1196 void Server::onMapEditEvent(MapEditEvent *event)
1198 if (m_ignore_map_edit_events_area.contains(event->getArea()))
1200 MapEditEvent *e = event->clone();
1201 m_unsent_map_edit_queue.push(e);
1204 Inventory* Server::getInventory(const InventoryLocation &loc)
1207 case InventoryLocation::UNDEFINED:
1208 case InventoryLocation::CURRENT_PLAYER:
1210 case InventoryLocation::PLAYER:
1212 RemotePlayer *player = m_env->getPlayer(loc.name.c_str());
1215 PlayerSAO *playersao = player->getPlayerSAO();
1218 return playersao->getInventory();
1221 case InventoryLocation::NODEMETA:
1223 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1226 return meta->getInventory();
1229 case InventoryLocation::DETACHED:
1231 if(m_detached_inventories.count(loc.name) == 0)
1233 return m_detached_inventories[loc.name];
1237 sanity_check(false); // abort
1243 void Server::setInventoryModified(const InventoryLocation &loc, bool playerSend)
1246 case InventoryLocation::UNDEFINED:
1248 case InventoryLocation::PLAYER:
1253 RemotePlayer *player = m_env->getPlayer(loc.name.c_str());
1258 PlayerSAO *playersao = player->getPlayerSAO();
1262 SendInventory(playersao);
1265 case InventoryLocation::NODEMETA:
1268 event.type = MEET_BLOCK_NODE_METADATA_CHANGED;
1270 m_env->getMap().dispatchEvent(&event);
1273 case InventoryLocation::DETACHED:
1275 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
1279 sanity_check(false); // abort
1284 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1286 std::vector<session_t> clients = m_clients.getClientIDs();
1288 // Set the modified blocks unsent for all the clients
1289 for (const session_t client_id : clients) {
1290 if (RemoteClient *client = m_clients.lockedGetClientNoEx(client_id))
1291 client->SetBlocksNotSent(block);
1296 void Server::peerAdded(con::Peer *peer)
1298 verbosestream<<"Server::peerAdded(): peer->id="
1299 <<peer->id<<std::endl;
1301 m_peer_change_queue.push(con::PeerChange(con::PEER_ADDED, peer->id, false));
1304 void Server::deletingPeer(con::Peer *peer, bool timeout)
1306 verbosestream<<"Server::deletingPeer(): peer->id="
1307 <<peer->id<<", timeout="<<timeout<<std::endl;
1309 m_clients.event(peer->id, CSE_Disconnect);
1310 m_peer_change_queue.push(con::PeerChange(con::PEER_REMOVED, peer->id, timeout));
1313 bool Server::getClientConInfo(session_t peer_id, con::rtt_stat_type type, float* retval)
1315 *retval = m_con->getPeerStat(peer_id,type);
1316 return *retval != -1;
1319 bool Server::getClientInfo(
1328 std::string* vers_string
1331 *state = m_clients.getClientState(peer_id);
1333 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1340 *uptime = client->uptime();
1341 *ser_vers = client->serialization_version;
1342 *prot_vers = client->net_proto_version;
1344 *major = client->getMajor();
1345 *minor = client->getMinor();
1346 *patch = client->getPatch();
1347 *vers_string = client->getPatch();
1354 void Server::handlePeerChanges()
1356 while(!m_peer_change_queue.empty())
1358 con::PeerChange c = m_peer_change_queue.front();
1359 m_peer_change_queue.pop();
1361 verbosestream<<"Server: Handling peer change: "
1362 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1367 case con::PEER_ADDED:
1368 m_clients.CreateClient(c.peer_id);
1371 case con::PEER_REMOVED:
1372 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1376 FATAL_ERROR("Invalid peer change event received!");
1382 void Server::printToConsoleOnly(const std::string &text)
1385 m_admin_chat->outgoing_queue.push_back(
1386 new ChatEventChat("", utf8_to_wide(text)));
1388 std::cout << text << std::endl;
1392 void Server::Send(NetworkPacket *pkt)
1394 Send(pkt->getPeerId(), pkt);
1397 void Server::Send(session_t peer_id, NetworkPacket *pkt)
1399 m_clients.send(peer_id,
1400 clientCommandFactoryTable[pkt->getCommand()].channel,
1402 clientCommandFactoryTable[pkt->getCommand()].reliable);
1405 void Server::SendMovement(session_t peer_id)
1407 std::ostringstream os(std::ios_base::binary);
1409 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1411 pkt << g_settings->getFloat("movement_acceleration_default");
1412 pkt << g_settings->getFloat("movement_acceleration_air");
1413 pkt << g_settings->getFloat("movement_acceleration_fast");
1414 pkt << g_settings->getFloat("movement_speed_walk");
1415 pkt << g_settings->getFloat("movement_speed_crouch");
1416 pkt << g_settings->getFloat("movement_speed_fast");
1417 pkt << g_settings->getFloat("movement_speed_climb");
1418 pkt << g_settings->getFloat("movement_speed_jump");
1419 pkt << g_settings->getFloat("movement_liquid_fluidity");
1420 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1421 pkt << g_settings->getFloat("movement_liquid_sink");
1422 pkt << g_settings->getFloat("movement_gravity");
1427 void Server::SendPlayerHPOrDie(PlayerSAO *playersao, const PlayerHPChangeReason &reason)
1429 if (!g_settings->getBool("enable_damage"))
1432 session_t peer_id = playersao->getPeerID();
1433 bool is_alive = playersao->getHP() > 0;
1436 SendPlayerHP(peer_id);
1438 DiePlayer(peer_id, reason);
1441 void Server::SendHP(session_t peer_id, u16 hp)
1443 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1448 void Server::SendBreath(session_t peer_id, u16 breath)
1450 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1451 pkt << (u16) breath;
1455 void Server::SendAccessDenied(session_t peer_id, AccessDeniedCode reason,
1456 const std::string &custom_reason, bool reconnect)
1458 assert(reason < SERVER_ACCESSDENIED_MAX);
1460 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1462 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
1463 pkt << custom_reason;
1464 else if (reason == SERVER_ACCESSDENIED_SHUTDOWN ||
1465 reason == SERVER_ACCESSDENIED_CRASH)
1466 pkt << custom_reason << (u8)reconnect;
1470 void Server::SendAccessDenied_Legacy(session_t peer_id,const std::wstring &reason)
1472 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1477 void Server::SendDeathscreen(session_t peer_id, bool set_camera_point_target,
1478 v3f camera_point_target)
1480 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1481 pkt << set_camera_point_target << camera_point_target;
1485 void Server::SendItemDef(session_t peer_id,
1486 IItemDefManager *itemdef, u16 protocol_version)
1488 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1492 u32 length of the next item
1493 zlib-compressed serialized ItemDefManager
1495 std::ostringstream tmp_os(std::ios::binary);
1496 itemdef->serialize(tmp_os, protocol_version);
1497 std::ostringstream tmp_os2(std::ios::binary);
1498 compressZlib(tmp_os.str(), tmp_os2);
1499 pkt.putLongString(tmp_os2.str());
1502 verbosestream << "Server: Sending item definitions to id(" << peer_id
1503 << "): size=" << pkt.getSize() << std::endl;
1508 void Server::SendNodeDef(session_t peer_id,
1509 const NodeDefManager *nodedef, u16 protocol_version)
1511 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1515 u32 length of the next item
1516 zlib-compressed serialized NodeDefManager
1518 std::ostringstream tmp_os(std::ios::binary);
1519 nodedef->serialize(tmp_os, protocol_version);
1520 std::ostringstream tmp_os2(std::ios::binary);
1521 compressZlib(tmp_os.str(), tmp_os2);
1523 pkt.putLongString(tmp_os2.str());
1526 verbosestream << "Server: Sending node definitions to id(" << peer_id
1527 << "): size=" << pkt.getSize() << std::endl;
1533 Non-static send methods
1536 void Server::SendInventory(PlayerSAO* playerSAO)
1538 UpdateCrafting(playerSAO->getPlayer());
1544 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, playerSAO->getPeerID());
1546 std::ostringstream os;
1547 playerSAO->getInventory()->serialize(os);
1549 std::string s = os.str();
1551 pkt.putRawString(s.c_str(), s.size());
1555 void Server::SendChatMessage(session_t peer_id, const ChatMessage &message)
1557 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1559 u8 type = message.type;
1560 pkt << version << type << std::wstring(L"") << message.message << (u64)message.timestamp;
1562 if (peer_id != PEER_ID_INEXISTENT) {
1563 RemotePlayer *player = m_env->getPlayer(peer_id);
1569 m_clients.sendToAll(&pkt);
1573 void Server::SendShowFormspecMessage(session_t peer_id, const std::string &formspec,
1574 const std::string &formname)
1576 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1577 if (formspec.empty()){
1578 //the client should close the formspec
1579 //but make sure there wasn't another one open in meantime
1580 const auto it = m_formspec_state_data.find(peer_id);
1581 if (it != m_formspec_state_data.end() && it->second == formname) {
1582 m_formspec_state_data.erase(peer_id);
1584 pkt.putLongString("");
1586 m_formspec_state_data[peer_id] = formname;
1587 pkt.putLongString(FORMSPEC_VERSION_STRING + formspec);
1594 // Spawns a particle on peer with peer_id
1595 void Server::SendSpawnParticle(session_t peer_id, u16 protocol_version,
1596 v3f pos, v3f velocity, v3f acceleration,
1597 float expirationtime, float size, bool collisiondetection,
1598 bool collision_removal, bool object_collision,
1599 bool vertical, const std::string &texture,
1600 const struct TileAnimationParams &animation, u8 glow)
1602 static thread_local const float radius =
1603 g_settings->getS16("max_block_send_distance") * MAP_BLOCKSIZE * BS;
1605 if (peer_id == PEER_ID_INEXISTENT) {
1606 std::vector<session_t> clients = m_clients.getClientIDs();
1608 for (const session_t client_id : clients) {
1609 RemotePlayer *player = m_env->getPlayer(client_id);
1613 PlayerSAO *sao = player->getPlayerSAO();
1617 // Do not send to distant clients
1618 if (sao->getBasePosition().getDistanceFrom(pos * BS) > radius)
1621 SendSpawnParticle(client_id, player->protocol_version,
1622 pos, velocity, acceleration,
1623 expirationtime, size, collisiondetection, collision_removal,
1624 object_collision, vertical, texture, animation, glow);
1629 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1631 pkt << pos << velocity << acceleration << expirationtime
1632 << size << collisiondetection;
1633 pkt.putLongString(texture);
1635 pkt << collision_removal;
1636 // This is horrible but required (why are there two ways to serialize pkts?)
1637 std::ostringstream os(std::ios_base::binary);
1638 animation.serialize(os, protocol_version);
1639 pkt.putRawString(os.str());
1641 pkt << object_collision;
1646 // Adds a ParticleSpawner on peer with peer_id
1647 void Server::SendAddParticleSpawner(session_t peer_id, u16 protocol_version,
1648 u16 amount, float spawntime, v3f minpos, v3f maxpos,
1649 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1650 float minsize, float maxsize, bool collisiondetection, bool collision_removal,
1651 bool object_collision, u16 attached_id, bool vertical, const std::string &texture, u32 id,
1652 const struct TileAnimationParams &animation, u8 glow)
1654 if (peer_id == PEER_ID_INEXISTENT) {
1655 // This sucks and should be replaced:
1656 std::vector<session_t> clients = m_clients.getClientIDs();
1657 for (const session_t client_id : clients) {
1658 RemotePlayer *player = m_env->getPlayer(client_id);
1661 SendAddParticleSpawner(client_id, player->protocol_version,
1662 amount, spawntime, minpos, maxpos,
1663 minvel, maxvel, minacc, maxacc, minexptime, maxexptime,
1664 minsize, maxsize, collisiondetection, collision_removal,
1665 object_collision, attached_id, vertical, texture, id,
1671 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1673 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1674 << minacc << maxacc << minexptime << maxexptime << minsize
1675 << maxsize << collisiondetection;
1677 pkt.putLongString(texture);
1679 pkt << id << vertical;
1680 pkt << collision_removal;
1682 // This is horrible but required
1683 std::ostringstream os(std::ios_base::binary);
1684 animation.serialize(os, protocol_version);
1685 pkt.putRawString(os.str());
1687 pkt << object_collision;
1692 void Server::SendDeleteParticleSpawner(session_t peer_id, u32 id)
1694 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER, 4, peer_id);
1696 // Ugly error in this packet
1699 if (peer_id != PEER_ID_INEXISTENT)
1702 m_clients.sendToAll(&pkt);
1706 void Server::SendHUDAdd(session_t peer_id, u32 id, HudElement *form)
1708 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1710 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1711 << form->text << form->number << form->item << form->dir
1712 << form->align << form->offset << form->world_pos << form->size;
1717 void Server::SendHUDRemove(session_t peer_id, u32 id)
1719 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1724 void Server::SendHUDChange(session_t peer_id, u32 id, HudElementStat stat, void *value)
1726 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1727 pkt << id << (u8) stat;
1731 case HUD_STAT_SCALE:
1732 case HUD_STAT_ALIGN:
1733 case HUD_STAT_OFFSET:
1734 pkt << *(v2f *) value;
1738 pkt << *(std::string *) value;
1740 case HUD_STAT_WORLD_POS:
1741 pkt << *(v3f *) value;
1744 pkt << *(v2s32 *) value;
1746 case HUD_STAT_NUMBER:
1750 pkt << *(u32 *) value;
1757 void Server::SendHUDSetFlags(session_t peer_id, u32 flags, u32 mask)
1759 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1761 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1763 pkt << flags << mask;
1768 void Server::SendHUDSetParam(session_t peer_id, u16 param, const std::string &value)
1770 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1771 pkt << param << value;
1775 void Server::SendSetSky(session_t peer_id, const video::SColor &bgcolor,
1776 const std::string &type, const std::vector<std::string> ¶ms,
1779 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1780 pkt << bgcolor << type << (u16) params.size();
1782 for (const std::string ¶m : params)
1790 void Server::SendCloudParams(session_t peer_id, const CloudParams ¶ms)
1792 NetworkPacket pkt(TOCLIENT_CLOUD_PARAMS, 0, peer_id);
1793 pkt << params.density << params.color_bright << params.color_ambient
1794 << params.height << params.thickness << params.speed;
1798 void Server::SendOverrideDayNightRatio(session_t peer_id, bool do_override,
1801 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1804 pkt << do_override << (u16) (ratio * 65535);
1809 void Server::SendTimeOfDay(session_t peer_id, u16 time, f32 time_speed)
1811 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1812 pkt << time << time_speed;
1814 if (peer_id == PEER_ID_INEXISTENT) {
1815 m_clients.sendToAll(&pkt);
1822 void Server::SendPlayerHP(session_t peer_id)
1824 PlayerSAO *playersao = getPlayerSAO(peer_id);
1825 // In some rare case if the player is disconnected
1826 // while Lua call l_punch, for example, this can be NULL
1830 SendHP(peer_id, playersao->getHP());
1831 m_script->player_event(playersao,"health_changed");
1833 // Send to other clients
1834 std::string str = gob_cmd_punched(playersao->getHP());
1835 ActiveObjectMessage aom(playersao->getId(), true, str);
1836 playersao->m_messages_out.push(aom);
1839 void Server::SendPlayerBreath(PlayerSAO *sao)
1843 m_script->player_event(sao, "breath_changed");
1844 SendBreath(sao->getPeerID(), sao->getBreath());
1847 void Server::SendMovePlayer(session_t peer_id)
1849 RemotePlayer *player = m_env->getPlayer(peer_id);
1851 PlayerSAO *sao = player->getPlayerSAO();
1854 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1855 pkt << sao->getBasePosition() << sao->getLookPitch() << sao->getRotation().Y;
1858 v3f pos = sao->getBasePosition();
1859 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1860 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1861 << " pitch=" << sao->getLookPitch()
1862 << " yaw=" << sao->getRotation().Y
1869 void Server::SendLocalPlayerAnimations(session_t peer_id, v2s32 animation_frames[4],
1870 f32 animation_speed)
1872 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1875 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1876 << animation_frames[3] << animation_speed;
1881 void Server::SendEyeOffset(session_t peer_id, v3f first, v3f third)
1883 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1884 pkt << first << third;
1888 void Server::SendPlayerPrivileges(session_t peer_id)
1890 RemotePlayer *player = m_env->getPlayer(peer_id);
1892 if(player->getPeerId() == PEER_ID_INEXISTENT)
1895 std::set<std::string> privs;
1896 m_script->getAuth(player->getName(), NULL, &privs);
1898 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1899 pkt << (u16) privs.size();
1901 for (const std::string &priv : privs) {
1908 void Server::SendPlayerInventoryFormspec(session_t peer_id)
1910 RemotePlayer *player = m_env->getPlayer(peer_id);
1912 if (player->getPeerId() == PEER_ID_INEXISTENT)
1915 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1916 pkt.putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
1920 void Server::SendPlayerFormspecPrepend(session_t peer_id)
1922 RemotePlayer *player = m_env->getPlayer(peer_id);
1924 if (player->getPeerId() == PEER_ID_INEXISTENT)
1927 NetworkPacket pkt(TOCLIENT_FORMSPEC_PREPEND, 0, peer_id);
1928 pkt << FORMSPEC_VERSION_STRING + player->formspec_prepend;
1932 u32 Server::SendActiveObjectRemoveAdd(session_t peer_id, const std::string &datas)
1934 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, datas.size(), peer_id);
1935 pkt.putRawString(datas.c_str(), datas.size());
1937 return pkt.getSize();
1940 void Server::SendActiveObjectMessages(session_t peer_id, const std::string &datas,
1943 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
1944 datas.size(), peer_id);
1946 pkt.putRawString(datas.c_str(), datas.size());
1948 m_clients.send(pkt.getPeerId(),
1949 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
1953 void Server::SendCSMRestrictionFlags(session_t peer_id)
1955 NetworkPacket pkt(TOCLIENT_CSM_RESTRICTION_FLAGS,
1956 sizeof(m_csm_restriction_flags) + sizeof(m_csm_restriction_noderange), peer_id);
1957 pkt << m_csm_restriction_flags << m_csm_restriction_noderange;
1961 s32 Server::playSound(const SimpleSoundSpec &spec,
1962 const ServerSoundParams ¶ms)
1964 // Find out initial position of sound
1965 bool pos_exists = false;
1966 v3f pos = params.getPos(m_env, &pos_exists);
1967 // If position is not found while it should be, cancel sound
1968 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
1971 // Filter destination clients
1972 std::vector<session_t> dst_clients;
1973 if(!params.to_player.empty()) {
1974 RemotePlayer *player = m_env->getPlayer(params.to_player.c_str());
1976 infostream<<"Server::playSound: Player \""<<params.to_player
1977 <<"\" not found"<<std::endl;
1980 if (player->getPeerId() == PEER_ID_INEXISTENT) {
1981 infostream<<"Server::playSound: Player \""<<params.to_player
1982 <<"\" not connected"<<std::endl;
1985 dst_clients.push_back(player->getPeerId());
1987 std::vector<session_t> clients = m_clients.getClientIDs();
1989 for (const session_t client_id : clients) {
1990 RemotePlayer *player = m_env->getPlayer(client_id);
1994 PlayerSAO *sao = player->getPlayerSAO();
1999 if(sao->getBasePosition().getDistanceFrom(pos) >
2000 params.max_hear_distance)
2003 dst_clients.push_back(client_id);
2007 if(dst_clients.empty())
2011 s32 id = m_next_sound_id++;
2012 // The sound will exist as a reference in m_playing_sounds
2013 m_playing_sounds[id] = ServerPlayingSound();
2014 ServerPlayingSound &psound = m_playing_sounds[id];
2015 psound.params = params;
2018 float gain = params.gain * spec.gain;
2019 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2020 pkt << id << spec.name << gain
2021 << (u8) params.type << pos << params.object
2022 << params.loop << params.fade << params.pitch;
2024 // Backwards compability
2025 bool play_sound = gain > 0;
2027 for (const u16 dst_client : dst_clients) {
2028 if (play_sound || m_clients.getProtocolVersion(dst_client) >= 32) {
2029 psound.clients.insert(dst_client);
2030 m_clients.send(dst_client, 0, &pkt, true);
2035 void Server::stopSound(s32 handle)
2037 // Get sound reference
2038 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2039 m_playing_sounds.find(handle);
2040 if (i == m_playing_sounds.end())
2042 ServerPlayingSound &psound = i->second;
2044 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2047 for (std::unordered_set<session_t>::const_iterator si = psound.clients.begin();
2048 si != psound.clients.end(); ++si) {
2050 m_clients.send(*si, 0, &pkt, true);
2052 // Remove sound reference
2053 m_playing_sounds.erase(i);
2056 void Server::fadeSound(s32 handle, float step, float gain)
2058 // Get sound reference
2059 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2060 m_playing_sounds.find(handle);
2061 if (i == m_playing_sounds.end())
2064 ServerPlayingSound &psound = i->second;
2065 psound.params.gain = gain;
2067 NetworkPacket pkt(TOCLIENT_FADE_SOUND, 4);
2068 pkt << handle << step << gain;
2070 // Backwards compability
2071 bool play_sound = gain > 0;
2072 ServerPlayingSound compat_psound = psound;
2073 compat_psound.clients.clear();
2075 NetworkPacket compat_pkt(TOCLIENT_STOP_SOUND, 4);
2076 compat_pkt << handle;
2078 for (std::unordered_set<u16>::iterator it = psound.clients.begin();
2079 it != psound.clients.end();) {
2080 if (m_clients.getProtocolVersion(*it) >= 32) {
2082 m_clients.send(*it, 0, &pkt, true);
2085 compat_psound.clients.insert(*it);
2087 m_clients.send(*it, 0, &compat_pkt, true);
2088 psound.clients.erase(it++);
2092 // Remove sound reference
2093 if (!play_sound || psound.clients.empty())
2094 m_playing_sounds.erase(i);
2096 if (play_sound && !compat_psound.clients.empty()) {
2097 // Play new sound volume on older clients
2098 playSound(compat_psound.spec, compat_psound.params);
2102 void Server::sendRemoveNode(v3s16 p, std::unordered_set<u16> *far_players,
2105 float maxd = far_d_nodes * BS;
2106 v3f p_f = intToFloat(p, BS);
2107 v3s16 block_pos = getNodeBlockPos(p);
2109 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2112 std::vector<session_t> clients = m_clients.getClientIDs();
2115 for (session_t client_id : clients) {
2116 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
2120 RemotePlayer *player = m_env->getPlayer(client_id);
2121 PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr;
2123 // If player is far away, only set modified blocks not sent
2124 if (!client->isBlockSent(block_pos) || (sao &&
2125 sao->getBasePosition().getDistanceFrom(p_f) > maxd)) {
2127 far_players->emplace(client_id);
2129 client->SetBlockNotSent(block_pos);
2134 m_clients.send(client_id, 0, &pkt, true);
2140 void Server::sendAddNode(v3s16 p, MapNode n, std::unordered_set<u16> *far_players,
2141 float far_d_nodes, bool remove_metadata)
2143 float maxd = far_d_nodes * BS;
2144 v3f p_f = intToFloat(p, BS);
2145 v3s16 block_pos = getNodeBlockPos(p);
2147 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2148 pkt << p << n.param0 << n.param1 << n.param2
2149 << (u8) (remove_metadata ? 0 : 1);
2151 std::vector<session_t> clients = m_clients.getClientIDs();
2154 for (session_t client_id : clients) {
2155 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
2159 RemotePlayer *player = m_env->getPlayer(client_id);
2160 PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr;
2162 // If player is far away, only set modified blocks not sent
2163 if (!client->isBlockSent(block_pos) || (sao &&
2164 sao->getBasePosition().getDistanceFrom(p_f) > maxd)) {
2166 far_players->emplace(client_id);
2168 client->SetBlockNotSent(block_pos);
2173 m_clients.send(client_id, 0, &pkt, true);
2179 void Server::sendMetadataChanged(const std::list<v3s16> &meta_updates, float far_d_nodes)
2181 float maxd = far_d_nodes * BS;
2182 NodeMetadataList meta_updates_list(false);
2183 std::vector<session_t> clients = m_clients.getClientIDs();
2187 for (session_t i : clients) {
2188 RemoteClient *client = m_clients.lockedGetClientNoEx(i);
2192 ServerActiveObject *player = m_env->getActiveObject(i);
2193 v3f player_pos = player ? player->getBasePosition() : v3f();
2195 for (const v3s16 &pos : meta_updates) {
2196 NodeMetadata *meta = m_env->getMap().getNodeMetadata(pos);
2201 v3s16 block_pos = getNodeBlockPos(pos);
2202 if (!client->isBlockSent(block_pos) || (player &&
2203 player_pos.getDistanceFrom(intToFloat(pos, BS)) > maxd)) {
2204 client->SetBlockNotSent(block_pos);
2208 // Add the change to send list
2209 meta_updates_list.set(pos, meta);
2211 if (meta_updates_list.size() == 0)
2214 // Send the meta changes
2215 std::ostringstream os(std::ios::binary);
2216 meta_updates_list.serialize(os, client->net_proto_version, false, true);
2217 std::ostringstream oss(std::ios::binary);
2218 compressZlib(os.str(), oss);
2220 NetworkPacket pkt(TOCLIENT_NODEMETA_CHANGED, 0);
2221 pkt.putLongString(oss.str());
2222 m_clients.send(i, 0, &pkt, true);
2224 meta_updates_list.clear();
2230 void Server::SendBlockNoLock(session_t peer_id, MapBlock *block, u8 ver,
2231 u16 net_proto_version)
2234 Create a packet with the block in the right format
2237 std::ostringstream os(std::ios_base::binary);
2238 block->serialize(os, ver, false);
2239 block->serializeNetworkSpecific(os);
2240 std::string s = os.str();
2242 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2244 pkt << block->getPos();
2245 pkt.putRawString(s.c_str(), s.size());
2249 void Server::SendBlocks(float dtime)
2251 MutexAutoLock envlock(m_env_mutex);
2252 //TODO check if one big lock could be faster then multiple small ones
2254 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
2256 std::vector<PrioritySortedBlockTransfer> queue;
2258 u32 total_sending = 0;
2261 ScopeProfiler sp2(g_profiler, "Server: selecting blocks for sending");
2263 std::vector<session_t> clients = m_clients.getClientIDs();
2266 for (const session_t client_id : clients) {
2267 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id, CS_Active);
2272 total_sending += client->getSendingCount();
2273 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2279 // Lowest priority number comes first.
2280 // Lowest is most important.
2281 std::sort(queue.begin(), queue.end());
2285 // Maximal total count calculation
2286 // The per-client block sends is halved with the maximal online users
2287 u32 max_blocks_to_send = (m_env->getPlayerCount() + g_settings->getU32("max_users")) *
2288 g_settings->getU32("max_simultaneous_block_sends_per_client") / 4 + 1;
2290 for (const PrioritySortedBlockTransfer &block_to_send : queue) {
2291 if (total_sending >= max_blocks_to_send)
2294 MapBlock *block = nullptr;
2296 block = m_env->getMap().getBlockNoCreate(block_to_send.pos);
2297 } catch (const InvalidPositionException &e) {
2301 RemoteClient *client = m_clients.lockedGetClientNoEx(block_to_send.peer_id,
2306 SendBlockNoLock(block_to_send.peer_id, block, client->serialization_version,
2307 client->net_proto_version);
2309 client->SentBlock(block_to_send.pos);
2315 void Server::fillMediaCache()
2317 infostream<<"Server: Calculating media file checksums"<<std::endl;
2319 // Collect all media file paths
2320 std::vector<std::string> paths;
2321 m_modmgr->getModsMediaPaths(paths);
2322 fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures");
2323 fs::GetRecursiveDirs(paths, porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2325 // Collect media file information from paths into cache
2326 for (const std::string &mediapath : paths) {
2327 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2328 for (const fs::DirListNode &dln : dirlist) {
2329 if (dln.dir) // Ignode dirs
2331 std::string filename = dln.name;
2332 // If name contains illegal characters, ignore the file
2333 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2334 infostream<<"Server: ignoring illegal file name: \""
2335 << filename << "\"" << std::endl;
2338 // If name is not in a supported format, ignore it
2339 const char *supported_ext[] = {
2340 ".png", ".jpg", ".bmp", ".tga",
2341 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2343 ".x", ".b3d", ".md2", ".obj",
2344 // Custom translation file format
2348 if (removeStringEnd(filename, supported_ext).empty()){
2349 infostream << "Server: ignoring unsupported file extension: \""
2350 << filename << "\"" << std::endl;
2353 // Ok, attempt to load the file and add to cache
2354 std::string filepath;
2355 filepath.append(mediapath).append(DIR_DELIM).append(filename);
2358 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2360 errorstream << "Server::fillMediaCache(): Could not open \""
2361 << filename << "\" for reading" << std::endl;
2364 std::ostringstream tmp_os(std::ios_base::binary);
2368 fis.read(buf, 1024);
2369 std::streamsize len = fis.gcount();
2370 tmp_os.write(buf, len);
2379 errorstream<<"Server::fillMediaCache(): Failed to read \""
2380 << filename << "\"" << std::endl;
2383 if(tmp_os.str().length() == 0) {
2384 errorstream << "Server::fillMediaCache(): Empty file \""
2385 << filepath << "\"" << std::endl;
2390 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2392 unsigned char *digest = sha1.getDigest();
2393 std::string sha1_base64 = base64_encode(digest, 20);
2394 std::string sha1_hex = hex_encode((char*)digest, 20);
2398 m_media[filename] = MediaInfo(filepath, sha1_base64);
2399 verbosestream << "Server: " << sha1_hex << " is " << filename
2405 void Server::sendMediaAnnouncement(session_t peer_id, const std::string &lang_code)
2407 verbosestream << "Server: Announcing files to id(" << peer_id << ")"
2411 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2414 std::string lang_suffix;
2415 lang_suffix.append(".").append(lang_code).append(".tr");
2416 for (const auto &i : m_media) {
2417 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2424 for (const auto &i : m_media) {
2425 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2427 pkt << i.first << i.second.sha1_digest;
2430 pkt << g_settings->get("remote_media");
2434 struct SendableMedia
2440 SendableMedia(const std::string &name_="", const std::string &path_="",
2441 const std::string &data_=""):
2448 void Server::sendRequestedMedia(session_t peer_id,
2449 const std::vector<std::string> &tosend)
2451 verbosestream<<"Server::sendRequestedMedia(): "
2452 <<"Sending files to client"<<std::endl;
2456 // Put 5kB in one bunch (this is not accurate)
2457 u32 bytes_per_bunch = 5000;
2459 std::vector< std::vector<SendableMedia> > file_bunches;
2460 file_bunches.emplace_back();
2462 u32 file_size_bunch_total = 0;
2464 for (const std::string &name : tosend) {
2465 if (m_media.find(name) == m_media.end()) {
2466 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2467 <<"unknown file \""<<(name)<<"\""<<std::endl;
2471 //TODO get path + name
2472 std::string tpath = m_media[name].path;
2475 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2477 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2478 <<tpath<<"\" for reading"<<std::endl;
2481 std::ostringstream tmp_os(std::ios_base::binary);
2485 fis.read(buf, 1024);
2486 std::streamsize len = fis.gcount();
2487 tmp_os.write(buf, len);
2488 file_size_bunch_total += len;
2497 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2498 <<name<<"\""<<std::endl;
2501 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2502 <<tname<<"\""<<std::endl;*/
2504 file_bunches[file_bunches.size()-1].emplace_back(name, tpath, tmp_os.str());
2506 // Start next bunch if got enough data
2507 if(file_size_bunch_total >= bytes_per_bunch) {
2508 file_bunches.emplace_back();
2509 file_size_bunch_total = 0;
2514 /* Create and send packets */
2516 u16 num_bunches = file_bunches.size();
2517 for (u16 i = 0; i < num_bunches; i++) {
2520 u16 total number of texture bunches
2521 u16 index of this bunch
2522 u32 number of files in this bunch
2531 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2532 pkt << num_bunches << i << (u32) file_bunches[i].size();
2534 for (const SendableMedia &j : file_bunches[i]) {
2536 pkt.putLongString(j.data);
2539 verbosestream << "Server::sendRequestedMedia(): bunch "
2540 << i << "/" << num_bunches
2541 << " files=" << file_bunches[i].size()
2542 << " size=" << pkt.getSize() << std::endl;
2547 void Server::sendDetachedInventory(const std::string &name, session_t peer_id)
2549 const auto &inv_it = m_detached_inventories.find(name);
2550 const auto &player_it = m_detached_inventories_player.find(name);
2552 if (player_it == m_detached_inventories_player.end() ||
2553 player_it->second.empty()) {
2554 // OK. Send to everyone
2556 RemotePlayer *p = m_env->getPlayer(player_it->second.c_str());
2558 return; // Player is offline
2560 if (peer_id != PEER_ID_INEXISTENT && peer_id != p->getPeerId())
2561 return; // Caller requested send to a different player, so don't send.
2563 peer_id = p->getPeerId();
2566 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2569 if (inv_it == m_detached_inventories.end()) {
2570 pkt << false; // Remove inventory
2572 pkt << true; // Update inventory
2574 // Serialization & NetworkPacket isn't a love story
2575 std::ostringstream os(std::ios_base::binary);
2576 inv_it->second->serialize(os);
2578 std::string os_str = os.str();
2579 pkt << static_cast<u16>(os_str.size()); // HACK: to keep compatibility with 5.0.0 clients
2580 pkt.putRawString(os_str);
2583 if (peer_id == PEER_ID_INEXISTENT)
2584 m_clients.sendToAll(&pkt);
2589 void Server::sendDetachedInventories(session_t peer_id)
2591 for (const auto &detached_inventory : m_detached_inventories) {
2592 const std::string &name = detached_inventory.first;
2593 //Inventory *inv = i->second;
2594 sendDetachedInventory(name, peer_id);
2602 void Server::DiePlayer(session_t peer_id, const PlayerHPChangeReason &reason)
2604 PlayerSAO *playersao = getPlayerSAO(peer_id);
2605 // In some rare cases this can be NULL -- if the player is disconnected
2606 // when a Lua function modifies l_punch, for example
2610 infostream << "Server::DiePlayer(): Player "
2611 << playersao->getPlayer()->getName()
2612 << " dies" << std::endl;
2614 playersao->setHP(0, reason);
2615 playersao->clearParentAttachment();
2617 // Trigger scripted stuff
2618 m_script->on_dieplayer(playersao, reason);
2620 SendPlayerHP(peer_id);
2621 SendDeathscreen(peer_id, false, v3f(0,0,0));
2624 void Server::RespawnPlayer(session_t peer_id)
2626 PlayerSAO *playersao = getPlayerSAO(peer_id);
2629 infostream << "Server::RespawnPlayer(): Player "
2630 << playersao->getPlayer()->getName()
2631 << " respawns" << std::endl;
2633 playersao->setHP(playersao->accessObjectProperties()->hp_max,
2634 PlayerHPChangeReason(PlayerHPChangeReason::RESPAWN));
2635 playersao->setBreath(playersao->accessObjectProperties()->breath_max);
2637 bool repositioned = m_script->on_respawnplayer(playersao);
2638 if (!repositioned) {
2639 // setPos will send the new position to client
2640 playersao->setPos(findSpawnPos());
2643 SendPlayerHP(peer_id);
2647 void Server::DenySudoAccess(session_t peer_id)
2649 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2654 void Server::DenyAccessVerCompliant(session_t peer_id, u16 proto_ver, AccessDeniedCode reason,
2655 const std::string &str_reason, bool reconnect)
2657 SendAccessDenied(peer_id, reason, str_reason, reconnect);
2659 m_clients.event(peer_id, CSE_SetDenied);
2660 DisconnectPeer(peer_id);
2664 void Server::DenyAccess(session_t peer_id, AccessDeniedCode reason,
2665 const std::string &custom_reason)
2667 SendAccessDenied(peer_id, reason, custom_reason);
2668 m_clients.event(peer_id, CSE_SetDenied);
2669 DisconnectPeer(peer_id);
2672 // 13/03/15: remove this function when protocol version 25 will become
2673 // the minimum version for MT users, maybe in 1 year
2674 void Server::DenyAccess_Legacy(session_t peer_id, const std::wstring &reason)
2676 SendAccessDenied_Legacy(peer_id, reason);
2677 m_clients.event(peer_id, CSE_SetDenied);
2678 DisconnectPeer(peer_id);
2681 void Server::DisconnectPeer(session_t peer_id)
2683 m_modchannel_mgr->leaveAllChannels(peer_id);
2684 m_con->DisconnectPeer(peer_id);
2687 void Server::acceptAuth(session_t peer_id, bool forSudoMode)
2690 RemoteClient* client = getClient(peer_id, CS_Invalid);
2692 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2694 // Right now, the auth mechs don't change between login and sudo mode.
2695 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2696 client->allowed_sudo_mechs = sudo_auth_mechs;
2698 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2699 << g_settings->getFloat("dedicated_server_step")
2703 m_clients.event(peer_id, CSE_AuthAccept);
2705 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2707 // We only support SRP right now
2708 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2710 resp_pkt << sudo_auth_mechs;
2712 m_clients.event(peer_id, CSE_SudoSuccess);
2716 void Server::DeleteClient(session_t peer_id, ClientDeletionReason reason)
2718 std::wstring message;
2721 Clear references to playing sounds
2723 for (std::unordered_map<s32, ServerPlayingSound>::iterator
2724 i = m_playing_sounds.begin(); i != m_playing_sounds.end();) {
2725 ServerPlayingSound &psound = i->second;
2726 psound.clients.erase(peer_id);
2727 if (psound.clients.empty())
2728 m_playing_sounds.erase(i++);
2733 // clear formspec info so the next client can't abuse the current state
2734 m_formspec_state_data.erase(peer_id);
2736 RemotePlayer *player = m_env->getPlayer(peer_id);
2738 /* Run scripts and remove from environment */
2740 PlayerSAO *playersao = player->getPlayerSAO();
2743 playersao->clearChildAttachments();
2744 playersao->clearParentAttachment();
2746 // inform connected clients
2747 const std::string &player_name = player->getName();
2748 NetworkPacket notice(TOCLIENT_UPDATE_PLAYER_LIST, 0, PEER_ID_INEXISTENT);
2749 // (u16) 1 + std::string represents a vector serialization representation
2750 notice << (u8) PLAYER_LIST_REMOVE << (u16) 1 << player_name;
2751 m_clients.sendToAll(¬ice);
2753 m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
2755 playersao->disconnected();
2762 if (player && reason != CDR_DENY) {
2763 std::ostringstream os(std::ios_base::binary);
2764 std::vector<session_t> clients = m_clients.getClientIDs();
2766 for (const session_t client_id : clients) {
2768 RemotePlayer *player = m_env->getPlayer(client_id);
2772 // Get name of player
2773 os << player->getName() << " ";
2776 std::string name = player->getName();
2777 actionstream << name << " "
2778 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2779 << " List of players: " << os.str() << std::endl;
2781 m_admin_chat->outgoing_queue.push_back(
2782 new ChatEventNick(CET_NICK_REMOVE, name));
2786 MutexAutoLock env_lock(m_env_mutex);
2787 m_clients.DeleteClient(peer_id);
2791 // Send leave chat message to all remaining clients
2792 if (!message.empty()) {
2793 SendChatMessage(PEER_ID_INEXISTENT,
2794 ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE, message));
2798 void Server::UpdateCrafting(RemotePlayer *player)
2800 InventoryList *clist = player->inventory.getList("craft");
2801 if (!clist || clist->getSize() == 0)
2804 // Get a preview for crafting
2806 InventoryLocation loc;
2807 loc.setPlayer(player->getName());
2808 std::vector<ItemStack> output_replacements;
2809 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2810 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(),
2813 InventoryList *plist = player->inventory.getList("craftpreview");
2814 if (plist && plist->getSize() >= 1) {
2815 // Put the new preview in
2816 plist->changeItem(0, preview);
2820 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2822 if (evt->type == CET_NICK_ADD) {
2823 // The terminal informed us of its nick choice
2824 m_admin_nick = ((ChatEventNick *)evt)->nick;
2825 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2826 errorstream << "You haven't set up an account." << std::endl
2827 << "Please log in using the client as '"
2828 << m_admin_nick << "' with a secure password." << std::endl
2829 << "Until then, you can't execute admin tasks via the console," << std::endl
2830 << "and everybody can claim the user account instead of you," << std::endl
2831 << "giving them full control over this server." << std::endl;
2834 assert(evt->type == CET_CHAT);
2835 handleAdminChat((ChatEventChat *)evt);
2839 std::wstring Server::handleChat(const std::string &name, const std::wstring &wname,
2840 std::wstring wmessage, bool check_shout_priv, RemotePlayer *player)
2842 // If something goes wrong, this player is to blame
2843 RollbackScopeActor rollback_scope(m_rollback,
2844 std::string("player:") + name);
2846 if (g_settings->getBool("strip_color_codes"))
2847 wmessage = unescape_enriched(wmessage);
2850 switch (player->canSendChatMessage()) {
2851 case RPLAYER_CHATRESULT_FLOODING: {
2852 std::wstringstream ws;
2853 ws << L"You cannot send more messages. You are limited to "
2854 << g_settings->getFloat("chat_message_limit_per_10sec")
2855 << L" messages per 10 seconds.";
2858 case RPLAYER_CHATRESULT_KICK:
2859 DenyAccess_Legacy(player->getPeerId(),
2860 L"You have been kicked due to message flooding.");
2862 case RPLAYER_CHATRESULT_OK:
2865 FATAL_ERROR("Unhandled chat filtering result found.");
2869 if (m_max_chatmessage_length > 0
2870 && wmessage.length() > m_max_chatmessage_length) {
2871 return L"Your message exceed the maximum chat message limit set on the server. "
2872 L"It was refused. Send a shorter message";
2875 auto message = trim(wide_to_utf8(wmessage));
2876 if (message.find_first_of("\n\r") != std::wstring::npos) {
2877 return L"New lines are not permitted in chat messages";
2880 // Run script hook, exit if script ate the chat message
2881 if (m_script->on_chat_message(name, message))
2886 // Whether to send line to the player that sent the message, or to all players
2887 bool broadcast_line = true;
2889 if (check_shout_priv && !checkPriv(name, "shout")) {
2890 line += L"-!- You don't have permission to shout.";
2891 broadcast_line = false;
2900 Tell calling method to send the message to sender
2902 if (!broadcast_line)
2906 Send the message to others
2908 actionstream << "CHAT: " << wide_to_narrow(unescape_enriched(line)) << std::endl;
2910 std::vector<session_t> clients = m_clients.getClientIDs();
2913 Send the message back to the inital sender
2914 if they are using protocol version >= 29
2917 session_t peer_id_to_avoid_sending =
2918 (player ? player->getPeerId() : PEER_ID_INEXISTENT);
2920 if (player && player->protocol_version >= 29)
2921 peer_id_to_avoid_sending = PEER_ID_INEXISTENT;
2923 for (u16 cid : clients) {
2924 if (cid != peer_id_to_avoid_sending)
2925 SendChatMessage(cid, ChatMessage(line));
2930 void Server::handleAdminChat(const ChatEventChat *evt)
2932 std::string name = evt->nick;
2933 std::wstring wname = utf8_to_wide(name);
2934 std::wstring wmessage = evt->evt_msg;
2936 std::wstring answer = handleChat(name, wname, wmessage);
2938 // If asked to send answer to sender
2939 if (!answer.empty()) {
2940 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
2944 RemoteClient *Server::getClient(session_t peer_id, ClientState state_min)
2946 RemoteClient *client = getClientNoEx(peer_id,state_min);
2948 throw ClientNotFoundException("Client not found");
2952 RemoteClient *Server::getClientNoEx(session_t peer_id, ClientState state_min)
2954 return m_clients.getClientNoEx(peer_id, state_min);
2957 std::string Server::getPlayerName(session_t peer_id)
2959 RemotePlayer *player = m_env->getPlayer(peer_id);
2961 return "[id="+itos(peer_id)+"]";
2962 return player->getName();
2965 PlayerSAO *Server::getPlayerSAO(session_t peer_id)
2967 RemotePlayer *player = m_env->getPlayer(peer_id);
2970 return player->getPlayerSAO();
2973 std::wstring Server::getStatusString()
2975 std::wostringstream os(std::ios_base::binary);
2976 os << L"# Server: ";
2978 os << L"version=" << narrow_to_wide(g_version_string);
2980 os << L", uptime=" << m_uptime.get();
2982 os << L", max_lag=" << (m_env ? m_env->getMaxLagEstimate() : 0);
2984 // Information about clients
2986 os << L", clients={";
2988 std::vector<session_t> clients = m_clients.getClientIDs();
2989 for (session_t client_id : clients) {
2990 RemotePlayer *player = m_env->getPlayer(client_id);
2992 // Get name of player
2993 std::wstring name = L"unknown";
2995 name = narrow_to_wide(player->getName());
2997 // Add name to information string
3008 if (m_env && !((ServerMap*)(&m_env->getMap()))->isSavingEnabled())
3009 os << std::endl << L"# Server: " << " WARNING: Map saving is disabled.";
3011 if (!g_settings->get("motd").empty())
3012 os << std::endl << L"# Server: " << narrow_to_wide(g_settings->get("motd"));
3017 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
3019 std::set<std::string> privs;
3020 m_script->getAuth(name, NULL, &privs);
3024 bool Server::checkPriv(const std::string &name, const std::string &priv)
3026 std::set<std::string> privs = getPlayerEffectivePrivs(name);
3027 return (privs.count(priv) != 0);
3030 void Server::reportPrivsModified(const std::string &name)
3033 std::vector<session_t> clients = m_clients.getClientIDs();
3034 for (const session_t client_id : clients) {
3035 RemotePlayer *player = m_env->getPlayer(client_id);
3036 reportPrivsModified(player->getName());
3039 RemotePlayer *player = m_env->getPlayer(name.c_str());
3042 SendPlayerPrivileges(player->getPeerId());
3043 PlayerSAO *sao = player->getPlayerSAO();
3046 sao->updatePrivileges(
3047 getPlayerEffectivePrivs(name),
3052 void Server::reportInventoryFormspecModified(const std::string &name)
3054 RemotePlayer *player = m_env->getPlayer(name.c_str());
3057 SendPlayerInventoryFormspec(player->getPeerId());
3060 void Server::reportFormspecPrependModified(const std::string &name)
3062 RemotePlayer *player = m_env->getPlayer(name.c_str());
3065 SendPlayerFormspecPrepend(player->getPeerId());
3068 void Server::setIpBanned(const std::string &ip, const std::string &name)
3070 m_banmanager->add(ip, name);
3073 void Server::unsetIpBanned(const std::string &ip_or_name)
3075 m_banmanager->remove(ip_or_name);
3078 std::string Server::getBanDescription(const std::string &ip_or_name)
3080 return m_banmanager->getBanDescription(ip_or_name);
3083 void Server::notifyPlayer(const char *name, const std::wstring &msg)
3085 // m_env will be NULL if the server is initializing
3089 if (m_admin_nick == name && !m_admin_nick.empty()) {
3090 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
3093 RemotePlayer *player = m_env->getPlayer(name);
3098 if (player->getPeerId() == PEER_ID_INEXISTENT)
3101 SendChatMessage(player->getPeerId(), ChatMessage(msg));
3104 bool Server::showFormspec(const char *playername, const std::string &formspec,
3105 const std::string &formname)
3107 // m_env will be NULL if the server is initializing
3111 RemotePlayer *player = m_env->getPlayer(playername);
3115 SendShowFormspecMessage(player->getPeerId(), formspec, formname);
3119 u32 Server::hudAdd(RemotePlayer *player, HudElement *form)
3124 u32 id = player->addHud(form);
3126 SendHUDAdd(player->getPeerId(), id, form);
3131 bool Server::hudRemove(RemotePlayer *player, u32 id) {
3135 HudElement* todel = player->removeHud(id);
3142 SendHUDRemove(player->getPeerId(), id);
3146 bool Server::hudChange(RemotePlayer *player, u32 id, HudElementStat stat, void *data)
3151 SendHUDChange(player->getPeerId(), id, stat, data);
3155 bool Server::hudSetFlags(RemotePlayer *player, u32 flags, u32 mask)
3160 SendHUDSetFlags(player->getPeerId(), flags, mask);
3161 player->hud_flags &= ~mask;
3162 player->hud_flags |= flags;
3164 PlayerSAO* playersao = player->getPlayerSAO();
3169 m_script->player_event(playersao, "hud_changed");
3173 bool Server::hudSetHotbarItemcount(RemotePlayer *player, s32 hotbar_itemcount)
3178 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3181 player->setHotbarItemcount(hotbar_itemcount);
3182 std::ostringstream os(std::ios::binary);
3183 writeS32(os, hotbar_itemcount);
3184 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3188 void Server::hudSetHotbarImage(RemotePlayer *player, std::string name)
3193 player->setHotbarImage(name);
3194 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_IMAGE, name);
3197 void Server::hudSetHotbarSelectedImage(RemotePlayer *player, std::string name)
3202 player->setHotbarSelectedImage(name);
3203 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3206 Address Server::getPeerAddress(session_t peer_id)
3208 return m_con->GetPeerAddress(peer_id);
3211 void Server::setLocalPlayerAnimations(RemotePlayer *player,
3212 v2s32 animation_frames[4], f32 frame_speed)
3214 sanity_check(player);
3215 player->setLocalAnimations(animation_frames, frame_speed);
3216 SendLocalPlayerAnimations(player->getPeerId(), animation_frames, frame_speed);
3219 void Server::setPlayerEyeOffset(RemotePlayer *player, const v3f &first, const v3f &third)
3221 sanity_check(player);
3222 player->eye_offset_first = first;
3223 player->eye_offset_third = third;
3224 SendEyeOffset(player->getPeerId(), first, third);
3227 void Server::setSky(RemotePlayer *player, const video::SColor &bgcolor,
3228 const std::string &type, const std::vector<std::string> ¶ms,
3231 sanity_check(player);
3232 player->setSky(bgcolor, type, params, clouds);
3233 SendSetSky(player->getPeerId(), bgcolor, type, params, clouds);
3236 void Server::setClouds(RemotePlayer *player, const CloudParams ¶ms)
3238 sanity_check(player);
3239 player->setCloudParams(params);
3240 SendCloudParams(player->getPeerId(), params);
3243 bool Server::overrideDayNightRatio(RemotePlayer *player, bool do_override,
3249 player->overrideDayNightRatio(do_override, ratio);
3250 SendOverrideDayNightRatio(player->getPeerId(), do_override, ratio);
3254 void Server::notifyPlayers(const std::wstring &msg)
3256 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(msg));
3259 void Server::spawnParticle(const std::string &playername, v3f pos,
3260 v3f velocity, v3f acceleration,
3261 float expirationtime, float size, bool
3262 collisiondetection, bool collision_removal, bool object_collision,
3263 bool vertical, const std::string &texture,
3264 const struct TileAnimationParams &animation, u8 glow)
3266 // m_env will be NULL if the server is initializing
3270 session_t peer_id = PEER_ID_INEXISTENT;
3272 if (!playername.empty()) {
3273 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3276 peer_id = player->getPeerId();
3277 proto_ver = player->protocol_version;
3280 SendSpawnParticle(peer_id, proto_ver, pos, velocity, acceleration,
3281 expirationtime, size, collisiondetection, collision_removal,
3282 object_collision, vertical, texture, animation, glow);
3285 u32 Server::addParticleSpawner(u16 amount, float spawntime,
3286 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
3287 float minexptime, float maxexptime, float minsize, float maxsize,
3288 bool collisiondetection, bool collision_removal, bool object_collision,
3289 ServerActiveObject *attached, bool vertical, const std::string &texture,
3290 const std::string &playername, const struct TileAnimationParams &animation,
3293 // m_env will be NULL if the server is initializing
3297 session_t peer_id = PEER_ID_INEXISTENT;
3299 if (!playername.empty()) {
3300 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3303 peer_id = player->getPeerId();
3304 proto_ver = player->protocol_version;
3307 u16 attached_id = attached ? attached->getId() : 0;
3310 if (attached_id == 0)
3311 id = m_env->addParticleSpawner(spawntime);
3313 id = m_env->addParticleSpawner(spawntime, attached_id);
3315 SendAddParticleSpawner(peer_id, proto_ver, amount, spawntime,
3316 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3317 minexptime, maxexptime, minsize, maxsize, collisiondetection,
3318 collision_removal, object_collision, attached_id, vertical,
3319 texture, id, animation, glow);
3324 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3326 // m_env will be NULL if the server is initializing
3328 throw ServerError("Can't delete particle spawners during initialisation!");
3330 session_t peer_id = PEER_ID_INEXISTENT;
3331 if (!playername.empty()) {
3332 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3335 peer_id = player->getPeerId();
3338 m_env->deleteParticleSpawner(id);
3339 SendDeleteParticleSpawner(peer_id, id);
3342 Inventory* Server::createDetachedInventory(const std::string &name, const std::string &player)
3344 if(m_detached_inventories.count(name) > 0){
3345 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3346 delete m_detached_inventories[name];
3348 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3350 Inventory *inv = new Inventory(m_itemdef);
3352 m_detached_inventories[name] = inv;
3353 m_detached_inventories_player[name] = player;
3354 //TODO find a better way to do this
3355 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3359 bool Server::removeDetachedInventory(const std::string &name)
3361 const auto &inv_it = m_detached_inventories.find(name);
3362 if (inv_it == m_detached_inventories.end())
3365 delete inv_it->second;
3366 m_detached_inventories.erase(inv_it);
3368 const auto &player_it = m_detached_inventories_player.find(name);
3369 if (player_it != m_detached_inventories_player.end()) {
3370 RemotePlayer *player = m_env->getPlayer(player_it->second.c_str());
3372 if (player && player->getPeerId() != PEER_ID_INEXISTENT)
3373 sendDetachedInventory(name, player->getPeerId());
3375 m_detached_inventories_player.erase(player_it);
3377 // Notify all players about the change
3378 sendDetachedInventory(name, PEER_ID_INEXISTENT);
3383 // actions: time-reversed list
3384 // Return value: success/failure
3385 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3386 std::list<std::string> *log)
3388 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3389 ServerMap *map = (ServerMap*)(&m_env->getMap());
3391 // Fail if no actions to handle
3392 if (actions.empty()) {
3394 log->push_back("Nothing to do.");
3401 for (const RollbackAction &action : actions) {
3403 bool success = action.applyRevert(map, this, this);
3406 std::ostringstream os;
3407 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3408 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3410 log->push_back(os.str());
3412 std::ostringstream os;
3413 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3414 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3416 log->push_back(os.str());
3420 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3421 <<" failed"<<std::endl;
3423 // Call it done if less than half failed
3424 return num_failed <= num_tried/2;
3427 // IGameDef interface
3429 IItemDefManager *Server::getItemDefManager()
3434 const NodeDefManager *Server::getNodeDefManager()
3439 ICraftDefManager *Server::getCraftDefManager()
3444 u16 Server::allocateUnknownNodeId(const std::string &name)
3446 return m_nodedef->allocateDummy(name);
3449 IWritableItemDefManager *Server::getWritableItemDefManager()
3454 NodeDefManager *Server::getWritableNodeDefManager()
3459 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3464 const std::vector<ModSpec> & Server::getMods() const
3466 return m_modmgr->getMods();
3469 const ModSpec *Server::getModSpec(const std::string &modname) const
3471 return m_modmgr->getModSpec(modname);
3474 void Server::getModNames(std::vector<std::string> &modlist)
3476 m_modmgr->getModNames(modlist);
3479 std::string Server::getBuiltinLuaPath()
3481 return porting::path_share + DIR_DELIM + "builtin";
3484 std::string Server::getModStoragePath() const
3486 return m_path_world + DIR_DELIM + "mod_storage";
3489 v3f Server::findSpawnPos()
3491 ServerMap &map = m_env->getServerMap();
3493 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf)) {
3494 return nodeposf * BS;
3497 bool is_good = false;
3498 // Limit spawn range to mapgen edges (determined by 'mapgen_limit')
3499 s32 range_max = map.getMapgenParams()->getSpawnRangeMax();
3501 // Try to find a good place a few times
3502 for(s32 i = 0; i < 4000 && !is_good; i++) {
3503 s32 range = MYMIN(1 + i, range_max);
3504 // We're going to try to throw the player to this position
3505 v2s16 nodepos2d = v2s16(
3506 -range + (myrand() % (range * 2)),
3507 -range + (myrand() % (range * 2)));
3509 // Get spawn level at point
3510 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3511 // Continue if MAX_MAP_GENERATION_LIMIT was returned by
3512 // the mapgen to signify an unsuitable spawn position
3513 if (spawn_level == MAX_MAP_GENERATION_LIMIT)
3516 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3519 for (s32 i = 0; i < 10; i++) {
3520 v3s16 blockpos = getNodeBlockPos(nodepos);
3521 map.emergeBlock(blockpos, true);
3522 content_t c = map.getNodeNoEx(nodepos).getContent();
3523 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
3525 if (air_count >= 2) {
3526 nodeposf = intToFloat(nodepos, BS);
3527 // Don't spawn the player outside map boundaries
3528 if (objectpos_over_limit(nodeposf))
3541 void Server::requestShutdown(const std::string &msg, bool reconnect, float delay)
3543 if (delay == 0.0f) {
3544 // No delay, shutdown immediately
3545 m_shutdown_state.is_requested = true;
3546 // only print to the infostream, a chat message saying
3547 // "Server Shutting Down" is sent when the server destructs.
3548 infostream << "*** Immediate Server shutdown requested." << std::endl;
3549 } else if (delay < 0.0f && m_shutdown_state.isTimerRunning()) {
3550 // Negative delay, cancel shutdown if requested
3551 m_shutdown_state.reset();
3552 std::wstringstream ws;
3554 ws << L"*** Server shutdown canceled.";
3556 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3557 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3558 // m_shutdown_* are already handled, skip.
3560 } else if (delay > 0.0f) {
3561 // Positive delay, tell the clients when the server will shut down
3562 std::wstringstream ws;
3564 ws << L"*** Server shutting down in "
3565 << duration_to_string(myround(delay)).c_str()
3568 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3569 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3572 m_shutdown_state.trigger(delay, msg, reconnect);
3575 PlayerSAO* Server::emergePlayer(const char *name, session_t peer_id, u16 proto_version)
3578 Try to get an existing player
3580 RemotePlayer *player = m_env->getPlayer(name);
3582 // If player is already connected, cancel
3583 if (player && player->getPeerId() != PEER_ID_INEXISTENT) {
3584 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3589 If player with the wanted peer_id already exists, cancel.
3591 if (m_env->getPlayer(peer_id)) {
3592 infostream<<"emergePlayer(): Player with wrong name but same"
3593 " peer_id already exists"<<std::endl;
3598 player = new RemotePlayer(name, idef());
3601 bool newplayer = false;
3604 PlayerSAO *playersao = m_env->loadPlayer(player, &newplayer, peer_id, isSingleplayer());
3606 // Complete init with server parts
3607 playersao->finalize(player, getPlayerEffectivePrivs(player->getName()));
3608 player->protocol_version = proto_version;
3612 m_script->on_newplayer(playersao);
3618 bool Server::registerModStorage(ModMetadata *storage)
3620 if (m_mod_storages.find(storage->getModName()) != m_mod_storages.end()) {
3621 errorstream << "Unable to register same mod storage twice. Storage name: "
3622 << storage->getModName() << std::endl;
3626 m_mod_storages[storage->getModName()] = storage;
3630 void Server::unregisterModStorage(const std::string &name)
3632 std::unordered_map<std::string, ModMetadata *>::const_iterator it = m_mod_storages.find(name);
3633 if (it != m_mod_storages.end()) {
3634 // Save unconditionaly on unregistration
3635 it->second->save(getModStoragePath());
3636 m_mod_storages.erase(name);
3640 void dedicated_server_loop(Server &server, bool &kill)
3642 verbosestream<<"dedicated_server_loop()"<<std::endl;
3644 IntervalLimiter m_profiler_interval;
3646 static thread_local const float steplen =
3647 g_settings->getFloat("dedicated_server_step");
3648 static thread_local const float profiler_print_interval =
3649 g_settings->getFloat("profiler_print_interval");
3652 // This is kind of a hack but can be done like this
3653 // because server.step() is very light
3655 ScopeProfiler sp(g_profiler, "dedicated server sleep");
3656 sleep_ms((int)(steplen*1000.0));
3658 server.step(steplen);
3660 if (server.isShutdownRequested() || kill)
3666 if (profiler_print_interval != 0) {
3667 if(m_profiler_interval.step(steplen, profiler_print_interval))
3669 infostream<<"Profiler:"<<std::endl;
3670 g_profiler->print(infostream);
3671 g_profiler->clear();
3676 infostream << "Dedicated server quitting" << std::endl;
3678 if (g_settings->getBool("server_announce"))
3679 ServerList::sendAnnounce(ServerList::AA_DELETE,
3680 server.m_bind_addr.getPort());
3689 bool Server::joinModChannel(const std::string &channel)
3691 return m_modchannel_mgr->joinChannel(channel, PEER_ID_SERVER) &&
3692 m_modchannel_mgr->setChannelState(channel, MODCHANNEL_STATE_READ_WRITE);
3695 bool Server::leaveModChannel(const std::string &channel)
3697 return m_modchannel_mgr->leaveChannel(channel, PEER_ID_SERVER);
3700 bool Server::sendModChannelMessage(const std::string &channel, const std::string &message)
3702 if (!m_modchannel_mgr->canWriteOnChannel(channel))
3705 broadcastModChannelMessage(channel, message, PEER_ID_SERVER);
3709 ModChannel* Server::getModChannel(const std::string &channel)
3711 return m_modchannel_mgr->getModChannel(channel);
3714 void Server::broadcastModChannelMessage(const std::string &channel,
3715 const std::string &message, session_t from_peer)
3717 const std::vector<u16> &peers = m_modchannel_mgr->getChannelPeers(channel);
3721 if (message.size() > STRING_MAX_LEN) {
3722 warningstream << "ModChannel message too long, dropping before sending "
3723 << " (" << message.size() << " > " << STRING_MAX_LEN << ", channel: "
3724 << channel << ")" << std::endl;
3729 if (from_peer != PEER_ID_SERVER) {
3730 sender = getPlayerName(from_peer);
3733 NetworkPacket resp_pkt(TOCLIENT_MODCHANNEL_MSG,
3734 2 + channel.size() + 2 + sender.size() + 2 + message.size());
3735 resp_pkt << channel << sender << message;
3736 for (session_t peer_id : peers) {
3738 if (peer_id == from_peer)
3741 Send(peer_id, &resp_pkt);
3744 if (from_peer != PEER_ID_SERVER) {
3745 m_script->on_modchannel_message(channel, sender, message);