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"
41 #include "scripting_server.h"
46 #include "mapgen/mapgen.h"
47 #include "mapgen/mg_biome.h"
48 #include "content_mapnode.h"
49 #include "content_nodemeta.h"
50 #include "content_sao.h"
51 #include "content/mods.h"
52 #include "modchannels.h"
53 #include "serverlist.h"
54 #include "util/string.h"
56 #include "util/serialize.h"
57 #include "util/thread.h"
58 #include "defaultsettings.h"
59 #include "server/mods.h"
60 #include "util/base64.h"
61 #include "util/sha1.h"
63 #include "database/database.h"
64 #include "chatmessage.h"
65 #include "chat_interface.h"
66 #include "remoteplayer.h"
68 class ClientNotFoundException : public BaseException
71 ClientNotFoundException(const char *s):
76 class ServerThread : public Thread
80 ServerThread(Server *server):
91 void *ServerThread::run()
93 BEGIN_DEBUG_EXCEPTION_HANDLER
96 * The real business of the server happens on the ServerThread.
98 * AsyncRunStep() runs an actual server step as soon as enough time has
99 * passed (dedicated_server_loop keeps track of that).
100 * Receive() blocks at least(!) 30ms waiting for a packet (so this loop
101 * doesn't busy wait) and will process any remaining packets.
104 m_server->AsyncRunStep(true);
106 while (!stopRequested()) {
108 m_server->AsyncRunStep();
112 } catch (con::PeerNotFoundException &e) {
113 infostream<<"Server: PeerNotFoundException"<<std::endl;
114 } catch (ClientNotFoundException &e) {
115 } catch (con::ConnectionBindFailed &e) {
116 m_server->setAsyncFatalError(e.what());
117 } catch (LuaError &e) {
118 m_server->setAsyncFatalError(
119 "ServerThread::run Lua: " + std::string(e.what()));
123 END_DEBUG_EXCEPTION_HANDLER
128 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
130 if(pos_exists) *pos_exists = false;
135 if(pos_exists) *pos_exists = true;
140 ServerActiveObject *sao = env->getActiveObject(object);
143 if(pos_exists) *pos_exists = true;
144 return sao->getBasePosition(); }
149 void Server::ShutdownState::reset()
153 should_reconnect = false;
154 is_requested = false;
157 void Server::ShutdownState::trigger(float delay, const std::string &msg, bool reconnect)
161 should_reconnect = reconnect;
164 void Server::ShutdownState::tick(float dtime, Server *server)
170 static const float shutdown_msg_times[] =
172 1, 2, 3, 4, 5, 10, 20, 40, 60, 120, 180, 300, 600, 1200, 1800, 3600
175 // Automated messages
176 if (m_timer < shutdown_msg_times[ARRLEN(shutdown_msg_times) - 1]) {
177 for (float t : shutdown_msg_times) {
178 // If shutdown timer matches an automessage, shot it
179 if (m_timer > t && m_timer - dtime < t) {
180 std::wstring periodicMsg = getShutdownTimerMessage();
182 infostream << wide_to_utf8(periodicMsg).c_str() << std::endl;
183 server->SendChatMessage(PEER_ID_INEXISTENT, periodicMsg);
190 if (m_timer < 0.0f) {
196 std::wstring Server::ShutdownState::getShutdownTimerMessage() const
198 std::wstringstream ws;
199 ws << L"*** Server shutting down in "
200 << duration_to_string(myround(m_timer)).c_str() << ".";
209 const std::string &path_world,
210 const SubgameSpec &gamespec,
211 bool simple_singleplayer_mode,
216 m_bind_addr(bind_addr),
217 m_path_world(path_world),
218 m_gamespec(gamespec),
219 m_simple_singleplayer_mode(simple_singleplayer_mode),
220 m_dedicated(dedicated),
221 m_async_fatal_error(""),
222 m_con(std::make_shared<con::Connection>(PROTOCOL_ID,
225 m_bind_addr.isIPv6(),
227 m_itemdef(createItemDefManager()),
228 m_nodedef(createNodeDefManager()),
229 m_craftdef(createCraftDefManager()),
230 m_thread(new ServerThread(this)),
234 m_modchannel_mgr(new ModChannelMgr())
236 m_lag = g_settings->getFloat("dedicated_server_step");
238 if (m_path_world.empty())
239 throw ServerError("Supplied empty world path");
241 if (!gamespec.isValid())
242 throw ServerError("Supplied invalid gamespec");
248 // Send shutdown message
249 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE,
250 L"*** Server shutting down"));
253 MutexAutoLock envlock(m_env_mutex);
255 infostream << "Server: Saving players" << std::endl;
256 m_env->saveLoadedPlayers();
258 infostream << "Server: Kicking players" << std::endl;
259 std::string kick_msg;
260 bool reconnect = false;
261 if (isShutdownRequested()) {
262 reconnect = m_shutdown_state.should_reconnect;
263 kick_msg = m_shutdown_state.message;
265 if (kick_msg.empty()) {
266 kick_msg = g_settings->get("kick_msg_shutdown");
268 m_env->saveLoadedPlayers(true);
269 m_env->kickAllPlayers(SERVER_ACCESSDENIED_SHUTDOWN,
270 kick_msg, reconnect);
273 actionstream << "Server: Shutting down" << std::endl;
275 // Do this before stopping the server in case mapgen callbacks need to access
276 // server-controlled resources (like ModStorages). Also do them before
277 // shutdown callbacks since they may modify state that is finalized in a
280 m_emerge->stopThreads();
283 MutexAutoLock envlock(m_env_mutex);
285 // Execute script shutdown hooks
286 infostream << "Executing shutdown hooks" << std::endl;
287 m_script->on_shutdown();
289 infostream << "Server: Saving environment metadata" << std::endl;
299 // Delete things in the reverse order of creation
308 // Deinitialize scripting
309 infostream << "Server: Deinitializing scripting" << std::endl;
312 // Delete detached inventories
313 for (auto &detached_inventory : m_detached_inventories) {
314 delete detached_inventory.second;
317 while (!m_unsent_map_edit_queue.empty()) {
318 delete m_unsent_map_edit_queue.front();
319 m_unsent_map_edit_queue.pop();
325 infostream << "Server created for gameid \"" << m_gamespec.id << "\"";
326 if (m_simple_singleplayer_mode)
327 infostream << " in simple singleplayer mode" << std::endl;
329 infostream << std::endl;
330 infostream << "- world: " << m_path_world << std::endl;
331 infostream << "- game: " << m_gamespec.path << std::endl;
333 // Create world if it doesn't exist
334 if (!loadGameConfAndInitWorld(m_path_world, m_gamespec))
335 throw ServerError("Failed to initialize world");
337 // Create emerge manager
338 m_emerge = new EmergeManager(this);
340 // Create ban manager
341 std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
342 m_banmanager = new BanManager(ban_path);
344 m_modmgr = std::unique_ptr<ServerModManager>(new ServerModManager(m_path_world));
345 std::vector<ModSpec> unsatisfied_mods = m_modmgr->getUnsatisfiedMods();
346 // complain about mods with unsatisfied dependencies
347 if (!m_modmgr->isConsistent()) {
348 m_modmgr->printUnsatisfiedModsError();
352 MutexAutoLock envlock(m_env_mutex);
354 // Create the Map (loads map_meta.txt, overriding configured mapgen params)
355 ServerMap *servermap = new ServerMap(m_path_world, this, m_emerge);
357 // Initialize scripting
358 infostream << "Server: Initializing Lua" << std::endl;
360 m_script = new ServerScripting(this);
362 m_script->loadMod(getBuiltinLuaPath() + DIR_DELIM "init.lua", BUILTIN_MOD_NAME);
364 m_modmgr->loadMods(m_script);
366 // Read Textures and calculate sha1 sums
369 // Apply item aliases in the node definition manager
370 m_nodedef->updateAliases(m_itemdef);
372 // Apply texture overrides from texturepack/override.txt
373 std::vector<std::string> paths;
374 fs::GetRecursiveDirs(paths, g_settings->get("texture_path"));
375 fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures");
376 for (const std::string &path : paths)
377 m_nodedef->applyTextureOverrides(path + DIR_DELIM + "override.txt");
379 m_nodedef->setNodeRegistrationStatus(true);
381 // Perform pending node name resolutions
382 m_nodedef->runNodeResolveCallbacks();
384 // unmap node names for connected nodeboxes
385 m_nodedef->mapNodeboxConnections();
387 // init the recipe hashes to speed up crafting
388 m_craftdef->initHashes(this);
390 // Initialize Environment
391 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
393 m_clients.setEnv(m_env);
395 if (!servermap->settings_mgr.makeMapgenParams())
396 FATAL_ERROR("Couldn't create any mapgen type");
398 // Initialize mapgens
399 m_emerge->initMapgens(servermap->getMapgenParams());
401 if (g_settings->getBool("enable_rollback_recording")) {
402 // Create rollback manager
403 m_rollback = new RollbackManager(m_path_world, this);
406 // Give environment reference to scripting api
407 m_script->initializeEnvironment(m_env);
409 // Register us to receive map edit events
410 servermap->addEventReceiver(this);
414 m_liquid_transform_every = g_settings->getFloat("liquid_update");
415 m_max_chatmessage_length = g_settings->getU16("chat_message_max_size");
416 m_csm_restriction_flags = g_settings->getU64("csm_restriction_flags");
417 m_csm_restriction_noderange = g_settings->getU32("csm_restriction_noderange");
422 infostream << "Starting server on " << m_bind_addr.serializeString()
423 << "..." << std::endl;
425 // Stop thread if already running
428 // Initialize connection
429 m_con->SetTimeoutMs(30);
430 m_con->Serve(m_bind_addr);
435 // ASCII art for the win!
437 << " .__ __ __ " << std::endl
438 << " _____ |__| ____ _____/ |_ ____ _______/ |_ " << std::endl
439 << " / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\" << std::endl
440 << "| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | " << std::endl
441 << "|__|_| /__|___| /\\___ >__| \\___ >____ > |__| " << std::endl
442 << " \\/ \\/ \\/ \\/ \\/ " << std::endl;
443 actionstream << "World at [" << m_path_world << "]" << std::endl;
444 actionstream << "Server for gameid=\"" << m_gamespec.id
445 << "\" listening on " << m_bind_addr.serializeString() << ":"
446 << m_bind_addr.getPort() << "." << std::endl;
451 infostream<<"Server: Stopping and waiting threads"<<std::endl;
453 // Stop threads (set run=false first so both start stopping)
455 //m_emergethread.setRun(false);
457 //m_emergethread.stop();
459 infostream<<"Server: Threads stopped"<<std::endl;
462 void Server::step(float dtime)
468 MutexAutoLock lock(m_step_dtime_mutex);
469 m_step_dtime += dtime;
471 // Throw if fatal error occurred in thread
472 std::string async_err = m_async_fatal_error.get();
473 if (!async_err.empty()) {
474 if (!m_simple_singleplayer_mode) {
475 m_env->kickAllPlayers(SERVER_ACCESSDENIED_CRASH,
476 g_settings->get("kick_msg_crash"),
477 g_settings->getBool("ask_reconnect_on_crash"));
479 throw ServerError("AsyncErr: " + async_err);
483 void Server::AsyncRunStep(bool initial_step)
488 MutexAutoLock lock1(m_step_dtime_mutex);
489 dtime = m_step_dtime;
493 // Send blocks to clients
497 if((dtime < 0.001) && !initial_step)
500 ScopeProfiler sp(g_profiler, "Server::AsyncRunStep()", SPT_AVG);
503 MutexAutoLock lock1(m_step_dtime_mutex);
504 m_step_dtime -= dtime;
511 m_uptime.set(m_uptime.get() + dtime);
517 Update time of day and overall game time
519 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
522 Send to clients at constant intervals
525 m_time_of_day_send_timer -= dtime;
526 if(m_time_of_day_send_timer < 0.0) {
527 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
528 u16 time = m_env->getTimeOfDay();
529 float time_speed = g_settings->getFloat("time_speed");
530 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
534 MutexAutoLock lock(m_env_mutex);
535 // Figure out and report maximum lag to environment
536 float max_lag = m_env->getMaxLagEstimate();
537 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
539 if(dtime > 0.1 && dtime > max_lag * 2.0)
540 infostream<<"Server: Maximum lag peaked to "<<dtime
544 m_env->reportMaxLagEstimate(max_lag);
549 static const float map_timer_and_unload_dtime = 2.92;
550 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
552 MutexAutoLock lock(m_env_mutex);
553 // Run Map's timers and unload unused data
554 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
555 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
556 g_settings->getFloat("server_unload_unused_data_timeout"),
561 Listen to the admin chat, if available
564 if (!m_admin_chat->command_queue.empty()) {
565 MutexAutoLock lock(m_env_mutex);
566 while (!m_admin_chat->command_queue.empty()) {
567 ChatEvent *evt = m_admin_chat->command_queue.pop_frontNoEx();
568 handleChatInterfaceEvent(evt);
572 m_admin_chat->outgoing_queue.push_back(
573 new ChatEventTimeInfo(m_env->getGameTime(), m_env->getTimeOfDay()));
580 /* Transform liquids */
581 m_liquid_transform_timer += dtime;
582 if(m_liquid_transform_timer >= m_liquid_transform_every)
584 m_liquid_transform_timer -= m_liquid_transform_every;
586 MutexAutoLock lock(m_env_mutex);
588 ScopeProfiler sp(g_profiler, "Server: liquid transform");
590 std::map<v3s16, MapBlock*> modified_blocks;
591 m_env->getMap().transformLiquids(modified_blocks, m_env);
594 Set the modified blocks unsent for all the clients
596 if (!modified_blocks.empty()) {
597 SetBlocksNotSent(modified_blocks);
600 m_clients.step(dtime);
602 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
604 // send masterserver announce
606 float &counter = m_masterserver_timer;
607 if (!isSingleplayer() && (!counter || counter >= 300.0) &&
608 g_settings->getBool("server_announce")) {
609 ServerList::sendAnnounce(counter ? ServerList::AA_UPDATE :
610 ServerList::AA_START,
611 m_bind_addr.getPort(),
612 m_clients.getPlayerNames(),
614 m_env->getGameTime(),
617 Mapgen::getMapgenName(m_emerge->mgparams->mgtype),
627 Check added and deleted active objects
630 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
631 MutexAutoLock envlock(m_env_mutex);
634 const RemoteClientMap &clients = m_clients.getClientList();
635 ScopeProfiler sp(g_profiler, "Server: update objects within range");
637 for (const auto &client_it : clients) {
638 RemoteClient *client = client_it.second;
640 if (client->getState() < CS_DefinitionsSent)
643 // This can happen if the client times out somehow
644 if (!m_env->getPlayer(client->peer_id))
647 PlayerSAO *playersao = getPlayerSAO(client->peer_id);
651 SendActiveObjectRemoveAdd(client, playersao);
655 // Save mod storages if modified
656 m_mod_storage_save_timer -= dtime;
657 if (m_mod_storage_save_timer <= 0.0f) {
658 m_mod_storage_save_timer = g_settings->getFloat("server_map_save_interval");
660 for (std::unordered_map<std::string, ModMetadata *>::const_iterator
661 it = m_mod_storages.begin(); it != m_mod_storages.end(); ++it) {
662 if (it->second->isModified()) {
663 it->second->save(getModStoragePath());
668 infostream << "Saved " << n << " modified mod storages." << std::endl;
676 MutexAutoLock envlock(m_env_mutex);
677 ScopeProfiler sp(g_profiler, "Server: send SAO messages");
680 // Value = data sent by object
681 std::unordered_map<u16, std::vector<ActiveObjectMessage>*> buffered_messages;
683 // Get active object messages from environment
685 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
689 std::vector<ActiveObjectMessage>* message_list = nullptr;
690 std::unordered_map<u16, std::vector<ActiveObjectMessage>* >::iterator n;
691 n = buffered_messages.find(aom.id);
692 if (n == buffered_messages.end()) {
693 message_list = new std::vector<ActiveObjectMessage>;
694 buffered_messages[aom.id] = message_list;
697 message_list = n->second;
699 message_list->push_back(aom);
703 const RemoteClientMap &clients = m_clients.getClientList();
704 // Route data to every client
705 for (const auto &client_it : clients) {
706 RemoteClient *client = client_it.second;
707 PlayerSAO *player = getPlayerSAO(client->peer_id);
708 std::string reliable_data;
709 std::string unreliable_data;
710 // Go through all objects in message buffer
711 for (const auto &buffered_message : buffered_messages) {
712 // If object does not exist or is not known by client, skip it
713 u16 id = buffered_message.first;
714 ServerActiveObject *sao = m_env->getActiveObject(id);
715 if (!sao || client->m_known_objects.find(id) == client->m_known_objects.end())
718 // Get message list of object
719 std::vector<ActiveObjectMessage>* list = buffered_message.second;
720 // Go through every message
721 for (const ActiveObjectMessage &aom : *list) {
722 // Send position updates to players who do not see the attachment
723 if (aom.datastring[0] == AO_CMD_UPDATE_POSITION) {
724 if (sao->getId() == player->getId())
727 // Do not send position updates for attached players
728 // as long the parent is known to the client
729 ServerActiveObject *parent = sao->getParent();
730 if (parent && client->m_known_objects.find(parent->getId()) !=
731 client->m_known_objects.end())
734 // Compose the full new data with header
735 std::string new_data;
738 writeU16((u8*)&buf[0], aom.id);
739 new_data.append(buf, 2);
741 new_data += serializeString(aom.datastring);
742 // Add data to buffer
744 reliable_data += new_data;
746 unreliable_data += new_data;
750 reliable_data and unreliable_data are now ready.
753 if (!reliable_data.empty()) {
754 SendActiveObjectMessages(client->peer_id, reliable_data);
757 if (!unreliable_data.empty()) {
758 SendActiveObjectMessages(client->peer_id, unreliable_data, false);
763 // Clear buffered_messages
764 for (auto &buffered_message : buffered_messages) {
765 delete buffered_message.second;
770 Send queued-for-sending map edit events.
773 // We will be accessing the environment
774 MutexAutoLock lock(m_env_mutex);
776 // Don't send too many at a time
779 // Single change sending is disabled if queue size is not small
780 bool disable_single_change_sending = false;
781 if(m_unsent_map_edit_queue.size() >= 4)
782 disable_single_change_sending = true;
784 int event_count = m_unsent_map_edit_queue.size();
786 // We'll log the amount of each
789 std::list<v3s16> node_meta_updates;
791 while (!m_unsent_map_edit_queue.empty()) {
792 MapEditEvent* event = m_unsent_map_edit_queue.front();
793 m_unsent_map_edit_queue.pop();
795 // Players far away from the change are stored here.
796 // Instead of sending the changes, MapBlocks are set not sent
798 std::unordered_set<u16> far_players;
800 switch (event->type) {
803 prof.add("MEET_ADDNODE", 1);
804 sendAddNode(event->p, event->n, &far_players,
805 disable_single_change_sending ? 5 : 30,
806 event->type == MEET_ADDNODE);
808 case MEET_REMOVENODE:
809 prof.add("MEET_REMOVENODE", 1);
810 sendRemoveNode(event->p, &far_players,
811 disable_single_change_sending ? 5 : 30);
813 case MEET_BLOCK_NODE_METADATA_CHANGED: {
814 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
815 if (!event->is_private_change) {
816 // Don't send the change yet. Collect them to eliminate dupes.
817 node_meta_updates.remove(event->p);
818 node_meta_updates.push_back(event->p);
821 if (MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(
822 getNodeBlockPos(event->p))) {
823 block->raiseModified(MOD_STATE_WRITE_NEEDED,
824 MOD_REASON_REPORT_META_CHANGE);
829 prof.add("MEET_OTHER", 1);
830 for (const v3s16 &modified_block : event->modified_blocks) {
831 m_clients.markBlockposAsNotSent(modified_block);
835 prof.add("unknown", 1);
836 warningstream << "Server: Unknown MapEditEvent "
837 << ((u32)event->type) << std::endl;
842 Set blocks not sent to far players
844 if (!far_players.empty()) {
845 // Convert list format to that wanted by SetBlocksNotSent
846 std::map<v3s16, MapBlock*> modified_blocks2;
847 for (const v3s16 &modified_block : event->modified_blocks) {
848 modified_blocks2[modified_block] =
849 m_env->getMap().getBlockNoCreateNoEx(modified_block);
852 // Set blocks not sent
853 for (const u16 far_player : far_players) {
854 if (RemoteClient *client = getClient(far_player))
855 client->SetBlocksNotSent(modified_blocks2);
862 if (event_count >= 5) {
863 infostream << "Server: MapEditEvents:" << std::endl;
864 prof.print(infostream);
865 } else if (event_count != 0) {
866 verbosestream << "Server: MapEditEvents:" << std::endl;
867 prof.print(verbosestream);
870 // Send all metadata updates
871 if (node_meta_updates.size())
872 sendMetadataChanged(node_meta_updates);
876 Trigger emergethread (it somehow gets to a non-triggered but
877 bysy state sometimes)
880 float &counter = m_emergethread_trigger_timer;
882 if (counter >= 2.0) {
885 m_emerge->startThreads();
889 // Save map, players and auth stuff
891 float &counter = m_savemap_timer;
893 static thread_local const float save_interval =
894 g_settings->getFloat("server_map_save_interval");
895 if (counter >= save_interval) {
897 MutexAutoLock lock(m_env_mutex);
899 ScopeProfiler sp(g_profiler, "Server: map saving (sum)");
902 if (m_banmanager->isModified()) {
903 m_banmanager->save();
906 // Save changed parts of map
907 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
910 m_env->saveLoadedPlayers();
912 // Save environment metadata
917 m_shutdown_state.tick(dtime, this);
920 void Server::Receive()
930 In the first iteration *wait* for a packet, afterwards process
931 all packets that are immediately available (no waiting).
934 m_con->Receive(&pkt);
937 if (!m_con->TryReceive(&pkt))
941 peer_id = pkt.getPeerId();
943 } catch (const con::InvalidIncomingDataException &e) {
944 infostream << "Server::Receive(): InvalidIncomingDataException: what()="
945 << e.what() << std::endl;
946 } catch (const SerializationError &e) {
947 infostream << "Server::Receive(): SerializationError: what()="
948 << e.what() << std::endl;
949 } catch (const ClientStateError &e) {
950 errorstream << "ProcessData: peer=" << peer_id << " what()="
951 << e.what() << std::endl;
952 DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
953 L"Try reconnecting or updating your client");
954 } catch (const con::PeerNotFoundException &e) {
956 } catch (const con::NoIncomingDataException &e) {
962 PlayerSAO* Server::StageTwoClientInit(session_t peer_id)
964 std::string playername;
965 PlayerSAO *playersao = NULL;
968 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
970 playername = client->getName();
971 playersao = emergePlayer(playername.c_str(), peer_id, client->net_proto_version);
973 } catch (std::exception &e) {
979 RemotePlayer *player = m_env->getPlayer(playername.c_str());
982 if (!playersao || !player) {
983 if (player && player->getPeerId() != PEER_ID_INEXISTENT) {
984 actionstream << "Server: Failed to emerge player \"" << playername
985 << "\" (player allocated to an another client)" << std::endl;
986 DenyAccess_Legacy(peer_id, L"Another client is connected with this "
987 L"name. If your client closed unexpectedly, try again in "
990 errorstream << "Server: " << playername << ": Failed to emerge player"
992 DenyAccess_Legacy(peer_id, L"Could not allocate player.");
998 Send complete position information
1000 SendMovePlayer(peer_id);
1003 SendPlayerPrivileges(peer_id);
1005 // Send inventory formspec
1006 SendPlayerInventoryFormspec(peer_id);
1009 SendInventory(playersao, false);
1011 // Send HP or death screen
1012 if (playersao->isDead())
1013 SendDeathscreen(peer_id, false, v3f(0,0,0));
1015 SendPlayerHPOrDie(playersao,
1016 PlayerHPChangeReason(PlayerHPChangeReason::SET_HP));
1019 SendPlayerBreath(playersao);
1025 Address addr = getPeerAddress(player->getPeerId());
1026 std::string ip_str = addr.serializeString();
1027 const std::vector<std::string> &names = m_clients.getPlayerNames();
1029 actionstream << player->getName() << " [" << ip_str << "] joins game. List of players: ";
1031 for (const std::string &name : names) {
1032 actionstream << name << " ";
1035 actionstream << player->getName() <<std::endl;
1040 inline void Server::handleCommand(NetworkPacket *pkt)
1042 const ToServerCommandHandler &opHandle = toServerCommandTable[pkt->getCommand()];
1043 (this->*opHandle.handler)(pkt);
1046 void Server::ProcessData(NetworkPacket *pkt)
1048 // Environment is locked first.
1049 MutexAutoLock envlock(m_env_mutex);
1051 ScopeProfiler sp(g_profiler, "Server: Process network packet (sum)");
1052 u32 peer_id = pkt->getPeerId();
1055 Address address = getPeerAddress(peer_id);
1056 std::string addr_s = address.serializeString();
1058 if(m_banmanager->isIpBanned(addr_s)) {
1059 std::string ban_name = m_banmanager->getBanName(addr_s);
1060 infostream << "Server: A banned client tried to connect from "
1061 << addr_s << "; banned name was "
1062 << ban_name << std::endl;
1063 // This actually doesn't seem to transfer to the client
1064 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1065 + utf8_to_wide(ban_name));
1069 catch(con::PeerNotFoundException &e) {
1071 * no peer for this packet found
1072 * most common reason is peer timeout, e.g. peer didn't
1073 * respond for some time, your server was overloaded or
1076 infostream << "Server::ProcessData(): Canceling: peer "
1077 << peer_id << " not found" << std::endl;
1082 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1084 // Command must be handled into ToServerCommandHandler
1085 if (command >= TOSERVER_NUM_MSG_TYPES) {
1086 infostream << "Server: Ignoring unknown command "
1087 << command << std::endl;
1091 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1096 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1098 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1099 errorstream << "Server::ProcessData(): Cancelling: Peer"
1100 " serialization format invalid or not initialized."
1101 " Skipping incoming command=" << command << std::endl;
1105 /* Handle commands related to client startup */
1106 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1111 if (m_clients.getClientState(peer_id) < CS_Active) {
1112 if (command == TOSERVER_PLAYERPOS) return;
1114 errorstream << "Got packet command: " << command << " for peer id "
1115 << peer_id << " but client isn't active yet. Dropping packet "
1121 } catch (SendFailedException &e) {
1122 errorstream << "Server::ProcessData(): SendFailedException: "
1123 << "what=" << e.what()
1125 } catch (PacketError &e) {
1126 actionstream << "Server::ProcessData(): PacketError: "
1127 << "what=" << e.what()
1132 void Server::setTimeOfDay(u32 time)
1134 m_env->setTimeOfDay(time);
1135 m_time_of_day_send_timer = 0;
1138 void Server::onMapEditEvent(const MapEditEvent &event)
1140 if (m_ignore_map_edit_events_area.contains(event.getArea()))
1143 m_unsent_map_edit_queue.push(new MapEditEvent(event));
1146 Inventory* Server::getInventory(const InventoryLocation &loc)
1149 case InventoryLocation::UNDEFINED:
1150 case InventoryLocation::CURRENT_PLAYER:
1152 case InventoryLocation::PLAYER:
1154 RemotePlayer *player = m_env->getPlayer(loc.name.c_str());
1157 PlayerSAO *playersao = player->getPlayerSAO();
1160 return playersao->getInventory();
1163 case InventoryLocation::NODEMETA:
1165 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1168 return meta->getInventory();
1171 case InventoryLocation::DETACHED:
1173 if(m_detached_inventories.count(loc.name) == 0)
1175 return m_detached_inventories[loc.name];
1179 sanity_check(false); // abort
1185 void Server::setInventoryModified(const InventoryLocation &loc)
1188 case InventoryLocation::UNDEFINED:
1190 case InventoryLocation::PLAYER:
1193 RemotePlayer *player = m_env->getPlayer(loc.name.c_str());
1198 player->setModified(true);
1199 player->inventory.setModified(true);
1200 // Updates are sent in ServerEnvironment::step()
1203 case InventoryLocation::NODEMETA:
1206 event.type = MEET_BLOCK_NODE_METADATA_CHANGED;
1208 m_env->getMap().dispatchEvent(event);
1211 case InventoryLocation::DETACHED:
1213 // Updates are sent in ServerEnvironment::step()
1217 sanity_check(false); // abort
1222 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1224 std::vector<session_t> clients = m_clients.getClientIDs();
1226 // Set the modified blocks unsent for all the clients
1227 for (const session_t client_id : clients) {
1228 if (RemoteClient *client = m_clients.lockedGetClientNoEx(client_id))
1229 client->SetBlocksNotSent(block);
1234 void Server::peerAdded(con::Peer *peer)
1236 verbosestream<<"Server::peerAdded(): peer->id="
1237 <<peer->id<<std::endl;
1239 m_peer_change_queue.push(con::PeerChange(con::PEER_ADDED, peer->id, false));
1242 void Server::deletingPeer(con::Peer *peer, bool timeout)
1244 verbosestream<<"Server::deletingPeer(): peer->id="
1245 <<peer->id<<", timeout="<<timeout<<std::endl;
1247 m_clients.event(peer->id, CSE_Disconnect);
1248 m_peer_change_queue.push(con::PeerChange(con::PEER_REMOVED, peer->id, timeout));
1251 bool Server::getClientConInfo(session_t peer_id, con::rtt_stat_type type, float* retval)
1253 *retval = m_con->getPeerStat(peer_id,type);
1254 return *retval != -1;
1257 bool Server::getClientInfo(
1266 std::string* vers_string
1269 *state = m_clients.getClientState(peer_id);
1271 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1278 *uptime = client->uptime();
1279 *ser_vers = client->serialization_version;
1280 *prot_vers = client->net_proto_version;
1282 *major = client->getMajor();
1283 *minor = client->getMinor();
1284 *patch = client->getPatch();
1285 *vers_string = client->getFull();
1292 void Server::handlePeerChanges()
1294 while(!m_peer_change_queue.empty())
1296 con::PeerChange c = m_peer_change_queue.front();
1297 m_peer_change_queue.pop();
1299 verbosestream<<"Server: Handling peer change: "
1300 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1305 case con::PEER_ADDED:
1306 m_clients.CreateClient(c.peer_id);
1309 case con::PEER_REMOVED:
1310 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1314 FATAL_ERROR("Invalid peer change event received!");
1320 void Server::printToConsoleOnly(const std::string &text)
1323 m_admin_chat->outgoing_queue.push_back(
1324 new ChatEventChat("", utf8_to_wide(text)));
1326 std::cout << text << std::endl;
1330 void Server::Send(NetworkPacket *pkt)
1332 Send(pkt->getPeerId(), pkt);
1335 void Server::Send(session_t peer_id, NetworkPacket *pkt)
1337 m_clients.send(peer_id,
1338 clientCommandFactoryTable[pkt->getCommand()].channel,
1340 clientCommandFactoryTable[pkt->getCommand()].reliable);
1343 void Server::SendMovement(session_t peer_id)
1345 std::ostringstream os(std::ios_base::binary);
1347 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1349 pkt << g_settings->getFloat("movement_acceleration_default");
1350 pkt << g_settings->getFloat("movement_acceleration_air");
1351 pkt << g_settings->getFloat("movement_acceleration_fast");
1352 pkt << g_settings->getFloat("movement_speed_walk");
1353 pkt << g_settings->getFloat("movement_speed_crouch");
1354 pkt << g_settings->getFloat("movement_speed_fast");
1355 pkt << g_settings->getFloat("movement_speed_climb");
1356 pkt << g_settings->getFloat("movement_speed_jump");
1357 pkt << g_settings->getFloat("movement_liquid_fluidity");
1358 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1359 pkt << g_settings->getFloat("movement_liquid_sink");
1360 pkt << g_settings->getFloat("movement_gravity");
1365 void Server::SendPlayerHPOrDie(PlayerSAO *playersao, const PlayerHPChangeReason &reason)
1367 if (playersao->isImmortal())
1370 session_t peer_id = playersao->getPeerID();
1371 bool is_alive = playersao->getHP() > 0;
1374 SendPlayerHP(peer_id);
1376 DiePlayer(peer_id, reason);
1379 void Server::SendHP(session_t peer_id, u16 hp)
1381 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1386 void Server::SendBreath(session_t peer_id, u16 breath)
1388 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1389 pkt << (u16) breath;
1393 void Server::SendAccessDenied(session_t peer_id, AccessDeniedCode reason,
1394 const std::string &custom_reason, bool reconnect)
1396 assert(reason < SERVER_ACCESSDENIED_MAX);
1398 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1400 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
1401 pkt << custom_reason;
1402 else if (reason == SERVER_ACCESSDENIED_SHUTDOWN ||
1403 reason == SERVER_ACCESSDENIED_CRASH)
1404 pkt << custom_reason << (u8)reconnect;
1408 void Server::SendAccessDenied_Legacy(session_t peer_id,const std::wstring &reason)
1410 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1415 void Server::SendDeathscreen(session_t peer_id, bool set_camera_point_target,
1416 v3f camera_point_target)
1418 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1419 pkt << set_camera_point_target << camera_point_target;
1423 void Server::SendItemDef(session_t peer_id,
1424 IItemDefManager *itemdef, u16 protocol_version)
1426 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1430 u32 length of the next item
1431 zlib-compressed serialized ItemDefManager
1433 std::ostringstream tmp_os(std::ios::binary);
1434 itemdef->serialize(tmp_os, protocol_version);
1435 std::ostringstream tmp_os2(std::ios::binary);
1436 compressZlib(tmp_os.str(), tmp_os2);
1437 pkt.putLongString(tmp_os2.str());
1440 verbosestream << "Server: Sending item definitions to id(" << peer_id
1441 << "): size=" << pkt.getSize() << std::endl;
1446 void Server::SendNodeDef(session_t peer_id,
1447 const NodeDefManager *nodedef, u16 protocol_version)
1449 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1453 u32 length of the next item
1454 zlib-compressed serialized NodeDefManager
1456 std::ostringstream tmp_os(std::ios::binary);
1457 nodedef->serialize(tmp_os, protocol_version);
1458 std::ostringstream tmp_os2(std::ios::binary);
1459 compressZlib(tmp_os.str(), tmp_os2);
1461 pkt.putLongString(tmp_os2.str());
1464 verbosestream << "Server: Sending node definitions to id(" << peer_id
1465 << "): size=" << pkt.getSize() << std::endl;
1471 Non-static send methods
1474 void Server::SendInventory(PlayerSAO *sao, bool incremental)
1476 RemotePlayer *player = sao->getPlayer();
1478 // Do not send new format to old clients
1479 incremental &= player->protocol_version >= 38;
1481 UpdateCrafting(player);
1487 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, sao->getPeerID());
1489 std::ostringstream os(std::ios::binary);
1490 sao->getInventory()->serialize(os, incremental);
1491 sao->getInventory()->setModified(false);
1492 player->setModified(true);
1494 const std::string &s = os.str();
1495 pkt.putRawString(s.c_str(), s.size());
1499 void Server::SendChatMessage(session_t peer_id, const ChatMessage &message)
1501 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1503 u8 type = message.type;
1504 pkt << version << type << std::wstring(L"") << message.message << (u64)message.timestamp;
1506 if (peer_id != PEER_ID_INEXISTENT) {
1507 RemotePlayer *player = m_env->getPlayer(peer_id);
1513 m_clients.sendToAll(&pkt);
1517 void Server::SendShowFormspecMessage(session_t peer_id, const std::string &formspec,
1518 const std::string &formname)
1520 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0, peer_id);
1521 if (formspec.empty()){
1522 //the client should close the formspec
1523 //but make sure there wasn't another one open in meantime
1524 const auto it = m_formspec_state_data.find(peer_id);
1525 if (it != m_formspec_state_data.end() && it->second == formname) {
1526 m_formspec_state_data.erase(peer_id);
1528 pkt.putLongString("");
1530 m_formspec_state_data[peer_id] = formname;
1531 pkt.putLongString(formspec);
1538 // Spawns a particle on peer with peer_id
1539 void Server::SendSpawnParticle(session_t peer_id, u16 protocol_version,
1540 v3f pos, v3f velocity, v3f acceleration,
1541 float expirationtime, float size, bool collisiondetection,
1542 bool collision_removal, bool object_collision,
1543 bool vertical, const std::string &texture,
1544 const struct TileAnimationParams &animation, u8 glow)
1546 static thread_local const float radius =
1547 g_settings->getS16("max_block_send_distance") * MAP_BLOCKSIZE * BS;
1549 if (peer_id == PEER_ID_INEXISTENT) {
1550 std::vector<session_t> clients = m_clients.getClientIDs();
1552 for (const session_t client_id : clients) {
1553 RemotePlayer *player = m_env->getPlayer(client_id);
1557 PlayerSAO *sao = player->getPlayerSAO();
1561 // Do not send to distant clients
1562 if (sao->getBasePosition().getDistanceFrom(pos * BS) > radius)
1565 SendSpawnParticle(client_id, player->protocol_version,
1566 pos, velocity, acceleration,
1567 expirationtime, size, collisiondetection, collision_removal,
1568 object_collision, vertical, texture, animation, glow);
1573 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1575 pkt << pos << velocity << acceleration << expirationtime
1576 << size << collisiondetection;
1577 pkt.putLongString(texture);
1579 pkt << collision_removal;
1580 // This is horrible but required (why are there two ways to serialize pkts?)
1581 std::ostringstream os(std::ios_base::binary);
1582 animation.serialize(os, protocol_version);
1583 pkt.putRawString(os.str());
1585 pkt << object_collision;
1590 // Adds a ParticleSpawner on peer with peer_id
1591 void Server::SendAddParticleSpawner(session_t peer_id, u16 protocol_version,
1592 u16 amount, float spawntime, v3f minpos, v3f maxpos,
1593 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1594 float minsize, float maxsize, bool collisiondetection, bool collision_removal,
1595 bool object_collision, u16 attached_id, bool vertical, const std::string &texture, u32 id,
1596 const struct TileAnimationParams &animation, u8 glow)
1598 if (peer_id == PEER_ID_INEXISTENT) {
1599 // This sucks and should be replaced:
1600 std::vector<session_t> clients = m_clients.getClientIDs();
1601 for (const session_t client_id : clients) {
1602 RemotePlayer *player = m_env->getPlayer(client_id);
1605 SendAddParticleSpawner(client_id, player->protocol_version,
1606 amount, spawntime, minpos, maxpos,
1607 minvel, maxvel, minacc, maxacc, minexptime, maxexptime,
1608 minsize, maxsize, collisiondetection, collision_removal,
1609 object_collision, attached_id, vertical, texture, id,
1615 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1617 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1618 << minacc << maxacc << minexptime << maxexptime << minsize
1619 << maxsize << collisiondetection;
1621 pkt.putLongString(texture);
1623 pkt << id << vertical;
1624 pkt << collision_removal;
1626 // This is horrible but required
1627 std::ostringstream os(std::ios_base::binary);
1628 animation.serialize(os, protocol_version);
1629 pkt.putRawString(os.str());
1631 pkt << object_collision;
1636 void Server::SendDeleteParticleSpawner(session_t peer_id, u32 id)
1638 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER, 4, peer_id);
1640 // Ugly error in this packet
1643 if (peer_id != PEER_ID_INEXISTENT)
1646 m_clients.sendToAll(&pkt);
1650 void Server::SendHUDAdd(session_t peer_id, u32 id, HudElement *form)
1652 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1654 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1655 << form->text << form->number << form->item << form->dir
1656 << form->align << form->offset << form->world_pos << form->size
1662 void Server::SendHUDRemove(session_t peer_id, u32 id)
1664 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1669 void Server::SendHUDChange(session_t peer_id, u32 id, HudElementStat stat, void *value)
1671 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1672 pkt << id << (u8) stat;
1676 case HUD_STAT_SCALE:
1677 case HUD_STAT_ALIGN:
1678 case HUD_STAT_OFFSET:
1679 pkt << *(v2f *) value;
1683 pkt << *(std::string *) value;
1685 case HUD_STAT_WORLD_POS:
1686 pkt << *(v3f *) value;
1689 pkt << *(v2s32 *) value;
1691 case HUD_STAT_NUMBER:
1695 pkt << *(u32 *) value;
1702 void Server::SendHUDSetFlags(session_t peer_id, u32 flags, u32 mask)
1704 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1706 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1708 pkt << flags << mask;
1713 void Server::SendHUDSetParam(session_t peer_id, u16 param, const std::string &value)
1715 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1716 pkt << param << value;
1720 void Server::SendSetSky(session_t peer_id, const SkyboxParams ¶ms)
1722 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1724 // Handle prior clients here
1725 if (m_clients.getProtocolVersion(peer_id) < 39) {
1726 pkt << params.bgcolor << params.type << (u16) params.textures.size();
1728 for (const std::string& texture : params.textures)
1731 pkt << params.clouds;
1732 } else { // Handle current clients and future clients
1733 pkt << params.bgcolor << params.type
1734 << params.clouds << params.sun_tint
1735 << params.moon_tint << params.tint_type;
1737 if (params.type == "skybox") {
1738 pkt << (u16) params.textures.size();
1739 for (const std::string &texture : params.textures)
1741 } else if (params.type == "regular") {
1742 pkt << params.sky_color.day_sky << params.sky_color.day_horizon
1743 << params.sky_color.dawn_sky << params.sky_color.dawn_horizon
1744 << params.sky_color.night_sky << params.sky_color.night_horizon
1745 << params.sky_color.indoors;
1752 void Server::SendSetSun(session_t peer_id, const SunParams ¶ms)
1754 NetworkPacket pkt(TOCLIENT_SET_SUN, 0, peer_id);
1755 pkt << params.visible << params.texture
1756 << params.tonemap << params.sunrise
1757 << params.sunrise_visible << params.scale;
1761 void Server::SendSetMoon(session_t peer_id, const MoonParams ¶ms)
1763 NetworkPacket pkt(TOCLIENT_SET_MOON, 0, peer_id);
1765 pkt << params.visible << params.texture
1766 << params.tonemap << params.scale;
1770 void Server::SendSetStars(session_t peer_id, const StarParams ¶ms)
1772 NetworkPacket pkt(TOCLIENT_SET_STARS, 0, peer_id);
1774 pkt << params.visible << params.count
1775 << params.starcolor << params.scale;
1780 void Server::SendCloudParams(session_t peer_id, const CloudParams ¶ms)
1782 NetworkPacket pkt(TOCLIENT_CLOUD_PARAMS, 0, peer_id);
1783 pkt << params.density << params.color_bright << params.color_ambient
1784 << params.height << params.thickness << params.speed;
1788 void Server::SendOverrideDayNightRatio(session_t peer_id, bool do_override,
1791 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1794 pkt << do_override << (u16) (ratio * 65535);
1799 void Server::SendTimeOfDay(session_t peer_id, u16 time, f32 time_speed)
1801 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1802 pkt << time << time_speed;
1804 if (peer_id == PEER_ID_INEXISTENT) {
1805 m_clients.sendToAll(&pkt);
1812 void Server::SendPlayerHP(session_t peer_id)
1814 PlayerSAO *playersao = getPlayerSAO(peer_id);
1817 SendHP(peer_id, playersao->getHP());
1818 m_script->player_event(playersao,"health_changed");
1820 // Send to other clients
1821 playersao->sendPunchCommand();
1824 void Server::SendPlayerBreath(PlayerSAO *sao)
1828 m_script->player_event(sao, "breath_changed");
1829 SendBreath(sao->getPeerID(), sao->getBreath());
1832 void Server::SendMovePlayer(session_t peer_id)
1834 RemotePlayer *player = m_env->getPlayer(peer_id);
1836 PlayerSAO *sao = player->getPlayerSAO();
1839 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1840 pkt << sao->getBasePosition() << sao->getLookPitch() << sao->getRotation().Y;
1843 v3f pos = sao->getBasePosition();
1844 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1845 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1846 << " pitch=" << sao->getLookPitch()
1847 << " yaw=" << sao->getRotation().Y
1854 void Server::SendPlayerFov(session_t peer_id)
1856 NetworkPacket pkt(TOCLIENT_FOV, 4 + 1, peer_id);
1858 PlayerFovSpec fov_spec = m_env->getPlayer(peer_id)->getFov();
1859 pkt << fov_spec.fov << fov_spec.is_multiplier;
1864 void Server::SendLocalPlayerAnimations(session_t peer_id, v2s32 animation_frames[4],
1865 f32 animation_speed)
1867 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1870 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1871 << animation_frames[3] << animation_speed;
1876 void Server::SendEyeOffset(session_t peer_id, v3f first, v3f third)
1878 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1879 pkt << first << third;
1883 void Server::SendPlayerPrivileges(session_t peer_id)
1885 RemotePlayer *player = m_env->getPlayer(peer_id);
1887 if(player->getPeerId() == PEER_ID_INEXISTENT)
1890 std::set<std::string> privs;
1891 m_script->getAuth(player->getName(), NULL, &privs);
1893 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1894 pkt << (u16) privs.size();
1896 for (const std::string &priv : privs) {
1903 void Server::SendPlayerInventoryFormspec(session_t peer_id)
1905 RemotePlayer *player = m_env->getPlayer(peer_id);
1907 if (player->getPeerId() == PEER_ID_INEXISTENT)
1910 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1911 pkt.putLongString(player->inventory_formspec);
1916 void Server::SendPlayerFormspecPrepend(session_t peer_id)
1918 RemotePlayer *player = m_env->getPlayer(peer_id);
1920 if (player->getPeerId() == PEER_ID_INEXISTENT)
1923 NetworkPacket pkt(TOCLIENT_FORMSPEC_PREPEND, 0, peer_id);
1924 pkt << player->formspec_prepend;
1928 void Server::SendActiveObjectRemoveAdd(RemoteClient *client, PlayerSAO *playersao)
1930 // Radius inside which objects are active
1931 static thread_local const s16 radius =
1932 g_settings->getS16("active_object_send_range_blocks") * MAP_BLOCKSIZE;
1934 // Radius inside which players are active
1935 static thread_local const bool is_transfer_limited =
1936 g_settings->exists("unlimited_player_transfer_distance") &&
1937 !g_settings->getBool("unlimited_player_transfer_distance");
1939 static thread_local const s16 player_transfer_dist =
1940 g_settings->getS16("player_transfer_distance") * MAP_BLOCKSIZE;
1942 s16 player_radius = player_transfer_dist == 0 && is_transfer_limited ?
1943 radius : player_transfer_dist;
1945 s16 my_radius = MYMIN(radius, playersao->getWantedRange() * MAP_BLOCKSIZE);
1949 std::queue<u16> removed_objects, added_objects;
1950 m_env->getRemovedActiveObjects(playersao, my_radius, player_radius,
1951 client->m_known_objects, removed_objects);
1952 m_env->getAddedActiveObjects(playersao, my_radius, player_radius,
1953 client->m_known_objects, added_objects);
1955 int removed_count = removed_objects.size();
1956 int added_count = added_objects.size();
1958 if (removed_objects.empty() && added_objects.empty())
1964 // Handle removed objects
1965 writeU16((u8*)buf, removed_objects.size());
1966 data.append(buf, 2);
1967 while (!removed_objects.empty()) {
1969 u16 id = removed_objects.front();
1970 ServerActiveObject* obj = m_env->getActiveObject(id);
1972 // Add to data buffer for sending
1973 writeU16((u8*)buf, id);
1974 data.append(buf, 2);
1976 // Remove from known objects
1977 client->m_known_objects.erase(id);
1979 if (obj && obj->m_known_by_count > 0)
1980 obj->m_known_by_count--;
1982 removed_objects.pop();
1985 // Handle added objects
1986 writeU16((u8*)buf, added_objects.size());
1987 data.append(buf, 2);
1988 while (!added_objects.empty()) {
1990 u16 id = added_objects.front();
1991 ServerActiveObject *obj = m_env->getActiveObject(id);
1992 added_objects.pop();
1995 warningstream << FUNCTION_NAME << ": NULL object id="
1996 << (int)id << std::endl;
2001 u8 type = obj->getSendType();
2003 // Add to data buffer for sending
2004 writeU16((u8*)buf, id);
2005 data.append(buf, 2);
2006 writeU8((u8*)buf, type);
2007 data.append(buf, 1);
2009 data.append(serializeLongString(
2010 obj->getClientInitializationData(client->net_proto_version)));
2012 // Add to known objects
2013 client->m_known_objects.insert(id);
2015 obj->m_known_by_count++;
2018 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, data.size(), client->peer_id);
2019 pkt.putRawString(data.c_str(), data.size());
2022 verbosestream << "Server::SendActiveObjectRemoveAdd: "
2023 << removed_count << " removed, " << added_count << " added, "
2024 << "packet size is " << pkt.getSize() << std::endl;
2027 void Server::SendActiveObjectMessages(session_t peer_id, const std::string &datas,
2030 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
2031 datas.size(), peer_id);
2033 pkt.putRawString(datas.c_str(), datas.size());
2035 m_clients.send(pkt.getPeerId(),
2036 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
2040 void Server::SendCSMRestrictionFlags(session_t peer_id)
2042 NetworkPacket pkt(TOCLIENT_CSM_RESTRICTION_FLAGS,
2043 sizeof(m_csm_restriction_flags) + sizeof(m_csm_restriction_noderange), peer_id);
2044 pkt << m_csm_restriction_flags << m_csm_restriction_noderange;
2048 void Server::SendPlayerSpeed(session_t peer_id, const v3f &added_vel)
2050 NetworkPacket pkt(TOCLIENT_PLAYER_SPEED, 0, peer_id);
2055 inline s32 Server::nextSoundId()
2057 s32 ret = m_next_sound_id;
2058 if (m_next_sound_id == INT32_MAX)
2059 m_next_sound_id = 0; // signed overflow is undefined
2065 s32 Server::playSound(const SimpleSoundSpec &spec,
2066 const ServerSoundParams ¶ms, bool ephemeral)
2068 // Find out initial position of sound
2069 bool pos_exists = false;
2070 v3f pos = params.getPos(m_env, &pos_exists);
2071 // If position is not found while it should be, cancel sound
2072 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
2075 // Filter destination clients
2076 std::vector<session_t> dst_clients;
2077 if (!params.to_player.empty()) {
2078 RemotePlayer *player = m_env->getPlayer(params.to_player.c_str());
2080 infostream<<"Server::playSound: Player \""<<params.to_player
2081 <<"\" not found"<<std::endl;
2084 if (player->getPeerId() == PEER_ID_INEXISTENT) {
2085 infostream<<"Server::playSound: Player \""<<params.to_player
2086 <<"\" not connected"<<std::endl;
2089 dst_clients.push_back(player->getPeerId());
2091 std::vector<session_t> clients = m_clients.getClientIDs();
2093 for (const session_t client_id : clients) {
2094 RemotePlayer *player = m_env->getPlayer(client_id);
2097 if (!params.exclude_player.empty() &&
2098 params.exclude_player == player->getName())
2101 PlayerSAO *sao = player->getPlayerSAO();
2106 if(sao->getBasePosition().getDistanceFrom(pos) >
2107 params.max_hear_distance)
2110 dst_clients.push_back(client_id);
2114 if(dst_clients.empty())
2119 ServerPlayingSound *psound = nullptr;
2121 id = -1; // old clients will still use this, so pick a reserved ID
2124 // The sound will exist as a reference in m_playing_sounds
2125 m_playing_sounds[id] = ServerPlayingSound();
2126 psound = &m_playing_sounds[id];
2127 psound->params = params;
2128 psound->spec = spec;
2131 float gain = params.gain * spec.gain;
2132 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2133 pkt << id << spec.name << gain
2134 << (u8) params.type << pos << params.object
2135 << params.loop << params.fade << params.pitch
2138 bool as_reliable = !ephemeral;
2140 for (const u16 dst_client : dst_clients) {
2142 psound->clients.insert(dst_client);
2143 m_clients.send(dst_client, 0, &pkt, as_reliable);
2147 void Server::stopSound(s32 handle)
2149 // Get sound reference
2150 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2151 m_playing_sounds.find(handle);
2152 if (i == m_playing_sounds.end())
2154 ServerPlayingSound &psound = i->second;
2156 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2159 for (std::unordered_set<session_t>::const_iterator si = psound.clients.begin();
2160 si != psound.clients.end(); ++si) {
2162 m_clients.send(*si, 0, &pkt, true);
2164 // Remove sound reference
2165 m_playing_sounds.erase(i);
2168 void Server::fadeSound(s32 handle, float step, float gain)
2170 // Get sound reference
2171 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2172 m_playing_sounds.find(handle);
2173 if (i == m_playing_sounds.end())
2176 ServerPlayingSound &psound = i->second;
2177 psound.params.gain = gain;
2179 NetworkPacket pkt(TOCLIENT_FADE_SOUND, 4);
2180 pkt << handle << step << gain;
2182 // Backwards compability
2183 bool play_sound = gain > 0;
2184 ServerPlayingSound compat_psound = psound;
2185 compat_psound.clients.clear();
2187 NetworkPacket compat_pkt(TOCLIENT_STOP_SOUND, 4);
2188 compat_pkt << handle;
2190 for (std::unordered_set<u16>::iterator it = psound.clients.begin();
2191 it != psound.clients.end();) {
2192 if (m_clients.getProtocolVersion(*it) >= 32) {
2194 m_clients.send(*it, 0, &pkt, true);
2197 compat_psound.clients.insert(*it);
2199 m_clients.send(*it, 0, &compat_pkt, true);
2200 psound.clients.erase(it++);
2204 // Remove sound reference
2205 if (!play_sound || psound.clients.empty())
2206 m_playing_sounds.erase(i);
2208 if (play_sound && !compat_psound.clients.empty()) {
2209 // Play new sound volume on older clients
2210 playSound(compat_psound.spec, compat_psound.params);
2214 void Server::sendRemoveNode(v3s16 p, std::unordered_set<u16> *far_players,
2217 float maxd = far_d_nodes * BS;
2218 v3f p_f = intToFloat(p, BS);
2219 v3s16 block_pos = getNodeBlockPos(p);
2221 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2224 std::vector<session_t> clients = m_clients.getClientIDs();
2227 for (session_t client_id : clients) {
2228 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
2232 RemotePlayer *player = m_env->getPlayer(client_id);
2233 PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr;
2235 // If player is far away, only set modified blocks not sent
2236 if (!client->isBlockSent(block_pos) || (sao &&
2237 sao->getBasePosition().getDistanceFrom(p_f) > maxd)) {
2239 far_players->emplace(client_id);
2241 client->SetBlockNotSent(block_pos);
2246 m_clients.send(client_id, 0, &pkt, true);
2252 void Server::sendAddNode(v3s16 p, MapNode n, std::unordered_set<u16> *far_players,
2253 float far_d_nodes, bool remove_metadata)
2255 float maxd = far_d_nodes * BS;
2256 v3f p_f = intToFloat(p, BS);
2257 v3s16 block_pos = getNodeBlockPos(p);
2259 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2260 pkt << p << n.param0 << n.param1 << n.param2
2261 << (u8) (remove_metadata ? 0 : 1);
2263 std::vector<session_t> clients = m_clients.getClientIDs();
2266 for (session_t client_id : clients) {
2267 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
2271 RemotePlayer *player = m_env->getPlayer(client_id);
2272 PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr;
2274 // If player is far away, only set modified blocks not sent
2275 if (!client->isBlockSent(block_pos) || (sao &&
2276 sao->getBasePosition().getDistanceFrom(p_f) > maxd)) {
2278 far_players->emplace(client_id);
2280 client->SetBlockNotSent(block_pos);
2285 m_clients.send(client_id, 0, &pkt, true);
2291 void Server::sendMetadataChanged(const std::list<v3s16> &meta_updates, float far_d_nodes)
2293 float maxd = far_d_nodes * BS;
2294 NodeMetadataList meta_updates_list(false);
2295 std::vector<session_t> clients = m_clients.getClientIDs();
2299 for (session_t i : clients) {
2300 RemoteClient *client = m_clients.lockedGetClientNoEx(i);
2304 ServerActiveObject *player = m_env->getActiveObject(i);
2305 v3f player_pos = player ? player->getBasePosition() : v3f();
2307 for (const v3s16 &pos : meta_updates) {
2308 NodeMetadata *meta = m_env->getMap().getNodeMetadata(pos);
2313 v3s16 block_pos = getNodeBlockPos(pos);
2314 if (!client->isBlockSent(block_pos) || (player &&
2315 player_pos.getDistanceFrom(intToFloat(pos, BS)) > maxd)) {
2316 client->SetBlockNotSent(block_pos);
2320 // Add the change to send list
2321 meta_updates_list.set(pos, meta);
2323 if (meta_updates_list.size() == 0)
2326 // Send the meta changes
2327 std::ostringstream os(std::ios::binary);
2328 meta_updates_list.serialize(os, client->net_proto_version, false, true);
2329 std::ostringstream oss(std::ios::binary);
2330 compressZlib(os.str(), oss);
2332 NetworkPacket pkt(TOCLIENT_NODEMETA_CHANGED, 0);
2333 pkt.putLongString(oss.str());
2334 m_clients.send(i, 0, &pkt, true);
2336 meta_updates_list.clear();
2342 void Server::SendBlockNoLock(session_t peer_id, MapBlock *block, u8 ver,
2343 u16 net_proto_version)
2346 Create a packet with the block in the right format
2349 std::ostringstream os(std::ios_base::binary);
2350 block->serialize(os, ver, false);
2351 block->serializeNetworkSpecific(os);
2352 std::string s = os.str();
2354 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2356 pkt << block->getPos();
2357 pkt.putRawString(s.c_str(), s.size());
2361 void Server::SendBlocks(float dtime)
2363 MutexAutoLock envlock(m_env_mutex);
2364 //TODO check if one big lock could be faster then multiple small ones
2366 std::vector<PrioritySortedBlockTransfer> queue;
2368 u32 total_sending = 0;
2371 ScopeProfiler sp2(g_profiler, "Server::SendBlocks(): Collect list");
2373 std::vector<session_t> clients = m_clients.getClientIDs();
2376 for (const session_t client_id : clients) {
2377 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id, CS_Active);
2382 total_sending += client->getSendingCount();
2383 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2389 // Lowest priority number comes first.
2390 // Lowest is most important.
2391 std::sort(queue.begin(), queue.end());
2395 // Maximal total count calculation
2396 // The per-client block sends is halved with the maximal online users
2397 u32 max_blocks_to_send = (m_env->getPlayerCount() + g_settings->getU32("max_users")) *
2398 g_settings->getU32("max_simultaneous_block_sends_per_client") / 4 + 1;
2400 ScopeProfiler sp(g_profiler, "Server::SendBlocks(): Send to clients");
2401 Map &map = m_env->getMap();
2403 for (const PrioritySortedBlockTransfer &block_to_send : queue) {
2404 if (total_sending >= max_blocks_to_send)
2407 MapBlock *block = map.getBlockNoCreateNoEx(block_to_send.pos);
2411 RemoteClient *client = m_clients.lockedGetClientNoEx(block_to_send.peer_id,
2416 SendBlockNoLock(block_to_send.peer_id, block, client->serialization_version,
2417 client->net_proto_version);
2419 client->SentBlock(block_to_send.pos);
2425 bool Server::SendBlock(session_t peer_id, const v3s16 &blockpos)
2427 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2432 RemoteClient *client = m_clients.lockedGetClientNoEx(peer_id, CS_Active);
2433 if (!client || client->isBlockSent(blockpos)) {
2437 SendBlockNoLock(peer_id, block, client->serialization_version,
2438 client->net_proto_version);
2444 void Server::fillMediaCache()
2446 infostream<<"Server: Calculating media file checksums"<<std::endl;
2448 // Collect all media file paths
2449 std::vector<std::string> paths;
2450 m_modmgr->getModsMediaPaths(paths);
2451 fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures");
2452 fs::GetRecursiveDirs(paths, porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2454 // Collect media file information from paths into cache
2455 for (const std::string &mediapath : paths) {
2456 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2457 for (const fs::DirListNode &dln : dirlist) {
2458 if (dln.dir) // Ignode dirs
2460 std::string filename = dln.name;
2461 // If name contains illegal characters, ignore the file
2462 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2463 infostream<<"Server: ignoring illegal file name: \""
2464 << filename << "\"" << std::endl;
2467 // If name is not in a supported format, ignore it
2468 const char *supported_ext[] = {
2469 ".png", ".jpg", ".bmp", ".tga",
2470 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2472 ".x", ".b3d", ".md2", ".obj",
2473 // Custom translation file format
2477 if (removeStringEnd(filename, supported_ext).empty()){
2478 infostream << "Server: ignoring unsupported file extension: \""
2479 << filename << "\"" << std::endl;
2482 // Ok, attempt to load the file and add to cache
2483 std::string filepath;
2484 filepath.append(mediapath).append(DIR_DELIM).append(filename);
2487 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2489 errorstream << "Server::fillMediaCache(): Could not open \""
2490 << filename << "\" for reading" << std::endl;
2493 std::ostringstream tmp_os(std::ios_base::binary);
2497 fis.read(buf, 1024);
2498 std::streamsize len = fis.gcount();
2499 tmp_os.write(buf, len);
2508 errorstream<<"Server::fillMediaCache(): Failed to read \""
2509 << filename << "\"" << std::endl;
2512 if(tmp_os.str().length() == 0) {
2513 errorstream << "Server::fillMediaCache(): Empty file \""
2514 << filepath << "\"" << std::endl;
2519 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2521 unsigned char *digest = sha1.getDigest();
2522 std::string sha1_base64 = base64_encode(digest, 20);
2523 std::string sha1_hex = hex_encode((char*)digest, 20);
2527 m_media[filename] = MediaInfo(filepath, sha1_base64);
2528 verbosestream << "Server: " << sha1_hex << " is " << filename
2534 void Server::sendMediaAnnouncement(session_t peer_id, const std::string &lang_code)
2537 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2540 std::string lang_suffix;
2541 lang_suffix.append(".").append(lang_code).append(".tr");
2542 for (const auto &i : m_media) {
2543 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2550 for (const auto &i : m_media) {
2551 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2553 pkt << i.first << i.second.sha1_digest;
2556 pkt << g_settings->get("remote_media");
2559 verbosestream << "Server: Announcing files to id(" << peer_id
2560 << "): count=" << media_sent << " size=" << pkt.getSize() << std::endl;
2563 struct SendableMedia
2569 SendableMedia(const std::string &name_="", const std::string &path_="",
2570 const std::string &data_=""):
2577 void Server::sendRequestedMedia(session_t peer_id,
2578 const std::vector<std::string> &tosend)
2580 verbosestream<<"Server::sendRequestedMedia(): "
2581 <<"Sending files to client"<<std::endl;
2585 // Put 5kB in one bunch (this is not accurate)
2586 u32 bytes_per_bunch = 5000;
2588 std::vector< std::vector<SendableMedia> > file_bunches;
2589 file_bunches.emplace_back();
2591 u32 file_size_bunch_total = 0;
2593 for (const std::string &name : tosend) {
2594 if (m_media.find(name) == m_media.end()) {
2595 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2596 <<"unknown file \""<<(name)<<"\""<<std::endl;
2600 //TODO get path + name
2601 std::string tpath = m_media[name].path;
2604 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2606 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2607 <<tpath<<"\" for reading"<<std::endl;
2610 std::ostringstream tmp_os(std::ios_base::binary);
2614 fis.read(buf, 1024);
2615 std::streamsize len = fis.gcount();
2616 tmp_os.write(buf, len);
2617 file_size_bunch_total += len;
2626 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2627 <<name<<"\""<<std::endl;
2630 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2631 <<tname<<"\""<<std::endl;*/
2633 file_bunches[file_bunches.size()-1].emplace_back(name, tpath, tmp_os.str());
2635 // Start next bunch if got enough data
2636 if(file_size_bunch_total >= bytes_per_bunch) {
2637 file_bunches.emplace_back();
2638 file_size_bunch_total = 0;
2643 /* Create and send packets */
2645 u16 num_bunches = file_bunches.size();
2646 for (u16 i = 0; i < num_bunches; i++) {
2649 u16 total number of texture bunches
2650 u16 index of this bunch
2651 u32 number of files in this bunch
2660 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2661 pkt << num_bunches << i << (u32) file_bunches[i].size();
2663 for (const SendableMedia &j : file_bunches[i]) {
2665 pkt.putLongString(j.data);
2668 verbosestream << "Server::sendRequestedMedia(): bunch "
2669 << i << "/" << num_bunches
2670 << " files=" << file_bunches[i].size()
2671 << " size=" << pkt.getSize() << std::endl;
2676 void Server::sendDetachedInventory(const std::string &name, session_t peer_id)
2678 const auto &inv_it = m_detached_inventories.find(name);
2679 const auto &player_it = m_detached_inventories_player.find(name);
2681 if (player_it == m_detached_inventories_player.end() ||
2682 player_it->second.empty()) {
2683 // OK. Send to everyone
2686 return; // Mods are not done loading
2688 RemotePlayer *p = m_env->getPlayer(player_it->second.c_str());
2690 return; // Player is offline
2692 if (peer_id != PEER_ID_INEXISTENT && peer_id != p->getPeerId())
2693 return; // Caller requested send to a different player, so don't send.
2695 peer_id = p->getPeerId();
2698 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2701 if (inv_it == m_detached_inventories.end()) {
2702 pkt << false; // Remove inventory
2704 pkt << true; // Update inventory
2706 // Serialization & NetworkPacket isn't a love story
2707 std::ostringstream os(std::ios_base::binary);
2708 inv_it->second->serialize(os);
2709 inv_it->second->setModified(false);
2711 const std::string &os_str = os.str();
2712 pkt << static_cast<u16>(os_str.size()); // HACK: to keep compatibility with 5.0.0 clients
2713 pkt.putRawString(os_str);
2716 if (peer_id == PEER_ID_INEXISTENT)
2717 m_clients.sendToAll(&pkt);
2722 void Server::sendDetachedInventories(session_t peer_id, bool incremental)
2724 for (const auto &detached_inventory : m_detached_inventories) {
2725 const std::string &name = detached_inventory.first;
2727 Inventory *inv = detached_inventory.second;
2728 if (!inv || !inv->checkModified())
2732 sendDetachedInventory(name, peer_id);
2740 void Server::DiePlayer(session_t peer_id, const PlayerHPChangeReason &reason)
2742 PlayerSAO *playersao = getPlayerSAO(peer_id);
2745 infostream << "Server::DiePlayer(): Player "
2746 << playersao->getPlayer()->getName()
2747 << " dies" << std::endl;
2749 playersao->setHP(0, reason);
2750 playersao->clearParentAttachment();
2752 // Trigger scripted stuff
2753 m_script->on_dieplayer(playersao, reason);
2755 SendPlayerHP(peer_id);
2756 SendDeathscreen(peer_id, false, v3f(0,0,0));
2759 void Server::RespawnPlayer(session_t peer_id)
2761 PlayerSAO *playersao = getPlayerSAO(peer_id);
2764 infostream << "Server::RespawnPlayer(): Player "
2765 << playersao->getPlayer()->getName()
2766 << " respawns" << std::endl;
2768 playersao->setHP(playersao->accessObjectProperties()->hp_max,
2769 PlayerHPChangeReason(PlayerHPChangeReason::RESPAWN));
2770 playersao->setBreath(playersao->accessObjectProperties()->breath_max);
2772 bool repositioned = m_script->on_respawnplayer(playersao);
2773 if (!repositioned) {
2774 // setPos will send the new position to client
2775 playersao->setPos(findSpawnPos());
2778 SendPlayerHP(peer_id);
2782 void Server::DenySudoAccess(session_t peer_id)
2784 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2789 void Server::DenyAccessVerCompliant(session_t peer_id, u16 proto_ver, AccessDeniedCode reason,
2790 const std::string &str_reason, bool reconnect)
2792 SendAccessDenied(peer_id, reason, str_reason, reconnect);
2794 m_clients.event(peer_id, CSE_SetDenied);
2795 DisconnectPeer(peer_id);
2799 void Server::DenyAccess(session_t peer_id, AccessDeniedCode reason,
2800 const std::string &custom_reason)
2802 SendAccessDenied(peer_id, reason, custom_reason);
2803 m_clients.event(peer_id, CSE_SetDenied);
2804 DisconnectPeer(peer_id);
2807 // 13/03/15: remove this function when protocol version 25 will become
2808 // the minimum version for MT users, maybe in 1 year
2809 void Server::DenyAccess_Legacy(session_t peer_id, const std::wstring &reason)
2811 SendAccessDenied_Legacy(peer_id, reason);
2812 m_clients.event(peer_id, CSE_SetDenied);
2813 DisconnectPeer(peer_id);
2816 void Server::DisconnectPeer(session_t peer_id)
2818 m_modchannel_mgr->leaveAllChannels(peer_id);
2819 m_con->DisconnectPeer(peer_id);
2822 void Server::acceptAuth(session_t peer_id, bool forSudoMode)
2825 RemoteClient* client = getClient(peer_id, CS_Invalid);
2827 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2829 // Right now, the auth mechs don't change between login and sudo mode.
2830 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2831 client->allowed_sudo_mechs = sudo_auth_mechs;
2833 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2834 << g_settings->getFloat("dedicated_server_step")
2838 m_clients.event(peer_id, CSE_AuthAccept);
2840 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2842 // We only support SRP right now
2843 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2845 resp_pkt << sudo_auth_mechs;
2847 m_clients.event(peer_id, CSE_SudoSuccess);
2851 void Server::DeleteClient(session_t peer_id, ClientDeletionReason reason)
2853 std::wstring message;
2856 Clear references to playing sounds
2858 for (std::unordered_map<s32, ServerPlayingSound>::iterator
2859 i = m_playing_sounds.begin(); i != m_playing_sounds.end();) {
2860 ServerPlayingSound &psound = i->second;
2861 psound.clients.erase(peer_id);
2862 if (psound.clients.empty())
2863 m_playing_sounds.erase(i++);
2868 // clear formspec info so the next client can't abuse the current state
2869 m_formspec_state_data.erase(peer_id);
2871 RemotePlayer *player = m_env->getPlayer(peer_id);
2873 /* Run scripts and remove from environment */
2875 PlayerSAO *playersao = player->getPlayerSAO();
2878 playersao->clearChildAttachments();
2879 playersao->clearParentAttachment();
2881 // inform connected clients
2882 const std::string &player_name = player->getName();
2883 NetworkPacket notice(TOCLIENT_UPDATE_PLAYER_LIST, 0, PEER_ID_INEXISTENT);
2884 // (u16) 1 + std::string represents a vector serialization representation
2885 notice << (u8) PLAYER_LIST_REMOVE << (u16) 1 << player_name;
2886 m_clients.sendToAll(¬ice);
2888 m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
2890 playersao->disconnected();
2897 if (player && reason != CDR_DENY) {
2898 std::ostringstream os(std::ios_base::binary);
2899 std::vector<session_t> clients = m_clients.getClientIDs();
2901 for (const session_t client_id : clients) {
2903 RemotePlayer *player = m_env->getPlayer(client_id);
2907 // Get name of player
2908 os << player->getName() << " ";
2911 std::string name = player->getName();
2912 actionstream << name << " "
2913 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2914 << " List of players: " << os.str() << std::endl;
2916 m_admin_chat->outgoing_queue.push_back(
2917 new ChatEventNick(CET_NICK_REMOVE, name));
2921 MutexAutoLock env_lock(m_env_mutex);
2922 m_clients.DeleteClient(peer_id);
2926 // Send leave chat message to all remaining clients
2927 if (!message.empty()) {
2928 SendChatMessage(PEER_ID_INEXISTENT,
2929 ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE, message));
2933 void Server::UpdateCrafting(RemotePlayer *player)
2935 InventoryList *clist = player->inventory.getList("craft");
2936 if (!clist || clist->getSize() == 0)
2939 if (!clist->checkModified())
2942 // Get a preview for crafting
2944 InventoryLocation loc;
2945 loc.setPlayer(player->getName());
2946 std::vector<ItemStack> output_replacements;
2947 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2948 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(),
2951 InventoryList *plist = player->inventory.getList("craftpreview");
2952 if (plist && plist->getSize() >= 1) {
2953 // Put the new preview in
2954 plist->changeItem(0, preview);
2958 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2960 if (evt->type == CET_NICK_ADD) {
2961 // The terminal informed us of its nick choice
2962 m_admin_nick = ((ChatEventNick *)evt)->nick;
2963 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2964 errorstream << "You haven't set up an account." << std::endl
2965 << "Please log in using the client as '"
2966 << m_admin_nick << "' with a secure password." << std::endl
2967 << "Until then, you can't execute admin tasks via the console," << std::endl
2968 << "and everybody can claim the user account instead of you," << std::endl
2969 << "giving them full control over this server." << std::endl;
2972 assert(evt->type == CET_CHAT);
2973 handleAdminChat((ChatEventChat *)evt);
2977 std::wstring Server::handleChat(const std::string &name, const std::wstring &wname,
2978 std::wstring wmessage, bool check_shout_priv, RemotePlayer *player)
2980 // If something goes wrong, this player is to blame
2981 RollbackScopeActor rollback_scope(m_rollback,
2982 std::string("player:") + name);
2984 if (g_settings->getBool("strip_color_codes"))
2985 wmessage = unescape_enriched(wmessage);
2988 switch (player->canSendChatMessage()) {
2989 case RPLAYER_CHATRESULT_FLOODING: {
2990 std::wstringstream ws;
2991 ws << L"You cannot send more messages. You are limited to "
2992 << g_settings->getFloat("chat_message_limit_per_10sec")
2993 << L" messages per 10 seconds.";
2996 case RPLAYER_CHATRESULT_KICK:
2997 DenyAccess_Legacy(player->getPeerId(),
2998 L"You have been kicked due to message flooding.");
3000 case RPLAYER_CHATRESULT_OK:
3003 FATAL_ERROR("Unhandled chat filtering result found.");
3007 if (m_max_chatmessage_length > 0
3008 && wmessage.length() > m_max_chatmessage_length) {
3009 return L"Your message exceed the maximum chat message limit set on the server. "
3010 L"It was refused. Send a shorter message";
3013 auto message = trim(wide_to_utf8(wmessage));
3014 if (message.find_first_of("\n\r") != std::wstring::npos) {
3015 return L"New lines are not permitted in chat messages";
3018 // Run script hook, exit if script ate the chat message
3019 if (m_script->on_chat_message(name, message))
3024 // Whether to send line to the player that sent the message, or to all players
3025 bool broadcast_line = true;
3027 if (check_shout_priv && !checkPriv(name, "shout")) {
3028 line += L"-!- You don't have permission to shout.";
3029 broadcast_line = false;
3031 line += narrow_to_wide(m_script->formatChatMessage(name,
3032 wide_to_narrow(wmessage)));
3036 Tell calling method to send the message to sender
3038 if (!broadcast_line)
3042 Send the message to others
3044 actionstream << "CHAT: " << wide_to_narrow(unescape_enriched(line)) << std::endl;
3046 std::vector<session_t> clients = m_clients.getClientIDs();
3049 Send the message back to the inital sender
3050 if they are using protocol version >= 29
3053 session_t peer_id_to_avoid_sending =
3054 (player ? player->getPeerId() : PEER_ID_INEXISTENT);
3056 if (player && player->protocol_version >= 29)
3057 peer_id_to_avoid_sending = PEER_ID_INEXISTENT;
3059 for (u16 cid : clients) {
3060 if (cid != peer_id_to_avoid_sending)
3061 SendChatMessage(cid, ChatMessage(line));
3066 void Server::handleAdminChat(const ChatEventChat *evt)
3068 std::string name = evt->nick;
3069 std::wstring wname = utf8_to_wide(name);
3070 std::wstring wmessage = evt->evt_msg;
3072 std::wstring answer = handleChat(name, wname, wmessage);
3074 // If asked to send answer to sender
3075 if (!answer.empty()) {
3076 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
3080 RemoteClient *Server::getClient(session_t peer_id, ClientState state_min)
3082 RemoteClient *client = getClientNoEx(peer_id,state_min);
3084 throw ClientNotFoundException("Client not found");
3088 RemoteClient *Server::getClientNoEx(session_t peer_id, ClientState state_min)
3090 return m_clients.getClientNoEx(peer_id, state_min);
3093 std::string Server::getPlayerName(session_t peer_id)
3095 RemotePlayer *player = m_env->getPlayer(peer_id);
3097 return "[id="+itos(peer_id)+"]";
3098 return player->getName();
3101 PlayerSAO *Server::getPlayerSAO(session_t peer_id)
3103 RemotePlayer *player = m_env->getPlayer(peer_id);
3106 return player->getPlayerSAO();
3109 std::wstring Server::getStatusString()
3111 std::wostringstream os(std::ios_base::binary);
3112 os << L"# Server: ";
3114 os << L"version=" << narrow_to_wide(g_version_string);
3116 os << L", uptime=" << m_uptime.get();
3118 os << L", max_lag=" << (m_env ? m_env->getMaxLagEstimate() : 0);
3120 // Information about clients
3122 os << L", clients={";
3124 std::vector<session_t> clients = m_clients.getClientIDs();
3125 for (session_t client_id : clients) {
3126 RemotePlayer *player = m_env->getPlayer(client_id);
3128 // Get name of player
3129 std::wstring name = L"unknown";
3131 name = narrow_to_wide(player->getName());
3133 // Add name to information string
3144 if (m_env && !((ServerMap*)(&m_env->getMap()))->isSavingEnabled())
3145 os << std::endl << L"# Server: " << " WARNING: Map saving is disabled.";
3147 if (!g_settings->get("motd").empty())
3148 os << std::endl << L"# Server: " << narrow_to_wide(g_settings->get("motd"));
3153 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
3155 std::set<std::string> privs;
3156 m_script->getAuth(name, NULL, &privs);
3160 bool Server::checkPriv(const std::string &name, const std::string &priv)
3162 std::set<std::string> privs = getPlayerEffectivePrivs(name);
3163 return (privs.count(priv) != 0);
3166 void Server::reportPrivsModified(const std::string &name)
3169 std::vector<session_t> clients = m_clients.getClientIDs();
3170 for (const session_t client_id : clients) {
3171 RemotePlayer *player = m_env->getPlayer(client_id);
3172 reportPrivsModified(player->getName());
3175 RemotePlayer *player = m_env->getPlayer(name.c_str());
3178 SendPlayerPrivileges(player->getPeerId());
3179 PlayerSAO *sao = player->getPlayerSAO();
3182 sao->updatePrivileges(
3183 getPlayerEffectivePrivs(name),
3188 void Server::reportInventoryFormspecModified(const std::string &name)
3190 RemotePlayer *player = m_env->getPlayer(name.c_str());
3193 SendPlayerInventoryFormspec(player->getPeerId());
3196 void Server::reportFormspecPrependModified(const std::string &name)
3198 RemotePlayer *player = m_env->getPlayer(name.c_str());
3201 SendPlayerFormspecPrepend(player->getPeerId());
3204 void Server::setIpBanned(const std::string &ip, const std::string &name)
3206 m_banmanager->add(ip, name);
3209 void Server::unsetIpBanned(const std::string &ip_or_name)
3211 m_banmanager->remove(ip_or_name);
3214 std::string Server::getBanDescription(const std::string &ip_or_name)
3216 return m_banmanager->getBanDescription(ip_or_name);
3219 void Server::notifyPlayer(const char *name, const std::wstring &msg)
3221 // m_env will be NULL if the server is initializing
3225 if (m_admin_nick == name && !m_admin_nick.empty()) {
3226 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
3229 RemotePlayer *player = m_env->getPlayer(name);
3234 if (player->getPeerId() == PEER_ID_INEXISTENT)
3237 SendChatMessage(player->getPeerId(), ChatMessage(msg));
3240 bool Server::showFormspec(const char *playername, const std::string &formspec,
3241 const std::string &formname)
3243 // m_env will be NULL if the server is initializing
3247 RemotePlayer *player = m_env->getPlayer(playername);
3251 SendShowFormspecMessage(player->getPeerId(), formspec, formname);
3255 u32 Server::hudAdd(RemotePlayer *player, HudElement *form)
3260 u32 id = player->addHud(form);
3262 SendHUDAdd(player->getPeerId(), id, form);
3267 bool Server::hudRemove(RemotePlayer *player, u32 id) {
3271 HudElement* todel = player->removeHud(id);
3278 SendHUDRemove(player->getPeerId(), id);
3282 bool Server::hudChange(RemotePlayer *player, u32 id, HudElementStat stat, void *data)
3287 SendHUDChange(player->getPeerId(), id, stat, data);
3291 bool Server::hudSetFlags(RemotePlayer *player, u32 flags, u32 mask)
3296 SendHUDSetFlags(player->getPeerId(), flags, mask);
3297 player->hud_flags &= ~mask;
3298 player->hud_flags |= flags;
3300 PlayerSAO* playersao = player->getPlayerSAO();
3305 m_script->player_event(playersao, "hud_changed");
3309 bool Server::hudSetHotbarItemcount(RemotePlayer *player, s32 hotbar_itemcount)
3314 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3317 player->setHotbarItemcount(hotbar_itemcount);
3318 std::ostringstream os(std::ios::binary);
3319 writeS32(os, hotbar_itemcount);
3320 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3324 void Server::hudSetHotbarImage(RemotePlayer *player, const std::string &name)
3329 player->setHotbarImage(name);
3330 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_IMAGE, name);
3333 void Server::hudSetHotbarSelectedImage(RemotePlayer *player, const std::string &name)
3338 player->setHotbarSelectedImage(name);
3339 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3342 Address Server::getPeerAddress(session_t peer_id)
3344 return m_con->GetPeerAddress(peer_id);
3347 void Server::setLocalPlayerAnimations(RemotePlayer *player,
3348 v2s32 animation_frames[4], f32 frame_speed)
3350 sanity_check(player);
3351 player->setLocalAnimations(animation_frames, frame_speed);
3352 SendLocalPlayerAnimations(player->getPeerId(), animation_frames, frame_speed);
3355 void Server::setPlayerEyeOffset(RemotePlayer *player, const v3f &first, const v3f &third)
3357 sanity_check(player);
3358 player->eye_offset_first = first;
3359 player->eye_offset_third = third;
3360 SendEyeOffset(player->getPeerId(), first, third);
3363 void Server::setSky(RemotePlayer *player, const SkyboxParams ¶ms)
3365 sanity_check(player);
3366 player->setSky(params);
3367 SendSetSky(player->getPeerId(), params);
3370 void Server::setSun(RemotePlayer *player, const SunParams ¶ms)
3372 sanity_check(player);
3373 player->setSun(params);
3374 SendSetSun(player->getPeerId(), params);
3377 void Server::setMoon(RemotePlayer *player, const MoonParams ¶ms)
3379 sanity_check(player);
3380 player->setMoon(params);
3381 SendSetMoon(player->getPeerId(), params);
3384 void Server::setStars(RemotePlayer *player, const StarParams ¶ms)
3386 sanity_check(player);
3387 player->setStars(params);
3388 SendSetStars(player->getPeerId(), params);
3391 void Server::setClouds(RemotePlayer *player, const CloudParams ¶ms)
3393 sanity_check(player);
3394 player->setCloudParams(params);
3395 SendCloudParams(player->getPeerId(), params);
3398 bool Server::overrideDayNightRatio(RemotePlayer *player, bool do_override,
3404 player->overrideDayNightRatio(do_override, ratio);
3405 SendOverrideDayNightRatio(player->getPeerId(), do_override, ratio);
3409 void Server::notifyPlayers(const std::wstring &msg)
3411 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(msg));
3414 void Server::spawnParticle(const std::string &playername, v3f pos,
3415 v3f velocity, v3f acceleration,
3416 float expirationtime, float size, bool
3417 collisiondetection, bool collision_removal, bool object_collision,
3418 bool vertical, const std::string &texture,
3419 const struct TileAnimationParams &animation, u8 glow)
3421 // m_env will be NULL if the server is initializing
3425 session_t peer_id = PEER_ID_INEXISTENT;
3427 if (!playername.empty()) {
3428 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3431 peer_id = player->getPeerId();
3432 proto_ver = player->protocol_version;
3435 SendSpawnParticle(peer_id, proto_ver, pos, velocity, acceleration,
3436 expirationtime, size, collisiondetection, collision_removal,
3437 object_collision, vertical, texture, animation, glow);
3440 u32 Server::addParticleSpawner(u16 amount, float spawntime,
3441 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
3442 float minexptime, float maxexptime, float minsize, float maxsize,
3443 bool collisiondetection, bool collision_removal, bool object_collision,
3444 ServerActiveObject *attached, bool vertical, const std::string &texture,
3445 const std::string &playername, const struct TileAnimationParams &animation,
3448 // m_env will be NULL if the server is initializing
3452 session_t peer_id = PEER_ID_INEXISTENT;
3454 if (!playername.empty()) {
3455 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3458 peer_id = player->getPeerId();
3459 proto_ver = player->protocol_version;
3462 u16 attached_id = attached ? attached->getId() : 0;
3465 if (attached_id == 0)
3466 id = m_env->addParticleSpawner(spawntime);
3468 id = m_env->addParticleSpawner(spawntime, attached_id);
3470 SendAddParticleSpawner(peer_id, proto_ver, amount, spawntime,
3471 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3472 minexptime, maxexptime, minsize, maxsize, collisiondetection,
3473 collision_removal, object_collision, attached_id, vertical,
3474 texture, id, animation, glow);
3479 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3481 // m_env will be NULL if the server is initializing
3483 throw ServerError("Can't delete particle spawners during initialisation!");
3485 session_t peer_id = PEER_ID_INEXISTENT;
3486 if (!playername.empty()) {
3487 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3490 peer_id = player->getPeerId();
3493 m_env->deleteParticleSpawner(id);
3494 SendDeleteParticleSpawner(peer_id, id);
3497 Inventory* Server::createDetachedInventory(const std::string &name, const std::string &player)
3499 if(m_detached_inventories.count(name) > 0){
3500 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3501 delete m_detached_inventories[name];
3503 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3505 Inventory *inv = new Inventory(m_itemdef);
3507 m_detached_inventories[name] = inv;
3508 if (!player.empty())
3509 m_detached_inventories_player[name] = player;
3511 //TODO find a better way to do this
3512 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3516 bool Server::removeDetachedInventory(const std::string &name)
3518 const auto &inv_it = m_detached_inventories.find(name);
3519 if (inv_it == m_detached_inventories.end())
3522 delete inv_it->second;
3523 m_detached_inventories.erase(inv_it);
3525 if (!m_env) // Mods are not done loading
3528 const auto &player_it = m_detached_inventories_player.find(name);
3529 if (player_it != m_detached_inventories_player.end()) {
3530 RemotePlayer *player = m_env->getPlayer(player_it->second.c_str());
3532 if (player && player->getPeerId() != PEER_ID_INEXISTENT)
3533 sendDetachedInventory(name, player->getPeerId());
3535 m_detached_inventories_player.erase(player_it);
3537 // Notify all players about the change
3538 sendDetachedInventory(name, PEER_ID_INEXISTENT);
3543 // actions: time-reversed list
3544 // Return value: success/failure
3545 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3546 std::list<std::string> *log)
3548 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3549 ServerMap *map = (ServerMap*)(&m_env->getMap());
3551 // Fail if no actions to handle
3552 if (actions.empty()) {
3554 log->push_back("Nothing to do.");
3561 for (const RollbackAction &action : actions) {
3563 bool success = action.applyRevert(map, this, this);
3566 std::ostringstream os;
3567 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3568 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3570 log->push_back(os.str());
3572 std::ostringstream os;
3573 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3574 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3576 log->push_back(os.str());
3580 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3581 <<" failed"<<std::endl;
3583 // Call it done if less than half failed
3584 return num_failed <= num_tried/2;
3587 // IGameDef interface
3589 IItemDefManager *Server::getItemDefManager()
3594 const NodeDefManager *Server::getNodeDefManager()
3599 ICraftDefManager *Server::getCraftDefManager()
3604 u16 Server::allocateUnknownNodeId(const std::string &name)
3606 return m_nodedef->allocateDummy(name);
3609 IWritableItemDefManager *Server::getWritableItemDefManager()
3614 NodeDefManager *Server::getWritableNodeDefManager()
3619 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3624 const std::vector<ModSpec> & Server::getMods() const
3626 return m_modmgr->getMods();
3629 const ModSpec *Server::getModSpec(const std::string &modname) const
3631 return m_modmgr->getModSpec(modname);
3634 void Server::getModNames(std::vector<std::string> &modlist)
3636 m_modmgr->getModNames(modlist);
3639 std::string Server::getBuiltinLuaPath()
3641 return porting::path_share + DIR_DELIM + "builtin";
3644 std::string Server::getModStoragePath() const
3646 return m_path_world + DIR_DELIM + "mod_storage";
3649 v3f Server::findSpawnPos()
3651 ServerMap &map = m_env->getServerMap();
3653 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf))
3654 return nodeposf * BS;
3656 bool is_good = false;
3657 // Limit spawn range to mapgen edges (determined by 'mapgen_limit')
3658 s32 range_max = map.getMapgenParams()->getSpawnRangeMax();
3660 // Try to find a good place a few times
3661 for (s32 i = 0; i < 4000 && !is_good; i++) {
3662 s32 range = MYMIN(1 + i, range_max);
3663 // We're going to try to throw the player to this position
3664 v2s16 nodepos2d = v2s16(
3665 -range + (myrand() % (range * 2)),
3666 -range + (myrand() % (range * 2)));
3667 // Get spawn level at point
3668 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3669 // Continue if MAX_MAP_GENERATION_LIMIT was returned by the mapgen to
3670 // signify an unsuitable spawn position, or if outside limits.
3671 if (spawn_level >= MAX_MAP_GENERATION_LIMIT ||
3672 spawn_level <= -MAX_MAP_GENERATION_LIMIT)
3675 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3676 // Consecutive empty nodes
3679 // Search upwards from 'spawn level' for 2 consecutive empty nodes, to
3680 // avoid obstructions in already-generated mapblocks.
3681 // In ungenerated mapblocks consisting of 'ignore' nodes, there will be
3682 // no obstructions, but mapgen decorations are generated after spawn so
3683 // the player may end up inside one.
3684 for (s32 i = 0; i < 8; i++) {
3685 v3s16 blockpos = getNodeBlockPos(nodepos);
3686 map.emergeBlock(blockpos, true);
3687 content_t c = map.getNode(nodepos).getContent();
3689 // In generated mapblocks allow spawn in all 'airlike' drawtype nodes.
3690 // In ungenerated mapblocks allow spawn in 'ignore' nodes.
3691 if (m_nodedef->get(c).drawtype == NDT_AIRLIKE || c == CONTENT_IGNORE) {
3693 if (air_count >= 2) {
3694 // Spawn in lower empty node
3696 nodeposf = intToFloat(nodepos, BS);
3697 // Don't spawn the player outside map boundaries
3698 if (objectpos_over_limit(nodeposf))
3699 // Exit this loop, positions above are probably over limit
3702 // Good position found, cause an exit from main loop
3716 // No suitable spawn point found, return fallback 0,0,0
3717 return v3f(0.0f, 0.0f, 0.0f);
3720 void Server::requestShutdown(const std::string &msg, bool reconnect, float delay)
3722 if (delay == 0.0f) {
3723 // No delay, shutdown immediately
3724 m_shutdown_state.is_requested = true;
3725 // only print to the infostream, a chat message saying
3726 // "Server Shutting Down" is sent when the server destructs.
3727 infostream << "*** Immediate Server shutdown requested." << std::endl;
3728 } else if (delay < 0.0f && m_shutdown_state.isTimerRunning()) {
3729 // Negative delay, cancel shutdown if requested
3730 m_shutdown_state.reset();
3731 std::wstringstream ws;
3733 ws << L"*** Server shutdown canceled.";
3735 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3736 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3737 // m_shutdown_* are already handled, skip.
3739 } else if (delay > 0.0f) {
3740 // Positive delay, tell the clients when the server will shut down
3741 std::wstringstream ws;
3743 ws << L"*** Server shutting down in "
3744 << duration_to_string(myround(delay)).c_str()
3747 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3748 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3751 m_shutdown_state.trigger(delay, msg, reconnect);
3754 PlayerSAO* Server::emergePlayer(const char *name, session_t peer_id, u16 proto_version)
3757 Try to get an existing player
3759 RemotePlayer *player = m_env->getPlayer(name);
3761 // If player is already connected, cancel
3762 if (player && player->getPeerId() != PEER_ID_INEXISTENT) {
3763 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3768 If player with the wanted peer_id already exists, cancel.
3770 if (m_env->getPlayer(peer_id)) {
3771 infostream<<"emergePlayer(): Player with wrong name but same"
3772 " peer_id already exists"<<std::endl;
3777 player = new RemotePlayer(name, idef());
3780 bool newplayer = false;
3783 PlayerSAO *playersao = m_env->loadPlayer(player, &newplayer, peer_id, isSingleplayer());
3785 // Complete init with server parts
3786 playersao->finalize(player, getPlayerEffectivePrivs(player->getName()));
3787 player->protocol_version = proto_version;
3791 m_script->on_newplayer(playersao);
3797 bool Server::registerModStorage(ModMetadata *storage)
3799 if (m_mod_storages.find(storage->getModName()) != m_mod_storages.end()) {
3800 errorstream << "Unable to register same mod storage twice. Storage name: "
3801 << storage->getModName() << std::endl;
3805 m_mod_storages[storage->getModName()] = storage;
3809 void Server::unregisterModStorage(const std::string &name)
3811 std::unordered_map<std::string, ModMetadata *>::const_iterator it = m_mod_storages.find(name);
3812 if (it != m_mod_storages.end()) {
3813 // Save unconditionaly on unregistration
3814 it->second->save(getModStoragePath());
3815 m_mod_storages.erase(name);
3819 void dedicated_server_loop(Server &server, bool &kill)
3821 verbosestream<<"dedicated_server_loop()"<<std::endl;
3823 IntervalLimiter m_profiler_interval;
3825 static thread_local const float steplen =
3826 g_settings->getFloat("dedicated_server_step");
3827 static thread_local const float profiler_print_interval =
3828 g_settings->getFloat("profiler_print_interval");
3831 * The dedicated server loop only does time-keeping (in Server::step) and
3832 * provides a way to main.cpp to kill the server externally (bool &kill).
3836 // This is kind of a hack but can be done like this
3837 // because server.step() is very light
3838 sleep_ms((int)(steplen*1000.0));
3839 server.step(steplen);
3841 if (server.isShutdownRequested() || kill)
3847 if (profiler_print_interval != 0) {
3848 if(m_profiler_interval.step(steplen, profiler_print_interval))
3850 infostream<<"Profiler:"<<std::endl;
3851 g_profiler->print(infostream);
3852 g_profiler->clear();
3857 infostream << "Dedicated server quitting" << std::endl;
3859 if (g_settings->getBool("server_announce"))
3860 ServerList::sendAnnounce(ServerList::AA_DELETE,
3861 server.m_bind_addr.getPort());
3870 bool Server::joinModChannel(const std::string &channel)
3872 return m_modchannel_mgr->joinChannel(channel, PEER_ID_SERVER) &&
3873 m_modchannel_mgr->setChannelState(channel, MODCHANNEL_STATE_READ_WRITE);
3876 bool Server::leaveModChannel(const std::string &channel)
3878 return m_modchannel_mgr->leaveChannel(channel, PEER_ID_SERVER);
3881 bool Server::sendModChannelMessage(const std::string &channel, const std::string &message)
3883 if (!m_modchannel_mgr->canWriteOnChannel(channel))
3886 broadcastModChannelMessage(channel, message, PEER_ID_SERVER);
3890 ModChannel* Server::getModChannel(const std::string &channel)
3892 return m_modchannel_mgr->getModChannel(channel);
3895 void Server::broadcastModChannelMessage(const std::string &channel,
3896 const std::string &message, session_t from_peer)
3898 const std::vector<u16> &peers = m_modchannel_mgr->getChannelPeers(channel);
3902 if (message.size() > STRING_MAX_LEN) {
3903 warningstream << "ModChannel message too long, dropping before sending "
3904 << " (" << message.size() << " > " << STRING_MAX_LEN << ", channel: "
3905 << channel << ")" << std::endl;
3910 if (from_peer != PEER_ID_SERVER) {
3911 sender = getPlayerName(from_peer);
3914 NetworkPacket resp_pkt(TOCLIENT_MODCHANNEL_MSG,
3915 2 + channel.size() + 2 + sender.size() + 2 + message.size());
3916 resp_pkt << channel << sender << message;
3917 for (session_t peer_id : peers) {
3919 if (peer_id == from_peer)
3922 Send(peer_id, &resp_pkt);
3925 if (from_peer != PEER_ID_SERVER) {
3926 m_script->on_modchannel_message(channel, sender, message);