3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include "network/connection.h"
25 #include "network/networkprotocol.h"
26 #include "network/serveropcodes.h"
28 #include "environment.h"
30 #include "threading/mutex_auto_lock.h"
31 #include "constants.h"
37 #include "serverobject.h"
38 #include "genericobject.h"
42 #include "scripting_server.h"
47 #include "mapgen/mapgen.h"
48 #include "mapgen/mg_biome.h"
49 #include "content_mapnode.h"
50 #include "content_nodemeta.h"
51 #include "content_sao.h"
52 #include "content/mods.h"
53 #include "modchannels.h"
54 #include "serverlist.h"
55 #include "util/string.h"
57 #include "util/serialize.h"
58 #include "util/thread.h"
59 #include "defaultsettings.h"
60 #include "server/mods.h"
61 #include "util/base64.h"
62 #include "util/sha1.h"
64 #include "database/database.h"
65 #include "chatmessage.h"
66 #include "chat_interface.h"
67 #include "remoteplayer.h"
69 class ClientNotFoundException : public BaseException
72 ClientNotFoundException(const char *s):
77 class ServerThread : public Thread
81 ServerThread(Server *server):
92 void *ServerThread::run()
94 BEGIN_DEBUG_EXCEPTION_HANDLER
97 * The real business of the server happens on the ServerThread.
99 * AsyncRunStep() runs an actual server step as soon as enough time has
100 * passed (dedicated_server_loop keeps track of that).
101 * Receive() blocks at least(!) 30ms waiting for a packet (so this loop
102 * doesn't busy wait) and will process any remaining packets.
105 m_server->AsyncRunStep(true);
107 while (!stopRequested()) {
109 m_server->AsyncRunStep();
113 } catch (con::PeerNotFoundException &e) {
114 infostream<<"Server: PeerNotFoundException"<<std::endl;
115 } catch (ClientNotFoundException &e) {
116 } catch (con::ConnectionBindFailed &e) {
117 m_server->setAsyncFatalError(e.what());
118 } catch (LuaError &e) {
119 m_server->setAsyncFatalError(
120 "ServerThread::run Lua: " + std::string(e.what()));
124 END_DEBUG_EXCEPTION_HANDLER
129 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
131 if(pos_exists) *pos_exists = false;
136 if(pos_exists) *pos_exists = true;
141 ServerActiveObject *sao = env->getActiveObject(object);
144 if(pos_exists) *pos_exists = true;
145 return sao->getBasePosition(); }
150 void Server::ShutdownState::reset()
154 should_reconnect = false;
155 is_requested = false;
158 void Server::ShutdownState::trigger(float delay, const std::string &msg, bool reconnect)
162 should_reconnect = reconnect;
165 void Server::ShutdownState::tick(float dtime, Server *server)
171 static const float shutdown_msg_times[] =
173 1, 2, 3, 4, 5, 10, 20, 40, 60, 120, 180, 300, 600, 1200, 1800, 3600
176 // Automated messages
177 if (m_timer < shutdown_msg_times[ARRLEN(shutdown_msg_times) - 1]) {
178 for (float t : shutdown_msg_times) {
179 // If shutdown timer matches an automessage, shot it
180 if (m_timer > t && m_timer - dtime < t) {
181 std::wstring periodicMsg = getShutdownTimerMessage();
183 infostream << wide_to_utf8(periodicMsg).c_str() << std::endl;
184 server->SendChatMessage(PEER_ID_INEXISTENT, periodicMsg);
191 if (m_timer < 0.0f) {
197 std::wstring Server::ShutdownState::getShutdownTimerMessage() const
199 std::wstringstream ws;
200 ws << L"*** Server shutting down in "
201 << duration_to_string(myround(m_timer)).c_str() << ".";
210 const std::string &path_world,
211 const SubgameSpec &gamespec,
212 bool simple_singleplayer_mode,
217 m_bind_addr(bind_addr),
218 m_path_world(path_world),
219 m_gamespec(gamespec),
220 m_simple_singleplayer_mode(simple_singleplayer_mode),
221 m_dedicated(dedicated),
222 m_async_fatal_error(""),
223 m_con(std::make_shared<con::Connection>(PROTOCOL_ID,
226 m_bind_addr.isIPv6(),
228 m_itemdef(createItemDefManager()),
229 m_nodedef(createNodeDefManager()),
230 m_craftdef(createCraftDefManager()),
231 m_thread(new ServerThread(this)),
235 m_modchannel_mgr(new ModChannelMgr())
237 m_lag = g_settings->getFloat("dedicated_server_step");
239 if (m_path_world.empty())
240 throw ServerError("Supplied empty world path");
242 if (!gamespec.isValid())
243 throw ServerError("Supplied invalid gamespec");
249 // Send shutdown message
250 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE,
251 L"*** Server shutting down"));
254 MutexAutoLock envlock(m_env_mutex);
256 infostream << "Server: Saving players" << std::endl;
257 m_env->saveLoadedPlayers();
259 infostream << "Server: Kicking players" << std::endl;
260 std::string kick_msg;
261 bool reconnect = false;
262 if (isShutdownRequested()) {
263 reconnect = m_shutdown_state.should_reconnect;
264 kick_msg = m_shutdown_state.message;
266 if (kick_msg.empty()) {
267 kick_msg = g_settings->get("kick_msg_shutdown");
269 m_env->saveLoadedPlayers(true);
270 m_env->kickAllPlayers(SERVER_ACCESSDENIED_SHUTDOWN,
271 kick_msg, reconnect);
274 actionstream << "Server: Shutting down" << std::endl;
276 // Do this before stopping the server in case mapgen callbacks need to access
277 // server-controlled resources (like ModStorages). Also do them before
278 // shutdown callbacks since they may modify state that is finalized in a
281 m_emerge->stopThreads();
284 MutexAutoLock envlock(m_env_mutex);
286 // Execute script shutdown hooks
287 infostream << "Executing shutdown hooks" << std::endl;
288 m_script->on_shutdown();
290 infostream << "Server: Saving environment metadata" << std::endl;
300 // Delete things in the reverse order of creation
309 // Deinitialize scripting
310 infostream << "Server: Deinitializing scripting" << std::endl;
313 // Delete detached inventories
314 for (auto &detached_inventory : m_detached_inventories) {
315 delete detached_inventory.second;
318 while (!m_unsent_map_edit_queue.empty()) {
319 delete m_unsent_map_edit_queue.front();
320 m_unsent_map_edit_queue.pop();
326 infostream << "Server created for gameid \"" << m_gamespec.id << "\"";
327 if (m_simple_singleplayer_mode)
328 infostream << " in simple singleplayer mode" << std::endl;
330 infostream << std::endl;
331 infostream << "- world: " << m_path_world << std::endl;
332 infostream << "- game: " << m_gamespec.path << std::endl;
334 // Create world if it doesn't exist
335 if (!loadGameConfAndInitWorld(m_path_world, m_gamespec))
336 throw ServerError("Failed to initialize world");
338 // Create emerge manager
339 m_emerge = new EmergeManager(this);
341 // Create ban manager
342 std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
343 m_banmanager = new BanManager(ban_path);
345 m_modmgr = std::unique_ptr<ServerModManager>(new ServerModManager(m_path_world));
346 std::vector<ModSpec> unsatisfied_mods = m_modmgr->getUnsatisfiedMods();
347 // complain about mods with unsatisfied dependencies
348 if (!m_modmgr->isConsistent()) {
349 m_modmgr->printUnsatisfiedModsError();
353 MutexAutoLock envlock(m_env_mutex);
355 // Create the Map (loads map_meta.txt, overriding configured mapgen params)
356 ServerMap *servermap = new ServerMap(m_path_world, this, m_emerge);
358 // Initialize scripting
359 infostream << "Server: Initializing Lua" << std::endl;
361 m_script = new ServerScripting(this);
363 m_script->loadMod(getBuiltinLuaPath() + DIR_DELIM "init.lua", BUILTIN_MOD_NAME);
365 m_modmgr->loadMods(m_script);
367 // Read Textures and calculate sha1 sums
370 // Apply item aliases in the node definition manager
371 m_nodedef->updateAliases(m_itemdef);
373 // Apply texture overrides from texturepack/override.txt
374 std::vector<std::string> paths;
375 fs::GetRecursiveDirs(paths, g_settings->get("texture_path"));
376 fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures");
377 for (const std::string &path : paths)
378 m_nodedef->applyTextureOverrides(path + DIR_DELIM + "override.txt");
380 m_nodedef->setNodeRegistrationStatus(true);
382 // Perform pending node name resolutions
383 m_nodedef->runNodeResolveCallbacks();
385 // unmap node names for connected nodeboxes
386 m_nodedef->mapNodeboxConnections();
388 // init the recipe hashes to speed up crafting
389 m_craftdef->initHashes(this);
391 // Initialize Environment
392 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
394 m_clients.setEnv(m_env);
396 if (!servermap->settings_mgr.makeMapgenParams())
397 FATAL_ERROR("Couldn't create any mapgen type");
399 // Initialize mapgens
400 m_emerge->initMapgens(servermap->getMapgenParams());
402 if (g_settings->getBool("enable_rollback_recording")) {
403 // Create rollback manager
404 m_rollback = new RollbackManager(m_path_world, this);
407 // Give environment reference to scripting api
408 m_script->initializeEnvironment(m_env);
410 // Register us to receive map edit events
411 servermap->addEventReceiver(this);
415 m_liquid_transform_every = g_settings->getFloat("liquid_update");
416 m_max_chatmessage_length = g_settings->getU16("chat_message_max_size");
417 m_csm_restriction_flags = g_settings->getU64("csm_restriction_flags");
418 m_csm_restriction_noderange = g_settings->getU32("csm_restriction_noderange");
423 infostream << "Starting server on " << m_bind_addr.serializeString()
424 << "..." << std::endl;
426 // Stop thread if already running
429 // Initialize connection
430 m_con->SetTimeoutMs(30);
431 m_con->Serve(m_bind_addr);
436 // ASCII art for the win!
438 << " .__ __ __ " << std::endl
439 << " _____ |__| ____ _____/ |_ ____ _______/ |_ " << std::endl
440 << " / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\" << std::endl
441 << "| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | " << std::endl
442 << "|__|_| /__|___| /\\___ >__| \\___ >____ > |__| " << std::endl
443 << " \\/ \\/ \\/ \\/ \\/ " << std::endl;
444 actionstream << "World at [" << m_path_world << "]" << std::endl;
445 actionstream << "Server for gameid=\"" << m_gamespec.id
446 << "\" listening on " << m_bind_addr.serializeString() << ":"
447 << m_bind_addr.getPort() << "." << std::endl;
452 infostream<<"Server: Stopping and waiting threads"<<std::endl;
454 // Stop threads (set run=false first so both start stopping)
456 //m_emergethread.setRun(false);
458 //m_emergethread.stop();
460 infostream<<"Server: Threads stopped"<<std::endl;
463 void Server::step(float dtime)
469 MutexAutoLock lock(m_step_dtime_mutex);
470 m_step_dtime += dtime;
472 // Throw if fatal error occurred in thread
473 std::string async_err = m_async_fatal_error.get();
474 if (!async_err.empty()) {
475 if (!m_simple_singleplayer_mode) {
476 m_env->kickAllPlayers(SERVER_ACCESSDENIED_CRASH,
477 g_settings->get("kick_msg_crash"),
478 g_settings->getBool("ask_reconnect_on_crash"));
480 throw ServerError("AsyncErr: " + async_err);
484 void Server::AsyncRunStep(bool initial_step)
489 MutexAutoLock lock1(m_step_dtime_mutex);
490 dtime = m_step_dtime;
494 // Send blocks to clients
498 if((dtime < 0.001) && !initial_step)
501 ScopeProfiler sp(g_profiler, "Server::AsyncRunStep()", SPT_AVG);
504 MutexAutoLock lock1(m_step_dtime_mutex);
505 m_step_dtime -= dtime;
512 m_uptime.set(m_uptime.get() + dtime);
518 Update time of day and overall game time
520 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
523 Send to clients at constant intervals
526 m_time_of_day_send_timer -= dtime;
527 if(m_time_of_day_send_timer < 0.0) {
528 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
529 u16 time = m_env->getTimeOfDay();
530 float time_speed = g_settings->getFloat("time_speed");
531 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
535 MutexAutoLock lock(m_env_mutex);
536 // Figure out and report maximum lag to environment
537 float max_lag = m_env->getMaxLagEstimate();
538 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
540 if(dtime > 0.1 && dtime > max_lag * 2.0)
541 infostream<<"Server: Maximum lag peaked to "<<dtime
545 m_env->reportMaxLagEstimate(max_lag);
550 static const float map_timer_and_unload_dtime = 2.92;
551 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
553 MutexAutoLock lock(m_env_mutex);
554 // Run Map's timers and unload unused data
555 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
556 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
557 g_settings->getFloat("server_unload_unused_data_timeout"),
562 Listen to the admin chat, if available
565 if (!m_admin_chat->command_queue.empty()) {
566 MutexAutoLock lock(m_env_mutex);
567 while (!m_admin_chat->command_queue.empty()) {
568 ChatEvent *evt = m_admin_chat->command_queue.pop_frontNoEx();
569 handleChatInterfaceEvent(evt);
573 m_admin_chat->outgoing_queue.push_back(
574 new ChatEventTimeInfo(m_env->getGameTime(), m_env->getTimeOfDay()));
581 /* Transform liquids */
582 m_liquid_transform_timer += dtime;
583 if(m_liquid_transform_timer >= m_liquid_transform_every)
585 m_liquid_transform_timer -= m_liquid_transform_every;
587 MutexAutoLock lock(m_env_mutex);
589 ScopeProfiler sp(g_profiler, "Server: liquid transform");
591 std::map<v3s16, MapBlock*> modified_blocks;
592 m_env->getMap().transformLiquids(modified_blocks, m_env);
595 Set the modified blocks unsent for all the clients
597 if (!modified_blocks.empty()) {
598 SetBlocksNotSent(modified_blocks);
601 m_clients.step(dtime);
603 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
605 // send masterserver announce
607 float &counter = m_masterserver_timer;
608 if (!isSingleplayer() && (!counter || counter >= 300.0) &&
609 g_settings->getBool("server_announce")) {
610 ServerList::sendAnnounce(counter ? ServerList::AA_UPDATE :
611 ServerList::AA_START,
612 m_bind_addr.getPort(),
613 m_clients.getPlayerNames(),
615 m_env->getGameTime(),
618 Mapgen::getMapgenName(m_emerge->mgparams->mgtype),
628 Check added and deleted active objects
631 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
632 MutexAutoLock envlock(m_env_mutex);
635 const RemoteClientMap &clients = m_clients.getClientList();
636 ScopeProfiler sp(g_profiler, "Server: update objects within range");
638 for (const auto &client_it : clients) {
639 RemoteClient *client = client_it.second;
641 if (client->getState() < CS_DefinitionsSent)
644 // This can happen if the client times out somehow
645 if (!m_env->getPlayer(client->peer_id))
648 PlayerSAO *playersao = getPlayerSAO(client->peer_id);
652 SendActiveObjectRemoveAdd(client, playersao);
656 // Save mod storages if modified
657 m_mod_storage_save_timer -= dtime;
658 if (m_mod_storage_save_timer <= 0.0f) {
659 infostream << "Saving registered mod storages." << std::endl;
660 m_mod_storage_save_timer = g_settings->getFloat("server_map_save_interval");
661 for (std::unordered_map<std::string, ModMetadata *>::const_iterator
662 it = m_mod_storages.begin(); it != m_mod_storages.end(); ++it) {
663 if (it->second->isModified()) {
664 it->second->save(getModStoragePath());
674 MutexAutoLock envlock(m_env_mutex);
675 ScopeProfiler sp(g_profiler, "Server: send SAO messages");
678 // Value = data sent by object
679 std::unordered_map<u16, std::vector<ActiveObjectMessage>*> buffered_messages;
681 // Get active object messages from environment
683 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
687 std::vector<ActiveObjectMessage>* message_list = nullptr;
688 std::unordered_map<u16, std::vector<ActiveObjectMessage>* >::iterator n;
689 n = buffered_messages.find(aom.id);
690 if (n == buffered_messages.end()) {
691 message_list = new std::vector<ActiveObjectMessage>;
692 buffered_messages[aom.id] = message_list;
695 message_list = n->second;
697 message_list->push_back(aom);
701 const RemoteClientMap &clients = m_clients.getClientList();
702 // Route data to every client
703 for (const auto &client_it : clients) {
704 RemoteClient *client = client_it.second;
705 PlayerSAO *player = getPlayerSAO(client->peer_id);
706 std::string reliable_data;
707 std::string unreliable_data;
708 // Go through all objects in message buffer
709 for (const auto &buffered_message : buffered_messages) {
710 // If object does not exist or is not known by client, skip it
711 u16 id = buffered_message.first;
712 ServerActiveObject *sao = m_env->getActiveObject(id);
713 if (!sao || client->m_known_objects.find(id) == client->m_known_objects.end())
716 // Get message list of object
717 std::vector<ActiveObjectMessage>* list = buffered_message.second;
718 // Go through every message
719 for (const ActiveObjectMessage &aom : *list) {
720 // Send position updates to players who do not see the attachment
721 if (aom.datastring[0] == GENERIC_CMD_UPDATE_POSITION) {
722 if (sao->getId() == player->getId())
725 // Do not send position updates for attached players
726 // as long the parent is known to the client
727 ServerActiveObject *parent = sao->getParent();
728 if (parent && client->m_known_objects.find(parent->getId()) !=
729 client->m_known_objects.end())
732 // Compose the full new data with header
733 std::string new_data;
736 writeU16((u8*)&buf[0], aom.id);
737 new_data.append(buf, 2);
739 new_data += serializeString(aom.datastring);
740 // Add data to buffer
742 reliable_data += new_data;
744 unreliable_data += new_data;
748 reliable_data and unreliable_data are now ready.
751 if (!reliable_data.empty()) {
752 SendActiveObjectMessages(client->peer_id, reliable_data);
755 if (!unreliable_data.empty()) {
756 SendActiveObjectMessages(client->peer_id, unreliable_data, false);
761 // Clear buffered_messages
762 for (auto &buffered_message : buffered_messages) {
763 delete buffered_message.second;
768 Send queued-for-sending map edit events.
771 // We will be accessing the environment
772 MutexAutoLock lock(m_env_mutex);
774 // Don't send too many at a time
777 // Single change sending is disabled if queue size is not small
778 bool disable_single_change_sending = false;
779 if(m_unsent_map_edit_queue.size() >= 4)
780 disable_single_change_sending = true;
782 int event_count = m_unsent_map_edit_queue.size();
784 // We'll log the amount of each
787 std::list<v3s16> node_meta_updates;
789 while (!m_unsent_map_edit_queue.empty()) {
790 MapEditEvent* event = m_unsent_map_edit_queue.front();
791 m_unsent_map_edit_queue.pop();
793 // Players far away from the change are stored here.
794 // Instead of sending the changes, MapBlocks are set not sent
796 std::unordered_set<u16> far_players;
798 switch (event->type) {
801 prof.add("MEET_ADDNODE", 1);
802 sendAddNode(event->p, event->n, &far_players,
803 disable_single_change_sending ? 5 : 30,
804 event->type == MEET_ADDNODE);
806 case MEET_REMOVENODE:
807 prof.add("MEET_REMOVENODE", 1);
808 sendRemoveNode(event->p, &far_players,
809 disable_single_change_sending ? 5 : 30);
811 case MEET_BLOCK_NODE_METADATA_CHANGED: {
812 verbosestream << "Server: MEET_BLOCK_NODE_METADATA_CHANGED" << std::endl;
813 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
814 if (!event->is_private_change) {
815 // Don't send the change yet. Collect them to eliminate dupes.
816 node_meta_updates.remove(event->p);
817 node_meta_updates.push_back(event->p);
820 if (MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(
821 getNodeBlockPos(event->p))) {
822 block->raiseModified(MOD_STATE_WRITE_NEEDED,
823 MOD_REASON_REPORT_META_CHANGE);
828 infostream << "Server: MEET_OTHER" << std::endl;
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);
1021 Address addr = getPeerAddress(player->getPeerId());
1022 std::string ip_str = addr.serializeString();
1023 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1028 const std::vector<std::string> &names = m_clients.getPlayerNames();
1030 actionstream << player->getName() << " joins game. List of players: ";
1032 for (const std::string &name : names) {
1033 actionstream << name << " ";
1036 actionstream << player->getName() <<std::endl;
1041 inline void Server::handleCommand(NetworkPacket *pkt)
1043 const ToServerCommandHandler &opHandle = toServerCommandTable[pkt->getCommand()];
1044 (this->*opHandle.handler)(pkt);
1047 void Server::ProcessData(NetworkPacket *pkt)
1049 // Environment is locked first.
1050 MutexAutoLock envlock(m_env_mutex);
1052 ScopeProfiler sp(g_profiler, "Server: Process network packet (sum)");
1053 u32 peer_id = pkt->getPeerId();
1056 Address address = getPeerAddress(peer_id);
1057 std::string addr_s = address.serializeString();
1059 if(m_banmanager->isIpBanned(addr_s)) {
1060 std::string ban_name = m_banmanager->getBanName(addr_s);
1061 infostream << "Server: A banned client tried to connect from "
1062 << addr_s << "; banned name was "
1063 << ban_name << std::endl;
1064 // This actually doesn't seem to transfer to the client
1065 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1066 + utf8_to_wide(ban_name));
1070 catch(con::PeerNotFoundException &e) {
1072 * no peer for this packet found
1073 * most common reason is peer timeout, e.g. peer didn't
1074 * respond for some time, your server was overloaded or
1077 infostream << "Server::ProcessData(): Canceling: peer "
1078 << peer_id << " not found" << std::endl;
1083 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1085 // Command must be handled into ToServerCommandHandler
1086 if (command >= TOSERVER_NUM_MSG_TYPES) {
1087 infostream << "Server: Ignoring unknown command "
1088 << command << std::endl;
1092 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1097 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1099 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1100 errorstream << "Server::ProcessData(): Cancelling: Peer"
1101 " serialization format invalid or not initialized."
1102 " Skipping incoming command=" << command << std::endl;
1106 /* Handle commands related to client startup */
1107 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1112 if (m_clients.getClientState(peer_id) < CS_Active) {
1113 if (command == TOSERVER_PLAYERPOS) return;
1115 errorstream << "Got packet command: " << command << " for peer id "
1116 << peer_id << " but client isn't active yet. Dropping packet "
1122 } catch (SendFailedException &e) {
1123 errorstream << "Server::ProcessData(): SendFailedException: "
1124 << "what=" << e.what()
1126 } catch (PacketError &e) {
1127 actionstream << "Server::ProcessData(): PacketError: "
1128 << "what=" << e.what()
1133 void Server::setTimeOfDay(u32 time)
1135 m_env->setTimeOfDay(time);
1136 m_time_of_day_send_timer = 0;
1139 void Server::onMapEditEvent(const MapEditEvent &event)
1141 if (m_ignore_map_edit_events_area.contains(event.getArea()))
1144 m_unsent_map_edit_queue.push(new MapEditEvent(event));
1147 Inventory* Server::getInventory(const InventoryLocation &loc)
1150 case InventoryLocation::UNDEFINED:
1151 case InventoryLocation::CURRENT_PLAYER:
1153 case InventoryLocation::PLAYER:
1155 RemotePlayer *player = m_env->getPlayer(loc.name.c_str());
1158 PlayerSAO *playersao = player->getPlayerSAO();
1161 return playersao->getInventory();
1164 case InventoryLocation::NODEMETA:
1166 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1169 return meta->getInventory();
1172 case InventoryLocation::DETACHED:
1174 if(m_detached_inventories.count(loc.name) == 0)
1176 return m_detached_inventories[loc.name];
1180 sanity_check(false); // abort
1186 void Server::setInventoryModified(const InventoryLocation &loc)
1189 case InventoryLocation::UNDEFINED:
1191 case InventoryLocation::PLAYER:
1194 RemotePlayer *player = m_env->getPlayer(loc.name.c_str());
1199 player->setModified(true);
1200 player->inventory.setModified(true);
1201 // Updates are sent in ServerEnvironment::step()
1204 case InventoryLocation::NODEMETA:
1207 event.type = MEET_BLOCK_NODE_METADATA_CHANGED;
1209 m_env->getMap().dispatchEvent(event);
1212 case InventoryLocation::DETACHED:
1214 // Updates are sent in ServerEnvironment::step()
1218 sanity_check(false); // abort
1223 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1225 std::vector<session_t> clients = m_clients.getClientIDs();
1227 // Set the modified blocks unsent for all the clients
1228 for (const session_t client_id : clients) {
1229 if (RemoteClient *client = m_clients.lockedGetClientNoEx(client_id))
1230 client->SetBlocksNotSent(block);
1235 void Server::peerAdded(con::Peer *peer)
1237 verbosestream<<"Server::peerAdded(): peer->id="
1238 <<peer->id<<std::endl;
1240 m_peer_change_queue.push(con::PeerChange(con::PEER_ADDED, peer->id, false));
1243 void Server::deletingPeer(con::Peer *peer, bool timeout)
1245 verbosestream<<"Server::deletingPeer(): peer->id="
1246 <<peer->id<<", timeout="<<timeout<<std::endl;
1248 m_clients.event(peer->id, CSE_Disconnect);
1249 m_peer_change_queue.push(con::PeerChange(con::PEER_REMOVED, peer->id, timeout));
1252 bool Server::getClientConInfo(session_t peer_id, con::rtt_stat_type type, float* retval)
1254 *retval = m_con->getPeerStat(peer_id,type);
1255 return *retval != -1;
1258 bool Server::getClientInfo(
1267 std::string* vers_string
1270 *state = m_clients.getClientState(peer_id);
1272 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1279 *uptime = client->uptime();
1280 *ser_vers = client->serialization_version;
1281 *prot_vers = client->net_proto_version;
1283 *major = client->getMajor();
1284 *minor = client->getMinor();
1285 *patch = client->getPatch();
1286 *vers_string = client->getFull();
1293 void Server::handlePeerChanges()
1295 while(!m_peer_change_queue.empty())
1297 con::PeerChange c = m_peer_change_queue.front();
1298 m_peer_change_queue.pop();
1300 verbosestream<<"Server: Handling peer change: "
1301 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1306 case con::PEER_ADDED:
1307 m_clients.CreateClient(c.peer_id);
1310 case con::PEER_REMOVED:
1311 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1315 FATAL_ERROR("Invalid peer change event received!");
1321 void Server::printToConsoleOnly(const std::string &text)
1324 m_admin_chat->outgoing_queue.push_back(
1325 new ChatEventChat("", utf8_to_wide(text)));
1327 std::cout << text << std::endl;
1331 void Server::Send(NetworkPacket *pkt)
1333 Send(pkt->getPeerId(), pkt);
1336 void Server::Send(session_t peer_id, NetworkPacket *pkt)
1338 m_clients.send(peer_id,
1339 clientCommandFactoryTable[pkt->getCommand()].channel,
1341 clientCommandFactoryTable[pkt->getCommand()].reliable);
1344 void Server::SendMovement(session_t peer_id)
1346 std::ostringstream os(std::ios_base::binary);
1348 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1350 pkt << g_settings->getFloat("movement_acceleration_default");
1351 pkt << g_settings->getFloat("movement_acceleration_air");
1352 pkt << g_settings->getFloat("movement_acceleration_fast");
1353 pkt << g_settings->getFloat("movement_speed_walk");
1354 pkt << g_settings->getFloat("movement_speed_crouch");
1355 pkt << g_settings->getFloat("movement_speed_fast");
1356 pkt << g_settings->getFloat("movement_speed_climb");
1357 pkt << g_settings->getFloat("movement_speed_jump");
1358 pkt << g_settings->getFloat("movement_liquid_fluidity");
1359 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1360 pkt << g_settings->getFloat("movement_liquid_sink");
1361 pkt << g_settings->getFloat("movement_gravity");
1366 void Server::SendPlayerHPOrDie(PlayerSAO *playersao, const PlayerHPChangeReason &reason)
1368 if (playersao->isImmortal())
1371 session_t peer_id = playersao->getPeerID();
1372 bool is_alive = playersao->getHP() > 0;
1375 SendPlayerHP(peer_id);
1377 DiePlayer(peer_id, reason);
1380 void Server::SendHP(session_t peer_id, u16 hp)
1382 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1387 void Server::SendBreath(session_t peer_id, u16 breath)
1389 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1390 pkt << (u16) breath;
1394 void Server::SendAccessDenied(session_t peer_id, AccessDeniedCode reason,
1395 const std::string &custom_reason, bool reconnect)
1397 assert(reason < SERVER_ACCESSDENIED_MAX);
1399 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1401 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
1402 pkt << custom_reason;
1403 else if (reason == SERVER_ACCESSDENIED_SHUTDOWN ||
1404 reason == SERVER_ACCESSDENIED_CRASH)
1405 pkt << custom_reason << (u8)reconnect;
1409 void Server::SendAccessDenied_Legacy(session_t peer_id,const std::wstring &reason)
1411 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1416 void Server::SendDeathscreen(session_t peer_id, bool set_camera_point_target,
1417 v3f camera_point_target)
1419 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1420 pkt << set_camera_point_target << camera_point_target;
1424 void Server::SendItemDef(session_t peer_id,
1425 IItemDefManager *itemdef, u16 protocol_version)
1427 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1431 u32 length of the next item
1432 zlib-compressed serialized ItemDefManager
1434 std::ostringstream tmp_os(std::ios::binary);
1435 itemdef->serialize(tmp_os, protocol_version);
1436 std::ostringstream tmp_os2(std::ios::binary);
1437 compressZlib(tmp_os.str(), tmp_os2);
1438 pkt.putLongString(tmp_os2.str());
1441 verbosestream << "Server: Sending item definitions to id(" << peer_id
1442 << "): size=" << pkt.getSize() << std::endl;
1447 void Server::SendNodeDef(session_t peer_id,
1448 const NodeDefManager *nodedef, u16 protocol_version)
1450 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1454 u32 length of the next item
1455 zlib-compressed serialized NodeDefManager
1457 std::ostringstream tmp_os(std::ios::binary);
1458 nodedef->serialize(tmp_os, protocol_version);
1459 std::ostringstream tmp_os2(std::ios::binary);
1460 compressZlib(tmp_os.str(), tmp_os2);
1462 pkt.putLongString(tmp_os2.str());
1465 verbosestream << "Server: Sending node definitions to id(" << peer_id
1466 << "): size=" << pkt.getSize() << std::endl;
1472 Non-static send methods
1475 void Server::SendInventory(PlayerSAO *sao, bool incremental)
1477 RemotePlayer *player = sao->getPlayer();
1479 // Do not send new format to old clients
1480 incremental &= player->protocol_version >= 38;
1482 UpdateCrafting(player);
1488 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, sao->getPeerID());
1490 std::ostringstream os(std::ios::binary);
1491 sao->getInventory()->serialize(os, incremental);
1492 sao->getInventory()->setModified(false);
1493 player->setModified(true);
1495 const std::string &s = os.str();
1496 pkt.putRawString(s.c_str(), s.size());
1500 void Server::SendChatMessage(session_t peer_id, const ChatMessage &message)
1502 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1504 u8 type = message.type;
1505 pkt << version << type << std::wstring(L"") << message.message << (u64)message.timestamp;
1507 if (peer_id != PEER_ID_INEXISTENT) {
1508 RemotePlayer *player = m_env->getPlayer(peer_id);
1514 m_clients.sendToAll(&pkt);
1518 void Server::SendShowFormspecMessage(session_t peer_id, const std::string &formspec,
1519 const std::string &formname)
1521 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0, peer_id);
1522 if (formspec.empty()){
1523 //the client should close the formspec
1524 //but make sure there wasn't another one open in meantime
1525 const auto it = m_formspec_state_data.find(peer_id);
1526 if (it != m_formspec_state_data.end() && it->second == formname) {
1527 m_formspec_state_data.erase(peer_id);
1529 pkt.putLongString("");
1531 m_formspec_state_data[peer_id] = formname;
1532 pkt.putLongString(formspec);
1539 // Spawns a particle on peer with peer_id
1540 void Server::SendSpawnParticle(session_t peer_id, u16 protocol_version,
1541 v3f pos, v3f velocity, v3f acceleration,
1542 float expirationtime, float size, bool collisiondetection,
1543 bool collision_removal, bool object_collision,
1544 bool vertical, const std::string &texture,
1545 const struct TileAnimationParams &animation, u8 glow)
1547 static thread_local const float radius =
1548 g_settings->getS16("max_block_send_distance") * MAP_BLOCKSIZE * BS;
1550 if (peer_id == PEER_ID_INEXISTENT) {
1551 std::vector<session_t> clients = m_clients.getClientIDs();
1553 for (const session_t client_id : clients) {
1554 RemotePlayer *player = m_env->getPlayer(client_id);
1558 PlayerSAO *sao = player->getPlayerSAO();
1562 // Do not send to distant clients
1563 if (sao->getBasePosition().getDistanceFrom(pos * BS) > radius)
1566 SendSpawnParticle(client_id, player->protocol_version,
1567 pos, velocity, acceleration,
1568 expirationtime, size, collisiondetection, collision_removal,
1569 object_collision, vertical, texture, animation, glow);
1574 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1576 pkt << pos << velocity << acceleration << expirationtime
1577 << size << collisiondetection;
1578 pkt.putLongString(texture);
1580 pkt << collision_removal;
1581 // This is horrible but required (why are there two ways to serialize pkts?)
1582 std::ostringstream os(std::ios_base::binary);
1583 animation.serialize(os, protocol_version);
1584 pkt.putRawString(os.str());
1586 pkt << object_collision;
1591 // Adds a ParticleSpawner on peer with peer_id
1592 void Server::SendAddParticleSpawner(session_t peer_id, u16 protocol_version,
1593 u16 amount, float spawntime, v3f minpos, v3f maxpos,
1594 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1595 float minsize, float maxsize, bool collisiondetection, bool collision_removal,
1596 bool object_collision, u16 attached_id, bool vertical, const std::string &texture, u32 id,
1597 const struct TileAnimationParams &animation, u8 glow)
1599 if (peer_id == PEER_ID_INEXISTENT) {
1600 // This sucks and should be replaced:
1601 std::vector<session_t> clients = m_clients.getClientIDs();
1602 for (const session_t client_id : clients) {
1603 RemotePlayer *player = m_env->getPlayer(client_id);
1606 SendAddParticleSpawner(client_id, player->protocol_version,
1607 amount, spawntime, minpos, maxpos,
1608 minvel, maxvel, minacc, maxacc, minexptime, maxexptime,
1609 minsize, maxsize, collisiondetection, collision_removal,
1610 object_collision, attached_id, vertical, texture, id,
1616 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1618 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1619 << minacc << maxacc << minexptime << maxexptime << minsize
1620 << maxsize << collisiondetection;
1622 pkt.putLongString(texture);
1624 pkt << id << vertical;
1625 pkt << collision_removal;
1627 // This is horrible but required
1628 std::ostringstream os(std::ios_base::binary);
1629 animation.serialize(os, protocol_version);
1630 pkt.putRawString(os.str());
1632 pkt << object_collision;
1637 void Server::SendDeleteParticleSpawner(session_t peer_id, u32 id)
1639 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER, 4, peer_id);
1641 // Ugly error in this packet
1644 if (peer_id != PEER_ID_INEXISTENT)
1647 m_clients.sendToAll(&pkt);
1651 void Server::SendHUDAdd(session_t peer_id, u32 id, HudElement *form)
1653 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1655 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1656 << form->text << form->number << form->item << form->dir
1657 << form->align << form->offset << form->world_pos << form->size
1663 void Server::SendHUDRemove(session_t peer_id, u32 id)
1665 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1670 void Server::SendHUDChange(session_t peer_id, u32 id, HudElementStat stat, void *value)
1672 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1673 pkt << id << (u8) stat;
1677 case HUD_STAT_SCALE:
1678 case HUD_STAT_ALIGN:
1679 case HUD_STAT_OFFSET:
1680 pkt << *(v2f *) value;
1684 pkt << *(std::string *) value;
1686 case HUD_STAT_WORLD_POS:
1687 pkt << *(v3f *) value;
1690 pkt << *(v2s32 *) value;
1692 case HUD_STAT_NUMBER:
1696 pkt << *(u32 *) value;
1703 void Server::SendHUDSetFlags(session_t peer_id, u32 flags, u32 mask)
1705 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1707 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1709 pkt << flags << mask;
1714 void Server::SendHUDSetParam(session_t peer_id, u16 param, const std::string &value)
1716 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1717 pkt << param << value;
1721 void Server::SendSetSky(session_t peer_id, const video::SColor &bgcolor,
1722 const std::string &type, const std::vector<std::string> ¶ms,
1725 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1726 pkt << bgcolor << type << (u16) params.size();
1728 for (const std::string ¶m : params)
1736 void Server::SendCloudParams(session_t peer_id, const CloudParams ¶ms)
1738 NetworkPacket pkt(TOCLIENT_CLOUD_PARAMS, 0, peer_id);
1739 pkt << params.density << params.color_bright << params.color_ambient
1740 << params.height << params.thickness << params.speed;
1744 void Server::SendOverrideDayNightRatio(session_t peer_id, bool do_override,
1747 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1750 pkt << do_override << (u16) (ratio * 65535);
1755 void Server::SendTimeOfDay(session_t peer_id, u16 time, f32 time_speed)
1757 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1758 pkt << time << time_speed;
1760 if (peer_id == PEER_ID_INEXISTENT) {
1761 m_clients.sendToAll(&pkt);
1768 void Server::SendPlayerHP(session_t peer_id)
1770 PlayerSAO *playersao = getPlayerSAO(peer_id);
1771 // In some rare case if the player is disconnected
1772 // while Lua call l_punch, for example, this can be NULL
1776 SendHP(peer_id, playersao->getHP());
1777 m_script->player_event(playersao,"health_changed");
1779 // Send to other clients
1780 std::string str = gob_cmd_punched(playersao->getHP());
1781 ActiveObjectMessage aom(playersao->getId(), true, str);
1782 playersao->m_messages_out.push(aom);
1785 void Server::SendPlayerBreath(PlayerSAO *sao)
1789 m_script->player_event(sao, "breath_changed");
1790 SendBreath(sao->getPeerID(), sao->getBreath());
1793 void Server::SendMovePlayer(session_t peer_id)
1795 RemotePlayer *player = m_env->getPlayer(peer_id);
1797 PlayerSAO *sao = player->getPlayerSAO();
1800 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1801 pkt << sao->getBasePosition() << sao->getLookPitch() << sao->getRotation().Y;
1804 v3f pos = sao->getBasePosition();
1805 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1806 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1807 << " pitch=" << sao->getLookPitch()
1808 << " yaw=" << sao->getRotation().Y
1815 void Server::SendPlayerFov(session_t peer_id)
1817 NetworkPacket pkt(TOCLIENT_FOV, 4 + 1, peer_id);
1819 PlayerFovSpec fov_spec = m_env->getPlayer(peer_id)->getFov();
1820 pkt << fov_spec.fov << fov_spec.is_multiplier;
1825 void Server::SendLocalPlayerAnimations(session_t peer_id, v2s32 animation_frames[4],
1826 f32 animation_speed)
1828 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1831 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1832 << animation_frames[3] << animation_speed;
1837 void Server::SendEyeOffset(session_t peer_id, v3f first, v3f third)
1839 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1840 pkt << first << third;
1844 void Server::SendPlayerPrivileges(session_t peer_id)
1846 RemotePlayer *player = m_env->getPlayer(peer_id);
1848 if(player->getPeerId() == PEER_ID_INEXISTENT)
1851 std::set<std::string> privs;
1852 m_script->getAuth(player->getName(), NULL, &privs);
1854 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1855 pkt << (u16) privs.size();
1857 for (const std::string &priv : privs) {
1864 void Server::SendPlayerInventoryFormspec(session_t peer_id)
1866 RemotePlayer *player = m_env->getPlayer(peer_id);
1868 if (player->getPeerId() == PEER_ID_INEXISTENT)
1871 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1872 pkt.putLongString(player->inventory_formspec);
1877 void Server::SendPlayerFormspecPrepend(session_t peer_id)
1879 RemotePlayer *player = m_env->getPlayer(peer_id);
1881 if (player->getPeerId() == PEER_ID_INEXISTENT)
1884 NetworkPacket pkt(TOCLIENT_FORMSPEC_PREPEND, 0, peer_id);
1885 pkt << player->formspec_prepend;
1889 void Server::SendActiveObjectRemoveAdd(RemoteClient *client, PlayerSAO *playersao)
1891 // Radius inside which objects are active
1892 static thread_local const s16 radius =
1893 g_settings->getS16("active_object_send_range_blocks") * MAP_BLOCKSIZE;
1895 // Radius inside which players are active
1896 static thread_local const bool is_transfer_limited =
1897 g_settings->exists("unlimited_player_transfer_distance") &&
1898 !g_settings->getBool("unlimited_player_transfer_distance");
1900 static thread_local const s16 player_transfer_dist =
1901 g_settings->getS16("player_transfer_distance") * MAP_BLOCKSIZE;
1903 s16 player_radius = player_transfer_dist == 0 && is_transfer_limited ?
1904 radius : player_transfer_dist;
1906 s16 my_radius = MYMIN(radius, playersao->getWantedRange() * MAP_BLOCKSIZE);
1910 std::queue<u16> removed_objects, added_objects;
1911 m_env->getRemovedActiveObjects(playersao, my_radius, player_radius,
1912 client->m_known_objects, removed_objects);
1913 m_env->getAddedActiveObjects(playersao, my_radius, player_radius,
1914 client->m_known_objects, added_objects);
1916 int removed_count = removed_objects.size();
1917 int added_count = added_objects.size();
1919 if (removed_objects.empty() && added_objects.empty())
1925 // Handle removed objects
1926 writeU16((u8*)buf, removed_objects.size());
1927 data.append(buf, 2);
1928 while (!removed_objects.empty()) {
1930 u16 id = removed_objects.front();
1931 ServerActiveObject* obj = m_env->getActiveObject(id);
1933 // Add to data buffer for sending
1934 writeU16((u8*)buf, id);
1935 data.append(buf, 2);
1937 // Remove from known objects
1938 client->m_known_objects.erase(id);
1940 if (obj && obj->m_known_by_count > 0)
1941 obj->m_known_by_count--;
1943 removed_objects.pop();
1946 // Handle added objects
1947 writeU16((u8*)buf, added_objects.size());
1948 data.append(buf, 2);
1949 while (!added_objects.empty()) {
1951 u16 id = added_objects.front();
1952 ServerActiveObject *obj = m_env->getActiveObject(id);
1953 added_objects.pop();
1956 warningstream << FUNCTION_NAME << ": NULL object id="
1957 << (int)id << std::endl;
1962 u8 type = obj->getSendType();
1964 // Add to data buffer for sending
1965 writeU16((u8*)buf, id);
1966 data.append(buf, 2);
1967 writeU8((u8*)buf, type);
1968 data.append(buf, 1);
1970 data.append(serializeLongString(
1971 obj->getClientInitializationData(client->net_proto_version)));
1973 // Add to known objects
1974 client->m_known_objects.insert(id);
1976 obj->m_known_by_count++;
1979 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, data.size(), client->peer_id);
1980 pkt.putRawString(data.c_str(), data.size());
1983 verbosestream << "Server::SendActiveObjectRemoveAdd: "
1984 << removed_count << " removed, " << added_count << " added, "
1985 << "packet size is " << pkt.getSize() << std::endl;
1988 void Server::SendActiveObjectMessages(session_t peer_id, const std::string &datas,
1991 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
1992 datas.size(), peer_id);
1994 pkt.putRawString(datas.c_str(), datas.size());
1996 m_clients.send(pkt.getPeerId(),
1997 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
2001 void Server::SendCSMRestrictionFlags(session_t peer_id)
2003 NetworkPacket pkt(TOCLIENT_CSM_RESTRICTION_FLAGS,
2004 sizeof(m_csm_restriction_flags) + sizeof(m_csm_restriction_noderange), peer_id);
2005 pkt << m_csm_restriction_flags << m_csm_restriction_noderange;
2009 void Server::SendPlayerSpeed(session_t peer_id, const v3f &added_vel)
2011 NetworkPacket pkt(TOCLIENT_PLAYER_SPEED, 0, peer_id);
2016 inline s32 Server::nextSoundId()
2018 s32 ret = m_next_sound_id;
2019 if (m_next_sound_id == INT32_MAX)
2020 m_next_sound_id = 0; // signed overflow is undefined
2026 s32 Server::playSound(const SimpleSoundSpec &spec,
2027 const ServerSoundParams ¶ms, bool ephemeral)
2029 // Find out initial position of sound
2030 bool pos_exists = false;
2031 v3f pos = params.getPos(m_env, &pos_exists);
2032 // If position is not found while it should be, cancel sound
2033 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
2036 // Filter destination clients
2037 std::vector<session_t> dst_clients;
2038 if (!params.to_player.empty()) {
2039 RemotePlayer *player = m_env->getPlayer(params.to_player.c_str());
2041 infostream<<"Server::playSound: Player \""<<params.to_player
2042 <<"\" not found"<<std::endl;
2045 if (player->getPeerId() == PEER_ID_INEXISTENT) {
2046 infostream<<"Server::playSound: Player \""<<params.to_player
2047 <<"\" not connected"<<std::endl;
2050 dst_clients.push_back(player->getPeerId());
2052 std::vector<session_t> clients = m_clients.getClientIDs();
2054 for (const session_t client_id : clients) {
2055 RemotePlayer *player = m_env->getPlayer(client_id);
2058 if (!params.exclude_player.empty() &&
2059 params.exclude_player == player->getName())
2062 PlayerSAO *sao = player->getPlayerSAO();
2067 if(sao->getBasePosition().getDistanceFrom(pos) >
2068 params.max_hear_distance)
2071 dst_clients.push_back(client_id);
2075 if(dst_clients.empty())
2080 ServerPlayingSound *psound = nullptr;
2082 id = -1; // old clients will still use this, so pick a reserved ID
2085 // The sound will exist as a reference in m_playing_sounds
2086 m_playing_sounds[id] = ServerPlayingSound();
2087 psound = &m_playing_sounds[id];
2088 psound->params = params;
2089 psound->spec = spec;
2092 float gain = params.gain * spec.gain;
2093 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2094 pkt << id << spec.name << gain
2095 << (u8) params.type << pos << params.object
2096 << params.loop << params.fade << params.pitch
2099 bool as_reliable = !ephemeral;
2101 for (const u16 dst_client : dst_clients) {
2103 psound->clients.insert(dst_client);
2104 m_clients.send(dst_client, 0, &pkt, as_reliable);
2108 void Server::stopSound(s32 handle)
2110 // Get sound reference
2111 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2112 m_playing_sounds.find(handle);
2113 if (i == m_playing_sounds.end())
2115 ServerPlayingSound &psound = i->second;
2117 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2120 for (std::unordered_set<session_t>::const_iterator si = psound.clients.begin();
2121 si != psound.clients.end(); ++si) {
2123 m_clients.send(*si, 0, &pkt, true);
2125 // Remove sound reference
2126 m_playing_sounds.erase(i);
2129 void Server::fadeSound(s32 handle, float step, float gain)
2131 // Get sound reference
2132 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2133 m_playing_sounds.find(handle);
2134 if (i == m_playing_sounds.end())
2137 ServerPlayingSound &psound = i->second;
2138 psound.params.gain = gain;
2140 NetworkPacket pkt(TOCLIENT_FADE_SOUND, 4);
2141 pkt << handle << step << gain;
2143 // Backwards compability
2144 bool play_sound = gain > 0;
2145 ServerPlayingSound compat_psound = psound;
2146 compat_psound.clients.clear();
2148 NetworkPacket compat_pkt(TOCLIENT_STOP_SOUND, 4);
2149 compat_pkt << handle;
2151 for (std::unordered_set<u16>::iterator it = psound.clients.begin();
2152 it != psound.clients.end();) {
2153 if (m_clients.getProtocolVersion(*it) >= 32) {
2155 m_clients.send(*it, 0, &pkt, true);
2158 compat_psound.clients.insert(*it);
2160 m_clients.send(*it, 0, &compat_pkt, true);
2161 psound.clients.erase(it++);
2165 // Remove sound reference
2166 if (!play_sound || psound.clients.empty())
2167 m_playing_sounds.erase(i);
2169 if (play_sound && !compat_psound.clients.empty()) {
2170 // Play new sound volume on older clients
2171 playSound(compat_psound.spec, compat_psound.params);
2175 void Server::sendRemoveNode(v3s16 p, std::unordered_set<u16> *far_players,
2178 float maxd = far_d_nodes * BS;
2179 v3f p_f = intToFloat(p, BS);
2180 v3s16 block_pos = getNodeBlockPos(p);
2182 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2185 std::vector<session_t> clients = m_clients.getClientIDs();
2188 for (session_t client_id : clients) {
2189 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
2193 RemotePlayer *player = m_env->getPlayer(client_id);
2194 PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr;
2196 // If player is far away, only set modified blocks not sent
2197 if (!client->isBlockSent(block_pos) || (sao &&
2198 sao->getBasePosition().getDistanceFrom(p_f) > maxd)) {
2200 far_players->emplace(client_id);
2202 client->SetBlockNotSent(block_pos);
2207 m_clients.send(client_id, 0, &pkt, true);
2213 void Server::sendAddNode(v3s16 p, MapNode n, std::unordered_set<u16> *far_players,
2214 float far_d_nodes, bool remove_metadata)
2216 float maxd = far_d_nodes * BS;
2217 v3f p_f = intToFloat(p, BS);
2218 v3s16 block_pos = getNodeBlockPos(p);
2220 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2221 pkt << p << n.param0 << n.param1 << n.param2
2222 << (u8) (remove_metadata ? 0 : 1);
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::sendMetadataChanged(const std::list<v3s16> &meta_updates, float far_d_nodes)
2254 float maxd = far_d_nodes * BS;
2255 NodeMetadataList meta_updates_list(false);
2256 std::vector<session_t> clients = m_clients.getClientIDs();
2260 for (session_t i : clients) {
2261 RemoteClient *client = m_clients.lockedGetClientNoEx(i);
2265 ServerActiveObject *player = m_env->getActiveObject(i);
2266 v3f player_pos = player ? player->getBasePosition() : v3f();
2268 for (const v3s16 &pos : meta_updates) {
2269 NodeMetadata *meta = m_env->getMap().getNodeMetadata(pos);
2274 v3s16 block_pos = getNodeBlockPos(pos);
2275 if (!client->isBlockSent(block_pos) || (player &&
2276 player_pos.getDistanceFrom(intToFloat(pos, BS)) > maxd)) {
2277 client->SetBlockNotSent(block_pos);
2281 // Add the change to send list
2282 meta_updates_list.set(pos, meta);
2284 if (meta_updates_list.size() == 0)
2287 // Send the meta changes
2288 std::ostringstream os(std::ios::binary);
2289 meta_updates_list.serialize(os, client->net_proto_version, false, true);
2290 std::ostringstream oss(std::ios::binary);
2291 compressZlib(os.str(), oss);
2293 NetworkPacket pkt(TOCLIENT_NODEMETA_CHANGED, 0);
2294 pkt.putLongString(oss.str());
2295 m_clients.send(i, 0, &pkt, true);
2297 meta_updates_list.clear();
2303 void Server::SendBlockNoLock(session_t peer_id, MapBlock *block, u8 ver,
2304 u16 net_proto_version)
2307 Create a packet with the block in the right format
2310 std::ostringstream os(std::ios_base::binary);
2311 block->serialize(os, ver, false);
2312 block->serializeNetworkSpecific(os);
2313 std::string s = os.str();
2315 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2317 pkt << block->getPos();
2318 pkt.putRawString(s.c_str(), s.size());
2322 void Server::SendBlocks(float dtime)
2324 MutexAutoLock envlock(m_env_mutex);
2325 //TODO check if one big lock could be faster then multiple small ones
2327 std::vector<PrioritySortedBlockTransfer> queue;
2329 u32 total_sending = 0;
2332 ScopeProfiler sp2(g_profiler, "Server::SendBlocks(): Collect list");
2334 std::vector<session_t> clients = m_clients.getClientIDs();
2337 for (const session_t client_id : clients) {
2338 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id, CS_Active);
2343 total_sending += client->getSendingCount();
2344 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2350 // Lowest priority number comes first.
2351 // Lowest is most important.
2352 std::sort(queue.begin(), queue.end());
2356 // Maximal total count calculation
2357 // The per-client block sends is halved with the maximal online users
2358 u32 max_blocks_to_send = (m_env->getPlayerCount() + g_settings->getU32("max_users")) *
2359 g_settings->getU32("max_simultaneous_block_sends_per_client") / 4 + 1;
2361 ScopeProfiler sp(g_profiler, "Server::SendBlocks(): Send to clients");
2362 Map &map = m_env->getMap();
2364 for (const PrioritySortedBlockTransfer &block_to_send : queue) {
2365 if (total_sending >= max_blocks_to_send)
2368 MapBlock *block = map.getBlockNoCreateNoEx(block_to_send.pos);
2372 RemoteClient *client = m_clients.lockedGetClientNoEx(block_to_send.peer_id,
2377 SendBlockNoLock(block_to_send.peer_id, block, client->serialization_version,
2378 client->net_proto_version);
2380 client->SentBlock(block_to_send.pos);
2386 bool Server::SendBlock(session_t peer_id, const v3s16 &blockpos)
2388 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2393 RemoteClient *client = m_clients.lockedGetClientNoEx(peer_id, CS_Active);
2394 if (!client || client->isBlockSent(blockpos)) {
2398 SendBlockNoLock(peer_id, block, client->serialization_version,
2399 client->net_proto_version);
2405 void Server::fillMediaCache()
2407 infostream<<"Server: Calculating media file checksums"<<std::endl;
2409 // Collect all media file paths
2410 std::vector<std::string> paths;
2411 m_modmgr->getModsMediaPaths(paths);
2412 fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures");
2413 fs::GetRecursiveDirs(paths, porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2415 // Collect media file information from paths into cache
2416 for (const std::string &mediapath : paths) {
2417 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2418 for (const fs::DirListNode &dln : dirlist) {
2419 if (dln.dir) // Ignode dirs
2421 std::string filename = dln.name;
2422 // If name contains illegal characters, ignore the file
2423 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2424 infostream<<"Server: ignoring illegal file name: \""
2425 << filename << "\"" << std::endl;
2428 // If name is not in a supported format, ignore it
2429 const char *supported_ext[] = {
2430 ".png", ".jpg", ".bmp", ".tga",
2431 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2433 ".x", ".b3d", ".md2", ".obj",
2434 // Custom translation file format
2438 if (removeStringEnd(filename, supported_ext).empty()){
2439 infostream << "Server: ignoring unsupported file extension: \""
2440 << filename << "\"" << std::endl;
2443 // Ok, attempt to load the file and add to cache
2444 std::string filepath;
2445 filepath.append(mediapath).append(DIR_DELIM).append(filename);
2448 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2450 errorstream << "Server::fillMediaCache(): Could not open \""
2451 << filename << "\" for reading" << std::endl;
2454 std::ostringstream tmp_os(std::ios_base::binary);
2458 fis.read(buf, 1024);
2459 std::streamsize len = fis.gcount();
2460 tmp_os.write(buf, len);
2469 errorstream<<"Server::fillMediaCache(): Failed to read \""
2470 << filename << "\"" << std::endl;
2473 if(tmp_os.str().length() == 0) {
2474 errorstream << "Server::fillMediaCache(): Empty file \""
2475 << filepath << "\"" << std::endl;
2480 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2482 unsigned char *digest = sha1.getDigest();
2483 std::string sha1_base64 = base64_encode(digest, 20);
2484 std::string sha1_hex = hex_encode((char*)digest, 20);
2488 m_media[filename] = MediaInfo(filepath, sha1_base64);
2489 verbosestream << "Server: " << sha1_hex << " is " << filename
2495 void Server::sendMediaAnnouncement(session_t peer_id, const std::string &lang_code)
2497 verbosestream << "Server: Announcing files to id(" << peer_id << ")"
2501 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2504 std::string lang_suffix;
2505 lang_suffix.append(".").append(lang_code).append(".tr");
2506 for (const auto &i : m_media) {
2507 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2514 for (const auto &i : m_media) {
2515 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2517 pkt << i.first << i.second.sha1_digest;
2520 pkt << g_settings->get("remote_media");
2524 struct SendableMedia
2530 SendableMedia(const std::string &name_="", const std::string &path_="",
2531 const std::string &data_=""):
2538 void Server::sendRequestedMedia(session_t peer_id,
2539 const std::vector<std::string> &tosend)
2541 verbosestream<<"Server::sendRequestedMedia(): "
2542 <<"Sending files to client"<<std::endl;
2546 // Put 5kB in one bunch (this is not accurate)
2547 u32 bytes_per_bunch = 5000;
2549 std::vector< std::vector<SendableMedia> > file_bunches;
2550 file_bunches.emplace_back();
2552 u32 file_size_bunch_total = 0;
2554 for (const std::string &name : tosend) {
2555 if (m_media.find(name) == m_media.end()) {
2556 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2557 <<"unknown file \""<<(name)<<"\""<<std::endl;
2561 //TODO get path + name
2562 std::string tpath = m_media[name].path;
2565 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2567 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2568 <<tpath<<"\" for reading"<<std::endl;
2571 std::ostringstream tmp_os(std::ios_base::binary);
2575 fis.read(buf, 1024);
2576 std::streamsize len = fis.gcount();
2577 tmp_os.write(buf, len);
2578 file_size_bunch_total += len;
2587 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2588 <<name<<"\""<<std::endl;
2591 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2592 <<tname<<"\""<<std::endl;*/
2594 file_bunches[file_bunches.size()-1].emplace_back(name, tpath, tmp_os.str());
2596 // Start next bunch if got enough data
2597 if(file_size_bunch_total >= bytes_per_bunch) {
2598 file_bunches.emplace_back();
2599 file_size_bunch_total = 0;
2604 /* Create and send packets */
2606 u16 num_bunches = file_bunches.size();
2607 for (u16 i = 0; i < num_bunches; i++) {
2610 u16 total number of texture bunches
2611 u16 index of this bunch
2612 u32 number of files in this bunch
2621 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2622 pkt << num_bunches << i << (u32) file_bunches[i].size();
2624 for (const SendableMedia &j : file_bunches[i]) {
2626 pkt.putLongString(j.data);
2629 verbosestream << "Server::sendRequestedMedia(): bunch "
2630 << i << "/" << num_bunches
2631 << " files=" << file_bunches[i].size()
2632 << " size=" << pkt.getSize() << std::endl;
2637 void Server::sendDetachedInventory(const std::string &name, session_t peer_id)
2639 const auto &inv_it = m_detached_inventories.find(name);
2640 const auto &player_it = m_detached_inventories_player.find(name);
2642 if (player_it == m_detached_inventories_player.end() ||
2643 player_it->second.empty()) {
2644 // OK. Send to everyone
2647 return; // Mods are not done loading
2649 RemotePlayer *p = m_env->getPlayer(player_it->second.c_str());
2651 return; // Player is offline
2653 if (peer_id != PEER_ID_INEXISTENT && peer_id != p->getPeerId())
2654 return; // Caller requested send to a different player, so don't send.
2656 peer_id = p->getPeerId();
2659 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2662 if (inv_it == m_detached_inventories.end()) {
2663 pkt << false; // Remove inventory
2665 pkt << true; // Update inventory
2667 // Serialization & NetworkPacket isn't a love story
2668 std::ostringstream os(std::ios_base::binary);
2669 inv_it->second->serialize(os);
2670 inv_it->second->setModified(false);
2672 const std::string &os_str = os.str();
2673 pkt << static_cast<u16>(os_str.size()); // HACK: to keep compatibility with 5.0.0 clients
2674 pkt.putRawString(os_str);
2677 if (peer_id == PEER_ID_INEXISTENT)
2678 m_clients.sendToAll(&pkt);
2683 void Server::sendDetachedInventories(session_t peer_id, bool incremental)
2685 for (const auto &detached_inventory : m_detached_inventories) {
2686 const std::string &name = detached_inventory.first;
2688 Inventory *inv = detached_inventory.second;
2689 if (!inv || !inv->checkModified())
2693 sendDetachedInventory(name, peer_id);
2701 void Server::DiePlayer(session_t peer_id, const PlayerHPChangeReason &reason)
2703 PlayerSAO *playersao = getPlayerSAO(peer_id);
2704 // In some rare cases this can be NULL -- if the player is disconnected
2705 // when a Lua function modifies l_punch, for example
2709 infostream << "Server::DiePlayer(): Player "
2710 << playersao->getPlayer()->getName()
2711 << " dies" << std::endl;
2713 playersao->setHP(0, reason);
2714 playersao->clearParentAttachment();
2716 // Trigger scripted stuff
2717 m_script->on_dieplayer(playersao, reason);
2719 SendPlayerHP(peer_id);
2720 SendDeathscreen(peer_id, false, v3f(0,0,0));
2723 void Server::RespawnPlayer(session_t peer_id)
2725 PlayerSAO *playersao = getPlayerSAO(peer_id);
2728 infostream << "Server::RespawnPlayer(): Player "
2729 << playersao->getPlayer()->getName()
2730 << " respawns" << std::endl;
2732 playersao->setHP(playersao->accessObjectProperties()->hp_max,
2733 PlayerHPChangeReason(PlayerHPChangeReason::RESPAWN));
2734 playersao->setBreath(playersao->accessObjectProperties()->breath_max);
2736 bool repositioned = m_script->on_respawnplayer(playersao);
2737 if (!repositioned) {
2738 // setPos will send the new position to client
2739 playersao->setPos(findSpawnPos());
2742 SendPlayerHP(peer_id);
2746 void Server::DenySudoAccess(session_t peer_id)
2748 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2753 void Server::DenyAccessVerCompliant(session_t peer_id, u16 proto_ver, AccessDeniedCode reason,
2754 const std::string &str_reason, bool reconnect)
2756 SendAccessDenied(peer_id, reason, str_reason, reconnect);
2758 m_clients.event(peer_id, CSE_SetDenied);
2759 DisconnectPeer(peer_id);
2763 void Server::DenyAccess(session_t peer_id, AccessDeniedCode reason,
2764 const std::string &custom_reason)
2766 SendAccessDenied(peer_id, reason, custom_reason);
2767 m_clients.event(peer_id, CSE_SetDenied);
2768 DisconnectPeer(peer_id);
2771 // 13/03/15: remove this function when protocol version 25 will become
2772 // the minimum version for MT users, maybe in 1 year
2773 void Server::DenyAccess_Legacy(session_t peer_id, const std::wstring &reason)
2775 SendAccessDenied_Legacy(peer_id, reason);
2776 m_clients.event(peer_id, CSE_SetDenied);
2777 DisconnectPeer(peer_id);
2780 void Server::DisconnectPeer(session_t peer_id)
2782 m_modchannel_mgr->leaveAllChannels(peer_id);
2783 m_con->DisconnectPeer(peer_id);
2786 void Server::acceptAuth(session_t peer_id, bool forSudoMode)
2789 RemoteClient* client = getClient(peer_id, CS_Invalid);
2791 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2793 // Right now, the auth mechs don't change between login and sudo mode.
2794 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2795 client->allowed_sudo_mechs = sudo_auth_mechs;
2797 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2798 << g_settings->getFloat("dedicated_server_step")
2802 m_clients.event(peer_id, CSE_AuthAccept);
2804 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2806 // We only support SRP right now
2807 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2809 resp_pkt << sudo_auth_mechs;
2811 m_clients.event(peer_id, CSE_SudoSuccess);
2815 void Server::DeleteClient(session_t peer_id, ClientDeletionReason reason)
2817 std::wstring message;
2820 Clear references to playing sounds
2822 for (std::unordered_map<s32, ServerPlayingSound>::iterator
2823 i = m_playing_sounds.begin(); i != m_playing_sounds.end();) {
2824 ServerPlayingSound &psound = i->second;
2825 psound.clients.erase(peer_id);
2826 if (psound.clients.empty())
2827 m_playing_sounds.erase(i++);
2832 // clear formspec info so the next client can't abuse the current state
2833 m_formspec_state_data.erase(peer_id);
2835 RemotePlayer *player = m_env->getPlayer(peer_id);
2837 /* Run scripts and remove from environment */
2839 PlayerSAO *playersao = player->getPlayerSAO();
2842 playersao->clearChildAttachments();
2843 playersao->clearParentAttachment();
2845 // inform connected clients
2846 const std::string &player_name = player->getName();
2847 NetworkPacket notice(TOCLIENT_UPDATE_PLAYER_LIST, 0, PEER_ID_INEXISTENT);
2848 // (u16) 1 + std::string represents a vector serialization representation
2849 notice << (u8) PLAYER_LIST_REMOVE << (u16) 1 << player_name;
2850 m_clients.sendToAll(¬ice);
2852 m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
2854 playersao->disconnected();
2861 if (player && reason != CDR_DENY) {
2862 std::ostringstream os(std::ios_base::binary);
2863 std::vector<session_t> clients = m_clients.getClientIDs();
2865 for (const session_t client_id : clients) {
2867 RemotePlayer *player = m_env->getPlayer(client_id);
2871 // Get name of player
2872 os << player->getName() << " ";
2875 std::string name = player->getName();
2876 actionstream << name << " "
2877 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2878 << " List of players: " << os.str() << std::endl;
2880 m_admin_chat->outgoing_queue.push_back(
2881 new ChatEventNick(CET_NICK_REMOVE, name));
2885 MutexAutoLock env_lock(m_env_mutex);
2886 m_clients.DeleteClient(peer_id);
2890 // Send leave chat message to all remaining clients
2891 if (!message.empty()) {
2892 SendChatMessage(PEER_ID_INEXISTENT,
2893 ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE, message));
2897 void Server::UpdateCrafting(RemotePlayer *player)
2899 InventoryList *clist = player->inventory.getList("craft");
2900 if (!clist || clist->getSize() == 0)
2903 if (!clist->checkModified()) {
2904 verbosestream << "Skip Server::UpdateCrafting(): list unmodified" << std::endl;
2908 // Get a preview for crafting
2910 InventoryLocation loc;
2911 loc.setPlayer(player->getName());
2912 std::vector<ItemStack> output_replacements;
2913 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2914 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(),
2917 InventoryList *plist = player->inventory.getList("craftpreview");
2918 if (plist && plist->getSize() >= 1) {
2919 // Put the new preview in
2920 plist->changeItem(0, preview);
2924 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2926 if (evt->type == CET_NICK_ADD) {
2927 // The terminal informed us of its nick choice
2928 m_admin_nick = ((ChatEventNick *)evt)->nick;
2929 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2930 errorstream << "You haven't set up an account." << std::endl
2931 << "Please log in using the client as '"
2932 << m_admin_nick << "' with a secure password." << std::endl
2933 << "Until then, you can't execute admin tasks via the console," << std::endl
2934 << "and everybody can claim the user account instead of you," << std::endl
2935 << "giving them full control over this server." << std::endl;
2938 assert(evt->type == CET_CHAT);
2939 handleAdminChat((ChatEventChat *)evt);
2943 std::wstring Server::handleChat(const std::string &name, const std::wstring &wname,
2944 std::wstring wmessage, bool check_shout_priv, RemotePlayer *player)
2946 // If something goes wrong, this player is to blame
2947 RollbackScopeActor rollback_scope(m_rollback,
2948 std::string("player:") + name);
2950 if (g_settings->getBool("strip_color_codes"))
2951 wmessage = unescape_enriched(wmessage);
2954 switch (player->canSendChatMessage()) {
2955 case RPLAYER_CHATRESULT_FLOODING: {
2956 std::wstringstream ws;
2957 ws << L"You cannot send more messages. You are limited to "
2958 << g_settings->getFloat("chat_message_limit_per_10sec")
2959 << L" messages per 10 seconds.";
2962 case RPLAYER_CHATRESULT_KICK:
2963 DenyAccess_Legacy(player->getPeerId(),
2964 L"You have been kicked due to message flooding.");
2966 case RPLAYER_CHATRESULT_OK:
2969 FATAL_ERROR("Unhandled chat filtering result found.");
2973 if (m_max_chatmessage_length > 0
2974 && wmessage.length() > m_max_chatmessage_length) {
2975 return L"Your message exceed the maximum chat message limit set on the server. "
2976 L"It was refused. Send a shorter message";
2979 auto message = trim(wide_to_utf8(wmessage));
2980 if (message.find_first_of("\n\r") != std::wstring::npos) {
2981 return L"New lines are not permitted in chat messages";
2984 // Run script hook, exit if script ate the chat message
2985 if (m_script->on_chat_message(name, message))
2990 // Whether to send line to the player that sent the message, or to all players
2991 bool broadcast_line = true;
2993 if (check_shout_priv && !checkPriv(name, "shout")) {
2994 line += L"-!- You don't have permission to shout.";
2995 broadcast_line = false;
2997 line += narrow_to_wide(m_script->formatChatMessage(name,
2998 wide_to_narrow(wmessage)));
3002 Tell calling method to send the message to sender
3004 if (!broadcast_line)
3008 Send the message to others
3010 actionstream << "CHAT: " << wide_to_narrow(unescape_enriched(line)) << std::endl;
3012 std::vector<session_t> clients = m_clients.getClientIDs();
3015 Send the message back to the inital sender
3016 if they are using protocol version >= 29
3019 session_t peer_id_to_avoid_sending =
3020 (player ? player->getPeerId() : PEER_ID_INEXISTENT);
3022 if (player && player->protocol_version >= 29)
3023 peer_id_to_avoid_sending = PEER_ID_INEXISTENT;
3025 for (u16 cid : clients) {
3026 if (cid != peer_id_to_avoid_sending)
3027 SendChatMessage(cid, ChatMessage(line));
3032 void Server::handleAdminChat(const ChatEventChat *evt)
3034 std::string name = evt->nick;
3035 std::wstring wname = utf8_to_wide(name);
3036 std::wstring wmessage = evt->evt_msg;
3038 std::wstring answer = handleChat(name, wname, wmessage);
3040 // If asked to send answer to sender
3041 if (!answer.empty()) {
3042 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
3046 RemoteClient *Server::getClient(session_t peer_id, ClientState state_min)
3048 RemoteClient *client = getClientNoEx(peer_id,state_min);
3050 throw ClientNotFoundException("Client not found");
3054 RemoteClient *Server::getClientNoEx(session_t peer_id, ClientState state_min)
3056 return m_clients.getClientNoEx(peer_id, state_min);
3059 std::string Server::getPlayerName(session_t peer_id)
3061 RemotePlayer *player = m_env->getPlayer(peer_id);
3063 return "[id="+itos(peer_id)+"]";
3064 return player->getName();
3067 PlayerSAO *Server::getPlayerSAO(session_t peer_id)
3069 RemotePlayer *player = m_env->getPlayer(peer_id);
3072 return player->getPlayerSAO();
3075 std::wstring Server::getStatusString()
3077 std::wostringstream os(std::ios_base::binary);
3078 os << L"# Server: ";
3080 os << L"version=" << narrow_to_wide(g_version_string);
3082 os << L", uptime=" << m_uptime.get();
3084 os << L", max_lag=" << (m_env ? m_env->getMaxLagEstimate() : 0);
3086 // Information about clients
3088 os << L", clients={";
3090 std::vector<session_t> clients = m_clients.getClientIDs();
3091 for (session_t client_id : clients) {
3092 RemotePlayer *player = m_env->getPlayer(client_id);
3094 // Get name of player
3095 std::wstring name = L"unknown";
3097 name = narrow_to_wide(player->getName());
3099 // Add name to information string
3110 if (m_env && !((ServerMap*)(&m_env->getMap()))->isSavingEnabled())
3111 os << std::endl << L"# Server: " << " WARNING: Map saving is disabled.";
3113 if (!g_settings->get("motd").empty())
3114 os << std::endl << L"# Server: " << narrow_to_wide(g_settings->get("motd"));
3119 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
3121 std::set<std::string> privs;
3122 m_script->getAuth(name, NULL, &privs);
3126 bool Server::checkPriv(const std::string &name, const std::string &priv)
3128 std::set<std::string> privs = getPlayerEffectivePrivs(name);
3129 return (privs.count(priv) != 0);
3132 void Server::reportPrivsModified(const std::string &name)
3135 std::vector<session_t> clients = m_clients.getClientIDs();
3136 for (const session_t client_id : clients) {
3137 RemotePlayer *player = m_env->getPlayer(client_id);
3138 reportPrivsModified(player->getName());
3141 RemotePlayer *player = m_env->getPlayer(name.c_str());
3144 SendPlayerPrivileges(player->getPeerId());
3145 PlayerSAO *sao = player->getPlayerSAO();
3148 sao->updatePrivileges(
3149 getPlayerEffectivePrivs(name),
3154 void Server::reportInventoryFormspecModified(const std::string &name)
3156 RemotePlayer *player = m_env->getPlayer(name.c_str());
3159 SendPlayerInventoryFormspec(player->getPeerId());
3162 void Server::reportFormspecPrependModified(const std::string &name)
3164 RemotePlayer *player = m_env->getPlayer(name.c_str());
3167 SendPlayerFormspecPrepend(player->getPeerId());
3170 void Server::setIpBanned(const std::string &ip, const std::string &name)
3172 m_banmanager->add(ip, name);
3175 void Server::unsetIpBanned(const std::string &ip_or_name)
3177 m_banmanager->remove(ip_or_name);
3180 std::string Server::getBanDescription(const std::string &ip_or_name)
3182 return m_banmanager->getBanDescription(ip_or_name);
3185 void Server::notifyPlayer(const char *name, const std::wstring &msg)
3187 // m_env will be NULL if the server is initializing
3191 if (m_admin_nick == name && !m_admin_nick.empty()) {
3192 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
3195 RemotePlayer *player = m_env->getPlayer(name);
3200 if (player->getPeerId() == PEER_ID_INEXISTENT)
3203 SendChatMessage(player->getPeerId(), ChatMessage(msg));
3206 bool Server::showFormspec(const char *playername, const std::string &formspec,
3207 const std::string &formname)
3209 // m_env will be NULL if the server is initializing
3213 RemotePlayer *player = m_env->getPlayer(playername);
3217 SendShowFormspecMessage(player->getPeerId(), formspec, formname);
3221 u32 Server::hudAdd(RemotePlayer *player, HudElement *form)
3226 u32 id = player->addHud(form);
3228 SendHUDAdd(player->getPeerId(), id, form);
3233 bool Server::hudRemove(RemotePlayer *player, u32 id) {
3237 HudElement* todel = player->removeHud(id);
3244 SendHUDRemove(player->getPeerId(), id);
3248 bool Server::hudChange(RemotePlayer *player, u32 id, HudElementStat stat, void *data)
3253 SendHUDChange(player->getPeerId(), id, stat, data);
3257 bool Server::hudSetFlags(RemotePlayer *player, u32 flags, u32 mask)
3262 SendHUDSetFlags(player->getPeerId(), flags, mask);
3263 player->hud_flags &= ~mask;
3264 player->hud_flags |= flags;
3266 PlayerSAO* playersao = player->getPlayerSAO();
3271 m_script->player_event(playersao, "hud_changed");
3275 bool Server::hudSetHotbarItemcount(RemotePlayer *player, s32 hotbar_itemcount)
3280 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3283 player->setHotbarItemcount(hotbar_itemcount);
3284 std::ostringstream os(std::ios::binary);
3285 writeS32(os, hotbar_itemcount);
3286 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3290 void Server::hudSetHotbarImage(RemotePlayer *player, const std::string &name)
3295 player->setHotbarImage(name);
3296 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_IMAGE, name);
3299 void Server::hudSetHotbarSelectedImage(RemotePlayer *player, const std::string &name)
3304 player->setHotbarSelectedImage(name);
3305 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3308 Address Server::getPeerAddress(session_t peer_id)
3310 return m_con->GetPeerAddress(peer_id);
3313 void Server::setLocalPlayerAnimations(RemotePlayer *player,
3314 v2s32 animation_frames[4], f32 frame_speed)
3316 sanity_check(player);
3317 player->setLocalAnimations(animation_frames, frame_speed);
3318 SendLocalPlayerAnimations(player->getPeerId(), animation_frames, frame_speed);
3321 void Server::setPlayerEyeOffset(RemotePlayer *player, const v3f &first, const v3f &third)
3323 sanity_check(player);
3324 player->eye_offset_first = first;
3325 player->eye_offset_third = third;
3326 SendEyeOffset(player->getPeerId(), first, third);
3329 void Server::setSky(RemotePlayer *player, const video::SColor &bgcolor,
3330 const std::string &type, const std::vector<std::string> ¶ms,
3333 sanity_check(player);
3334 player->setSky(bgcolor, type, params, clouds);
3335 SendSetSky(player->getPeerId(), bgcolor, type, params, clouds);
3338 void Server::setClouds(RemotePlayer *player, const CloudParams ¶ms)
3340 sanity_check(player);
3341 player->setCloudParams(params);
3342 SendCloudParams(player->getPeerId(), params);
3345 bool Server::overrideDayNightRatio(RemotePlayer *player, bool do_override,
3351 player->overrideDayNightRatio(do_override, ratio);
3352 SendOverrideDayNightRatio(player->getPeerId(), do_override, ratio);
3356 void Server::notifyPlayers(const std::wstring &msg)
3358 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(msg));
3361 void Server::spawnParticle(const std::string &playername, v3f pos,
3362 v3f velocity, v3f acceleration,
3363 float expirationtime, float size, bool
3364 collisiondetection, bool collision_removal, bool object_collision,
3365 bool vertical, const std::string &texture,
3366 const struct TileAnimationParams &animation, u8 glow)
3368 // m_env will be NULL if the server is initializing
3372 session_t peer_id = PEER_ID_INEXISTENT;
3374 if (!playername.empty()) {
3375 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3378 peer_id = player->getPeerId();
3379 proto_ver = player->protocol_version;
3382 SendSpawnParticle(peer_id, proto_ver, pos, velocity, acceleration,
3383 expirationtime, size, collisiondetection, collision_removal,
3384 object_collision, vertical, texture, animation, glow);
3387 u32 Server::addParticleSpawner(u16 amount, float spawntime,
3388 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
3389 float minexptime, float maxexptime, float minsize, float maxsize,
3390 bool collisiondetection, bool collision_removal, bool object_collision,
3391 ServerActiveObject *attached, bool vertical, const std::string &texture,
3392 const std::string &playername, const struct TileAnimationParams &animation,
3395 // m_env will be NULL if the server is initializing
3399 session_t peer_id = PEER_ID_INEXISTENT;
3401 if (!playername.empty()) {
3402 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3405 peer_id = player->getPeerId();
3406 proto_ver = player->protocol_version;
3409 u16 attached_id = attached ? attached->getId() : 0;
3412 if (attached_id == 0)
3413 id = m_env->addParticleSpawner(spawntime);
3415 id = m_env->addParticleSpawner(spawntime, attached_id);
3417 SendAddParticleSpawner(peer_id, proto_ver, amount, spawntime,
3418 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3419 minexptime, maxexptime, minsize, maxsize, collisiondetection,
3420 collision_removal, object_collision, attached_id, vertical,
3421 texture, id, animation, glow);
3426 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3428 // m_env will be NULL if the server is initializing
3430 throw ServerError("Can't delete particle spawners during initialisation!");
3432 session_t peer_id = PEER_ID_INEXISTENT;
3433 if (!playername.empty()) {
3434 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3437 peer_id = player->getPeerId();
3440 m_env->deleteParticleSpawner(id);
3441 SendDeleteParticleSpawner(peer_id, id);
3444 Inventory* Server::createDetachedInventory(const std::string &name, const std::string &player)
3446 if(m_detached_inventories.count(name) > 0){
3447 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3448 delete m_detached_inventories[name];
3450 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3452 Inventory *inv = new Inventory(m_itemdef);
3454 m_detached_inventories[name] = inv;
3455 if (!player.empty())
3456 m_detached_inventories_player[name] = player;
3458 //TODO find a better way to do this
3459 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3463 bool Server::removeDetachedInventory(const std::string &name)
3465 const auto &inv_it = m_detached_inventories.find(name);
3466 if (inv_it == m_detached_inventories.end())
3469 delete inv_it->second;
3470 m_detached_inventories.erase(inv_it);
3472 if (!m_env) // Mods are not done loading
3475 const auto &player_it = m_detached_inventories_player.find(name);
3476 if (player_it != m_detached_inventories_player.end()) {
3477 RemotePlayer *player = m_env->getPlayer(player_it->second.c_str());
3479 if (player && player->getPeerId() != PEER_ID_INEXISTENT)
3480 sendDetachedInventory(name, player->getPeerId());
3482 m_detached_inventories_player.erase(player_it);
3484 // Notify all players about the change
3485 sendDetachedInventory(name, PEER_ID_INEXISTENT);
3490 // actions: time-reversed list
3491 // Return value: success/failure
3492 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3493 std::list<std::string> *log)
3495 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3496 ServerMap *map = (ServerMap*)(&m_env->getMap());
3498 // Fail if no actions to handle
3499 if (actions.empty()) {
3501 log->push_back("Nothing to do.");
3508 for (const RollbackAction &action : actions) {
3510 bool success = action.applyRevert(map, this, this);
3513 std::ostringstream os;
3514 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3515 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3517 log->push_back(os.str());
3519 std::ostringstream os;
3520 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3521 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3523 log->push_back(os.str());
3527 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3528 <<" failed"<<std::endl;
3530 // Call it done if less than half failed
3531 return num_failed <= num_tried/2;
3534 // IGameDef interface
3536 IItemDefManager *Server::getItemDefManager()
3541 const NodeDefManager *Server::getNodeDefManager()
3546 ICraftDefManager *Server::getCraftDefManager()
3551 u16 Server::allocateUnknownNodeId(const std::string &name)
3553 return m_nodedef->allocateDummy(name);
3556 IWritableItemDefManager *Server::getWritableItemDefManager()
3561 NodeDefManager *Server::getWritableNodeDefManager()
3566 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3571 const std::vector<ModSpec> & Server::getMods() const
3573 return m_modmgr->getMods();
3576 const ModSpec *Server::getModSpec(const std::string &modname) const
3578 return m_modmgr->getModSpec(modname);
3581 void Server::getModNames(std::vector<std::string> &modlist)
3583 m_modmgr->getModNames(modlist);
3586 std::string Server::getBuiltinLuaPath()
3588 return porting::path_share + DIR_DELIM + "builtin";
3591 std::string Server::getModStoragePath() const
3593 return m_path_world + DIR_DELIM + "mod_storage";
3596 v3f Server::findSpawnPos()
3598 ServerMap &map = m_env->getServerMap();
3600 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf))
3601 return nodeposf * BS;
3603 bool is_good = false;
3604 // Limit spawn range to mapgen edges (determined by 'mapgen_limit')
3605 s32 range_max = map.getMapgenParams()->getSpawnRangeMax();
3607 // Try to find a good place a few times
3608 for (s32 i = 0; i < 4000 && !is_good; i++) {
3609 s32 range = MYMIN(1 + i, range_max);
3610 // We're going to try to throw the player to this position
3611 v2s16 nodepos2d = v2s16(
3612 -range + (myrand() % (range * 2)),
3613 -range + (myrand() % (range * 2)));
3614 // Get spawn level at point
3615 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3616 // Continue if MAX_MAP_GENERATION_LIMIT was returned by the mapgen to
3617 // signify an unsuitable spawn position, or if outside limits.
3618 if (spawn_level >= MAX_MAP_GENERATION_LIMIT ||
3619 spawn_level <= -MAX_MAP_GENERATION_LIMIT)
3622 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3623 // Consecutive empty nodes
3626 // Search upwards from 'spawn level' for 2 consecutive empty nodes, to
3627 // avoid obstructions in already-generated mapblocks.
3628 // In ungenerated mapblocks consisting of 'ignore' nodes, there will be
3629 // no obstructions, but mapgen decorations are generated after spawn so
3630 // the player may end up inside one.
3631 for (s32 i = 0; i < 8; i++) {
3632 v3s16 blockpos = getNodeBlockPos(nodepos);
3633 map.emergeBlock(blockpos, true);
3634 content_t c = map.getNode(nodepos).getContent();
3636 // In generated mapblocks allow spawn in all 'airlike' drawtype nodes.
3637 // In ungenerated mapblocks allow spawn in 'ignore' nodes.
3638 if (m_nodedef->get(c).drawtype == NDT_AIRLIKE || c == CONTENT_IGNORE) {
3640 if (air_count >= 2) {
3641 // Spawn in lower empty node
3643 nodeposf = intToFloat(nodepos, BS);
3644 // Don't spawn the player outside map boundaries
3645 if (objectpos_over_limit(nodeposf))
3646 // Exit this loop, positions above are probably over limit
3649 // Good position found, cause an exit from main loop
3663 // No suitable spawn point found, return fallback 0,0,0
3664 return v3f(0.0f, 0.0f, 0.0f);
3667 void Server::requestShutdown(const std::string &msg, bool reconnect, float delay)
3669 if (delay == 0.0f) {
3670 // No delay, shutdown immediately
3671 m_shutdown_state.is_requested = true;
3672 // only print to the infostream, a chat message saying
3673 // "Server Shutting Down" is sent when the server destructs.
3674 infostream << "*** Immediate Server shutdown requested." << std::endl;
3675 } else if (delay < 0.0f && m_shutdown_state.isTimerRunning()) {
3676 // Negative delay, cancel shutdown if requested
3677 m_shutdown_state.reset();
3678 std::wstringstream ws;
3680 ws << L"*** Server shutdown canceled.";
3682 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3683 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3684 // m_shutdown_* are already handled, skip.
3686 } else if (delay > 0.0f) {
3687 // Positive delay, tell the clients when the server will shut down
3688 std::wstringstream ws;
3690 ws << L"*** Server shutting down in "
3691 << duration_to_string(myround(delay)).c_str()
3694 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3695 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3698 m_shutdown_state.trigger(delay, msg, reconnect);
3701 PlayerSAO* Server::emergePlayer(const char *name, session_t peer_id, u16 proto_version)
3704 Try to get an existing player
3706 RemotePlayer *player = m_env->getPlayer(name);
3708 // If player is already connected, cancel
3709 if (player && player->getPeerId() != PEER_ID_INEXISTENT) {
3710 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3715 If player with the wanted peer_id already exists, cancel.
3717 if (m_env->getPlayer(peer_id)) {
3718 infostream<<"emergePlayer(): Player with wrong name but same"
3719 " peer_id already exists"<<std::endl;
3724 player = new RemotePlayer(name, idef());
3727 bool newplayer = false;
3730 PlayerSAO *playersao = m_env->loadPlayer(player, &newplayer, peer_id, isSingleplayer());
3732 // Complete init with server parts
3733 playersao->finalize(player, getPlayerEffectivePrivs(player->getName()));
3734 player->protocol_version = proto_version;
3738 m_script->on_newplayer(playersao);
3744 bool Server::registerModStorage(ModMetadata *storage)
3746 if (m_mod_storages.find(storage->getModName()) != m_mod_storages.end()) {
3747 errorstream << "Unable to register same mod storage twice. Storage name: "
3748 << storage->getModName() << std::endl;
3752 m_mod_storages[storage->getModName()] = storage;
3756 void Server::unregisterModStorage(const std::string &name)
3758 std::unordered_map<std::string, ModMetadata *>::const_iterator it = m_mod_storages.find(name);
3759 if (it != m_mod_storages.end()) {
3760 // Save unconditionaly on unregistration
3761 it->second->save(getModStoragePath());
3762 m_mod_storages.erase(name);
3766 void dedicated_server_loop(Server &server, bool &kill)
3768 verbosestream<<"dedicated_server_loop()"<<std::endl;
3770 IntervalLimiter m_profiler_interval;
3772 static thread_local const float steplen =
3773 g_settings->getFloat("dedicated_server_step");
3774 static thread_local const float profiler_print_interval =
3775 g_settings->getFloat("profiler_print_interval");
3778 * The dedicated server loop only does time-keeping (in Server::step) and
3779 * provides a way to main.cpp to kill the server externally (bool &kill).
3783 // This is kind of a hack but can be done like this
3784 // because server.step() is very light
3785 sleep_ms((int)(steplen*1000.0));
3786 server.step(steplen);
3788 if (server.isShutdownRequested() || kill)
3794 if (profiler_print_interval != 0) {
3795 if(m_profiler_interval.step(steplen, profiler_print_interval))
3797 infostream<<"Profiler:"<<std::endl;
3798 g_profiler->print(infostream);
3799 g_profiler->clear();
3804 infostream << "Dedicated server quitting" << std::endl;
3806 if (g_settings->getBool("server_announce"))
3807 ServerList::sendAnnounce(ServerList::AA_DELETE,
3808 server.m_bind_addr.getPort());
3817 bool Server::joinModChannel(const std::string &channel)
3819 return m_modchannel_mgr->joinChannel(channel, PEER_ID_SERVER) &&
3820 m_modchannel_mgr->setChannelState(channel, MODCHANNEL_STATE_READ_WRITE);
3823 bool Server::leaveModChannel(const std::string &channel)
3825 return m_modchannel_mgr->leaveChannel(channel, PEER_ID_SERVER);
3828 bool Server::sendModChannelMessage(const std::string &channel, const std::string &message)
3830 if (!m_modchannel_mgr->canWriteOnChannel(channel))
3833 broadcastModChannelMessage(channel, message, PEER_ID_SERVER);
3837 ModChannel* Server::getModChannel(const std::string &channel)
3839 return m_modchannel_mgr->getModChannel(channel);
3842 void Server::broadcastModChannelMessage(const std::string &channel,
3843 const std::string &message, session_t from_peer)
3845 const std::vector<u16> &peers = m_modchannel_mgr->getChannelPeers(channel);
3849 if (message.size() > STRING_MAX_LEN) {
3850 warningstream << "ModChannel message too long, dropping before sending "
3851 << " (" << message.size() << " > " << STRING_MAX_LEN << ", channel: "
3852 << channel << ")" << std::endl;
3857 if (from_peer != PEER_ID_SERVER) {
3858 sender = getPlayerName(from_peer);
3861 NetworkPacket resp_pkt(TOCLIENT_MODCHANNEL_MSG,
3862 2 + channel.size() + 2 + sender.size() + 2 + message.size());
3863 resp_pkt << channel << sender << message;
3864 for (session_t peer_id : peers) {
3866 if (peer_id == from_peer)
3869 Send(peer_id, &resp_pkt);
3872 if (from_peer != PEER_ID_SERVER) {
3873 m_script->on_modchannel_message(channel, sender, message);