3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include "network/connection.h"
25 #include "network/networkprotocol.h"
26 #include "network/serveropcodes.h"
28 #include "environment.h"
30 #include "threading/mutex_auto_lock.h"
31 #include "constants.h"
37 #include "serverobject.h"
38 #include "genericobject.h"
42 #include "scripting_server.h"
47 #include "mapgen/mapgen.h"
48 #include "mapgen/mg_biome.h"
49 #include "content_mapnode.h"
50 #include "content_nodemeta.h"
51 #include "content_sao.h"
52 #include "content/mods.h"
53 #include "modchannels.h"
54 #include "serverlist.h"
55 #include "util/string.h"
57 #include "util/serialize.h"
58 #include "util/thread.h"
59 #include "defaultsettings.h"
60 #include "server/mods.h"
61 #include "util/base64.h"
62 #include "util/sha1.h"
64 #include "database/database.h"
65 #include "chatmessage.h"
66 #include "chat_interface.h"
67 #include "remoteplayer.h"
69 class ClientNotFoundException : public BaseException
72 ClientNotFoundException(const char *s):
77 class ServerThread : public Thread
81 ServerThread(Server *server):
92 void *ServerThread::run()
94 BEGIN_DEBUG_EXCEPTION_HANDLER
96 m_server->AsyncRunStep(true);
98 while (!stopRequested()) {
100 m_server->AsyncRunStep();
104 } catch (con::NoIncomingDataException &e) {
105 } catch (con::PeerNotFoundException &e) {
106 infostream<<"Server: PeerNotFoundException"<<std::endl;
107 } catch (ClientNotFoundException &e) {
108 } catch (con::ConnectionBindFailed &e) {
109 m_server->setAsyncFatalError(e.what());
110 } catch (LuaError &e) {
111 m_server->setAsyncFatalError(
112 "ServerThread::run Lua: " + std::string(e.what()));
116 END_DEBUG_EXCEPTION_HANDLER
121 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
123 if(pos_exists) *pos_exists = false;
128 if(pos_exists) *pos_exists = true;
133 ServerActiveObject *sao = env->getActiveObject(object);
136 if(pos_exists) *pos_exists = true;
137 return sao->getBasePosition(); }
142 void Server::ShutdownState::reset()
146 should_reconnect = false;
147 is_requested = false;
150 void Server::ShutdownState::trigger(float delay, const std::string &msg, bool reconnect)
154 should_reconnect = reconnect;
157 void Server::ShutdownState::tick(float dtime, Server *server)
163 static const float shutdown_msg_times[] =
165 1, 2, 3, 4, 5, 10, 20, 40, 60, 120, 180, 300, 600, 1200, 1800, 3600
168 // Automated messages
169 if (m_timer < shutdown_msg_times[ARRLEN(shutdown_msg_times) - 1]) {
170 for (float t : shutdown_msg_times) {
171 // If shutdown timer matches an automessage, shot it
172 if (m_timer > t && m_timer - dtime < t) {
173 std::wstring periodicMsg = getShutdownTimerMessage();
175 infostream << wide_to_utf8(periodicMsg).c_str() << std::endl;
176 server->SendChatMessage(PEER_ID_INEXISTENT, periodicMsg);
183 if (m_timer < 0.0f) {
189 std::wstring Server::ShutdownState::getShutdownTimerMessage() const
191 std::wstringstream ws;
192 ws << L"*** Server shutting down in "
193 << duration_to_string(myround(m_timer)).c_str() << ".";
202 const std::string &path_world,
203 const SubgameSpec &gamespec,
204 bool simple_singleplayer_mode,
209 m_bind_addr(bind_addr),
210 m_path_world(path_world),
211 m_gamespec(gamespec),
212 m_simple_singleplayer_mode(simple_singleplayer_mode),
213 m_dedicated(dedicated),
214 m_async_fatal_error(""),
215 m_con(std::make_shared<con::Connection>(PROTOCOL_ID,
218 m_bind_addr.isIPv6(),
220 m_itemdef(createItemDefManager()),
221 m_nodedef(createNodeDefManager()),
222 m_craftdef(createCraftDefManager()),
223 m_thread(new ServerThread(this)),
227 m_modchannel_mgr(new ModChannelMgr())
229 m_lag = g_settings->getFloat("dedicated_server_step");
231 if (m_path_world.empty())
232 throw ServerError("Supplied empty world path");
234 if (!gamespec.isValid())
235 throw ServerError("Supplied invalid gamespec");
241 // Send shutdown message
242 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE,
243 L"*** Server shutting down"));
246 MutexAutoLock envlock(m_env_mutex);
248 infostream << "Server: Saving players" << std::endl;
249 m_env->saveLoadedPlayers();
251 infostream << "Server: Kicking players" << std::endl;
252 std::string kick_msg;
253 bool reconnect = false;
254 if (isShutdownRequested()) {
255 reconnect = m_shutdown_state.should_reconnect;
256 kick_msg = m_shutdown_state.message;
258 if (kick_msg.empty()) {
259 kick_msg = g_settings->get("kick_msg_shutdown");
261 m_env->saveLoadedPlayers(true);
262 m_env->kickAllPlayers(SERVER_ACCESSDENIED_SHUTDOWN,
263 kick_msg, reconnect);
266 actionstream << "Server: Shutting down" << std::endl;
268 // Do this before stopping the server in case mapgen callbacks need to access
269 // server-controlled resources (like ModStorages). Also do them before
270 // shutdown callbacks since they may modify state that is finalized in a
273 m_emerge->stopThreads();
276 MutexAutoLock envlock(m_env_mutex);
278 // Execute script shutdown hooks
279 infostream << "Executing shutdown hooks" << std::endl;
280 m_script->on_shutdown();
282 infostream << "Server: Saving environment metadata" << std::endl;
292 // Delete things in the reverse order of creation
301 // Deinitialize scripting
302 infostream << "Server: Deinitializing scripting" << std::endl;
305 // Delete detached inventories
306 for (auto &detached_inventory : m_detached_inventories) {
307 delete detached_inventory.second;
313 infostream << "Server created for gameid \"" << m_gamespec.id << "\"";
314 if (m_simple_singleplayer_mode)
315 infostream << " in simple singleplayer mode" << std::endl;
317 infostream << std::endl;
318 infostream << "- world: " << m_path_world << std::endl;
319 infostream << "- game: " << m_gamespec.path << std::endl;
321 // Create world if it doesn't exist
322 if (!loadGameConfAndInitWorld(m_path_world, m_gamespec))
323 throw ServerError("Failed to initialize world");
325 // Create emerge manager
326 m_emerge = new EmergeManager(this);
328 // Create ban manager
329 std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
330 m_banmanager = new BanManager(ban_path);
332 m_modmgr = std::unique_ptr<ServerModManager>(new ServerModManager(m_path_world));
333 std::vector<ModSpec> unsatisfied_mods = m_modmgr->getUnsatisfiedMods();
334 // complain about mods with unsatisfied dependencies
335 if (!m_modmgr->isConsistent()) {
336 m_modmgr->printUnsatisfiedModsError();
340 MutexAutoLock envlock(m_env_mutex);
342 // Create the Map (loads map_meta.txt, overriding configured mapgen params)
343 ServerMap *servermap = new ServerMap(m_path_world, this, m_emerge);
345 // Initialize scripting
346 infostream << "Server: Initializing Lua" << std::endl;
348 m_script = new ServerScripting(this);
350 m_script->loadMod(getBuiltinLuaPath() + DIR_DELIM "init.lua", BUILTIN_MOD_NAME);
352 m_modmgr->loadMods(m_script);
354 // Read Textures and calculate sha1 sums
357 // Apply item aliases in the node definition manager
358 m_nodedef->updateAliases(m_itemdef);
360 // Apply texture overrides from texturepack/override.txt
361 std::vector<std::string> paths;
362 fs::GetRecursiveDirs(paths, g_settings->get("texture_path"));
363 fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures");
364 for (const std::string &path : paths)
365 m_nodedef->applyTextureOverrides(path + DIR_DELIM + "override.txt");
367 m_nodedef->setNodeRegistrationStatus(true);
369 // Perform pending node name resolutions
370 m_nodedef->runNodeResolveCallbacks();
372 // unmap node names for connected nodeboxes
373 m_nodedef->mapNodeboxConnections();
375 // init the recipe hashes to speed up crafting
376 m_craftdef->initHashes(this);
378 // Initialize Environment
379 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
381 m_clients.setEnv(m_env);
383 if (!servermap->settings_mgr.makeMapgenParams())
384 FATAL_ERROR("Couldn't create any mapgen type");
386 // Initialize mapgens
387 m_emerge->initMapgens(servermap->getMapgenParams());
389 if (g_settings->getBool("enable_rollback_recording")) {
390 // Create rollback manager
391 m_rollback = new RollbackManager(m_path_world, this);
394 // Give environment reference to scripting api
395 m_script->initializeEnvironment(m_env);
397 // Register us to receive map edit events
398 servermap->addEventReceiver(this);
402 m_liquid_transform_every = g_settings->getFloat("liquid_update");
403 m_max_chatmessage_length = g_settings->getU16("chat_message_max_size");
404 m_csm_restriction_flags = g_settings->getU64("csm_restriction_flags");
405 m_csm_restriction_noderange = g_settings->getU32("csm_restriction_noderange");
410 infostream << "Starting server on " << m_bind_addr.serializeString()
411 << "..." << std::endl;
413 // Stop thread if already running
416 // Initialize connection
417 m_con->SetTimeoutMs(30);
418 m_con->Serve(m_bind_addr);
423 // ASCII art for the win!
425 << " .__ __ __ " << std::endl
426 << " _____ |__| ____ _____/ |_ ____ _______/ |_ " << std::endl
427 << " / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\" << std::endl
428 << "| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | " << std::endl
429 << "|__|_| /__|___| /\\___ >__| \\___ >____ > |__| " << std::endl
430 << " \\/ \\/ \\/ \\/ \\/ " << std::endl;
431 actionstream << "World at [" << m_path_world << "]" << std::endl;
432 actionstream << "Server for gameid=\"" << m_gamespec.id
433 << "\" listening on " << m_bind_addr.serializeString() << ":"
434 << m_bind_addr.getPort() << "." << std::endl;
439 infostream<<"Server: Stopping and waiting threads"<<std::endl;
441 // Stop threads (set run=false first so both start stopping)
443 //m_emergethread.setRun(false);
445 //m_emergethread.stop();
447 infostream<<"Server: Threads stopped"<<std::endl;
450 void Server::step(float dtime)
456 MutexAutoLock lock(m_step_dtime_mutex);
457 m_step_dtime += dtime;
459 // Throw if fatal error occurred in thread
460 std::string async_err = m_async_fatal_error.get();
461 if (!async_err.empty()) {
462 if (!m_simple_singleplayer_mode) {
463 m_env->kickAllPlayers(SERVER_ACCESSDENIED_CRASH,
464 g_settings->get("kick_msg_crash"),
465 g_settings->getBool("ask_reconnect_on_crash"));
467 throw ServerError("AsyncErr: " + async_err);
471 void Server::AsyncRunStep(bool initial_step)
476 MutexAutoLock lock1(m_step_dtime_mutex);
477 dtime = m_step_dtime;
481 // Send blocks to clients
485 if((dtime < 0.001) && !initial_step)
488 ScopeProfiler sp(g_profiler, "Server::AsyncRunStep()", SPT_AVG);
491 MutexAutoLock lock1(m_step_dtime_mutex);
492 m_step_dtime -= dtime;
499 m_uptime.set(m_uptime.get() + dtime);
505 Update time of day and overall game time
507 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
510 Send to clients at constant intervals
513 m_time_of_day_send_timer -= dtime;
514 if(m_time_of_day_send_timer < 0.0) {
515 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
516 u16 time = m_env->getTimeOfDay();
517 float time_speed = g_settings->getFloat("time_speed");
518 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
522 MutexAutoLock lock(m_env_mutex);
523 // Figure out and report maximum lag to environment
524 float max_lag = m_env->getMaxLagEstimate();
525 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
527 if(dtime > 0.1 && dtime > max_lag * 2.0)
528 infostream<<"Server: Maximum lag peaked to "<<dtime
532 m_env->reportMaxLagEstimate(max_lag);
537 static const float map_timer_and_unload_dtime = 2.92;
538 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
540 MutexAutoLock lock(m_env_mutex);
541 // Run Map's timers and unload unused data
542 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
543 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
544 g_settings->getFloat("server_unload_unused_data_timeout"),
549 Listen to the admin chat, if available
552 if (!m_admin_chat->command_queue.empty()) {
553 MutexAutoLock lock(m_env_mutex);
554 while (!m_admin_chat->command_queue.empty()) {
555 ChatEvent *evt = m_admin_chat->command_queue.pop_frontNoEx();
556 handleChatInterfaceEvent(evt);
560 m_admin_chat->outgoing_queue.push_back(
561 new ChatEventTimeInfo(m_env->getGameTime(), m_env->getTimeOfDay()));
568 /* Transform liquids */
569 m_liquid_transform_timer += dtime;
570 if(m_liquid_transform_timer >= m_liquid_transform_every)
572 m_liquid_transform_timer -= m_liquid_transform_every;
574 MutexAutoLock lock(m_env_mutex);
576 ScopeProfiler sp(g_profiler, "Server: liquid transform");
578 std::map<v3s16, MapBlock*> modified_blocks;
579 m_env->getMap().transformLiquids(modified_blocks, m_env);
582 Set the modified blocks unsent for all the clients
584 if (!modified_blocks.empty()) {
585 SetBlocksNotSent(modified_blocks);
588 m_clients.step(dtime);
590 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
592 // send masterserver announce
594 float &counter = m_masterserver_timer;
595 if (!isSingleplayer() && (!counter || counter >= 300.0) &&
596 g_settings->getBool("server_announce")) {
597 ServerList::sendAnnounce(counter ? ServerList::AA_UPDATE :
598 ServerList::AA_START,
599 m_bind_addr.getPort(),
600 m_clients.getPlayerNames(),
602 m_env->getGameTime(),
605 Mapgen::getMapgenName(m_emerge->mgparams->mgtype),
615 Check added and deleted active objects
618 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
619 MutexAutoLock envlock(m_env_mutex);
622 const RemoteClientMap &clients = m_clients.getClientList();
623 ScopeProfiler sp(g_profiler, "Server: update objects within range");
625 for (const auto &client_it : clients) {
626 RemoteClient *client = client_it.second;
628 if (client->getState() < CS_DefinitionsSent)
631 // This can happen if the client times out somehow
632 if (!m_env->getPlayer(client->peer_id))
635 PlayerSAO *playersao = getPlayerSAO(client->peer_id);
639 SendActiveObjectRemoveAdd(client, playersao);
643 // Save mod storages if modified
644 m_mod_storage_save_timer -= dtime;
645 if (m_mod_storage_save_timer <= 0.0f) {
646 infostream << "Saving registered mod storages." << std::endl;
647 m_mod_storage_save_timer = g_settings->getFloat("server_map_save_interval");
648 for (std::unordered_map<std::string, ModMetadata *>::const_iterator
649 it = m_mod_storages.begin(); it != m_mod_storages.end(); ++it) {
650 if (it->second->isModified()) {
651 it->second->save(getModStoragePath());
661 MutexAutoLock envlock(m_env_mutex);
662 ScopeProfiler sp(g_profiler, "Server: send SAO messages");
665 // Value = data sent by object
666 std::unordered_map<u16, std::vector<ActiveObjectMessage>*> buffered_messages;
668 // Get active object messages from environment
670 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
674 std::vector<ActiveObjectMessage>* message_list = nullptr;
675 std::unordered_map<u16, std::vector<ActiveObjectMessage>* >::iterator n;
676 n = buffered_messages.find(aom.id);
677 if (n == buffered_messages.end()) {
678 message_list = new std::vector<ActiveObjectMessage>;
679 buffered_messages[aom.id] = message_list;
682 message_list = n->second;
684 message_list->push_back(aom);
688 const RemoteClientMap &clients = m_clients.getClientList();
689 // Route data to every client
690 for (const auto &client_it : clients) {
691 RemoteClient *client = client_it.second;
692 std::string reliable_data;
693 std::string unreliable_data;
694 // Go through all objects in message buffer
695 for (const auto &buffered_message : buffered_messages) {
696 // If object is not known by client, skip it
697 u16 id = buffered_message.first;
698 if (client->m_known_objects.find(id) == client->m_known_objects.end())
701 // Get message list of object
702 std::vector<ActiveObjectMessage>* list = buffered_message.second;
703 // Go through every message
704 for (const ActiveObjectMessage &aom : *list) {
705 // Compose the full new data with header
706 std::string new_data;
709 writeU16((u8*)&buf[0], aom.id);
710 new_data.append(buf, 2);
712 new_data += serializeString(aom.datastring);
713 // Add data to buffer
715 reliable_data += new_data;
717 unreliable_data += new_data;
721 reliable_data and unreliable_data are now ready.
724 if (!reliable_data.empty()) {
725 SendActiveObjectMessages(client->peer_id, reliable_data);
728 if (!unreliable_data.empty()) {
729 SendActiveObjectMessages(client->peer_id, unreliable_data, false);
734 // Clear buffered_messages
735 for (auto &buffered_message : buffered_messages) {
736 delete buffered_message.second;
741 Send queued-for-sending map edit events.
744 // We will be accessing the environment
745 MutexAutoLock lock(m_env_mutex);
747 // Don't send too many at a time
750 // Single change sending is disabled if queue size is not small
751 bool disable_single_change_sending = false;
752 if(m_unsent_map_edit_queue.size() >= 4)
753 disable_single_change_sending = true;
755 int event_count = m_unsent_map_edit_queue.size();
757 // We'll log the amount of each
760 std::list<v3s16> node_meta_updates;
762 while (!m_unsent_map_edit_queue.empty()) {
763 MapEditEvent* event = m_unsent_map_edit_queue.front();
764 m_unsent_map_edit_queue.pop();
766 // Players far away from the change are stored here.
767 // Instead of sending the changes, MapBlocks are set not sent
769 std::unordered_set<u16> far_players;
771 switch (event->type) {
774 prof.add("MEET_ADDNODE", 1);
775 sendAddNode(event->p, event->n, &far_players,
776 disable_single_change_sending ? 5 : 30,
777 event->type == MEET_ADDNODE);
779 case MEET_REMOVENODE:
780 prof.add("MEET_REMOVENODE", 1);
781 sendRemoveNode(event->p, &far_players,
782 disable_single_change_sending ? 5 : 30);
784 case MEET_BLOCK_NODE_METADATA_CHANGED: {
785 verbosestream << "Server: MEET_BLOCK_NODE_METADATA_CHANGED" << std::endl;
786 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
787 if (!event->is_private_change) {
788 // Don't send the change yet. Collect them to eliminate dupes.
789 node_meta_updates.remove(event->p);
790 node_meta_updates.push_back(event->p);
793 if (MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(
794 getNodeBlockPos(event->p))) {
795 block->raiseModified(MOD_STATE_WRITE_NEEDED,
796 MOD_REASON_REPORT_META_CHANGE);
801 infostream << "Server: MEET_OTHER" << std::endl;
802 prof.add("MEET_OTHER", 1);
803 for (const v3s16 &modified_block : event->modified_blocks) {
804 m_clients.markBlockposAsNotSent(modified_block);
808 prof.add("unknown", 1);
809 warningstream << "Server: Unknown MapEditEvent "
810 << ((u32)event->type) << std::endl;
815 Set blocks not sent to far players
817 if (!far_players.empty()) {
818 // Convert list format to that wanted by SetBlocksNotSent
819 std::map<v3s16, MapBlock*> modified_blocks2;
820 for (const v3s16 &modified_block : event->modified_blocks) {
821 modified_blocks2[modified_block] =
822 m_env->getMap().getBlockNoCreateNoEx(modified_block);
825 // Set blocks not sent
826 for (const u16 far_player : far_players) {
827 if (RemoteClient *client = getClient(far_player))
828 client->SetBlocksNotSent(modified_blocks2);
835 if (event_count >= 5) {
836 infostream << "Server: MapEditEvents:" << std::endl;
837 prof.print(infostream);
838 } else if (event_count != 0) {
839 verbosestream << "Server: MapEditEvents:" << std::endl;
840 prof.print(verbosestream);
843 // Send all metadata updates
844 if (node_meta_updates.size())
845 sendMetadataChanged(node_meta_updates);
849 Trigger emergethread (it somehow gets to a non-triggered but
850 bysy state sometimes)
853 float &counter = m_emergethread_trigger_timer;
855 if (counter >= 2.0) {
858 m_emerge->startThreads();
862 // Save map, players and auth stuff
864 float &counter = m_savemap_timer;
866 static thread_local const float save_interval =
867 g_settings->getFloat("server_map_save_interval");
868 if (counter >= save_interval) {
870 MutexAutoLock lock(m_env_mutex);
872 ScopeProfiler sp(g_profiler, "Server: map saving (sum)");
875 if (m_banmanager->isModified()) {
876 m_banmanager->save();
879 // Save changed parts of map
880 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
883 m_env->saveLoadedPlayers();
885 // Save environment metadata
890 m_shutdown_state.tick(dtime, this);
893 void Server::Receive()
895 session_t peer_id = 0;
898 m_con->Receive(&pkt);
899 peer_id = pkt.getPeerId();
901 } catch (const con::InvalidIncomingDataException &e) {
902 infostream << "Server::Receive(): InvalidIncomingDataException: what()="
903 << e.what() << std::endl;
904 } catch (const SerializationError &e) {
905 infostream << "Server::Receive(): SerializationError: what()="
906 << e.what() << std::endl;
907 } catch (const ClientStateError &e) {
908 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
909 DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
910 L"Try reconnecting or updating your client");
911 } catch (const con::PeerNotFoundException &e) {
916 PlayerSAO* Server::StageTwoClientInit(session_t peer_id)
918 std::string playername;
919 PlayerSAO *playersao = NULL;
922 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
924 playername = client->getName();
925 playersao = emergePlayer(playername.c_str(), peer_id, client->net_proto_version);
927 } catch (std::exception &e) {
933 RemotePlayer *player = m_env->getPlayer(playername.c_str());
936 if (!playersao || !player) {
937 if (player && player->getPeerId() != PEER_ID_INEXISTENT) {
938 actionstream << "Server: Failed to emerge player \"" << playername
939 << "\" (player allocated to an another client)" << std::endl;
940 DenyAccess_Legacy(peer_id, L"Another client is connected with this "
941 L"name. If your client closed unexpectedly, try again in "
944 errorstream << "Server: " << playername << ": Failed to emerge player"
946 DenyAccess_Legacy(peer_id, L"Could not allocate player.");
952 Send complete position information
954 SendMovePlayer(peer_id);
957 SendPlayerPrivileges(peer_id);
959 // Send inventory formspec
960 SendPlayerInventoryFormspec(peer_id);
963 SendInventory(playersao, false);
965 // Send HP or death screen
966 if (playersao->isDead())
967 SendDeathscreen(peer_id, false, v3f(0,0,0));
969 SendPlayerHPOrDie(playersao,
970 PlayerHPChangeReason(PlayerHPChangeReason::SET_HP));
973 SendPlayerBreath(playersao);
975 Address addr = getPeerAddress(player->getPeerId());
976 std::string ip_str = addr.serializeString();
977 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
982 const std::vector<std::string> &names = m_clients.getPlayerNames();
984 actionstream << player->getName() << " joins game. List of players: ";
986 for (const std::string &name : names) {
987 actionstream << name << " ";
990 actionstream << player->getName() <<std::endl;
995 inline void Server::handleCommand(NetworkPacket *pkt)
997 const ToServerCommandHandler &opHandle = toServerCommandTable[pkt->getCommand()];
998 (this->*opHandle.handler)(pkt);
1001 void Server::ProcessData(NetworkPacket *pkt)
1003 // Environment is locked first.
1004 MutexAutoLock envlock(m_env_mutex);
1006 ScopeProfiler sp(g_profiler, "Server: Process network packet (sum)");
1007 u32 peer_id = pkt->getPeerId();
1010 Address address = getPeerAddress(peer_id);
1011 std::string addr_s = address.serializeString();
1013 if(m_banmanager->isIpBanned(addr_s)) {
1014 std::string ban_name = m_banmanager->getBanName(addr_s);
1015 infostream << "Server: A banned client tried to connect from "
1016 << addr_s << "; banned name was "
1017 << ban_name << std::endl;
1018 // This actually doesn't seem to transfer to the client
1019 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1020 + utf8_to_wide(ban_name));
1024 catch(con::PeerNotFoundException &e) {
1026 * no peer for this packet found
1027 * most common reason is peer timeout, e.g. peer didn't
1028 * respond for some time, your server was overloaded or
1031 infostream << "Server::ProcessData(): Canceling: peer "
1032 << peer_id << " not found" << std::endl;
1037 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1039 // Command must be handled into ToServerCommandHandler
1040 if (command >= TOSERVER_NUM_MSG_TYPES) {
1041 infostream << "Server: Ignoring unknown command "
1042 << command << std::endl;
1046 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1051 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1053 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1054 errorstream << "Server::ProcessData(): Cancelling: Peer"
1055 " serialization format invalid or not initialized."
1056 " Skipping incoming command=" << command << std::endl;
1060 /* Handle commands related to client startup */
1061 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1066 if (m_clients.getClientState(peer_id) < CS_Active) {
1067 if (command == TOSERVER_PLAYERPOS) return;
1069 errorstream << "Got packet command: " << command << " for peer id "
1070 << peer_id << " but client isn't active yet. Dropping packet "
1076 } catch (SendFailedException &e) {
1077 errorstream << "Server::ProcessData(): SendFailedException: "
1078 << "what=" << e.what()
1080 } catch (PacketError &e) {
1081 actionstream << "Server::ProcessData(): PacketError: "
1082 << "what=" << e.what()
1087 void Server::setTimeOfDay(u32 time)
1089 m_env->setTimeOfDay(time);
1090 m_time_of_day_send_timer = 0;
1093 void Server::onMapEditEvent(MapEditEvent *event)
1095 if (m_ignore_map_edit_events_area.contains(event->getArea()))
1097 MapEditEvent *e = event->clone();
1098 m_unsent_map_edit_queue.push(e);
1101 Inventory* Server::getInventory(const InventoryLocation &loc)
1104 case InventoryLocation::UNDEFINED:
1105 case InventoryLocation::CURRENT_PLAYER:
1107 case InventoryLocation::PLAYER:
1109 RemotePlayer *player = m_env->getPlayer(loc.name.c_str());
1112 PlayerSAO *playersao = player->getPlayerSAO();
1115 return playersao->getInventory();
1118 case InventoryLocation::NODEMETA:
1120 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1123 return meta->getInventory();
1126 case InventoryLocation::DETACHED:
1128 if(m_detached_inventories.count(loc.name) == 0)
1130 return m_detached_inventories[loc.name];
1134 sanity_check(false); // abort
1140 void Server::setInventoryModified(const InventoryLocation &loc)
1143 case InventoryLocation::UNDEFINED:
1145 case InventoryLocation::PLAYER:
1148 RemotePlayer *player = m_env->getPlayer(loc.name.c_str());
1153 player->setModified(true);
1154 // Updates are sent in ServerEnvironment::step()
1157 case InventoryLocation::NODEMETA:
1160 event.type = MEET_BLOCK_NODE_METADATA_CHANGED;
1162 m_env->getMap().dispatchEvent(&event);
1165 case InventoryLocation::DETACHED:
1167 // Updates are sent in ServerEnvironment::step()
1171 sanity_check(false); // abort
1176 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1178 std::vector<session_t> clients = m_clients.getClientIDs();
1180 // Set the modified blocks unsent for all the clients
1181 for (const session_t client_id : clients) {
1182 if (RemoteClient *client = m_clients.lockedGetClientNoEx(client_id))
1183 client->SetBlocksNotSent(block);
1188 void Server::peerAdded(con::Peer *peer)
1190 verbosestream<<"Server::peerAdded(): peer->id="
1191 <<peer->id<<std::endl;
1193 m_peer_change_queue.push(con::PeerChange(con::PEER_ADDED, peer->id, false));
1196 void Server::deletingPeer(con::Peer *peer, bool timeout)
1198 verbosestream<<"Server::deletingPeer(): peer->id="
1199 <<peer->id<<", timeout="<<timeout<<std::endl;
1201 m_clients.event(peer->id, CSE_Disconnect);
1202 m_peer_change_queue.push(con::PeerChange(con::PEER_REMOVED, peer->id, timeout));
1205 bool Server::getClientConInfo(session_t peer_id, con::rtt_stat_type type, float* retval)
1207 *retval = m_con->getPeerStat(peer_id,type);
1208 return *retval != -1;
1211 bool Server::getClientInfo(
1220 std::string* vers_string
1223 *state = m_clients.getClientState(peer_id);
1225 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1232 *uptime = client->uptime();
1233 *ser_vers = client->serialization_version;
1234 *prot_vers = client->net_proto_version;
1236 *major = client->getMajor();
1237 *minor = client->getMinor();
1238 *patch = client->getPatch();
1239 *vers_string = client->getPatch();
1246 void Server::handlePeerChanges()
1248 while(!m_peer_change_queue.empty())
1250 con::PeerChange c = m_peer_change_queue.front();
1251 m_peer_change_queue.pop();
1253 verbosestream<<"Server: Handling peer change: "
1254 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1259 case con::PEER_ADDED:
1260 m_clients.CreateClient(c.peer_id);
1263 case con::PEER_REMOVED:
1264 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1268 FATAL_ERROR("Invalid peer change event received!");
1274 void Server::printToConsoleOnly(const std::string &text)
1277 m_admin_chat->outgoing_queue.push_back(
1278 new ChatEventChat("", utf8_to_wide(text)));
1280 std::cout << text << std::endl;
1284 void Server::Send(NetworkPacket *pkt)
1286 Send(pkt->getPeerId(), pkt);
1289 void Server::Send(session_t peer_id, NetworkPacket *pkt)
1291 m_clients.send(peer_id,
1292 clientCommandFactoryTable[pkt->getCommand()].channel,
1294 clientCommandFactoryTable[pkt->getCommand()].reliable);
1297 void Server::SendMovement(session_t peer_id)
1299 std::ostringstream os(std::ios_base::binary);
1301 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1303 pkt << g_settings->getFloat("movement_acceleration_default");
1304 pkt << g_settings->getFloat("movement_acceleration_air");
1305 pkt << g_settings->getFloat("movement_acceleration_fast");
1306 pkt << g_settings->getFloat("movement_speed_walk");
1307 pkt << g_settings->getFloat("movement_speed_crouch");
1308 pkt << g_settings->getFloat("movement_speed_fast");
1309 pkt << g_settings->getFloat("movement_speed_climb");
1310 pkt << g_settings->getFloat("movement_speed_jump");
1311 pkt << g_settings->getFloat("movement_liquid_fluidity");
1312 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1313 pkt << g_settings->getFloat("movement_liquid_sink");
1314 pkt << g_settings->getFloat("movement_gravity");
1319 void Server::SendPlayerHPOrDie(PlayerSAO *playersao, const PlayerHPChangeReason &reason)
1321 if (playersao->isImmortal())
1324 session_t peer_id = playersao->getPeerID();
1325 bool is_alive = playersao->getHP() > 0;
1328 SendPlayerHP(peer_id);
1330 DiePlayer(peer_id, reason);
1333 void Server::SendHP(session_t peer_id, u16 hp)
1335 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1340 void Server::SendBreath(session_t peer_id, u16 breath)
1342 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1343 pkt << (u16) breath;
1347 void Server::SendAccessDenied(session_t peer_id, AccessDeniedCode reason,
1348 const std::string &custom_reason, bool reconnect)
1350 assert(reason < SERVER_ACCESSDENIED_MAX);
1352 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1354 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
1355 pkt << custom_reason;
1356 else if (reason == SERVER_ACCESSDENIED_SHUTDOWN ||
1357 reason == SERVER_ACCESSDENIED_CRASH)
1358 pkt << custom_reason << (u8)reconnect;
1362 void Server::SendAccessDenied_Legacy(session_t peer_id,const std::wstring &reason)
1364 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1369 void Server::SendDeathscreen(session_t peer_id, bool set_camera_point_target,
1370 v3f camera_point_target)
1372 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1373 pkt << set_camera_point_target << camera_point_target;
1377 void Server::SendItemDef(session_t peer_id,
1378 IItemDefManager *itemdef, u16 protocol_version)
1380 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1384 u32 length of the next item
1385 zlib-compressed serialized ItemDefManager
1387 std::ostringstream tmp_os(std::ios::binary);
1388 itemdef->serialize(tmp_os, protocol_version);
1389 std::ostringstream tmp_os2(std::ios::binary);
1390 compressZlib(tmp_os.str(), tmp_os2);
1391 pkt.putLongString(tmp_os2.str());
1394 verbosestream << "Server: Sending item definitions to id(" << peer_id
1395 << "): size=" << pkt.getSize() << std::endl;
1400 void Server::SendNodeDef(session_t peer_id,
1401 const NodeDefManager *nodedef, u16 protocol_version)
1403 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1407 u32 length of the next item
1408 zlib-compressed serialized NodeDefManager
1410 std::ostringstream tmp_os(std::ios::binary);
1411 nodedef->serialize(tmp_os, protocol_version);
1412 std::ostringstream tmp_os2(std::ios::binary);
1413 compressZlib(tmp_os.str(), tmp_os2);
1415 pkt.putLongString(tmp_os2.str());
1418 verbosestream << "Server: Sending node definitions to id(" << peer_id
1419 << "): size=" << pkt.getSize() << std::endl;
1425 Non-static send methods
1428 void Server::SendInventory(PlayerSAO *sao, bool incremental)
1430 RemotePlayer *player = sao->getPlayer();
1432 // Do not send new format to old clients
1433 incremental &= player->protocol_version >= 38;
1435 UpdateCrafting(player);
1441 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, sao->getPeerID());
1443 std::ostringstream os(std::ios::binary);
1444 sao->getInventory()->serialize(os, incremental);
1445 sao->getInventory()->setModified(false);
1446 player->setModified(true);
1448 const std::string &s = os.str();
1449 pkt.putRawString(s.c_str(), s.size());
1453 void Server::SendChatMessage(session_t peer_id, const ChatMessage &message)
1455 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1457 u8 type = message.type;
1458 pkt << version << type << std::wstring(L"") << message.message << (u64)message.timestamp;
1460 if (peer_id != PEER_ID_INEXISTENT) {
1461 RemotePlayer *player = m_env->getPlayer(peer_id);
1467 m_clients.sendToAll(&pkt);
1471 void Server::SendShowFormspecMessage(session_t peer_id, const std::string &formspec,
1472 const std::string &formname)
1474 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0, peer_id);
1475 if (formspec.empty()){
1476 //the client should close the formspec
1477 //but make sure there wasn't another one open in meantime
1478 const auto it = m_formspec_state_data.find(peer_id);
1479 if (it != m_formspec_state_data.end() && it->second == formname) {
1480 m_formspec_state_data.erase(peer_id);
1482 pkt.putLongString("");
1484 m_formspec_state_data[peer_id] = formname;
1485 pkt.putLongString(formspec);
1492 // Spawns a particle on peer with peer_id
1493 void Server::SendSpawnParticle(session_t peer_id, u16 protocol_version,
1494 v3f pos, v3f velocity, v3f acceleration,
1495 float expirationtime, float size, bool collisiondetection,
1496 bool collision_removal, bool object_collision,
1497 bool vertical, const std::string &texture,
1498 const struct TileAnimationParams &animation, u8 glow)
1500 static thread_local const float radius =
1501 g_settings->getS16("max_block_send_distance") * MAP_BLOCKSIZE * BS;
1503 if (peer_id == PEER_ID_INEXISTENT) {
1504 std::vector<session_t> clients = m_clients.getClientIDs();
1506 for (const session_t client_id : clients) {
1507 RemotePlayer *player = m_env->getPlayer(client_id);
1511 PlayerSAO *sao = player->getPlayerSAO();
1515 // Do not send to distant clients
1516 if (sao->getBasePosition().getDistanceFrom(pos * BS) > radius)
1519 SendSpawnParticle(client_id, player->protocol_version,
1520 pos, velocity, acceleration,
1521 expirationtime, size, collisiondetection, collision_removal,
1522 object_collision, vertical, texture, animation, glow);
1527 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1529 pkt << pos << velocity << acceleration << expirationtime
1530 << size << collisiondetection;
1531 pkt.putLongString(texture);
1533 pkt << collision_removal;
1534 // This is horrible but required (why are there two ways to serialize pkts?)
1535 std::ostringstream os(std::ios_base::binary);
1536 animation.serialize(os, protocol_version);
1537 pkt.putRawString(os.str());
1539 pkt << object_collision;
1544 // Adds a ParticleSpawner on peer with peer_id
1545 void Server::SendAddParticleSpawner(session_t peer_id, u16 protocol_version,
1546 u16 amount, float spawntime, v3f minpos, v3f maxpos,
1547 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1548 float minsize, float maxsize, bool collisiondetection, bool collision_removal,
1549 bool object_collision, u16 attached_id, bool vertical, const std::string &texture, u32 id,
1550 const struct TileAnimationParams &animation, u8 glow)
1552 if (peer_id == PEER_ID_INEXISTENT) {
1553 // This sucks and should be replaced:
1554 std::vector<session_t> clients = m_clients.getClientIDs();
1555 for (const session_t client_id : clients) {
1556 RemotePlayer *player = m_env->getPlayer(client_id);
1559 SendAddParticleSpawner(client_id, player->protocol_version,
1560 amount, spawntime, minpos, maxpos,
1561 minvel, maxvel, minacc, maxacc, minexptime, maxexptime,
1562 minsize, maxsize, collisiondetection, collision_removal,
1563 object_collision, attached_id, vertical, texture, id,
1569 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1571 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1572 << minacc << maxacc << minexptime << maxexptime << minsize
1573 << maxsize << collisiondetection;
1575 pkt.putLongString(texture);
1577 pkt << id << vertical;
1578 pkt << collision_removal;
1580 // This is horrible but required
1581 std::ostringstream os(std::ios_base::binary);
1582 animation.serialize(os, protocol_version);
1583 pkt.putRawString(os.str());
1585 pkt << object_collision;
1590 void Server::SendDeleteParticleSpawner(session_t peer_id, u32 id)
1592 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER, 4, peer_id);
1594 // Ugly error in this packet
1597 if (peer_id != PEER_ID_INEXISTENT)
1600 m_clients.sendToAll(&pkt);
1604 void Server::SendHUDAdd(session_t peer_id, u32 id, HudElement *form)
1606 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1608 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1609 << form->text << form->number << form->item << form->dir
1610 << form->align << form->offset << form->world_pos << form->size;
1615 void Server::SendHUDRemove(session_t peer_id, u32 id)
1617 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1622 void Server::SendHUDChange(session_t peer_id, u32 id, HudElementStat stat, void *value)
1624 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1625 pkt << id << (u8) stat;
1629 case HUD_STAT_SCALE:
1630 case HUD_STAT_ALIGN:
1631 case HUD_STAT_OFFSET:
1632 pkt << *(v2f *) value;
1636 pkt << *(std::string *) value;
1638 case HUD_STAT_WORLD_POS:
1639 pkt << *(v3f *) value;
1642 pkt << *(v2s32 *) value;
1644 case HUD_STAT_NUMBER:
1648 pkt << *(u32 *) value;
1655 void Server::SendHUDSetFlags(session_t peer_id, u32 flags, u32 mask)
1657 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1659 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1661 pkt << flags << mask;
1666 void Server::SendHUDSetParam(session_t peer_id, u16 param, const std::string &value)
1668 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1669 pkt << param << value;
1673 void Server::SendSetSky(session_t peer_id, const video::SColor &bgcolor,
1674 const std::string &type, const std::vector<std::string> ¶ms,
1677 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1678 pkt << bgcolor << type << (u16) params.size();
1680 for (const std::string ¶m : params)
1688 void Server::SendCloudParams(session_t peer_id, const CloudParams ¶ms)
1690 NetworkPacket pkt(TOCLIENT_CLOUD_PARAMS, 0, peer_id);
1691 pkt << params.density << params.color_bright << params.color_ambient
1692 << params.height << params.thickness << params.speed;
1696 void Server::SendOverrideDayNightRatio(session_t peer_id, bool do_override,
1699 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1702 pkt << do_override << (u16) (ratio * 65535);
1707 void Server::SendTimeOfDay(session_t peer_id, u16 time, f32 time_speed)
1709 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1710 pkt << time << time_speed;
1712 if (peer_id == PEER_ID_INEXISTENT) {
1713 m_clients.sendToAll(&pkt);
1720 void Server::SendPlayerHP(session_t peer_id)
1722 PlayerSAO *playersao = getPlayerSAO(peer_id);
1723 // In some rare case if the player is disconnected
1724 // while Lua call l_punch, for example, this can be NULL
1728 SendHP(peer_id, playersao->getHP());
1729 m_script->player_event(playersao,"health_changed");
1731 // Send to other clients
1732 std::string str = gob_cmd_punched(playersao->getHP());
1733 ActiveObjectMessage aom(playersao->getId(), true, str);
1734 playersao->m_messages_out.push(aom);
1737 void Server::SendPlayerBreath(PlayerSAO *sao)
1741 m_script->player_event(sao, "breath_changed");
1742 SendBreath(sao->getPeerID(), sao->getBreath());
1745 void Server::SendMovePlayer(session_t peer_id)
1747 RemotePlayer *player = m_env->getPlayer(peer_id);
1749 PlayerSAO *sao = player->getPlayerSAO();
1752 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1753 pkt << sao->getBasePosition() << sao->getLookPitch() << sao->getRotation().Y;
1756 v3f pos = sao->getBasePosition();
1757 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1758 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1759 << " pitch=" << sao->getLookPitch()
1760 << " yaw=" << sao->getRotation().Y
1767 void Server::SendLocalPlayerAnimations(session_t peer_id, v2s32 animation_frames[4],
1768 f32 animation_speed)
1770 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1773 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1774 << animation_frames[3] << animation_speed;
1779 void Server::SendEyeOffset(session_t peer_id, v3f first, v3f third)
1781 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1782 pkt << first << third;
1786 void Server::SendPlayerPrivileges(session_t peer_id)
1788 RemotePlayer *player = m_env->getPlayer(peer_id);
1790 if(player->getPeerId() == PEER_ID_INEXISTENT)
1793 std::set<std::string> privs;
1794 m_script->getAuth(player->getName(), NULL, &privs);
1796 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1797 pkt << (u16) privs.size();
1799 for (const std::string &priv : privs) {
1806 void Server::SendPlayerInventoryFormspec(session_t peer_id)
1808 RemotePlayer *player = m_env->getPlayer(peer_id);
1810 if (player->getPeerId() == PEER_ID_INEXISTENT)
1813 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1814 pkt.putLongString(player->inventory_formspec);
1819 void Server::SendPlayerFormspecPrepend(session_t peer_id)
1821 RemotePlayer *player = m_env->getPlayer(peer_id);
1823 if (player->getPeerId() == PEER_ID_INEXISTENT)
1826 NetworkPacket pkt(TOCLIENT_FORMSPEC_PREPEND, 0, peer_id);
1827 pkt << player->formspec_prepend;
1831 void Server::SendActiveObjectRemoveAdd(RemoteClient *client, PlayerSAO *playersao)
1833 // Radius inside which objects are active
1834 static thread_local const s16 radius =
1835 g_settings->getS16("active_object_send_range_blocks") * MAP_BLOCKSIZE;
1837 // Radius inside which players are active
1838 static thread_local const bool is_transfer_limited =
1839 g_settings->exists("unlimited_player_transfer_distance") &&
1840 !g_settings->getBool("unlimited_player_transfer_distance");
1842 static thread_local const s16 player_transfer_dist =
1843 g_settings->getS16("player_transfer_distance") * MAP_BLOCKSIZE;
1845 s16 player_radius = player_transfer_dist == 0 && is_transfer_limited ?
1846 radius : player_transfer_dist;
1848 s16 my_radius = MYMIN(radius, playersao->getWantedRange() * MAP_BLOCKSIZE);
1852 std::queue<u16> removed_objects, added_objects;
1853 m_env->getRemovedActiveObjects(playersao, my_radius, player_radius,
1854 client->m_known_objects, removed_objects);
1855 m_env->getAddedActiveObjects(playersao, my_radius, player_radius,
1856 client->m_known_objects, added_objects);
1858 int removed_count = removed_objects.size();
1859 int added_count = added_objects.size();
1861 if (removed_objects.empty() && added_objects.empty())
1867 // Handle removed objects
1868 writeU16((u8*)buf, removed_objects.size());
1869 data.append(buf, 2);
1870 while (!removed_objects.empty()) {
1872 u16 id = removed_objects.front();
1873 ServerActiveObject* obj = m_env->getActiveObject(id);
1875 // Add to data buffer for sending
1876 writeU16((u8*)buf, id);
1877 data.append(buf, 2);
1879 // Remove from known objects
1880 client->m_known_objects.erase(id);
1882 if (obj && obj->m_known_by_count > 0)
1883 obj->m_known_by_count--;
1885 removed_objects.pop();
1888 // Handle added objects
1889 writeU16((u8*)buf, added_objects.size());
1890 data.append(buf, 2);
1891 while (!added_objects.empty()) {
1893 u16 id = added_objects.front();
1894 ServerActiveObject* obj = m_env->getActiveObject(id);
1897 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1899 warningstream << FUNCTION_NAME << ": NULL object" << std::endl;
1901 type = obj->getSendType();
1903 // Add to data buffer for sending
1904 writeU16((u8*)buf, id);
1905 data.append(buf, 2);
1906 writeU8((u8*)buf, type);
1907 data.append(buf, 1);
1910 data.append(serializeLongString(
1911 obj->getClientInitializationData(client->net_proto_version)));
1913 data.append(serializeLongString(""));
1915 // Add to known objects
1916 client->m_known_objects.insert(id);
1919 obj->m_known_by_count++;
1921 added_objects.pop();
1924 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, data.size(), client->peer_id);
1925 pkt.putRawString(data.c_str(), data.size());
1928 verbosestream << "Server::SendActiveObjectRemoveAdd: "
1929 << removed_count << " removed, " << added_count << " added, "
1930 << "packet size is " << pkt.getSize() << std::endl;
1933 void Server::SendActiveObjectMessages(session_t peer_id, const std::string &datas,
1936 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
1937 datas.size(), peer_id);
1939 pkt.putRawString(datas.c_str(), datas.size());
1941 m_clients.send(pkt.getPeerId(),
1942 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
1946 void Server::SendCSMRestrictionFlags(session_t peer_id)
1948 NetworkPacket pkt(TOCLIENT_CSM_RESTRICTION_FLAGS,
1949 sizeof(m_csm_restriction_flags) + sizeof(m_csm_restriction_noderange), peer_id);
1950 pkt << m_csm_restriction_flags << m_csm_restriction_noderange;
1954 void Server::SendPlayerSpeed(session_t peer_id, const v3f &added_vel)
1956 NetworkPacket pkt(TOCLIENT_PLAYER_SPEED, 0, peer_id);
1961 s32 Server::playSound(const SimpleSoundSpec &spec,
1962 const ServerSoundParams ¶ms)
1964 // Find out initial position of sound
1965 bool pos_exists = false;
1966 v3f pos = params.getPos(m_env, &pos_exists);
1967 // If position is not found while it should be, cancel sound
1968 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
1971 // Filter destination clients
1972 std::vector<session_t> dst_clients;
1973 if(!params.to_player.empty()) {
1974 RemotePlayer *player = m_env->getPlayer(params.to_player.c_str());
1976 infostream<<"Server::playSound: Player \""<<params.to_player
1977 <<"\" not found"<<std::endl;
1980 if (player->getPeerId() == PEER_ID_INEXISTENT) {
1981 infostream<<"Server::playSound: Player \""<<params.to_player
1982 <<"\" not connected"<<std::endl;
1985 dst_clients.push_back(player->getPeerId());
1987 std::vector<session_t> clients = m_clients.getClientIDs();
1989 for (const session_t client_id : clients) {
1990 RemotePlayer *player = m_env->getPlayer(client_id);
1994 PlayerSAO *sao = player->getPlayerSAO();
1999 if(sao->getBasePosition().getDistanceFrom(pos) >
2000 params.max_hear_distance)
2003 dst_clients.push_back(client_id);
2007 if(dst_clients.empty())
2011 s32 id = m_next_sound_id++;
2012 // The sound will exist as a reference in m_playing_sounds
2013 m_playing_sounds[id] = ServerPlayingSound();
2014 ServerPlayingSound &psound = m_playing_sounds[id];
2015 psound.params = params;
2018 float gain = params.gain * spec.gain;
2019 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2020 pkt << id << spec.name << gain
2021 << (u8) params.type << pos << params.object
2022 << params.loop << params.fade << params.pitch;
2024 // Backwards compability
2025 bool play_sound = gain > 0;
2027 for (const u16 dst_client : dst_clients) {
2028 if (play_sound || m_clients.getProtocolVersion(dst_client) >= 32) {
2029 psound.clients.insert(dst_client);
2030 m_clients.send(dst_client, 0, &pkt, true);
2035 void Server::stopSound(s32 handle)
2037 // Get sound reference
2038 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2039 m_playing_sounds.find(handle);
2040 if (i == m_playing_sounds.end())
2042 ServerPlayingSound &psound = i->second;
2044 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2047 for (std::unordered_set<session_t>::const_iterator si = psound.clients.begin();
2048 si != psound.clients.end(); ++si) {
2050 m_clients.send(*si, 0, &pkt, true);
2052 // Remove sound reference
2053 m_playing_sounds.erase(i);
2056 void Server::fadeSound(s32 handle, float step, float gain)
2058 // Get sound reference
2059 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2060 m_playing_sounds.find(handle);
2061 if (i == m_playing_sounds.end())
2064 ServerPlayingSound &psound = i->second;
2065 psound.params.gain = gain;
2067 NetworkPacket pkt(TOCLIENT_FADE_SOUND, 4);
2068 pkt << handle << step << gain;
2070 // Backwards compability
2071 bool play_sound = gain > 0;
2072 ServerPlayingSound compat_psound = psound;
2073 compat_psound.clients.clear();
2075 NetworkPacket compat_pkt(TOCLIENT_STOP_SOUND, 4);
2076 compat_pkt << handle;
2078 for (std::unordered_set<u16>::iterator it = psound.clients.begin();
2079 it != psound.clients.end();) {
2080 if (m_clients.getProtocolVersion(*it) >= 32) {
2082 m_clients.send(*it, 0, &pkt, true);
2085 compat_psound.clients.insert(*it);
2087 m_clients.send(*it, 0, &compat_pkt, true);
2088 psound.clients.erase(it++);
2092 // Remove sound reference
2093 if (!play_sound || psound.clients.empty())
2094 m_playing_sounds.erase(i);
2096 if (play_sound && !compat_psound.clients.empty()) {
2097 // Play new sound volume on older clients
2098 playSound(compat_psound.spec, compat_psound.params);
2102 void Server::sendRemoveNode(v3s16 p, std::unordered_set<u16> *far_players,
2105 float maxd = far_d_nodes * BS;
2106 v3f p_f = intToFloat(p, BS);
2107 v3s16 block_pos = getNodeBlockPos(p);
2109 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2112 std::vector<session_t> clients = m_clients.getClientIDs();
2115 for (session_t client_id : clients) {
2116 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
2120 RemotePlayer *player = m_env->getPlayer(client_id);
2121 PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr;
2123 // If player is far away, only set modified blocks not sent
2124 if (!client->isBlockSent(block_pos) || (sao &&
2125 sao->getBasePosition().getDistanceFrom(p_f) > maxd)) {
2127 far_players->emplace(client_id);
2129 client->SetBlockNotSent(block_pos);
2134 m_clients.send(client_id, 0, &pkt, true);
2140 void Server::sendAddNode(v3s16 p, MapNode n, std::unordered_set<u16> *far_players,
2141 float far_d_nodes, bool remove_metadata)
2143 float maxd = far_d_nodes * BS;
2144 v3f p_f = intToFloat(p, BS);
2145 v3s16 block_pos = getNodeBlockPos(p);
2147 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2148 pkt << p << n.param0 << n.param1 << n.param2
2149 << (u8) (remove_metadata ? 0 : 1);
2151 std::vector<session_t> clients = m_clients.getClientIDs();
2154 for (session_t client_id : clients) {
2155 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
2159 RemotePlayer *player = m_env->getPlayer(client_id);
2160 PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr;
2162 // If player is far away, only set modified blocks not sent
2163 if (!client->isBlockSent(block_pos) || (sao &&
2164 sao->getBasePosition().getDistanceFrom(p_f) > maxd)) {
2166 far_players->emplace(client_id);
2168 client->SetBlockNotSent(block_pos);
2173 m_clients.send(client_id, 0, &pkt, true);
2179 void Server::sendMetadataChanged(const std::list<v3s16> &meta_updates, float far_d_nodes)
2181 float maxd = far_d_nodes * BS;
2182 NodeMetadataList meta_updates_list(false);
2183 std::vector<session_t> clients = m_clients.getClientIDs();
2187 for (session_t i : clients) {
2188 RemoteClient *client = m_clients.lockedGetClientNoEx(i);
2192 ServerActiveObject *player = m_env->getActiveObject(i);
2193 v3f player_pos = player ? player->getBasePosition() : v3f();
2195 for (const v3s16 &pos : meta_updates) {
2196 NodeMetadata *meta = m_env->getMap().getNodeMetadata(pos);
2201 v3s16 block_pos = getNodeBlockPos(pos);
2202 if (!client->isBlockSent(block_pos) || (player &&
2203 player_pos.getDistanceFrom(intToFloat(pos, BS)) > maxd)) {
2204 client->SetBlockNotSent(block_pos);
2208 // Add the change to send list
2209 meta_updates_list.set(pos, meta);
2211 if (meta_updates_list.size() == 0)
2214 // Send the meta changes
2215 std::ostringstream os(std::ios::binary);
2216 meta_updates_list.serialize(os, client->net_proto_version, false, true);
2217 std::ostringstream oss(std::ios::binary);
2218 compressZlib(os.str(), oss);
2220 NetworkPacket pkt(TOCLIENT_NODEMETA_CHANGED, 0);
2221 pkt.putLongString(oss.str());
2222 m_clients.send(i, 0, &pkt, true);
2224 meta_updates_list.clear();
2230 void Server::SendBlockNoLock(session_t peer_id, MapBlock *block, u8 ver,
2231 u16 net_proto_version)
2234 Create a packet with the block in the right format
2237 std::ostringstream os(std::ios_base::binary);
2238 block->serialize(os, ver, false);
2239 block->serializeNetworkSpecific(os);
2240 std::string s = os.str();
2242 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2244 pkt << block->getPos();
2245 pkt.putRawString(s.c_str(), s.size());
2249 void Server::SendBlocks(float dtime)
2251 MutexAutoLock envlock(m_env_mutex);
2252 //TODO check if one big lock could be faster then multiple small ones
2254 std::vector<PrioritySortedBlockTransfer> queue;
2256 u32 total_sending = 0;
2259 ScopeProfiler sp2(g_profiler, "Server::SendBlocks(): Collect list");
2261 std::vector<session_t> clients = m_clients.getClientIDs();
2264 for (const session_t client_id : clients) {
2265 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id, CS_Active);
2270 total_sending += client->getSendingCount();
2271 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2277 // Lowest priority number comes first.
2278 // Lowest is most important.
2279 std::sort(queue.begin(), queue.end());
2283 // Maximal total count calculation
2284 // The per-client block sends is halved with the maximal online users
2285 u32 max_blocks_to_send = (m_env->getPlayerCount() + g_settings->getU32("max_users")) *
2286 g_settings->getU32("max_simultaneous_block_sends_per_client") / 4 + 1;
2288 ScopeProfiler sp(g_profiler, "Server::SendBlocks(): Send to clients");
2289 Map &map = m_env->getMap();
2291 for (const PrioritySortedBlockTransfer &block_to_send : queue) {
2292 if (total_sending >= max_blocks_to_send)
2295 MapBlock *block = map.getBlockNoCreateNoEx(block_to_send.pos);
2299 RemoteClient *client = m_clients.lockedGetClientNoEx(block_to_send.peer_id,
2304 SendBlockNoLock(block_to_send.peer_id, block, client->serialization_version,
2305 client->net_proto_version);
2307 client->SentBlock(block_to_send.pos);
2313 bool Server::SendBlock(session_t peer_id, const v3s16 &blockpos)
2315 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2320 RemoteClient *client = m_clients.lockedGetClientNoEx(peer_id, CS_Active);
2321 if (!client || client->isBlockSent(blockpos)) {
2325 SendBlockNoLock(peer_id, block, client->serialization_version,
2326 client->net_proto_version);
2332 void Server::fillMediaCache()
2334 infostream<<"Server: Calculating media file checksums"<<std::endl;
2336 // Collect all media file paths
2337 std::vector<std::string> paths;
2338 m_modmgr->getModsMediaPaths(paths);
2339 fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures");
2340 fs::GetRecursiveDirs(paths, porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2342 // Collect media file information from paths into cache
2343 for (const std::string &mediapath : paths) {
2344 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2345 for (const fs::DirListNode &dln : dirlist) {
2346 if (dln.dir) // Ignode dirs
2348 std::string filename = dln.name;
2349 // If name contains illegal characters, ignore the file
2350 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2351 infostream<<"Server: ignoring illegal file name: \""
2352 << filename << "\"" << std::endl;
2355 // If name is not in a supported format, ignore it
2356 const char *supported_ext[] = {
2357 ".png", ".jpg", ".bmp", ".tga",
2358 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2360 ".x", ".b3d", ".md2", ".obj",
2361 // Custom translation file format
2365 if (removeStringEnd(filename, supported_ext).empty()){
2366 infostream << "Server: ignoring unsupported file extension: \""
2367 << filename << "\"" << std::endl;
2370 // Ok, attempt to load the file and add to cache
2371 std::string filepath;
2372 filepath.append(mediapath).append(DIR_DELIM).append(filename);
2375 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2377 errorstream << "Server::fillMediaCache(): Could not open \""
2378 << filename << "\" for reading" << std::endl;
2381 std::ostringstream tmp_os(std::ios_base::binary);
2385 fis.read(buf, 1024);
2386 std::streamsize len = fis.gcount();
2387 tmp_os.write(buf, len);
2396 errorstream<<"Server::fillMediaCache(): Failed to read \""
2397 << filename << "\"" << std::endl;
2400 if(tmp_os.str().length() == 0) {
2401 errorstream << "Server::fillMediaCache(): Empty file \""
2402 << filepath << "\"" << std::endl;
2407 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2409 unsigned char *digest = sha1.getDigest();
2410 std::string sha1_base64 = base64_encode(digest, 20);
2411 std::string sha1_hex = hex_encode((char*)digest, 20);
2415 m_media[filename] = MediaInfo(filepath, sha1_base64);
2416 verbosestream << "Server: " << sha1_hex << " is " << filename
2422 void Server::sendMediaAnnouncement(session_t peer_id, const std::string &lang_code)
2424 verbosestream << "Server: Announcing files to id(" << peer_id << ")"
2428 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2431 std::string lang_suffix;
2432 lang_suffix.append(".").append(lang_code).append(".tr");
2433 for (const auto &i : m_media) {
2434 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2441 for (const auto &i : m_media) {
2442 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2444 pkt << i.first << i.second.sha1_digest;
2447 pkt << g_settings->get("remote_media");
2451 struct SendableMedia
2457 SendableMedia(const std::string &name_="", const std::string &path_="",
2458 const std::string &data_=""):
2465 void Server::sendRequestedMedia(session_t peer_id,
2466 const std::vector<std::string> &tosend)
2468 verbosestream<<"Server::sendRequestedMedia(): "
2469 <<"Sending files to client"<<std::endl;
2473 // Put 5kB in one bunch (this is not accurate)
2474 u32 bytes_per_bunch = 5000;
2476 std::vector< std::vector<SendableMedia> > file_bunches;
2477 file_bunches.emplace_back();
2479 u32 file_size_bunch_total = 0;
2481 for (const std::string &name : tosend) {
2482 if (m_media.find(name) == m_media.end()) {
2483 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2484 <<"unknown file \""<<(name)<<"\""<<std::endl;
2488 //TODO get path + name
2489 std::string tpath = m_media[name].path;
2492 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2494 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2495 <<tpath<<"\" for reading"<<std::endl;
2498 std::ostringstream tmp_os(std::ios_base::binary);
2502 fis.read(buf, 1024);
2503 std::streamsize len = fis.gcount();
2504 tmp_os.write(buf, len);
2505 file_size_bunch_total += len;
2514 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2515 <<name<<"\""<<std::endl;
2518 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2519 <<tname<<"\""<<std::endl;*/
2521 file_bunches[file_bunches.size()-1].emplace_back(name, tpath, tmp_os.str());
2523 // Start next bunch if got enough data
2524 if(file_size_bunch_total >= bytes_per_bunch) {
2525 file_bunches.emplace_back();
2526 file_size_bunch_total = 0;
2531 /* Create and send packets */
2533 u16 num_bunches = file_bunches.size();
2534 for (u16 i = 0; i < num_bunches; i++) {
2537 u16 total number of texture bunches
2538 u16 index of this bunch
2539 u32 number of files in this bunch
2548 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2549 pkt << num_bunches << i << (u32) file_bunches[i].size();
2551 for (const SendableMedia &j : file_bunches[i]) {
2553 pkt.putLongString(j.data);
2556 verbosestream << "Server::sendRequestedMedia(): bunch "
2557 << i << "/" << num_bunches
2558 << " files=" << file_bunches[i].size()
2559 << " size=" << pkt.getSize() << std::endl;
2564 void Server::sendDetachedInventory(const std::string &name, session_t peer_id)
2566 const auto &inv_it = m_detached_inventories.find(name);
2567 const auto &player_it = m_detached_inventories_player.find(name);
2569 if (player_it == m_detached_inventories_player.end() ||
2570 player_it->second.empty()) {
2571 // OK. Send to everyone
2574 return; // Mods are not done loading
2576 RemotePlayer *p = m_env->getPlayer(player_it->second.c_str());
2578 return; // Player is offline
2580 if (peer_id != PEER_ID_INEXISTENT && peer_id != p->getPeerId())
2581 return; // Caller requested send to a different player, so don't send.
2583 peer_id = p->getPeerId();
2586 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2589 if (inv_it == m_detached_inventories.end()) {
2590 pkt << false; // Remove inventory
2592 pkt << true; // Update inventory
2594 // Serialization & NetworkPacket isn't a love story
2595 std::ostringstream os(std::ios_base::binary);
2596 inv_it->second->serialize(os);
2597 inv_it->second->setModified(false);
2599 const std::string &os_str = os.str();
2600 pkt << static_cast<u16>(os_str.size()); // HACK: to keep compatibility with 5.0.0 clients
2601 pkt.putRawString(os_str);
2604 if (peer_id == PEER_ID_INEXISTENT)
2605 m_clients.sendToAll(&pkt);
2610 void Server::sendDetachedInventories(session_t peer_id, bool incremental)
2612 for (const auto &detached_inventory : m_detached_inventories) {
2613 const std::string &name = detached_inventory.first;
2615 Inventory *inv = detached_inventory.second;
2616 if (!inv || !inv->checkModified())
2620 sendDetachedInventory(name, peer_id);
2628 void Server::DiePlayer(session_t peer_id, const PlayerHPChangeReason &reason)
2630 PlayerSAO *playersao = getPlayerSAO(peer_id);
2631 // In some rare cases this can be NULL -- if the player is disconnected
2632 // when a Lua function modifies l_punch, for example
2636 infostream << "Server::DiePlayer(): Player "
2637 << playersao->getPlayer()->getName()
2638 << " dies" << std::endl;
2640 playersao->setHP(0, reason);
2641 playersao->clearParentAttachment();
2643 // Trigger scripted stuff
2644 m_script->on_dieplayer(playersao, reason);
2646 SendPlayerHP(peer_id);
2647 SendDeathscreen(peer_id, false, v3f(0,0,0));
2650 void Server::RespawnPlayer(session_t peer_id)
2652 PlayerSAO *playersao = getPlayerSAO(peer_id);
2655 infostream << "Server::RespawnPlayer(): Player "
2656 << playersao->getPlayer()->getName()
2657 << " respawns" << std::endl;
2659 playersao->setHP(playersao->accessObjectProperties()->hp_max,
2660 PlayerHPChangeReason(PlayerHPChangeReason::RESPAWN));
2661 playersao->setBreath(playersao->accessObjectProperties()->breath_max);
2663 bool repositioned = m_script->on_respawnplayer(playersao);
2664 if (!repositioned) {
2665 // setPos will send the new position to client
2666 playersao->setPos(findSpawnPos());
2669 SendPlayerHP(peer_id);
2673 void Server::DenySudoAccess(session_t peer_id)
2675 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2680 void Server::DenyAccessVerCompliant(session_t peer_id, u16 proto_ver, AccessDeniedCode reason,
2681 const std::string &str_reason, bool reconnect)
2683 SendAccessDenied(peer_id, reason, str_reason, reconnect);
2685 m_clients.event(peer_id, CSE_SetDenied);
2686 DisconnectPeer(peer_id);
2690 void Server::DenyAccess(session_t peer_id, AccessDeniedCode reason,
2691 const std::string &custom_reason)
2693 SendAccessDenied(peer_id, reason, custom_reason);
2694 m_clients.event(peer_id, CSE_SetDenied);
2695 DisconnectPeer(peer_id);
2698 // 13/03/15: remove this function when protocol version 25 will become
2699 // the minimum version for MT users, maybe in 1 year
2700 void Server::DenyAccess_Legacy(session_t peer_id, const std::wstring &reason)
2702 SendAccessDenied_Legacy(peer_id, reason);
2703 m_clients.event(peer_id, CSE_SetDenied);
2704 DisconnectPeer(peer_id);
2707 void Server::DisconnectPeer(session_t peer_id)
2709 m_modchannel_mgr->leaveAllChannels(peer_id);
2710 m_con->DisconnectPeer(peer_id);
2713 void Server::acceptAuth(session_t peer_id, bool forSudoMode)
2716 RemoteClient* client = getClient(peer_id, CS_Invalid);
2718 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2720 // Right now, the auth mechs don't change between login and sudo mode.
2721 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2722 client->allowed_sudo_mechs = sudo_auth_mechs;
2724 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2725 << g_settings->getFloat("dedicated_server_step")
2729 m_clients.event(peer_id, CSE_AuthAccept);
2731 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2733 // We only support SRP right now
2734 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2736 resp_pkt << sudo_auth_mechs;
2738 m_clients.event(peer_id, CSE_SudoSuccess);
2742 void Server::DeleteClient(session_t peer_id, ClientDeletionReason reason)
2744 std::wstring message;
2747 Clear references to playing sounds
2749 for (std::unordered_map<s32, ServerPlayingSound>::iterator
2750 i = m_playing_sounds.begin(); i != m_playing_sounds.end();) {
2751 ServerPlayingSound &psound = i->second;
2752 psound.clients.erase(peer_id);
2753 if (psound.clients.empty())
2754 m_playing_sounds.erase(i++);
2759 // clear formspec info so the next client can't abuse the current state
2760 m_formspec_state_data.erase(peer_id);
2762 RemotePlayer *player = m_env->getPlayer(peer_id);
2764 /* Run scripts and remove from environment */
2766 PlayerSAO *playersao = player->getPlayerSAO();
2769 playersao->clearChildAttachments();
2770 playersao->clearParentAttachment();
2772 // inform connected clients
2773 const std::string &player_name = player->getName();
2774 NetworkPacket notice(TOCLIENT_UPDATE_PLAYER_LIST, 0, PEER_ID_INEXISTENT);
2775 // (u16) 1 + std::string represents a vector serialization representation
2776 notice << (u8) PLAYER_LIST_REMOVE << (u16) 1 << player_name;
2777 m_clients.sendToAll(¬ice);
2779 m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
2781 playersao->disconnected();
2788 if (player && reason != CDR_DENY) {
2789 std::ostringstream os(std::ios_base::binary);
2790 std::vector<session_t> clients = m_clients.getClientIDs();
2792 for (const session_t client_id : clients) {
2794 RemotePlayer *player = m_env->getPlayer(client_id);
2798 // Get name of player
2799 os << player->getName() << " ";
2802 std::string name = player->getName();
2803 actionstream << name << " "
2804 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2805 << " List of players: " << os.str() << std::endl;
2807 m_admin_chat->outgoing_queue.push_back(
2808 new ChatEventNick(CET_NICK_REMOVE, name));
2812 MutexAutoLock env_lock(m_env_mutex);
2813 m_clients.DeleteClient(peer_id);
2817 // Send leave chat message to all remaining clients
2818 if (!message.empty()) {
2819 SendChatMessage(PEER_ID_INEXISTENT,
2820 ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE, message));
2824 void Server::UpdateCrafting(RemotePlayer *player)
2826 InventoryList *clist = player->inventory.getList("craft");
2827 if (!clist || clist->getSize() == 0)
2830 if (!clist->checkModified()) {
2831 verbosestream << "Skip Server::UpdateCrafting(): list unmodified" << std::endl;
2835 // Get a preview for crafting
2837 InventoryLocation loc;
2838 loc.setPlayer(player->getName());
2839 std::vector<ItemStack> output_replacements;
2840 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2841 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(),
2844 InventoryList *plist = player->inventory.getList("craftpreview");
2845 if (plist && plist->getSize() >= 1) {
2846 // Put the new preview in
2847 plist->changeItem(0, preview);
2851 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2853 if (evt->type == CET_NICK_ADD) {
2854 // The terminal informed us of its nick choice
2855 m_admin_nick = ((ChatEventNick *)evt)->nick;
2856 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2857 errorstream << "You haven't set up an account." << std::endl
2858 << "Please log in using the client as '"
2859 << m_admin_nick << "' with a secure password." << std::endl
2860 << "Until then, you can't execute admin tasks via the console," << std::endl
2861 << "and everybody can claim the user account instead of you," << std::endl
2862 << "giving them full control over this server." << std::endl;
2865 assert(evt->type == CET_CHAT);
2866 handleAdminChat((ChatEventChat *)evt);
2870 std::wstring Server::handleChat(const std::string &name, const std::wstring &wname,
2871 std::wstring wmessage, bool check_shout_priv, RemotePlayer *player)
2873 // If something goes wrong, this player is to blame
2874 RollbackScopeActor rollback_scope(m_rollback,
2875 std::string("player:") + name);
2877 if (g_settings->getBool("strip_color_codes"))
2878 wmessage = unescape_enriched(wmessage);
2881 switch (player->canSendChatMessage()) {
2882 case RPLAYER_CHATRESULT_FLOODING: {
2883 std::wstringstream ws;
2884 ws << L"You cannot send more messages. You are limited to "
2885 << g_settings->getFloat("chat_message_limit_per_10sec")
2886 << L" messages per 10 seconds.";
2889 case RPLAYER_CHATRESULT_KICK:
2890 DenyAccess_Legacy(player->getPeerId(),
2891 L"You have been kicked due to message flooding.");
2893 case RPLAYER_CHATRESULT_OK:
2896 FATAL_ERROR("Unhandled chat filtering result found.");
2900 if (m_max_chatmessage_length > 0
2901 && wmessage.length() > m_max_chatmessage_length) {
2902 return L"Your message exceed the maximum chat message limit set on the server. "
2903 L"It was refused. Send a shorter message";
2906 auto message = trim(wide_to_utf8(wmessage));
2907 if (message.find_first_of("\n\r") != std::wstring::npos) {
2908 return L"New lines are not permitted in chat messages";
2911 // Run script hook, exit if script ate the chat message
2912 if (m_script->on_chat_message(name, message))
2917 // Whether to send line to the player that sent the message, or to all players
2918 bool broadcast_line = true;
2920 if (check_shout_priv && !checkPriv(name, "shout")) {
2921 line += L"-!- You don't have permission to shout.";
2922 broadcast_line = false;
2924 line += narrow_to_wide(m_script->formatChatMessage(name,
2925 wide_to_narrow(wmessage)));
2929 Tell calling method to send the message to sender
2931 if (!broadcast_line)
2935 Send the message to others
2937 actionstream << "CHAT: " << wide_to_narrow(unescape_enriched(line)) << std::endl;
2939 std::vector<session_t> clients = m_clients.getClientIDs();
2942 Send the message back to the inital sender
2943 if they are using protocol version >= 29
2946 session_t peer_id_to_avoid_sending =
2947 (player ? player->getPeerId() : PEER_ID_INEXISTENT);
2949 if (player && player->protocol_version >= 29)
2950 peer_id_to_avoid_sending = PEER_ID_INEXISTENT;
2952 for (u16 cid : clients) {
2953 if (cid != peer_id_to_avoid_sending)
2954 SendChatMessage(cid, ChatMessage(line));
2959 void Server::handleAdminChat(const ChatEventChat *evt)
2961 std::string name = evt->nick;
2962 std::wstring wname = utf8_to_wide(name);
2963 std::wstring wmessage = evt->evt_msg;
2965 std::wstring answer = handleChat(name, wname, wmessage);
2967 // If asked to send answer to sender
2968 if (!answer.empty()) {
2969 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
2973 RemoteClient *Server::getClient(session_t peer_id, ClientState state_min)
2975 RemoteClient *client = getClientNoEx(peer_id,state_min);
2977 throw ClientNotFoundException("Client not found");
2981 RemoteClient *Server::getClientNoEx(session_t peer_id, ClientState state_min)
2983 return m_clients.getClientNoEx(peer_id, state_min);
2986 std::string Server::getPlayerName(session_t peer_id)
2988 RemotePlayer *player = m_env->getPlayer(peer_id);
2990 return "[id="+itos(peer_id)+"]";
2991 return player->getName();
2994 PlayerSAO *Server::getPlayerSAO(session_t peer_id)
2996 RemotePlayer *player = m_env->getPlayer(peer_id);
2999 return player->getPlayerSAO();
3002 std::wstring Server::getStatusString()
3004 std::wostringstream os(std::ios_base::binary);
3005 os << L"# Server: ";
3007 os << L"version=" << narrow_to_wide(g_version_string);
3009 os << L", uptime=" << m_uptime.get();
3011 os << L", max_lag=" << (m_env ? m_env->getMaxLagEstimate() : 0);
3013 // Information about clients
3015 os << L", clients={";
3017 std::vector<session_t> clients = m_clients.getClientIDs();
3018 for (session_t client_id : clients) {
3019 RemotePlayer *player = m_env->getPlayer(client_id);
3021 // Get name of player
3022 std::wstring name = L"unknown";
3024 name = narrow_to_wide(player->getName());
3026 // Add name to information string
3037 if (m_env && !((ServerMap*)(&m_env->getMap()))->isSavingEnabled())
3038 os << std::endl << L"# Server: " << " WARNING: Map saving is disabled.";
3040 if (!g_settings->get("motd").empty())
3041 os << std::endl << L"# Server: " << narrow_to_wide(g_settings->get("motd"));
3046 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
3048 std::set<std::string> privs;
3049 m_script->getAuth(name, NULL, &privs);
3053 bool Server::checkPriv(const std::string &name, const std::string &priv)
3055 std::set<std::string> privs = getPlayerEffectivePrivs(name);
3056 return (privs.count(priv) != 0);
3059 void Server::reportPrivsModified(const std::string &name)
3062 std::vector<session_t> clients = m_clients.getClientIDs();
3063 for (const session_t client_id : clients) {
3064 RemotePlayer *player = m_env->getPlayer(client_id);
3065 reportPrivsModified(player->getName());
3068 RemotePlayer *player = m_env->getPlayer(name.c_str());
3071 SendPlayerPrivileges(player->getPeerId());
3072 PlayerSAO *sao = player->getPlayerSAO();
3075 sao->updatePrivileges(
3076 getPlayerEffectivePrivs(name),
3081 void Server::reportInventoryFormspecModified(const std::string &name)
3083 RemotePlayer *player = m_env->getPlayer(name.c_str());
3086 SendPlayerInventoryFormspec(player->getPeerId());
3089 void Server::reportFormspecPrependModified(const std::string &name)
3091 RemotePlayer *player = m_env->getPlayer(name.c_str());
3094 SendPlayerFormspecPrepend(player->getPeerId());
3097 void Server::setIpBanned(const std::string &ip, const std::string &name)
3099 m_banmanager->add(ip, name);
3102 void Server::unsetIpBanned(const std::string &ip_or_name)
3104 m_banmanager->remove(ip_or_name);
3107 std::string Server::getBanDescription(const std::string &ip_or_name)
3109 return m_banmanager->getBanDescription(ip_or_name);
3112 void Server::notifyPlayer(const char *name, const std::wstring &msg)
3114 // m_env will be NULL if the server is initializing
3118 if (m_admin_nick == name && !m_admin_nick.empty()) {
3119 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
3122 RemotePlayer *player = m_env->getPlayer(name);
3127 if (player->getPeerId() == PEER_ID_INEXISTENT)
3130 SendChatMessage(player->getPeerId(), ChatMessage(msg));
3133 bool Server::showFormspec(const char *playername, const std::string &formspec,
3134 const std::string &formname)
3136 // m_env will be NULL if the server is initializing
3140 RemotePlayer *player = m_env->getPlayer(playername);
3144 SendShowFormspecMessage(player->getPeerId(), formspec, formname);
3148 u32 Server::hudAdd(RemotePlayer *player, HudElement *form)
3153 u32 id = player->addHud(form);
3155 SendHUDAdd(player->getPeerId(), id, form);
3160 bool Server::hudRemove(RemotePlayer *player, u32 id) {
3164 HudElement* todel = player->removeHud(id);
3171 SendHUDRemove(player->getPeerId(), id);
3175 bool Server::hudChange(RemotePlayer *player, u32 id, HudElementStat stat, void *data)
3180 SendHUDChange(player->getPeerId(), id, stat, data);
3184 bool Server::hudSetFlags(RemotePlayer *player, u32 flags, u32 mask)
3189 SendHUDSetFlags(player->getPeerId(), flags, mask);
3190 player->hud_flags &= ~mask;
3191 player->hud_flags |= flags;
3193 PlayerSAO* playersao = player->getPlayerSAO();
3198 m_script->player_event(playersao, "hud_changed");
3202 bool Server::hudSetHotbarItemcount(RemotePlayer *player, s32 hotbar_itemcount)
3207 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3210 player->setHotbarItemcount(hotbar_itemcount);
3211 std::ostringstream os(std::ios::binary);
3212 writeS32(os, hotbar_itemcount);
3213 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3217 void Server::hudSetHotbarImage(RemotePlayer *player, const std::string &name)
3222 player->setHotbarImage(name);
3223 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_IMAGE, name);
3226 void Server::hudSetHotbarSelectedImage(RemotePlayer *player, const std::string &name)
3231 player->setHotbarSelectedImage(name);
3232 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3235 Address Server::getPeerAddress(session_t peer_id)
3237 return m_con->GetPeerAddress(peer_id);
3240 void Server::setLocalPlayerAnimations(RemotePlayer *player,
3241 v2s32 animation_frames[4], f32 frame_speed)
3243 sanity_check(player);
3244 player->setLocalAnimations(animation_frames, frame_speed);
3245 SendLocalPlayerAnimations(player->getPeerId(), animation_frames, frame_speed);
3248 void Server::setPlayerEyeOffset(RemotePlayer *player, const v3f &first, const v3f &third)
3250 sanity_check(player);
3251 player->eye_offset_first = first;
3252 player->eye_offset_third = third;
3253 SendEyeOffset(player->getPeerId(), first, third);
3256 void Server::setSky(RemotePlayer *player, const video::SColor &bgcolor,
3257 const std::string &type, const std::vector<std::string> ¶ms,
3260 sanity_check(player);
3261 player->setSky(bgcolor, type, params, clouds);
3262 SendSetSky(player->getPeerId(), bgcolor, type, params, clouds);
3265 void Server::setClouds(RemotePlayer *player, const CloudParams ¶ms)
3267 sanity_check(player);
3268 player->setCloudParams(params);
3269 SendCloudParams(player->getPeerId(), params);
3272 bool Server::overrideDayNightRatio(RemotePlayer *player, bool do_override,
3278 player->overrideDayNightRatio(do_override, ratio);
3279 SendOverrideDayNightRatio(player->getPeerId(), do_override, ratio);
3283 void Server::notifyPlayers(const std::wstring &msg)
3285 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(msg));
3288 void Server::spawnParticle(const std::string &playername, v3f pos,
3289 v3f velocity, v3f acceleration,
3290 float expirationtime, float size, bool
3291 collisiondetection, bool collision_removal, bool object_collision,
3292 bool vertical, const std::string &texture,
3293 const struct TileAnimationParams &animation, u8 glow)
3295 // m_env will be NULL if the server is initializing
3299 session_t peer_id = PEER_ID_INEXISTENT;
3301 if (!playername.empty()) {
3302 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3305 peer_id = player->getPeerId();
3306 proto_ver = player->protocol_version;
3309 SendSpawnParticle(peer_id, proto_ver, pos, velocity, acceleration,
3310 expirationtime, size, collisiondetection, collision_removal,
3311 object_collision, vertical, texture, animation, glow);
3314 u32 Server::addParticleSpawner(u16 amount, float spawntime,
3315 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
3316 float minexptime, float maxexptime, float minsize, float maxsize,
3317 bool collisiondetection, bool collision_removal, bool object_collision,
3318 ServerActiveObject *attached, bool vertical, const std::string &texture,
3319 const std::string &playername, const struct TileAnimationParams &animation,
3322 // m_env will be NULL if the server is initializing
3326 session_t peer_id = PEER_ID_INEXISTENT;
3328 if (!playername.empty()) {
3329 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3332 peer_id = player->getPeerId();
3333 proto_ver = player->protocol_version;
3336 u16 attached_id = attached ? attached->getId() : 0;
3339 if (attached_id == 0)
3340 id = m_env->addParticleSpawner(spawntime);
3342 id = m_env->addParticleSpawner(spawntime, attached_id);
3344 SendAddParticleSpawner(peer_id, proto_ver, amount, spawntime,
3345 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3346 minexptime, maxexptime, minsize, maxsize, collisiondetection,
3347 collision_removal, object_collision, attached_id, vertical,
3348 texture, id, animation, glow);
3353 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3355 // m_env will be NULL if the server is initializing
3357 throw ServerError("Can't delete particle spawners during initialisation!");
3359 session_t peer_id = PEER_ID_INEXISTENT;
3360 if (!playername.empty()) {
3361 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3364 peer_id = player->getPeerId();
3367 m_env->deleteParticleSpawner(id);
3368 SendDeleteParticleSpawner(peer_id, id);
3371 Inventory* Server::createDetachedInventory(const std::string &name, const std::string &player)
3373 if(m_detached_inventories.count(name) > 0){
3374 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3375 delete m_detached_inventories[name];
3377 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3379 Inventory *inv = new Inventory(m_itemdef);
3381 m_detached_inventories[name] = inv;
3382 if (!player.empty())
3383 m_detached_inventories_player[name] = player;
3385 //TODO find a better way to do this
3386 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3390 bool Server::removeDetachedInventory(const std::string &name)
3392 const auto &inv_it = m_detached_inventories.find(name);
3393 if (inv_it == m_detached_inventories.end())
3396 delete inv_it->second;
3397 m_detached_inventories.erase(inv_it);
3399 if (!m_env) // Mods are not done loading
3402 const auto &player_it = m_detached_inventories_player.find(name);
3403 if (player_it != m_detached_inventories_player.end()) {
3404 RemotePlayer *player = m_env->getPlayer(player_it->second.c_str());
3406 if (player && player->getPeerId() != PEER_ID_INEXISTENT)
3407 sendDetachedInventory(name, player->getPeerId());
3409 m_detached_inventories_player.erase(player_it);
3411 // Notify all players about the change
3412 sendDetachedInventory(name, PEER_ID_INEXISTENT);
3417 // actions: time-reversed list
3418 // Return value: success/failure
3419 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3420 std::list<std::string> *log)
3422 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3423 ServerMap *map = (ServerMap*)(&m_env->getMap());
3425 // Fail if no actions to handle
3426 if (actions.empty()) {
3428 log->push_back("Nothing to do.");
3435 for (const RollbackAction &action : actions) {
3437 bool success = action.applyRevert(map, this, this);
3440 std::ostringstream os;
3441 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3442 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3444 log->push_back(os.str());
3446 std::ostringstream os;
3447 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3448 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3450 log->push_back(os.str());
3454 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3455 <<" failed"<<std::endl;
3457 // Call it done if less than half failed
3458 return num_failed <= num_tried/2;
3461 // IGameDef interface
3463 IItemDefManager *Server::getItemDefManager()
3468 const NodeDefManager *Server::getNodeDefManager()
3473 ICraftDefManager *Server::getCraftDefManager()
3478 u16 Server::allocateUnknownNodeId(const std::string &name)
3480 return m_nodedef->allocateDummy(name);
3483 IWritableItemDefManager *Server::getWritableItemDefManager()
3488 NodeDefManager *Server::getWritableNodeDefManager()
3493 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3498 const std::vector<ModSpec> & Server::getMods() const
3500 return m_modmgr->getMods();
3503 const ModSpec *Server::getModSpec(const std::string &modname) const
3505 return m_modmgr->getModSpec(modname);
3508 void Server::getModNames(std::vector<std::string> &modlist)
3510 m_modmgr->getModNames(modlist);
3513 std::string Server::getBuiltinLuaPath()
3515 return porting::path_share + DIR_DELIM + "builtin";
3518 std::string Server::getModStoragePath() const
3520 return m_path_world + DIR_DELIM + "mod_storage";
3523 v3f Server::findSpawnPos()
3525 ServerMap &map = m_env->getServerMap();
3527 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf))
3528 return nodeposf * BS;
3530 bool is_good = false;
3531 // Limit spawn range to mapgen edges (determined by 'mapgen_limit')
3532 s32 range_max = map.getMapgenParams()->getSpawnRangeMax();
3534 // Try to find a good place a few times
3535 for (s32 i = 0; i < 4000 && !is_good; i++) {
3536 s32 range = MYMIN(1 + i, range_max);
3537 // We're going to try to throw the player to this position
3538 v2s16 nodepos2d = v2s16(
3539 -range + (myrand() % (range * 2)),
3540 -range + (myrand() % (range * 2)));
3541 // Get spawn level at point
3542 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3543 // Continue if MAX_MAP_GENERATION_LIMIT was returned by the mapgen to
3544 // signify an unsuitable spawn position, or if outside limits.
3545 if (spawn_level >= MAX_MAP_GENERATION_LIMIT ||
3546 spawn_level <= -MAX_MAP_GENERATION_LIMIT)
3549 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3550 // Consecutive empty nodes
3553 // Search upwards from 'spawn level' for 2 consecutive empty nodes, to
3554 // avoid obstructions in already-generated mapblocks.
3555 // In ungenerated mapblocks consisting of 'ignore' nodes, there will be
3556 // no obstructions, but mapgen decorations are generated after spawn so
3557 // the player may end up inside one.
3558 for (s32 i = 0; i < 8; i++) {
3559 v3s16 blockpos = getNodeBlockPos(nodepos);
3560 map.emergeBlock(blockpos, true);
3561 content_t c = map.getNode(nodepos).getContent();
3563 // In generated mapblocks allow spawn in all 'airlike' drawtype nodes.
3564 // In ungenerated mapblocks allow spawn in 'ignore' nodes.
3565 if (m_nodedef->get(c).drawtype == NDT_AIRLIKE || c == CONTENT_IGNORE) {
3567 if (air_count >= 2) {
3568 // Spawn in lower empty node
3570 nodeposf = intToFloat(nodepos, BS);
3571 // Don't spawn the player outside map boundaries
3572 if (objectpos_over_limit(nodeposf))
3573 // Exit this loop, positions above are probably over limit
3576 // Good position found, cause an exit from main loop
3590 // No suitable spawn point found, return fallback 0,0,0
3591 return v3f(0.0f, 0.0f, 0.0f);
3594 void Server::requestShutdown(const std::string &msg, bool reconnect, float delay)
3596 if (delay == 0.0f) {
3597 // No delay, shutdown immediately
3598 m_shutdown_state.is_requested = true;
3599 // only print to the infostream, a chat message saying
3600 // "Server Shutting Down" is sent when the server destructs.
3601 infostream << "*** Immediate Server shutdown requested." << std::endl;
3602 } else if (delay < 0.0f && m_shutdown_state.isTimerRunning()) {
3603 // Negative delay, cancel shutdown if requested
3604 m_shutdown_state.reset();
3605 std::wstringstream ws;
3607 ws << L"*** Server shutdown canceled.";
3609 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3610 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3611 // m_shutdown_* are already handled, skip.
3613 } else if (delay > 0.0f) {
3614 // Positive delay, tell the clients when the server will shut down
3615 std::wstringstream ws;
3617 ws << L"*** Server shutting down in "
3618 << duration_to_string(myround(delay)).c_str()
3621 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3622 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3625 m_shutdown_state.trigger(delay, msg, reconnect);
3628 PlayerSAO* Server::emergePlayer(const char *name, session_t peer_id, u16 proto_version)
3631 Try to get an existing player
3633 RemotePlayer *player = m_env->getPlayer(name);
3635 // If player is already connected, cancel
3636 if (player && player->getPeerId() != PEER_ID_INEXISTENT) {
3637 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3642 If player with the wanted peer_id already exists, cancel.
3644 if (m_env->getPlayer(peer_id)) {
3645 infostream<<"emergePlayer(): Player with wrong name but same"
3646 " peer_id already exists"<<std::endl;
3651 player = new RemotePlayer(name, idef());
3654 bool newplayer = false;
3657 PlayerSAO *playersao = m_env->loadPlayer(player, &newplayer, peer_id, isSingleplayer());
3659 // Complete init with server parts
3660 playersao->finalize(player, getPlayerEffectivePrivs(player->getName()));
3661 player->protocol_version = proto_version;
3665 m_script->on_newplayer(playersao);
3671 bool Server::registerModStorage(ModMetadata *storage)
3673 if (m_mod_storages.find(storage->getModName()) != m_mod_storages.end()) {
3674 errorstream << "Unable to register same mod storage twice. Storage name: "
3675 << storage->getModName() << std::endl;
3679 m_mod_storages[storage->getModName()] = storage;
3683 void Server::unregisterModStorage(const std::string &name)
3685 std::unordered_map<std::string, ModMetadata *>::const_iterator it = m_mod_storages.find(name);
3686 if (it != m_mod_storages.end()) {
3687 // Save unconditionaly on unregistration
3688 it->second->save(getModStoragePath());
3689 m_mod_storages.erase(name);
3693 void dedicated_server_loop(Server &server, bool &kill)
3695 verbosestream<<"dedicated_server_loop()"<<std::endl;
3697 IntervalLimiter m_profiler_interval;
3699 static thread_local const float steplen =
3700 g_settings->getFloat("dedicated_server_step");
3701 static thread_local const float profiler_print_interval =
3702 g_settings->getFloat("profiler_print_interval");
3705 // This is kind of a hack but can be done like this
3706 // because server.step() is very light
3707 sleep_ms((int)(steplen*1000.0));
3708 server.step(steplen);
3710 if (server.isShutdownRequested() || kill)
3716 if (profiler_print_interval != 0) {
3717 if(m_profiler_interval.step(steplen, profiler_print_interval))
3719 infostream<<"Profiler:"<<std::endl;
3720 g_profiler->print(infostream);
3721 g_profiler->clear();
3726 infostream << "Dedicated server quitting" << std::endl;
3728 if (g_settings->getBool("server_announce"))
3729 ServerList::sendAnnounce(ServerList::AA_DELETE,
3730 server.m_bind_addr.getPort());
3739 bool Server::joinModChannel(const std::string &channel)
3741 return m_modchannel_mgr->joinChannel(channel, PEER_ID_SERVER) &&
3742 m_modchannel_mgr->setChannelState(channel, MODCHANNEL_STATE_READ_WRITE);
3745 bool Server::leaveModChannel(const std::string &channel)
3747 return m_modchannel_mgr->leaveChannel(channel, PEER_ID_SERVER);
3750 bool Server::sendModChannelMessage(const std::string &channel, const std::string &message)
3752 if (!m_modchannel_mgr->canWriteOnChannel(channel))
3755 broadcastModChannelMessage(channel, message, PEER_ID_SERVER);
3759 ModChannel* Server::getModChannel(const std::string &channel)
3761 return m_modchannel_mgr->getModChannel(channel);
3764 void Server::broadcastModChannelMessage(const std::string &channel,
3765 const std::string &message, session_t from_peer)
3767 const std::vector<u16> &peers = m_modchannel_mgr->getChannelPeers(channel);
3771 if (message.size() > STRING_MAX_LEN) {
3772 warningstream << "ModChannel message too long, dropping before sending "
3773 << " (" << message.size() << " > " << STRING_MAX_LEN << ", channel: "
3774 << channel << ")" << std::endl;
3779 if (from_peer != PEER_ID_SERVER) {
3780 sender = getPlayerName(from_peer);
3783 NetworkPacket resp_pkt(TOCLIENT_MODCHANNEL_MSG,
3784 2 + channel.size() + 2 + sender.size() + 2 + message.size());
3785 resp_pkt << channel << sender << message;
3786 for (session_t peer_id : peers) {
3788 if (peer_id == from_peer)
3791 Send(peer_id, &resp_pkt);
3794 if (from_peer != PEER_ID_SERVER) {
3795 m_script->on_modchannel_message(channel, sender, message);