3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include "network/connection.h"
25 #include "network/networkprotocol.h"
26 #include "network/serveropcodes.h"
28 #include "environment.h"
30 #include "threading/mutex_auto_lock.h"
31 #include "constants.h"
37 #include "serverobject.h"
38 #include "genericobject.h"
42 #include "scripting_server.h"
47 #include "mapgen/mapgen.h"
48 #include "mapgen/mg_biome.h"
49 #include "content_mapnode.h"
50 #include "content_nodemeta.h"
51 #include "content_sao.h"
52 #include "content/mods.h"
53 #include "modchannels.h"
54 #include "serverlist.h"
55 #include "util/string.h"
57 #include "util/serialize.h"
58 #include "util/thread.h"
59 #include "defaultsettings.h"
60 #include "server/mods.h"
61 #include "util/base64.h"
62 #include "util/sha1.h"
64 #include "database/database.h"
65 #include "chatmessage.h"
66 #include "chat_interface.h"
67 #include "remoteplayer.h"
69 class ClientNotFoundException : public BaseException
72 ClientNotFoundException(const char *s):
77 class ServerThread : public Thread
81 ServerThread(Server *server):
92 void *ServerThread::run()
94 BEGIN_DEBUG_EXCEPTION_HANDLER
96 m_server->AsyncRunStep(true);
98 while (!stopRequested()) {
100 m_server->AsyncRunStep();
104 } catch (con::NoIncomingDataException &e) {
105 } catch (con::PeerNotFoundException &e) {
106 infostream<<"Server: PeerNotFoundException"<<std::endl;
107 } catch (ClientNotFoundException &e) {
108 } catch (con::ConnectionBindFailed &e) {
109 m_server->setAsyncFatalError(e.what());
110 } catch (LuaError &e) {
111 m_server->setAsyncFatalError(
112 "ServerThread::run Lua: " + std::string(e.what()));
116 END_DEBUG_EXCEPTION_HANDLER
121 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
123 if(pos_exists) *pos_exists = false;
128 if(pos_exists) *pos_exists = true;
133 ServerActiveObject *sao = env->getActiveObject(object);
136 if(pos_exists) *pos_exists = true;
137 return sao->getBasePosition(); }
142 void Server::ShutdownState::reset()
146 should_reconnect = false;
147 is_requested = false;
150 void Server::ShutdownState::trigger(float delay, const std::string &msg, bool reconnect)
154 should_reconnect = reconnect;
157 void Server::ShutdownState::tick(float dtime, Server *server)
163 static const float shutdown_msg_times[] =
165 1, 2, 3, 4, 5, 10, 20, 40, 60, 120, 180, 300, 600, 1200, 1800, 3600
168 // Automated messages
169 if (m_timer < shutdown_msg_times[ARRLEN(shutdown_msg_times) - 1]) {
170 for (float t : shutdown_msg_times) {
171 // If shutdown timer matches an automessage, shot it
172 if (m_timer > t && m_timer - dtime < t) {
173 std::wstring periodicMsg = getShutdownTimerMessage();
175 infostream << wide_to_utf8(periodicMsg).c_str() << std::endl;
176 server->SendChatMessage(PEER_ID_INEXISTENT, periodicMsg);
183 if (m_timer < 0.0f) {
189 std::wstring Server::ShutdownState::getShutdownTimerMessage() const
191 std::wstringstream ws;
192 ws << L"*** Server shutting down in "
193 << duration_to_string(myround(m_timer)).c_str() << ".";
202 const std::string &path_world,
203 const SubgameSpec &gamespec,
204 bool simple_singleplayer_mode,
209 m_bind_addr(bind_addr),
210 m_path_world(path_world),
211 m_gamespec(gamespec),
212 m_simple_singleplayer_mode(simple_singleplayer_mode),
213 m_dedicated(dedicated),
214 m_async_fatal_error(""),
215 m_con(std::make_shared<con::Connection>(PROTOCOL_ID,
218 m_bind_addr.isIPv6(),
220 m_itemdef(createItemDefManager()),
221 m_nodedef(createNodeDefManager()),
222 m_craftdef(createCraftDefManager()),
223 m_thread(new ServerThread(this)),
227 m_modchannel_mgr(new ModChannelMgr())
229 m_lag = g_settings->getFloat("dedicated_server_step");
231 if (m_path_world.empty())
232 throw ServerError("Supplied empty world path");
234 if (!gamespec.isValid())
235 throw ServerError("Supplied invalid gamespec");
241 // Send shutdown message
242 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE,
243 L"*** Server shutting down"));
246 MutexAutoLock envlock(m_env_mutex);
248 infostream << "Server: Saving players" << std::endl;
249 m_env->saveLoadedPlayers();
251 infostream << "Server: Kicking players" << std::endl;
252 std::string kick_msg;
253 bool reconnect = false;
254 if (isShutdownRequested()) {
255 reconnect = m_shutdown_state.should_reconnect;
256 kick_msg = m_shutdown_state.message;
258 if (kick_msg.empty()) {
259 kick_msg = g_settings->get("kick_msg_shutdown");
261 m_env->saveLoadedPlayers(true);
262 m_env->kickAllPlayers(SERVER_ACCESSDENIED_SHUTDOWN,
263 kick_msg, reconnect);
266 actionstream << "Server: Shutting down" << std::endl;
268 // Do this before stopping the server in case mapgen callbacks need to access
269 // server-controlled resources (like ModStorages). Also do them before
270 // shutdown callbacks since they may modify state that is finalized in a
273 m_emerge->stopThreads();
276 MutexAutoLock envlock(m_env_mutex);
278 // Execute script shutdown hooks
279 infostream << "Executing shutdown hooks" << std::endl;
280 m_script->on_shutdown();
282 infostream << "Server: Saving environment metadata" << std::endl;
292 // Delete things in the reverse order of creation
301 // Deinitialize scripting
302 infostream << "Server: Deinitializing scripting" << std::endl;
305 // Delete detached inventories
306 for (auto &detached_inventory : m_detached_inventories) {
307 delete detached_inventory.second;
313 infostream << "Server created for gameid \"" << m_gamespec.id << "\"";
314 if (m_simple_singleplayer_mode)
315 infostream << " in simple singleplayer mode" << std::endl;
317 infostream << std::endl;
318 infostream << "- world: " << m_path_world << std::endl;
319 infostream << "- game: " << m_gamespec.path << std::endl;
321 // Create world if it doesn't exist
322 if (!loadGameConfAndInitWorld(m_path_world, m_gamespec))
323 throw ServerError("Failed to initialize world");
325 // Create emerge manager
326 m_emerge = new EmergeManager(this);
328 // Create ban manager
329 std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
330 m_banmanager = new BanManager(ban_path);
332 m_modmgr = std::unique_ptr<ServerModManager>(new ServerModManager(m_path_world));
333 std::vector<ModSpec> unsatisfied_mods = m_modmgr->getUnsatisfiedMods();
334 // complain about mods with unsatisfied dependencies
335 if (!m_modmgr->isConsistent()) {
336 m_modmgr->printUnsatisfiedModsError();
340 MutexAutoLock envlock(m_env_mutex);
342 // Create the Map (loads map_meta.txt, overriding configured mapgen params)
343 ServerMap *servermap = new ServerMap(m_path_world, this, m_emerge);
345 // Initialize scripting
346 infostream << "Server: Initializing Lua" << std::endl;
348 m_script = new ServerScripting(this);
350 m_script->loadMod(getBuiltinLuaPath() + DIR_DELIM "init.lua", BUILTIN_MOD_NAME);
352 m_modmgr->loadMods(m_script);
354 // Read Textures and calculate sha1 sums
357 // Apply item aliases in the node definition manager
358 m_nodedef->updateAliases(m_itemdef);
360 // Apply texture overrides from texturepack/override.txt
361 std::vector<std::string> paths;
362 fs::GetRecursiveDirs(paths, g_settings->get("texture_path"));
363 fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures");
364 for (const std::string &path : paths)
365 m_nodedef->applyTextureOverrides(path + DIR_DELIM + "override.txt");
367 m_nodedef->setNodeRegistrationStatus(true);
369 // Perform pending node name resolutions
370 m_nodedef->runNodeResolveCallbacks();
372 // unmap node names for connected nodeboxes
373 m_nodedef->mapNodeboxConnections();
375 // init the recipe hashes to speed up crafting
376 m_craftdef->initHashes(this);
378 // Initialize Environment
379 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
381 m_clients.setEnv(m_env);
383 if (!servermap->settings_mgr.makeMapgenParams())
384 FATAL_ERROR("Couldn't create any mapgen type");
386 // Initialize mapgens
387 m_emerge->initMapgens(servermap->getMapgenParams());
389 if (g_settings->getBool("enable_rollback_recording")) {
390 // Create rollback manager
391 m_rollback = new RollbackManager(m_path_world, this);
394 // Give environment reference to scripting api
395 m_script->initializeEnvironment(m_env);
397 // Register us to receive map edit events
398 servermap->addEventReceiver(this);
402 m_liquid_transform_every = g_settings->getFloat("liquid_update");
403 m_max_chatmessage_length = g_settings->getU16("chat_message_max_size");
404 m_csm_restriction_flags = g_settings->getU64("csm_restriction_flags");
405 m_csm_restriction_noderange = g_settings->getU32("csm_restriction_noderange");
410 infostream << "Starting server on " << m_bind_addr.serializeString()
411 << "..." << std::endl;
413 // Stop thread if already running
416 // Initialize connection
417 m_con->SetTimeoutMs(30);
418 m_con->Serve(m_bind_addr);
423 // ASCII art for the win!
425 << " .__ __ __ " << std::endl
426 << " _____ |__| ____ _____/ |_ ____ _______/ |_ " << std::endl
427 << " / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\" << std::endl
428 << "| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | " << std::endl
429 << "|__|_| /__|___| /\\___ >__| \\___ >____ > |__| " << std::endl
430 << " \\/ \\/ \\/ \\/ \\/ " << std::endl;
431 actionstream << "World at [" << m_path_world << "]" << std::endl;
432 actionstream << "Server for gameid=\"" << m_gamespec.id
433 << "\" listening on " << m_bind_addr.serializeString() << ":"
434 << m_bind_addr.getPort() << "." << std::endl;
439 infostream<<"Server: Stopping and waiting threads"<<std::endl;
441 // Stop threads (set run=false first so both start stopping)
443 //m_emergethread.setRun(false);
445 //m_emergethread.stop();
447 infostream<<"Server: Threads stopped"<<std::endl;
450 void Server::step(float dtime)
456 MutexAutoLock lock(m_step_dtime_mutex);
457 m_step_dtime += dtime;
459 // Throw if fatal error occurred in thread
460 std::string async_err = m_async_fatal_error.get();
461 if (!async_err.empty()) {
462 if (!m_simple_singleplayer_mode) {
463 m_env->kickAllPlayers(SERVER_ACCESSDENIED_CRASH,
464 g_settings->get("kick_msg_crash"),
465 g_settings->getBool("ask_reconnect_on_crash"));
467 throw ServerError("AsyncErr: " + async_err);
471 void Server::AsyncRunStep(bool initial_step)
476 MutexAutoLock lock1(m_step_dtime_mutex);
477 dtime = m_step_dtime;
481 // Send blocks to clients
485 if((dtime < 0.001) && !initial_step)
488 ScopeProfiler sp(g_profiler, "Server::AsyncRunStep()", SPT_AVG);
491 MutexAutoLock lock1(m_step_dtime_mutex);
492 m_step_dtime -= dtime;
499 m_uptime.set(m_uptime.get() + dtime);
505 Update time of day and overall game time
507 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
510 Send to clients at constant intervals
513 m_time_of_day_send_timer -= dtime;
514 if(m_time_of_day_send_timer < 0.0) {
515 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
516 u16 time = m_env->getTimeOfDay();
517 float time_speed = g_settings->getFloat("time_speed");
518 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
522 MutexAutoLock lock(m_env_mutex);
523 // Figure out and report maximum lag to environment
524 float max_lag = m_env->getMaxLagEstimate();
525 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
527 if(dtime > 0.1 && dtime > max_lag * 2.0)
528 infostream<<"Server: Maximum lag peaked to "<<dtime
532 m_env->reportMaxLagEstimate(max_lag);
537 static const float map_timer_and_unload_dtime = 2.92;
538 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
540 MutexAutoLock lock(m_env_mutex);
541 // Run Map's timers and unload unused data
542 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
543 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
544 g_settings->getFloat("server_unload_unused_data_timeout"),
549 Listen to the admin chat, if available
552 if (!m_admin_chat->command_queue.empty()) {
553 MutexAutoLock lock(m_env_mutex);
554 while (!m_admin_chat->command_queue.empty()) {
555 ChatEvent *evt = m_admin_chat->command_queue.pop_frontNoEx();
556 handleChatInterfaceEvent(evt);
560 m_admin_chat->outgoing_queue.push_back(
561 new ChatEventTimeInfo(m_env->getGameTime(), m_env->getTimeOfDay()));
568 /* Transform liquids */
569 m_liquid_transform_timer += dtime;
570 if(m_liquid_transform_timer >= m_liquid_transform_every)
572 m_liquid_transform_timer -= m_liquid_transform_every;
574 MutexAutoLock lock(m_env_mutex);
576 ScopeProfiler sp(g_profiler, "Server: liquid transform");
578 std::map<v3s16, MapBlock*> modified_blocks;
579 m_env->getMap().transformLiquids(modified_blocks, m_env);
582 Set the modified blocks unsent for all the clients
584 if (!modified_blocks.empty()) {
585 SetBlocksNotSent(modified_blocks);
588 m_clients.step(dtime);
590 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
592 // send masterserver announce
594 float &counter = m_masterserver_timer;
595 if (!isSingleplayer() && (!counter || counter >= 300.0) &&
596 g_settings->getBool("server_announce")) {
597 ServerList::sendAnnounce(counter ? ServerList::AA_UPDATE :
598 ServerList::AA_START,
599 m_bind_addr.getPort(),
600 m_clients.getPlayerNames(),
602 m_env->getGameTime(),
605 Mapgen::getMapgenName(m_emerge->mgparams->mgtype),
615 Check added and deleted active objects
618 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
619 MutexAutoLock envlock(m_env_mutex);
622 const RemoteClientMap &clients = m_clients.getClientList();
623 ScopeProfiler sp(g_profiler, "Server: update visible objects");
625 // Radius inside which objects are active
626 static thread_local const s16 radius =
627 g_settings->getS16("active_object_send_range_blocks") * MAP_BLOCKSIZE;
629 // Radius inside which players are active
630 static thread_local const bool is_transfer_limited =
631 g_settings->exists("unlimited_player_transfer_distance") &&
632 !g_settings->getBool("unlimited_player_transfer_distance");
633 static thread_local const s16 player_transfer_dist =
634 g_settings->getS16("player_transfer_distance") * MAP_BLOCKSIZE;
635 s16 player_radius = player_transfer_dist;
636 if (player_radius == 0 && is_transfer_limited)
637 player_radius = radius;
639 for (const auto &client_it : clients) {
640 RemoteClient *client = client_it.second;
642 // If definitions and textures have not been sent, don't
643 // send objects either
644 if (client->getState() < CS_DefinitionsSent)
647 RemotePlayer *player = m_env->getPlayer(client->peer_id);
649 // This can happen if the client timeouts somehow
653 PlayerSAO *playersao = player->getPlayerSAO();
657 s16 my_radius = MYMIN(radius, playersao->getWantedRange() * MAP_BLOCKSIZE);
658 if (my_radius <= 0) my_radius = radius;
659 //infostream << "Server: Active Radius " << my_radius << std::endl;
661 std::queue<u16> removed_objects;
662 std::queue<u16> added_objects;
663 m_env->getRemovedActiveObjects(playersao, my_radius, player_radius,
664 client->m_known_objects, removed_objects);
665 m_env->getAddedActiveObjects(playersao, my_radius, player_radius,
666 client->m_known_objects, added_objects);
668 // Ignore if nothing happened
669 if (removed_objects.empty() && added_objects.empty()) {
673 std::string data_buffer;
677 // Handle removed objects
678 writeU16((u8*)buf, removed_objects.size());
679 data_buffer.append(buf, 2);
680 while (!removed_objects.empty()) {
682 u16 id = removed_objects.front();
683 ServerActiveObject* obj = m_env->getActiveObject(id);
685 // Add to data buffer for sending
686 writeU16((u8*)buf, id);
687 data_buffer.append(buf, 2);
689 // Remove from known objects
690 client->m_known_objects.erase(id);
692 if(obj && obj->m_known_by_count > 0)
693 obj->m_known_by_count--;
694 removed_objects.pop();
697 // Handle added objects
698 writeU16((u8*)buf, added_objects.size());
699 data_buffer.append(buf, 2);
700 while (!added_objects.empty()) {
702 u16 id = added_objects.front();
703 ServerActiveObject* obj = m_env->getActiveObject(id);
706 u8 type = ACTIVEOBJECT_TYPE_INVALID;
708 warningstream << FUNCTION_NAME << ": NULL object" << std::endl;
710 type = obj->getSendType();
712 // Add to data buffer for sending
713 writeU16((u8*)buf, id);
714 data_buffer.append(buf, 2);
715 writeU8((u8*)buf, type);
716 data_buffer.append(buf, 1);
719 data_buffer.append(serializeLongString(
720 obj->getClientInitializationData(client->net_proto_version)));
722 data_buffer.append(serializeLongString(""));
724 // Add to known objects
725 client->m_known_objects.insert(id);
728 obj->m_known_by_count++;
733 u32 pktSize = SendActiveObjectRemoveAdd(client->peer_id, data_buffer);
734 verbosestream << "Server: Sent object remove/add: "
735 << removed_objects.size() << " removed, "
736 << added_objects.size() << " added, "
737 << "packet size is " << pktSize << std::endl;
741 m_mod_storage_save_timer -= dtime;
742 if (m_mod_storage_save_timer <= 0.0f) {
743 infostream << "Saving registered mod storages." << std::endl;
744 m_mod_storage_save_timer = g_settings->getFloat("server_map_save_interval");
745 for (std::unordered_map<std::string, ModMetadata *>::const_iterator
746 it = m_mod_storages.begin(); it != m_mod_storages.end(); ++it) {
747 if (it->second->isModified()) {
748 it->second->save(getModStoragePath());
758 MutexAutoLock envlock(m_env_mutex);
759 ScopeProfiler sp(g_profiler, "Server: send SAO messages");
762 // Value = data sent by object
763 std::unordered_map<u16, std::vector<ActiveObjectMessage>*> buffered_messages;
765 // Get active object messages from environment
767 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
771 std::vector<ActiveObjectMessage>* message_list = nullptr;
772 std::unordered_map<u16, std::vector<ActiveObjectMessage>* >::iterator n;
773 n = buffered_messages.find(aom.id);
774 if (n == buffered_messages.end()) {
775 message_list = new std::vector<ActiveObjectMessage>;
776 buffered_messages[aom.id] = message_list;
779 message_list = n->second;
781 message_list->push_back(aom);
785 const RemoteClientMap &clients = m_clients.getClientList();
786 // Route data to every client
787 for (const auto &client_it : clients) {
788 RemoteClient *client = client_it.second;
789 std::string reliable_data;
790 std::string unreliable_data;
791 // Go through all objects in message buffer
792 for (const auto &buffered_message : buffered_messages) {
793 // If object is not known by client, skip it
794 u16 id = buffered_message.first;
795 if (client->m_known_objects.find(id) == client->m_known_objects.end())
798 // Get message list of object
799 std::vector<ActiveObjectMessage>* list = buffered_message.second;
800 // Go through every message
801 for (const ActiveObjectMessage &aom : *list) {
802 // Compose the full new data with header
803 std::string new_data;
806 writeU16((u8*)&buf[0], aom.id);
807 new_data.append(buf, 2);
809 new_data += serializeString(aom.datastring);
810 // Add data to buffer
812 reliable_data += new_data;
814 unreliable_data += new_data;
818 reliable_data and unreliable_data are now ready.
821 if (!reliable_data.empty()) {
822 SendActiveObjectMessages(client->peer_id, reliable_data);
825 if (!unreliable_data.empty()) {
826 SendActiveObjectMessages(client->peer_id, unreliable_data, false);
831 // Clear buffered_messages
832 for (auto &buffered_message : buffered_messages) {
833 delete buffered_message.second;
838 Send queued-for-sending map edit events.
841 // We will be accessing the environment
842 MutexAutoLock lock(m_env_mutex);
844 // Don't send too many at a time
847 // Single change sending is disabled if queue size is not small
848 bool disable_single_change_sending = false;
849 if(m_unsent_map_edit_queue.size() >= 4)
850 disable_single_change_sending = true;
852 int event_count = m_unsent_map_edit_queue.size();
854 // We'll log the amount of each
857 std::list<v3s16> node_meta_updates;
859 while (!m_unsent_map_edit_queue.empty()) {
860 MapEditEvent* event = m_unsent_map_edit_queue.front();
861 m_unsent_map_edit_queue.pop();
863 // Players far away from the change are stored here.
864 // Instead of sending the changes, MapBlocks are set not sent
866 std::unordered_set<u16> far_players;
868 switch (event->type) {
871 prof.add("MEET_ADDNODE", 1);
872 sendAddNode(event->p, event->n, &far_players,
873 disable_single_change_sending ? 5 : 30,
874 event->type == MEET_ADDNODE);
876 case MEET_REMOVENODE:
877 prof.add("MEET_REMOVENODE", 1);
878 sendRemoveNode(event->p, &far_players,
879 disable_single_change_sending ? 5 : 30);
881 case MEET_BLOCK_NODE_METADATA_CHANGED: {
882 verbosestream << "Server: MEET_BLOCK_NODE_METADATA_CHANGED" << std::endl;
883 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
884 if (!event->is_private_change) {
885 // Don't send the change yet. Collect them to eliminate dupes.
886 node_meta_updates.remove(event->p);
887 node_meta_updates.push_back(event->p);
890 if (MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(
891 getNodeBlockPos(event->p))) {
892 block->raiseModified(MOD_STATE_WRITE_NEEDED,
893 MOD_REASON_REPORT_META_CHANGE);
898 infostream << "Server: MEET_OTHER" << std::endl;
899 prof.add("MEET_OTHER", 1);
900 for (const v3s16 &modified_block : event->modified_blocks) {
901 m_clients.markBlockposAsNotSent(modified_block);
905 prof.add("unknown", 1);
906 warningstream << "Server: Unknown MapEditEvent "
907 << ((u32)event->type) << std::endl;
912 Set blocks not sent to far players
914 if (!far_players.empty()) {
915 // Convert list format to that wanted by SetBlocksNotSent
916 std::map<v3s16, MapBlock*> modified_blocks2;
917 for (const v3s16 &modified_block : event->modified_blocks) {
918 modified_blocks2[modified_block] =
919 m_env->getMap().getBlockNoCreateNoEx(modified_block);
922 // Set blocks not sent
923 for (const u16 far_player : far_players) {
924 if (RemoteClient *client = getClient(far_player))
925 client->SetBlocksNotSent(modified_blocks2);
932 if (event_count >= 5) {
933 infostream << "Server: MapEditEvents:" << std::endl;
934 prof.print(infostream);
935 } else if (event_count != 0) {
936 verbosestream << "Server: MapEditEvents:" << std::endl;
937 prof.print(verbosestream);
940 // Send all metadata updates
941 if (node_meta_updates.size())
942 sendMetadataChanged(node_meta_updates);
946 Trigger emergethread (it somehow gets to a non-triggered but
947 bysy state sometimes)
950 float &counter = m_emergethread_trigger_timer;
952 if (counter >= 2.0) {
955 m_emerge->startThreads();
959 // Save map, players and auth stuff
961 float &counter = m_savemap_timer;
963 static thread_local const float save_interval =
964 g_settings->getFloat("server_map_save_interval");
965 if (counter >= save_interval) {
967 MutexAutoLock lock(m_env_mutex);
969 ScopeProfiler sp(g_profiler, "Server: map saving (sum)");
972 if (m_banmanager->isModified()) {
973 m_banmanager->save();
976 // Save changed parts of map
977 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
980 m_env->saveLoadedPlayers();
982 // Save environment metadata
987 m_shutdown_state.tick(dtime, this);
990 void Server::Receive()
992 session_t peer_id = 0;
995 m_con->Receive(&pkt);
996 peer_id = pkt.getPeerId();
998 } catch (const con::InvalidIncomingDataException &e) {
999 infostream << "Server::Receive(): InvalidIncomingDataException: what()="
1000 << e.what() << std::endl;
1001 } catch (const SerializationError &e) {
1002 infostream << "Server::Receive(): SerializationError: what()="
1003 << e.what() << std::endl;
1004 } catch (const ClientStateError &e) {
1005 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1006 DenyAccess_Legacy(peer_id, L"Your client sent something server didn't expect."
1007 L"Try reconnecting or updating your client");
1008 } catch (const con::PeerNotFoundException &e) {
1013 PlayerSAO* Server::StageTwoClientInit(session_t peer_id)
1015 std::string playername;
1016 PlayerSAO *playersao = NULL;
1019 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1021 playername = client->getName();
1022 playersao = emergePlayer(playername.c_str(), peer_id, client->net_proto_version);
1024 } catch (std::exception &e) {
1030 RemotePlayer *player = m_env->getPlayer(playername.c_str());
1032 // If failed, cancel
1033 if (!playersao || !player) {
1034 if (player && player->getPeerId() != PEER_ID_INEXISTENT) {
1035 actionstream << "Server: Failed to emerge player \"" << playername
1036 << "\" (player allocated to an another client)" << std::endl;
1037 DenyAccess_Legacy(peer_id, L"Another client is connected with this "
1038 L"name. If your client closed unexpectedly, try again in "
1041 errorstream << "Server: " << playername << ": Failed to emerge player"
1043 DenyAccess_Legacy(peer_id, L"Could not allocate player.");
1049 Send complete position information
1051 SendMovePlayer(peer_id);
1054 SendPlayerPrivileges(peer_id);
1056 // Send inventory formspec
1057 SendPlayerInventoryFormspec(peer_id);
1060 SendInventory(playersao);
1062 // Send HP or death screen
1063 if (playersao->isDead())
1064 SendDeathscreen(peer_id, false, v3f(0,0,0));
1066 SendPlayerHPOrDie(playersao,
1067 PlayerHPChangeReason(PlayerHPChangeReason::SET_HP));
1070 SendPlayerBreath(playersao);
1072 Address addr = getPeerAddress(player->getPeerId());
1073 std::string ip_str = addr.serializeString();
1074 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1079 const std::vector<std::string> &names = m_clients.getPlayerNames();
1081 actionstream << player->getName() << " joins game. List of players: ";
1083 for (const std::string &name : names) {
1084 actionstream << name << " ";
1087 actionstream << player->getName() <<std::endl;
1092 inline void Server::handleCommand(NetworkPacket* pkt)
1094 const ToServerCommandHandler& opHandle = toServerCommandTable[pkt->getCommand()];
1095 (this->*opHandle.handler)(pkt);
1098 void Server::ProcessData(NetworkPacket *pkt)
1100 // Environment is locked first.
1101 MutexAutoLock envlock(m_env_mutex);
1103 ScopeProfiler sp(g_profiler, "Server: Process network packet (sum)");
1104 u32 peer_id = pkt->getPeerId();
1107 Address address = getPeerAddress(peer_id);
1108 std::string addr_s = address.serializeString();
1110 if(m_banmanager->isIpBanned(addr_s)) {
1111 std::string ban_name = m_banmanager->getBanName(addr_s);
1112 infostream << "Server: A banned client tried to connect from "
1113 << addr_s << "; banned name was "
1114 << ban_name << std::endl;
1115 // This actually doesn't seem to transfer to the client
1116 DenyAccess_Legacy(peer_id, L"Your ip is banned. Banned name was "
1117 + utf8_to_wide(ban_name));
1121 catch(con::PeerNotFoundException &e) {
1123 * no peer for this packet found
1124 * most common reason is peer timeout, e.g. peer didn't
1125 * respond for some time, your server was overloaded or
1128 infostream << "Server::ProcessData(): Canceling: peer "
1129 << peer_id << " not found" << std::endl;
1134 ToServerCommand command = (ToServerCommand) pkt->getCommand();
1136 // Command must be handled into ToServerCommandHandler
1137 if (command >= TOSERVER_NUM_MSG_TYPES) {
1138 infostream << "Server: Ignoring unknown command "
1139 << command << std::endl;
1143 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
1148 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1150 if(peer_ser_ver == SER_FMT_VER_INVALID) {
1151 errorstream << "Server::ProcessData(): Cancelling: Peer"
1152 " serialization format invalid or not initialized."
1153 " Skipping incoming command=" << command << std::endl;
1157 /* Handle commands related to client startup */
1158 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
1163 if (m_clients.getClientState(peer_id) < CS_Active) {
1164 if (command == TOSERVER_PLAYERPOS) return;
1166 errorstream << "Got packet command: " << command << " for peer id "
1167 << peer_id << " but client isn't active yet. Dropping packet "
1173 } catch (SendFailedException &e) {
1174 errorstream << "Server::ProcessData(): SendFailedException: "
1175 << "what=" << e.what()
1177 } catch (PacketError &e) {
1178 actionstream << "Server::ProcessData(): PacketError: "
1179 << "what=" << e.what()
1184 void Server::setTimeOfDay(u32 time)
1186 m_env->setTimeOfDay(time);
1187 m_time_of_day_send_timer = 0;
1190 void Server::onMapEditEvent(MapEditEvent *event)
1192 if (m_ignore_map_edit_events_area.contains(event->getArea()))
1194 MapEditEvent *e = event->clone();
1195 m_unsent_map_edit_queue.push(e);
1198 Inventory* Server::getInventory(const InventoryLocation &loc)
1201 case InventoryLocation::UNDEFINED:
1202 case InventoryLocation::CURRENT_PLAYER:
1204 case InventoryLocation::PLAYER:
1206 RemotePlayer *player = m_env->getPlayer(loc.name.c_str());
1209 PlayerSAO *playersao = player->getPlayerSAO();
1212 return playersao->getInventory();
1215 case InventoryLocation::NODEMETA:
1217 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
1220 return meta->getInventory();
1223 case InventoryLocation::DETACHED:
1225 if(m_detached_inventories.count(loc.name) == 0)
1227 return m_detached_inventories[loc.name];
1231 sanity_check(false); // abort
1237 void Server::setInventoryModified(const InventoryLocation &loc, bool playerSend)
1240 case InventoryLocation::UNDEFINED:
1242 case InventoryLocation::PLAYER:
1247 RemotePlayer *player = m_env->getPlayer(loc.name.c_str());
1252 PlayerSAO *playersao = player->getPlayerSAO();
1256 SendInventory(playersao);
1259 case InventoryLocation::NODEMETA:
1262 event.type = MEET_BLOCK_NODE_METADATA_CHANGED;
1264 m_env->getMap().dispatchEvent(&event);
1267 case InventoryLocation::DETACHED:
1269 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
1273 sanity_check(false); // abort
1278 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
1280 std::vector<session_t> clients = m_clients.getClientIDs();
1282 // Set the modified blocks unsent for all the clients
1283 for (const session_t client_id : clients) {
1284 if (RemoteClient *client = m_clients.lockedGetClientNoEx(client_id))
1285 client->SetBlocksNotSent(block);
1290 void Server::peerAdded(con::Peer *peer)
1292 verbosestream<<"Server::peerAdded(): peer->id="
1293 <<peer->id<<std::endl;
1295 m_peer_change_queue.push(con::PeerChange(con::PEER_ADDED, peer->id, false));
1298 void Server::deletingPeer(con::Peer *peer, bool timeout)
1300 verbosestream<<"Server::deletingPeer(): peer->id="
1301 <<peer->id<<", timeout="<<timeout<<std::endl;
1303 m_clients.event(peer->id, CSE_Disconnect);
1304 m_peer_change_queue.push(con::PeerChange(con::PEER_REMOVED, peer->id, timeout));
1307 bool Server::getClientConInfo(session_t peer_id, con::rtt_stat_type type, float* retval)
1309 *retval = m_con->getPeerStat(peer_id,type);
1310 return *retval != -1;
1313 bool Server::getClientInfo(
1322 std::string* vers_string
1325 *state = m_clients.getClientState(peer_id);
1327 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
1334 *uptime = client->uptime();
1335 *ser_vers = client->serialization_version;
1336 *prot_vers = client->net_proto_version;
1338 *major = client->getMajor();
1339 *minor = client->getMinor();
1340 *patch = client->getPatch();
1341 *vers_string = client->getPatch();
1348 void Server::handlePeerChanges()
1350 while(!m_peer_change_queue.empty())
1352 con::PeerChange c = m_peer_change_queue.front();
1353 m_peer_change_queue.pop();
1355 verbosestream<<"Server: Handling peer change: "
1356 <<"id="<<c.peer_id<<", timeout="<<c.timeout
1361 case con::PEER_ADDED:
1362 m_clients.CreateClient(c.peer_id);
1365 case con::PEER_REMOVED:
1366 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
1370 FATAL_ERROR("Invalid peer change event received!");
1376 void Server::printToConsoleOnly(const std::string &text)
1379 m_admin_chat->outgoing_queue.push_back(
1380 new ChatEventChat("", utf8_to_wide(text)));
1382 std::cout << text << std::endl;
1386 void Server::Send(NetworkPacket *pkt)
1388 Send(pkt->getPeerId(), pkt);
1391 void Server::Send(session_t peer_id, NetworkPacket *pkt)
1393 m_clients.send(peer_id,
1394 clientCommandFactoryTable[pkt->getCommand()].channel,
1396 clientCommandFactoryTable[pkt->getCommand()].reliable);
1399 void Server::SendMovement(session_t peer_id)
1401 std::ostringstream os(std::ios_base::binary);
1403 NetworkPacket pkt(TOCLIENT_MOVEMENT, 12 * sizeof(float), peer_id);
1405 pkt << g_settings->getFloat("movement_acceleration_default");
1406 pkt << g_settings->getFloat("movement_acceleration_air");
1407 pkt << g_settings->getFloat("movement_acceleration_fast");
1408 pkt << g_settings->getFloat("movement_speed_walk");
1409 pkt << g_settings->getFloat("movement_speed_crouch");
1410 pkt << g_settings->getFloat("movement_speed_fast");
1411 pkt << g_settings->getFloat("movement_speed_climb");
1412 pkt << g_settings->getFloat("movement_speed_jump");
1413 pkt << g_settings->getFloat("movement_liquid_fluidity");
1414 pkt << g_settings->getFloat("movement_liquid_fluidity_smooth");
1415 pkt << g_settings->getFloat("movement_liquid_sink");
1416 pkt << g_settings->getFloat("movement_gravity");
1421 void Server::SendPlayerHPOrDie(PlayerSAO *playersao, const PlayerHPChangeReason &reason)
1423 if (playersao->isImmortal())
1426 session_t peer_id = playersao->getPeerID();
1427 bool is_alive = playersao->getHP() > 0;
1430 SendPlayerHP(peer_id);
1432 DiePlayer(peer_id, reason);
1435 void Server::SendHP(session_t peer_id, u16 hp)
1437 NetworkPacket pkt(TOCLIENT_HP, 1, peer_id);
1442 void Server::SendBreath(session_t peer_id, u16 breath)
1444 NetworkPacket pkt(TOCLIENT_BREATH, 2, peer_id);
1445 pkt << (u16) breath;
1449 void Server::SendAccessDenied(session_t peer_id, AccessDeniedCode reason,
1450 const std::string &custom_reason, bool reconnect)
1452 assert(reason < SERVER_ACCESSDENIED_MAX);
1454 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED, 1, peer_id);
1456 if (reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
1457 pkt << custom_reason;
1458 else if (reason == SERVER_ACCESSDENIED_SHUTDOWN ||
1459 reason == SERVER_ACCESSDENIED_CRASH)
1460 pkt << custom_reason << (u8)reconnect;
1464 void Server::SendAccessDenied_Legacy(session_t peer_id,const std::wstring &reason)
1466 NetworkPacket pkt(TOCLIENT_ACCESS_DENIED_LEGACY, 0, peer_id);
1471 void Server::SendDeathscreen(session_t peer_id, bool set_camera_point_target,
1472 v3f camera_point_target)
1474 NetworkPacket pkt(TOCLIENT_DEATHSCREEN, 1 + sizeof(v3f), peer_id);
1475 pkt << set_camera_point_target << camera_point_target;
1479 void Server::SendItemDef(session_t peer_id,
1480 IItemDefManager *itemdef, u16 protocol_version)
1482 NetworkPacket pkt(TOCLIENT_ITEMDEF, 0, peer_id);
1486 u32 length of the next item
1487 zlib-compressed serialized ItemDefManager
1489 std::ostringstream tmp_os(std::ios::binary);
1490 itemdef->serialize(tmp_os, protocol_version);
1491 std::ostringstream tmp_os2(std::ios::binary);
1492 compressZlib(tmp_os.str(), tmp_os2);
1493 pkt.putLongString(tmp_os2.str());
1496 verbosestream << "Server: Sending item definitions to id(" << peer_id
1497 << "): size=" << pkt.getSize() << std::endl;
1502 void Server::SendNodeDef(session_t peer_id,
1503 const NodeDefManager *nodedef, u16 protocol_version)
1505 NetworkPacket pkt(TOCLIENT_NODEDEF, 0, peer_id);
1509 u32 length of the next item
1510 zlib-compressed serialized NodeDefManager
1512 std::ostringstream tmp_os(std::ios::binary);
1513 nodedef->serialize(tmp_os, protocol_version);
1514 std::ostringstream tmp_os2(std::ios::binary);
1515 compressZlib(tmp_os.str(), tmp_os2);
1517 pkt.putLongString(tmp_os2.str());
1520 verbosestream << "Server: Sending node definitions to id(" << peer_id
1521 << "): size=" << pkt.getSize() << std::endl;
1527 Non-static send methods
1530 void Server::SendInventory(PlayerSAO* playerSAO)
1532 UpdateCrafting(playerSAO->getPlayer());
1538 NetworkPacket pkt(TOCLIENT_INVENTORY, 0, playerSAO->getPeerID());
1540 std::ostringstream os;
1541 playerSAO->getInventory()->serialize(os);
1543 std::string s = os.str();
1545 pkt.putRawString(s.c_str(), s.size());
1549 void Server::SendChatMessage(session_t peer_id, const ChatMessage &message)
1551 NetworkPacket pkt(TOCLIENT_CHAT_MESSAGE, 0, peer_id);
1553 u8 type = message.type;
1554 pkt << version << type << std::wstring(L"") << message.message << (u64)message.timestamp;
1556 if (peer_id != PEER_ID_INEXISTENT) {
1557 RemotePlayer *player = m_env->getPlayer(peer_id);
1563 m_clients.sendToAll(&pkt);
1567 void Server::SendShowFormspecMessage(session_t peer_id, const std::string &formspec,
1568 const std::string &formname)
1570 NetworkPacket pkt(TOCLIENT_SHOW_FORMSPEC, 0 , peer_id);
1571 if (formspec.empty()){
1572 //the client should close the formspec
1573 //but make sure there wasn't another one open in meantime
1574 const auto it = m_formspec_state_data.find(peer_id);
1575 if (it != m_formspec_state_data.end() && it->second == formname) {
1576 m_formspec_state_data.erase(peer_id);
1578 pkt.putLongString("");
1580 m_formspec_state_data[peer_id] = formname;
1581 pkt.putLongString(FORMSPEC_VERSION_STRING + formspec);
1588 // Spawns a particle on peer with peer_id
1589 void Server::SendSpawnParticle(session_t peer_id, u16 protocol_version,
1590 v3f pos, v3f velocity, v3f acceleration,
1591 float expirationtime, float size, bool collisiondetection,
1592 bool collision_removal, bool object_collision,
1593 bool vertical, const std::string &texture,
1594 const struct TileAnimationParams &animation, u8 glow)
1596 static thread_local const float radius =
1597 g_settings->getS16("max_block_send_distance") * MAP_BLOCKSIZE * BS;
1599 if (peer_id == PEER_ID_INEXISTENT) {
1600 std::vector<session_t> clients = m_clients.getClientIDs();
1602 for (const session_t client_id : clients) {
1603 RemotePlayer *player = m_env->getPlayer(client_id);
1607 PlayerSAO *sao = player->getPlayerSAO();
1611 // Do not send to distant clients
1612 if (sao->getBasePosition().getDistanceFrom(pos * BS) > radius)
1615 SendSpawnParticle(client_id, player->protocol_version,
1616 pos, velocity, acceleration,
1617 expirationtime, size, collisiondetection, collision_removal,
1618 object_collision, vertical, texture, animation, glow);
1623 NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
1625 pkt << pos << velocity << acceleration << expirationtime
1626 << size << collisiondetection;
1627 pkt.putLongString(texture);
1629 pkt << collision_removal;
1630 // This is horrible but required (why are there two ways to serialize pkts?)
1631 std::ostringstream os(std::ios_base::binary);
1632 animation.serialize(os, protocol_version);
1633 pkt.putRawString(os.str());
1635 pkt << object_collision;
1640 // Adds a ParticleSpawner on peer with peer_id
1641 void Server::SendAddParticleSpawner(session_t peer_id, u16 protocol_version,
1642 u16 amount, float spawntime, v3f minpos, v3f maxpos,
1643 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
1644 float minsize, float maxsize, bool collisiondetection, bool collision_removal,
1645 bool object_collision, u16 attached_id, bool vertical, const std::string &texture, u32 id,
1646 const struct TileAnimationParams &animation, u8 glow)
1648 if (peer_id == PEER_ID_INEXISTENT) {
1649 // This sucks and should be replaced:
1650 std::vector<session_t> clients = m_clients.getClientIDs();
1651 for (const session_t client_id : clients) {
1652 RemotePlayer *player = m_env->getPlayer(client_id);
1655 SendAddParticleSpawner(client_id, player->protocol_version,
1656 amount, spawntime, minpos, maxpos,
1657 minvel, maxvel, minacc, maxacc, minexptime, maxexptime,
1658 minsize, maxsize, collisiondetection, collision_removal,
1659 object_collision, attached_id, vertical, texture, id,
1665 NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
1667 pkt << amount << spawntime << minpos << maxpos << minvel << maxvel
1668 << minacc << maxacc << minexptime << maxexptime << minsize
1669 << maxsize << collisiondetection;
1671 pkt.putLongString(texture);
1673 pkt << id << vertical;
1674 pkt << collision_removal;
1676 // This is horrible but required
1677 std::ostringstream os(std::ios_base::binary);
1678 animation.serialize(os, protocol_version);
1679 pkt.putRawString(os.str());
1681 pkt << object_collision;
1686 void Server::SendDeleteParticleSpawner(session_t peer_id, u32 id)
1688 NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER, 4, peer_id);
1690 // Ugly error in this packet
1693 if (peer_id != PEER_ID_INEXISTENT)
1696 m_clients.sendToAll(&pkt);
1700 void Server::SendHUDAdd(session_t peer_id, u32 id, HudElement *form)
1702 NetworkPacket pkt(TOCLIENT_HUDADD, 0 , peer_id);
1704 pkt << id << (u8) form->type << form->pos << form->name << form->scale
1705 << form->text << form->number << form->item << form->dir
1706 << form->align << form->offset << form->world_pos << form->size;
1711 void Server::SendHUDRemove(session_t peer_id, u32 id)
1713 NetworkPacket pkt(TOCLIENT_HUDRM, 4, peer_id);
1718 void Server::SendHUDChange(session_t peer_id, u32 id, HudElementStat stat, void *value)
1720 NetworkPacket pkt(TOCLIENT_HUDCHANGE, 0, peer_id);
1721 pkt << id << (u8) stat;
1725 case HUD_STAT_SCALE:
1726 case HUD_STAT_ALIGN:
1727 case HUD_STAT_OFFSET:
1728 pkt << *(v2f *) value;
1732 pkt << *(std::string *) value;
1734 case HUD_STAT_WORLD_POS:
1735 pkt << *(v3f *) value;
1738 pkt << *(v2s32 *) value;
1740 case HUD_STAT_NUMBER:
1744 pkt << *(u32 *) value;
1751 void Server::SendHUDSetFlags(session_t peer_id, u32 flags, u32 mask)
1753 NetworkPacket pkt(TOCLIENT_HUD_SET_FLAGS, 4 + 4, peer_id);
1755 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
1757 pkt << flags << mask;
1762 void Server::SendHUDSetParam(session_t peer_id, u16 param, const std::string &value)
1764 NetworkPacket pkt(TOCLIENT_HUD_SET_PARAM, 0, peer_id);
1765 pkt << param << value;
1769 void Server::SendSetSky(session_t peer_id, const video::SColor &bgcolor,
1770 const std::string &type, const std::vector<std::string> ¶ms,
1773 NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id);
1774 pkt << bgcolor << type << (u16) params.size();
1776 for (const std::string ¶m : params)
1784 void Server::SendCloudParams(session_t peer_id, const CloudParams ¶ms)
1786 NetworkPacket pkt(TOCLIENT_CLOUD_PARAMS, 0, peer_id);
1787 pkt << params.density << params.color_bright << params.color_ambient
1788 << params.height << params.thickness << params.speed;
1792 void Server::SendOverrideDayNightRatio(session_t peer_id, bool do_override,
1795 NetworkPacket pkt(TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO,
1798 pkt << do_override << (u16) (ratio * 65535);
1803 void Server::SendTimeOfDay(session_t peer_id, u16 time, f32 time_speed)
1805 NetworkPacket pkt(TOCLIENT_TIME_OF_DAY, 0, peer_id);
1806 pkt << time << time_speed;
1808 if (peer_id == PEER_ID_INEXISTENT) {
1809 m_clients.sendToAll(&pkt);
1816 void Server::SendPlayerHP(session_t peer_id)
1818 PlayerSAO *playersao = getPlayerSAO(peer_id);
1819 // In some rare case if the player is disconnected
1820 // while Lua call l_punch, for example, this can be NULL
1824 SendHP(peer_id, playersao->getHP());
1825 m_script->player_event(playersao,"health_changed");
1827 // Send to other clients
1828 std::string str = gob_cmd_punched(playersao->getHP());
1829 ActiveObjectMessage aom(playersao->getId(), true, str);
1830 playersao->m_messages_out.push(aom);
1833 void Server::SendPlayerBreath(PlayerSAO *sao)
1837 m_script->player_event(sao, "breath_changed");
1838 SendBreath(sao->getPeerID(), sao->getBreath());
1841 void Server::SendMovePlayer(session_t peer_id)
1843 RemotePlayer *player = m_env->getPlayer(peer_id);
1845 PlayerSAO *sao = player->getPlayerSAO();
1848 NetworkPacket pkt(TOCLIENT_MOVE_PLAYER, sizeof(v3f) + sizeof(f32) * 2, peer_id);
1849 pkt << sao->getBasePosition() << sao->getLookPitch() << sao->getRotation().Y;
1852 v3f pos = sao->getBasePosition();
1853 verbosestream << "Server: Sending TOCLIENT_MOVE_PLAYER"
1854 << " pos=(" << pos.X << "," << pos.Y << "," << pos.Z << ")"
1855 << " pitch=" << sao->getLookPitch()
1856 << " yaw=" << sao->getRotation().Y
1863 void Server::SendLocalPlayerAnimations(session_t peer_id, v2s32 animation_frames[4],
1864 f32 animation_speed)
1866 NetworkPacket pkt(TOCLIENT_LOCAL_PLAYER_ANIMATIONS, 0,
1869 pkt << animation_frames[0] << animation_frames[1] << animation_frames[2]
1870 << animation_frames[3] << animation_speed;
1875 void Server::SendEyeOffset(session_t peer_id, v3f first, v3f third)
1877 NetworkPacket pkt(TOCLIENT_EYE_OFFSET, 0, peer_id);
1878 pkt << first << third;
1882 void Server::SendPlayerPrivileges(session_t peer_id)
1884 RemotePlayer *player = m_env->getPlayer(peer_id);
1886 if(player->getPeerId() == PEER_ID_INEXISTENT)
1889 std::set<std::string> privs;
1890 m_script->getAuth(player->getName(), NULL, &privs);
1892 NetworkPacket pkt(TOCLIENT_PRIVILEGES, 0, peer_id);
1893 pkt << (u16) privs.size();
1895 for (const std::string &priv : privs) {
1902 void Server::SendPlayerInventoryFormspec(session_t peer_id)
1904 RemotePlayer *player = m_env->getPlayer(peer_id);
1906 if (player->getPeerId() == PEER_ID_INEXISTENT)
1909 NetworkPacket pkt(TOCLIENT_INVENTORY_FORMSPEC, 0, peer_id);
1910 pkt.putLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
1914 void Server::SendPlayerFormspecPrepend(session_t peer_id)
1916 RemotePlayer *player = m_env->getPlayer(peer_id);
1918 if (player->getPeerId() == PEER_ID_INEXISTENT)
1921 NetworkPacket pkt(TOCLIENT_FORMSPEC_PREPEND, 0, peer_id);
1922 pkt << FORMSPEC_VERSION_STRING + player->formspec_prepend;
1926 u32 Server::SendActiveObjectRemoveAdd(session_t peer_id, const std::string &datas)
1928 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, datas.size(), peer_id);
1929 pkt.putRawString(datas.c_str(), datas.size());
1931 return pkt.getSize();
1934 void Server::SendActiveObjectMessages(session_t peer_id, const std::string &datas,
1937 NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_MESSAGES,
1938 datas.size(), peer_id);
1940 pkt.putRawString(datas.c_str(), datas.size());
1942 m_clients.send(pkt.getPeerId(),
1943 reliable ? clientCommandFactoryTable[pkt.getCommand()].channel : 1,
1947 void Server::SendCSMRestrictionFlags(session_t peer_id)
1949 NetworkPacket pkt(TOCLIENT_CSM_RESTRICTION_FLAGS,
1950 sizeof(m_csm_restriction_flags) + sizeof(m_csm_restriction_noderange), peer_id);
1951 pkt << m_csm_restriction_flags << m_csm_restriction_noderange;
1955 void Server::SendPlayerSpeed(session_t peer_id, const v3f &added_vel)
1957 NetworkPacket pkt(TOCLIENT_PLAYER_SPEED, 0, peer_id);
1962 s32 Server::playSound(const SimpleSoundSpec &spec,
1963 const ServerSoundParams ¶ms)
1965 // Find out initial position of sound
1966 bool pos_exists = false;
1967 v3f pos = params.getPos(m_env, &pos_exists);
1968 // If position is not found while it should be, cancel sound
1969 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
1972 // Filter destination clients
1973 std::vector<session_t> dst_clients;
1974 if(!params.to_player.empty()) {
1975 RemotePlayer *player = m_env->getPlayer(params.to_player.c_str());
1977 infostream<<"Server::playSound: Player \""<<params.to_player
1978 <<"\" not found"<<std::endl;
1981 if (player->getPeerId() == PEER_ID_INEXISTENT) {
1982 infostream<<"Server::playSound: Player \""<<params.to_player
1983 <<"\" not connected"<<std::endl;
1986 dst_clients.push_back(player->getPeerId());
1988 std::vector<session_t> clients = m_clients.getClientIDs();
1990 for (const session_t client_id : clients) {
1991 RemotePlayer *player = m_env->getPlayer(client_id);
1995 PlayerSAO *sao = player->getPlayerSAO();
2000 if(sao->getBasePosition().getDistanceFrom(pos) >
2001 params.max_hear_distance)
2004 dst_clients.push_back(client_id);
2008 if(dst_clients.empty())
2012 s32 id = m_next_sound_id++;
2013 // The sound will exist as a reference in m_playing_sounds
2014 m_playing_sounds[id] = ServerPlayingSound();
2015 ServerPlayingSound &psound = m_playing_sounds[id];
2016 psound.params = params;
2019 float gain = params.gain * spec.gain;
2020 NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0);
2021 pkt << id << spec.name << gain
2022 << (u8) params.type << pos << params.object
2023 << params.loop << params.fade << params.pitch;
2025 // Backwards compability
2026 bool play_sound = gain > 0;
2028 for (const u16 dst_client : dst_clients) {
2029 if (play_sound || m_clients.getProtocolVersion(dst_client) >= 32) {
2030 psound.clients.insert(dst_client);
2031 m_clients.send(dst_client, 0, &pkt, true);
2036 void Server::stopSound(s32 handle)
2038 // Get sound reference
2039 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2040 m_playing_sounds.find(handle);
2041 if (i == m_playing_sounds.end())
2043 ServerPlayingSound &psound = i->second;
2045 NetworkPacket pkt(TOCLIENT_STOP_SOUND, 4);
2048 for (std::unordered_set<session_t>::const_iterator si = psound.clients.begin();
2049 si != psound.clients.end(); ++si) {
2051 m_clients.send(*si, 0, &pkt, true);
2053 // Remove sound reference
2054 m_playing_sounds.erase(i);
2057 void Server::fadeSound(s32 handle, float step, float gain)
2059 // Get sound reference
2060 std::unordered_map<s32, ServerPlayingSound>::iterator i =
2061 m_playing_sounds.find(handle);
2062 if (i == m_playing_sounds.end())
2065 ServerPlayingSound &psound = i->second;
2066 psound.params.gain = gain;
2068 NetworkPacket pkt(TOCLIENT_FADE_SOUND, 4);
2069 pkt << handle << step << gain;
2071 // Backwards compability
2072 bool play_sound = gain > 0;
2073 ServerPlayingSound compat_psound = psound;
2074 compat_psound.clients.clear();
2076 NetworkPacket compat_pkt(TOCLIENT_STOP_SOUND, 4);
2077 compat_pkt << handle;
2079 for (std::unordered_set<u16>::iterator it = psound.clients.begin();
2080 it != psound.clients.end();) {
2081 if (m_clients.getProtocolVersion(*it) >= 32) {
2083 m_clients.send(*it, 0, &pkt, true);
2086 compat_psound.clients.insert(*it);
2088 m_clients.send(*it, 0, &compat_pkt, true);
2089 psound.clients.erase(it++);
2093 // Remove sound reference
2094 if (!play_sound || psound.clients.empty())
2095 m_playing_sounds.erase(i);
2097 if (play_sound && !compat_psound.clients.empty()) {
2098 // Play new sound volume on older clients
2099 playSound(compat_psound.spec, compat_psound.params);
2103 void Server::sendRemoveNode(v3s16 p, std::unordered_set<u16> *far_players,
2106 float maxd = far_d_nodes * BS;
2107 v3f p_f = intToFloat(p, BS);
2108 v3s16 block_pos = getNodeBlockPos(p);
2110 NetworkPacket pkt(TOCLIENT_REMOVENODE, 6);
2113 std::vector<session_t> clients = m_clients.getClientIDs();
2116 for (session_t client_id : clients) {
2117 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
2121 RemotePlayer *player = m_env->getPlayer(client_id);
2122 PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr;
2124 // If player is far away, only set modified blocks not sent
2125 if (!client->isBlockSent(block_pos) || (sao &&
2126 sao->getBasePosition().getDistanceFrom(p_f) > maxd)) {
2128 far_players->emplace(client_id);
2130 client->SetBlockNotSent(block_pos);
2135 m_clients.send(client_id, 0, &pkt, true);
2141 void Server::sendAddNode(v3s16 p, MapNode n, std::unordered_set<u16> *far_players,
2142 float far_d_nodes, bool remove_metadata)
2144 float maxd = far_d_nodes * BS;
2145 v3f p_f = intToFloat(p, BS);
2146 v3s16 block_pos = getNodeBlockPos(p);
2148 NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1);
2149 pkt << p << n.param0 << n.param1 << n.param2
2150 << (u8) (remove_metadata ? 0 : 1);
2152 std::vector<session_t> clients = m_clients.getClientIDs();
2155 for (session_t client_id : clients) {
2156 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
2160 RemotePlayer *player = m_env->getPlayer(client_id);
2161 PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr;
2163 // If player is far away, only set modified blocks not sent
2164 if (!client->isBlockSent(block_pos) || (sao &&
2165 sao->getBasePosition().getDistanceFrom(p_f) > maxd)) {
2167 far_players->emplace(client_id);
2169 client->SetBlockNotSent(block_pos);
2174 m_clients.send(client_id, 0, &pkt, true);
2180 void Server::sendMetadataChanged(const std::list<v3s16> &meta_updates, float far_d_nodes)
2182 float maxd = far_d_nodes * BS;
2183 NodeMetadataList meta_updates_list(false);
2184 std::vector<session_t> clients = m_clients.getClientIDs();
2188 for (session_t i : clients) {
2189 RemoteClient *client = m_clients.lockedGetClientNoEx(i);
2193 ServerActiveObject *player = m_env->getActiveObject(i);
2194 v3f player_pos = player ? player->getBasePosition() : v3f();
2196 for (const v3s16 &pos : meta_updates) {
2197 NodeMetadata *meta = m_env->getMap().getNodeMetadata(pos);
2202 v3s16 block_pos = getNodeBlockPos(pos);
2203 if (!client->isBlockSent(block_pos) || (player &&
2204 player_pos.getDistanceFrom(intToFloat(pos, BS)) > maxd)) {
2205 client->SetBlockNotSent(block_pos);
2209 // Add the change to send list
2210 meta_updates_list.set(pos, meta);
2212 if (meta_updates_list.size() == 0)
2215 // Send the meta changes
2216 std::ostringstream os(std::ios::binary);
2217 meta_updates_list.serialize(os, client->net_proto_version, false, true);
2218 std::ostringstream oss(std::ios::binary);
2219 compressZlib(os.str(), oss);
2221 NetworkPacket pkt(TOCLIENT_NODEMETA_CHANGED, 0);
2222 pkt.putLongString(oss.str());
2223 m_clients.send(i, 0, &pkt, true);
2225 meta_updates_list.clear();
2231 void Server::SendBlockNoLock(session_t peer_id, MapBlock *block, u8 ver,
2232 u16 net_proto_version)
2235 Create a packet with the block in the right format
2238 std::ostringstream os(std::ios_base::binary);
2239 block->serialize(os, ver, false);
2240 block->serializeNetworkSpecific(os);
2241 std::string s = os.str();
2243 NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id);
2245 pkt << block->getPos();
2246 pkt.putRawString(s.c_str(), s.size());
2250 void Server::SendBlocks(float dtime)
2252 MutexAutoLock envlock(m_env_mutex);
2253 //TODO check if one big lock could be faster then multiple small ones
2255 std::vector<PrioritySortedBlockTransfer> queue;
2257 u32 total_sending = 0;
2260 ScopeProfiler sp2(g_profiler, "Server::SendBlocks(): Collect list");
2262 std::vector<session_t> clients = m_clients.getClientIDs();
2265 for (const session_t client_id : clients) {
2266 RemoteClient *client = m_clients.lockedGetClientNoEx(client_id, CS_Active);
2271 total_sending += client->getSendingCount();
2272 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
2278 // Lowest priority number comes first.
2279 // Lowest is most important.
2280 std::sort(queue.begin(), queue.end());
2284 // Maximal total count calculation
2285 // The per-client block sends is halved with the maximal online users
2286 u32 max_blocks_to_send = (m_env->getPlayerCount() + g_settings->getU32("max_users")) *
2287 g_settings->getU32("max_simultaneous_block_sends_per_client") / 4 + 1;
2289 ScopeProfiler sp(g_profiler, "Server::SendBlocks(): Send to clients");
2290 Map &map = m_env->getMap();
2292 for (const PrioritySortedBlockTransfer &block_to_send : queue) {
2293 if (total_sending >= max_blocks_to_send)
2296 MapBlock *block = map.getBlockNoCreateNoEx(block_to_send.pos);
2300 RemoteClient *client = m_clients.lockedGetClientNoEx(block_to_send.peer_id,
2305 SendBlockNoLock(block_to_send.peer_id, block, client->serialization_version,
2306 client->net_proto_version);
2308 client->SentBlock(block_to_send.pos);
2314 bool Server::SendBlock(session_t peer_id, const v3s16 &blockpos)
2316 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2321 RemoteClient *client = m_clients.lockedGetClientNoEx(peer_id, CS_Active);
2322 if (!client || client->isBlockSent(blockpos)) {
2326 SendBlockNoLock(peer_id, block, client->serialization_version,
2327 client->net_proto_version);
2333 void Server::fillMediaCache()
2335 infostream<<"Server: Calculating media file checksums"<<std::endl;
2337 // Collect all media file paths
2338 std::vector<std::string> paths;
2339 m_modmgr->getModsMediaPaths(paths);
2340 fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures");
2341 fs::GetRecursiveDirs(paths, porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
2343 // Collect media file information from paths into cache
2344 for (const std::string &mediapath : paths) {
2345 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
2346 for (const fs::DirListNode &dln : dirlist) {
2347 if (dln.dir) // Ignode dirs
2349 std::string filename = dln.name;
2350 // If name contains illegal characters, ignore the file
2351 if (!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
2352 infostream<<"Server: ignoring illegal file name: \""
2353 << filename << "\"" << std::endl;
2356 // If name is not in a supported format, ignore it
2357 const char *supported_ext[] = {
2358 ".png", ".jpg", ".bmp", ".tga",
2359 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
2361 ".x", ".b3d", ".md2", ".obj",
2362 // Custom translation file format
2366 if (removeStringEnd(filename, supported_ext).empty()){
2367 infostream << "Server: ignoring unsupported file extension: \""
2368 << filename << "\"" << std::endl;
2371 // Ok, attempt to load the file and add to cache
2372 std::string filepath;
2373 filepath.append(mediapath).append(DIR_DELIM).append(filename);
2376 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
2378 errorstream << "Server::fillMediaCache(): Could not open \""
2379 << filename << "\" for reading" << std::endl;
2382 std::ostringstream tmp_os(std::ios_base::binary);
2386 fis.read(buf, 1024);
2387 std::streamsize len = fis.gcount();
2388 tmp_os.write(buf, len);
2397 errorstream<<"Server::fillMediaCache(): Failed to read \""
2398 << filename << "\"" << std::endl;
2401 if(tmp_os.str().length() == 0) {
2402 errorstream << "Server::fillMediaCache(): Empty file \""
2403 << filepath << "\"" << std::endl;
2408 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
2410 unsigned char *digest = sha1.getDigest();
2411 std::string sha1_base64 = base64_encode(digest, 20);
2412 std::string sha1_hex = hex_encode((char*)digest, 20);
2416 m_media[filename] = MediaInfo(filepath, sha1_base64);
2417 verbosestream << "Server: " << sha1_hex << " is " << filename
2423 void Server::sendMediaAnnouncement(session_t peer_id, const std::string &lang_code)
2425 verbosestream << "Server: Announcing files to id(" << peer_id << ")"
2429 NetworkPacket pkt(TOCLIENT_ANNOUNCE_MEDIA, 0, peer_id);
2432 std::string lang_suffix;
2433 lang_suffix.append(".").append(lang_code).append(".tr");
2434 for (const auto &i : m_media) {
2435 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2442 for (const auto &i : m_media) {
2443 if (str_ends_with(i.first, ".tr") && !str_ends_with(i.first, lang_suffix))
2445 pkt << i.first << i.second.sha1_digest;
2448 pkt << g_settings->get("remote_media");
2452 struct SendableMedia
2458 SendableMedia(const std::string &name_="", const std::string &path_="",
2459 const std::string &data_=""):
2466 void Server::sendRequestedMedia(session_t peer_id,
2467 const std::vector<std::string> &tosend)
2469 verbosestream<<"Server::sendRequestedMedia(): "
2470 <<"Sending files to client"<<std::endl;
2474 // Put 5kB in one bunch (this is not accurate)
2475 u32 bytes_per_bunch = 5000;
2477 std::vector< std::vector<SendableMedia> > file_bunches;
2478 file_bunches.emplace_back();
2480 u32 file_size_bunch_total = 0;
2482 for (const std::string &name : tosend) {
2483 if (m_media.find(name) == m_media.end()) {
2484 errorstream<<"Server::sendRequestedMedia(): Client asked for "
2485 <<"unknown file \""<<(name)<<"\""<<std::endl;
2489 //TODO get path + name
2490 std::string tpath = m_media[name].path;
2493 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
2495 errorstream<<"Server::sendRequestedMedia(): Could not open \""
2496 <<tpath<<"\" for reading"<<std::endl;
2499 std::ostringstream tmp_os(std::ios_base::binary);
2503 fis.read(buf, 1024);
2504 std::streamsize len = fis.gcount();
2505 tmp_os.write(buf, len);
2506 file_size_bunch_total += len;
2515 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
2516 <<name<<"\""<<std::endl;
2519 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
2520 <<tname<<"\""<<std::endl;*/
2522 file_bunches[file_bunches.size()-1].emplace_back(name, tpath, tmp_os.str());
2524 // Start next bunch if got enough data
2525 if(file_size_bunch_total >= bytes_per_bunch) {
2526 file_bunches.emplace_back();
2527 file_size_bunch_total = 0;
2532 /* Create and send packets */
2534 u16 num_bunches = file_bunches.size();
2535 for (u16 i = 0; i < num_bunches; i++) {
2538 u16 total number of texture bunches
2539 u16 index of this bunch
2540 u32 number of files in this bunch
2549 NetworkPacket pkt(TOCLIENT_MEDIA, 4 + 0, peer_id);
2550 pkt << num_bunches << i << (u32) file_bunches[i].size();
2552 for (const SendableMedia &j : file_bunches[i]) {
2554 pkt.putLongString(j.data);
2557 verbosestream << "Server::sendRequestedMedia(): bunch "
2558 << i << "/" << num_bunches
2559 << " files=" << file_bunches[i].size()
2560 << " size=" << pkt.getSize() << std::endl;
2565 void Server::sendDetachedInventory(const std::string &name, session_t peer_id)
2567 const auto &inv_it = m_detached_inventories.find(name);
2568 const auto &player_it = m_detached_inventories_player.find(name);
2570 if (player_it == m_detached_inventories_player.end() ||
2571 player_it->second.empty()) {
2572 // OK. Send to everyone
2574 RemotePlayer *p = m_env->getPlayer(player_it->second.c_str());
2576 return; // Player is offline
2578 if (peer_id != PEER_ID_INEXISTENT && peer_id != p->getPeerId())
2579 return; // Caller requested send to a different player, so don't send.
2581 peer_id = p->getPeerId();
2584 NetworkPacket pkt(TOCLIENT_DETACHED_INVENTORY, 0, peer_id);
2587 if (inv_it == m_detached_inventories.end()) {
2588 pkt << false; // Remove inventory
2590 pkt << true; // Update inventory
2592 // Serialization & NetworkPacket isn't a love story
2593 std::ostringstream os(std::ios_base::binary);
2594 inv_it->second->serialize(os);
2596 std::string os_str = os.str();
2597 pkt << static_cast<u16>(os_str.size()); // HACK: to keep compatibility with 5.0.0 clients
2598 pkt.putRawString(os_str);
2601 if (peer_id == PEER_ID_INEXISTENT)
2602 m_clients.sendToAll(&pkt);
2607 void Server::sendDetachedInventories(session_t peer_id)
2609 for (const auto &detached_inventory : m_detached_inventories) {
2610 const std::string &name = detached_inventory.first;
2611 //Inventory *inv = i->second;
2612 sendDetachedInventory(name, peer_id);
2620 void Server::DiePlayer(session_t peer_id, const PlayerHPChangeReason &reason)
2622 PlayerSAO *playersao = getPlayerSAO(peer_id);
2623 // In some rare cases this can be NULL -- if the player is disconnected
2624 // when a Lua function modifies l_punch, for example
2628 infostream << "Server::DiePlayer(): Player "
2629 << playersao->getPlayer()->getName()
2630 << " dies" << std::endl;
2632 playersao->setHP(0, reason);
2633 playersao->clearParentAttachment();
2635 // Trigger scripted stuff
2636 m_script->on_dieplayer(playersao, reason);
2638 SendPlayerHP(peer_id);
2639 SendDeathscreen(peer_id, false, v3f(0,0,0));
2642 void Server::RespawnPlayer(session_t peer_id)
2644 PlayerSAO *playersao = getPlayerSAO(peer_id);
2647 infostream << "Server::RespawnPlayer(): Player "
2648 << playersao->getPlayer()->getName()
2649 << " respawns" << std::endl;
2651 playersao->setHP(playersao->accessObjectProperties()->hp_max,
2652 PlayerHPChangeReason(PlayerHPChangeReason::RESPAWN));
2653 playersao->setBreath(playersao->accessObjectProperties()->breath_max);
2655 bool repositioned = m_script->on_respawnplayer(playersao);
2656 if (!repositioned) {
2657 // setPos will send the new position to client
2658 playersao->setPos(findSpawnPos());
2661 SendPlayerHP(peer_id);
2665 void Server::DenySudoAccess(session_t peer_id)
2667 NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
2672 void Server::DenyAccessVerCompliant(session_t peer_id, u16 proto_ver, AccessDeniedCode reason,
2673 const std::string &str_reason, bool reconnect)
2675 SendAccessDenied(peer_id, reason, str_reason, reconnect);
2677 m_clients.event(peer_id, CSE_SetDenied);
2678 DisconnectPeer(peer_id);
2682 void Server::DenyAccess(session_t peer_id, AccessDeniedCode reason,
2683 const std::string &custom_reason)
2685 SendAccessDenied(peer_id, reason, custom_reason);
2686 m_clients.event(peer_id, CSE_SetDenied);
2687 DisconnectPeer(peer_id);
2690 // 13/03/15: remove this function when protocol version 25 will become
2691 // the minimum version for MT users, maybe in 1 year
2692 void Server::DenyAccess_Legacy(session_t peer_id, const std::wstring &reason)
2694 SendAccessDenied_Legacy(peer_id, reason);
2695 m_clients.event(peer_id, CSE_SetDenied);
2696 DisconnectPeer(peer_id);
2699 void Server::DisconnectPeer(session_t peer_id)
2701 m_modchannel_mgr->leaveAllChannels(peer_id);
2702 m_con->DisconnectPeer(peer_id);
2705 void Server::acceptAuth(session_t peer_id, bool forSudoMode)
2708 RemoteClient* client = getClient(peer_id, CS_Invalid);
2710 NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);
2712 // Right now, the auth mechs don't change between login and sudo mode.
2713 u32 sudo_auth_mechs = client->allowed_auth_mechs;
2714 client->allowed_sudo_mechs = sudo_auth_mechs;
2716 resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
2717 << g_settings->getFloat("dedicated_server_step")
2721 m_clients.event(peer_id, CSE_AuthAccept);
2723 NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);
2725 // We only support SRP right now
2726 u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;
2728 resp_pkt << sudo_auth_mechs;
2730 m_clients.event(peer_id, CSE_SudoSuccess);
2734 void Server::DeleteClient(session_t peer_id, ClientDeletionReason reason)
2736 std::wstring message;
2739 Clear references to playing sounds
2741 for (std::unordered_map<s32, ServerPlayingSound>::iterator
2742 i = m_playing_sounds.begin(); i != m_playing_sounds.end();) {
2743 ServerPlayingSound &psound = i->second;
2744 psound.clients.erase(peer_id);
2745 if (psound.clients.empty())
2746 m_playing_sounds.erase(i++);
2751 // clear formspec info so the next client can't abuse the current state
2752 m_formspec_state_data.erase(peer_id);
2754 RemotePlayer *player = m_env->getPlayer(peer_id);
2756 /* Run scripts and remove from environment */
2758 PlayerSAO *playersao = player->getPlayerSAO();
2761 playersao->clearChildAttachments();
2762 playersao->clearParentAttachment();
2764 // inform connected clients
2765 const std::string &player_name = player->getName();
2766 NetworkPacket notice(TOCLIENT_UPDATE_PLAYER_LIST, 0, PEER_ID_INEXISTENT);
2767 // (u16) 1 + std::string represents a vector serialization representation
2768 notice << (u8) PLAYER_LIST_REMOVE << (u16) 1 << player_name;
2769 m_clients.sendToAll(¬ice);
2771 m_script->on_leaveplayer(playersao, reason == CDR_TIMEOUT);
2773 playersao->disconnected();
2780 if (player && reason != CDR_DENY) {
2781 std::ostringstream os(std::ios_base::binary);
2782 std::vector<session_t> clients = m_clients.getClientIDs();
2784 for (const session_t client_id : clients) {
2786 RemotePlayer *player = m_env->getPlayer(client_id);
2790 // Get name of player
2791 os << player->getName() << " ";
2794 std::string name = player->getName();
2795 actionstream << name << " "
2796 << (reason == CDR_TIMEOUT ? "times out." : "leaves game.")
2797 << " List of players: " << os.str() << std::endl;
2799 m_admin_chat->outgoing_queue.push_back(
2800 new ChatEventNick(CET_NICK_REMOVE, name));
2804 MutexAutoLock env_lock(m_env_mutex);
2805 m_clients.DeleteClient(peer_id);
2809 // Send leave chat message to all remaining clients
2810 if (!message.empty()) {
2811 SendChatMessage(PEER_ID_INEXISTENT,
2812 ChatMessage(CHATMESSAGE_TYPE_ANNOUNCE, message));
2816 void Server::UpdateCrafting(RemotePlayer *player)
2818 InventoryList *clist = player->inventory.getList("craft");
2819 if (!clist || clist->getSize() == 0)
2822 // Get a preview for crafting
2824 InventoryLocation loc;
2825 loc.setPlayer(player->getName());
2826 std::vector<ItemStack> output_replacements;
2827 getCraftingResult(&player->inventory, preview, output_replacements, false, this);
2828 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(),
2831 InventoryList *plist = player->inventory.getList("craftpreview");
2832 if (plist && plist->getSize() >= 1) {
2833 // Put the new preview in
2834 plist->changeItem(0, preview);
2838 void Server::handleChatInterfaceEvent(ChatEvent *evt)
2840 if (evt->type == CET_NICK_ADD) {
2841 // The terminal informed us of its nick choice
2842 m_admin_nick = ((ChatEventNick *)evt)->nick;
2843 if (!m_script->getAuth(m_admin_nick, NULL, NULL)) {
2844 errorstream << "You haven't set up an account." << std::endl
2845 << "Please log in using the client as '"
2846 << m_admin_nick << "' with a secure password." << std::endl
2847 << "Until then, you can't execute admin tasks via the console," << std::endl
2848 << "and everybody can claim the user account instead of you," << std::endl
2849 << "giving them full control over this server." << std::endl;
2852 assert(evt->type == CET_CHAT);
2853 handleAdminChat((ChatEventChat *)evt);
2857 std::wstring Server::handleChat(const std::string &name, const std::wstring &wname,
2858 std::wstring wmessage, bool check_shout_priv, RemotePlayer *player)
2860 // If something goes wrong, this player is to blame
2861 RollbackScopeActor rollback_scope(m_rollback,
2862 std::string("player:") + name);
2864 if (g_settings->getBool("strip_color_codes"))
2865 wmessage = unescape_enriched(wmessage);
2868 switch (player->canSendChatMessage()) {
2869 case RPLAYER_CHATRESULT_FLOODING: {
2870 std::wstringstream ws;
2871 ws << L"You cannot send more messages. You are limited to "
2872 << g_settings->getFloat("chat_message_limit_per_10sec")
2873 << L" messages per 10 seconds.";
2876 case RPLAYER_CHATRESULT_KICK:
2877 DenyAccess_Legacy(player->getPeerId(),
2878 L"You have been kicked due to message flooding.");
2880 case RPLAYER_CHATRESULT_OK:
2883 FATAL_ERROR("Unhandled chat filtering result found.");
2887 if (m_max_chatmessage_length > 0
2888 && wmessage.length() > m_max_chatmessage_length) {
2889 return L"Your message exceed the maximum chat message limit set on the server. "
2890 L"It was refused. Send a shorter message";
2893 auto message = trim(wide_to_utf8(wmessage));
2894 if (message.find_first_of("\n\r") != std::wstring::npos) {
2895 return L"New lines are not permitted in chat messages";
2898 // Run script hook, exit if script ate the chat message
2899 if (m_script->on_chat_message(name, message))
2904 // Whether to send line to the player that sent the message, or to all players
2905 bool broadcast_line = true;
2907 if (check_shout_priv && !checkPriv(name, "shout")) {
2908 line += L"-!- You don't have permission to shout.";
2909 broadcast_line = false;
2911 line += narrow_to_wide(m_script->formatChatMessage(name,
2912 wide_to_narrow(wmessage)));
2916 Tell calling method to send the message to sender
2918 if (!broadcast_line)
2922 Send the message to others
2924 actionstream << "CHAT: " << wide_to_narrow(unescape_enriched(line)) << std::endl;
2926 std::vector<session_t> clients = m_clients.getClientIDs();
2929 Send the message back to the inital sender
2930 if they are using protocol version >= 29
2933 session_t peer_id_to_avoid_sending =
2934 (player ? player->getPeerId() : PEER_ID_INEXISTENT);
2936 if (player && player->protocol_version >= 29)
2937 peer_id_to_avoid_sending = PEER_ID_INEXISTENT;
2939 for (u16 cid : clients) {
2940 if (cid != peer_id_to_avoid_sending)
2941 SendChatMessage(cid, ChatMessage(line));
2946 void Server::handleAdminChat(const ChatEventChat *evt)
2948 std::string name = evt->nick;
2949 std::wstring wname = utf8_to_wide(name);
2950 std::wstring wmessage = evt->evt_msg;
2952 std::wstring answer = handleChat(name, wname, wmessage);
2954 // If asked to send answer to sender
2955 if (!answer.empty()) {
2956 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", answer));
2960 RemoteClient *Server::getClient(session_t peer_id, ClientState state_min)
2962 RemoteClient *client = getClientNoEx(peer_id,state_min);
2964 throw ClientNotFoundException("Client not found");
2968 RemoteClient *Server::getClientNoEx(session_t peer_id, ClientState state_min)
2970 return m_clients.getClientNoEx(peer_id, state_min);
2973 std::string Server::getPlayerName(session_t peer_id)
2975 RemotePlayer *player = m_env->getPlayer(peer_id);
2977 return "[id="+itos(peer_id)+"]";
2978 return player->getName();
2981 PlayerSAO *Server::getPlayerSAO(session_t peer_id)
2983 RemotePlayer *player = m_env->getPlayer(peer_id);
2986 return player->getPlayerSAO();
2989 std::wstring Server::getStatusString()
2991 std::wostringstream os(std::ios_base::binary);
2992 os << L"# Server: ";
2994 os << L"version=" << narrow_to_wide(g_version_string);
2996 os << L", uptime=" << m_uptime.get();
2998 os << L", max_lag=" << (m_env ? m_env->getMaxLagEstimate() : 0);
3000 // Information about clients
3002 os << L", clients={";
3004 std::vector<session_t> clients = m_clients.getClientIDs();
3005 for (session_t client_id : clients) {
3006 RemotePlayer *player = m_env->getPlayer(client_id);
3008 // Get name of player
3009 std::wstring name = L"unknown";
3011 name = narrow_to_wide(player->getName());
3013 // Add name to information string
3024 if (m_env && !((ServerMap*)(&m_env->getMap()))->isSavingEnabled())
3025 os << std::endl << L"# Server: " << " WARNING: Map saving is disabled.";
3027 if (!g_settings->get("motd").empty())
3028 os << std::endl << L"# Server: " << narrow_to_wide(g_settings->get("motd"));
3033 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
3035 std::set<std::string> privs;
3036 m_script->getAuth(name, NULL, &privs);
3040 bool Server::checkPriv(const std::string &name, const std::string &priv)
3042 std::set<std::string> privs = getPlayerEffectivePrivs(name);
3043 return (privs.count(priv) != 0);
3046 void Server::reportPrivsModified(const std::string &name)
3049 std::vector<session_t> clients = m_clients.getClientIDs();
3050 for (const session_t client_id : clients) {
3051 RemotePlayer *player = m_env->getPlayer(client_id);
3052 reportPrivsModified(player->getName());
3055 RemotePlayer *player = m_env->getPlayer(name.c_str());
3058 SendPlayerPrivileges(player->getPeerId());
3059 PlayerSAO *sao = player->getPlayerSAO();
3062 sao->updatePrivileges(
3063 getPlayerEffectivePrivs(name),
3068 void Server::reportInventoryFormspecModified(const std::string &name)
3070 RemotePlayer *player = m_env->getPlayer(name.c_str());
3073 SendPlayerInventoryFormspec(player->getPeerId());
3076 void Server::reportFormspecPrependModified(const std::string &name)
3078 RemotePlayer *player = m_env->getPlayer(name.c_str());
3081 SendPlayerFormspecPrepend(player->getPeerId());
3084 void Server::setIpBanned(const std::string &ip, const std::string &name)
3086 m_banmanager->add(ip, name);
3089 void Server::unsetIpBanned(const std::string &ip_or_name)
3091 m_banmanager->remove(ip_or_name);
3094 std::string Server::getBanDescription(const std::string &ip_or_name)
3096 return m_banmanager->getBanDescription(ip_or_name);
3099 void Server::notifyPlayer(const char *name, const std::wstring &msg)
3101 // m_env will be NULL if the server is initializing
3105 if (m_admin_nick == name && !m_admin_nick.empty()) {
3106 m_admin_chat->outgoing_queue.push_back(new ChatEventChat("", msg));
3109 RemotePlayer *player = m_env->getPlayer(name);
3114 if (player->getPeerId() == PEER_ID_INEXISTENT)
3117 SendChatMessage(player->getPeerId(), ChatMessage(msg));
3120 bool Server::showFormspec(const char *playername, const std::string &formspec,
3121 const std::string &formname)
3123 // m_env will be NULL if the server is initializing
3127 RemotePlayer *player = m_env->getPlayer(playername);
3131 SendShowFormspecMessage(player->getPeerId(), formspec, formname);
3135 u32 Server::hudAdd(RemotePlayer *player, HudElement *form)
3140 u32 id = player->addHud(form);
3142 SendHUDAdd(player->getPeerId(), id, form);
3147 bool Server::hudRemove(RemotePlayer *player, u32 id) {
3151 HudElement* todel = player->removeHud(id);
3158 SendHUDRemove(player->getPeerId(), id);
3162 bool Server::hudChange(RemotePlayer *player, u32 id, HudElementStat stat, void *data)
3167 SendHUDChange(player->getPeerId(), id, stat, data);
3171 bool Server::hudSetFlags(RemotePlayer *player, u32 flags, u32 mask)
3176 SendHUDSetFlags(player->getPeerId(), flags, mask);
3177 player->hud_flags &= ~mask;
3178 player->hud_flags |= flags;
3180 PlayerSAO* playersao = player->getPlayerSAO();
3185 m_script->player_event(playersao, "hud_changed");
3189 bool Server::hudSetHotbarItemcount(RemotePlayer *player, s32 hotbar_itemcount)
3194 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
3197 player->setHotbarItemcount(hotbar_itemcount);
3198 std::ostringstream os(std::ios::binary);
3199 writeS32(os, hotbar_itemcount);
3200 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
3204 void Server::hudSetHotbarImage(RemotePlayer *player, const std::string &name)
3209 player->setHotbarImage(name);
3210 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_IMAGE, name);
3213 void Server::hudSetHotbarSelectedImage(RemotePlayer *player, const std::string &name)
3218 player->setHotbarSelectedImage(name);
3219 SendHUDSetParam(player->getPeerId(), HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
3222 Address Server::getPeerAddress(session_t peer_id)
3224 return m_con->GetPeerAddress(peer_id);
3227 void Server::setLocalPlayerAnimations(RemotePlayer *player,
3228 v2s32 animation_frames[4], f32 frame_speed)
3230 sanity_check(player);
3231 player->setLocalAnimations(animation_frames, frame_speed);
3232 SendLocalPlayerAnimations(player->getPeerId(), animation_frames, frame_speed);
3235 void Server::setPlayerEyeOffset(RemotePlayer *player, const v3f &first, const v3f &third)
3237 sanity_check(player);
3238 player->eye_offset_first = first;
3239 player->eye_offset_third = third;
3240 SendEyeOffset(player->getPeerId(), first, third);
3243 void Server::setSky(RemotePlayer *player, const video::SColor &bgcolor,
3244 const std::string &type, const std::vector<std::string> ¶ms,
3247 sanity_check(player);
3248 player->setSky(bgcolor, type, params, clouds);
3249 SendSetSky(player->getPeerId(), bgcolor, type, params, clouds);
3252 void Server::setClouds(RemotePlayer *player, const CloudParams ¶ms)
3254 sanity_check(player);
3255 player->setCloudParams(params);
3256 SendCloudParams(player->getPeerId(), params);
3259 bool Server::overrideDayNightRatio(RemotePlayer *player, bool do_override,
3265 player->overrideDayNightRatio(do_override, ratio);
3266 SendOverrideDayNightRatio(player->getPeerId(), do_override, ratio);
3270 void Server::notifyPlayers(const std::wstring &msg)
3272 SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(msg));
3275 void Server::spawnParticle(const std::string &playername, v3f pos,
3276 v3f velocity, v3f acceleration,
3277 float expirationtime, float size, bool
3278 collisiondetection, bool collision_removal, bool object_collision,
3279 bool vertical, const std::string &texture,
3280 const struct TileAnimationParams &animation, u8 glow)
3282 // m_env will be NULL if the server is initializing
3286 session_t peer_id = PEER_ID_INEXISTENT;
3288 if (!playername.empty()) {
3289 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3292 peer_id = player->getPeerId();
3293 proto_ver = player->protocol_version;
3296 SendSpawnParticle(peer_id, proto_ver, pos, velocity, acceleration,
3297 expirationtime, size, collisiondetection, collision_removal,
3298 object_collision, vertical, texture, animation, glow);
3301 u32 Server::addParticleSpawner(u16 amount, float spawntime,
3302 v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
3303 float minexptime, float maxexptime, float minsize, float maxsize,
3304 bool collisiondetection, bool collision_removal, bool object_collision,
3305 ServerActiveObject *attached, bool vertical, const std::string &texture,
3306 const std::string &playername, const struct TileAnimationParams &animation,
3309 // m_env will be NULL if the server is initializing
3313 session_t peer_id = PEER_ID_INEXISTENT;
3315 if (!playername.empty()) {
3316 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3319 peer_id = player->getPeerId();
3320 proto_ver = player->protocol_version;
3323 u16 attached_id = attached ? attached->getId() : 0;
3326 if (attached_id == 0)
3327 id = m_env->addParticleSpawner(spawntime);
3329 id = m_env->addParticleSpawner(spawntime, attached_id);
3331 SendAddParticleSpawner(peer_id, proto_ver, amount, spawntime,
3332 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3333 minexptime, maxexptime, minsize, maxsize, collisiondetection,
3334 collision_removal, object_collision, attached_id, vertical,
3335 texture, id, animation, glow);
3340 void Server::deleteParticleSpawner(const std::string &playername, u32 id)
3342 // m_env will be NULL if the server is initializing
3344 throw ServerError("Can't delete particle spawners during initialisation!");
3346 session_t peer_id = PEER_ID_INEXISTENT;
3347 if (!playername.empty()) {
3348 RemotePlayer *player = m_env->getPlayer(playername.c_str());
3351 peer_id = player->getPeerId();
3354 m_env->deleteParticleSpawner(id);
3355 SendDeleteParticleSpawner(peer_id, id);
3358 Inventory* Server::createDetachedInventory(const std::string &name, const std::string &player)
3360 if(m_detached_inventories.count(name) > 0){
3361 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
3362 delete m_detached_inventories[name];
3364 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
3366 Inventory *inv = new Inventory(m_itemdef);
3368 m_detached_inventories[name] = inv;
3369 m_detached_inventories_player[name] = player;
3370 //TODO find a better way to do this
3371 sendDetachedInventory(name,PEER_ID_INEXISTENT);
3375 bool Server::removeDetachedInventory(const std::string &name)
3377 const auto &inv_it = m_detached_inventories.find(name);
3378 if (inv_it == m_detached_inventories.end())
3381 delete inv_it->second;
3382 m_detached_inventories.erase(inv_it);
3384 const auto &player_it = m_detached_inventories_player.find(name);
3385 if (player_it != m_detached_inventories_player.end()) {
3386 RemotePlayer *player = m_env->getPlayer(player_it->second.c_str());
3388 if (player && player->getPeerId() != PEER_ID_INEXISTENT)
3389 sendDetachedInventory(name, player->getPeerId());
3391 m_detached_inventories_player.erase(player_it);
3393 // Notify all players about the change
3394 sendDetachedInventory(name, PEER_ID_INEXISTENT);
3399 // actions: time-reversed list
3400 // Return value: success/failure
3401 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
3402 std::list<std::string> *log)
3404 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
3405 ServerMap *map = (ServerMap*)(&m_env->getMap());
3407 // Fail if no actions to handle
3408 if (actions.empty()) {
3410 log->push_back("Nothing to do.");
3417 for (const RollbackAction &action : actions) {
3419 bool success = action.applyRevert(map, this, this);
3422 std::ostringstream os;
3423 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
3424 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3426 log->push_back(os.str());
3428 std::ostringstream os;
3429 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
3430 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
3432 log->push_back(os.str());
3436 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
3437 <<" failed"<<std::endl;
3439 // Call it done if less than half failed
3440 return num_failed <= num_tried/2;
3443 // IGameDef interface
3445 IItemDefManager *Server::getItemDefManager()
3450 const NodeDefManager *Server::getNodeDefManager()
3455 ICraftDefManager *Server::getCraftDefManager()
3460 u16 Server::allocateUnknownNodeId(const std::string &name)
3462 return m_nodedef->allocateDummy(name);
3465 IWritableItemDefManager *Server::getWritableItemDefManager()
3470 NodeDefManager *Server::getWritableNodeDefManager()
3475 IWritableCraftDefManager *Server::getWritableCraftDefManager()
3480 const std::vector<ModSpec> & Server::getMods() const
3482 return m_modmgr->getMods();
3485 const ModSpec *Server::getModSpec(const std::string &modname) const
3487 return m_modmgr->getModSpec(modname);
3490 void Server::getModNames(std::vector<std::string> &modlist)
3492 m_modmgr->getModNames(modlist);
3495 std::string Server::getBuiltinLuaPath()
3497 return porting::path_share + DIR_DELIM + "builtin";
3500 std::string Server::getModStoragePath() const
3502 return m_path_world + DIR_DELIM + "mod_storage";
3505 v3f Server::findSpawnPos()
3507 ServerMap &map = m_env->getServerMap();
3509 if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf))
3510 return nodeposf * BS;
3512 bool is_good = false;
3513 // Limit spawn range to mapgen edges (determined by 'mapgen_limit')
3514 s32 range_max = map.getMapgenParams()->getSpawnRangeMax();
3516 // Try to find a good place a few times
3517 for (s32 i = 0; i < 4000 && !is_good; i++) {
3518 s32 range = MYMIN(1 + i, range_max);
3519 // We're going to try to throw the player to this position
3520 v2s16 nodepos2d = v2s16(
3521 -range + (myrand() % (range * 2)),
3522 -range + (myrand() % (range * 2)));
3523 // Get spawn level at point
3524 s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d);
3525 // Continue if MAX_MAP_GENERATION_LIMIT was returned by the mapgen to
3526 // signify an unsuitable spawn position, or if outside limits.
3527 if (spawn_level >= MAX_MAP_GENERATION_LIMIT ||
3528 spawn_level <= -MAX_MAP_GENERATION_LIMIT)
3531 v3s16 nodepos(nodepos2d.X, spawn_level, nodepos2d.Y);
3532 // Consecutive empty nodes
3535 // Search upwards from 'spawn level' for 2 consecutive empty nodes, to
3536 // avoid obstructions in already-generated mapblocks.
3537 // In ungenerated mapblocks consisting of 'ignore' nodes, there will be
3538 // no obstructions, but mapgen decorations are generated after spawn so
3539 // the player may end up inside one.
3540 for (s32 i = 0; i < 8; i++) {
3541 v3s16 blockpos = getNodeBlockPos(nodepos);
3542 map.emergeBlock(blockpos, true);
3543 content_t c = map.getNode(nodepos).getContent();
3545 // In generated mapblocks allow spawn in all 'airlike' drawtype nodes.
3546 // In ungenerated mapblocks allow spawn in 'ignore' nodes.
3547 if (m_nodedef->get(c).drawtype == NDT_AIRLIKE || c == CONTENT_IGNORE) {
3549 if (air_count >= 2) {
3550 // Spawn in lower empty node
3552 nodeposf = intToFloat(nodepos, BS);
3553 // Don't spawn the player outside map boundaries
3554 if (objectpos_over_limit(nodeposf))
3555 // Exit this loop, positions above are probably over limit
3558 // Good position found, cause an exit from main loop
3572 // No suitable spawn point found, return fallback 0,0,0
3573 return v3f(0.0f, 0.0f, 0.0f);
3576 void Server::requestShutdown(const std::string &msg, bool reconnect, float delay)
3578 if (delay == 0.0f) {
3579 // No delay, shutdown immediately
3580 m_shutdown_state.is_requested = true;
3581 // only print to the infostream, a chat message saying
3582 // "Server Shutting Down" is sent when the server destructs.
3583 infostream << "*** Immediate Server shutdown requested." << std::endl;
3584 } else if (delay < 0.0f && m_shutdown_state.isTimerRunning()) {
3585 // Negative delay, cancel shutdown if requested
3586 m_shutdown_state.reset();
3587 std::wstringstream ws;
3589 ws << L"*** Server shutdown canceled.";
3591 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3592 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3593 // m_shutdown_* are already handled, skip.
3595 } else if (delay > 0.0f) {
3596 // Positive delay, tell the clients when the server will shut down
3597 std::wstringstream ws;
3599 ws << L"*** Server shutting down in "
3600 << duration_to_string(myround(delay)).c_str()
3603 infostream << wide_to_utf8(ws.str()).c_str() << std::endl;
3604 SendChatMessage(PEER_ID_INEXISTENT, ws.str());
3607 m_shutdown_state.trigger(delay, msg, reconnect);
3610 PlayerSAO* Server::emergePlayer(const char *name, session_t peer_id, u16 proto_version)
3613 Try to get an existing player
3615 RemotePlayer *player = m_env->getPlayer(name);
3617 // If player is already connected, cancel
3618 if (player && player->getPeerId() != PEER_ID_INEXISTENT) {
3619 infostream<<"emergePlayer(): Player already connected"<<std::endl;
3624 If player with the wanted peer_id already exists, cancel.
3626 if (m_env->getPlayer(peer_id)) {
3627 infostream<<"emergePlayer(): Player with wrong name but same"
3628 " peer_id already exists"<<std::endl;
3633 player = new RemotePlayer(name, idef());
3636 bool newplayer = false;
3639 PlayerSAO *playersao = m_env->loadPlayer(player, &newplayer, peer_id, isSingleplayer());
3641 // Complete init with server parts
3642 playersao->finalize(player, getPlayerEffectivePrivs(player->getName()));
3643 player->protocol_version = proto_version;
3647 m_script->on_newplayer(playersao);
3653 bool Server::registerModStorage(ModMetadata *storage)
3655 if (m_mod_storages.find(storage->getModName()) != m_mod_storages.end()) {
3656 errorstream << "Unable to register same mod storage twice. Storage name: "
3657 << storage->getModName() << std::endl;
3661 m_mod_storages[storage->getModName()] = storage;
3665 void Server::unregisterModStorage(const std::string &name)
3667 std::unordered_map<std::string, ModMetadata *>::const_iterator it = m_mod_storages.find(name);
3668 if (it != m_mod_storages.end()) {
3669 // Save unconditionaly on unregistration
3670 it->second->save(getModStoragePath());
3671 m_mod_storages.erase(name);
3675 void dedicated_server_loop(Server &server, bool &kill)
3677 verbosestream<<"dedicated_server_loop()"<<std::endl;
3679 IntervalLimiter m_profiler_interval;
3681 static thread_local const float steplen =
3682 g_settings->getFloat("dedicated_server_step");
3683 static thread_local const float profiler_print_interval =
3684 g_settings->getFloat("profiler_print_interval");
3687 // This is kind of a hack but can be done like this
3688 // because server.step() is very light
3689 sleep_ms((int)(steplen*1000.0));
3690 server.step(steplen);
3692 if (server.isShutdownRequested() || kill)
3698 if (profiler_print_interval != 0) {
3699 if(m_profiler_interval.step(steplen, profiler_print_interval))
3701 infostream<<"Profiler:"<<std::endl;
3702 g_profiler->print(infostream);
3703 g_profiler->clear();
3708 infostream << "Dedicated server quitting" << std::endl;
3710 if (g_settings->getBool("server_announce"))
3711 ServerList::sendAnnounce(ServerList::AA_DELETE,
3712 server.m_bind_addr.getPort());
3721 bool Server::joinModChannel(const std::string &channel)
3723 return m_modchannel_mgr->joinChannel(channel, PEER_ID_SERVER) &&
3724 m_modchannel_mgr->setChannelState(channel, MODCHANNEL_STATE_READ_WRITE);
3727 bool Server::leaveModChannel(const std::string &channel)
3729 return m_modchannel_mgr->leaveChannel(channel, PEER_ID_SERVER);
3732 bool Server::sendModChannelMessage(const std::string &channel, const std::string &message)
3734 if (!m_modchannel_mgr->canWriteOnChannel(channel))
3737 broadcastModChannelMessage(channel, message, PEER_ID_SERVER);
3741 ModChannel* Server::getModChannel(const std::string &channel)
3743 return m_modchannel_mgr->getModChannel(channel);
3746 void Server::broadcastModChannelMessage(const std::string &channel,
3747 const std::string &message, session_t from_peer)
3749 const std::vector<u16> &peers = m_modchannel_mgr->getChannelPeers(channel);
3753 if (message.size() > STRING_MAX_LEN) {
3754 warningstream << "ModChannel message too long, dropping before sending "
3755 << " (" << message.size() << " > " << STRING_MAX_LEN << ", channel: "
3756 << channel << ")" << std::endl;
3761 if (from_peer != PEER_ID_SERVER) {
3762 sender = getPlayerName(from_peer);
3765 NetworkPacket resp_pkt(TOCLIENT_MODCHANNEL_MSG,
3766 2 + channel.size() + 2 + sender.size() + 2 + message.size());
3767 resp_pkt << channel << sender << message;
3768 for (session_t peer_id : peers) {
3770 if (peer_id == from_peer)
3773 Send(peer_id, &resp_pkt);
3776 if (from_peer != PEER_ID_SERVER) {
3777 m_script->on_modchannel_message(channel, sender, message);