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;
310 while (!m_unsent_map_edit_queue.empty()) {
311 delete m_unsent_map_edit_queue.front();
312 m_unsent_map_edit_queue.pop();
318 infostream << "Server created for gameid \"" << m_gamespec.id << "\"";
319 if (m_simple_singleplayer_mode)
320 infostream << " in simple singleplayer mode" << std::endl;
322 infostream << std::endl;
323 infostream << "- world: " << m_path_world << std::endl;
324 infostream << "- game: " << m_gamespec.path << std::endl;
326 // Create world if it doesn't exist
327 if (!loadGameConfAndInitWorld(m_path_world, m_gamespec))
328 throw ServerError("Failed to initialize world");
330 // Create emerge manager
331 m_emerge = new EmergeManager(this);
333 // Create ban manager
334 std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
335 m_banmanager = new BanManager(ban_path);
337 m_modmgr = std::unique_ptr<ServerModManager>(new ServerModManager(m_path_world));
338 std::vector<ModSpec> unsatisfied_mods = m_modmgr->getUnsatisfiedMods();
339 // complain about mods with unsatisfied dependencies
340 if (!m_modmgr->isConsistent()) {
341 m_modmgr->printUnsatisfiedModsError();
345 MutexAutoLock envlock(m_env_mutex);
347 // Create the Map (loads map_meta.txt, overriding configured mapgen params)
348 ServerMap *servermap = new ServerMap(m_path_world, this, m_emerge);
350 // Initialize scripting
351 infostream << "Server: Initializing Lua" << std::endl;
353 m_script = new ServerScripting(this);
355 m_script->loadMod(getBuiltinLuaPath() + DIR_DELIM "init.lua", BUILTIN_MOD_NAME);
357 m_modmgr->loadMods(m_script);
359 // Read Textures and calculate sha1 sums
362 // Apply item aliases in the node definition manager
363 m_nodedef->updateAliases(m_itemdef);
365 // Apply texture overrides from texturepack/override.txt
366 std::vector<std::string> paths;
367 fs::GetRecursiveDirs(paths, g_settings->get("texture_path"));
368 fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures");
369 for (const std::string &path : paths)
370 m_nodedef->applyTextureOverrides(path + DIR_DELIM + "override.txt");
372 m_nodedef->setNodeRegistrationStatus(true);
374 // Perform pending node name resolutions
375 m_nodedef->runNodeResolveCallbacks();
377 // unmap node names for connected nodeboxes
378 m_nodedef->mapNodeboxConnections();
380 // init the recipe hashes to speed up crafting
381 m_craftdef->initHashes(this);
383 // Initialize Environment
384 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
386 m_clients.setEnv(m_env);
388 if (!servermap->settings_mgr.makeMapgenParams())
389 FATAL_ERROR("Couldn't create any mapgen type");
391 // Initialize mapgens
392 m_emerge->initMapgens(servermap->getMapgenParams());
394 if (g_settings->getBool("enable_rollback_recording")) {
395 // Create rollback manager
396 m_rollback = new RollbackManager(m_path_world, this);
399 // Give environment reference to scripting api
400 m_script->initializeEnvironment(m_env);
402 // Register us to receive map edit events
403 servermap->addEventReceiver(this);
407 m_liquid_transform_every = g_settings->getFloat("liquid_update");
408 m_max_chatmessage_length = g_settings->getU16("chat_message_max_size");
409 m_csm_restriction_flags = g_settings->getU64("csm_restriction_flags");
410 m_csm_restriction_noderange = g_settings->getU32("csm_restriction_noderange");
415 infostream << "Starting server on " << m_bind_addr.serializeString()
416 << "..." << std::endl;
418 // Stop thread if already running
421 // Initialize connection
422 m_con->SetTimeoutMs(30);
423 m_con->Serve(m_bind_addr);
428 // ASCII art for the win!
430 << " .__ __ __ " << std::endl
431 << " _____ |__| ____ _____/ |_ ____ _______/ |_ " << std::endl
432 << " / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\" << std::endl
433 << "| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | " << std::endl
434 << "|__|_| /__|___| /\\___ >__| \\___ >____ > |__| " << std::endl
435 << " \\/ \\/ \\/ \\/ \\/ " << std::endl;
436 actionstream << "World at [" << m_path_world << "]" << std::endl;
437 actionstream << "Server for gameid=\"" << m_gamespec.id
438 << "\" listening on " << m_bind_addr.serializeString() << ":"
439 << m_bind_addr.getPort() << "." << std::endl;
444 infostream<<"Server: Stopping and waiting threads"<<std::endl;
446 // Stop threads (set run=false first so both start stopping)
448 //m_emergethread.setRun(false);
450 //m_emergethread.stop();
452 infostream<<"Server: Threads stopped"<<std::endl;
455 void Server::step(float dtime)
461 MutexAutoLock lock(m_step_dtime_mutex);
462 m_step_dtime += dtime;
464 // Throw if fatal error occurred in thread
465 std::string async_err = m_async_fatal_error.get();
466 if (!async_err.empty()) {
467 if (!m_simple_singleplayer_mode) {
468 m_env->kickAllPlayers(SERVER_ACCESSDENIED_CRASH,
469 g_settings->get("kick_msg_crash"),
470 g_settings->getBool("ask_reconnect_on_crash"));
472 throw ServerError("AsyncErr: " + async_err);
476 void Server::AsyncRunStep(bool initial_step)
481 MutexAutoLock lock1(m_step_dtime_mutex);
482 dtime = m_step_dtime;
486 // Send blocks to clients
490 if((dtime < 0.001) && !initial_step)
493 ScopeProfiler sp(g_profiler, "Server::AsyncRunStep()", SPT_AVG);
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);
542 static const float map_timer_and_unload_dtime = 2.92;
543 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
545 MutexAutoLock lock(m_env_mutex);
546 // Run Map's timers and unload unused data
547 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
548 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
549 g_settings->getFloat("server_unload_unused_data_timeout"),
554 Listen to the admin chat, if available
557 if (!m_admin_chat->command_queue.empty()) {
558 MutexAutoLock lock(m_env_mutex);
559 while (!m_admin_chat->command_queue.empty()) {
560 ChatEvent *evt = m_admin_chat->command_queue.pop_frontNoEx();
561 handleChatInterfaceEvent(evt);
565 m_admin_chat->outgoing_queue.push_back(
566 new ChatEventTimeInfo(m_env->getGameTime(), m_env->getTimeOfDay()));
573 /* Transform liquids */
574 m_liquid_transform_timer += dtime;
575 if(m_liquid_transform_timer >= m_liquid_transform_every)
577 m_liquid_transform_timer -= m_liquid_transform_every;
579 MutexAutoLock lock(m_env_mutex);
581 ScopeProfiler sp(g_profiler, "Server: liquid transform");
583 std::map<v3s16, MapBlock*> modified_blocks;
584 m_env->getMap().transformLiquids(modified_blocks, m_env);
587 Set the modified blocks unsent for all the clients
589 if (!modified_blocks.empty()) {
590 SetBlocksNotSent(modified_blocks);
593 m_clients.step(dtime);
595 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
597 // send masterserver announce
599 float &counter = m_masterserver_timer;
600 if (!isSingleplayer() && (!counter || counter >= 300.0) &&
601 g_settings->getBool("server_announce")) {
602 ServerList::sendAnnounce(counter ? ServerList::AA_UPDATE :
603 ServerList::AA_START,
604 m_bind_addr.getPort(),
605 m_clients.getPlayerNames(),
607 m_env->getGameTime(),
610 Mapgen::getMapgenName(m_emerge->mgparams->mgtype),
620 Check added and deleted active objects
623 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
624 MutexAutoLock envlock(m_env_mutex);
627 const RemoteClientMap &clients = m_clients.getClientList();
628 ScopeProfiler sp(g_profiler, "Server: update objects within range");
630 for (const auto &client_it : clients) {
631 RemoteClient *client = client_it.second;
633 if (client->getState() < CS_DefinitionsSent)
636 // This can happen if the client times out somehow
637 if (!m_env->getPlayer(client->peer_id))
640 PlayerSAO *playersao = getPlayerSAO(client->peer_id);
644 SendActiveObjectRemoveAdd(client, playersao);
648 // Save mod storages if modified
649 m_mod_storage_save_timer -= dtime;
650 if (m_mod_storage_save_timer <= 0.0f) {
651 infostream << "Saving registered mod storages." << std::endl;
652 m_mod_storage_save_timer = g_settings->getFloat("server_map_save_interval");
653 for (std::unordered_map<std::string, ModMetadata *>::const_iterator
654 it = m_mod_storages.begin(); it != m_mod_storages.end(); ++it) {
655 if (it->second->isModified()) {
656 it->second->save(getModStoragePath());
666 MutexAutoLock envlock(m_env_mutex);
667 ScopeProfiler sp(g_profiler, "Server: send SAO messages");
670 // Value = data sent by object
671 std::unordered_map<u16, std::vector<ActiveObjectMessage>*> buffered_messages;
673 // Get active object messages from environment
675 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
679 std::vector<ActiveObjectMessage>* message_list = nullptr;
680 std::unordered_map<u16, std::vector<ActiveObjectMessage>* >::iterator n;
681 n = buffered_messages.find(aom.id);
682 if (n == buffered_messages.end()) {
683 message_list = new std::vector<ActiveObjectMessage>;
684 buffered_messages[aom.id] = message_list;
687 message_list = n->second;
689 message_list->push_back(aom);
693 const RemoteClientMap &clients = m_clients.getClientList();
694 // Route data to every client
695 for (const auto &client_it : clients) {
696 RemoteClient *client = client_it.second;
697 std::string reliable_data;
698 std::string unreliable_data;
699 // Go through all objects in message buffer
700 for (const auto &buffered_message : buffered_messages) {
701 // If object is not known by client, skip it
702 u16 id = buffered_message.first;
703 if (client->m_known_objects.find(id) == client->m_known_objects.end())
706 // Get message list of object
707 std::vector<ActiveObjectMessage>* list = buffered_message.second;
708 // Go through every message
709 for (const ActiveObjectMessage &aom : *list) {
710 // Compose the full new data with header
711 std::string new_data;
714 writeU16((u8*)&buf[0], aom.id);
715 new_data.append(buf, 2);
717 new_data += serializeString(aom.datastring);
718 // Add data to buffer
720 reliable_data += new_data;
722 unreliable_data += new_data;
726 reliable_data and unreliable_data are now ready.
729 if (!reliable_data.empty()) {
730 SendActiveObjectMessages(client->peer_id, reliable_data);
733 if (!unreliable_data.empty()) {
734 SendActiveObjectMessages(client->peer_id, unreliable_data, false);
739 // Clear buffered_messages
740 for (auto &buffered_message : buffered_messages) {
741 delete buffered_message.second;
746 Send queued-for-sending map edit events.
749 // We will be accessing the environment
750 MutexAutoLock lock(m_env_mutex);
752 // Don't send too many at a time
755 // Single change sending is disabled if queue size is not small
756 bool disable_single_change_sending = false;
757 if(m_unsent_map_edit_queue.size() >= 4)
758 disable_single_change_sending = true;
760 int event_count = m_unsent_map_edit_queue.size();
762 // We'll log the amount of each
765 std::list<v3s16> node_meta_updates;
767 while (!m_unsent_map_edit_queue.empty()) {
768 MapEditEvent* event = m_unsent_map_edit_queue.front();
769 m_unsent_map_edit_queue.pop();
771 // Players far away from the change are stored here.
772 // Instead of sending the changes, MapBlocks are set not sent
774 std::unordered_set<u16> far_players;
776 switch (event->type) {
779 prof.add("MEET_ADDNODE", 1);
780 sendAddNode(event->p, event->n, &far_players,
781 disable_single_change_sending ? 5 : 30,
782 event->type == MEET_ADDNODE);
784 case MEET_REMOVENODE:
785 prof.add("MEET_REMOVENODE", 1);
786 sendRemoveNode(event->p, &far_players,
787 disable_single_change_sending ? 5 : 30);
789 case MEET_BLOCK_NODE_METADATA_CHANGED: {
790 verbosestream << "Server: MEET_BLOCK_NODE_METADATA_CHANGED" << std::endl;
791 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
792 if (!event->is_private_change) {
793 // Don't send the change yet. Collect them to eliminate dupes.
794 node_meta_updates.remove(event->p);
795 node_meta_updates.push_back(event->p);
798 if (MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(
799 getNodeBlockPos(event->p))) {
800 block->raiseModified(MOD_STATE_WRITE_NEEDED,
801 MOD_REASON_REPORT_META_CHANGE);
806 infostream << "Server: MEET_OTHER" << std::endl;
807 prof.add("MEET_OTHER", 1);
808 for (const v3s16 &modified_block : event->modified_blocks) {
809 m_clients.markBlockposAsNotSent(modified_block);
813 prof.add("unknown", 1);
814 warningstream << "Server: Unknown MapEditEvent "
815 << ((u32)event->type) << std::endl;
820 Set blocks not sent to far players
822 if (!far_players.empty()) {
823 // Convert list format to that wanted by SetBlocksNotSent
824 std::map<v3s16, MapBlock*> modified_blocks2;
825 for (const v3s16 &modified_block : event->modified_blocks) {
826 modified_blocks2[modified_block] =
827 m_env->getMap().getBlockNoCreateNoEx(modified_block);
830 // Set blocks not sent
831 for (const u16 far_player : far_players) {
832 if (RemoteClient *client = getClient(far_player))
833 client->SetBlocksNotSent(modified_blocks2);
840 if (event_count >= 5) {
841 infostream << "Server: MapEditEvents:" << std::endl;
842 prof.print(infostream);
843 } else if (event_count != 0) {
844 verbosestream << "Server: MapEditEvents:" << std::endl;
845 prof.print(verbosestream);
848 // Send all metadata updates
849 if (node_meta_updates.size())
850 sendMetadataChanged(node_meta_updates);
854 Trigger emergethread (it somehow gets to a non-triggered but
855 bysy state sometimes)
858 float &counter = m_emergethread_trigger_timer;
860 if (counter >= 2.0) {
863 m_emerge->startThreads();
867 // Save map, players and auth stuff
869 float &counter = m_savemap_timer;
871 static thread_local const float save_interval =
872 g_settings->getFloat("server_map_save_interval");
873 if (counter >= save_interval) {
875 MutexAutoLock lock(m_env_mutex);
877 ScopeProfiler sp(g_profiler, "Server: map saving (sum)");
880 if (m_banmanager->isModified()) {
881 m_banmanager->save();
884 // Save changed parts of map
885 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
888 m_env->saveLoadedPlayers();
890 // Save environment metadata
895 m_shutdown_state.tick(dtime, this);
898 void Server::Receive()
900 session_t peer_id = 0;
903 m_con->Receive(&pkt);
904 peer_id = pkt.getPeerId();
906 } catch (const con::InvalidIncomingDataException &e) {
907 infostream << "Server::Receive(): InvalidIncomingDataException: what()="
908 << e.what() << std::endl;
909 } catch (const SerializationError &e) {
910 infostream << "Server::Receive(): SerializationError: what()="
911 << e.what() << std::endl;
912 } catch (const ClientStateError &e) {
913 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
914 DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
915 L"Try reconnecting or updating your client");
916 } catch (const con::PeerNotFoundException &e) {
921 PlayerSAO* Server::StageTwoClientInit(session_t peer_id)
923 std::string playername;
924 PlayerSAO *playersao = NULL;
927 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
929 playername = client->getName();
930 playersao = emergePlayer(playername.c_str(), peer_id, client->net_proto_version);
932 } catch (std::exception &e) {
938 RemotePlayer *player = m_env->getPlayer(playername.c_str());
941 if (!playersao || !player) {
942 if (player && player->getPeerId() != PEER_ID_INEXISTENT) {
943 actionstream << "Server: Failed to emerge player \"" << playername
944 << "\" (player allocated to an another client)" << std::endl;
945 DenyAccess_Legacy(peer_id, L"Another client is connected with this "
946 L"name. If your client closed unexpectedly, try again in "
949 errorstream << "Server: " << playername << ": Failed to emerge player"
951 DenyAccess_Legacy(peer_id, L"Could not allocate player.");
957 Send complete position information
959 SendMovePlayer(peer_id);
962 SendPlayerPrivileges(peer_id);
964 // Send inventory formspec
965 SendPlayerInventoryFormspec(peer_id);
968 SendInventory(playersao, false);
970 // Send HP or death screen
971 if (playersao->isDead())
972 SendDeathscreen(peer_id, false, v3f(0,0,0));
974 SendPlayerHPOrDie(playersao,
975 PlayerHPChangeReason(PlayerHPChangeReason::SET_HP));
978 SendPlayerBreath(playersao);
980 Address addr = getPeerAddress(player->getPeerId());
981 std::string ip_str = addr.serializeString();
982 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
987 const std::vector<std::string> &names = m_clients.getPlayerNames();
989 actionstream << player->getName() << " joins game. List of players: ";
991 for (const std::string &name : names) {
992 actionstream << name << " ";
995 actionstream << player->getName() <<std::endl;
1000 inline void Server::handleCommand(NetworkPacket *pkt)
1002 const ToServerCommandHandler &opHandle = toServerCommandTable[pkt->getCommand()];
1003 (this->*opHandle.handler)(pkt);
1006 void Server::ProcessData(NetworkPacket *pkt)
1008 // Environment is locked first.
1009 MutexAutoLock envlock(m_env_mutex);
1011 ScopeProfiler sp(g_profiler, "Server: Process network packet (sum)");
1012 u32 peer_id = pkt->getPeerId();
1015 Address address = getPeerAddress(peer_id);
1016 std::string addr_s = address.serializeString();
1018 if(m_banmanager->isIpBanned(addr_s)) {
1019 std::string ban_name = m_banmanager->getBanName(addr_s);
1020 infostream << "Server: A banned client tried to connect from "
1021 << addr_s << "; banned name was "
1022 << ban_name << std::endl;
1023 // This actually doesn't seem to transfer to the client
1024 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1025 + utf8_to_wide(ban_name));
1029 catch(con::PeerNotFoundException &e) {
1031 * no peer for this packet found
1032 * most common reason is peer timeout, e.g. peer didn't
1033 * respond for some time, your server was overloaded or
1036 infostream << "Server::ProcessData(): Canceling: peer "
1037 << peer_id << " not found" << std::endl;
1042 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1044 // Command must be handled into ToServerCommandHandler
1045 if (command >= TOSERVER_NUM_MSG_TYPES) {
1046 infostream << "Server: Ignoring unknown command "
1047 << command << std::endl;
1051 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1056 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1058 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1059 errorstream << "Server::ProcessData(): Cancelling: Peer"
1060 " serialization format invalid or not initialized."
1061 " Skipping incoming command=" << command << std::endl;
1065 /* Handle commands related to client startup */
1066 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1071 if (m_clients.getClientState(peer_id) < CS_Active) {
1072 if (command == TOSERVER_PLAYERPOS) return;
1074 errorstream << "Got packet command: " << command << " for peer id "
1075 << peer_id << " but client isn't active yet. Dropping packet "
1081 } catch (SendFailedException &e) {
1082 errorstream << "Server::ProcessData(): SendFailedException: "
1083 << "what=" << e.what()
1085 } catch (PacketError &e) {
1086 actionstream << "Server::ProcessData(): PacketError: "
1087 << "what=" << e.what()
1092 void Server::setTimeOfDay(u32 time)
1094 m_env->setTimeOfDay(time);
1095 m_time_of_day_send_timer = 0;
1098 void Server::onMapEditEvent(const MapEditEvent &event)
1100 if (m_ignore_map_edit_events_area.contains(event.getArea()))
1103 m_unsent_map_edit_queue.push(new MapEditEvent(event));
1106 Inventory* Server::getInventory(const InventoryLocation &loc)
1109 case InventoryLocation::UNDEFINED:
1110 case InventoryLocation::CURRENT_PLAYER:
1112 case InventoryLocation::PLAYER:
1114 RemotePlayer *player = m_env->getPlayer(loc.name.c_str());
1117 PlayerSAO *playersao = player->getPlayerSAO();
1120 return playersao->getInventory();
1123 case InventoryLocation::NODEMETA:
1125 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1128 return meta->getInventory();
1131 case InventoryLocation::DETACHED:
1133 if(m_detached_inventories.count(loc.name) == 0)
1135 return m_detached_inventories[loc.name];
1139 sanity_check(false); // abort
1145 void Server::setInventoryModified(const InventoryLocation &loc)
1148 case InventoryLocation::UNDEFINED:
1150 case InventoryLocation::PLAYER:
1153 RemotePlayer *player = m_env->getPlayer(loc.name.c_str());
1158 player->setModified(true);
1159 player->inventory.setModified(true);
1160 // Updates are sent in ServerEnvironment::step()
1163 case InventoryLocation::NODEMETA:
1166 event.type = MEET_BLOCK_NODE_METADATA_CHANGED;
1168 m_env->getMap().dispatchEvent(event);
1171 case InventoryLocation::DETACHED:
1173 // Updates are sent in ServerEnvironment::step()
1177 sanity_check(false); // abort
1182 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1184 std::vector<session_t> clients = m_clients.getClientIDs();
1186 // Set the modified blocks unsent for all the clients
1187 for (const session_t client_id : clients) {
1188 if (RemoteClient *client = m_clients.lockedGetClientNoEx(client_id))
1189 client->SetBlocksNotSent(block);
1194 void Server::peerAdded(con::Peer *peer)
1196 verbosestream<<"Server::peerAdded(): peer->id="
1197 <<peer->id<<std::endl;
1199 m_peer_change_queue.push(con::PeerChange(con::PEER_ADDED, peer->id, false));
1202 void Server::deletingPeer(con::Peer *peer, bool timeout)
1204 verbosestream<<"Server::deletingPeer(): peer->id="
1205 <<peer->id<<", timeout="<<timeout<<std::endl;
1207 m_clients.event(peer->id, CSE_Disconnect);
1208 m_peer_change_queue.push(con::PeerChange(con::PEER_REMOVED, peer->id, timeout));
1211 bool Server::getClientConInfo(session_t peer_id, con::rtt_stat_type type, float* retval)
1213 *retval = m_con->getPeerStat(peer_id,type);
1214 return *retval != -1;
1217 bool Server::getClientInfo(
1226 std::string* vers_string
1229 *state = m_clients.getClientState(peer_id);
1231 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1238 *uptime = client->uptime();
1239 *ser_vers = client->serialization_version;
1240 *prot_vers = client->net_proto_version;
1242 *major = client->getMajor();
1243 *minor = client->getMinor();
1244 *patch = client->getPatch();
1245 *vers_string = client->getPatch();
1252 void Server::handlePeerChanges()
1254 while(!m_peer_change_queue.empty())
1256 con::PeerChange c = m_peer_change_queue.front();
1257 m_peer_change_queue.pop();
1259 verbosestream<<"Server: Handling peer change: "
1260 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1265 case con::PEER_ADDED:
1266 m_clients.CreateClient(c.peer_id);
1269 case con::PEER_REMOVED:
1270 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1274 FATAL_ERROR("Invalid peer change event received!");
1280 void Server::printToConsoleOnly(const std::string &text)
1283 m_admin_chat->outgoing_queue.push_back(
1284 new ChatEventChat("", utf8_to_wide(text)));
1286 std::cout << text << std::endl;
1290 void Server::Send(NetworkPacket *pkt)
1292 Send(pkt->getPeerId(), pkt);
1295 void Server::Send(session_t peer_id, NetworkPacket *pkt)
1297 m_clients.send(peer_id,
1298 clientCommandFactoryTable[pkt->getCommand()].channel,
1300 clientCommandFactoryTable[pkt->getCommand()].reliable);
1303 void Server::SendMovement(session_t peer_id)
1305 std::ostringstream os(std::ios_base::binary);
1307 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1309 pkt << g_settings->getFloat("movement_acceleration_default");
1310 pkt << g_settings->getFloat("movement_acceleration_air");
1311 pkt << g_settings->getFloat("movement_acceleration_fast");
1312 pkt << g_settings->getFloat("movement_speed_walk");
1313 pkt << g_settings->getFloat("movement_speed_crouch");
1314 pkt << g_settings->getFloat("movement_speed_fast");
1315 pkt << g_settings->getFloat("movement_speed_climb");
1316 pkt << g_settings->getFloat("movement_speed_jump");
1317 pkt << g_settings->getFloat("movement_liquid_fluidity");
1318 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1319 pkt << g_settings->getFloat("movement_liquid_sink");
1320 pkt << g_settings->getFloat("movement_gravity");
1325 void Server::SendPlayerHPOrDie(PlayerSAO *playersao, const PlayerHPChangeReason &reason)
1327 if (playersao->isImmortal())
1330 session_t peer_id = playersao->getPeerID();
1331 bool is_alive = playersao->getHP() > 0;
1334 SendPlayerHP(peer_id);
1336 DiePlayer(peer_id, reason);
1339 void Server::SendHP(session_t peer_id, u16 hp)
1341 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1346 void Server::SendBreath(session_t peer_id, u16 breath)
1348 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1349 pkt << (u16) breath;
1353 void Server::SendAccessDenied(session_t peer_id, AccessDeniedCode reason,
1354 const std::string &custom_reason, bool reconnect)
1356 assert(reason < SERVER_ACCESSDENIED_MAX);
1358 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1360 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
1361 pkt << custom_reason;
1362 else if (reason == SERVER_ACCESSDENIED_SHUTDOWN ||
1363 reason == SERVER_ACCESSDENIED_CRASH)
1364 pkt << custom_reason << (u8)reconnect;
1368 void Server::SendAccessDenied_Legacy(session_t peer_id,const std::wstring &reason)
1370 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1375 void Server::SendDeathscreen(session_t peer_id, bool set_camera_point_target,
1376 v3f camera_point_target)
1378 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1379 pkt << set_camera_point_target << camera_point_target;
1383 void Server::SendItemDef(session_t peer_id,
1384 IItemDefManager *itemdef, u16 protocol_version)
1386 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1390 u32 length of the next item
1391 zlib-compressed serialized ItemDefManager
1393 std::ostringstream tmp_os(std::ios::binary);
1394 itemdef->serialize(tmp_os, protocol_version);
1395 std::ostringstream tmp_os2(std::ios::binary);
1396 compressZlib(tmp_os.str(), tmp_os2);
1397 pkt.putLongString(tmp_os2.str());
1400 verbosestream << "Server: Sending item definitions to id(" << peer_id
1401 << "): size=" << pkt.getSize() << std::endl;
1406 void Server::SendNodeDef(session_t peer_id,
1407 const NodeDefManager *nodedef, u16 protocol_version)
1409 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1413 u32 length of the next item
1414 zlib-compressed serialized NodeDefManager
1416 std::ostringstream tmp_os(std::ios::binary);
1417 nodedef->serialize(tmp_os, protocol_version);
1418 std::ostringstream tmp_os2(std::ios::binary);
1419 compressZlib(tmp_os.str(), tmp_os2);
1421 pkt.putLongString(tmp_os2.str());
1424 verbosestream << "Server: Sending node definitions to id(" << peer_id
1425 << "): size=" << pkt.getSize() << std::endl;
1431 Non-static send methods
1434 void Server::SendInventory(PlayerSAO *sao, bool incremental)
1436 RemotePlayer *player = sao->getPlayer();
1438 // Do not send new format to old clients
1439 incremental &= player->protocol_version >= 38;
1441 UpdateCrafting(player);
1447 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, sao->getPeerID());
1449 std::ostringstream os(std::ios::binary);
1450 sao->getInventory()->serialize(os, incremental);
1451 sao->getInventory()->setModified(false);
1452 player->setModified(true);
1454 const std::string &s = os.str();
1455 pkt.putRawString(s.c_str(), s.size());
1459 void Server::SendChatMessage(session_t peer_id, const ChatMessage &message)
1461 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1463 u8 type = message.type;
1464 pkt << version << type << std::wstring(L"") << message.message << (u64)message.timestamp;
1466 if (peer_id != PEER_ID_INEXISTENT) {
1467 RemotePlayer *player = m_env->getPlayer(peer_id);
1473 m_clients.sendToAll(&pkt);
1477 void Server::SendShowFormspecMessage(session_t peer_id, const std::string &formspec,
1478 const std::string &formname)
1480 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0, peer_id);
1481 if (formspec.empty()){
1482 //the client should close the formspec
1483 //but make sure there wasn't another one open in meantime
1484 const auto it = m_formspec_state_data.find(peer_id);
1485 if (it != m_formspec_state_data.end() && it->second == formname) {
1486 m_formspec_state_data.erase(peer_id);
1488 pkt.putLongString("");
1490 m_formspec_state_data[peer_id] = formname;
1491 pkt.putLongString(formspec);
1498 // Spawns a particle on peer with peer_id
1499 void Server::SendSpawnParticle(session_t peer_id, u16 protocol_version,
1500 v3f pos, v3f velocity, v3f acceleration,
1501 float expirationtime, float size, bool collisiondetection,
1502 bool collision_removal, bool object_collision,
1503 bool vertical, const std::string &texture,
1504 const struct TileAnimationParams &animation, u8 glow)
1506 static thread_local const float radius =
1507 g_settings->getS16("max_block_send_distance") * MAP_BLOCKSIZE * BS;
1509 if (peer_id == PEER_ID_INEXISTENT) {
1510 std::vector<session_t> clients = m_clients.getClientIDs();
1512 for (const session_t client_id : clients) {
1513 RemotePlayer *player = m_env->getPlayer(client_id);
1517 PlayerSAO *sao = player->getPlayerSAO();
1521 // Do not send to distant clients
1522 if (sao->getBasePosition().getDistanceFrom(pos * BS) > radius)
1525 SendSpawnParticle(client_id, player->protocol_version,
1526 pos, velocity, acceleration,
1527 expirationtime, size, collisiondetection, collision_removal,
1528 object_collision, vertical, texture, animation, glow);
1533 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1535 pkt << pos << velocity << acceleration << expirationtime
1536 << size << collisiondetection;
1537 pkt.putLongString(texture);
1539 pkt << collision_removal;
1540 // This is horrible but required (why are there two ways to serialize pkts?)
1541 std::ostringstream os(std::ios_base::binary);
1542 animation.serialize(os, protocol_version);
1543 pkt.putRawString(os.str());
1545 pkt << object_collision;
1550 // Adds a ParticleSpawner on peer with peer_id
1551 void Server::SendAddParticleSpawner(session_t peer_id, u16 protocol_version,
1552 u16 amount, float spawntime, v3f minpos, v3f maxpos,
1553 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1554 float minsize, float maxsize, bool collisiondetection, bool collision_removal,
1555 bool object_collision, u16 attached_id, bool vertical, const std::string &texture, u32 id,
1556 const struct TileAnimationParams &animation, u8 glow)
1558 if (peer_id == PEER_ID_INEXISTENT) {
1559 // This sucks and should be replaced:
1560 std::vector<session_t> clients = m_clients.getClientIDs();
1561 for (const session_t client_id : clients) {
1562 RemotePlayer *player = m_env->getPlayer(client_id);
1565 SendAddParticleSpawner(client_id, player->protocol_version,
1566 amount, spawntime, minpos, maxpos,
1567 minvel, maxvel, minacc, maxacc, minexptime, maxexptime,
1568 minsize, maxsize, collisiondetection, collision_removal,
1569 object_collision, attached_id, vertical, texture, id,
1575 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1577 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1578 << minacc << maxacc << minexptime << maxexptime << minsize
1579 << maxsize << collisiondetection;
1581 pkt.putLongString(texture);
1583 pkt << id << vertical;
1584 pkt << collision_removal;
1586 // This is horrible but required
1587 std::ostringstream os(std::ios_base::binary);
1588 animation.serialize(os, protocol_version);
1589 pkt.putRawString(os.str());
1591 pkt << object_collision;
1596 void Server::SendDeleteParticleSpawner(session_t peer_id, u32 id)
1598 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER, 4, peer_id);
1600 // Ugly error in this packet
1603 if (peer_id != PEER_ID_INEXISTENT)
1606 m_clients.sendToAll(&pkt);
1610 void Server::SendHUDAdd(session_t peer_id, u32 id, HudElement *form)
1612 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1614 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1615 << form->text << form->number << form->item << form->dir
1616 << form->align << form->offset << form->world_pos << form->size;
1621 void Server::SendHUDRemove(session_t peer_id, u32 id)
1623 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1628 void Server::SendHUDChange(session_t peer_id, u32 id, HudElementStat stat, void *value)
1630 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1631 pkt << id << (u8) stat;
1635 case HUD_STAT_SCALE:
1636 case HUD_STAT_ALIGN:
1637 case HUD_STAT_OFFSET:
1638 pkt << *(v2f *) value;
1642 pkt << *(std::string *) value;
1644 case HUD_STAT_WORLD_POS:
1645 pkt << *(v3f *) value;
1648 pkt << *(v2s32 *) value;
1650 case HUD_STAT_NUMBER:
1654 pkt << *(u32 *) value;
1661 void Server::SendHUDSetFlags(session_t peer_id, u32 flags, u32 mask)
1663 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1665 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1667 pkt << flags << mask;
1672 void Server::SendHUDSetParam(session_t peer_id, u16 param, const std::string &value)
1674 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1675 pkt << param << value;
1679 void Server::SendSetSky(session_t peer_id, const video::SColor &bgcolor,
1680 const std::string &type, const std::vector<std::string> ¶ms,
1683 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1684 pkt << bgcolor << type << (u16) params.size();
1686 for (const std::string ¶m : params)
1694 void Server::SendCloudParams(session_t peer_id, const CloudParams ¶ms)
1696 NetworkPacket pkt(TOCLIENT_CLOUD_PARAMS, 0, peer_id);
1697 pkt << params.density << params.color_bright << params.color_ambient
1698 << params.height << params.thickness << params.speed;
1702 void Server::SendOverrideDayNightRatio(session_t peer_id, bool do_override,
1705 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1708 pkt << do_override << (u16) (ratio * 65535);
1713 void Server::SendTimeOfDay(session_t peer_id, u16 time, f32 time_speed)
1715 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1716 pkt << time << time_speed;
1718 if (peer_id == PEER_ID_INEXISTENT) {
1719 m_clients.sendToAll(&pkt);
1726 void Server::SendPlayerHP(session_t peer_id)
1728 PlayerSAO *playersao = getPlayerSAO(peer_id);
1729 // In some rare case if the player is disconnected
1730 // while Lua call l_punch, for example, this can be NULL
1734 SendHP(peer_id, playersao->getHP());
1735 m_script->player_event(playersao,"health_changed");
1737 // Send to other clients
1738 std::string str = gob_cmd_punched(playersao->getHP());
1739 ActiveObjectMessage aom(playersao->getId(), true, str);
1740 playersao->m_messages_out.push(aom);
1743 void Server::SendPlayerBreath(PlayerSAO *sao)
1747 m_script->player_event(sao, "breath_changed");
1748 SendBreath(sao->getPeerID(), sao->getBreath());
1751 void Server::SendMovePlayer(session_t peer_id)
1753 RemotePlayer *player = m_env->getPlayer(peer_id);
1755 PlayerSAO *sao = player->getPlayerSAO();
1758 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1759 pkt << sao->getBasePosition() << sao->getLookPitch() << sao->getRotation().Y;
1762 v3f pos = sao->getBasePosition();
1763 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1764 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1765 << " pitch=" << sao->getLookPitch()
1766 << " yaw=" << sao->getRotation().Y
1773 void Server::SendPlayerFov(session_t peer_id)
1775 NetworkPacket pkt(TOCLIENT_FOV, 4 + 1, peer_id);
1777 PlayerFovSpec fov_spec = m_env->getPlayer(peer_id)->getFov();
1778 pkt << fov_spec.fov << fov_spec.is_multiplier;
1783 void Server::SendLocalPlayerAnimations(session_t peer_id, v2s32 animation_frames[4],
1784 f32 animation_speed)
1786 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1789 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1790 << animation_frames[3] << animation_speed;
1795 void Server::SendEyeOffset(session_t peer_id, v3f first, v3f third)
1797 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1798 pkt << first << third;
1802 void Server::SendPlayerPrivileges(session_t peer_id)
1804 RemotePlayer *player = m_env->getPlayer(peer_id);
1806 if(player->getPeerId() == PEER_ID_INEXISTENT)
1809 std::set<std::string> privs;
1810 m_script->getAuth(player->getName(), NULL, &privs);
1812 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1813 pkt << (u16) privs.size();
1815 for (const std::string &priv : privs) {
1822 void Server::SendPlayerInventoryFormspec(session_t peer_id)
1824 RemotePlayer *player = m_env->getPlayer(peer_id);
1826 if (player->getPeerId() == PEER_ID_INEXISTENT)
1829 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1830 pkt.putLongString(player->inventory_formspec);
1835 void Server::SendPlayerFormspecPrepend(session_t peer_id)
1837 RemotePlayer *player = m_env->getPlayer(peer_id);
1839 if (player->getPeerId() == PEER_ID_INEXISTENT)
1842 NetworkPacket pkt(TOCLIENT_FORMSPEC_PREPEND, 0, peer_id);
1843 pkt << player->formspec_prepend;
1847 void Server::SendActiveObjectRemoveAdd(RemoteClient *client, PlayerSAO *playersao)
1849 // Radius inside which objects are active
1850 static thread_local const s16 radius =
1851 g_settings->getS16("active_object_send_range_blocks") * MAP_BLOCKSIZE;
1853 // Radius inside which players are active
1854 static thread_local const bool is_transfer_limited =
1855 g_settings->exists("unlimited_player_transfer_distance") &&
1856 !g_settings->getBool("unlimited_player_transfer_distance");
1858 static thread_local const s16 player_transfer_dist =
1859 g_settings->getS16("player_transfer_distance") * MAP_BLOCKSIZE;
1861 s16 player_radius = player_transfer_dist == 0 && is_transfer_limited ?
1862 radius : player_transfer_dist;
1864 s16 my_radius = MYMIN(radius, playersao->getWantedRange() * MAP_BLOCKSIZE);
1868 std::queue<u16> removed_objects, added_objects;
1869 m_env->getRemovedActiveObjects(playersao, my_radius, player_radius,
1870 client->m_known_objects, removed_objects);
1871 m_env->getAddedActiveObjects(playersao, my_radius, player_radius,
1872 client->m_known_objects, added_objects);
1874 int removed_count = removed_objects.size();
1875 int added_count = added_objects.size();
1877 if (removed_objects.empty() && added_objects.empty())
1883 // Handle removed objects
1884 writeU16((u8*)buf, removed_objects.size());
1885 data.append(buf, 2);
1886 while (!removed_objects.empty()) {
1888 u16 id = removed_objects.front();
1889 ServerActiveObject* obj = m_env->getActiveObject(id);
1891 // Add to data buffer for sending
1892 writeU16((u8*)buf, id);
1893 data.append(buf, 2);
1895 // Remove from known objects
1896 client->m_known_objects.erase(id);
1898 if (obj && obj->m_known_by_count > 0)
1899 obj->m_known_by_count--;
1901 removed_objects.pop();
1904 // Handle added objects
1905 writeU16((u8*)buf, added_objects.size());
1906 data.append(buf, 2);
1907 while (!added_objects.empty()) {
1909 u16 id = added_objects.front();
1910 ServerActiveObject* obj = m_env->getActiveObject(id);
1913 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1915 warningstream << FUNCTION_NAME << ": NULL object" << std::endl;
1917 type = obj->getSendType();
1919 // Add to data buffer for sending
1920 writeU16((u8*)buf, id);
1921 data.append(buf, 2);
1922 writeU8((u8*)buf, type);
1923 data.append(buf, 1);
1926 data.append(serializeLongString(
1927 obj->getClientInitializationData(client->net_proto_version)));
1929 data.append(serializeLongString(""));
1931 // Add to known objects
1932 client->m_known_objects.insert(id);
1935 obj->m_known_by_count++;
1937 added_objects.pop();
1940 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, data.size(), client->peer_id);
1941 pkt.putRawString(data.c_str(), data.size());
1944 verbosestream << "Server::SendActiveObjectRemoveAdd: "
1945 << removed_count << " removed, " << added_count << " added, "
1946 << "packet size is " << pkt.getSize() << std::endl;
1949 void Server::SendActiveObjectMessages(session_t peer_id, const std::string &datas,
1952 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
1953 datas.size(), peer_id);
1955 pkt.putRawString(datas.c_str(), datas.size());
1957 m_clients.send(pkt.getPeerId(),
1958 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
1962 void Server::SendCSMRestrictionFlags(session_t peer_id)
1964 NetworkPacket pkt(TOCLIENT_CSM_RESTRICTION_FLAGS,
1965 sizeof(m_csm_restriction_flags) + sizeof(m_csm_restriction_noderange), peer_id);
1966 pkt << m_csm_restriction_flags << m_csm_restriction_noderange;
1970 void Server::SendPlayerSpeed(session_t peer_id, const v3f &added_vel)
1972 NetworkPacket pkt(TOCLIENT_PLAYER_SPEED, 0, peer_id);
1977 s32 Server::playSound(const SimpleSoundSpec &spec,
1978 const ServerSoundParams ¶ms)
1980 // Find out initial position of sound
1981 bool pos_exists = false;
1982 v3f pos = params.getPos(m_env, &pos_exists);
1983 // If position is not found while it should be, cancel sound
1984 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
1987 // Filter destination clients
1988 std::vector<session_t> dst_clients;
1989 if(!params.to_player.empty()) {
1990 RemotePlayer *player = m_env->getPlayer(params.to_player.c_str());
1992 infostream<<"Server::playSound: Player \""<<params.to_player
1993 <<"\" not found"<<std::endl;
1996 if (player->getPeerId() == PEER_ID_INEXISTENT) {
1997 infostream<<"Server::playSound: Player \""<<params.to_player
1998 <<"\" not connected"<<std::endl;
2001 dst_clients.push_back(player->getPeerId());
2003 std::vector<session_t> clients = m_clients.getClientIDs();
2005 for (const session_t client_id : clients) {
2006 RemotePlayer *player = m_env->getPlayer(client_id);
2010 PlayerSAO *sao = player->getPlayerSAO();
2015 if(sao->getBasePosition().getDistanceFrom(pos) >
2016 params.max_hear_distance)
2019 dst_clients.push_back(client_id);
2023 if(dst_clients.empty())
2027 s32 id = m_next_sound_id++;
2028 // The sound will exist as a reference in m_playing_sounds
2029 m_playing_sounds[id] = ServerPlayingSound();
2030 ServerPlayingSound &psound = m_playing_sounds[id];
2031 psound.params = params;
2034 float gain = params.gain * spec.gain;
2035 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2036 pkt << id << spec.name << gain
2037 << (u8) params.type << pos << params.object
2038 << params.loop << params.fade << params.pitch;
2040 // Backwards compability
2041 bool play_sound = gain > 0;
2043 for (const u16 dst_client : dst_clients) {
2044 if (play_sound || m_clients.getProtocolVersion(dst_client) >= 32) {
2045 psound.clients.insert(dst_client);
2046 m_clients.send(dst_client, 0, &pkt, true);
2051 void Server::stopSound(s32 handle)
2053 // Get sound reference
2054 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2055 m_playing_sounds.find(handle);
2056 if (i == m_playing_sounds.end())
2058 ServerPlayingSound &psound = i->second;
2060 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2063 for (std::unordered_set<session_t>::const_iterator si = psound.clients.begin();
2064 si != psound.clients.end(); ++si) {
2066 m_clients.send(*si, 0, &pkt, true);
2068 // Remove sound reference
2069 m_playing_sounds.erase(i);
2072 void Server::fadeSound(s32 handle, float step, float gain)
2074 // Get sound reference
2075 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2076 m_playing_sounds.find(handle);
2077 if (i == m_playing_sounds.end())
2080 ServerPlayingSound &psound = i->second;
2081 psound.params.gain = gain;
2083 NetworkPacket pkt(TOCLIENT_FADE_SOUND, 4);
2084 pkt << handle << step << gain;
2086 // Backwards compability
2087 bool play_sound = gain > 0;
2088 ServerPlayingSound compat_psound = psound;
2089 compat_psound.clients.clear();
2091 NetworkPacket compat_pkt(TOCLIENT_STOP_SOUND, 4);
2092 compat_pkt << handle;
2094 for (std::unordered_set<u16>::iterator it = psound.clients.begin();
2095 it != psound.clients.end();) {
2096 if (m_clients.getProtocolVersion(*it) >= 32) {
2098 m_clients.send(*it, 0, &pkt, true);
2101 compat_psound.clients.insert(*it);
2103 m_clients.send(*it, 0, &compat_pkt, true);
2104 psound.clients.erase(it++);
2108 // Remove sound reference
2109 if (!play_sound || psound.clients.empty())
2110 m_playing_sounds.erase(i);
2112 if (play_sound && !compat_psound.clients.empty()) {
2113 // Play new sound volume on older clients
2114 playSound(compat_psound.spec, compat_psound.params);
2118 void Server::sendRemoveNode(v3s16 p, std::unordered_set<u16> *far_players,
2121 float maxd = far_d_nodes * BS;
2122 v3f p_f = intToFloat(p, BS);
2123 v3s16 block_pos = getNodeBlockPos(p);
2125 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2128 std::vector<session_t> clients = m_clients.getClientIDs();
2131 for (session_t client_id : clients) {
2132 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
2136 RemotePlayer *player = m_env->getPlayer(client_id);
2137 PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr;
2139 // If player is far away, only set modified blocks not sent
2140 if (!client->isBlockSent(block_pos) || (sao &&
2141 sao->getBasePosition().getDistanceFrom(p_f) > maxd)) {
2143 far_players->emplace(client_id);
2145 client->SetBlockNotSent(block_pos);
2150 m_clients.send(client_id, 0, &pkt, true);
2156 void Server::sendAddNode(v3s16 p, MapNode n, std::unordered_set<u16> *far_players,
2157 float far_d_nodes, bool remove_metadata)
2159 float maxd = far_d_nodes * BS;
2160 v3f p_f = intToFloat(p, BS);
2161 v3s16 block_pos = getNodeBlockPos(p);
2163 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2164 pkt << p << n.param0 << n.param1 << n.param2
2165 << (u8) (remove_metadata ? 0 : 1);
2167 std::vector<session_t> clients = m_clients.getClientIDs();
2170 for (session_t client_id : clients) {
2171 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
2175 RemotePlayer *player = m_env->getPlayer(client_id);
2176 PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr;
2178 // If player is far away, only set modified blocks not sent
2179 if (!client->isBlockSent(block_pos) || (sao &&
2180 sao->getBasePosition().getDistanceFrom(p_f) > maxd)) {
2182 far_players->emplace(client_id);
2184 client->SetBlockNotSent(block_pos);
2189 m_clients.send(client_id, 0, &pkt, true);
2195 void Server::sendMetadataChanged(const std::list<v3s16> &meta_updates, float far_d_nodes)
2197 float maxd = far_d_nodes * BS;
2198 NodeMetadataList meta_updates_list(false);
2199 std::vector<session_t> clients = m_clients.getClientIDs();
2203 for (session_t i : clients) {
2204 RemoteClient *client = m_clients.lockedGetClientNoEx(i);
2208 ServerActiveObject *player = m_env->getActiveObject(i);
2209 v3f player_pos = player ? player->getBasePosition() : v3f();
2211 for (const v3s16 &pos : meta_updates) {
2212 NodeMetadata *meta = m_env->getMap().getNodeMetadata(pos);
2217 v3s16 block_pos = getNodeBlockPos(pos);
2218 if (!client->isBlockSent(block_pos) || (player &&
2219 player_pos.getDistanceFrom(intToFloat(pos, BS)) > maxd)) {
2220 client->SetBlockNotSent(block_pos);
2224 // Add the change to send list
2225 meta_updates_list.set(pos, meta);
2227 if (meta_updates_list.size() == 0)
2230 // Send the meta changes
2231 std::ostringstream os(std::ios::binary);
2232 meta_updates_list.serialize(os, client->net_proto_version, false, true);
2233 std::ostringstream oss(std::ios::binary);
2234 compressZlib(os.str(), oss);
2236 NetworkPacket pkt(TOCLIENT_NODEMETA_CHANGED, 0);
2237 pkt.putLongString(oss.str());
2238 m_clients.send(i, 0, &pkt, true);
2240 meta_updates_list.clear();
2246 void Server::SendBlockNoLock(session_t peer_id, MapBlock *block, u8 ver,
2247 u16 net_proto_version)
2250 Create a packet with the block in the right format
2253 std::ostringstream os(std::ios_base::binary);
2254 block->serialize(os, ver, false);
2255 block->serializeNetworkSpecific(os);
2256 std::string s = os.str();
2258 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2260 pkt << block->getPos();
2261 pkt.putRawString(s.c_str(), s.size());
2265 void Server::SendBlocks(float dtime)
2267 MutexAutoLock envlock(m_env_mutex);
2268 //TODO check if one big lock could be faster then multiple small ones
2270 std::vector<PrioritySortedBlockTransfer> queue;
2272 u32 total_sending = 0;
2275 ScopeProfiler sp2(g_profiler, "Server::SendBlocks(): Collect list");
2277 std::vector<session_t> clients = m_clients.getClientIDs();
2280 for (const session_t client_id : clients) {
2281 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id, CS_Active);
2286 total_sending += client->getSendingCount();
2287 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2293 // Lowest priority number comes first.
2294 // Lowest is most important.
2295 std::sort(queue.begin(), queue.end());
2299 // Maximal total count calculation
2300 // The per-client block sends is halved with the maximal online users
2301 u32 max_blocks_to_send = (m_env->getPlayerCount() + g_settings->getU32("max_users")) *
2302 g_settings->getU32("max_simultaneous_block_sends_per_client") / 4 + 1;
2304 ScopeProfiler sp(g_profiler, "Server::SendBlocks(): Send to clients");
2305 Map &map = m_env->getMap();
2307 for (const PrioritySortedBlockTransfer &block_to_send : queue) {
2308 if (total_sending >= max_blocks_to_send)
2311 MapBlock *block = map.getBlockNoCreateNoEx(block_to_send.pos);
2315 RemoteClient *client = m_clients.lockedGetClientNoEx(block_to_send.peer_id,
2320 SendBlockNoLock(block_to_send.peer_id, block, client->serialization_version,
2321 client->net_proto_version);
2323 client->SentBlock(block_to_send.pos);
2329 bool Server::SendBlock(session_t peer_id, const v3s16 &blockpos)
2331 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2336 RemoteClient *client = m_clients.lockedGetClientNoEx(peer_id, CS_Active);
2337 if (!client || client->isBlockSent(blockpos)) {
2341 SendBlockNoLock(peer_id, block, client->serialization_version,
2342 client->net_proto_version);
2348 void Server::fillMediaCache()
2350 infostream<<"Server: Calculating media file checksums"<<std::endl;
2352 // Collect all media file paths
2353 std::vector<std::string> paths;
2354 m_modmgr->getModsMediaPaths(paths);
2355 fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures");
2356 fs::GetRecursiveDirs(paths, porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2358 // Collect media file information from paths into cache
2359 for (const std::string &mediapath : paths) {
2360 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2361 for (const fs::DirListNode &dln : dirlist) {
2362 if (dln.dir) // Ignode dirs
2364 std::string filename = dln.name;
2365 // If name contains illegal characters, ignore the file
2366 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2367 infostream<<"Server: ignoring illegal file name: \""
2368 << filename << "\"" << std::endl;
2371 // If name is not in a supported format, ignore it
2372 const char *supported_ext[] = {
2373 ".png", ".jpg", ".bmp", ".tga",
2374 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2376 ".x", ".b3d", ".md2", ".obj",
2377 // Custom translation file format
2381 if (removeStringEnd(filename, supported_ext).empty()){
2382 infostream << "Server: ignoring unsupported file extension: \""
2383 << filename << "\"" << std::endl;
2386 // Ok, attempt to load the file and add to cache
2387 std::string filepath;
2388 filepath.append(mediapath).append(DIR_DELIM).append(filename);
2391 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2393 errorstream << "Server::fillMediaCache(): Could not open \""
2394 << filename << "\" for reading" << std::endl;
2397 std::ostringstream tmp_os(std::ios_base::binary);
2401 fis.read(buf, 1024);
2402 std::streamsize len = fis.gcount();
2403 tmp_os.write(buf, len);
2412 errorstream<<"Server::fillMediaCache(): Failed to read \""
2413 << filename << "\"" << std::endl;
2416 if(tmp_os.str().length() == 0) {
2417 errorstream << "Server::fillMediaCache(): Empty file \""
2418 << filepath << "\"" << std::endl;
2423 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2425 unsigned char *digest = sha1.getDigest();
2426 std::string sha1_base64 = base64_encode(digest, 20);
2427 std::string sha1_hex = hex_encode((char*)digest, 20);
2431 m_media[filename] = MediaInfo(filepath, sha1_base64);
2432 verbosestream << "Server: " << sha1_hex << " is " << filename
2438 void Server::sendMediaAnnouncement(session_t peer_id, const std::string &lang_code)
2440 verbosestream << "Server: Announcing files to id(" << peer_id << ")"
2444 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2447 std::string lang_suffix;
2448 lang_suffix.append(".").append(lang_code).append(".tr");
2449 for (const auto &i : m_media) {
2450 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2457 for (const auto &i : m_media) {
2458 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2460 pkt << i.first << i.second.sha1_digest;
2463 pkt << g_settings->get("remote_media");
2467 struct SendableMedia
2473 SendableMedia(const std::string &name_="", const std::string &path_="",
2474 const std::string &data_=""):
2481 void Server::sendRequestedMedia(session_t peer_id,
2482 const std::vector<std::string> &tosend)
2484 verbosestream<<"Server::sendRequestedMedia(): "
2485 <<"Sending files to client"<<std::endl;
2489 // Put 5kB in one bunch (this is not accurate)
2490 u32 bytes_per_bunch = 5000;
2492 std::vector< std::vector<SendableMedia> > file_bunches;
2493 file_bunches.emplace_back();
2495 u32 file_size_bunch_total = 0;
2497 for (const std::string &name : tosend) {
2498 if (m_media.find(name) == m_media.end()) {
2499 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2500 <<"unknown file \""<<(name)<<"\""<<std::endl;
2504 //TODO get path + name
2505 std::string tpath = m_media[name].path;
2508 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2510 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2511 <<tpath<<"\" for reading"<<std::endl;
2514 std::ostringstream tmp_os(std::ios_base::binary);
2518 fis.read(buf, 1024);
2519 std::streamsize len = fis.gcount();
2520 tmp_os.write(buf, len);
2521 file_size_bunch_total += len;
2530 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2531 <<name<<"\""<<std::endl;
2534 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2535 <<tname<<"\""<<std::endl;*/
2537 file_bunches[file_bunches.size()-1].emplace_back(name, tpath, tmp_os.str());
2539 // Start next bunch if got enough data
2540 if(file_size_bunch_total >= bytes_per_bunch) {
2541 file_bunches.emplace_back();
2542 file_size_bunch_total = 0;
2547 /* Create and send packets */
2549 u16 num_bunches = file_bunches.size();
2550 for (u16 i = 0; i < num_bunches; i++) {
2553 u16 total number of texture bunches
2554 u16 index of this bunch
2555 u32 number of files in this bunch
2564 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2565 pkt << num_bunches << i << (u32) file_bunches[i].size();
2567 for (const SendableMedia &j : file_bunches[i]) {
2569 pkt.putLongString(j.data);
2572 verbosestream << "Server::sendRequestedMedia(): bunch "
2573 << i << "/" << num_bunches
2574 << " files=" << file_bunches[i].size()
2575 << " size=" << pkt.getSize() << std::endl;
2580 void Server::sendDetachedInventory(const std::string &name, session_t peer_id)
2582 const auto &inv_it = m_detached_inventories.find(name);
2583 const auto &player_it = m_detached_inventories_player.find(name);
2585 if (player_it == m_detached_inventories_player.end() ||
2586 player_it->second.empty()) {
2587 // OK. Send to everyone
2590 return; // Mods are not done loading
2592 RemotePlayer *p = m_env->getPlayer(player_it->second.c_str());
2594 return; // Player is offline
2596 if (peer_id != PEER_ID_INEXISTENT && peer_id != p->getPeerId())
2597 return; // Caller requested send to a different player, so don't send.
2599 peer_id = p->getPeerId();
2602 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2605 if (inv_it == m_detached_inventories.end()) {
2606 pkt << false; // Remove inventory
2608 pkt << true; // Update inventory
2610 // Serialization & NetworkPacket isn't a love story
2611 std::ostringstream os(std::ios_base::binary);
2612 inv_it->second->serialize(os);
2613 inv_it->second->setModified(false);
2615 const std::string &os_str = os.str();
2616 pkt << static_cast<u16>(os_str.size()); // HACK: to keep compatibility with 5.0.0 clients
2617 pkt.putRawString(os_str);
2620 if (peer_id == PEER_ID_INEXISTENT)
2621 m_clients.sendToAll(&pkt);
2626 void Server::sendDetachedInventories(session_t peer_id, bool incremental)
2628 for (const auto &detached_inventory : m_detached_inventories) {
2629 const std::string &name = detached_inventory.first;
2631 Inventory *inv = detached_inventory.second;
2632 if (!inv || !inv->checkModified())
2636 sendDetachedInventory(name, peer_id);
2644 void Server::DiePlayer(session_t peer_id, const PlayerHPChangeReason &reason)
2646 PlayerSAO *playersao = getPlayerSAO(peer_id);
2647 // In some rare cases this can be NULL -- if the player is disconnected
2648 // when a Lua function modifies l_punch, for example
2652 infostream << "Server::DiePlayer(): Player "
2653 << playersao->getPlayer()->getName()
2654 << " dies" << std::endl;
2656 playersao->setHP(0, reason);
2657 playersao->clearParentAttachment();
2659 // Trigger scripted stuff
2660 m_script->on_dieplayer(playersao, reason);
2662 SendPlayerHP(peer_id);
2663 SendDeathscreen(peer_id, false, v3f(0,0,0));
2666 void Server::RespawnPlayer(session_t peer_id)
2668 PlayerSAO *playersao = getPlayerSAO(peer_id);
2671 infostream << "Server::RespawnPlayer(): Player "
2672 << playersao->getPlayer()->getName()
2673 << " respawns" << std::endl;
2675 playersao->setHP(playersao->accessObjectProperties()->hp_max,
2676 PlayerHPChangeReason(PlayerHPChangeReason::RESPAWN));
2677 playersao->setBreath(playersao->accessObjectProperties()->breath_max);
2679 bool repositioned = m_script->on_respawnplayer(playersao);
2680 if (!repositioned) {
2681 // setPos will send the new position to client
2682 playersao->setPos(findSpawnPos());
2685 SendPlayerHP(peer_id);
2689 void Server::DenySudoAccess(session_t peer_id)
2691 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2696 void Server::DenyAccessVerCompliant(session_t peer_id, u16 proto_ver, AccessDeniedCode reason,
2697 const std::string &str_reason, bool reconnect)
2699 SendAccessDenied(peer_id, reason, str_reason, reconnect);
2701 m_clients.event(peer_id, CSE_SetDenied);
2702 DisconnectPeer(peer_id);
2706 void Server::DenyAccess(session_t peer_id, AccessDeniedCode reason,
2707 const std::string &custom_reason)
2709 SendAccessDenied(peer_id, reason, custom_reason);
2710 m_clients.event(peer_id, CSE_SetDenied);
2711 DisconnectPeer(peer_id);
2714 // 13/03/15: remove this function when protocol version 25 will become
2715 // the minimum version for MT users, maybe in 1 year
2716 void Server::DenyAccess_Legacy(session_t peer_id, const std::wstring &reason)
2718 SendAccessDenied_Legacy(peer_id, reason);
2719 m_clients.event(peer_id, CSE_SetDenied);
2720 DisconnectPeer(peer_id);
2723 void Server::DisconnectPeer(session_t peer_id)
2725 m_modchannel_mgr->leaveAllChannels(peer_id);
2726 m_con->DisconnectPeer(peer_id);
2729 void Server::acceptAuth(session_t peer_id, bool forSudoMode)
2732 RemoteClient* client = getClient(peer_id, CS_Invalid);
2734 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2736 // Right now, the auth mechs don't change between login and sudo mode.
2737 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2738 client->allowed_sudo_mechs = sudo_auth_mechs;
2740 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2741 << g_settings->getFloat("dedicated_server_step")
2745 m_clients.event(peer_id, CSE_AuthAccept);
2747 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2749 // We only support SRP right now
2750 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2752 resp_pkt << sudo_auth_mechs;
2754 m_clients.event(peer_id, CSE_SudoSuccess);
2758 void Server::DeleteClient(session_t peer_id, ClientDeletionReason reason)
2760 std::wstring message;
2763 Clear references to playing sounds
2765 for (std::unordered_map<s32, ServerPlayingSound>::iterator
2766 i = m_playing_sounds.begin(); i != m_playing_sounds.end();) {
2767 ServerPlayingSound &psound = i->second;
2768 psound.clients.erase(peer_id);
2769 if (psound.clients.empty())
2770 m_playing_sounds.erase(i++);
2775 // clear formspec info so the next client can't abuse the current state
2776 m_formspec_state_data.erase(peer_id);
2778 RemotePlayer *player = m_env->getPlayer(peer_id);
2780 /* Run scripts and remove from environment */
2782 PlayerSAO *playersao = player->getPlayerSAO();
2785 playersao->clearChildAttachments();
2786 playersao->clearParentAttachment();
2788 // inform connected clients
2789 const std::string &player_name = player->getName();
2790 NetworkPacket notice(TOCLIENT_UPDATE_PLAYER_LIST, 0, PEER_ID_INEXISTENT);
2791 // (u16) 1 + std::string represents a vector serialization representation
2792 notice << (u8) PLAYER_LIST_REMOVE << (u16) 1 << player_name;
2793 m_clients.sendToAll(¬ice);
2795 m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
2797 playersao->disconnected();
2804 if (player && reason != CDR_DENY) {
2805 std::ostringstream os(std::ios_base::binary);
2806 std::vector<session_t> clients = m_clients.getClientIDs();
2808 for (const session_t client_id : clients) {
2810 RemotePlayer *player = m_env->getPlayer(client_id);
2814 // Get name of player
2815 os << player->getName() << " ";
2818 std::string name = player->getName();
2819 actionstream << name << " "
2820 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2821 << " List of players: " << os.str() << std::endl;
2823 m_admin_chat->outgoing_queue.push_back(
2824 new ChatEventNick(CET_NICK_REMOVE, name));
2828 MutexAutoLock env_lock(m_env_mutex);
2829 m_clients.DeleteClient(peer_id);
2833 // Send leave chat message to all remaining clients
2834 if (!message.empty()) {
2835 SendChatMessage(PEER_ID_INEXISTENT,
2836 ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE, message));
2840 void Server::UpdateCrafting(RemotePlayer *player)
2842 InventoryList *clist = player->inventory.getList("craft");
2843 if (!clist || clist->getSize() == 0)
2846 if (!clist->checkModified()) {
2847 verbosestream << "Skip Server::UpdateCrafting(): list unmodified" << std::endl;
2851 // Get a preview for crafting
2853 InventoryLocation loc;
2854 loc.setPlayer(player->getName());
2855 std::vector<ItemStack> output_replacements;
2856 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2857 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(),
2860 InventoryList *plist = player->inventory.getList("craftpreview");
2861 if (plist && plist->getSize() >= 1) {
2862 // Put the new preview in
2863 plist->changeItem(0, preview);
2867 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2869 if (evt->type == CET_NICK_ADD) {
2870 // The terminal informed us of its nick choice
2871 m_admin_nick = ((ChatEventNick *)evt)->nick;
2872 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2873 errorstream << "You haven't set up an account." << std::endl
2874 << "Please log in using the client as '"
2875 << m_admin_nick << "' with a secure password." << std::endl
2876 << "Until then, you can't execute admin tasks via the console," << std::endl
2877 << "and everybody can claim the user account instead of you," << std::endl
2878 << "giving them full control over this server." << std::endl;
2881 assert(evt->type == CET_CHAT);
2882 handleAdminChat((ChatEventChat *)evt);
2886 std::wstring Server::handleChat(const std::string &name, const std::wstring &wname,
2887 std::wstring wmessage, bool check_shout_priv, RemotePlayer *player)
2889 // If something goes wrong, this player is to blame
2890 RollbackScopeActor rollback_scope(m_rollback,
2891 std::string("player:") + name);
2893 if (g_settings->getBool("strip_color_codes"))
2894 wmessage = unescape_enriched(wmessage);
2897 switch (player->canSendChatMessage()) {
2898 case RPLAYER_CHATRESULT_FLOODING: {
2899 std::wstringstream ws;
2900 ws << L"You cannot send more messages. You are limited to "
2901 << g_settings->getFloat("chat_message_limit_per_10sec")
2902 << L" messages per 10 seconds.";
2905 case RPLAYER_CHATRESULT_KICK:
2906 DenyAccess_Legacy(player->getPeerId(),
2907 L"You have been kicked due to message flooding.");
2909 case RPLAYER_CHATRESULT_OK:
2912 FATAL_ERROR("Unhandled chat filtering result found.");
2916 if (m_max_chatmessage_length > 0
2917 && wmessage.length() > m_max_chatmessage_length) {
2918 return L"Your message exceed the maximum chat message limit set on the server. "
2919 L"It was refused. Send a shorter message";
2922 auto message = trim(wide_to_utf8(wmessage));
2923 if (message.find_first_of("\n\r") != std::wstring::npos) {
2924 return L"New lines are not permitted in chat messages";
2927 // Run script hook, exit if script ate the chat message
2928 if (m_script->on_chat_message(name, message))
2933 // Whether to send line to the player that sent the message, or to all players
2934 bool broadcast_line = true;
2936 if (check_shout_priv && !checkPriv(name, "shout")) {
2937 line += L"-!- You don't have permission to shout.";
2938 broadcast_line = false;
2940 line += narrow_to_wide(m_script->formatChatMessage(name,
2941 wide_to_narrow(wmessage)));
2945 Tell calling method to send the message to sender
2947 if (!broadcast_line)
2951 Send the message to others
2953 actionstream << "CHAT: " << wide_to_narrow(unescape_enriched(line)) << std::endl;
2955 std::vector<session_t> clients = m_clients.getClientIDs();
2958 Send the message back to the inital sender
2959 if they are using protocol version >= 29
2962 session_t peer_id_to_avoid_sending =
2963 (player ? player->getPeerId() : PEER_ID_INEXISTENT);
2965 if (player && player->protocol_version >= 29)
2966 peer_id_to_avoid_sending = PEER_ID_INEXISTENT;
2968 for (u16 cid : clients) {
2969 if (cid != peer_id_to_avoid_sending)
2970 SendChatMessage(cid, ChatMessage(line));
2975 void Server::handleAdminChat(const ChatEventChat *evt)
2977 std::string name = evt->nick;
2978 std::wstring wname = utf8_to_wide(name);
2979 std::wstring wmessage = evt->evt_msg;
2981 std::wstring answer = handleChat(name, wname, wmessage);
2983 // If asked to send answer to sender
2984 if (!answer.empty()) {
2985 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
2989 RemoteClient *Server::getClient(session_t peer_id, ClientState state_min)
2991 RemoteClient *client = getClientNoEx(peer_id,state_min);
2993 throw ClientNotFoundException("Client not found");
2997 RemoteClient *Server::getClientNoEx(session_t peer_id, ClientState state_min)
2999 return m_clients.getClientNoEx(peer_id, state_min);
3002 std::string Server::getPlayerName(session_t peer_id)
3004 RemotePlayer *player = m_env->getPlayer(peer_id);
3006 return "[id="+itos(peer_id)+"]";
3007 return player->getName();
3010 PlayerSAO *Server::getPlayerSAO(session_t peer_id)
3012 RemotePlayer *player = m_env->getPlayer(peer_id);
3015 return player->getPlayerSAO();
3018 std::wstring Server::getStatusString()
3020 std::wostringstream os(std::ios_base::binary);
3021 os << L"# Server: ";
3023 os << L"version=" << narrow_to_wide(g_version_string);
3025 os << L", uptime=" << m_uptime.get();
3027 os << L", max_lag=" << (m_env ? m_env->getMaxLagEstimate() : 0);
3029 // Information about clients
3031 os << L", clients={";
3033 std::vector<session_t> clients = m_clients.getClientIDs();
3034 for (session_t client_id : clients) {
3035 RemotePlayer *player = m_env->getPlayer(client_id);
3037 // Get name of player
3038 std::wstring name = L"unknown";
3040 name = narrow_to_wide(player->getName());
3042 // Add name to information string
3053 if (m_env && !((ServerMap*)(&m_env->getMap()))->isSavingEnabled())
3054 os << std::endl << L"# Server: " << " WARNING: Map saving is disabled.";
3056 if (!g_settings->get("motd").empty())
3057 os << std::endl << L"# Server: " << narrow_to_wide(g_settings->get("motd"));
3062 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
3064 std::set<std::string> privs;
3065 m_script->getAuth(name, NULL, &privs);
3069 bool Server::checkPriv(const std::string &name, const std::string &priv)
3071 std::set<std::string> privs = getPlayerEffectivePrivs(name);
3072 return (privs.count(priv) != 0);
3075 void Server::reportPrivsModified(const std::string &name)
3078 std::vector<session_t> clients = m_clients.getClientIDs();
3079 for (const session_t client_id : clients) {
3080 RemotePlayer *player = m_env->getPlayer(client_id);
3081 reportPrivsModified(player->getName());
3084 RemotePlayer *player = m_env->getPlayer(name.c_str());
3087 SendPlayerPrivileges(player->getPeerId());
3088 PlayerSAO *sao = player->getPlayerSAO();
3091 sao->updatePrivileges(
3092 getPlayerEffectivePrivs(name),
3097 void Server::reportInventoryFormspecModified(const std::string &name)
3099 RemotePlayer *player = m_env->getPlayer(name.c_str());
3102 SendPlayerInventoryFormspec(player->getPeerId());
3105 void Server::reportFormspecPrependModified(const std::string &name)
3107 RemotePlayer *player = m_env->getPlayer(name.c_str());
3110 SendPlayerFormspecPrepend(player->getPeerId());
3113 void Server::setIpBanned(const std::string &ip, const std::string &name)
3115 m_banmanager->add(ip, name);
3118 void Server::unsetIpBanned(const std::string &ip_or_name)
3120 m_banmanager->remove(ip_or_name);
3123 std::string Server::getBanDescription(const std::string &ip_or_name)
3125 return m_banmanager->getBanDescription(ip_or_name);
3128 void Server::notifyPlayer(const char *name, const std::wstring &msg)
3130 // m_env will be NULL if the server is initializing
3134 if (m_admin_nick == name && !m_admin_nick.empty()) {
3135 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
3138 RemotePlayer *player = m_env->getPlayer(name);
3143 if (player->getPeerId() == PEER_ID_INEXISTENT)
3146 SendChatMessage(player->getPeerId(), ChatMessage(msg));
3149 bool Server::showFormspec(const char *playername, const std::string &formspec,
3150 const std::string &formname)
3152 // m_env will be NULL if the server is initializing
3156 RemotePlayer *player = m_env->getPlayer(playername);
3160 SendShowFormspecMessage(player->getPeerId(), formspec, formname);
3164 u32 Server::hudAdd(RemotePlayer *player, HudElement *form)
3169 u32 id = player->addHud(form);
3171 SendHUDAdd(player->getPeerId(), id, form);
3176 bool Server::hudRemove(RemotePlayer *player, u32 id) {
3180 HudElement* todel = player->removeHud(id);
3187 SendHUDRemove(player->getPeerId(), id);
3191 bool Server::hudChange(RemotePlayer *player, u32 id, HudElementStat stat, void *data)
3196 SendHUDChange(player->getPeerId(), id, stat, data);
3200 bool Server::hudSetFlags(RemotePlayer *player, u32 flags, u32 mask)
3205 SendHUDSetFlags(player->getPeerId(), flags, mask);
3206 player->hud_flags &= ~mask;
3207 player->hud_flags |= flags;
3209 PlayerSAO* playersao = player->getPlayerSAO();
3214 m_script->player_event(playersao, "hud_changed");
3218 bool Server::hudSetHotbarItemcount(RemotePlayer *player, s32 hotbar_itemcount)
3223 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3226 player->setHotbarItemcount(hotbar_itemcount);
3227 std::ostringstream os(std::ios::binary);
3228 writeS32(os, hotbar_itemcount);
3229 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3233 void Server::hudSetHotbarImage(RemotePlayer *player, const std::string &name)
3238 player->setHotbarImage(name);
3239 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_IMAGE, name);
3242 void Server::hudSetHotbarSelectedImage(RemotePlayer *player, const std::string &name)
3247 player->setHotbarSelectedImage(name);
3248 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3251 Address Server::getPeerAddress(session_t peer_id)
3253 return m_con->GetPeerAddress(peer_id);
3256 void Server::setLocalPlayerAnimations(RemotePlayer *player,
3257 v2s32 animation_frames[4], f32 frame_speed)
3259 sanity_check(player);
3260 player->setLocalAnimations(animation_frames, frame_speed);
3261 SendLocalPlayerAnimations(player->getPeerId(), animation_frames, frame_speed);
3264 void Server::setPlayerEyeOffset(RemotePlayer *player, const v3f &first, const v3f &third)
3266 sanity_check(player);
3267 player->eye_offset_first = first;
3268 player->eye_offset_third = third;
3269 SendEyeOffset(player->getPeerId(), first, third);
3272 void Server::setSky(RemotePlayer *player, const video::SColor &bgcolor,
3273 const std::string &type, const std::vector<std::string> ¶ms,
3276 sanity_check(player);
3277 player->setSky(bgcolor, type, params, clouds);
3278 SendSetSky(player->getPeerId(), bgcolor, type, params, clouds);
3281 void Server::setClouds(RemotePlayer *player, const CloudParams ¶ms)
3283 sanity_check(player);
3284 player->setCloudParams(params);
3285 SendCloudParams(player->getPeerId(), params);
3288 bool Server::overrideDayNightRatio(RemotePlayer *player, bool do_override,
3294 player->overrideDayNightRatio(do_override, ratio);
3295 SendOverrideDayNightRatio(player->getPeerId(), do_override, ratio);
3299 void Server::notifyPlayers(const std::wstring &msg)
3301 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(msg));
3304 void Server::spawnParticle(const std::string &playername, v3f pos,
3305 v3f velocity, v3f acceleration,
3306 float expirationtime, float size, bool
3307 collisiondetection, bool collision_removal, bool object_collision,
3308 bool vertical, const std::string &texture,
3309 const struct TileAnimationParams &animation, u8 glow)
3311 // m_env will be NULL if the server is initializing
3315 session_t peer_id = PEER_ID_INEXISTENT;
3317 if (!playername.empty()) {
3318 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3321 peer_id = player->getPeerId();
3322 proto_ver = player->protocol_version;
3325 SendSpawnParticle(peer_id, proto_ver, pos, velocity, acceleration,
3326 expirationtime, size, collisiondetection, collision_removal,
3327 object_collision, vertical, texture, animation, glow);
3330 u32 Server::addParticleSpawner(u16 amount, float spawntime,
3331 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
3332 float minexptime, float maxexptime, float minsize, float maxsize,
3333 bool collisiondetection, bool collision_removal, bool object_collision,
3334 ServerActiveObject *attached, bool vertical, const std::string &texture,
3335 const std::string &playername, const struct TileAnimationParams &animation,
3338 // m_env will be NULL if the server is initializing
3342 session_t peer_id = PEER_ID_INEXISTENT;
3344 if (!playername.empty()) {
3345 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3348 peer_id = player->getPeerId();
3349 proto_ver = player->protocol_version;
3352 u16 attached_id = attached ? attached->getId() : 0;
3355 if (attached_id == 0)
3356 id = m_env->addParticleSpawner(spawntime);
3358 id = m_env->addParticleSpawner(spawntime, attached_id);
3360 SendAddParticleSpawner(peer_id, proto_ver, amount, spawntime,
3361 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3362 minexptime, maxexptime, minsize, maxsize, collisiondetection,
3363 collision_removal, object_collision, attached_id, vertical,
3364 texture, id, animation, glow);
3369 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3371 // m_env will be NULL if the server is initializing
3373 throw ServerError("Can't delete particle spawners during initialisation!");
3375 session_t peer_id = PEER_ID_INEXISTENT;
3376 if (!playername.empty()) {
3377 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3380 peer_id = player->getPeerId();
3383 m_env->deleteParticleSpawner(id);
3384 SendDeleteParticleSpawner(peer_id, id);
3387 Inventory* Server::createDetachedInventory(const std::string &name, const std::string &player)
3389 if(m_detached_inventories.count(name) > 0){
3390 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3391 delete m_detached_inventories[name];
3393 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3395 Inventory *inv = new Inventory(m_itemdef);
3397 m_detached_inventories[name] = inv;
3398 if (!player.empty())
3399 m_detached_inventories_player[name] = player;
3401 //TODO find a better way to do this
3402 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3406 bool Server::removeDetachedInventory(const std::string &name)
3408 const auto &inv_it = m_detached_inventories.find(name);
3409 if (inv_it == m_detached_inventories.end())
3412 delete inv_it->second;
3413 m_detached_inventories.erase(inv_it);
3415 if (!m_env) // Mods are not done loading
3418 const auto &player_it = m_detached_inventories_player.find(name);
3419 if (player_it != m_detached_inventories_player.end()) {
3420 RemotePlayer *player = m_env->getPlayer(player_it->second.c_str());
3422 if (player && player->getPeerId() != PEER_ID_INEXISTENT)
3423 sendDetachedInventory(name, player->getPeerId());
3425 m_detached_inventories_player.erase(player_it);
3427 // Notify all players about the change
3428 sendDetachedInventory(name, PEER_ID_INEXISTENT);
3433 // actions: time-reversed list
3434 // Return value: success/failure
3435 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3436 std::list<std::string> *log)
3438 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3439 ServerMap *map = (ServerMap*)(&m_env->getMap());
3441 // Fail if no actions to handle
3442 if (actions.empty()) {
3444 log->push_back("Nothing to do.");
3451 for (const RollbackAction &action : actions) {
3453 bool success = action.applyRevert(map, this, this);
3456 std::ostringstream os;
3457 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3458 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3460 log->push_back(os.str());
3462 std::ostringstream os;
3463 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3464 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3466 log->push_back(os.str());
3470 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3471 <<" failed"<<std::endl;
3473 // Call it done if less than half failed
3474 return num_failed <= num_tried/2;
3477 // IGameDef interface
3479 IItemDefManager *Server::getItemDefManager()
3484 const NodeDefManager *Server::getNodeDefManager()
3489 ICraftDefManager *Server::getCraftDefManager()
3494 u16 Server::allocateUnknownNodeId(const std::string &name)
3496 return m_nodedef->allocateDummy(name);
3499 IWritableItemDefManager *Server::getWritableItemDefManager()
3504 NodeDefManager *Server::getWritableNodeDefManager()
3509 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3514 const std::vector<ModSpec> & Server::getMods() const
3516 return m_modmgr->getMods();
3519 const ModSpec *Server::getModSpec(const std::string &modname) const
3521 return m_modmgr->getModSpec(modname);
3524 void Server::getModNames(std::vector<std::string> &modlist)
3526 m_modmgr->getModNames(modlist);
3529 std::string Server::getBuiltinLuaPath()
3531 return porting::path_share + DIR_DELIM + "builtin";
3534 std::string Server::getModStoragePath() const
3536 return m_path_world + DIR_DELIM + "mod_storage";
3539 v3f Server::findSpawnPos()
3541 ServerMap &map = m_env->getServerMap();
3543 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf))
3544 return nodeposf * BS;
3546 bool is_good = false;
3547 // Limit spawn range to mapgen edges (determined by 'mapgen_limit')
3548 s32 range_max = map.getMapgenParams()->getSpawnRangeMax();
3550 // Try to find a good place a few times
3551 for (s32 i = 0; i < 4000 && !is_good; i++) {
3552 s32 range = MYMIN(1 + i, range_max);
3553 // We're going to try to throw the player to this position
3554 v2s16 nodepos2d = v2s16(
3555 -range + (myrand() % (range * 2)),
3556 -range + (myrand() % (range * 2)));
3557 // Get spawn level at point
3558 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3559 // Continue if MAX_MAP_GENERATION_LIMIT was returned by the mapgen to
3560 // signify an unsuitable spawn position, or if outside limits.
3561 if (spawn_level >= MAX_MAP_GENERATION_LIMIT ||
3562 spawn_level <= -MAX_MAP_GENERATION_LIMIT)
3565 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3566 // Consecutive empty nodes
3569 // Search upwards from 'spawn level' for 2 consecutive empty nodes, to
3570 // avoid obstructions in already-generated mapblocks.
3571 // In ungenerated mapblocks consisting of 'ignore' nodes, there will be
3572 // no obstructions, but mapgen decorations are generated after spawn so
3573 // the player may end up inside one.
3574 for (s32 i = 0; i < 8; i++) {
3575 v3s16 blockpos = getNodeBlockPos(nodepos);
3576 map.emergeBlock(blockpos, true);
3577 content_t c = map.getNode(nodepos).getContent();
3579 // In generated mapblocks allow spawn in all 'airlike' drawtype nodes.
3580 // In ungenerated mapblocks allow spawn in 'ignore' nodes.
3581 if (m_nodedef->get(c).drawtype == NDT_AIRLIKE || c == CONTENT_IGNORE) {
3583 if (air_count >= 2) {
3584 // Spawn in lower empty node
3586 nodeposf = intToFloat(nodepos, BS);
3587 // Don't spawn the player outside map boundaries
3588 if (objectpos_over_limit(nodeposf))
3589 // Exit this loop, positions above are probably over limit
3592 // Good position found, cause an exit from main loop
3606 // No suitable spawn point found, return fallback 0,0,0
3607 return v3f(0.0f, 0.0f, 0.0f);
3610 void Server::requestShutdown(const std::string &msg, bool reconnect, float delay)
3612 if (delay == 0.0f) {
3613 // No delay, shutdown immediately
3614 m_shutdown_state.is_requested = true;
3615 // only print to the infostream, a chat message saying
3616 // "Server Shutting Down" is sent when the server destructs.
3617 infostream << "*** Immediate Server shutdown requested." << std::endl;
3618 } else if (delay < 0.0f && m_shutdown_state.isTimerRunning()) {
3619 // Negative delay, cancel shutdown if requested
3620 m_shutdown_state.reset();
3621 std::wstringstream ws;
3623 ws << L"*** Server shutdown canceled.";
3625 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3626 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3627 // m_shutdown_* are already handled, skip.
3629 } else if (delay > 0.0f) {
3630 // Positive delay, tell the clients when the server will shut down
3631 std::wstringstream ws;
3633 ws << L"*** Server shutting down in "
3634 << duration_to_string(myround(delay)).c_str()
3637 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3638 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3641 m_shutdown_state.trigger(delay, msg, reconnect);
3644 PlayerSAO* Server::emergePlayer(const char *name, session_t peer_id, u16 proto_version)
3647 Try to get an existing player
3649 RemotePlayer *player = m_env->getPlayer(name);
3651 // If player is already connected, cancel
3652 if (player && player->getPeerId() != PEER_ID_INEXISTENT) {
3653 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3658 If player with the wanted peer_id already exists, cancel.
3660 if (m_env->getPlayer(peer_id)) {
3661 infostream<<"emergePlayer(): Player with wrong name but same"
3662 " peer_id already exists"<<std::endl;
3667 player = new RemotePlayer(name, idef());
3670 bool newplayer = false;
3673 PlayerSAO *playersao = m_env->loadPlayer(player, &newplayer, peer_id, isSingleplayer());
3675 // Complete init with server parts
3676 playersao->finalize(player, getPlayerEffectivePrivs(player->getName()));
3677 player->protocol_version = proto_version;
3681 m_script->on_newplayer(playersao);
3687 bool Server::registerModStorage(ModMetadata *storage)
3689 if (m_mod_storages.find(storage->getModName()) != m_mod_storages.end()) {
3690 errorstream << "Unable to register same mod storage twice. Storage name: "
3691 << storage->getModName() << std::endl;
3695 m_mod_storages[storage->getModName()] = storage;
3699 void Server::unregisterModStorage(const std::string &name)
3701 std::unordered_map<std::string, ModMetadata *>::const_iterator it = m_mod_storages.find(name);
3702 if (it != m_mod_storages.end()) {
3703 // Save unconditionaly on unregistration
3704 it->second->save(getModStoragePath());
3705 m_mod_storages.erase(name);
3709 void dedicated_server_loop(Server &server, bool &kill)
3711 verbosestream<<"dedicated_server_loop()"<<std::endl;
3713 IntervalLimiter m_profiler_interval;
3715 static thread_local const float steplen =
3716 g_settings->getFloat("dedicated_server_step");
3717 static thread_local const float profiler_print_interval =
3718 g_settings->getFloat("profiler_print_interval");
3721 // This is kind of a hack but can be done like this
3722 // because server.step() is very light
3723 sleep_ms((int)(steplen*1000.0));
3724 server.step(steplen);
3726 if (server.isShutdownRequested() || kill)
3732 if (profiler_print_interval != 0) {
3733 if(m_profiler_interval.step(steplen, profiler_print_interval))
3735 infostream<<"Profiler:"<<std::endl;
3736 g_profiler->print(infostream);
3737 g_profiler->clear();
3742 infostream << "Dedicated server quitting" << std::endl;
3744 if (g_settings->getBool("server_announce"))
3745 ServerList::sendAnnounce(ServerList::AA_DELETE,
3746 server.m_bind_addr.getPort());
3755 bool Server::joinModChannel(const std::string &channel)
3757 return m_modchannel_mgr->joinChannel(channel, PEER_ID_SERVER) &&
3758 m_modchannel_mgr->setChannelState(channel, MODCHANNEL_STATE_READ_WRITE);
3761 bool Server::leaveModChannel(const std::string &channel)
3763 return m_modchannel_mgr->leaveChannel(channel, PEER_ID_SERVER);
3766 bool Server::sendModChannelMessage(const std::string &channel, const std::string &message)
3768 if (!m_modchannel_mgr->canWriteOnChannel(channel))
3771 broadcastModChannelMessage(channel, message, PEER_ID_SERVER);
3775 ModChannel* Server::getModChannel(const std::string &channel)
3777 return m_modchannel_mgr->getModChannel(channel);
3780 void Server::broadcastModChannelMessage(const std::string &channel,
3781 const std::string &message, session_t from_peer)
3783 const std::vector<u16> &peers = m_modchannel_mgr->getChannelPeers(channel);
3787 if (message.size() > STRING_MAX_LEN) {
3788 warningstream << "ModChannel message too long, dropping before sending "
3789 << " (" << message.size() << " > " << STRING_MAX_LEN << ", channel: "
3790 << channel << ")" << std::endl;
3795 if (from_peer != PEER_ID_SERVER) {
3796 sender = getPlayerName(from_peer);
3799 NetworkPacket resp_pkt(TOCLIENT_MODCHANNEL_MSG,
3800 2 + channel.size() + 2 + sender.size() + 2 + message.size());
3801 resp_pkt << channel << sender << message;
3802 for (session_t peer_id : peers) {
3804 if (peer_id == from_peer)
3807 Send(peer_id, &resp_pkt);
3810 if (from_peer != PEER_ID_SERVER) {
3811 m_script->on_modchannel_message(channel, sender, message);